13

I´m getting this Exception:

System.DmlException: Update failed. first error: ENTITY_IS_LOCKED, the entity is locked for editing:

The problem is that i´m updating a case that is locked by an approval process. I want to add a check in my APEX controller, in order to update the record only if not in an approval process.

How i can accomplish that?

1

4 Answers 4

25

From Winter16 you can check this using the Approval system class

Pass it the Id of a record you want to check if is locked or not:

Approval.isLocked(recordId);

Make sure you set the class api version to 35.0 or higher!

4
  • 2
    Things do change in 2 yrs. Thanks for posting this as an update to a 2 yr old question.
    – crmprogdev
    Commented Feb 14, 2016 at 18:58
  • This definitely deserves to be the approved answer. Far simpler than those already posted!
    – Adrian Larson
    Commented Feb 15, 2016 at 0:30
  • There is one edge case: after record was updated Approval.isLocked(recordId); still return TRUE. In other words the fact record is locked does not mean an approval process on this record is in progress Commented Sep 13, 2017 at 15:17
  • @Yury I think what your saying is that if your approval process doesnt unlock a record upon approval or rejection isLocked cant be reliably used as an identifier of whether the record is in an approval process or not right? while locking an being in an approval process tend to go hand in hand it doesnt necessarily always have to be the case, I think.
    – ebt
    Commented May 9, 2018 at 22:11
6

How I have handled this in the past (leaving out the part where we get a set of the record Ids were are processing stored in recordIds):

set<Id> existingApprovalsSet = new set<Id>();

list<ProcessInstance> existingApprovals = [SELECT Id, TargetObjectId
                                            FROM ProcessInstance 
                                            WHERE TargetObjectId IN :recordIds];

if(existingApprovals.size() != 0){
                for(ProcessInstance e : existingApprovals){
                    existingApprovalsSet.add(e.TargetObjectId);
                }
            }

for(SObject record : recordList){
                    if(!existingApprovalsSet.contains(record.Id)){
                        filteredRecordList.add(record);
                    }
                }

This will give you a list of just the records that do not have an approval process. You can then continue processing them however you would like. What this doesn't give you is whether the record is locked or not, because that can be controlled on the Approval Process. You can adjust the SOQL query on ProcessInstance to account for the status of the Approval Process to try to account for this i.e.:

list<ProcessInstance> existingApprovals = [SELECT Id, TargetObjectId
                                                FROM ProcessInstance 
                                                WHERE TargetObjectId IN :recordIds
                                                AND Status = 'Pending'];

Again, this will depend on how the Approval Process is setup and whether it locks records on Submission, Approval, etc.

2
  • 2
    Isn't a much simpler solution to add a field update to the initial actions of the approval process that sets a boolean custom field is_locked__c in Case to true (and another field update when the case leaves the approval process (final accept/reject/recall action to set is_locked__c to false? This is what I do. Then the controller merely looks at the is_locked__c field
    – cropredy
    Commented Mar 27, 2014 at 6:15
  • That would work as well, you should add it as an answer. :) Commented Mar 27, 2014 at 13:58
6

An alternative solution is to:

  • add a field update to the initial actions of the approval process that sets a boolean custom field is_locked__c in Case to true
  • and another field update when the case leaves the approval process (final accept/reject/recall action to set is_locked__c to false

Then the controller merely looks at the is_locked__c field to decide if record is locked

2

This is my working solution:

  private Id SYS_ADMIN_PROFILE_ID; 


    public ctrl() {
        List<user> lstUsers = [select ProfileId from User where Profile.Name = 'System Administrator' limit   1];
        if (!lstUsers.isEmpty() ) {
            SYS_ADMIN_PROFILE_ID=lstUsers[0].ProfileId;
        }  
     }  

then :

  doesCaseHavePendingApproval=false;
        if((![ Select Id From ProcessInstance WHERE TargetObjectId =: caseId AND Status = 'Pending' ].isEmpty()) && (UserInfo.getProfileId() != SYS_ADMIN_PROFILE_ID )){
              ApexPages.addMessage(new ApexPages.message(ApexPages.severity.warning, 'Please note that case in under an approval process '));
              doesCaseHavePendingApproval=true;
           }

Thanks to all.

You must log in to answer this question.

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