Monday, 5 October 2015

PeopleSoft Approval Framework-Line Level Approval

PeopleSoft has moved from the traditional workflow to the Approval Workflow Engine. Approval Workflow Engine (AWE) also known as Approval Framework is the framework providing capabilities to create, run and manage the approval processes within PeopleSoft. When the user submits a transaction, the application hands the transaction over to Approval Workflow Engine, which will determine the appropriate approval process definition and then launch the required routing based on the steps configured.

There are two types of approval process :
  1.  Header Level - Header level approval is the commonly used approval process in AWE where only the top level header record is used and transaction lines are grouped together and processed as one unit.
  2.   Line Level – In line level approval, action can be  taken on different line items  without waiting for the approval of other line items. In this case, the application can act on the individual lines as they get approved. Each item can be routed to different approvers. For example, if a purchase order contains multiple line items, each line item is treated as a different transaction. So, if you order laptops,printers and desktops, you might obtain approval for laptops only, and not for printers and desktops. The denial of printers and desktops will not have any impact for the approval process of laptops. If treated as a header approval, the entire PO would have been denied. This is the advantage of line level processing.

Business benefits of Line Level Approval:


  •  In line level approval, multiple approvers can be included for individual steps
  •  Each item can be routed to different approvers, based on certain criteria.
  •   Denial /Approval of one line item does not  affect the other.

There are many websites for detailed study on Header level approval. Here, let us have a glance on Line Level Approval with an example.

Line level approval:

Most of the steps in line level are same as Header level approval. Let us see a sample workflow process using line level approval.

Sample Test Case:

An employee tries to submit different items (Laptop, Desktop and Printer) based on the asset id. Each item is routed to different approvers and the approver can approve only the specific items routed to him/her.
 A component has to be created for the employee to submit the asset items and for the managers to approve/deny them. Let’s see the process step by step.

Development Steps:

Step 1: Create a top-level header record ASSET_ID as key-field. Also, create a line record with ASSET_ID and KOV_ITEM_NAME as keys. For header level approval, only the header record is enough.

KOV_TEST_HEADER:



KOV_TEST_LINE-

Step 2: Create a cross reference record with the key-fields used in header and line record as non-keys here to link the workflow process to PIA. Include the EOAW_XREF_SBR delivered sub-record in this record for getting the thread values.



Step 3: Design a standard page with the header record at level 0 and line record at level 1 as shown below. Include the delivered sub-page EOAW_MON_SBP to this page for displaying  the Approval status monitor.


Step 4: Create a new component with the header record as search record. Place the page in this component and register the component to a menu.


Step 5: Give the appropriate permission lists and security access to the component.

Step 6: Coming to the PIA configuration, navigate to Set Up HRMS -> Common Definitions -> Approvals -> Transaction Registry. Add a new Process ID and specify the cross reference, header and line level record names as shown below. Create a new application package and a class and include it here. The coding for app package is mentioned later.


Step 7:  Create three generic templates for submission, approval and denial by navigating to Set Up HRMS -> Common Definitions -> Approvals -> Generic Templates. The emails triggered to the requester and approver will be in the format of this template created. Create a SQL to fetch the bind values mentioned in the template. Like the approval template shown below, similarly create a template for submission and denial mails. This step is needed only if business requires notifications to be sent, else creation of generic templates is optional.


Step 8: Navigate to Set Up HRMS -> Common Definitions -> Approvals -> Transaction Configuration. Here, add the following four events:
a)      On Process Launch (Header level)
b)      On Final Approval (Line Level)
c)       On Final Denial (Line Level)
d)      Route For Approval (Line Level)



If generic templates had been created earlier step , then mention those names here to each event respectively, but this is not mandatory.  For header level approval, all the events specified, including “On Final Approval” and “On Final Denial” must be given as Header level only.

Step 9: Navigate to Set Up HRMS -> Common Definitions -> Approvals -> Approval Process Setup. Add a new Definition ID for the process id created.


a)      The checkbox “Take Action on Line Completion” gets automatically checked for line level approval.
b)      Approver Userlist can be created by mapping it to a specified role or Application Package, SQL or Query. The  approvalof  submitted transactions are  based on certain criteria.
c)      Stage is a collection of paths and can be at header level or line level. As level here, specify line level is being used here , create 3 paths.
d)      A path is a collection of steps and since we have 3 items here.Once a transaction is being submitted,it will route to three different approvers as shown above.
Printer – Department Head
Laptop - Manager
Desktop – Admin
e)      Click on the Definition Criteria and Alert Criteria links and give it as always true. In all the three path level criteria, mention the criteria as “User Entered” and enter the record field value which must be considered for approving.




 In the above screenshot, the value is entered as “L” which stands for Laptop. So, the Userlist mapped to this value can approve only Laptop transactions. Similarly, for Desktop and Printer, criteria is added and values are given as “D” and “P” respectively.

Step 10: In the backend, the coding in work record buttons FieldChange and the Component PostBuild are same as the Header level coding. There are few changes in SavePostChange coding for passing the line record which is highlighted below. The coding in Application Package includes two more events “OnLineApprove” and “OnLineDeny” other than the events used in Header level approval.
   Component SavePostChange:
/***
 * AWE SavePostChange Code
 * This Save Post Change Code Will Handled When Submit, Approve & Deny Action Performed
 **/

/** Import Approval Framework Base Classes */
import EOAW_CORE:LaunchManager;
import EOAW_CORE:ApprovalManager;

/** Declare functions*/
Declare Function createStatusMonitor PeopleCode EOAW_MON_WRK.EOAW_FC_HANDLER FieldFormula;

Component EOAW_CORE:LaunchManager &c_aweLaunchManager;
Component EOAW_CORE:ApprovalManager &c_aweApprovalManager;

Component string &sbmt_action;
Component string &c_AWEProcessDefnID;
Component Record &headerRec; /** We have set it Component Level, So Get Acess to Others Component **/

Component Rowset &line_rws;
Local Record &line;
Local number &i;

&line_rws = GetLevel0()(1).GetRowset(Scroll.KOV_TEST_LINE);

Local boolean &IsActionTaken = True;
Local string &sActionMsgString = "";

Evaluate &sbmt_action
When "S"
   /* Call DoSubmit, passing in current header info.  ;*/
   /** It is always safe to call this method (as long as the header record being passed in is valid!), */
   &c_aweLaunchManager.DoSubmit();
   If (&c_aweLaunchManager.hasAppInst) Then
      /** Initialize Approval Manager if transaction was submitted */
      &c_aweApprovalManager = create EOAW_CORE:ApprovalManager(&c_aweLaunchManager.txn.awprcs_id, &headerRec, %OperatorId);
   End-If;
   Break;
When "A"
   /* Call DoApprove, passing in current header info. */
   For &i = 1 To &line_rws.ActiveRowCount
      &line = &line_rws(&i).GetRecord(Record.KOV_TEST_LINE);
      &c_aweApprovalManager.DoApprove(&headerRec);
      &c_aweApprovalManager.DoApprove(&line);
   End-For;
   Break;
When "D"
   /* Call DoDeny, passing in current header info. */
   For &i = 1 To &line_rws.ActiveRowCount
      &line = &line_rws(&i).GetRecord(Record.KOV_TEST_LINE);
      &c_aweApprovalManager.DoDeny(&headerRec);
      &c_aweApprovalManager.DoDeny(&line);
   End-For;
   Break;
When-Other
   &sActionMsgString = "Error - Invalid Action.";
   &IsActionTaken = False;
End-Evaluate;

/** Show Transaction Status Monitor & Save & Submit Button **/
If &c_aweApprovalManager.hasAppInst Then
  
   REM &IsActionTaken = &c_aweApprovalManager.hasPending;
   createStatusMonitor(&c_aweApprovalManager.the_inst, "D", Null, False);
   KOV_TEST_WRK.EOAW_SUBMIT.Visible = False;
   KOV_TEST_WRK.EOAW_APPROVE.Visible = False;
   KOV_TEST_WRK.EOAW_DENY.Visible = False;
End-If;

/* Reset &Action to Null */
&sbmt_action = " ";


Application package:
/***
 * Approval Event Handler Class
 * This Handle All the AWE Events
 *Event values include:
 */

import EOAW_CORE:ApprovalEventHandler;
import EOAW_CORE:ENGINE:AppInst;
import EOAW_CORE:ENGINE:UserStepInst;
import EOAW_CORE:ENGINE:StepInst;
import EOAW_CORE:ENGINE:Thread;
import EOAW_CORE:*;

class ApprEventHandler extends EOAW_CORE:ApprovalEventHandler
   method ApprEventHandler();
   method OnProcessLaunch(&appinst As EOAW_CORE:ENGINE:AppInst);
   method OnLineDeny(&userstep As EOAW_CORE:ENGINE:UserStepInst);
   method OnLineApprove(&appinst As EOAW_CORE:ENGINE:AppInst, &thread As EOAW_CORE:ENGINE:Thread);
  
private
   instance Record &HeaderRecord; /** Declare Record Instance **/
end-class;


/** Constructor */
method ApprEventHandler
   %Super = create EOAW_CORE:ApprovalEventHandler();
   &HeaderRecord = CreateRecord(Record.KOV_TEST_HEADER); /** Set the Header Record **/
end-method;


method OnProcessLaunch
   /+ &appinst as EOAW_CORE:ENGINE:AppInst +/
   /+ Extends/implements EOAW_CORE:ApprovalEventHandler.OnProcessLaunch +/; /** Set Approval Prcoess **/
  
   Local string &item, &asset;
   Local Rowset &line_rws;
   Local Record &line;
   Local number &i;
  
   /** Update the Workflow Status **/
   &line_rws = GetLevel0()(1).GetRowset(Scroll.KOV_TEST_LINE);
   For &i = 1 To &line_rws.ActiveRowCount
      &line = &line_rws(&i).GetRecord(Record.KOV_TEST_LINE);
      &asset = &line.GetField(Field.ASSET_ID).Value;
      &item = &line.GetField(Field.KOV_ITEM_NAME).Value;
   End-For;
  
   Local Record &recHdrRecord = CreateRecord(Record.KOV_TEST_LINE);
   &recHdrRecord.GetField(Field.ASSET_ID).Value = &asset;
   &recHdrRecord.GetField(Field.KOV_ITEM_NAME).Value = &item;
  
   If &recHdrRecord.SelectByKey() = True Then
      For &i = 1 To &line_rws.ActiveRowCount
         &line = &line_rws(&i).GetRecord(Record.KOV_TEST_LINE);
         &line.GetField(Field.WF_STATUS).Value = "S"; /** Set InApproval Process **/
         &line.Update();
      End-For;
     
      GetLevel0().Refresh();
   End-If;
  
end-method;

method OnLineApprove
   /+ &appinst as EOAW_CORE:ENGINE:AppInst, +/
   /+ &thread as EOAW_CORE:ENGINE:Thread +/
   /+ Extends/implements EOAW_CORE:ApprovalEventHandler.OnLineApprove +/
   Local string &as, &kov;
   Local Record &poRecord;
   Local EOAW_CORE:ApprovalManager &appMgr;
   Local number &lineNbr;
  
   /*---Line Approval---*/
   &poRecord = CreateRecord(Record.KOV_TEST_LINE);
   &thread.SetAppKeys(&poRecord);
   &as = &poRecord.ASSET_ID.Value;
   &kov = &poRecord.KOV_ITEM_NAME.Value;
  
   SQLExec("UPDATE PS_KOV_TEST_LINE SET WF_STATUS = :1 WHERE ASSET_ID = :2 AND KOV_ITEM_NAME = :3", "A", &as, &kov);
   GetLevel0().Refresh();
  
end-method;

method OnLineDeny
   /+ &userstep as EOAW_CORE:ENGINE:UserStepInst +/
   /+ Extends/implements EOAW_CORE:ApprovalEventHandler.OnLineDeny +/
   Local string &as, &kov;
   Local Record &poRecord;
   Local EOAW_CORE:ApprovalManager &appMgr;

Local number &lineNbr;
  
   /*---Line Approval---*/
   &poRecord = CreateRecord(Record.KOV_TEST_LINE);
   &userstep.step.path.thread.SetAppKeys(&poRecord);
   &as = &poRecord.ASSET_ID.Value;
   &kov = &poRecord.KOV_ITEM_NAME.Value;
  
   SQLExec("UPDATE PS_KOV_TEST_LINE SET WF_STATUS = :1 WHERE ASSET_ID = :2 AND KOV_ITEM_NAME = :3", "D", &as, &kov);
   GetLevel0().Refresh();
  
end-method;


Step 11: The coding and configuration is complete.
Now  this can be tested by log in  to PIA with the requestor’s id and add a new transaction.Below screenshot shows a  submitted  transaction for Laptop and Printer and it has been routed to two different approvers,showing the line level approval.


Step 12: To approve this transaction, login with one of these approvers‘ id. For example, login with the Department Head’s ID and approve/deny the transaction. Since the Department Head is mapped to the asset Printer, once Approve button is clicked, the Printer line alone gets approved as shown below.
 



Best Practices
  • In line level approval, the line level record must be passed in all events except OnProcessLaunch which is done at header level only.
  • The header record is usually given as the search record in the component.
  • A line record cannot be used alone in transaction registry and can be used only along with a header record. The cross reference record in this case must have the line record key values.
  • An approval process once created and if some transactions have occurred, cannot be modified.The same Process ID has to be cloned with a different effective date in order to modify it. The older ones have  to be made INACTIVE.

         Author:
  Felice Jennifer
  Kovaion-Peoplesoft Consulting Practice
        Email: felice.jennifer@kovaion.com

13 comments:

  1. Brilliant Article Felice. Quite Detailed. Good one.

    ReplyDelete
  2. Very good contribuition. God blessed you!

    ReplyDelete
  3. Crystal clear explanation. Thanks very much..

    ReplyDelete
  4. Excellent Practice..Very Very helpful..

    ReplyDelete
  5. Great Article and it is very useful

    ReplyDelete
  6. Excellent Article.

    ReplyDelete
  7. Hi Felice,
    Could you please explain what the below classes does
    AppInst
    UserStepInst
    StepInst
    Thread
    Thanks :)

    ReplyDelete
  8. Nice Article for AWE with header and line records

    ReplyDelete
  9. Nice Article with detailed explanation

    ReplyDelete
  10. Nice explanation and easy to understand step-by-step how to do

    ReplyDelete
  11. Excellent blog I visit this blog it's really awesome. The important thing is that in this blog content written clearly and understandable. The content of information is very informative.
    Oracle Fusion HCM Online Training
    Oracle Fusion SCM Online Training
    Oracle Fusion Financials Online Training
    Big Data and Hadoop Training In Hyderabad

    ReplyDelete
  12. Very interesting blog Really excellent information and thank you for giving your valuable information

    Oracle Fusion HCM Online Training

    ReplyDelete