Skip to main content
Solved

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


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?

Try casting poSourceLine as POLine:

POLine sourceLine = poSourceLine as POLine;

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

 


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)]
        nPXUIField(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)]
        PPXUIField(DisplayName="Port")]
        public virtual string UsrPortID { get; set; }
        public abstract class usrPortID : PX.Data.BQL.BqlString.Field<usrPortID> { }
        #endregion
    }


Do

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

instead of 

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

 


Thanks!

I really appreciate you help.

I am getting the following GetItemExtension failed on trace.

 

 


Could you post your code please?


 public class APInvoiceEntry_Extension : PXGraphExtension<PX.Objects.AP.APInvoiceEntry>
  {
    public delegate void CopyCustomizationFieldsToAPTranDelegate(APTran apTranToFill, IAPTranSource poSourceLine, Boolean areCurrenciesSame);
    ePXOverride]
    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;

    }
 
  }


Use this instead:

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

 


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.!


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);
    iPXOverride]
    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.

 

 


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:

 


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;
}
}

 


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);
    nPXOverride]
    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'

Change 'this' to 'Base' in 

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


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 

 


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


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);
        bPXOverride]
        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


Hi @lnd74,

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


Port ID from PO

Port ID is blank on AP Invoice

 


@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.


@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.


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;
}

 


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


@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.


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

There’s no reason this should be bold.


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


Reply