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__c
field. - Updates each Opportunity’s approver fields (
Approver1__c
andApprover2__c
) and sets thestatus__c
field 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
ApprovalMatrixMatch
that accepts a set of Opportunity IDs and returns a list ofApproval.ProcessResult
objects, 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__c
records 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__c
record 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
approvalMatrixMap
is checked for a matchingCountry__c
. - If a match is found, the corresponding approvers are assigned to the Opportunity, and the
status__c
field is set to “Open.” - The Opportunity is added to
updatedOpptyList
for later update, and its ID is added toOpptyIds
for approval submission.
Step 5: Update Opportunities
if (!updatedOpptyList.isEmpty()) {
update updatedOpptyList;
}
- Updates all Opportunities in
updatedOpptyList
with 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.ProcessSubmitRequest
objects 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.ProcessResult
objects 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
ApprovalMatrixMatch
method is called with a set of Opportunity IDs. - For each Opportunity, the method assigns approvers based on the country using the
Approval_Matrix__c
object, 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
ApprovalMatrixMatch
method 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__c
record, the Opportunity is skipped and does not receive approvers. - Such records are not added to
updatedOpptyList
orOpptyIds
, 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.ProcessResult
is 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.