Skip to main content
Answer

Copy User Defined Fields from Sales Order Line to Purchase Order Line on Clicking 'Create Purchase Order' Action in Sales Order Screen (SO301000)

  • December 12, 2024
  • 9 replies
  • 166 views

Forum|alt.badge.img+2

I have a few user defined fields in sales order line which I need to copy when the 'Create Purchase Order' action is clicked in the sales order screen. How can I override the action in order to copy these values?

I have tried this override action based on the source code but there is no copying of values.

using PX.Objects;
using PX.Objects.SO;


namespace PX.Objects.SO
{
public class SOOrderEntry_Extension : PXGraphExtension<PX.Objects.SO.SOOrderEntry>
{
#region Event Handlers
[PXOverride]
public virtual IEnumerable CreatePurchaseOrder(PXAdapter adapter, Func<PXAdapter, IEnumerable> baseMethod)
{
// Call the base method to create the purchase order
IEnumerable result = baseMethod(adapter);

// Retrieve the created purchase orders
POOrderEntry poGraph = PXGraph.CreateInstance<POOrderEntry>();

foreach (var poOrder in poGraph.Document.Cache.Cached)
{
var poOrderRow = (POOrder)poOrder;

// Retrieve the related purchase order lines
var poLines = PXSelect<POLine,
Where<POLine.orderType, Equal<Required<POOrder.orderType>>,
And<POLine.orderNbr, Equal<Required<POOrder.orderNbr>>>>>
.Select(Base, poOrderRow.OrderType, poOrderRow.OrderNbr);

foreach (POLine poLine in poLines)
{
// Retrieve the corresponding sales order line using SOLineNbr and SOOrderNbr
SOLine soLine = PXSelect<SOLine,
Where<SOLine.orderType, Equal<Required<POLine.sOOrderType>>,
And<SOLine.orderNbr, Equal<Required<POLine.sOOrderNbr>>,
And<SOLine.lineNbr, Equal<Required<POLine.sOLineNbr>>>>>>
.Select(Base, poLine.SOOrderType, poLine.SOOrderNbr, poLine.SOLineNbr);

if (soLine != null)
{
// Copy user-defined fields from the sales order line to the purchase order line
var soLineExt = PXCache<SOLine>.GetExtension<SOLineExt>(soLine);
var poLineExt = PXCache<POLine>.GetExtension<POLineExt>(poLine);

poLineExt.UsrPackageType = soLineExt.UsrCustomPackageType;
poLineExt.UsrPackageQty = soLineExt.UsrPackageQty;
poLineExt.UsrDeliveryNotes = soLineExt.UsrDeliveryNotes;

// Update the purchase order line
poGraph.Transactions.Update(poLine);
}
}
}

// Save changes to the purchase order
poGraph.Actions.PressSave();

return result;
}





#endregion
}
}

 

Best answer by noorula77

Hi ​@TharidhiP ,
  Override action on PXGraphExtension<PX.Objects.PO.POCreate> Create Purchase Orders screen.
Two methods you need to override.


public delegate POOrder FindOrCreatePOOrderDelegate(DocumentList<POOrder> created, POOrder previousOrder, POFixedDemand demand, SOOrder soorder, SOLineSplit3 soline, Boolean requireSingleProject);
        [PXOverride]
        public POOrder FindOrCreatePOOrder(DocumentList<POOrder> created, POOrder previousOrder, POFixedDemand demand, SOOrder soorder, SOLineSplit3 soline, Boolean requireSingleProject, FindOrCreatePOOrderDelegate baseMethod)
        {
            // Call the base method to get or create the POOrder
            POOrder pOOrder = baseMethod(created, previousOrder, demand, soorder, soline, requireSingleProject);
            // If a POOrder was created or retrieved
return pOOrder;
        }

public delegate POLine FindOrCreatePOLineDelegate(POOrderEntry docgraph, DocumentList<POLine> ordered, String orderType, POFixedDemand demand, SOLineSplit3 soline);
        [PXOverride]
        public POLine FindOrCreatePOLine(POOrderEntry docgraph, DocumentList<POLine> ordered, String orderType, POFixedDemand demand, SOLineSplit3 soline, FindOrCreatePOLineDelegate baseMethod)
        {
            // Call the base method to get or create the POLine
            POLine poLine = baseMethod(docgraph, ordered, orderType, demand, soline);
 return poLine;
        }

Hope it will work.

9 replies

Forum|alt.badge.img+1
  • Jr Varsity III
  • Answer
  • December 12, 2024

Hi ​@TharidhiP ,
  Override action on PXGraphExtension<PX.Objects.PO.POCreate> Create Purchase Orders screen.
Two methods you need to override.


public delegate POOrder FindOrCreatePOOrderDelegate(DocumentList<POOrder> created, POOrder previousOrder, POFixedDemand demand, SOOrder soorder, SOLineSplit3 soline, Boolean requireSingleProject);
        [PXOverride]
        public POOrder FindOrCreatePOOrder(DocumentList<POOrder> created, POOrder previousOrder, POFixedDemand demand, SOOrder soorder, SOLineSplit3 soline, Boolean requireSingleProject, FindOrCreatePOOrderDelegate baseMethod)
        {
            // Call the base method to get or create the POOrder
            POOrder pOOrder = baseMethod(created, previousOrder, demand, soorder, soline, requireSingleProject);
            // If a POOrder was created or retrieved
return pOOrder;
        }

public delegate POLine FindOrCreatePOLineDelegate(POOrderEntry docgraph, DocumentList<POLine> ordered, String orderType, POFixedDemand demand, SOLineSplit3 soline);
        [PXOverride]
        public POLine FindOrCreatePOLine(POOrderEntry docgraph, DocumentList<POLine> ordered, String orderType, POFixedDemand demand, SOLineSplit3 soline, FindOrCreatePOLineDelegate baseMethod)
        {
            // Call the base method to get or create the POLine
            POLine poLine = baseMethod(docgraph, ordered, orderType, demand, soline);
 return poLine;
        }

Hope it will work.


Forum|alt.badge.img+2
  • Author
  • Pro III
  • December 12, 2024

Thanks ​@noorula77 I copied SOLine details to POLine using your suggestion and it works!

   public delegate POLine FindOrCreatePOLineDelegate(POOrderEntry docgraph, DocumentList<POLine> ordered, String orderType, POFixedDemand demand, SOLineSplit3 soline);

[PXOverride]
public POLine FindOrCreatePOLine(
POOrderEntry docgraph,
DocumentList<POLine> ordered,
String orderType,
POFixedDemand demand,
SOLineSplit3 soline,
FindOrCreatePOLineDelegate baseMethod)
{
// Call the base method to get or create the POLine
POLine poLine = baseMethod(docgraph, ordered, orderType, demand, soline);

if (poLine != null && soline != null)
{
// Fetch the associated SOLine using its line reference
SOLine soLine = PXSelect<SOLine,
Where<SOLine.orderType, Equal<Required<SOLine.orderType>>,
And<SOLine.orderNbr, Equal<Required<SOLine.orderNbr>>,
And<SOLine.lineNbr, Equal<Required<SOLine.lineNbr>>>>>>
.Select(docgraph, soline.OrderType, soline.OrderNbr, soline.LineNbr);

if (soLine != null)
{
// Retrieve the extensions
var soLineExt = PXCache<SOLine>.GetExtension<SOLineExt>(soLine);
var poLineExt = PXCache<POLine>.GetExtension<POLineExt>(poLine);

if (soLineExt != null && poLineExt != null)
{
// Map the custom fields from SOLine to POLine
poLineExt.UsrPackageType = soLineExt.UsrCustomPackageType;
poLineExt.UsrPackageQty = soLineExt.UsrPackageQty;
poLineExt.UsrDeliveryNotes = soLineExt.UsrDeliveryNotes;
poLineExt.UsrDeliveryNoteDetail = soLineExt.UsrDeliveryNoteDetail;
poLineExt.UsrCountryOfOrigin = soLineExt.UsrCountryOfOrigin;
poLineExt.UsrCropYear = soLineExt.UsrCropYear;
poLineExt.UsrBrand = soLineExt.UsrBrand;
}
}
}

return poLine;
}

 


Forum|alt.badge.img+1
  • Jr Varsity III
  • December 12, 2024

Welcome ​@TharidhiP 


Forum|alt.badge.img
  • Semi-Pro III
  • November 3, 2025

Hi ​@TharidhiP and ​@noorula77 This post has been very helpful, thank you both! 

I did have to make a few changes to the code (see below) to get the UDF to copy to the Create Purchase Order screen, but the UDF value does not copy to POLine. Are you able to help me review and see what I’m missing and if the changes I made is appropriate, please? Thank you in advance! 

 

I was not able to get it working using the SOOrderEntry graph extension, I created a POOrderEntry graph extension and copied the below code, it is the same one that ​@TharidhiP shows in the last screenshot, except I got a couple errors and had to remove [PXOverride] and change SOLineSplit3 to SOLineSplit: 

namespace PX.Objects.PO
  {
  public class POOrderEntry_Extension : PXGraphExtension<PX.Objects.PO.POOrderEntry>
  {
  public delegate POLine FindOrCreatePOLineDelegate(POOrderEntry docgraph, DocumentList<POLine> ordered, String orderType, POFixedDemand demand, SOLineSplit soline);
public POLine FindOrCreatePOLine(
    POOrderEntry docgraph,
    DocumentList<POLine> ordered,
    String orderType,
    POFixedDemand demand,
    SOLineSplit soline,
    FindOrCreatePOLineDelegate baseMethod
)
{
    // Call the base method to get or create the POLine
    POLine poLine = baseMethod(docgraph, ordered, orderType, demand, soline);
    if (poLine != null && soline != null)
    {
        // Fetch the associated SOLine using its line reference
        SOLine soLine = PXSelect<SOLine,
                            Where<SOLine.orderType, Equal<Required<SOLine.orderType>>,
                                And<SOLine.orderNbr, Equal<Required<SOLine.orderNbr>>,
                                And<SOLine.lineNbr, Equal<Required<SOLine.lineNbr>>>>>>
                            .Select(docgraph, soline.OrderType, soline.OrderNbr, soline.LineNbr);
        if (soLine != null)
        {
            // Retrieve the extensions
            var soLineExt = PXCache<SOLine>.GetExtension<SOLineExt>(soLine);
            var poLineExt = PXCache<POLine>.GetExtension<POLineExt>(poLine);
            if (soLineExt != null && poLineExt != null)
            {
                // Map the custom fields from SOLine to POLine
                poLineExt.UsrQuoteCost= soLineExt.UsrQuoteCost;
            }
        }
    }
    return poLine;
}
  }
  }


Forum|alt.badge.img+1
  • Jr Varsity III
  • November 3, 2025

Hi ​@jzhu ,
  Write same logic this delegate also hope it will work.
public delegate POOrder FindOrCreatePOOrderDelegate(DocumentList<POOrder> created, POOrder previousOrder, POFixedDemand demand, SOOrder soorder, SOLineSplit3 soline, Boolean requireSingleProject);
        [PXOverride]
        public POOrder FindOrCreatePOOrder(DocumentList<POOrder> created, POOrder previousOrder, POFixedDemand demand, SOOrder soorder, SOLineSplit3 soline, Boolean requireSingleProject, FindOrCreatePOOrderDelegate baseMethod)
        {
            // Call the base method to get or create the POOrder
            POOrder pOOrder = baseMethod(created, previousOrder, demand, soorder, soline, requireSingleProject);
            // If a POOrder was created or retrieved
return pOOrder;
        }


Forum|alt.badge.img
  • Semi-Pro III
  • November 3, 2025

Hi ​@noorula77 I realize I should have created the graph extension on POCreate instead of POOrder. The original code worked. Thank you for responding!

A related question, do you know if there is a way to pass a UDF value from the SOLine to an Acumatica field in Create Purchase Order screen and POLine? We have UsrQuoteCost and UsrVendor created on SOLine. The ask is that vendor should be pulled from UsrVendor from SOLine, not item default vendor. And PO cost should be pulled from UsrQuoteCost on SOLine, not the default inventory valuation cost. 

Do you know how I can copy these values to the acumatica fields on POCreate and POLine?


Forum|alt.badge.img+1
  • Jr Varsity III
  • November 3, 2025

Hi ​@jzhu ,
                 Use the same delegate mentioned above to pass the value. If you pass the value in your existing code, it will work.


Forum|alt.badge.img
  • Semi-Pro III
  • November 3, 2025

Hi ​@noorula77 Thank you, I was able to successfully get the UDF value from SOLine to pass to an acumatica field on POLine using the same delegate I had above.

The issue I am encountering is I want to pass a UDF vendor field from SOLine to the Vendor field in Create Purchase Order screen. In the current process, vendor field on Create Purchase Order screen is pulled from the preferred vendor on the item record, then this vendor field is used in the Purchase Order header level. 

I need the vendor field on Create Purchase Order screen to pull from my UsrVendorId field on SOLine. Below is the section of code I tried for this specific need, while it published successfully, nothing is showing up in the vendor field, what should I adjust here? Thank you!

 #region Event Handlers
    public delegate POOrder FindOrCreatePOOrderDelegate(DocumentList<POOrder> created, POOrder previousOrder, POFixedDemand demand, SOOrder soorder, SOLineSplit3 soline);
    [PXOverride]
    public POOrder FindOrCreatePOOrder(DocumentList<POOrder> created, POOrder previousOrder, POFixedDemand demand, SOOrder soorder, SOLineSplit3 soline, FindOrCreatePOOrderDelegate baseMethod)
    {
           if (soline != null)           
    {
                      // Fetch the SOLine to read UsrVendor
                SOLine soLine = PXSelect<SOLine,
                    Where<SOLine.orderType, Equal<Required<SOLine.orderType>>,
                      And<SOLine.orderNbr, Equal<Required<SOLine.orderNbr>>,
                      And<SOLine.lineNbr, Equal<Required<SOLine.lineNbr>>>>>>
                    .Select(Base, soline.OrderType, soline.OrderNbr, soline.LineNbr);      
           if (soLine != null)
                {
                    var soLineExt = PXCache<SOLine>.GetExtension<SOLineExt>(soLine);            
                    if (!string.IsNullOrEmpty(soLineExt?.UsrVendor))
                    {
                        // Lookup Vendor by AcctCD
                        Vendor vendor = PXSelect<Vendor,
                            Where<Vendor.acctCD, Equal<Required<Vendor.acctCD>>>>
                            .Select(Base, soLineExt.UsrVendor);

                        if (vendor != null)
                        {
                            demand.VendorID = vendor.BAccountID;      
                        }
                    }
                }
            }
      POOrder pOOrder = baseMethod(created,previousOrder,demand,soorder,soline);
              
      return pOOrder;
    }
    #endregion


Forum|alt.badge.img
  • Semi-Pro III
  • November 4, 2025

@noorula77 Just wanted to thank you for your help! We figured out how to pass value from a UDF field on SOLine to the Vendor ID field on Create Purchase Order screen, here is the code we use:

  #region Event Handlers

  protected void POFixedDemand_RowSelected(PXCache cache, PXRowSelectedEventArgs e)
        {
            var row = (POFixedDemand)e.Row;
            if (row == null) return;

            // Ensure it's linked to a Sales Order Line
            if (row.OrderType == null || row.OrderNbr == null || row.LineNbr == null)
                return;

            // Always get the Vendor from the originating SOLine
            SOLine soLine = SOLine.PK.Find(Base, row.OrderType, row.OrderNbr, row.LineNbr);
            if (soLine == null)
                return;

            var soLineExt = soLine.GetExtension<SOLineExt>();

            if (soLineExt?.UsrBUYSELLMANUFACTURER != null)
            {
                 // Custom behavior: use Vendor from Sales Order line
                cache.SetValueExt<POFixedDemand.vendorID>(row, soLineExt.UsrBUYSELLMANUFACTURER);
            }
            else
            { 
               // Do nothing — let the base Acumatica logic handle vendor selection
               // (This will pull the preferred vendor from the item automatically)      
        }

    }
    #endregion