BPM to Track Delete Logs from multiple tables

I have seen many BPM on the forum to track deletion but they only seem to fit for tracking 1 table such as from ChgLog - Track Delete Records or BPM to track deletion - #2 by A.Baeisa

So I understand the concept on but I don’t really understand how to update it to a UD table. And I would prefer to have just 1 UD table that is able to track deleted data from multiple different table such as Customer, InvoiceHeader, ShipDtl, etc.

To my understanding, I could use the Data Directive set condition to track delete. But how do I copy that into the UD table exactly? I know there is a way using the Custom Code from looking at ChgLog - Track Delete Records but I am uncertain how to change it to be able to fit different table fields.

Is there a way to query out the deleted data and insert all of it into 1 field similarly to the CDC Log?

Those examples there use the Change Log widget which adds the records in Epicor’s log tables for you. You would need your own thing insted which uses a UD table. This is a perfect case to use a function which inserts a record in the UD table and then just call it from the BPMs. Basically, follow the same logic in those posts but replace Epicor’s widget with your own function. For the UD, you could go with something like this:

Key1 - table name
Key2 - date & time stamp (or an increment)

And then use Shortchar or Character for others like user name, etc.

For inserting the record in the UD table, below is an example of a function I use. It has more params than you need, but it is a good start. Basically, call GetNew, set your fields and then save with Update.

this.CallService<Ice.Contracts.UD02SvcContract>(ud2c => {

  // define ud02 tableset
  Ice.Tablesets.UD02Tableset tsUD2 = new Ice.Tablesets.UD02Tableset();

  // get new record
  ud2c.GetaNewUD02(ref tsUD2);

  // set fields
  tsUD2.UD02[0].Key1 = logFrom;
  tsUD2.UD02[0].Key2 = pinTimeStamp;
  tsUD2.UD02[0].Character01 = pinIP;
  tsUD2.UD02[0].Character02 = pinType;
  tsUD2.UD02[0]["Descr_c"] = pinLogText;
  // save
  ud2c.Update(ref tsUD2);


Separately, there is an Epicor Idea to improve logging, which would also include additions and deletions.


Sorry, I don;t understand what you mean by call GetNew…where am I supposed to call this? In Data Directive Custom Code? Is this set for the UD table side or the table where the data was deleted?

In the Code there is a “Descr_c” = pinlogText, what is this?

You mention to also set my fields, do you mean the fields that I want to save into the UD table? For mine I basically just want to have it call all the fields in the table for that deleted data.

For example, Customer table a customerID has been deleted. It just takes all the fields in the customer table that was deleted following the customerID and put it into say “Descr_c” field as a long string of text of the UD02. Then if another table for example POHeader has the PONum deleted, it will do the same and update to the “Descr_c” field as a long string of text as well.

The coding above is for inserting data right? How do retrieve the ID needed for it to know which data to update?

The code I put there is from a function I’m currently using. You need to amend it to fit your needs. If you’re not familiar with functions, you can just use the code directly in the BPM

Yes, in the data directive. Alternatively, you could put it in a function and call the function from the BPM.

That’s a custom field I use, you don’t need to use the same. Again, it’s just an example, you’ll need to amend the code.

You will have to add the fields to a string or whatever one by one. Not sure if it’s a good idea to have all the fields there. Maybe just the most important ones ?

Yes, it inserts a record into the UD02 table. You can use a different table if you want. You will get the IDs from the BPM. The idea is you’ll have a BPM for each record deleted (customer, PO, SO, etc.). That’s why I said you can use a function, otherwise you’ll have to write the same logic each time.

1 Like

Hmm, still not really understanding the exact process…but let me go through step by step first then I’ll come back once I face an issue

Hi it has been a while,

Referring to the steps above, I created a UD30 Table and the create a new in-transaction data directive for UD30 table. My question is, how do I set the condition to detect if the other table such as InvHead has a data deleted?

Or in this case I go to the InvHed table and set the condition there?

Yes. You will be setting all your in-trans data directives on the tables that are having the changes.

So I did the condition as long as InvcHead table data deleted it will run the code. But I get the error below.

Please bear with me as I am a beginner at coding. Thanks everyone

Click Usings and References → References → Add
Find Ice.Contracts.BO.UD30 → Click OK

@Dragos Example was incomplete, he was just showing an example.

My example is also incomplete, but explains a bit more:

  CallService<Ice.Contracts.UD30SvcContract>(ud30 =>
      // define UD30 tableset
      Ice.Tablesets.UD30Tableset tsUD30 = new Ice.Tablesets.UD30Tableset();
      // get new record
      ud30.GetaNewUD30(ref tsUD30);
      // set fields
      // the variables you had here were not defined, you can use variables, but need to define them like...
      string myKey = "Some type of Key To Identify"; 
      tsUD30.UD30[0].Key1 = myKey;
      tsUD30.UD30[0].Key2 = "Some type of Key To Identify (Maybe a timestamp?)";
      tsUD30.UD30[0].Character01 = ttInvcHead.First().InvoiceNum; //example from Invoice Head Row 
      // save
      ud30.Update(ref tsUD30);

Thanks for the replied, so I tried teh code made some changes then fixed the error but after that when I tested in Ar Invoice entry I got this. Likely due to the fact the table has these fields but no data is being inserted.

For the log value field currently its just the invoicehead.Invoice Num, will try to change it to a string of values later on…but that’s in a later step on my guess.


  CallService<Ice.Contracts.UD40SvcContract>(ud40 =>
      // define UD40 tableset
      Ice.Tablesets.UD40Tableset tsUD40 = new Ice.Tablesets.UD40Tableset();
      // get new record
      ud40.GetaNewUD40(ref tsUD40);
      // set fields
      // the variables you had here were not defined, you can use variables, but need to define them like...
      DateTime now = DateTime.Now;
      string CompanyCode = ttInvcHead.First().Company; //Call the CurrCompany with deleted data
      string TableName = "InvcHead";
      string myKey = now+TableName; 
      tsUD40.UD40[0].Key1 = CompanyCode;
      tsUD40.UD40[0].Key2 = myKey;
      tsUD40.UD40[0].DatetimeEntry = now.ToString();
      tsUD40.UD40[0].TableName = TableName;
      tsUD40.UD40[0].FieldName = ""; 
      tsUD40.UD40[0].Value = ttInvcHead.First().InvoiceNum.ToString();
      //tsUD40.UD40[0].Character01 = ttInvcHead.First().InvoiceNum.ToString(); //example from Invoice Head Row 
      // save
      ud40.Update(ref tsUD40);

So I changed the coding as per above but I think I’m misunderstanding the way the coding works? I thought the line tsUD40.UD40[0].Key1 will insert the data into Key 1 in my table but when I do the same for the other 4 fields I get the error as below.

Is there another reference I need to add?

The coding, no, but the fields yes.

UD40 does not contain any fields like DatetimeEntry, TableName, FieldName, Value etc.

You will have to either chose from the existing fields, like CharacterXX, ShortCharXX, NumberXX, etc

or you can add fields to the table (I won’t cover that here)

You can look in the Data Dictionary, or make a BAQ and see what fields are available.

Also when you’re coding, the fields will show up in the autocomplete when you press
Ctrl + Space after the dot on tsUD40.UD40[0].

I did add fields before I started coding. Will try the Ctrl Space. Thanks :smiley:

I’m an idiot. After thinking through for a bit I thought ‘why create new fields and not just used the existing ones? Duh’ :melting_face:

I got it to work, now I just need to make multiple fields into string and put them into a field and tweak it a bit into a report. And copy the code into other tables.


Thanks everyone for the help on this! I really appreciate it. :laughing:

1 Like