I have to copy the custom field values from opportunity to sales order while converting the opportunity to sales order.
I have come across a sample code to pass custom field from sales order to shipment and I have tried to use the code for overriding the “create sales order” action.
The following code snippet I have used in OpportunityMaint extension class
public PXAction action;
[PXButton]
[PXUIField(DisplayName="Actions",MapEnableRights=PXCacheRights.Select,MapViewRights=PXCacheRights.Select)]
protected IEnumerable Action( PXAdapter adapter,
[PXIntList(new int[] {1,2,3}, new string[] {"Create Account","Create Sales order","Create Invoice"}),PXInt]
int? actionId,
[PXString]
string ActionName)
{
if(actionId == 2)
{
// Implement So Order row insert handler
}
return Base.Action.Press(adapter);
}
The piece of code is not triggering.
Looking forward for better solution to implement this option
Regards,
R.Muralidharan
You will need to override the CreateSalesOrder action. Below is a snippet of code where I had to push the opportunity down to the sales order.
public class OpportunityMaint_Extension : PXGraphExtension<OpportunityMaint>
{
public PXAction<CROpportunity> createSalesOrder;
[PXUIField(DisplayName = Messages.CreateSalesOrder, MapEnableRights = PXCacheRights.Update, MapViewRights = PXCacheRights.Select)]
[PXButton(ImageKey = PX.Web.UI.Sprite.Main.DataEntry)]
public virtual IEnumerable CreateSalesOrder(PXAdapter adapter)
{
PXGraph.InstanceCreated.AddHandler<SOOrderEntry>((graph) =>
{
graph.RowInserted.AddHandler<SOOrder>((cache, args) =>
{
var soOrder = (SOOrder)args.Row;
var soOrderExt = PXCache<SOOrder>.GetExtension<SOOrderExt>(soOrder);
foreach (CROpportunity opportunity in adapter.Get())
{
soOrderExt.UsrOpportunityID = opportunity.OpportunityID;
}
});
});
return Base.createSalesOrder.Press(adapter);
}
}
Related
I have a need to modify the behavior of the Create Sales Order action on the Opportunity screen.
I'm trying to find the best / least intrusive method possible. I have a snippet of the base code below.
The changes I need to make are relatively simple. I need to populate some custom fields that exist on new SO.
What's the best approach?
public PXAction<CROpportunity> createSalesOrder;
[PXUIField(DisplayName = Messages.CreateSalesOrder, MapEnableRights = PXCacheRights.Update, MapViewRights = PXCacheRights.Select)]
[PXButton(ImageKey = PX.Web.UI.Sprite.Main.DataEntry)]
public virtual IEnumerable CreateSalesOrder(PXAdapter adapter)
{
foreach (CROpportunity opportunity in adapter.Get<CROpportunity>())
{
Customer customer = (Customer)PXSelect<Customer, Where<Customer.bAccountID, Equal<Current<CROpportunity.bAccountID>>>>
.SelectSingleBound(this, new object[] { opportunity });
if (customer == null)
{
throw new PXException(Messages.ProspectNotCustomer);
}
if (CreateOrderParams.AskExtFullyValid((graph, viewName) => { }, DialogAnswerType.Positive))
{
Actions.PressSave();
PXLongOperation.StartOperation(this, delegate()
{
var grapph = PXGraph.CreateInstance<OpportunityMaint>();
grapph.Opportunity.Current = opportunity;
grapph.CreateOrderParams.Current = CreateOrderParams.Current;
grapph.DoCreateSalesOrder(CreateOrderParams.Current);
});
}
yield return opportunity;
}
}
protected virtual void DoCreateSalesOrder(CreateSalesOrderFilter param)
{
bool recalcAny = param.RecalculatePrices == true ||
param.RecalculateDiscounts == true ||
param.OverrideManualDiscounts == true ||
param.OverrideManualDocGroupDiscounts == true ||
param.OverrideManualPrices == true;
var opportunity = this.Opportunity.Current;
Customer customer = (Customer)PXSelect<Customer, Where<Customer.bAccountID, Equal<Current<CROpportunity.bAccountID>>>>.Select(this);
A simple override should accomplish your goal. Below is an example, which injects custom logic into the event handler SOOrder.RowInserted, during the Create Sales Order action. Then allow the action to finish normally. This approach extends the action with your custom logic, while retaining base code of the Action.
public class OpportunityMaint_Extension : PXGraphExtension<OpportunityMaint>
{
public delegate IEnumerable CreateSalesOrderDelegate(PXAdapter adapter);
[PXOverride]
public IEnumerable CreateSalesOrder(PXAdapter adapter, CreateSalesOrderDelegate baseMethod)
{
PXGraph.InstanceCreated.AddHandler<SOOrderEntry>((graph) =>
{
graph.RowInserted.AddHandler<SOOrder>((sender, e) =>
{
SOOrder order = (SOOrder)e.Row;
SOOrderExt orderExt = PXCache<SOOrder>.GetExtension<SOOrderExt>(order);
orderExt.UsrCustomOne = "Howdy"; //assign anything you want here
});
});
return baseMethod(adapter);
}
}
}
Hopefully this will be an easy question!
I've created a new report for the Acumatica Opportunity screen, and I'd like to add it to the screen itself. I've previously added a new report to the existing REPORTS dropdown, but I have not played with Automation Steps enough to create the REPORTS dropdown if it does not already exist.
Can someone provide instructions or point me in the direction of the appropriate documentation?
EDIT: So, what I'm running into is that the Opportunity doesn't have a Reports section already there to add to; I have to create it.
What I have so far gets a REPORTS button on the screen but it's not a dropdown and it doesn't appear to do anything.
public class OpportunityMaint_Extension : PXGraphExtension<OpportunityMaint>
{
#region Event Handlers
#endregion
#region Actions
public PXAction<CROpportunity> report;
[PXUIField(DisplayName = "Reports", MapEnableRights = PXCacheRights.Select)]
[PXButton(SpecialType = PXSpecialButtonType.Report)]
protected virtual IEnumerable Report(PXAdapter adapter,
[PXString(8, InputMask = "CC.CC.CC.CC")]
[PXStringList(new string[] { "IOCR6410" }, new string[] { "Quote" })]
string reportID)
{
List<CROpportunity> list = adapter.Get<CROpportunity>().ToList();
if (!String.IsNullOrEmpty(reportID))
{
Base.Save.Press();
int i = 0;
Dictionary<string, string> parameters = new Dictionary<string, string>();
foreach (CROpportunity opp in list)
{
if (reportID == "IOCR6410")
{
parameters["CROpportunity.OpportunityID" + i.ToString()] = opp.OpportunityID;
}
i++;
}
if (i > 0)
{
throw new PXReportRequiredException(parameters, reportID, string.Format("Report {0}", reportID));
}
}
return list;
}
#endregion
}
For this type of changes, it's better to not make changes in automation step(s), but follow the approach suggested in How to add report to Inventory Transfers dropdown menu for reports
Below is a slightly updated version of your code snippet, which should lead to the following result:
public class OpportunityMaint_Extension : PXGraphExtension<OpportunityMaint>
{
public override void Initialize()
{
Report.AddMenuAction(QuoteReport);
Report.MenuAutoOpen = true;
}
public PXAction<CROpportunity> Report;
[PXButton]
[PXUIField(DisplayName = "Reports", MapEnableRights = PXCacheRights.Select)]
protected void report()
{ }
public PXAction<CROpportunity> QuoteReport;
[PXButton]
[PXUIField(DisplayName = "Quote", MapEnableRights = PXCacheRights.Select)]
protected IEnumerable quoteReport(PXAdapter adapter)
{
var reportID = "IOCR6410";
List<CROpportunity> list = adapter.Get<CROpportunity>().ToList();
Base.Save.Press();
int i = 0;
Dictionary<string, string> parameters = new Dictionary<string, string>();
foreach (CROpportunity opp in list)
{
parameters["CROpportunity.OpportunityID" + i.ToString()] = opp.OpportunityID;
i++;
}
if (i > 0)
{
throw new PXReportRequiredException(parameters, reportID, string.Format("Report {0}", reportID));
}
return list;
}
}
I want to execute some code (to change the shipment date) upon the 'Confirm Shipment' action on the Shipments screen (SO302000).
I was thinking that this would be the way to do it:
public class SOShipmentEntryExt : PXGraphExtension<SOShipmentEntry>
{
[PXOverride]
public virtual void ConfirmShipment(SOOrderEntry docgraph, SOShipment shiporder)
{
Base.ConfirmShipment(docgraph, shiporder);
//Add my code to do something here...
}
}
When I try this, I get a shipment counter error. Is there a better way to do this?
From a similar case:
How to add custom business logic to Acumatica framework's Actions?
public class SOShipmentEntryExt : PXGraphExtension<SOShipmentEntry>
{
public PXAction<SOShipment> action;
[PXButton]
[PXUIField(DisplayName = "Actions", MapEnableRights = PXCacheRights.Select)]
protected IEnumerable Action(PXAdapter adapter
,[PXIntList(new int[] { 1 }
,new string[] { "Confirm Shipment" })
,PXInt] int? actionID)
{
//actionID = 1 means the Confirm Shipment action was the one invoked
if (actionID == 1)
{
Base.Document.Current.ShipDate = Base.Accessinfo.BusinessDate;
Base.Document.Update(Base.Document.Current);
}
//calls the basic action that was invoked
return Base.action.Press(adapter);
}
}
I added a custom field to SOShipment and I want to set its value when the CreateShipment action is invoked on Order Entry or through Process Orders screens. How do I do that ?
Create a graph extension for SOOrderEntry and add an Action method like this :
using PX.Data;
using System.Collections;
namespace PX.Objects.SO
{
public class SOOrderEntry_Extension : PXGraphExtension<SOOrderEntry>
{
public PXAction<SOOrder> action;
[PXUIField(DisplayName = "Actions", MapEnableRights = PXCacheRights.Select)]
[PXButton]
protected virtual IEnumerable Action(PXAdapter adapter,
[PXInt]
[PXIntList(new int[] { 1, 2, 3, 4, 5 }, new string[] { "Create Shipment", "Apply Assignment Rules", "Create Invoice", "Post Invoice to IN", "Create Purchase Order" })]
int? actionID,
[PXDate]
DateTime? shipDate,
[PXSelector(typeof(INSite.siteCD))]
string siteCD,
[SOOperation.List]
string operation,
[PXString()]
string ActionName)
{
//actionID = 1 means the CreateShipment action was the one invoked
if (actionID == 1)
{
PXGraph.InstanceCreated.AddHandler<SOShipmentEntry>((graph) =>
{
graph.RowInserting.AddHandler<SOShipment>((sender, e) =>
{
//Custom logic goes here
var shipment = (SOShipment)e.Row;
var shipmentExt = PXCache<SOShipment>.GetExtension<SOShipmentExt>(shipment);
if (Base.Document.Current != null && shipmentExt != null)
{
shipmentExt.UsrPriority = Base.Document.Current.Priority;
}
});
});
}
//calls the basic action that was invoked
return Base.action.Press(adapter);
}
}
}
When any of SOOrderEntry's actions is run (even through the Process Orders screen), this method is invoked. We verify that the action really is CreateShipment with the actionID == 1 and add events handler for SOShipmentEntry graph creation and SOShipment RowInserting. Our custom logic is added inside the RowInserting event.
When I do a custom logic before the APPROVE in requisition screen, it seems like the logic is triggered after. My code is as below.
public PXAction<RQRequisition> action;
[PXUIField(DisplayName = "Actions")]
[PXButton]
protected virtual IEnumerable Action(PXAdapter adapter,
[PXInt][PXIntList(new int[] { 1, 2 }, new string[] { "Approve", "Reject" })] int? actionID,
[PXBool]bool refresh,
[PXString]string actionName)
{
if (adapter.Menu == "Approve")
{
SIApprovalInfo.updateNextApprover(this.Base);
}
return Base.action.Press(adapter);
}
and I tried this action without calling the return Base.action.Press(adapter);
Sample code:
public PXAction<RQRequisition> action;
[PXUIField(DisplayName = "Actions")]
[PXButton]
protected virtual IEnumerable Action(PXAdapter adapter,
[PXInt][PXIntList(new int[] { 1, 2 }, new string[] { "Approve", "Reject" })]int? actionID,
[PXBool]bool refresh,
[PXString]string actionName)
{
if (adapter.Menu == "Approve")
{
SIApprovalInfo.updateNextApprover(this.Base);
}
return adapter.Get();
}
Still the document is getting approved somehow. So where exactly is this approval getting triggered? How can I add my custom logic before that action?
I suggest a workaround which would be the create your own action, add it to the menu and depending on your business logic, call the Approval. Here is the basic snippet you could use :
using PX.Data;
using System.Collections;
namespace PX.Objects.RQ
{
public class RQRequisitionEntry_Extension : PXGraphExtension<RQRequisitionEntry>
{
public override void Initialize()
{
Base.action.AddMenuAction(CustomApprove);
CustomApprove.SetEnabled(true);
}
public PXAction<RQRequisition> CustomApprove;
[PXButton]
[PXUIField(DisplayName = "Custom Approve")]
protected virtual IEnumerable customApprove(PXAdapter adapter)
{
PXCache cache = Base.Caches[typeof(RQRequisition)];
var requisition = Base.Document.Current;
if (Base.Approval.Approve(requisition))
{
requisition.Approved = true;
yield return Base.Document.Update(requisition); ;
}
else
{
throw new PXInvalidOperationException(PXLocalizer.Localize("Approval failed"));
}
}
}
}