[SalesForce] Validation rule to prevent a profile user to edit a record in certain case

I have setup a validation rule to prevent any user with a particular profile(Worker) not to edit the record except the status field. This record is of Case object. I wish to allow the user to update only the case status to close when the recordType is "NmN Record Type"/'PHN Record Type', meaning when the record is owned by NMN group then do not allow the "Worker" profile to edit it. Below is my validation rule:

AND
(
  OR(
     AND($Profile.Name ='Worker',TEXT(Status)!= 'Closed',ISCHANGED( Status)),
     AND($Profile.Name ='Worker',NOT(ISCHANGED( Status )), NOT(ISNEW()))
    ),
  OR(RecordType.Name = 'NmN Record Type' , RecordType.Name = 'PHN Record Type')
)

My problem – I have a process builder which fails due to this validation rule. The process builder tries to update the case's status to New when it is created for the first time. I want to prevent the user to not edit the record after it has been created for the first time. It seems this condition is becoming true when the process builder tries to update the record – AND($Profile.Name ='Worker',NOT(ISCHANGED( Status )), NOT(ISNEW()). Does'nt the PB runs in system context though? How to allow Process builder to update the record without even though validation rule passes? Any insight is appreciated.

I also look at this article – https://help.salesforce.com/articleView?id=000247715&type=1

Best Answer

You generally are not able to differentiate between a user directly making an edit to a record in the UI and some declarative or programmatic automation making an edit to a record while running in that user's context.

For example, if a user performs some action in the UI that results in a trigger firing, and that trigger updates some other record as a consequence, any subsequent automations that run based on that update cannot tell that the update was performed by the trigger as opposed to being performed directly by the user.

There's a larger issue here, and that's that your validation rule doesn't do what you want it to do. If we reformat it for clarity, it looks like this:

AND(
    OR(
        AND(
            $Profile.Name ='Worker',
            TEXT(Status)!= 'Closed',
            ISCHANGED( Status )
        ),
        AND(
            $Profile.Name ='Worker',
            NOT(ISCHANGED( Status )), 
            NOT(ISNEW())
        )
    ),
    OR(
        RecordType.Name = 'NmN Record Type', 
        RecordType.Name = 'PHN Record Type'
    )
)

Your stated objective is to allow the user with the profile 'Worker' to make no changes to the record save to move the status to Closed when it falls within the two record types you specify.

But what this validation rule does is to prevent Workers from either

  • Changing the status to any value other than 'Closed', regardless of any other changes to the record.
  • Changing the record without changing the Status.

So if they change the status to 'Closed', they can edit any other field on the object at the same time and your validation rule will not fire.

There's not a good way to do what you want with a validation rule. You can do it with a trigger, by looping over the fields on the new and old objects to validate the total extent of the changes. Alternately, you can override the edit function with a Visualforce or Lightning page, which would achieve your objective of enforcing this validation only for changes made through the UI, since it wouldn't affect non-UI automations.

Another option would be to completely remove Edit permission for the Worker profile, so they cannot edit it in the UI at all. Then, provide them with, for example, a Visualforce-backed button that's surfaced only on these record types and allows them to move the status to Closed, while deliberately ignoring FLS.