Friday, July 13, 2012

AWE: RSPriorApprover and RSPriorApprovers in 9.1 Workaround

RSPriorApprover and RSPriorApprovers were 2 user lists that were removed when AWE processing was moved from the SAC_AW to EOAW_CORE.



It seems when the AWE classes that were spread around each Module were reworked into the new EOAW classes, that the processing order of events changed, resulting in these 2 notification classes no longer worked as designed. Rather than fixing them - they were removed. I had a need to direct workflow and approvals to the previous approver and approvers so I recreated them. In order to get them to work though, it requires some code on each transaction and action you intend to utilize the lists from. That means Approve, Deny, Pushback and Override Buttons will all need the 2 lines of code added in order for it to work. If you don't want to utilize these lists for those actions, don't add the code.

On my custom Event Handler App Package I added 3 new classes, UserBase, UserListPriorApprover and UserListPriorApprovers. UserBase will be instantiated on each action that will trigger the Approval Workflow Engine(AWE). The new user lists reference my UserListPriorApprover and UserListPriorApprovers classes to get the users. UserListPriorApprover looks for the top approver in an array created by UserBase and UserListPriorApprovers looks at all users in the array. If the array can't be found - I look at USERINST to try and determine who has approved. The issue I found is that USERINST is already updated by the time the EventHandler is triggered. I think this is why it was removed in 9.1. Someone reorderd the processing order which affected the abililty to reference the USERINST rows that were present. By filling the array on each action with what is in USERINST - before it is updated we can see who was in the approval chain. Not the most elegant solution - but it works!

To make the User lists work point them at the relevant new custom class, UserListPriorApprover or UserListPriorApprover.

AWE_EVENT_HNDLR.UserBase
/* John Mahon Base class to check prior approvers called from 
Component Peoplecode in 4 transactions before pushback */
import EOAW_CORE:DEFN:*;
import EOAW_CORE:LaunchManager;

class UserBase
   property string PrcsId get;
   property string HeaderRec get;
   property string XrefRec get;
   property array of string PriorApprover get;
   
   method UserBase();
   method Approver() Returns array of string;
   method GetPriorApprovers() Returns array of string;
private
   instance EOAW_CORE:LaunchManager &LaunchManager;
   instance Record &recUserListDef, &recThread;
   instance array of string &aryPrevOprs;
end-class;

Global array of string &PriorApprovers;

get PrcsId
   /+ Returns String +/
   Local string &prcsid;
   SQLExec("SELECT EOAWPRCS_ID FROM %TABLE(:1) WHERE EOAWAPPR_COMPONENT = :2"
, Record.EOAW_TXN, %Component, &prcsid);
   Return &prcsid;
end-get;

get HeaderRec
   /+ Returns String +/
   Local string &headerrec;
   SQLExec("SELECT RECNAME FROM %TABLE(:1) WHERE EOAWPRCS_ID = :2 AND EOAWLEVEL = 0"
, Record.EOAW_TXN_LVL, %This.PrcsId, &headerrec);
   Return &headerrec;
end-get;

get XrefRec
   /+ Returns String +/
   Local string &xrefrec;
   SQLExec("SELECT EOAWRECNAME_XREF FROM %TABLE(:1) WHERE EOAWPRCS_ID = :2"
, Record.EOAW_TXN, &LaunchManager.appInst.appDef.txn.awprcs_id, &xrefrec);
   &xrefrec = "PS_" | &xrefrec;
   Return &xrefrec;
end-get;

get PriorApprover
   /+ Returns Array of String +/
   Local array of string &approver = %This.Approver();
   Return &approver;
end-get;

method UserBase
   &PriorApprovers = %This.PriorApprover;
end-method;

method Approver
   /+ Returns Array of String +/
   Local array of string &aryUsers = CreateArrayRept("", 0);
   Local Record &headerRec = CreateRecord(@("Record." | %This.HeaderRec));
   GetLevel0()(1).GetRecord(@("Record." | %This.HeaderRec)).CopyFieldsTo(&headerRec);
   
   &LaunchManager = create EOAW_CORE:LaunchManager(%This.PrcsId, &headerRec, %OperatorId);
   If &LaunchManager.hasAppInst Then
      &aryUsers = %This.GetPriorApprovers();
   End-If;
   
   Return &aryUsers;
end-method;

method GetPriorApprovers
   /+ Returns Array of String +/
   Local array of string &users = CreateArrayRept("", 0);
   Local string &approver;
   Local number &stepinstance;
   
   Local SQL &priorsql = CreateSQL("select DISTINCT OPRID, EOAWSTEP_INSTANCE 
FROM %Table(:1) WHERE EOAWUSER_TYPE = :3 AND (EOAWSTEP_STATUS = :4 
OR EOAWSTEP_STATUS = :5) AND EOAWSTEP_INSTANCE IN (SELECT EOAWSTEP_INSTANCE 
FROM %Table(:2) WHERE EOAWTHREAD_ID IN (SELECT EOAWTHREAD_ID FROM " | %This.XrefRec | " 
WHERE EOAWTHREAD_ID =:6 OR EOAWPARENT_THREAD=:6) and EOAW_EXTERN_FLAG <> 'Y' 
AND EOAWPRCS_ID = :7) ORDER BY EOAWSTEP_INSTANCE DESC "
, Record.EOAW_USERINST, Record.EOAW_STEPINST, "A", "A", "U"
, &LaunchManager.appInst.thread.awthread_id
, &LaunchManager.appInst.appDef.txn.awprcs_id);
   
   While (&priorsql.Fetch(&approver, &stepinstance))
      &users.Push(&approver);
   End-While;
   
   Return &users;
end-method;

AWE_EVENT_HNDLR.UserListPriorAprover
/* John Mahon Prior Approver Class for RSPriorApprover User List */
import EOAW_CORE:DEFN:*;
import EOAW_CORE:LaunchManager;

class UserListPriorApprover extends EOAW_CORE:DEFN:UserListBase
   property string PrcsId get;
   property string HeaderRec get;
   property string XrefRec get;
   
   method UserListPriorApprover(&rec_ As Record);
   method GetUsers(&aryPrevOprs_ As array of string, &recThread_ As Record) 
Returns array of string;
   method getPriorApprover() Returns array of string;
private
   instance EOAW_CORE:LaunchManager &LaunchManager;
   instance array of string &aryPrevOprs;
   instance Record &recUserListDef, &recThread;
   instance array of string &priors;
end-class;

Global array of string &PriorApprovers;

get PrcsId
   /+ Returns String +/
   Local string &prcsid;
   SQLExec("SELECT EOAWPRCS_ID FROM %TABLE(:1) WHERE EOAWAPPR_COMPONENT = :2"
, Record.EOAW_TXN, %Component, &prcsid);
   Return &prcsid;
end-get;

get HeaderRec
   /+ Returns String +/
   Local string &headerrec;
   SQLExec("SELECT RECNAME FROM %TABLE(:1) WHERE EOAWPRCS_ID = :2 AND EOAWLEVEL = 0"
, Record.EOAW_TXN_LVL, %This.PrcsId, &headerrec);
   Return &headerrec;
end-get;

get XrefRec
   /+ Returns String +/
   Local string &xrefrec;
   SQLExec("SELECT EOAWRECNAME_XREF FROM %TABLE(:1) WHERE EOAWPRCS_ID = :2"
, Record.EOAW_TXN, %This.path.awprcs_id, &xrefrec);
   &xrefrec = "PS_" | &xrefrec;
   Return &xrefrec;
end-get;

method UserListPriorApprover
   /+ &rec_ as Record +/
   %Super = create EOAW_CORE:DEFN:UserListBase(&rec_);
   &recUserListDef = &rec_;
end-method;

method GetUsers
   /+ &aryPrevOprs_ as Array of String, +/
   /+ &recThread_ as Record +/
   /+ Returns Array of String +/
   /+ Extends/implements EOAW_CORE:DEFN:UserListBase.GetUsers +/
   
   &aryPrevOprs = &aryPrevOprs_;
   &recThread = &recThread_;
   Local number &i;
   Local array of string &aryUsers = CreateArrayRept("", 0);
   /* If &PriorApprovers.Len > 0 Then */
   If All(&PriorApprovers) Then
      rem MessageBox(0, "", 0, 0, "Found &PriorApprovers");
      /* Local number &index = 0;
      While &PriorApprovers.Next(&index);
         Local string &array_value = &PriorApprovers [&index];
         &aryUsers.Push(&array_value);
      End-While; */
      Local string &array_value = &PriorApprovers [1];
      &aryUsers.Push(&array_value);
   Else
      rem MessageBox(0, "", 0, 0, "Did not find &PriorApprovers");
      &aryUsers = %This.getPriorApprover();
   End-If;
   
   Local number &index = 0;
   While &aryUsers.Next(&index);
      &array_value = &aryUsers [&index];
      MessageBox(0, "", 0, 0, "&index: '" | &index | "', &array_value: '" | 
&array_value | "'");
   End-While;
   
   Return &aryUsers;
end-method;

method getPriorApprover
   /+ Returns Array of String +/
   Local string &approver, &xref;
   &priors = CreateArrayRept("", 0);
   
   Local Record &headerRec = CreateRecord(@("Record." | %This.HeaderRec));
   GetLevel0()(1).GetRecord(@("Record." | %This.HeaderRec)).CopyFieldsTo(&headerRec);
   
   &LaunchManager = create EOAW_CORE:LaunchManager(%This.PrcsId, &headerRec, %OperatorId);
   If &LaunchManager.hasAppInst Then
      /* Getting the Max user instance with Status of approved doesn't work as 
the RSPriorApprover User list is built after the status has already been set. 
We need to get the Min pending status in order to return correct row. */
      Local SQL &priorsql = CreateSQL("SELECT DISTINCT OPRID 
FROM %table(:1) A WHERE A.EOAWSTEP_STATUS = :4 AND A.EOAWSTEP_INSTANCE 
IN (SELECT E.EOAWSTEP_INSTANCE FROM %table(:2) E WHERE E.EOAWTHREAD_ID 
IN (SELECT D.EOAWTHREAD_ID FROM " | %This.XrefRec | " D WHERE D.EOAWTHREAD_ID = :3 
OR D.EOAWPARENT_THREAD= :3)) AND A.EOAWSTEP_INSTANCE = 
(SELECT MIN(B.EOAWSTEP_INSTANCE) FROM %table(:2) B WHERE B.EOAWSTEP_STATUS = :4 
AND B.EOAWTHREAD_ID IN (SELECT EOAWTHREAD_ID FROM " | %This.XrefRec | " C 
WHERE C.EOAWTHREAD_ID = :3 OR C.EOAWPARENT_THREAD =:3 ))", Record.EOAW_USERINST
, Record.EOAW_STEPINST, %This.step.awthread_id
, %This.step.utils.STEP_STATUS_PENDING);
      
      While &priorsql.Fetch(&approver)
         &priors.Push(&approver);
      End-While;
   End-If;
   
   Return &priors;
end-method;

AWE_EVENT_HNDLR.UserListPriorAprovers
/* John Mahon Prior Approvers Class for RSPriorApprovers User List */
import EOAW_CORE:DEFN:*;
import EOAW_CORE:LaunchManager;

class UserListPriorApprovers extends EOAW_CORE:DEFN:UserListBase
   property string PrcsId get;
   property string HeaderRec get;
   property string XrefRec get;
   
   method UserListPriorApprovers(&rec_ As Record);
   method GetUsers(&aryPrevOprs_ As array of string, &recThread_ As Record) 
Returns array of string;
   method getPriorApprovers() Returns array of string;
private
   instance EOAW_CORE:LaunchManager &LaunchManager;
   instance Record &recUserListDef, &recThread;
   instance array of string &aryPrevOprs;
end-class;

Global array of string &PriorApprovers;

get PrcsId
   /+ Returns String +/
   Local string &prcsid;
   SQLExec("SELECT EOAWPRCS_ID FROM %TABLE(:1) WHERE EOAWAPPR_COMPONENT = :2"
, Record.EOAW_TXN, %Component, &prcsid);
   Return &prcsid;
end-get;

get HeaderRec
   /+ Returns String +/
   Local string &headerrec;
   SQLExec("SELECT RECNAME FROM %TABLE(:1) WHERE EOAWPRCS_ID = :2 AND EOAWLEVEL = 0"
, Record.EOAW_TXN_LVL, %This.PrcsId, &headerrec);
   Return &headerrec;
end-get;

get XrefRec
   /+ Returns String +/
   Local string &xrefrec;
   SQLExec("SELECT EOAWRECNAME_XREF FROM %TABLE(:1) WHERE EOAWPRCS_ID = :2"
, Record.EOAW_TXN, &LaunchManager.appInst.appDef.txn.awprcs_id, &xrefrec);
   &xrefrec = "PS_" | &xrefrec;
   Return &xrefrec;
end-get;

method UserListPriorApprovers
   /+ &rec_ as Record +/
   %Super = create EOAW_CORE:DEFN:UserListBase(&rec_);
   &recUserListDef = &rec_;
end-method;

method GetUsers
   /+ &aryPrevOprs_ as Array of String, +/
   /+ &recThread_ as Record +/
   /+ Returns Array of String +/
   /+ Extends/implements EOAW_CORE:DEFN:UserListBase.GetUsers +/
   
   &aryPrevOprs = &aryPrevOprs_;
   &recThread = &recThread_;
   Local number &i;
   Local array of string &aryUsers = CreateArrayRept("", 0);
   /* If &PriorApprovers.Len > 0 Then */
   If All(&PriorApprovers) Then
      rem MessageBox(0, "", 0, 0, "Found &PriorApprovers");
      Local number &index = 0;
      While &PriorApprovers.Next(&index);
         Local string &array_value = &PriorApprovers [&index];
         &aryUsers.Push(&array_value);
      End-While;
   Else
      rem MessageBox(0, "", 0, 0, "Did not find &PriorApprovers");
      &aryUsers = %This.getPriorApprovers();
   End-If;
   
   &index = 0;
   While &aryUsers.Next(&index);
      &array_value = &aryUsers [&index];
      MessageBox(0, "", 0, 0, "&index: '" | &index | "', &array_value: '" | 
&array_value | "'");
   End-While;
   
   Return &aryUsers;
end-method;

method getPriorApprovers
   /+ Returns Array of String +/
   Local array of string &users = CreateArrayRept("", 0);
   Local string &approver;
   Local number &stepinstance;
   
   Local Record &headerRec = CreateRecord(@("Record." | %This.HeaderRec));
   GetLevel0()(1).GetRecord(@("Record." | %This.HeaderRec)).CopyFieldsTo(&headerRec);
   
   &LaunchManager = create EOAW_CORE:LaunchManager(%This.PrcsId, &headerRec
, %OperatorId);
   If &LaunchManager.hasAppInst Then
      Local SQL &priorsql = CreateSQL("select DISTINCT OPRID, EOAWSTEP_INSTANCE 
FROM %Table(:1) WHERE EOAWUSER_TYPE = :3 AND (EOAWSTEP_STATUS = :4 
OR EOAWSTEP_STATUS = :5) AND EOAWSTEP_INSTANCE IN (SELECT EOAWSTEP_INSTANCE 
FROM %Table(:2) WHERE EOAWTHREAD_ID IN (SELECT EOAWTHREAD_ID FROM " | %This.XrefRec | 
" WHERE EOAWTHREAD_ID =:6 OR EOAWPARENT_THREAD=:6) and EOAW_EXTERN_FLAG <> 'Y' 
AND EOAWPRCS_ID = :7) ORDER BY EOAWSTEP_INSTANCE DESC ", Record.EOAW_USERINST
, Record.EOAW_STEPINST, "A", "A", "U"
, &LaunchManager.appInst.thread.awthread_id
, &LaunchManager.appInst.appDef.txn.awprcs_id);
      
      While (&priorsql.Fetch(&approver, &stepinstance))
         &users.Push(&approver);
      End-While;
   End-If;
   
   Return &users;
end-method;

Now all I need to do to use these new UserLists as part of my AWE definitions is to call UserBase on my triggering action. In the case of the Recruiting Components - you can see below that it's called on the Approval Field Change.
import HRS_JOB_OPENING_MANAGER:CMP_HRS_JOB_OPENING:BUS:JOController;

/* John Mahon Logic for RSPriorApprover and RSPriorApprovers User Lists */
import TU_AWE_EVNT_HNDLR:UserBase;

/* END John Mahon */

Component HRS_JOB_OPENING_MANAGER:CMP_HRS_JOB_OPENING:BUS:JOController &JO;

/* John Mahon Logic for RSPriorApprover and RSPriorApprovers User Lists */
&userbase = create TU_AWE_EVNT_HNDLR:UserBase();
/* END John Mahon */

&JO.doFldAction(&JO.FieldChangeAction, GetRecord().Name, GetField().Name);

RSPriorApproverCode.txt

No comments:

Post a Comment