BPM - Data Directive IN-Transaction Reading old value

Hi,

I am trying to read old value of a custom field (StatusField_c) in a BPM but it just does not retrieve it. To my understanding the temp tables have two rows per database changed row, one with RowMod of ‘U’ and the other ‘’. Here is the BPM code and the old status value never retrieves any value:

The following BPM code is triggered on the condition of:
The field has been changed from any to other

using (var txScope = IceContext.CreateDefaultTransactionScope())
{
string key2Val = string.Empty;
string key3Val = string.Empty;
string key4Val = string.Empty;
int orderNum = 0;
int orderLine = 0;
int orderRelNum = 0;
int oldStatus = 0;
int newStatus = 0;

foreach (var ttOrderRelRow in (from row in ttOrderRel select row))
{
if (ttOrderRelRow.RowMod == “U”)
{
orderNum = ttOrderRelRow.OrderNum;
orderLine = ttOrderRelRow.OrderLine;
orderRelNum = ttOrderRelRow.OrderRelNum;
key2Val = ttOrderRelRow.OrderNum.ToString();
newStatus = ttOrderRelRow.StatusField_c;
}
else
oldStatus = ttOrderRelRow.StatusField_c;
}

key3Val = string.Format("{0}|{1}|{2}|{3}|{4}", orderNum,
orderLine,
orderRelNum,
oldStatus,
newStatus);
key4Val = DateTime.Now.ToString(“yyyy/MM/dd hh:mm:ss tt”);

UD17 newRow = new UD17();
Db.UD17.Insert(newRow);
newRow.Company = Session.CompanyID;
newRow.Key1 = “TrackStatus”;
newRow.Key2 = key2Val;
newRow.Key3 = key3Val;
newRow.Key4 = key4Val;
newRow.ShortChar01 = Session.UserID.ToString();
newRow.Date01 = DateTime.Now;
newRow.Number01 = orderNum;
newRow.Number02 = orderLine;
newRow.Number03 = orderRelNum;
newRow.Number04 = oldStatus;
newRow.Number05 = newStatus;

Db.Validate();
txScope.Complete();
}

Any ideas what I am doing wrong? Seems like the temp table does not have 2 rows.
I also tried to read Db.OrderRel table but the value of the field is always the same as the value on the temp table. This BPM is under Data Directive / In-Transaction. Is that too late to have the old value?

Would appreciate your feedbacks! Be safe and wear masks :slight_smile: and keep 6 feet distance and do not have multiple lovers hahaha :slight_smile:

Hmmm … I did a quick test of an In-Tran DD on OrderRel (to a std field, not a UD one), and see the following when the value changes from 3333 to 4444.

image

PriorValue is fetched from the OrderRel table using:

PriorValue = Db.OrderRel
  .Where( r =>r.Company == callContextClient.CurrentCompany 
         && r.OrderNum == ttOrderRelRow.OrderNum 
         && r.OrderLine == ttOrderRelRow.OrderLine 
         && r.OrderRelNum == ttOrderRelRow.OrderRelNum)
  .Select( r =>r.OurReqQty ).DefaultIfEmpty(0).FirstOrDefault();

Which I thought would fetch the value before the OrderRel table was updated.

Inserting field queries (one for just Add, one for Just Delete, … and one for All (add&Delete&Updated&Unchanged) of ttOrderRel.OurReqQty, shows that withe just one Row mod filter, only the Updated returns a result. But when all are selected, the Updated retursn 2 values (the new and the old, respectively).

A trace shows that BO SalesOrder.ChangeSellingReqQty() is being called, followed by BO SalesOrder.MasterUpdate().

The OrderRel table appears to be updated during ChangeSellingReqQty, but the DD isn’t firing until the second BO (MasterUpdate).

I know that my use of the OurReqQty field act differently than your UD field, but maybe there is something updating OrderRel prior to the DD firing.

1 Like

I changed my test to use a OrderRel field that doesn’t have any pre-processing (i.e. call any BO’s prior to update), and see the following for OrderRel.TaxExempt, when it changes from 111 to 222

image
(I forgot to change the static text of fqOurRelQty to fqTaxExempt)

Now it shows the new and old values

I’d focus on something being called before the MasterUpdate (which is when the OrderRel table actually appears to get updated)

1 Like

If you have a condition before the code-block it will eat away the RowMod “” and you will NOT Find it. Epicor tends to somehow re-filter the ttTable (assuming it does that so if you chained more Conditions, each one would have already the prior conditions filtered version of the ttTable).

I do tend to go back to the Db Context and fetch it from there.

@jgiese.wci right? :slight_smile:

1 Like

Now add a Condition Block before your Code Block with any changed to xyz, and watch the RowMod U disappear into the abbys :slight_smile:

1 Like

And if you use the filter condition but then want your original unchanged row back you can use the FilterData method. I’m sure there is a good reason for all of this but outside looking in, it’s not intuitive, provides what feels like inconsistent behaviour and is just strange.

this.FilterData(row =>
                {
                  var typedRow = row as Ice.Bpm.TempTables.UD103TempRow;
                  RowCount =ttUD103.Count;
                    if(typedRow.RowMod=="U")
                      {
                        CurrentValue = typedRow.ShortChar01;    //New value
                      }
                    else
                      PriorValue = typedRow.ShortChar01; //Prior Value... maybe
                    return true; // You need to return true here or your tt dataset dissapears.. seriously WTF..
                });
3 Likes

I didn’t use a code block and had no condition blocks. My test was:

The values displayed in the Show Message were the variables and field queries.

2 Likes

I resolved it! Problem was that in my BPM diagram I had a condition which was not letting me see the prior value. I removed the condition all together. See the attachment

Thanks a lot for all your replies, you guys are THE BEST!

1 Like

Not having the condition I think it will have a big impact on performance as it will be called everytime orderRel is modified. How can I have a condition (that I had to remove) and still have access to previous values?

User FilterData

1 Like

That is too late. I meant to filter BEFORE we even enter the C# code like on the diagram level.

Correct. In a standard directive, you can use the condition block to look for your changed from any to any like normal with the widget. At that point in time the unchanged row is removed and all you have left is the updated row. Now in your C# widget if you need access to the unchanged row, it’s still there but not accessible by the normal ttTempTable but via the FilterData method.

In an in-trans you can hit the Db.MyTable.

3 Likes

You can create a condition and there will be a “custom code…” option, you can make your own Condition and you return true/false. Just do what Epicor does in a simply if/else code block - Epicor shouldnt re-filter your dataset as long as Custom Code is used.

Or as Josh said just use out-of-the-box Condition.

Or simply in your C# block do an if/else and check there.

2 Likes

I had this issue and this thread helped me solve. You just need to get the original values of interest before the condition checking for change:

Before that condition occurs, there are 2 rows in the tt table. The 2nd row has the prior values.
I got it this way to avoid potential out of range errors:
image

You could also use eg

ttJobMtl[1].MtlSeq

Know that that code will error out if you use it after the condition.

FYI, to do it in a Method Directive, you have to use ds.TableName, not dsTableName:
image