Skip to main content
Solved

Copy UDF from PO Line to AP Invoice when entering AP Bill from PO

  • August 6, 2024
  • 28 replies
  • 418 views

Forum|alt.badge.img

Could someone please help in providing a solution of moving the UDF from PO into AP Invoice?

I am new to developing in acumatica. I have created the user defined fields in POLine and APTran.

While reviewing the source of APInvoiceEntry, I looked at overriding the method CopyCustomizationFieldsToAPTran.

Code I added is below.

public void CopyCustomizationFieldsToAPTran(APTran apTranToFill, IAPTranSource poSourceLine, Boolean areCurrenciesSame, CopyCustomizationFieldsToAPTranDelegate baseMethod)
    {
  
      baseMethod(apTranToFill,poSourceLine,areCurrenciesSame);

      var portID = poSourceLine.GetExtension<POLineExt>()?.UsrPortID;
      var tranline = apTranToFill?.GetExtension<APTranExt>()?.UsrPortID;         
      
      if (tranline != null && portID != null ) tranline.UsrPortID = portID;

    }

I am getting validation errors when I try to publish.

error CS1929: 'IAPTranSource' does not contain a definition for 'GetExtension' and the best extension method overload 'PXCacheEx.GetExtension<POLineExt>(IBqlTable)' requires a receiver of type 'IBqlTable'
error CS1061: 'string' does not contain a definition for 'UsrPortID' and no accessible extension method 'UsrPortID' accepting a first argument of type 'string' could be found (are you missing a using directive or an assembly reference?)
error CS1929: 'IAPTranSource' does not contain a definition for 'GetExtension' and the best extension method overload 'PXCacheEx.GetExtension<POLineExt>(IBqlTable)' requires a receiver of type 'IBqlTable'

Am I using the correct method to accomplish the task?

Best answer by Vignesh Ponnusamy

Hi @lnd74,

Adding to @darylbowman suggestions.

You can also override the CreateAPInvoice method and add the RowInserting event handler for APTran DAC like below copy the custom fields,

 public class POOrderEntry_Extension : PXGraphExtension<PX.Objects.PO.POOrderEntry>
{
#region Event Handlers
public delegate IEnumerable CreateAPInvoiceDelegate(PXAdapter adapter);
[PXOverride]
public IEnumerable CreateAPInvoice(PXAdapter adapter, CreateAPInvoiceDelegate baseMethod)
{
PXGraph.InstanceCreated.AddHandler<APInvoiceEntry>((invoiceEntryGraph) =>
{
invoiceEntryGraph.RowInserting.AddHandler<APTran>((sender, e) =>
{
APTran apTran = (APTran)e.Row;
APTranExt apTranExt = apTran.GetExtension<APTranExt>();
POLine poLine = PXSelect<POLine, Where<POLine.orderType, Equal<Required<APTran.pOOrderType>>,
And<POLine.orderNbr, Equal<Required<APTran.pONbr>>,
And<POLine.lineNbr, Equal<Required<APTran.pOLineNbr>>>>>>.Select(Base, apTran.POOrderType, apTran.PONbr, apTran.POLineNbr);
if (poLine != null)
{
POLineExt poLineExt = poLine.GetExtension<POLineExt>();
apTranExt.UsrPortID = poLineExt.UsrPortID;
}
});
}
);
return baseMethod(adapter);
}
#endregion
}

Feel free to post back if you have any questions. Happy coding.!

28 replies

darylbowman
Captain II
Forum|alt.badge.img+16

Try casting poSourceLine as POLine:

POLine sourceLine = poSourceLine as POLine;

var portID = sourceLine.GetExtension<POLineExt>()?.UsrPortID;

 


Forum|alt.badge.img
  • Author
  • Freshman I
  • August 6, 2024

Thank you!

Now I am getting the error below.

error CS1061: 'string' does not contain a definition for 'UsrPortID' and no accessible extension method 'UsrPortID' accepting a first argument of type 'string' could be found (are you missing a using directive or an assembly reference?)

Am I missing something in my DAC?

public class POLineExt : PXCacheExtension<PX.Objects.PO.POLine>
    {
        #region UsrPortID
        [PXSelector(typeof(Search<XY_Ports.XY_Port.name,Where<XY_Ports.XY_Port.isActive, Equal<True>>>),typeof(XY_Ports.XY_Port.description))]
        [PXDBString(10)]
        [PXUIField(DisplayName="Port")]
        public virtual string UsrPortID { get; set; }
        public abstract class usrPortID : PX.Data.BQL.BqlString.Field<usrPortID> { }
        #endregion
    }

public class APTranExt : PXCacheExtension<PX.Objects.AP.APTran>
    {
        #region UsrPortID
        [PXSelector(typeof(Search<XY_Ports.XY_Port.name,Where<XY_Ports.XY_Port.isActive, Equal<True>>>),typeof(XY_Ports.XY_Port.description))]
        [PXDBString(10)]
        [PXUIField(DisplayName="Port")]
        public virtual string UsrPortID { get; set; }
        public abstract class usrPortID : PX.Data.BQL.BqlString.Field<usrPortID> { }
        #endregion
    }


darylbowman
Captain II
Forum|alt.badge.img+16

Do

var tranline = apTranToFill?.GetExtension<APTranExt>();

instead of 

var tranline = apTranToFill?.GetExtension<APTranExt>()?.UsrPortID;

 


Forum|alt.badge.img
  • Author
  • Freshman I
  • August 6, 2024

Thanks!

I really appreciate you help.

I am getting the following GetItemExtension failed on trace.

 

 


darylbowman
Captain II
Forum|alt.badge.img+16

Could you post your code please?


Forum|alt.badge.img
  • Author
  • Freshman I
  • August 6, 2024

 public class APInvoiceEntry_Extension : PXGraphExtension<PX.Objects.AP.APInvoiceEntry>
  {
    public delegate void CopyCustomizationFieldsToAPTranDelegate(APTran apTranToFill, IAPTranSource poSourceLine, Boolean areCurrenciesSame);
    [PXOverride]
    public void CopyCustomizationFieldsToAPTran(APTran apTranToFill, IAPTranSource poSourceLine, Boolean areCurrenciesSame, CopyCustomizationFieldsToAPTranDelegate baseMethod)
    {
  
  
      baseMethod(apTranToFill,poSourceLine,areCurrenciesSame);

      POLine sourceLine = poSourceLine as POLine;

      var portID = sourceLine.GetExtension<POLineExt>()?.UsrPortID;

      var tranline = apTranToFill?.GetExtension<APTranExt>();       
      
      if (tranline != null && portID != null ) tranline.UsrPortID = portID;

    }
 
  }


darylbowman
Captain II
Forum|alt.badge.img+16

Use this instead:

var portID = sourceLine?.GetExtension<POLineExt>()?.UsrPortID;

 


Vignesh Ponnusamy
Acumatica Moderator
Forum|alt.badge.img+5

Hi @lnd74,

Adding to @darylbowman suggestions.

You can also override the CreateAPInvoice method and add the RowInserting event handler for APTran DAC like below copy the custom fields,

 public class POOrderEntry_Extension : PXGraphExtension<PX.Objects.PO.POOrderEntry>
{
#region Event Handlers
public delegate IEnumerable CreateAPInvoiceDelegate(PXAdapter adapter);
[PXOverride]
public IEnumerable CreateAPInvoice(PXAdapter adapter, CreateAPInvoiceDelegate baseMethod)
{
PXGraph.InstanceCreated.AddHandler<APInvoiceEntry>((invoiceEntryGraph) =>
{
invoiceEntryGraph.RowInserting.AddHandler<APTran>((sender, e) =>
{
APTran apTran = (APTran)e.Row;
APTranExt apTranExt = apTran.GetExtension<APTranExt>();
POLine poLine = PXSelect<POLine, Where<POLine.orderType, Equal<Required<APTran.pOOrderType>>,
And<POLine.orderNbr, Equal<Required<APTran.pONbr>>,
And<POLine.lineNbr, Equal<Required<APTran.pOLineNbr>>>>>>.Select(Base, apTran.POOrderType, apTran.PONbr, apTran.POLineNbr);
if (poLine != null)
{
POLineExt poLineExt = poLine.GetExtension<POLineExt>();
apTranExt.UsrPortID = poLineExt.UsrPortID;
}
});
}
);
return baseMethod(adapter);
}
#endregion
}

Feel free to post back if you have any questions. Happy coding.!


Forum|alt.badge.img
  • Author
  • Freshman I
  • August 6, 2024

To @darylbowman  I am still having the same issue with GetExtension Failed. Code is below.

 public class APInvoiceEntry_Extension : PXGraphExtension<PX.Objects.AP.APInvoiceEntry>
  {
    public delegate void CopyCustomizationFieldsToAPTranDelegate(APTran apTranToFill, IAPTranSource poSourceLine, Boolean areCurrenciesSame);
    [PXOverride]
    public void CopyCustomizationFieldsToAPTran(APTran apTranToFill, IAPTranSource poSourceLine, Boolean areCurrenciesSame, CopyCustomizationFieldsToAPTranDelegate baseMethod)
    {
  
  
      baseMethod(apTranToFill,poSourceLine,areCurrenciesSame);

      POLine sourceLine = poSourceLine as POLine;

      var portID = sourceLine?.GetExtension<POLineExt>()?.UsrPortID;
      
      var tranline = apTranToFill?.GetExtension<APTranExt>();       
      
      if (tranline != null && portID != null ) tranline.UsrPortID = portID;

    }
 
  }

To @Vignesh Ponnusamy I will also try your solution.

 

 


darylbowman
Captain II
Forum|alt.badge.img+16

Sorry, I led you astray in several ways. POLine is not a IAPTranSource, neither is POReceiptLine. But POReceiptLineS is and you should be able to get the POLine from there.

Update, see below:

 


darylbowman
Captain II
Forum|alt.badge.img+16
public class APInvoiceEntry_Extension : PXGraphExtension<PX.Objects.AP.APInvoiceEntry>
{
public delegate void CopyCustomizationFieldsToAPTranDelegate(APTran apTranToFill, IAPTranSource poSourceLine, Boolean areCurrenciesSame);
[PXOverride]
public void CopyCustomizationFieldsToAPTran(APTran apTranToFill, IAPTranSource poSourceLine, Boolean areCurrenciesSame, CopyCustomizationFieldsToAPTranDelegate baseMethod)
{
baseMethod(apTranToFill,poSourceLine,areCurrenciesSame);

POReceiptLineS sourceLineS = poSourceLine as POReceiptLineS;
POLine sourceLine = POLine.PK.Find(this, sourceLineS?.POType, sourceLineS?.PONbr, sourceLineS?.POLineNbr);

var portID = sourceLine?.GetExtension<POLineExt>()?.UsrPortID;

var tranline = apTranToFill?.GetExtension<APTranExt>();

if (tranline != null && portID != null ) tranline.UsrPortID = portID;
}
}

 


Forum|alt.badge.img
  • Author
  • Freshman I
  • August 6, 2024

I get a different validation error from the following code.

 

public class APInvoiceEntry_Extension : PXGraphExtension<PX.Objects.AP.APInvoiceEntry>
  {
    #region Event Handlers
    public delegate void CopyCustomizationFieldsToAPTranDelegate(APTran apTranToFill, IAPTranSource poSourceLine, Boolean areCurrenciesSame);
    [PXOverride]
    public void CopyCustomizationFieldsToAPTran(APTran apTranToFill, IAPTranSource poSourceLine, Boolean areCurrenciesSame, CopyCustomizationFieldsToAPTranDelegate baseMethod)
    {
      baseMethod(apTranToFill,poSourceLine,areCurrenciesSame);

        POReceiptLineS sourceLineS = poSourceLine as POReceiptLineS;
        POLine sourceLine = POLine.PK.Find(this, sourceLineS?.POType, sourceLineS?.PONbr, sourceLineS?.POLineNbr);

        var portID = sourceLine?.GetExtension<POLineExt>()?.UsrPortID;

        var tranline = apTranToFill?.GetExtension<APTranExt>();       

        if (tranline != null && portID != null ) tranline.UsrPortID = portID;


    }


    #endregion
  }

 

 

\App_RuntimeCode\APInvoiceEntry.cs(64): error CS1503: Argument 1: cannot convert from 'PX.Objects.AP.APInvoiceEntry_Extension' to 'PX.Data.PXGraph'

darylbowman
Captain II
Forum|alt.badge.img+16

Change 'this' to 'Base' in 

POLine sourceLine = POLine.PK.Find(this, sourceLineS?.POType, sourceLineS?.PONbr, sourceLineS?.POLineNbr);


Forum|alt.badge.img
  • Author
  • Freshman I
  • August 6, 2024

It now compliles properly, but still gets the GetItemExtension Error.

 

Code below.

#region Event Handlers
    public delegate void CopyCustomizationFieldsToAPTranDelegate(APTran apTranToFill, IAPTranSource poSourceLine, Boolean areCurrenciesSame);
    [PXOverride]
    public void CopyCustomizationFieldsToAPTran(APTran apTranToFill, IAPTranSource poSourceLine, Boolean areCurrenciesSame, CopyCustomizationFieldsToAPTranDelegate baseMethod)
    {
      baseMethod(apTranToFill,poSourceLine,areCurrenciesSame);

        POReceiptLineS sourceLineS = poSourceLine as POReceiptLineS;
        POLine sourceLine = POLine.PK.Find(Base, sourceLineS?.POType, sourceLineS?.PONbr, sourceLineS?.POLineNbr);

        var portID = sourceLine?.GetExtension<POLineExt>()?.UsrPortID;

        var tranline = apTranToFill?.GetExtension<APTranExt>();       

        if (tranline != null && portID != null ) tranline.UsrPortID = portID;


    }


    #endregion

 

 

Trace 

 


darylbowman
Captain II
Forum|alt.badge.img+16

Maybe go with Vignesh's code. That's how I would do it if I was starting from scratch.


Forum|alt.badge.img
  • Author
  • Freshman I
  • August 7, 2024

Ok, started from scratch with Vignesh’s and added warning to see if I am getting the UDF.

I am having an issue of it not saving on the line.

On the trace below it is getting the UDF but not saving.

Code below

  #region Event Handlers
        public delegate IEnumerable CreateAPInvoiceDelegate(PXAdapter adapter);
        [PXOverride]
        public IEnumerable CreateAPInvoice(PXAdapter adapter, CreateAPInvoiceDelegate baseMethod)
        {
            PXGraph.InstanceCreated.AddHandler<APInvoiceEntry>((invoiceEntryGraph) =>
            {
                invoiceEntryGraph.RowInserting.AddHandler<APTran>((sender, e) =>
                {
                    APTran apTran = (APTran)e.Row;

                    if (apTran == null) return;
 
                    APTranExt apTranExt = apTran.GetExtension<APTranExt>();
                    
                    POLine poLine = new PXSelect<POLine, Where<POLine.orderType, Equal<Required<APTran.pOOrderType>>,
                        And<POLine.orderNbr, Equal<Required<APTran.pONbr>>,
                        And<POLine.lineNbr, Equal<Required<APTran.pOLineNbr>>>>>>(Base).SelectSingle(apTran.POOrderType, apTran.PONbr, apTran.POLineNbr);
                   
                    if (poLine != null)
                    {
                        POLineExt poLineExt = poLine.GetExtension<POLineExt>();
                      
                         PXTrace.WriteWarning("POLine Port ID:"+poLineExt.UsrPortID);
                      
                        apTranExt.UsrPortID = poLineExt.UsrPortID;
                      
                         PXTrace.WriteWarning("APTran Port ID:"+apTranExt.UsrPortID);
                    
                    } else {
                      
                       PXTrace.WriteWarning("poLine is null");
                      
                    }
                });
            }
            );
            return baseMethod(adapter);
        }
        #endregion


Vignesh Ponnusamy
Acumatica Moderator
Forum|alt.badge.img+5

Hi @lnd74,

To clarify, so the field is inserted in cache, displayed and when you save the document the value isn’t persisted?


Forum|alt.badge.img
  • Author
  • Freshman I
  • August 7, 2024

Port ID from PO

Port ID is blank on AP Invoice

 


Vignesh Ponnusamy
Acumatica Moderator
Forum|alt.badge.img+5

@lnd74,

The looks good to me, from my testing with your code I was able to reproduce the issue once. Then again it works as expected. Try removing the PXTrace.WriteWarning in the if condition to see if that helps.

I am testing the in 24R106. If the issue still persists, share the build number you are using.


Forum|alt.badge.img
  • Author
  • Freshman I
  • August 7, 2024

@Vignesh Ponnusamy ,

 

I removed the trace, I tested with a dropship and regular PO as well and it is not working for me. Our version  of Acumatica 2023 R2 Build 23.204.0031.


darylbowman
Captain II
Forum|alt.badge.img+16

I use this framework convention frequently and have found that when adding an event handler, it is also a good idea to remove it after the baseMethod runs. It seems to help with consistency issues.

You could try something like this:

public delegate IEnumerable CreateAPInvoiceDelegate(PXAdapter adapter);
[PXOverride]
public IEnumerable CreateAPInvoice(PXAdapter adapter, CreateAPInvoiceDelegate baseMethod)
{
// Handler
void APInvoiceEntryInstanceCreated(APInvoiceEntry graph)
{
graph.RowInserted.AddHandler<APTran>((cache, e) =>
{
APTran apTran = (APTran)e.Row;
if (apTran == null) return;

APTranExt apTranExt = apTran?.GetExtension<APTranExt>();

POLine poLine = new PXSelect<POLine, Where<POLine.orderType, Equal<Required<APTran.pOOrderType>>,
And<POLine.orderNbr, Equal<Required<APTran.pONbr>>,
And<POLine.lineNbr, Equal<Required<APTran.pOLineNbr>>>>>>(Base).SelectSingle(apTran.POOrderType, apTran.PONbr, apTran.POLineNbr);

if (poLine != null)
{
POLineExt poLineExt = poLine?.GetExtension<POLineExt>();

PXTrace.WriteWarning("POLine Port ID:" + poLineExt.UsrPortID);

apTranExt.UsrPortID = poLineExt?.UsrPortID;

PXTrace.WriteWarning("APTran Port ID:" + apTranExt.UsrPortID);
}
else
PXTrace.WriteWarning("poLine is null");
});
}

PXGraph.InstanceCreated.AddHandler<APInvoiceEntry>(APInvoiceEntryInstanceCreated);
var result = baseMethod(adapter);
PXGraph.InstanceCreated.RemoveHandler<APInvoiceEntry>(APInvoiceEntryInstanceCreated);

return result;
}

 


darylbowman
Captain II
Forum|alt.badge.img+16

Also, @Chris Hackett, what is up with the formatting?


Chris Hackett
Community Manager
Forum|alt.badge.img
  • Acumatica Community Manager
  • August 7, 2024

@darylbowman? formatting? not sure what you’re asking about...formatting on the site? need more specifics if it needs to be brought to Gainsight’s attention.


darylbowman
Captain II
Forum|alt.badge.img+16

Yeah, for the code formatting. There are times when it’s really wonky:

There’s no reason this should be bold.


Chris Hackett
Community Manager
Forum|alt.badge.img
  • Acumatica Community Manager
  • August 7, 2024

@darylbowman  - well I can post out to their community with this feedback...don’t hold your breath on it changing anytime soon