0

Is there any way to re-assign a pending approval request thru apex code (code executing under standard user context i.e. not as sysadmin or without without sharing)?

I have an Opportunity Approval process that when kicked off will create the approval requests (in Pending status). The approval process and requests will be stored in ProcessInstance & ProcessInstance* sobjects (like ProcessInstanceNode, ProcessInstanceWorkItem etc). Active approval step/ request will have records in ProcessInstanceWorkItem sobject. I've used the following apex code that will reassign a pending approval request to another user and this code works fine as system admin (or as the current actor of the ProcessInstanceWorkitem record i.e. current assigned approver), but fails for all other profiles and users.

List<ProcessInstanceWorkitem> piWorkItemsUpdate = new List<ProcessInstanceWorkitem>();

List<ProcessInstanceWorkitem> piWorkItems = [SELECT Id, ActorId, OriginalActorId, ProcessInstance.TargetObjectId FROM ProcessInstanceWorkitem WHERE ProcessInstance.TargetObjectId = <Opportunity Record ID>];

for(ProcessInstanceWorkitem piWorkItem: piWorkItems){
     piWorkItem.ActorId = <User ID>;
     piWorkItem.OriginalActorId = <User ID>;
     piWorkItemsUpdate.add(piWorkItem);
}

if(!piWorkItemsUpdate.isEmpty()){
   Database.SaveResult[] updateResults = Database.update(piWorkItemsUpdate, false);
}

My requirement is that when a non-admin user changes value in a specific user lookup field in the opportunity record page, the corresponding pending approval request should be assigned to the new user selected in the lookup. So, I had placed the above code in opportunity trigger and this piece of code would run as the user who updates the opportunity record. As given in the following article, the code will work only for system admin or current actor of the ProcessInstanceWorkItem record (current pending approval request): https://help.salesforce.com/articleView?id=000206576&type=1

I've tried the following options, but none worked:

  • Using Approval.ProcessSubmitRequest or Approval.ProcessWorkitemRequest doesn't help
  • There seems to be no options for enabling/ accessing Sharing settings nor setting OWD for ProcessInstanceWorkitem object or records.
  • Tried 'without sharing' keyword on the apex class
  • Shared all the records of the current assigned approver to the new approver (from Setup > Users page) with Read/ Write permission.

Any help/ ideas?

0

3 Answers 3

0

Although, this is a really late answer, I hope it would help someone looking for a solution to this problem. I came across this work-around in the same week this question was originally posted, but missed out to post it here. [Thanks to my co-worker Frank Dipoma who suggested this approach to me (not sure if he is on this forum)]

Per the standard approval process in salesforce, system admin or the current approver of the approval request have the ability to re-assign the request to another user and most companies don't fiddle over this standard functionality. However, the client that I was working with had a specific requirement where a standard user would update a user lookup field in an opportunity record and all the related pending approval requests should be re-assigned to this new user. The most obvious approach anybody would take is to put the code snippet (given in the question) in a class marked as WITHOUT SHARING, but this will NOT specifically work in case of approval request re-assignment (nor will any of the options mentioned in my question). Anybody interested can try this out.


Note that this workaround exploits a loophole in salesforce (I don't want to call it a bug or defect in salesforce). Since, approvals & approval re-assignments are quite critical for any business, I recommend anybody trying this solution to have a thorough understanding of the use-cases, before adopting this workaround.


Without getting into minute details of the work-around, I'll summarize the approach that worked for me. The idea is that the apex trigger will send the relevant details to a specific email service address and then the inbound email handler code will use the details from the email to process the relevant approval request records.

  • Create an apex class that implements Messaging.InboundEmailHandler and in its handleInboundEmail method, place the code snippet given in the question. (Sample code for the inbound email handler class can be found in the developer guide here, although it isn't related to opportunity object)
  • Create an Email Service Address and associate it with the apex class created as mentioned above. This can be created from Setup > Custom Code > Email Services > New Email Service. After a new email service is created, a email service address needs to be created within. Note that this set-up has other standard email related configurations like accepted FROM addresses, dis-allowing attachments etc. which may be opted.
  • In the apex trigger (opportunity trigger in my case), send an email (SingleEmailMessage) with parent record ID (or opportunity ID) in the email body or subject. This email should be sent to the service address created above.

My memory is a bit hazy on a particular point related to this solution, since its been over an year. The apex code in the inbound handler class will run as the context user specified in the email service, but I don't remember whether the LastModifiedBy of the approval request is updated with this context user name or the actual user who updated the opportunity record.

4
  • If the answer requires clarity, do let me know and I'll try to improve it (may be with code snippets).
    – arut
    Commented Nov 3, 2020 at 17:03
  • Hi @arut I have come come across this workaround and trying to implement after a full 2 days of research. Since this is 2 years old answer, does this still work or is there any other solutions? I'm still trying to test your suggestion
    – MnZ
    Commented Jul 12, 2022 at 12:33
  • @MnZ I've not tried this lately, but I believe this should still work (I've not noticed anything in the subsequent Salesforce releases related to this, esp w.r.t the context under which the inbound email handler runs). I'd be glad to hear from you if this solution works for your case, but as mentioned in my answer please implement this at your discretion and complete understanding of your use cases.
    – arut
    Commented Jul 12, 2022 at 16:43
  • I have thought of 2 solutions, but running into mixed DML and other issues. My first try is to create a platform event. This failed with the similar insufficient issue. Secondly I'm trying right now and seems to be viable at this point is to temporarily add the modify all permission set, do the reassignment/recall and then remove assignment of permission set after. It comes with its own complexities, but does resolves the issues.
    – MnZ
    Commented Jul 13, 2022 at 12:29
0

This solution worked for me. I temporarily added the modify all permission set, performed the reassignment/recall and then finally removed assignment of permission set after. I achieved the adding and removing via flow, while recall functionality was performed in an apex. One has to be very careful of removing the modify all permission if the process failed in between.

It comes with its own complexities, but does resolves the above issue.

2
  • I temporarily added the modify all permission set, performed the reassignment/recall and then finally remove assignment of permission set after Did you do this manually? or via code?
    – arut
    Commented Jul 13, 2022 at 13:41
  • That was via flow. Let me update the answer.
    – MnZ
    Commented Jul 14, 2022 at 3:55
0

I think running it using a automated user will work, as you can assign admin like user access to automated user making a platform event and running a trigger with appropriate value will work.

I am in a same situation right now as my client have this specific requirement i will keep this updated if find anything usefull.

You must log in to answer this question.

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