Use Apex Code to Dynamically Select the Approver in a Salesforce Approval Process

One of the most frustrating things about Salesforce Approval Processes is that you can’t really use complex business logic to route the approvals to the right person without creating a lot of tedious approval steps and hardcoding users. In this tutorial, I will show you how you can use Apex code to build complex logic to tell Salesforce who the approver should be.

advertisement

The Problem

If you are anything like me, the first time you wrote an Approval Process in Salesforce, your first thought was probably: “Wow, this is super powerful”. And your second thought was probably: “Wow, this is painfully limiting”.  Let’s face it, if you want to have complex routing of approvals, you have to create a bunch of tedious approval steps and often it involves hardcoding users in the process which is never a good thing. Fortunately, there is a way to use Apex code to route approvals for your processes but we have to get a little tricky.

The Solution

YouTube blocked at work? No Headphones in the office? No worries, Just keep reading!

Overview

So the heart of this solution lies in the fact that you can add an Initial Submission Action to your approval process. This action can update a field on the record that was submitted but more importantly, it will update the record before locking it so that the update trigger for the record will fire. This is crucial because you can’t write a trigger on any of the approval process tables. Once the trigger fires, it will execute apex code to select a user to be an approver. Then the trigger will update a custom  Hierarchical Relationship field on the the record owner’s user record. Then immediately after, the Salesforce approval Process will assign the approval to that user.

This is great because the apex code runs every time the Submit for Approval button is clicked so the field on the user record will always be updated right before the approval is assigned. Have a look at the graphic below to see how it all works.

conditional-approva-routing-diagram-for-web

Step 1 – Create a Hierarchical Relationship Field

  1. Go to  Setup  Customize  Users  Fields and scroll down to the User Custom Fields section
  2. Click the New button
  3. Select the Hierarchical Relationship data type and click Next
  4. Give the field a name. In the example code I used Special Approver for the Label and Special_Approver for the Name and Child Relationship Name
  5. Click Next
  6. Set the field level security as needed and click Next
  7. Click Save

Step 2 – Create a Custom Field on the sObject to be Approved

The example code here assumes that the we will be approving Contact records so we need to add a custom field to the Contact sObject. If you are going to write an approval process for another type of record, obviously, you would want to create the custom field on that sObject instead of on Contact. This field will server 2 purposes. Primarily, it simply serves as a field that can be updated for the purposes of firing a trigger in such a way that the trigger logic can understand that the record was just submitted for approval. Additionally, the field will show users that the record is in an approval process. This is a great field to show on reports. If you do decide to put it on the page layout it is important to set the field’s read-only property to true to prevent any records from running the approval logic in error.

For this example, I am using a checkbox. It will be checked when the record is in an approval process and unchecked when it is not. If you plan on having an approval process with multiple stages, you might consider using a picklist instead. This would allow you to set the picklist value to say “submitted” (be sure and update the code in the trigger to reflect this) and then for each approval step, you can change the picklist value to something that describes the state (e.g. “Awaiting Regional Approval”).
  1. Go to  Setup  Customize  Contacts  Fields and scroll down to the User Custom Fields section
  2. Click the New button
  3. Select the Checkbox data type and click Next
  4. Give the field a name. In the example code I used In Approval for the Label and In_Approval for the Name
  5. Click Next
  6. Set the field level security as needed and click Next
  7. Click Save

Step 3 – Setting up your Approval Process

You will obviously need to create an Approval Process. The only thing you will need to make sure you do is add a field update to the Initial Submission Action to check the checkbox we just created.

  1. Go to Setup  Workflows & Approvals  Approval Processes and setup an Approval Process that meats your business needs but don’t activate it yet
  2. While viewing the approval process, click the Add New dropdown button in the Initial Submission Actions section and select Field Update
  3. Give the field update a name and unique name. These values are not important for the sake of this tutorial. For the Field to Update picklist, select the checkbox we created in Step 2.
  4. Set the Checkbox Options to True
  5. Click Save

Now, it’s a good idea to go ahead and set up a Field Update to uncheck the checkbox whenever the record has been fully approved, fully rejected or recalled.

  1. Go to the Final Approval Actions section and follow the steps listed above except set the Checkbox Options to False.
  2. Then for the Final Rejection Actions and the Recall Actions, you can select the Add Existing button
  3. In the Search field, select Field Update, find the Field Update that you just created that unchecks the checkbox and select it
  4. Click the Add button to move it to the Selected Actions column
  5. Click Save
  6. Now you can activate your Approval Process

Step 4- Let’s Write Some Code

I am a firm believer in not adding any business logic in a trigger so all of our code will be in a utility class. There is a great article on Developer Force written by Kevin O’Hara that goes into more details of “Logic-less” Triggers.

Another widely-recognized best practice is to make your Triggers logic-less. That means, the role of the Trigger is just to delegate the logic responsibilities to some other handler class. There are many reasons to do this. For one, testing a Trigger is difficult if all of the application logic is in the trigger itself. If you write methods in your Triggers, those can’t be exposed for test purposes. You also can’t expose logic to be re-used anywhere else in your org. Good old OO principles tell us that this is a bad practice. And to top it all off, cramming all of your logic into a Trigger is going to make for a mess one day. To remedy this scenario, just create a handler class and let your Trigger delegate to it.”

DeveloperForce – Trigger Frameworks and Apex Trigger Best Practices

In this example I called the utility class ContactTrgUtilities and the trigger ContactTrg. This is a common naming convention but feel free to change the names if you need to. You will only have to modify the class name in the trigger code below if you use a different name for the utility class.

Apex Utility Class

Apex Trigger

And that’s it. You should be good to go.

 

 

 If you learned something here, or this helped you in a project, please leave a comment. I’d love to hear about it. Also please consider clicking the “+1” button below or sharing this post on your  favorite social network. Happy Approving 🙂
advertisement

Leave a Reply