Record Lock Validation

One of the most overlooked configurations I see in orgs is leaving records open to edits that should be locked.  For example, sales or support processes can drag on indefinitely if closed cases or opportunities remain editable.  Closed records should be closed.  Like Chick-fil-A-on-a-Sunday closed.

Locking records does not need to be complicated.  You don’t need a new “locked” record type that is updated by a trigger and assigned a page layout with read-only fields.  You don’t need a Visualforce page that replaces the standard edit button.  And no, you definitely don’t need a validation rule that checks for changes to every single field on the object.

Let’s explore how a record can be locked with a custom permission (optional) and a validation rule with only one or two criteria.

Use Case

Users at Universal Containers have been adding products to closed won opportunities, rather than creating a new opportunity to track new sales.  Additionally, users have been reviving closed lost opportunities for cold prospects that reheat in order to improve their win rate and avoid creating a new record.

Sales leadership would like to prevent these undesired processes since they are distorting a variety of sales metrics.  Luckily for UC, their Salesforce admin, Tom, can create validations that rule to lock down closed opportunities.

The Build

  1. Create and assign a custom permission.
  2. Write opportunity validation rule.
  3. Review automations.

Custom Permission

First, we need to define who can edit closed opportunities.

Rather than hardcoding profile or user parameters, create a custom permission: Modify Closed Opps. Custom permissions should always be used in place of profiles and users in validation rules as they are better to scale, maintain, and deploy.

Assign this custom permission to the system administrator profile and any other profiles that will need to edit these records. The custom permission can also be assigned to a permission set if needed by specific users.

We now have a clean exclusion in our validation rule:

NOT($Permission.ModifyClosedOpps)

Validation Rule

We next need to determine the criteria for this validation rule.  For this requirement, simply lock opportunities once they’re closed – won or lost.

Since we still need to allow users to close opportunities, but prevent edits thereafter, we will use the PRIORVALUE function.  This function will set a trap that allows records to enter a closed stage but will lock them once they do.  Combining this logic with our exclusion above, we get the following error condition formula:

AND(
NOT($Permission.ModifyClosedOpps),
PRIORVALUE(IsClosed)
)

…no more zombie opps.  If you have an opportunity process builder with IsClosed = True entry criteria, read-on.

Automation

There are three types of automated record updates that can be blocked by this validation that are outlined below.  Note that workflow rule field updates, scheduled actions, and account ownership transfers bypass validation rules.

  1. Process builder immediate action field updates.

Record updates that fire after a record is locked will result in the dreaded FIELD_CUSTOM_VALIDATION_EXCEPTION error.  To avoid this, I recommend one of two approaches: (1) use a validation rule to require users to manually update the field in question before the record is locked, or (2) exempt edits to the field(s) within the record lock validation rule with NOT(ISCHANGED([Field in Question]))

  1. Flow record update elements.

See #1 above.

  1. Apex updates.

As always, if you have custom code, run Apex tests to verify that the new validation rule does not cause your tests to fail.  Run tests early and often – your dev resource will appreciate it.

Summary

This simple solution can also be applied to closed cases, activated orders, or any other criteria that should render a record as read-only.  If you have a path or process with a defined end, consider this record lock solution to both improve data quality and encourage better business practices.

Leave a Reply

Your email address will not be published. Required fields are marked *