BPM not triggered from BO Method call in another BPM

I have a situation where I want a BPM on the JobEntry.Update method to fire as a result of code running in a BPM on the Project.Update method.

I have four BPMs total. Pre and Post processing on both the JobEntry.Update and Project.Update methods.

JobEntry.Update
Pre-Processing: If JobOnHold_c is changed from false to true, enable post-processing BPM.
Post-Processing: Clear the JobEngineered flag, remove from schedule.

Project.Update
Pre-Processing: If ProjectOnHold_c is changed from false to true, enable post-processing BPM.
Post-Processing: Get the list of open and engineered jobs that are related to the project. Loop through them, setting JobOnHold_c to true, RowMod = U, and call the JobEntry.Update method.

Individually, both pairs of BPMs work as expected. However, the JobEntry.Update BPMs are not triggered when JobEntry.Update is called from the Project.Update BPM.

Is this normal behavior? I thought a BPM is executed on a method call no matter where it is called from. What am I missing? Let me know if I can provide any other info.

Project.Update BPM Code:

var project = ds.Project.FirstOrDefault();

if (project != null)
{
  var jobEntry = ServiceRenderer.GetService<Erp.Contracts.JobEntrySvcContract>(Db);
  
  var company = project.Company;
  var projectID = project.ProjectID;
  
  var jobNums = Db.JobHead.Where(job => job.Company == company && job.ProjectID == projectID && !job.JobClosed && !job.JobComplete && job.JobEngineered).Select(job => job.JobNum).ToList();
  
  foreach (var jobNum in jobNums)
  {
    var jobDS = jobEntry.GetByID(jobNum);
    var jobHead = jobDS.JobHead.First();
    
    jobHead["JobOnHold_c"] = true;
    jobHead.RowMod = "U";
    
    jobEntry.Update(ref jobDS);
  }
}

To clarify, the above code does run successfully (JobOnHold_c is set to true), but the BPM attached to the JobEntry.Update method (that I am calling in this code) does not.

Thanks

I was able to make this work by moving the widgets from JobEntry.Update Post-Processing BPM to a function, and calling the function from the BPM.

I don’t think that should be necessary, but that is my workaround.

Epicor is increasingly often using the format of “original row / modified row” in the dataset to determine changes. If BPMs are trying to execute based on a condition such as “this field has been changed from any to another”, those conditions are likely being evaluated based on the “original row / modified row” paradigm. I suppose Epicor is doing this to save a database lookup for REST call performance to quickly do a differential in memory to evaluate what has changed.

Here’s an example of a simple update to a quote header which does respect the original row / modified row paradigm and triggers BPMs using those conditions on Quote.Update:


this.CallService<Erp.Contracts.QuoteSvcContract>(hQuote => {
    Erp.Tablesets.QuoteTableset qds = new Erp.Tablesets.QuoteTableset();
    qds = hQuote.GetByID(this.quoteNum);
    var quoteHed = qds.QuoteHed.FirstOrDefault();
    var quoteHedNew = qds.QuoteHed.NewRow();
    BufferCopy.Copy(quoteHed, quoteHedNew);
    qds.QuoteHed.Add(quoteHedNew);
    quoteHedNew["MyFieldToUpdateHere"] = this.MyFieldValueParameter;
    quoteHedNew.RowMod = "U";
    hQuote.Update(ref qds);
});

In a BPM for Job Entry, you’ll just want to replace the this.CallService line with using(Erp.Contracts.JobEntrySvcContract hJobEntry = Ice.Assemblies.ServiceRenderer.GetService<Erp.Contracts.JobEntrySvcContract>(Db, true))

1 Like