3

Scenario

I have a requirement for an approval process on Opportunity that must go to multiple approvers. Opportunities cannot be owned by queues, so the approval cannot be submitted to a queue. As the documentation states, although Approval.ProcessRequest.setNextApproverIds() takes a list of ids, you can only supply one id. Using the approach outlined in the sample code in this answer, I am submitting one request per potential reviewer (via trigger). This is working.

The second half of the requirement is that once any approver approves or rejects the request, the request should no longer appear on other approvers' home page "Items to approve" list. Unfortunately, using the process outlined above, this isn't the case. If I generate two approval requests and approver A approves the request, the approval actions run, but the request to approver B remains in the 'Pending' state.

The Problem

Since the approval action changes a field on the opportunity, I can use a trigger to take additional action upon approval/rejection. I have tried using Approval.ProcessWorkitemRequest.setAction('Removed') to recall the remaining 'pending' requests. The docs state that only sys admins can use 'Removed', although this answer shows that the submitter can also revoke a request if the approval process is so configured. However, the trigger will be invoked by an approver, who probably will not be a sys admin and will not be the submitter. I have confirmed that placing the code in a without sharing class has no effect; non-admins who approve a request and trigger the revoke logic will get INSUFFICIENT_ACCESS_ON_CROSS_REFERENCE_ENTITY error.

Question(s)

Is there any way to revoke or otherwise cancel the extra approval requests that will work regardless of triggering user?

I tried deleting the ProcessInstanceWorkitem records. This does accomplish the goal of removing the extra requests, however, it does not complete the instance of the approval process - the ProcessInstance remains, and subsequent attempts to submit for other approval processes will fail with 'This record is currently in an approval process'. In fact, once the ProcessInstanceWorkItem is deleted, I can find no way to resolve the approval process. Ideally I would delete the ProcessInstance records, but delete is not supported; of the 5 Process* API objects, only ProcessInstanceWorkitem supports delete. Not sure why, since it breaks the approval instance as mentioned.

Baring a way to revoke/cancel/remove the additional approval requests, is there another way to meet the requirements that I've overlooked? Some way of submitting a single Approval.processSubmitRequest for multiple approvers that I have missed?

2
  • I guess with out sharing should work .If your trigger is invoking class and that has with out sharing that should ideally work. Commented Sep 26, 2014 at 4:21
  • As I stated in the question, I have tested 'without sharing', and it does not work. I believe that the approval request revoke process must look at the running user's identity, not at CRUD/FLS. Commented Sep 26, 2014 at 4:56

3 Answers 3

1

I think changing the approval process approver type from "Manual" to "Related user" will take you closer.

enter image description here

In this case you just need to populate the user lookup instead of setNextApproverIds() and then submit for approval. Key here is to let the Salesforce handle most of the parts of approval process rather than managing in apex.

Only downside of this approach, you need to know prior that maximum how many approvers you would like to support in your approval process and same number of user lookup you have to create in your object and configure in approver steps of approval process.

while submission, you can't let any of these fields blank so you have to set them mandatorily e.g. if you decided to go with 2 approvers, then you have to populate both the user field before submission. However, Salesforce does allow you to mention same user for all the fields. so you could tweak that when needed.

1

I've had similar requirement in the past, and implemented a not-so-pretty solution, but it worked.

As far as the approval process is concerned, the permissions are quite restrictive and as you mentioned, without sharing will not help.

You can give the relevant users Modify All permission on the relevant object and then the Recall will go through. The problem is that this is a very strong permission that you probably don't want to give.

What I did in the past is create a permission set with the Modify All permission for the relevant object. When the process starts, the user is given this permission set and calls an asynchronous process which will perform the Recall and at the end runs another last process that removes the permission set.

As mentioned, not a pretty solution. But it worked

2
  • A temporary permission set is certainly a clever idea! I'm not sure I'd use it in most cases, but it could certainly solve some issues. Commented Jul 18, 2023 at 12:31
  • You can also consider other similar solution- create a webservice that will run with admin privileges and perform the recall. The disadvantage of this approach is that it will be recorded that a admin user performed the recall and not the original user. In such a case, it is possible to write down the original username in a comment
    – Liron C
    Commented Jul 18, 2023 at 12:34
0

You can try method setSubmitterId by Approval.processSubmitRequest. This submitter can recall that ProcessInstance too.

You must log in to answer this question.

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