Flows | Do Validations Using Before Save Update Flow in Salesforce

In this article I am talking about Before Save Flow in Salesforce.We will see how can we use Before Save Update Flows to fire Validation Rules and perform complex data validations without custom code.

Perform Before Save Updates using Flows

Remember the time when for every small custom data validation we needed to write Apex Triggers. Just because Salesforce Validation rules are not capable of handling custom scenarios say for
Before Update Flows in Salesforce
example duplicate data checks, data integrity checks etc, we mostly had no other option than to write Apex Triggers. Even other out of box features like workflows, process builders fail us during these times as they cannot be used for data validations effectively.

Well we can now say good bye to those days! 

Salesforce Lightning Flows and Validation Rules to the rescue. Will try to show a simple hack which can be used at-least for less complex scenarios & we can avoid writing Triggers. 

Salesforce Record Triggered Flows - Before Save Flow 

Salesforce had launched the Autolaunched Flow with a Record Trigger capability in Spring'20 release. A record-triggered flow runs when a record is created or updated automatically. 

A record-triggered autolaunched flow makes additional updates to the triggering record before it's saved to the database. A record-triggered flow can update a Salesforce record 10 times faster than a record-change process as per Salesforce's official documentation.

Checkout great stuff about these type of Flows here: Record Triggers for Flows That Make Before-Save Updates

Main Takeaways from this article
  1. How to use Record-triggered Autolaunched Flows for before-update or before-insert scenarios.
  2. How to use a combination of Autolaunched record triggered Flows and Validation Rules to perform Custom Validations before a record is saved to database (inserted or updated).
  3. Flows are Awesome!

How to use Before Save Flows to Fire Validation Rules and Perform Data Validations

Sample/ Hypothetical use case:
Whenever a new Contact record is inserted in Salesforce, we need to check if that has a linked Account or not(Basically while creating contact did user provide any account in the Account lookup field of contact) . If the contact was created with an Account populated, then we need to check if this particular Account has any other Contact (child record) with same name as of this newly inserted contact or not. If any existing contact with same name is found for the Account, we need to prevent this new Contact creation.

New Contact Inserted (Example- Name: John and Account Name : Apple) --> Check if  this Account (Apple) has any other Contact already with same Name (John) -- > If  such a Contact is found for the Account (Apple), stop the insertion/creation of this new Contact Record (John).

Please Note: The contact name criteria/check is for a same Account record only. Basically, we can have two Contacts with name John for two different Accounts but not on the same Account.

Challenges: 
Validation Rules cannot help in this scenario. They at most can fire if we are changing or checking any particular field on a particular record. They cannot check data and other records which are not related.
Process Builders and Workflows won't work too in this scenario since they are fired after validation rules in the Order of execution and they are not even designed for such scenarios.
Ok so do we write an Apex Trigger?

Note: To learn more about the Latest order of execution checkout this Salesforce help document : Order Of Execution. This is very important to understand the solution.

Solution/Approach:
We can use Record Triggered Flows which run before a record is saved to the database. 
These take the highest priority in the latest order of executionThese are fired even before Validation rules and even before triggers(after and before triggers). We will utilise this fact in our solution.
  • First we need to create one new Field (or we can use any existing field) on Contact object. This will be more clear later in the article. For our example, I am creating a new checkbox/boolean field on Contact Object with name (Prevent Save) .The default value for this new field is set as false or unchecked. This field should not be added to page layouts.
  • Next, we will create a Validation Rule on Contact object. This validation will fire whenever "Prevent Save" field value is true/checked on contact records.
  • Lastly, we will create a Before Update Record Triggered Flow, which will check for the matching criteria when any new Contact is created/inserted and if it finds records that match our criteria(record with same name on related Account), it will update this newly created boolean field on Contact(Prevent Save) with value as checked/True. 
  • Since as per latest order of execution, after this flow runs, Validation rules will run, the error condition for the validation which we created will be matched and validation rule will stop the duplicate/new record creation.
Please Note: As a best practice and to keep the org clean, we should not create many new fields for any new validations.Try to generalise all the validations(for an event like before insert or before update) by bucketing them and create new fields only if absolutely necessary. For example: If there are multiple validations for a single object on before insert, we should try to utilise a single field at the end of all conditions and set this field true when all or any of criteria matches as per the requirement.

Consideration: If you plan to use generic Validation Rule for multiple scenarios, the validation error message for all of them will be same. This is an important consideration if you need to show different validation error Messages in different scenarios. In that case, may need to create separate Validation Rules.

Prerequisites 

Custom Field: New Boolean/Checkbox Field on Contact Object- Prevent Save.
Validation Rule: As described above , create a simple validation rule for Contact (Will fire when Prevent Save is True) and throw a sample error " Same contact is already on the Account". 
Flow: Flow is the main component of this post. Please see the design and implementation steps below. Flow will first try to find any records for matching criteria on contact insert , and if found it will just set the value of Prevent Save field as true which in turn will fire the validation rule and prevent record creation. Let's jump into the action.

Please Note: In order to try and showcase a Specific Use Case, I may have overlooked some of the best practises related to Flow Development in this article. Please make sure to follow these in real world scenarios and projects. Check some really important ones below.


Flow Design
Before Update Flows in Salesforce
This flow has 6 elements. Below are the details and step by step video to create each one.


1. Start Element: 

This is where we will define the type of flow that we are creating. After clicking new flow, select Autolaunched Flow.
Record Triggered Flows Salesforce

Select the "New or updated records—flow makes fast field updates" option
Also, Select in Choose When to Launch the Flow options, select When the record is created as in this example we are only checking criteria if a new contact is inserted.

Select the object as Contact as we are doing validation on that object.

Most Important Note Related to Before Update Record Triggered Flows: 
  • The $Record global variable contains the values from the record that triggers the flow to run. As a result, there’s no need to add a Get Records element to obtain the record data nor create flow variables to store the record data. This we will see in action in next steps. Checkout Video.
  • When the flow changes the values in the $Record global variable, Salesforce automatically applies those new values to the record. So there’s no need to add an Update Records element to save the new values to the database.
  • Only these elements are supported: Assignment, Decision, Get Records, and Loop. These elements let you obtain data from other Salesforce records, and use them to decide whether to update the triggering record’s fields and to what values.
2. Decision Element: This flow will be triggered whenever a new contact is inserted in the system. Not every contact will have account field populated as that is not a required field on contact. But since we need to run this check only if Account is populated on the contact, we first need to check if the newly inserted contact has any Account populated or not. If there is no Account on contact then we anyways don't need to do any validations and it can be saved.

Check out the video and note how to use the $Record variable I mentioned before. This is most important concept about record triggered flows.
3. Get Records Element: 
In the last step we checked if an Account is present on the Contact or not. If account was populated on Contact, we will just use this Get element to find all the matching Contact records for the Account(if Any). For the sample use case and scope of this article, I am using FirstName and Last Name to identify the duplicates/matching Contacts. So basically we will find all the Contacts for this Account with the same First and Last Name as the Contact record which was inserted and fired this flow.
We will select the object as Contact in Get Record Element as we are querying-on/finding contacts. Also, we will search/query for those contacts which have First Name, Last Name and Account equal to the First Name, Last Name and Account of the newly inserted Contact.

Please Note: We will use the  $Record.AccountId to make sure that we are finding only the contacts with the same Account as on this newly inserted Contact(that fired this flow) and not any other Account in the org as per our requirement. Video Below
4. Decision Element:
In this element we will just check if our Get Element returned any matching Contacts in last step. Basically it's like checking if our Search for matching contacts returned any values/results or not.
If any matching contacts were found then only we will proceed otherwise we need not do anything and let the record save successfully. 

Note: Check video how to use the variable of Get Record Element in the last step. Basically whenever we search for any records using Get Records, a variable is assigned to that automatically to fetch those records and we need not assign them to a new variable.In our scenario, if we find even one matching record of contact that is enough to stop this new contact from Saving. So we will check if the Get Records Element returned any values or not by using Null Check. Video Below:

                                           

5. Assignment Element: This is the place is where all the good stuff happens. If all the conditions are satisfied and we have found at-least one matching contact records, we will just use this to update/assign the field value of the field "Prevent Save" of the newly created contact. We will set "Prevent Save" as true using this assignment element.

Note: As mentioned above, we will use the $Record global variable again to just assign this value. This is a very important concept. We need not save this record after assigning as it is a before update flow and eventually system will save the record (Obviously if we don't stop/prevent it as we are doing in this case).


It's Done!

Now, since we have updated the "Prevent Save" field of the Contact, our flow's work is done. Now as per the Order of execution, Validation Rules will run after this and they will check on the latest values in the fields of this contact. Because of this fact, validation rule that was created by us earlier will be fired as its criteria will be met ("Prevent Save" equals true) and it will stop this new Contact record from getting saved. 

To learn more about the Latest Order of Execution checkout this Salesforce Help Link: Order Of Execution.

Hope this helps!

If you like this please do Share! #Learn and Share!
Enter your email address:


Delivered by FeedBurner

Comments

  1. why i cant use core actions in this type of flow?

    ReplyDelete
    Replies
    1. This is before save flow. We can use core actions after flow is triggered as per requirement.

      Delete

Post a comment

Thanks for your Feedback!


Never Miss Latest Posts