How to use a recurring Integration Endpoint for importing data
You are here
Event Handlers and Field Value Change Detection
Submitted by Nathan Clouse on 11/17/17.
Last modified:
11/17/17
Catching if a field was changed for a particular table is easy if you use buffer.orig() inside the table method. However, if you are using event handlers, things can get a little more tricky. A post event handler on a table method of Update() will have the same values in buffer and buffer.orig(). However, there are a few ways we can catch these updates depending on where the update occurs. Let's use CustTable as an example. all code is attached as an XPO.
Using the Update method for pre and post event handlers
First, let's create a called CustTableEventHandler. This will hold the handles we are going to create for the various events. Now, add two methods called PreUpdateHandler and PostUpdateHandler.
public static void preUpdateHandler(XppPrePostArgs _args) { CustTable custTable = _args.getThis(); if (custTable.BankAccount != custTable.orig().BankAccount) info(strFmt("bank account changed from from '%1' to '%2' with %3", custTable.orig().BankAccount, custTable.BankAccount, funcName())); }
 
public static void PostUpdateHandler(XppPrePostArgs _args) { CustTable custTable = _args.getThis(); if (custTable.BankAccount != custTable.orig().BankAccount) info(strFmt("bank account changed from from '%1' to '%2' with %3", custTable.orig().BankAccount, custTable.BankAccount, funcName())); }
 
Now, let's add the two event handles to our update() method on CustTable. Right click on the update() method on custTable in the AOT and select "New Event Handler Subscription". Fill in the appropriate values for the new event handler subscription, like so:
 
But What If the Update Happens Inside Update()?
 
If we leave things like this, we would only ever get an info log from the preUpdateHandle method. That's helpful but we may not pick up every update on the BankAccount field. If the update to the field happens inside the CustTable.Update() method, we would never be able to detect the change. Let's add something that will help. Right click on methods on CustTable, select "override method" and select "aosValidateUpdate". We don't need to do anything other than that. Now, let's add two more methods to out CustTableEventHandler class.
 
 
public static void preValidateHandler(XppPrePostArgs _args) { CustTable custTable = _args.getThis(); if (custTable.BankAccount != custTable.orig().BankAccount) info(strFmt("bank account changed from from '%1' to '%2' with %3", custTable.orig().BankAccount, custTable.BankAccount, funcName())); }
 
public static void PostValidateHandler(XppPrePostArgs _args) { CustTable custTable = _args.getThis(); if (custTable.BankAccount != custTable.orig().BankAccount) info(strFmt("bank account changed from from '%1' to '%2' with %3", custTable.orig().BankAccount, custTable.BankAccount, funcName())); }
We'll also want to add a new parameter to the CustTable.Update() method so we can trigger a field update from inside the tables update() method so we can attempt to trap it. From the start of the method to super(), make your CustTable.Update() method look like this (If using 2012 R3 CU12):
void update(boolean _updateSmmBusRelTable = true, boolean _updateParty = true/* AAX Start */, boolean blankOutBankAccount = false /* AAX end */) { CustTable this_Orig = this.orig(); RecVersion rv = this_Orig.RecVersion; //#isoCountryRegionCodes // ttsbegin; //if (SysCountryRegionCode::isLegalEntityInCountryRegion([#isoRU])) { this.setInventProfileId_RU(); } // // Add for Connector integration if (this.daxIntegrationId == emptyGuid()) { this.daxIntegrationId = newGuid(); } //AAX start if(blankOutBankAccount) { this.BankAccount = ""; } //AAX end super();
 
 
 
Bringing It All Together
 
Now that we have a few event handles setup, let's test and see what they would actually catch. Let's use this job to do it.
static void testUpdateCustTable(Args _args) { CustTable CustTable; select firstOnly1 forupdate * from CustTable; info("outer update on CustTable - Start"); ttsBegin; CustTable.BankAccount = int2str(CustTable.recVersion); CustTable.update(); ttsCommit; info("outer update on CustTable - End"); info("-------------"); info("inner update on CustTable - Start"); ttsBegin; CustTable.update(true,true,true); ttsCommit; info("inner update on CustTable - End"); info("-------------"); info("outer doUpdate on CustTable - Start"); ttsBegin; CustTable.BankAccount = int2str(CustTable.recVersion); CustTable.doUpdate(); ttsCommit; info("outer doUpdate on CustTable - End"); }
 
 
 
if we run this job, we will get this output
 
 
The outer update Infolog message block represents if something outside of our table performs a field value change. The inner update block is if something inside our table performs a field update. As you can see, we never trip the PostUpdateHandle method ever, so thats not an option to use for this. Also, on the outer, we trip the preUpdateHandle method but not when performing an update inside the update() method itself. The two event handlers we hit are the pre and post on the aosValidate method that we created an override on but left it as is. That's where we want to add our event subscriptions to detect all field changes, whether they are from inside or outside the table. It is also work noting that aosValidate() pre and post event handlers are even tripped when using doUpdate().