Have you wanted to customize the SO Process orders screen? Notice that many actions found here are shared in the Sales Order entry screen. How are these actions linked between the two screens? Our goal today is to explore the relationship between these screens, and how these actions are invoked from the processing screen.
In the screen Process Orders (SO501000), we find similar selections in the Action drop-down, as found in the Sales Order entry screen (SO301000). For example, Create Shipment and Cancel Order actions are found on both screens. Using the code inquiry tool, we can open the graph file which powers the sales order entry screen – SOOrderEntry.cs. Upon inspection, we notice members such as:
Before we continue, there is an interesting history of Acumatica pre-version 2017. In those versions, the workflows of standard document lifecycles such as Sales Order, Purchase Order, Invoices, etc, were defined using Automation Workflows. Each lifecycle was defined internally with an ugly XML file, which defined document & field states, menu actions, reports, and values. Acumatica allowed the developer to modify the XML file to override the default workflow. In addition, an automation workflow menu assisted the developer with creating these alterations via a separate screen (which still exists). It certainly made the job easier but was not a great help to learn about the link between the processing screen actions and the document entry screen.
With the code browser, it’s easier to learn how the actions are shared between the screens.
Upon first look at the graph SOCreateShipment.cs, we notice several members of the class
- Orders data view
- RowSelected event
- RowUpdated event
But notice there are no natural named types for our actions drop-down? Should we expect to see named members for each one of these actions in the graph?
Let’s remember one of the pillars of object-oriented programming – encapsulation. As we can infer, it is not good practice to define the contents of each action, repeatedly, on both screens.
So as we look at the graph code, notice the data view Orders. This data view is of type PXFilteredProcessing, which inherits from PXProcessingBase. PXProcessing class defines the PXView, to form the selection criteria of our records. Notice in the custom constructor for the Records dataview passes the Filter.Owner ID field, in order to append the OuterView Where criteria of the data view. This is used to help select records in which the current user has ownership of the Contact record.
A typical design pattern for processing screens is to define the processing delegate in the graph constructor. In our case, we do not see this. Further down the graph code, notice the RowSelected event.
Several Acumatica processing screens use the Filter RowSelected event to invoke a data process delegate. For example, we see this in the screen Release Retainage (AR510000).
In that case, the SetProcessDelegate is more obvious. But what about our sales order processing screen? Return to the SOProcessFilter RowSelected event. SetProcessWorkflowAction is a member of PXProcessingBase. Let’s use our a reflector tool in order to explore this member.
We find some interesting statements within this method. In particular, there are some variables set in the body of this method to notice
We have a way to learn what the screen Id and action name is, the ProcessOrder graph, during the RowSelected event. Notice the Action type is S0301000$PrepareInvoice (in this case, we chose the Prepare Invoice action in the processing screen).
Upon further investigation of the details of method SetProcessWorkflowAction, notice a call to a deeper method named _SetProcessTargetInternal. What we discover is the code that creates screen and menu variables by splitting the Action variable along with the $ character. This is important since they are used further down the method, to invoke workflow automation, specifically by screen and action ID.
The code goes quite deeper than this method, but eventually, the link between the screen SO301000 and graph SOOrderEntry is established in the graph. Later the action is invoked in a batch.
If you are curious about the storage of this relation, check out table AUDefinitionDetail:
In this post, we have explored the graphs for the Process Orders screen. We investigated the Actions member. By using a reflector tool, we discovered the screen ID and the Action name is intercepted deep in members of the PXProcessBase class, in order to invoke the actions in the sales order entry screen.
I hope that you have found this useful – and always – Happy Coding!