Use Case
It might be necessary to override the Convert To Order action in the Sales Quotes and Opportunities screens to modify a logic of copying or to copy a line custom field value from a Sales Quote or Opportunity lines to Sales Order lines.
Solution
Create Sales Order action is present in both Opportunities and Sales Quotes screen. And it has been separated logically to a different class CRCreateSalesOrder and is being extended and utilized from both OpportunityMaint and QuoteMaint. In this article, we will understand how CRCreateSalesOrder extension can be extended to create sales order.
Overriding Copy Sales Quote code to Sales Order
In this example, we are trying to extend CRCreateSalesOrderExt graph extension of the QuoteMaint graph in order to fill PO Source = Drop Ship in Sales Order lines where the corresponding Sales Quote line has Mark for PO checked (by default, PO Source is filled as Purchase to Order in a sales order line in this case)
The below code adds RowUpdated event handler to SOLine cache within which we are overriding the PO Source of sales order lines created in this process.
public class QuoteMaintCRCreateSalesOrderExt : PXGraphExtension<PX.Objects.CR.QuoteMaint.CRCreateSalesOrderExt,
QuoteMaint>
{
public delegate void DoCreateSalesOrderDelegate();
[PXOverride]
public void DoCreateSalesOrder(DoCreateSalesOrderDelegate baseMethod)
{
SOOrderEntry SOGraph = PXGraph.CreateInstance<SOOrderEntry>();
PXGraph.InstanceCreated.AddHandler(delegate (SOOrderEntry graph)
{
graph.RowUpdated.AddHandler<SOLine>(delegate (PXCache sender, PXRowUpdatedEventArgs e)
{
SOLine objSOLine = e.Row as SOLine;
if (objSOLine != null)
{
foreach (CROpportunityProducts item in
PXSelect<
CROpportunityProducts,
Where<
CROpportunityProducts.quoteID, Equal<Current<PX.Objects.CR.Extensions.CRCreateSalesOrder.Document.quoteID>>,
And<CROpportunityProducts.sortOrder, Equal<Required<CROpportunityProducts.sortOrder>>>>>
.Select(Base, objSOLine.SortOrder))
{
if (item.POCreate == true)
{
sender.SetValueExt<SOLine.pOCreate>((object)objSOLine, true);
sender.SetValueExt<SOLine.pOSource>((object)objSOLine, "D");
}
}
}
});
});
baseMethod();
}
}
Copy custom fields from Opportunities (OpportunityMaint) to Sales Order
-
As the logic to creating a sales order from Opportunities lies in CRCreateSalesOrder and a graph extension – CRCreateSalesOrderExt which lies inside OpportunityMaint, you need to create a second-level graph extension - CRCreateSalesOrderExt_extension like this:
public class CRCreateSalesOrderExt_Extension : PXGraphExtension<OpportunityMaint.CRCreateSalesOrderExt, OpportunityMaint> { [PXOverride] [PXUIField()] [PXButton] public virtual IEnumerable createSalesOrder(PXAdapter adapter, Func<PXAdapter, IEnumerable> baseMethod) { //return baseMethod.Invoke(adapter); Customer customer = PXSelect< Customer, Where< Customer.bAccountID, Equal<Current<Document.bAccountID>>>> .SelectSingleBound(Base, new object[] { Base1.DocumentView.Current }); if (customer == null) { throw new PXException(Messages.ProspectNotCustomer); } if (Base1.CreateOrderParams.AskExtFullyValid((graph, viewName) => { }, DialogAnswerType.Positive)) { Base.Actions.PressSave(); //var graph = Base.CloneGraphState(); PXLongOperation.StartOperation(Base, delegate () { Base1.DoCreateSalesOrder(); }); } return adapter.Get(); } }
-
Add a custom field (example: UsrCustomField) by creating an extension to CROpportunity DAC.
public class CROpportunityExt1 : PXCacheExtension<PX.Objects.CR.CROpportunity> { #region UsrCustomField [PXString] [PXUIField(DisplayName = "Custom Field")] [PXDefault("Default")] public virtual string UsrCustomField { get; set; } public abstract class usrCustomField : PX.Data.BQL.BqlString.Field<usrCustomField> { } #endregion }
-
Inside the CRCreateSalesOrderExtension, we need to override the createSalesOrder action – and enclose the logic from original action to execute the creation of a sales order and add the below logic inside the PXLongOperation before actually calling the DoCreateSalesOrder method to pass the custom field to SOOrder:
PXGraph.InstanceCreated.AddHandler<SOOrderEntry>(graph1 => { graph1.RowUpdated.AddHandler<SOOrder>((cache, e) => { //CROpportunity opportunity = new CROpportunity(); //CROpportunity opportunity = PXSelect<CROpportunity>.SelectSingleBound(Base, new object[] { Base.Opportunity.Current }); CROpportunityExt1 oppExt = PXCache<CROpportunity>.GetExtension<CROpportunityExt1>(Base.Opportunity.Current); string oppur = oppExt.UsrCustomField; SOOrder soorder = (SOOrder)e.Row; //soorder.OrderDesc += " test "; if (soorder != null) { if (soorder.OrderDesc != null) { if (!soorder.OrderDesc.ToString().Contains(oppur)) soorder.OrderDesc += oppur; // add logic here } } }); });
The above logic will add RowUpdated event to SOOrder within which we are accessing the custom field from the Current object and append it to the Description of a Sales Order as an example