Configuration, Validation Rule

[ART-001] Validation Rule Implementation Pattern


This pattern will help you write dynamic validation rules to handle multi-country behavior. It also helps to activate or deactivate the rule based on Profile or Permission Set assigned to user.


Naming Pattern

ComponentValidation Rule
NameObjectName_VRXXX_Word1Word2
Ex: Account_VR001_StreetIsMandatory
DescriptionFree text
Ex: The field Street must contain a value.
Error MessageFree text
Ex: Please fill the Street field.

Step 1

Start creating a Custom Metadata Type that we will call “ValidationRules”. The reason behind is that it helps configuration to be deployed easily between orgs which is not the case of custom settings records that need to be handle manually. In the past we were adding this kind of information in the user Object but it doesn’t give the flexibility we have with this new settings implementation.

Alternatively, you can move this to Custom setting (hierarchical or not) but it implies more steps and more hard-coding from my point of view.

Step 2

Create a Text Field with length of 255 that we will call “Countries”. Picklist or Multi-Picklist are currently not supported in Custom Metadata types.

Step 3

Populate one record for our first validation rule that we are going to write.

LabelAccount validation rule 001
NameAccount_VR001
CountriesFR;GB

If your rule is meant to be applied to all countries then you can leave the field blank or add a default value ‘*’ for example.

Use a separator like ‘;’ between each country.

Step 4

Create 2 Custom Permissions to handle activation and deactivation of the rule.

Permission 1Permission 2
NameBP_ACC_VR001BP_ALL_VR

The first one will be used to deactivate all validation rules when the Custom Permission is assigned Profile or Permission Set.

The second one will be used to deactivate only this validation rule.

Step 5

We are going to write a simple validation rule for the Account object based on a standard field “BillingCountry”, we suppose this field will contain value like “FR”, “GB”, etc…

NameAccount_VR001_POC
DescriptionThis a POC.
ActiveChecked
Error LocationTop of Page or Field checked
Choose Field for better user experience
FormulaBelow
IF(
   NOT($Permission.BP_ALL_VR) &&
   NOT($Permission.BP_ACC_VR001) &&
   (
    CONTAINS($CustomMetadata.ValidationRules__mdt.Account_VR001.Countries__c,'*') ||
    CONTAINS($CustomMetadata.ValidationRules__mdt.Account_VR001.Countries__c,BillingCountry)
   ),
   true,
   false
)

Now you can save your formula and play with some records and profiles / permission sets to see the magic.

Another thing to retain that I’ve discovered recently is that every time you update the API name of the record of the Custom Metadata Type, it updates automatically the reference in your validation rule! Fantastic !

Step 6

Now that you have mastered the pattern, let’s go further. Imagine you were asked to write a specific rule for France and general rule for all other countries, you will start writing some “IF” condition to handle this.

IF(
   BillingCountry == 'FR', doSomething
   doOtherThing
)

As number of specificity grows, your rule will become complex to handle.

IF(
   BillingCountry == 'FR', doSomething,
   IF(
      BillingCounbtry == 'GB', doSomething, 
      doOtherThing
   )
)

Fortunately, we can rewrite this formula with the CASE function.

CASE (BillingCountry, 
      'FR', doSomething,
      'GB', doSomething,
       doOtherThing
)

Step 7

Sometime you have to write the same rule or same regexp for example for many fields that need validation, to avoid this you can consider using Custom Metadata Type again.

CASE(BillingCountry, 
     'FR', IF(1==1, 1, 0),
     'GB', IF(2==2, 1, 0),
      1
) > 0, 

Here we can replace a small part of the condition in order to reuse it elsewhere.

CASE(BillingCountry, 
     'FR', IF(1==1, VALUE($CustomMetadata.Rules__mdt.FR_R1.Value__c), 0),
     'GB', IF(2==2, VALUE($CustomMetadata.Rules__mdt.GB_R1.Value__c), 0),
      1
) > 0,

For this example, I have created a Custom Metadata Type called “Rules” with a custom Text(255) field named “Value__c”, and I have created one record per country to hold specific values to render.

The validation should run & block if  :

  • BillingCountry is GB or FR because only those are allowed for this rule
  • The user has no global or local bypass assigned
  • The result is greater than 0

Conclusion

Keep in mind that there are many ways to implement Validation Rule, but you have to design it well first in order to be scalable and maintainable. Some limitations introduce constraints (Number of characters, number of countries …) that can be challenging and make you rethink the initial design. Try to keep it simple, optimize the rule to reduce complexity and length, mutualize to reduce the number of rule and don’t forget to challenge your business 🙂

Hope you enjoy reading this article, see you soon for the next one ...

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.