How do I add an action and handler to the Process Shipments screen? We want to add an action to the Action combobox on screen SO503000, and then add a handler in code to process the new action. We want to do this without having to override the huge switch/case statement for Action in the SOShipmentEntry graph.
The PXAutomationMenu attribute pulls from Automation Steps all actions, which have appropriate processing screen set up as Mass Processing Screen:
To extend the list of actions available on the Process Shipments screen, please proceed as follows:
Declare custom action within a BLC extension and invoke AddMenuAction method during BLC initialization to add it as a drop-down item for the Actions button
To add custom action to the Process Shipments screen, add custom actions to appropriate automation step(s) and specify Mass Processing Screen ID. When user selects your custom action, Shipments from all Automations Steps, that contain a custom action, will be available for selection on the Process Shipments screen:
Two extensions (of the same 1st level) declared for the SOShipmentEntry BLC, as shown in the code snippet below, can be used to extend Actions drop-down with multiple customization projects (two customization packages that are independent of each other; either one or both may be published on a particular site. And both add an action to the Process Shipments screen):
To address this scenario, :
public class SOShipmentEntryExt1 : PXGraphExtension<SOShipmentEntry>
{
public PXAction<SOShipment> Test1;
[PXButton]
[PXUIField(DisplayName = "Test Action 1")]
protected void test1()
{
throw new PXException("Not implemented action: {0}", "Test Action 1");
}
public override void Initialize()
{
Base.action.AddMenuAction(Test1);
}
}
public class SOShipmentEntryExt2 : PXGraphExtension<SOShipmentEntry>
{
public PXAction<SOShipment> Test2;
[PXButton]
[PXUIField(DisplayName = "Test Action 2")]
protected void test2()
{
throw new PXException("Not implemented action: {0}", "Test Action 2");
}
public override void Initialize()
{
Base.action.AddMenuAction(Test2);
}
}
Related
I would like to add a custom action to the Bills and Adjustments (AP301000) screen which navigates to a report. I want to add the action to the special folder in acumatica (action menu) as shown on screenshot 1 where the red line is.
Screenshot 1: Action Menu
Below code is used to add the action to the menu
public class APInvoiceEntry_Extension : PXGraphExtension<PX.Objects.AP.APInvoiceEntry>
{
public override void Initialize()
{
base.Initialize();
//this added the report to the reports menu
Base.report.AddMenuAction(SupplierInvoice);
}
public PXAction<PX.Objects.AP.APInvoice> SupplierInvoice;
[PXButton(CommitChanges = true)]
[PXUIField(DisplayName = "Supplier Invoice")]
protected void supplierInvoice()
{
if (Base.Document.Current.RefNbr != string.Empty)
{
//create parameters for report! Check report by editing it to see what reports are needed
Dictionary<string, string> parameters = new Dictionary<string, string>();
parameters["RefNbr"] = Base.Document.Current.RefNbr.ToString();
parameters["DocType"] = Base.Document.Current.DocType;
//the report number gets set below and parameters are sent with
throw new PXReportRequiredException(parameters, "AP641500");
}
}
}
}
The error which I get is shown in below screenshot
Screenshot 2: Code error
The issue I encountered is that the report folder for the Bills and Adjustments (AP301000) screen in the screen editor of the customization does not the Layout Properties as shown in the screenshot below:
Screenshot 3: Bill and Adjustments (AP301000) Screen Editor
The Acumatica Version I am currently using is: 22.101.0085
How could I possibly fix the error in order to add the action in the action menu of the screen?
You can apply a Category to the action that should position it correctly in the category:
public override void Initialize()
{
base.Initialize();
SupplierInvoice.SetCategory("Reports");
}
I'm trying to display a warning every time the ShippedQty field is changed to a value < OrigOrderQty on the "Shipment - SO302000" screen, but I only want the code to be active for that specific screen/form.
I added the code below to extend the SOShipmentEntry graph, which accomplishes my original goal, but the issue is that now the code I added is also being used by the "Create Shipment" action in "Sales Orders - SO301000" screen/form.
Create Shipment Action Discussed
namespace PX.Objects.SO
{
public class SOShipmentEntry_Extension : PXGraphExtension<SOShipmentEntry>
{
#region Event Handlers
protected void SOShipLine_ShippedQty_FieldUpdated(PXCache cache,PXFieldUpdatedEventArgs e)
{
var myrow = (SOShipLine)e.Row;
if (myrow == null) return;
if (myrow.ShippedQty >= myrow.OrigOrderQty)
{
}
else
{
throw new PXSetPropertyException("The difference between the shipped-qty and the ordered-qty will be placed on a back-order", PXErrorLevel.Warning);
}
}
#endregion
}
}
While the warning allows the user to save changes to a shipment on the Shipment Screen/form SO302000 (Because the exception is set up as a warning and not an error), I get the following error when I create a shipment using the "Create Shipment" button on the "Sales Orders - SO301000" screen.
Warning works fine for form-mode
Warning becomes error when processed in background by action button
Any ideas to accomplish this? It is my understanding that if I want to make global changes to a field I must make them in the DAC, but if I want to make changes that only affect screens/forms where a graph is used, then I have to make those changes in the graph code itself. I'm guessing the "Create Shipment" action button in the Sales Orders screen is creating an instance of the graph where I added the code, so I'm wondering what are my options here.
Best regards,
-An Acumatica newbie
If you want your event logic to execute only when CreateShipment is invoked from the Shipment screen you can override the other calls to CreateShipment to dynamically remove your event handler.
The event that invokes CreateShipment action from the SalesOrderEntry graph is Action:
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
)
In that method it creates a SOShipmentEntry graph to create the shipment. You can override Action and remove your handler from that graph instance:
SOShipmentEntry docgraph = PXGraph.CreateInstance<SOShipmentEntry>();
// >> Remove event handler
SOShipmentEntry_Extension docgraphExt = docgraph.GetExtension<SOShipmentEntry_Extension>();
docgraph.FieldUpdated.RemoveHandler<SOShipLine.shippedQuantity>(docgrapExt.SOShipLine_ShippedQty_FieldUpdated);
// << Remove event handler
docgraph.CreateShipment(order, SiteID, filter.ShipDate, adapter.MassProcess, operation, created);
Note that in order to reference SOShipLine_ShippedQty_FieldUpdated method from another graph you'll have to make it public:
public void SOShipLine_ShippedQty_FieldUpdated(PXCache cache,PXFieldUpdatedEventArgs e)
I have described how to do this in that answer too:
Updating custom field is ending into infinite loop
If you want your event logic to execute only when it is modified in the UI or by web service.
You can use the ExternalCall Boolean property of the PXFieldUpdatedEventArgs parameter.
This property value will be true only when the sender field is modified in the UI or by web service.
Usage example:
protected void SOShipLine_ShippedQty_FieldUpdated(PXCache cache,PXFieldUpdatedEventArgs e)
{
// If ShippedQty was updated in the UI or by a web service call
if (e.ExternalCall)
{
// The logic here won't be executed when CreateShipment is invoked
}
}
ExternalCall Property (PXFieldUpdatedEventArgs)
Gets the value specifying whether the new value of the current DAC field has been changed in the UI or through the Web Service API.
I would like to override the standard method of the RowSelected event on the Service Orders screen. Specifically, the DocDesc field gets populated when you select a row item for the Labor tab. It will set the TranDesc to the DocDesc and I would like to keep this from happening. I am using Acumatica 6.1 which means that the Service Management Module is not standard in Acumatica during this time. I would like the method that populates this field to not run when the labor line is populated, so the DocDesc field would remain null or blank, this way the user can input their own description.
You should be able to customize the ServiceOrderEntry graph like any other graph :
protected virtual void FSServiceOrder_RowSelected(PXCache sender, PXRowSelectedEventArgs e, PXRowSelected bs)
{
...
}
See https://help.acumatica.com/(W(3))/Main?ScreenId=ShowWiki&pageid=4a05d4c2-cd8b-4131-bf3b-d05861de3ae6
You could override the method if it is virtual, like this :
public delegate void PersistDelegate();
[PXOverride]
public void Persist(PersistDelegate baseMethod)
{
...
baseMethod();
...
}
See https://help.acumatica.com/(W(3))/Main?ScreenId=ShowWiki&pageid=635c830e-4617-4d5c-9fa5-035952311aa9
You could also modify the base customization, but since you are not the owner it could get difficult to maintain and track the changes.
I am trying to customise an Acumatica Processing Page by adding my own processing button. I have tried the usual methods of extending the processing page but unfortunately the button is not displayed on the page.
public class APPrintChecks_Extension : PXGraphExtension<APPrintChecks>
{
public PXAction<APPayment> Test;
[PXProcessButton]
[PXUIField(DisplayName = "Button Test")]
protected virtual IEnumerable test(PXAdapter adapter)
{
return adapter.Get();
}
}
I do not want to override the existing functionality provided by the processing button and as such would like to add my own.
Thanks.
The primary view of the Process Payments / Print Checks page is Filter which is of type PrintChecksFilter. So you need to have your PXAction on that Type. Try to replace
public PXAction<APPayment> Test;
with
public PXAction<PrintChecksFilter> Test;
We're using the Run Project Billing screen to create records in AR / Invoice and Memo.
In the Invoice & Memo screen, we need the process to populate the header Customer Ord. number, along with a user field that has been added to the grid section on the 'Document Details' tab. At the moment, the process is not doing this.
I'd like to intercept the processing action on the screen using a technique I'm familiar with, namely using an 'AddHandler':
[PXOverride]
protected virtual IEnumerable Items (PXAdapter adapter)
{
PXGraph.InstanceCreated.AddHandler<BillingProcess>((graph) =>
{
graph.RowInserting.AddHandler<BillingProcess.ProjectsList>((sender, e) =>
{
//Custom logic goes here
});
});
return Base.action.Press(adapter);
}
I see no Base.Actions that remotely resembles 'Bill' or 'Bill All'.
This is obviously not exactly the code I need, but I would think this is the general place to start.
After reviewing the source business logic, I don't see any 'Bill' or 'Bill All' Actions - or any 'Actions' at all (baffling). I see an IEnumerable method called 'items', so that's what I started with above.
Is this the correct way to go about this?
Update: 2/14/2017
Using the answer provided re: the overridden method InsertTransaction(...) I've tried to set our ARTran user field (which is required) using the following logic:
PMProject pmproj = PXSelect<PMProject, Where<PMProject.contractID, Equal<Required<PMProject.contractID>>>>.Select(Base, tran.ProjectID);
if (pmproj == null) return;
PMProjectExt pmprojext = PXCache<PMProject>.GetExtension<PMProjectExt>(pmproj);
if (pmprojext == null) return;
ARTranExt tranext = PXCache<ARTran>.GetExtension<ARTranExt>(tran);
if (tranext == null) return;
tranext.UsrContractID = pmprojext.UsrContractID;
Even though this sets the user field to the correct value, it still gives me an error that the required field is empty when the process finishes. My limited knowledge prevents me from understanding why.
On the Run Project Billing screen, captions of Process and Process All buttons were changed to Bill and Bill All respectively in BLC constructor.
Process delegate is set for Items data view within the BillingFilter_RowSelected handler:
public class BillingProcess : PXGraph<BillingProcess>
{
...
public BillingProcess()
{
Items.SetProcessCaption(PM.Messages.ProcBill);
Items.SetProcessAllCaption(PM.Messages.ProcBillAll);
}
...
protected virtual void BillingFilter_RowSelected(PXCache cache, PXRowSelectedEventArgs e)
{
BillingFilter filter = Filter.Current;
Items.SetProcessDelegate<PMBillEngine>(
delegate (PMBillEngine engine, ProjectsList item)
{
if (!engine.Bill(item.ProjectID, filter.InvoiceDate, filter.InvFinPeriodID))
{
throw new PXSetPropertyException(Warnings.NothingToBill, PXErrorLevel.RowWarning);
}
});
}
...
}
As code snippet above confirms, all records in the AR Invoice and Memos screen are created by instance of the PMBillEngine class. Below is code snippet showing how to override InsertNewInvoiceDocument and InsertTransaction methods within the PMBillEngine BLC extension:
public class PMBillEngineExt : PXGraphExtension<PMBillEngine>
{
public delegate ARInvoice InsertNewInvoiceDocumentDel(string finPeriod, string docType, Customer customer,
PMProject project, DateTime billingDate, string docDesc);
[PXOverride]
public ARInvoice InsertNewInvoiceDocument(string finPeriod, string docType, Customer customer, PMProject project,
DateTime billingDate, string docDesc, InsertNewInvoiceDocumentDel del)
{
var result = del(finPeriod, docType, customer, project, billingDate, docDesc);
// custom logic goes here
return result;
}
[PXOverride]
public void InsertTransaction(ARTran tran, string subCD, string note, Guid[] files)
{
// the system will automatically invoke base method prior to the customized one
// custom logic goes here
}
}
Run Project Billing process invokes InsertNewInvoiceDocument method to create new record on the AR Invoice and Memos screen and InsertTransaction method to add new invoice transaction.
One important thing to mention: overridden InsertNewInvoiceDocument and InsertTransaction methods will be invoked when a user launches Run Project Billing operation either from the processing Run Project Billing screen or from the data entry Projects screen.
For more information on how to override virtual BLC methods, see Help -> Customization -> Customizing Business Logic -> Graph -> To Override a Virtual Method available in every Acumatica ERP 6.1 website