Can you use both SalesOrder.Update and MasterUpdate in a method directive BPM?

Elsewhere I have described building my first BPM.

Now I have a working solution for sales orders created manually or via DMT (Sales Order Combined). A pre-proc method directive that enables a post-proc.

However, it turns out we have a service connect implementation for online orders and after a lot of digging have found that it uses SalesOrder.MasterUpdate. I don’t understand it enough to be certain but this seems to preclude the method directives based on SalesOrder.Update.

Can I call the directive built in Update from a trigger in MasterUpdate? Or something like that?

Or do I need to do something separate for the two types of orders? I’ve tried to read up on this but haven’t found an answer.

SalesOrder.MasterUpdate performs a number of “pre-checks” before it ultimately calls Update. The MasterUpdate method was added to improve the overall UI performance experience so instead of having the UI make numerous calls to the Server and then call Update, the MasterUpdate method does the work on the Server.

Your BPM on Update should still be fired but depending on what you are doing, you may need to adjust it.

Epicor ERP Trivia - the Sales Order BO was the first one to receive this special save method and is the only BO with a MasterUpdate method name. All the other BOs that also had this technique applied have a method called UpdateMaster. Why? Because alphabetically Update and UpdateMaster sort out together and it is obvious to see that there is an UpdateMaster method on the BO without having to scroll the list of Methods.


Wouldn’t it be cool if there was a method called SalesOrder.UpdateMaster that was exactly the same as today’s SalesOrder.MasterUpdate? Then SalesOrder.MasterUpdate could simply call SalesOrder.UpdateMaster for backward compatability, but the new method would be more in line with all the other BOs! :grin:

@Rich, thanks so much for your help on everything. I have always greatly appreciated it.

1 Like

Ah, ok. So does that mean if my BPM on Update relies on a new or changed row, there won’t be one - having already been committed to DB by MasterUpdate?

And if so, what might I put into my Update BPM to catch a newly-entered order?

Appreciate both of your help @Rich and @Jason_Woods. I might have missed out on the last 10 years of Epicor but looks like I’m in for the long haul :slight_smile:

MasterUpdate calls Update from within itself. Update is “safe enough” as it will catch most uses and requires less variables.

Correct. MasterUpdate does the actual DB update via the Update method and I expect that you would still be able to trigger on a new row.

I’m losing my mind… My BPM on Update works for everything except the service connect orders, and they have a BPM on MasterUpdate…

What could be causing Update to miss these orders? And is there any way to put a pre-proc on MasterUpdate that triggers a post on Update?

Yes. In Pre-Processing, do your conditions and add an “Enable Post-Processing” widget.
In Post-Processing, your condition would be “Enabled from XYZ directive” (or something close).

There may be more going on here, but try the scenario above first. It is actually the correct way to update the OrderRel.

Yes, I have that working within a Given directive.

What I’m really asking is whether a pre-processing in salesorder.masterupdate can enable or call a post-processing directive in salesorder.update?

Or am I missing something within masterupdate that is somehow keeping salesorder.update from acting?

I don’t think so. I doubt it’s available in the condition.

In the Before on MasterUpdate set a BPMData Checkbox field and then in Post Processing on Update use the Checkbox in a Condition. Remember that BPMData does persist from call to call when used with the Epicor Smart Client so you should reset your checkbox in the actions triggered by your Condition.

Service Connect typically has a different data pattern than the Smart Client so SC Initiated calls may not trigger your BPM Condition but if your SC Workflow is working, Update will be getting called.


Oh, interesting, thanks for that, I’ll give it a shot

Hello @Rich, is CallContextBPMData accessible elsewhere? or does “Call Context” mean it’s private to the instance?

The point of my question is this: I already know that in my system, “Many Waldos Have Been This Way Before”. Should I be worried about some other BPM using my “Checkbox01” in conflict? Or is it isolated within the current usage?

This system is a bit like:


You should be somewhat concerned - maybe use a Character Field instead of a Checkbox and then you can base the decision on the exact text you set in the Before on MasterUpdate and not just on True / False.

Long Boring Explanation:
The CallContext dataset is made up of several tables - the ones you are familiar with are ClientData and BPMData. While the CallContext tables are initialized by the Framework, there is very little management of those tables by the Epicor code. The ClientData is provided to give “context” about the Client UI and Environment calling the Server - things like: Type of Client; DLL name; UI Customization applied; Menu ID; etc. The BPMData table is a single record table provided by the Epicor Framework for you to use and with the exception of the BPM InfoPrompt forms, Epicor code does not do anything with BPMData.

Each UI Form has one instance of a CallContext dataset and that instance is passed to/from the Server for every method call made by the UI code. If you open Part Maintenance and Sales Order Entry, each UI has its own instance of a CallContext dataset - values set into the BPMData record on the Part Maint instance will not effect the BPMData record on the Sales Order instance. That said, it is entirely possible that both those UIs will call the same Method on the same BO and if that shared method has a BPM with a condition triggered by Checkbox01 which you configured for Part Maintenance, the condition could be inadvertently triggered by the method call from Sales Order if you had set Checkbox01 on that BPMData instance for some other reason.

The CallContext dataset is expected to be initialized by the Client and BPMData fields set in Client Customization are available on the Server and if changed / set on the Server the values are available in Client Customization. As there is only a Single instance of BPMData per UI, every method call that UI Form makes will transfer the same values to/from the Server regardless of how many different BOs and Methods a UI might call. The Scope of the CallContext dataset is for the lifetime of the UI Form and it is untouched by any of the standard Client Side events like Save, Delete, GetNew, or Refresh.

If the CallContext dataset is not initialized by the Client - non-Epicor Client, REST Call, etc. - the Server code will initialize a default instance. Assuming that the calling code ignores the CallContext dataset, the Scope of the CallContext dataset is for the life of the Server Method call.


Thanks a million for taking the time to put that down, not boring at all. Very helpful.

And yes, I’m very concerned, but have taken us from 4 showstoppers a day 12 months ago to about 1 per month, so getting somewhere.

Depending on what you are trying to do, you might consider a Data Directive instead, and have that directive look for the CallContextBPMData in order to see whether it’s used or not. Data Directives fire no matter what is updating the table.