Data Directive

When I run the Production Yield Recalculation I want to send an email per job detailing:

  1. JobNum
  2. Previous ProdQty
  3. New Prod Qty

When I code this in a Standard Directive I cannot grab the previous ProdQty because it has already changed.

Is there a way I can grab it in an In-Transaction Directive and pass it to the Standard Directive for each Job one at a time.

Roberto.

Give BPM Data a try. You can set the BPM Fields in both directive types, you will need to see if they pass through. Be sure to clear the data right after assigning it.

For in-trans directives, there’s a block called “enable standard directive”. You can use one of those in your in-trans directive, then make a standard directive for the e-mail portion. In the standard directive, use a conditional block and add the statement to catch when the standard directive has been enabled.

image

But I don’t know if you will be able to pull the old value this way. hmmm

Two q’s

  1. How do you get a value from the InTran DD to the StdDD? Are the values in the BPM Data fields (like Character01) maintained throughout all DD’s of the particular table? Is that why there is an “Order” field for BPMs so that you can ensure the order they happen in?

  2. Does the “Enable Standard Directive” widget just enable the referenced Std DD, or does it actually cause it to be called?

Does it actually affect the “enabled” checkbox on the Std DD?

If the Std DD’s Enabled checkbox was cleared, would the “Enable Std DD” widget in the InTran DD do anything?

I’ve not tried anything that proves #2 in any way, but for #1:
I know that BPM data is tied to the session and persistent for a given session. If you use it a lot, you have to make sure you are flushing/clearing/setting BPM data fields correctly. And yes, the order field is to make sure directives fire in a certain order (in case you want to build up from one to the next).

Point 1.

The data persists through that BO call so will persist from intran to std dd in this case.

Point 2.

To call it in the standard directive you will need a Condition as the first widget that will say “The directive has been called from the SPECIFIED directive”. Where the specified directive is your InTran DD.

Vinay Kamboj

1 Like

Within my In-Transaction I capture the ProdQty and it works fine for a single record - I then Enable Dependent Standard Directives.
callContextBpmData.Number01 = 0;
var ttJobHead_xRow = (from ttJobHead_Row in ttJobHead
where ttJobHead_Row.RowMod == “”
select ttJobHead_Row).FirstOrDefault();
if (ttJobHead_xRow != null)
{
callContextBpmData.Number01 = ttJobHead_xRow.ProdQty;
}
Within my Standard Directive I already have the condition of being enabled from the In-Transaction.

The code all works fine but only for a single record.

But, I want to pass through multiple records and it’s this bit that is confusing me.

If I use callContextBpmData.Number01 - will this not be overwritten for each Job or can I use a foreach in the In-Transaction and in the Standard with an OrderBy?

Data Directives work on a single record at a time.

You should set the value of callContextBpmData.Number01 prior to enabling the Std DD.

I think the InTran DD would flow like:

  1. Set callContextBpmData.Number01 to the value you want to pass to the Std DD
  2. Call the Enable Standard Directive widget.

Then in the Std DD

  1. Condition block to see if it was called from the InTran DD
  2. Build your email, using the DD’s table for the new value and the callContextBpmData.Number01 as the prior value

Calvin:
I am doing exactly as you suggest already but I only get one email - I assumed this is because I need for a foreach somewhere but if Data Directives work on a single record at a time I shouldn’t need a foreach?
This is what is confusing me?
Roberto.

I assume you can do this in a widget, but here is how I do this in code. The transaction has the ttrow with a rowmod of “” so Epicor can tell if the row was modified by another user before saving. I have a generic OLD statement for getting the OLD data to compare to in an in-transaction DD. Then you can compare the current to the OLD.

OLDPart = (from Old_Row in ttPart
          where Old_Row.RowMod == ""
          select Old_Row).FirstOrDefault();

if (Part.UOMClassID != OLDPart.UOMClassID)
{
}

1 Like

Roberto -

Standard Data Directives run as the very last event before the AppServer completes and it runs once regardless of how many records were updated. With the way your code is written, it appears to me that you will be working with the First record updated but the BPMData value will be for the Last record updated.

As noted - BPMData is valid for the complete execution chain on the AppServer but it is a single record so you cannot use it in the way you are attempting.

Rich
Thank you for clarifying this for me.
I was going round in circles a little with my testing.
I’ll need to try a different approach to grab the data pre update and publish alongside the post update.

Can you clarify for my understanding:
The ProductionYieldRecalculation process will update 1 or many Jobs - as part of this update process:

  1. How often will the In-Transaction Data Directive run when many records are updated
  2. How often will the Standard Data Directive run when many records are updated

Thank you in advance.

Make a test DD BPM that does nothing but send you an email. Then count the number of emails you get after the update process has finished running. It wouldn’t hurt to add some debugging info into the subject or body of the email.

Also, back on your original request:

Is it expected to receive an email if there was no change in ProdQty? Because a DD will only fire when the table changes, and if the Re-calc determined there was no change, then it would not fire. If that’s the case, maybe make a MD BPM to tweak a field in the table that the DD is monitoring.

Roberto -

In-Transaction directives will fire for every record updated - if you update 1 record 5 different times or 5 different records one time each, the In-Tran directive will fire a total of 5 times.

The Standard directive will fire only once regardless of how many records in that table were updated. For the Standard directive, the Temp Table (ttJobMtl in this case based on your example) will contain a number of records based on the update processing that occurred on that table during the execution of the Business Method called.

If we look at the simple case of a single existing record updated during a method call, the Temp Table will contain two records - the original record with RowMod = empty string and the latest version of the updated record with RowMod = “U”. In the case where a single record was updated multiple times, there would still be only two records - the original version of the record prior to any updates being made and the final version of the record after all the updates were made.

In the case of 5 different records being updated during a single method execution, the Temp Table will contain 5 record pairs (total of 10 records) with each record being updated having an original version record and a final version record.

In the case of records added or deleted during a method call, the Temp Table holds the appropriate record. For Added records, there will be one Record with the final version of the record and a RowMod = “A”. For Deleted records, there will be one Record with the original version of the record and a RowMod = “D”.

For a record that is added and ultimately deleted during the scope of a method call, the Temp Table will not contain anything for that record.

3 Likes

Finally got this working.
With Rich’s explanation of how the In-Tran and Standard work I was able to understand where to capture the data and when to trigger the email.
Solution.

  1. Add into the code a foreach to capture all Updated records in the In-Trans
  2. Build a BpmData string with the pre and post data using the Row.Updated and RowMod == “”
  3. Enable Standard Directive
  4. Send email with the built up string from the Standard Directive once for all records
  5. Reset the BpmData

Tested and working perfectly.

All - thank you for the input.

1 Like

What do you mean by that? How can a record be updated multiple times but the DD doesn’t fire each time?

Calvin -

In-Transaction DD fire on every update to the DB. Standard DD fire once per table regardless of the number of records updated or the number of times they are updated.

There are areas of the Epicor Server code where a record may get updated multiple times during execution of a single Method. The multiple update pattern is more common during complex operations - scheduling, MRP, etc. - but it is also seen in some relatively simple update operations and can also be caused by BPM.

Hypothetical (made up) example - You change the Quantity on an Order row and save the row. The initial update will save the row with the new Quantity and other changes seen in the UI - This is the first Update to the DB. Epicor code then does an additional update to the same record as a result of logic that adjusts the discount due to a review of the entire order - 2nd Update to the DB on the same record.

Each of the above updates will fire the In-Transaction DD so it will fire twice.

The Standard DD will only fire once. The temp table on Order detail in the Standard DD will contain 2 records. One record will be the original Order detail record before any updates and will have a RowMod of “”. The other record will be the final version of the Order detail record (with all changes applied) and will have a RowMod of “U”.