17th Sep 2018

Declarative Record Deletion Handling Without Process Builder in Salesforce CRM

by: Tim Combridge

blog hero img

The Problem: Process Builder Can't Handle Deleted Records

Process Builder is one of the brilliant declarative tools within Salesforce CRM. It allows us to perform various actions on records as they are created or updated. One unfortunate downfall that it currently has is that it can’t handle records as they are deleted.

We use Process Builder and Flows a lot in our work. We love these tools because they’re declarative (doesn’t require code to work with), meaning we can build something and train our clients to understand and update it where required with ease. We love that a record can be passed through Process Builder into a Flow (Visual Workflow) to perform more complex actions (loop through child records and perform updates, post to a Chatter Group, send an email notification, etc).

One thing we wanted to be able to do was to create complex actions using Flows and have them fire when a record is deleted. As we’ve mentioned previously, Process Builder is not able to handle these deletions so we do require a very small amount of code to begin with.

Don’t worry if you’ve never coded before; we’ll walk you through the very short process below.

 

Writing the Trigger

The first step is to open Developer Console. You can find this by clicking on the icon.

From here, click New, Apex Trigger, and give your trigger a name. Best practice suggests that we have a single Trigger for each Object. In this example, I’m creating opportunityTrigger for the standard Opportunity object.

The first thing you’ll want to do is change the default first line from before insert to before delete. What this does is it tells Salesforce that this Trigger is going to handle records that are deleted.

The next step that we need to do is set up a section within the Trigger that specifically handles the deleted records. This is basically like setting a criteria node within Process Builder.

Now the most important part - what is the one action we use the most in Process Builder? At Liquid, we find that if something requires some complex processing, we push it into a Flow to be handled further. However, just like in Process Builder, we will need to push values into the Flow to make it function correctly. In this example below, we’re pushing the Opportunity record that triggered the Process into the ‘Update Primary Campaign Source’ Flow.

There’s a few things we need to do in the code to achieve the same thing. Once again, it might look daunting at first, but I can guarantee you’ll wrap your head around it pretty quickly. Let’s break it down together.

The first thing we need to do is specify the parameters to push into your Flow. This means that your variable inside the Flow needs to be set to ‘Input Only’ or ‘Input and Output’.

Your variables are made up of a key (the name) and a value (the value given to the variable). In Apex, this is known as a key-value pair and they are stored within a Map. Create a Map in your code for any variables that you want to push through to the Flow. In our case, we’re pushing the Opportunity’s Id as ‘recordId’.

The code above simply creates an empty map, so now we need to populate it.

We’re going to achieve this for what’s known as a for loop, which is very similar to a loop within your flows. Essentially, for every Opportunity (we’ll call it ‘o’) that is deleted (for (Opportunity o : Trigger.old)), we want to put its Id into the ‘recordId’ variable (params.put(‘recordId’, o.Id)).

Once we have our variables populated, we’re then ready to start the Flow. We do this by creating a new instance of the Flow, giving it our parameters, and telling it to start.

And that’s it! You can then declaratively build your Flow to handle the more complex data processing. All you need is a few lines of code to have the deleted record data passed into the Flow, and you’re good to go!

There’s a bit to take in, but it’s a very cookie-cutter technique that you can repeat for different objects to get some practice. I’ll also add the finished code to the bottom of this post for your reference.

Trigger Sample

This is the trigger that we built in the article above. Any line starting with '//' is a comment used to explain the code, and is not required for the trigger to function. Important parts have been bolded. 

trigger opportunityTrigger on Opportunity (before delete) {
if (Trigger.isBefore){
if (Trigger.isDelete){

//Our first step is to create an empty map of the Oppotunities.
//A map is made up of a key and a value
//In this case, the key is the Variable Name from the Flow,
//and we will assign it a value from the Opportunity
Map<String, Object> params = new Map<String, Object>();

//We then populate this list with any Opportunity record
//in Trigger.old (the Opportunity records that were deleted)

//for any Opportunity (we'll call it 'o') in the Trigger.old list
for (Opportunity o : Trigger.old){
//We're going to give our variable 'recordId' a value
//The value will be the Opportunity o's Id
params.put('recordId', o.Id);

//After we've set our variables, we're ready to call the Flow itself
//and pass those values into it. We create a new instance of our Flow
//called 'flowRun', and pass the 'params' map into it.
Flow.Interview.Update_Primary_Campaign_Source flowRun = new Flow.Interview.Update_Primary_Campaign_Source(params);
//Then, we tell it to start
flowRun.start();


}
}
}
}

Blaze Your Own Trail!

Want to learn more?

Simple

Build a Discount Calculator

Create a Satisfaction Survey

Advanced

Quick Start: Apex Coding for Admins

Apex Triggers

 

 

ABOUT THE AUTHOR

Tim Combridge

Tim is Liquid's Lead Salesforce Consultant