Sync Next Approval Reason to CRM on Approve/Submit/Reject

In a typical business workflow, after a quote is created it goes through multiple approvals before the quotation is finalized. Oracle CPQs approval workflow engine allows setting up complex workflows with ease. However, integrating real time status of the workflow, the current approver and calculating approval future path is challenging.

This document contains a generic solution to calculate the next approval path and the next approval reason dynamically for any type of approval (sequential/parallel/combination) at real time.

Business Requirement:

Integrate the approval workflow data from CPQ cloud to CRM when the approval sequence is underway. The CRM system should have real time information about the current status of the approval workflow at every approval stage.

Provide a way for administrators to change the approvers and approval thresholds without code changes and deployments as these values change time to time as per the business needs.

Technical Challenge:

CPQ cloud is integrated with the CRM system (Salesforce) using Salesforce commerce integration managed package i.e. via integration XSLs.  When the salesrep clicks on “Submit”, the next approver should be calculated and passed on to the CRM. Subsequently, next approver should be calculated and passed to CRM on Approve/Reject actions as well.

The system attributes provided by Oracle CPQ will contain the next approver/reason information after the “Submit/Approve/Reject” action is performed. This information is not available at the time when integration XSLs are executed to perform the data sync.

The solution below describes one way to calculate the next approval workflow on click of Submit/Approve/Reject so we can sync the data back to CRM using integration XSL.

Sample Approvals Tree: (Note: This has also been validated with other Approval tree structures.)











In the tree structure above, we have the following possible approval paths:

  1. Regional Sales Officer –>Regional Sales Manager –>Regional Sales Director –>Geo VP –>WWVP
  2. Regional Sales Officer –> Regional Channel Manager –> WWVP
  3. Regional Sales Officer –> Global Accounting Manager –> WWVP

All the three paths converge at the same approval gate “WWVP”. But as the approval gates Regional Sales Manager, Regional Channel Manager and Global Accounting Manager are in parallel, the last approval gate WWVP will be reached only after all the active approval gates above it are approved.


Step 1:

  1. Store all approval thresholds for the corresponding approval gates/levels in a data table ‘approvalThresholds’.
  2. Create a commerce library function calculateApprovalStatus() which references ‘approvalThresholds’ data table and current workflow of the quote to determine the approvals required for the quote. This library function returns a dictionary approvalStatusDict which holds the status of all the approval gates. If an approver approves the quote, the corresponding gate will be set to false.


approvalStatusDict = dict(“boolean”);

{              // key :  approval gate , value : true/false [Value is true if approval is required]

                Regional Sales Officer = true,

                Regional Sales Manager = true,

                Regional Channel Manager = false,

                Global Accounting Manager = false,

                Regional Sales Director = true,

                Geo VP = true,

                WWVP = true,  


 Step 2:

Create a util library function calculateNextApprovalGates(). This util has approvalStatusDict(from Step1 ) as the input parameter.

Prepare a dictionary of arrays to hold all possible workflow combinations of the approval tree.


allPossibleWorkflowCombinationsDict = dict(“string[]”);


//[key = workflow combination array (approval gates are comma separated) ]

1=[ Regional Sales Officer, Regional Channel Manager, WWVP],

2=[ Regional Sales Officer, Global Accounting Manager, WWVP],

3=[ Regional Sales Officer, Regional Sales Manager, Regional Sales Director, GEO VP,WWVP],


Step 3:

Pull all the keys from above dictionary (allPossibleWorkflowCombinationsDict) to form the keys array as below.

allPossibleWorkflowCombinationsKeysArr = keys(allPossibleWorkflowCombinationsDict);

Step 4:

Sample Code:







As per our example if Regional Sales Officer is true, we will have [Regional Sales Officer] in the nextGateArray. Once the Regional Sales Officer approves the quote, the status for this gate gets set to false in the approvalStatusDict dictionary.

Once the nextGateArray array is ready, loop through the nextGateArray array to check whether there are any previous pending approval gates.

For instance, after the Regional Sales Officer approves the quote, we will have [WWVP, Regional Sales Manager] in the nextGateArray. But Regional Sales Manager is not at the same hierarchy level as WWVP and therefore we need to remove gate WWVP from the nextGateArray.

Sample Code:









The above solution gives us a list of next approvers/reasons which are pending for approval.We can now calculate the next set of approvers dynamically and send this information to the CRM at every approval stage.