Dynamic Approval Process
Dynamic Approval Process in Salesforce: Allocate the approvers dynamically to the record. Populate the approvers in the user lookup fields in the record.
In static approval process, we have to define the approvers in the approval process. Meaning whenever the record matches the approval process condition and approval process fires and associate the record to the approver which we define in approval process.
Always we cannot achieve business criteria with static approval process, meaning we have conditions like record should be routed to different approvers based on region, country or with some other criteria. We have to write one static approval process for each condition.
So to avoid multiple static approval process for the same requirement with same kind of implementation we will go for dynamic approval process.
– This process is full of apex and implementation is somewhat tricky but very powerful and useful for the huge projects.
– We have to write apex (triggers) to populate the approver in the record lookups.
– To achieve dynamic approval process we have to create one new object (approval matrix), which is useful to define all the conditions (region, country, etc…) and the approvers.
So once user clicks on SUBMIT button. We should fires apex code and check what and all the approval matrix matches to the record and we will take the approvers from the approval matrix and populate the approvers into the user lookups in the record, then we will fire the approval process. Inside approval process we have to define the steps like route process instance to approvers.
Example: Create an approval process on opportunity object, should be routed to base on Country. (Let say we have almost 200 countries in our project)
Steps to Implementation of dynamic approval process
1. Create User lookup fields and one picklist field (Status__c and values are Open, Submitted, Approved and Rejected).
2. Create an Approval process on Opportunity Object with Entry criteria is Status equal to Open.
3. Create one new Object called Approval Matrix to define all the conditions
4. Execute the below code on submit button.
public class OpportunityApprovalMatrix {
public static List<Approval.ProcessResult> ApprovalMatrixMatch(Set<Id> OpportunitySet) {
List<Opportunity> updatedOpptyList = new List<Opportunity>();
Set<String> countrySet = new Set<String>();
List<Id> OpptyIds = new List<Id>();
// Query Opportunities based on the given Opportunity IDs
List<Opportunity> opptyList = [SELECT Id, Name, Country__c, Status__c, Approver1__c, Approver2__c
FROM Opportunity WHERE Id IN :OpportunitySet];
// Clear approvers in Opportunity records and add countries to countrySet
for (Opportunity opptyRec : opptyList) {
opptyRec.Approver1__c = ''; // Clear previous approvers
opptyRec.Approver2__c = '';
countrySet.add(opptyRec.Country__c); // Add country for filtering
}
// Query Approval Matrix records based on countries found in Opportunities
Map<String, Approval_Matrix__c> approvalMatrixMap = new Map<String, Approval_Matrix__c>();
for (Approval_Matrix__c approvalMatrix : [SELECT Country__c, Approver1__c, Approver2__c
FROM Approval_Matrix__c WHERE Country__c IN :countrySet]) {
approvalMatrixMap.put(approvalMatrix.Country__c, approvalMatrix);
}
// Match Approval Matrix records with Opportunities by Country and update approvers
for (Opportunity opptyRec : opptyList) {
Approval_Matrix__c approvalMatrix = approvalMatrixMap.get(opptyRec.Country__c);
if (approvalMatrix != null) {
opptyRec.Approver1__c = approvalMatrix.Approver1__c;
opptyRec.Approver2__c = approvalMatrix.Approver2__c;
opptyRec.Status__c = 'Open';
updatedOpptyList.add(opptyRec);
OpptyIds.add(opptyRec.Id);
}
}
// Update Opportunities with assigned approvers
if (!updatedOpptyList.isEmpty()) {
update updatedOpptyList;
}
// Prepare and submit approval requests
List<Approval.ProcessSubmitRequest> submitOpptyList = new List<Approval.ProcessSubmitRequest>();
for (Id oppId : OpptyIds) {
Approval.ProcessSubmitRequest req = new Approval.ProcessSubmitRequest();
req.setComments('Submitting request for approval.');
req.setObjectId(oppId);
submitOpptyList.add(req);
}
// Process approval requests and return results
if (!submitOpptyList.isEmpty()) {
return Approval.process(submitOpptyList);
} else {
return new List<Approval.ProcessResult>(); // Return empty list if no submissions
}
}
}
The OpportunityApprovalMatrix class in Apex is designed to manage the approval process for a set of Opportunity records based on a custom approval matrix. Here’s an explanation of the code and its working scenarios.
Purpose of the Code
The OpportunityApprovalMatrix class contains a single method, ApprovalMatrixMatch, which:
- Matches each Opportunity record to approvers based on the
Country__cfield. - Updates each Opportunity’s approver fields (
Approver1__candApprover2__c) and sets thestatus__cfield to “Open.” - Submits the Opportunities for approval in bulk.
Code Breakdown
public class OpportunityApprovalMatrix {
public static List<Approval.ProcessResult> ApprovalMatrixMatch(Set<Id> OpportunitySet) {
- The class has a public static method
ApprovalMatrixMatchthat accepts a set of Opportunity IDs and returns a list ofApproval.ProcessResultobjects, representing the outcome of the approval submission process.
Step 1: Initialize Collections and Query Opportunities
List<Opportunity> updatedOpptyList = new List<Opportunity>();
Set<String> countrySet = new Set<String>();
List<Id> OpptyIds = new List<Id>();
- These variables are initialized to keep track of Opportunities to update, the countries present in these Opportunities, and the Opportunity IDs for approval submission.
List<Opportunity> opptyList = [SELECT Id, Name, Country__c, Status__c, Approver1__c, Approver2__c
FROM Opportunity WHERE Id IN :OpportunitySet];
- The code queries Opportunity records based on the provided IDs. It retrieves fields necessary for assigning approvers, setting statuses, and managing the approval process.
Step 2: Clear Previous Approvers and Collect Countries
for (Opportunity opptyRec : opptyList) {
opptyRec.Approver1__c = ''; // Clear previous approvers
opptyRec.Approver2__c = '';
countrySet.add(opptyRec.Country__c); // Add country for filtering
}
- Clears existing approvers on each Opportunity.
- Collects the countries into
countrySet, which will later be used to retrieve matching approval matrices.
Step 3: Query and Map Approval Matrix Records by Country
Map<String, Approval_Matrix__c> approvalMatrixMap = new Map<String, Approval_Matrix__c>();
for (Approval_Matrix__c approvalMatrix : [SELECT Country__c, Approver1__c, Approver2__c
FROM Approval_Matrix__c WHERE Country__c IN :countrySet]) {
approvalMatrixMap.put(approvalMatrix.Country__c, approvalMatrix);
}
- The code queries
Approval_Matrix__crecords where the country matches any of the countries incountrySet. - Creates a map (
approvalMatrixMap) where each country code (Country__c) is the key, and theApproval_Matrix__crecord is the value. This allows for efficient lookup.
Step 4: Assign Approvers and Update Opportunities
for (Opportunity opptyRec : opptyList) {
Approval_Matrix__c approvalMatrix = approvalMatrixMap.get(opptyRec.Country__c);
if (approvalMatrix != null) {
opptyRec.Approver1__c = approvalMatrix.Approver1__c;
opptyRec.Approver2__c = approvalMatrix.Approver2__c;
opptyRec.Status__c = 'Open';
updatedOpptyList.add(opptyRec);
OpptyIds.add(opptyRec.Id);
}
}
- For each Opportunity, the
approvalMatrixMapis checked for a matchingCountry__c. - If a match is found, the corresponding approvers are assigned to the Opportunity, and the
status__cfield is set to “Open.” - The Opportunity is added to
updatedOpptyListfor later update, and its ID is added toOpptyIdsfor approval submission.
Step 5: Update Opportunities
if (!updatedOpptyList.isEmpty()) {
update updatedOpptyList;
}
- Updates all Opportunities in
updatedOpptyListwith the new approver information and status, provided there are records to update.
Step 6: Create and Submit Approval Requests
List<Approval.ProcessSubmitRequest> submitOpptyList = new List<Approval.ProcessSubmitRequest>();
for (Id oppId : OpptyIds) {
Approval.ProcessSubmitRequest req = new Approval.ProcessSubmitRequest();
req.setComments('Submitting request for approval.');
req.setObjectId(oppId);
submitOpptyList.add(req);
}
- A list of
Approval.ProcessSubmitRequestobjects is created for each Opportunity ID inOpptyIds. - Each request includes a comment and sets the Opportunity ID as the object for submission.
Step 7: Process and Return Approval Results
if (!submitOpptyList.isEmpty()) {
return Approval.process(submitOpptyList);
} else {
return new List<Approval.ProcessResult>(); // Return empty list if no submissions
}
- The approval requests are processed in bulk, returning a list of
Approval.ProcessResultobjects that provide information on the status of each submission. - If there were no Opportunities to submit, an empty list is returned.
Working Scenarios
- Scenario 1: Standard Approval Based on Country
- The
ApprovalMatrixMatchmethod is called with a set of Opportunity IDs. - For each Opportunity, the method assigns approvers based on the country using the
Approval_Matrix__cobject, then submits each Opportunity for approval. - This scenario works well when there’s a clear, direct match between countries in Opportunities and the approval matrix.
- Scenario 2: Multiple Opportunities, Same Country
- When multiple Opportunities share the same country, the
ApprovalMatrixMatchmethod handles all of them by setting the same approvers. - This ensures consistency across Opportunities in the same region.
- Scenario 3: No Matching Country in Approval Matrix
- If an Opportunity’s country has no matching
Approval_Matrix__crecord, the Opportunity is skipped and does not receive approvers. - Such records are not added to
updatedOpptyListorOpptyIds, and they are not submitted for approval.
- Scenario 4: No Opportunities to Process
- If the provided set of Opportunity IDs is empty or none of the Opportunities match any country in the approval matrix, the method completes without updating or submitting records.
- In this case, an empty list of
Approval.ProcessResultis returned, indicating no actions were taken.
This method is efficient for managing Opportunity approvals based on location-specific criteria, providing flexibility for bulk processing and efficient approval management in Salesforce.