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
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
- How to use Record-triggered Autolaunched Flows for before-update or before-insert scenarios.
- 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).
- 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 execution. These 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
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.
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:
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
1. Start Element:
This is where we will define the type of flow that we are creating. After clicking new flow, select Autolaunched Flow.
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.
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:
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!
To learn more about the Latest Order of Execution checkout this Salesforce Help Link: Order Of Execution.
Hope this helps!Don't Miss Latest Posts : CLICK HERE TO SUBSCRIBE TO THIS BLOG
Checkout this Article for all Flow Related Scenarios : All Flow Examples
See you next time!
why i cant use core actions in this type of flow?
ReplyDeleteThis is before save flow. We can use core actions after flow is triggered as per requirement.
DeleteGreat Post Vibhor Goel !!!
ReplyDeleteGreat solution! In order to be even more flexible, I create a number type prevent save field and assigned different numbers depending on the situation. Then, I used the number to give an meaningful error message for the user.
ReplyDeleteWow, it's a good trick. Thanks for the suggestion :)
DeleteError on record detail page looks ugly. Is there a way we can show only error message on record save instead of whole exception thing.
ReplyDeleteHow to reset the Prevent Save value to False ?
ReplyDeleteDid you find a solution to this?
DeleteHi , you do not need to set value, as the record is being update in the before update/insert and if exception happens, the field value is rolled back to its original value
DeleteHi I tried the steps you have given I am not getting the flows
ReplyDeleteI guess duplicate rule on contact object work here. If it Matches with account lookup field on a contact object
ReplyDeleteHey, When I click on Auto launched Flow in my org, I do not get the option for edition Start Element. I get it when I click on Record Triggered Flow. Any suggestions?
ReplyDelete