2

The Status field of Case and Opportunity objects cannot be read only for any profile. How could I prevent the manual changes only?

I've tried with a validation rule that allows a free choice when the case is created and block all changes to users different than System Administrator:

AND( 
  NOT(ISNEW()), 
  ISCHANGED(Status), 
  $Profile.Name<>"System Administrator" 
)

This one works fine for manual changes but it also blocks automate processes that should be able to change the field.

4 Answers 4

2

"Automated Process" is a real user profile under the hood. You should be able to check their profile/name and allow their edits.

In my org, "Automated Process" has a Name of Automated Process and a null profile.

Adding another check to your formula should do it:

AND( 
  NOT(ISNEW()), 
  ISCHANGED(Status), 
  AND(
      $Profile.Name != "System Administrator",
      Name !=  "Automated Process"
  )
)
4
  • Thanks, it works with automated process like Approval Processes but it doesn't work for Apex code (that run witthout sharing but launched by users). There is a way to make it work also in this case without introducing a dummy field like a checkbox?
    – gvgramazio
    Commented Mar 16, 2019 at 11:02
  • I posted an answer with a complete solution to my problem. Of course, without your help I would have not been able to find it so I marked your answer as the accepted one. However, if you are able to propose an even clearer solution please do it.
    – gvgramazio
    Commented Mar 16, 2019 at 11:52
  • Good answer! In my org, we use a custom setting to handle who has their rules turned on. It helps us avoid updating the users often, we just change the setting. Theres a whole class we use to handle the custom setting changes & state. Usually I only need to call it when theres a @future method which needs to run on questionable records. Commented Mar 18, 2019 at 13:41
  • Unfortunately is not my case. Also, it's almost impossible and surely unmaintainable to use either blacklist or whitelist regardless if in the form of groups, sharing rules, profiles or whatever (there are really too much of them and usually change without notifications). I think that for now I have to rely on the solution that I posted.
    – gvgramazio
    Commented Mar 18, 2019 at 15:39
2

The proposed solution works well with automated processes that run under the profile name Automated Process but doesn't work with Apex code that runs under the same profile name of the user that launched it.

A complete solution to my problem would be to create a dummy checkbox field (e.g. Status_Change_Enabled__c). Then use the following validation rule that takes into account both the case of automated process and Apex code.

AND( 
  NOT(ISNEW()), 
  ISCHANGED(Status), 
  AND(
      $Profile.Name != "System Administrator",
      $Profile.Name !=  "Automated Process",
      Status_Change_Enabled__c != true
  )
)

In order to make it works, one way is to:

  • Set the default value of the checkbox to false.
  • At each update of Status field through Apex, update also the value of the checkbox to true.
  • Use a trigger with after update that update the value of the checkbox to false again.

Since the trigger will be called after the validation rule, the status will be update successfully. The trigger will update only the checkbox, so there will be no problems with the validation rule. Be sure to not generate an infinite recursive loop of triggers call. A working example could be the following:

trigger CaseTrigger on Case (after update) {
    if (trigger.isAfter && trigger.isUpdate) {
        List<Id> case_ids = New List<Id>();
        for (Case c: Trigger.New) {
            if (c.Status_Change_Enabled__c) {
                case_ids.add(c.Id);
            }
        }
        List<Case> cases = [SELECT Status_Change_Enabled__c FROM Case WHERE Id IN : case_ids];
        for (Case c: cases) {
            c.Status_Change_Enabled__c = false;
        }
        update cases;
    }
}

Of course, the best practice would be to put it in a trigger handler.

Anyway, this implementation doesn't completely satisfy me because it's prone to errors since one should remember to update the checkbox each time an update of the status should be made. I encourage any of you that has a better way to handle this to post an answer.

0

What I did is quite similar but does not need a trigger, so maybe it helps you or others reading this question. In my case, the users should never use the status field in the layout and always use flows, because there is complex business logic running in the background based on the status field.

So I created a custom text field Last_Status_change__c which I use in every Process, Flow and Apex code to write the current DateTime in. This field is not on the Case Layout.

The validation rule to prevent the manual changes looks like this:

ISCHANGED(Status) &&
NOT(ISCHANGED(Last_Status_change__c)) &&
NOT($User.Bypass_Validation_Rules__c)

In this scenario we have a custom field on the User to define, who is allowed to bypass any validation rule, but of course you can replace this with $Profile.Name != "System Administrator"

Note: Pay attention to always use a formula that creates a time with seconds like 2020-06-17 16:34:26, otherwise you write something like 17/06/2020 17:29 into the field and the status field would be blocked for up to a minute.

Hope this helps. If you find an issue in this solution, of course let me know.

-1

This is another simple way of making sure that status is not changed once it has been completed.

AND(ISCHANGED(Status), ISPICKVAL( PRIORVALUE(Status),"completed"))

1
  • While this would work in the scenario you've provided, this question is about a rather different scenario (how do I prevent changes to status except if it's a system administrator or an automated process?)
    – Derek F
    Commented Jun 5, 2020 at 3:08

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .