BPM Automation - Help Needed

Well, the BEST way to trace (in my opinion) is to trace one thing at a time. ie…

  1. get into the Process (Order Entry).
  2. Turn on Trace Logging (no datasets yet) and clear the log
  3. press the New Order in order entry
  4. Look at the log file to see what happened… document it… then clear the log
  5. enter your data into the order header and save
  6. do step 4 again… only this time, you will see it calls multiple things. Reason? When you enter a customer, it does things, etc… SOMETIMES, you need to do step 4 after every field, just in case you want to capture that step.
  7. Press new line, then step 4 again
  8. enter part number, check step 4
  9. enter Qty, check step 4
  10. enter price, check step 4
  11. Save, check step 4.

I think when doing it this way, you can narrow down the exact UDMethod you are trying to find.
All that said, you are probably looking for the method SalesOrder.Update which is the method that is used to save any changes to the order.

1 Like

One more hint for cleaning up the Trace Log: Before you start the Trace, right-click on System Monitor in your system tray and choose Exit, to eliminate the repetitive ReportMonitor calls.

I only select Track Changes Only, and that usually has enough info to figure out what is happening. Then add more checkboxes if needed.

New problem with the integration, it appears that their program is going to delete out all of my sales order releases and create new ones every time it runs. This means there is no way for me to call in my promise dates. Does anyone have a good idea on how to work around this?

Action Plan:

  1. Create a BPM to store all relevant data getting changed into UD Table before update.
  2. Create a BPM to write promise dates back in after call has been made.

The first bpm is planned to be a pre-process that grabs the entire order rel table related to the sales orders being updated. It will need to purge all release records in the table before it writes the new ones.

The second BPM will need to be a post-process that runs a C# custom code iterator for filling the promise dates back in.

What I need:

Help creating a function to purge entries in the ud table using widgets.
Help creating a BO method caller to initiate the transfer of data from the OrderRel table to UD01 Table.

Thanks in advance for the help!

Currently, in the process of creating the first BPM this is the layout I have so far:


The two show message sections are just troubleshooting portions and will be removed when I publish it to our live environment.

The Invoked BO Method is set up for Ice.UD01.UpdateExt, and is configured as follows:
image

The Update Table by Query is set up using the ds.OrderRel filtered for open releases and displays the company, ordernum, linenum, relnum, and reqdate. It is mapped to UD04LogRecords.UD01 table with the following configuration mapping:

I am receiving the following error when trying to save the bpm:

After troubleshooting I know that this error is coming from the Update Table by Query widget. Any ideas on what I can change to try and get around this?

Error was on my criteria statement for the query. Had it set to 1 instead of “true”. Credit this thread for solution:

New problem is that what I have built doesn’t seem to be populating the UD table at all. The bpm is a pre process because we need to grab the data before the integration data trickles in. I know there is data to grab as I am able to get the message boxes mentioned prior to populate. Am I missing a step?

Turns out I needed to have the update method after the update table by query widget. After moving those two around I get the following error:

@ckrusen,

Have you had any luck pushing data from a table to a UD table using these widgets?

I don’t think I ever tried doing that. And since I no longer have access to an E10 system (or any version of Epicor), I can’t try it out for you.

Pretty much all my future posts will be strictly from memory. A memory that doesn’t advance past 10.2.300.

I didn’t know you were out of Epicor! Thanks for responding though!

Instead of UpdateTable by Query use the Fill Table by Query. I have used that to write to UD tables. Use the Row Mod as “A” since you are adding data. Update is used if you are going to modify an existing dataset created earlier using Fill Table.

Ill give that a shot. Current use case is I have to be able to blow up the UD01 table and fill it any time OrderRel.UpdateExt is called via rest. Will using that be able to handle multiple rows simultaneously?

Ended up C# coding as found in the forum below, credit to them:

using (var txScope = IceContext.CreateDefaultTransactionScope())
{
foreach(var UD01 in (from row in Db.UD01 select row))
   {
      Db.UD01.Delete(UD01);
   }
   Db.Validate();
   txScope.Complete();
}

/* Find current record in dataset */
using (var txScope = IceContext.CreateDefaultTransactionScope())
{    
foreach (var recOrderHed in (from row in Db.OrderHed where row.OpenOrder == true select row))
        {
        /* Find all lines for Order */
        foreach (var recOrdDetail in (from row in Db.OrderDtl where row.Company == Session.CompanyID && row.OrderNum == recOrderHed.OrderNum && row.OpenLine == true select row))
            {
              foreach (var recOrdRel in (from row in Db.OrderRel where row.Company == Session.CompanyID && row.OrderNum == recOrdDetail.OrderNum && row.OrderLine == recOrdDetail.OrderLine && row.OpenRelease == true select row))
                  {            
            
                          /* Update UD Record */
                         UD01 newRow = new UD01();
                         Db.UD01.Insert(newRow);
                         newRow.Company = Session.CompanyID;
                         newRow.Key1 = recOrdDetail.OrderNum.ToString();
                         newRow.Key2 = recOrdDetail.OrderLine.ToString();
                         newRow.Key3 = Guid.NewGuid().ToString();
                         newRow.ShortChar01 = "Example";
                         newRow.Number01 = recOrdRel.OrderNum;
                         newRow.Number02 = recOrdRel.OrderLine;   
                         newRow.Number03 = recOrdRel.OrderRelNum;
                         newRow.Date01 = recOrdRel.ReqDate;   
                   }    
            }
        }

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

}

New Goals:
I need to be able to detect when a user invokes the UpdateEXT with a row mod of “D” for the first time each day. This should then toggle the bpm to run deleting the old data out of the UD01 table and writing the new. Additionally, I would like a toggle that triggers four hours after that would engage that toggle again. I figure this can be done using a function and would like someones help standing one up.

@josecgomez,

Ive been working on this code a second and I believe I have it working the way I want it to. The code goes through an iterative process to get the order in which the added/updated release was in related to order#, Line, release order. It then iterates through the UD01 Table, that I have set up to grab and hold prior data, and finds its related field to pull a date out of.

The issue is the code used to write the old data to the UD01 table is doubling entries and putting them in out of order. See below pic and code for what I’m working with:

image

using (var txScope = IceContext.CreateDefaultTransactionScope())
{
foreach(var UD01 in (from row in Db.UD01 select row))
   {
      Db.UD01.Delete(UD01);
   }
   Db.Validate();
   txScope.Complete();
}

/* Find current record in dataset */
using (var txScope = IceContext.CreateDefaultTransactionScope())
{    
foreach (var recOrderHed in (from row in Db.OrderHed where row.OpenOrder == true select row))
        {
        /* Find all lines for Order */
        foreach (var recOrdDetail in (from row in Db.OrderDtl where row.Company == Session.CompanyID && row.OrderNum == recOrderHed.OrderNum && row.OpenLine == true select row))
            {
              foreach (var recOrdRel in (from row in Db.OrderRel where row.Company == Session.CompanyID && row.OrderNum == recOrdDetail.OrderNum && row.OrderLine == recOrdDetail.OrderLine && row.OpenRelease == true select row))
                  {            
            
                          /* Update UD Record */
                         UD01 newRow = new UD01();
                         Db.UD01.Insert(newRow);
                         newRow.Company = Session.CompanyID;
                         newRow.Key1 = recOrdDetail.OrderNum.ToString();
                         newRow.Key2 = recOrdDetail.OrderLine.ToString();
                         newRow.Key3 = Guid.NewGuid().ToString();
                         newRow.ShortChar01 = "Example";
                         newRow.Number01 = recOrdRel.OrderNum;
                         newRow.Number02 = recOrdRel.OrderLine;   
                         newRow.Number03 = recOrdRel.OrderRelNum;
                         newRow.Date01 = recOrdRel.ReqDate;   
                   }    
            }
        }

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

}

I believe the issue stems from the chunk of code that creates a new guid. I cannot however get that chunk of code to run without erroring out if I do not keep the guid included. Is there a better way of coding this?

Thanks a ton!!

Just did a hot-swap on the code to use some of Joses old recommendations on the same post. I get the following error:

Server Side Exception

BPM runtime caught an unexpected exception of ‘EntityException’ type.
See more info in the Inner Exception section of Exception Details.

Exception caught in: Epicor.ServiceModel

Error Detail

Correlation ID: 752e7d57-0fd4-4758-b5a6-733e6c159a3e
Description: BPM runtime caught an unexpected exception of ‘EntityException’ type.
See more info in the Inner Exception section of Exception Details.
Inner Exception: The partner transaction manager has disabled its support for remote/network transactions. (Exception from HRESULT: 0x8004D025)
The partner transaction manager has disabled its support for remote/network transactions. (Exception from HRESULT: 0x8004D025)
Program: EntityFramework.dll
Method: EnlistTransaction
Original Exception Type: EntityException
Framework Method: SaveChanges
Framework Line Number: 352
Framework Column Number: 17
Framework Source: SaveChanges at offset 404 in file:line:column C:_Releases\ICE\ICE4.1.100.0\Source\Server\Framework\Epicor.System\Data\IceDataContext.cs:352:17

Client Stack Trace

at Epicor.ServiceModel.Channels.ImplBase`1.ShouldRethrowNonRetryableException(Exception ex, DataSet dataSets)
at Erp.Proxy.BO.SalesOrderImpl.MasterUpdate(Boolean lCheckForOrderChangedMsg, Boolean lcheckForResponse, String cTableName, Int32 iCustNum, Int32 iOrderNum, Boolean lweLicensed, Boolean& lContinue, String& cResponseMsg, String& cCreditShipAction, String& cDisplayMsg, String& cCompliantMsg, String& cResponseMsgOrdRel, String& cAgingMessage, SalesOrderDataSet ds)
at Erp.Adapters.SalesOrderAdapter.MasterUpdate(Boolean lCheckForOrderChangedMsg, Boolean lcheckForResponse, String cTableName, Int32 iCustNum, Int32 iOrderNum, Boolean lweLicensed, Boolean& lContinue, String& cResponseMsg, String& cCreditShipAction, String& cDisplayMsg, String& cCompliantMsg, String& cResponseMsgOrdRel, String& cAgingMessage)
at Erp.UI.App.SalesOrderEntry.Transaction.Update()

Inner Exception

The underlying provider failed on EnlistTransaction.

Inner Exception

The partner transaction manager has disabled its support for remote/network transactions. (Exception from HRESULT: 0x8004D025)

Inner Exception

The partner transaction manager has disabled its support for remote/network transactions. (Exception from HRESULT: 0x8004D025)

using (var txScope = IceContext.CreateDefaultTransactionScope())
{
foreach(var UD01 in (from row in Db.UD01 select row))
   {
      Db.UD01.Delete(UD01);
   }
   Db.Validate();
   txScope.Complete();
}

/* Find current record in dataset */
using(var UD01svc = Ice.Assemblies.ServiceRenderer.GetService<Ice.Contracts.UD01SvcContract>(Db))
{   
foreach (var recOrderHed in (from row in Db.OrderHed where row.OpenOrder == true select row))
        {
        /* Find all lines for Order */
        foreach (var recOrdDetail in (from row in Db.OrderDtl where row.Company == Session.CompanyID && row.OrderNum == recOrderHed.OrderNum && row.OpenLine == true select row))
            {
              foreach (var recOrdRel in (from row in Db.OrderRel where row.Company == Session.CompanyID && row.OrderNum == recOrdDetail.OrderNum && row.OrderLine == recOrdDetail.OrderLine && row.OpenRelease == true select row))
                  {            
            
                          /* Update UD Record */
                          UD01Tableset ds = new UD01Tableset();
                          UD01svc.GetaNewUD01(ref ds);
                          ds.UD01[0].Company = Session.CompanyID;
                          ds.UD01[0].Number01 = recOrdRel.OrderNum;
                          ds.UD01[0].Number02 = recOrdRel.OrderLine;
                          ds.UD01[0].Number03 = recOrdRel.OrderRelNum;
                          ds.UD01[0].Date01 = recOrdRel.ReqDate;
                          UD01svc.Update(ref ds);
   
                   }    
            }
        }
}

Does anyone have an idea what could be causing this?

Dunno if this is the answer but, on the last bit of code you posted you are not setting the Key fields on UD01

Do I have to set those key fields when writing to UD01?

Normally when creating a new record you need at least one key field filled in, something that makes the record unique

So if I set Key 1 = order number, key2 to order line, and key 3 to order release will that work?

Thats what I do in similar situations… and thats what you where doing in your earlier code