Locking a Record From Editing

An interesting conversation came up on Twitter today with @SFDCMatt. he was looking for a way to lock a record from being edited even by the record owner after some criteria was met. For a while, there were lots of ideas thrown about such as validation rules and changing the record type so it uses a different page layout. Both of these solutions weren’t ideal. Validation rules happen after the user has entered in a bunch of data and then, wham! they can’t save. So frustrating! Also, you’d have to check every field to see if it had changed. Changing the record type is another option, but users can still edit the record through the API or list view edit functionality.

We then came around to Approval Processes and how they can lock the record. Now wouldn’t it be nice if we could lock the record too? Unfortunately, there isn’t a way in workflow rules or apex to just set an isLocked field to true. Wouldn’t that be nice? Go vote now!

Now that we’ve whined about this lack of functionality, let’s try to work around it. I found that you can submit a record for approval from Apex. I immediately started thinking of triggers, so when I got home, I whipped up a solution pretty quickly. (Yeah, I lead an exciting life.)

First, let’s set up an approval process. I want my Account records to lock after the rating is changed to Cold, so I’ll set that as my entry criteria. You need at least one step in an approval, but I didn’t want to deal with it, so I set the criteria on the set to False. This means that as soon as the record is submitted for approval, it is approved and left locked!

Approval Process to Lock Record

Now all I need is a trigger to catch the event and submit the approval:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
trigger AccountRecordLock on Account (after update, after insert) {
  for (Account a : Trigger.New) {
    if (a.Rating == 'Cold') {
      // Create an approval request for the account
      Approval.ProcessSubmitRequest req1 =
      new Approval.ProcessSubmitRequest();
      req1.setComments('Automatic record lock.');
      req1.setObjectId(a.id);
 
      // Submit the approval request for the account
      Approval.ProcessResult result = Approval.process(req1);
    }
  }
}

Now as soon as I save a record with a Rating of Cold, the approval process kicks off and locks the record. Only users with Modify All permission on the object can now edit it!

You can add the Approval Process related list to the view to see that the approval was kicked off.

Custom Settings and Validation Rules

I’ve had this same conversation several times over the past month, so thought I’d make a post about it. This isn’t a new trick and there are probably dozens of posts on this same topic. Hopefully I can add a little bit of new information.

Custom Settings are hidden under the Develop section of Setup so many people aren’t even aware they are there. I’ll be covering hierarchical custom settings in this post. A hierarchical custom setting allows you to set values at the org, profile and user levels. When a custom setting is requested for a particular user, Salesforce returns the lowest level available.

Consider these two use cases: you are doing a big data load and validation rules would prevent the data to be loaded. You have an object that a lot of users have edit rights on, but you only want a subset of users to be able to make changes to a particular field. We can use custom settings to help us out.

1. Create a new custom setting. Note that you want the Setting Type to be Hierarchy. Visibility doesn’t matter unless you are including the custom setting in a managed package.

Creating a Custom Setting

2. Add a field to the custom setting. This will be used to bypass all the validation rules.

Creating a Custom Setting Field

3. Add values at the different hierarchy levels you need. Let’s first just add an org-wide one to require all validation rules to work. To add values, you click on the “Manage” link for the custom setting and then click on the “New” button.

4. Update your validation rules. Let’s say we have a validation rule that requires Accounts to have an Annual Revenue greater than $1,000. Our validation rule will look something like this:

!$Setup.ValidationsRules__c.BypassRules__c &&   AnnualRevenue <1000

The first part of this validation rule checks to see if we can bypass the validation rules and the second part is the actual rule.

Now you can add a hierarchy level to the custom setting at the profile or user level and check the box to allow those users to save records even if their Annual Revenue is less that $1000.

To meet the other need to only allow some users to edit specific fields, the concept is the same: create a new custom setting, add a field and then set the values as needed. Your validation rule would look something like this:

!$Setup.ValidationsRules__c.BypassRules__c && IsChanged(AnnualRevenue)

A couple of things to note:

  1. Use a different custom setting for each of these scenarios. If you use the same one with multiple fields, it will be harder to keep track of who has what defaults.
  2. You can also use custom settings in formula fields!

How do you like to use custom settings in the admin world?

Accessing Salesforce Object Tabs Without Actually Creating a Tab

Here’s a quick tip I use quite often. Sometimes I don’t actually want to create and use up a tab in my org for custom objects, especially when the object is usually accessed through related lists on another object. Sometimes I want to see all the records without going through a parent. In those cases, you can access the tab page using a URL trick:

1. Figure out what the key prefix is for the object. This is the first three characters of the object ID. You can use http://workbench.developerforce.com to find this prefix. Go to Info -> Standard and Custom Objects and select the object you want. Expand the Attributes and look for keyPrefix.

2. Once you’ve got the prefix, point your browser to https://yourinstance.salesforce.com/prefix/o. So to get to Accounts, you’d go to: https://na12.salesforce.com/001/o.