function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion

How to Approve the record through Apex Programming.



I have approval process created in salesforce.But according to the requirement user need to enter Approval/Rejection reason before he approves or rejects the record.Hence I have created custom button for Submit for approval,Approve and Reject button with VF page.


I know how to create approval request record through apex programming.I want to update the the approval request record created,  once the user clicks on  custom Approve button on  VF page.Can anyone please tell me is it possible to update the approval request record through programming.




Srilakshmi B




You need to go through processInstance records....   I have some code which I'll put here which may help... it's pulled out of a large VF controller which presented a list of Items for approval (Items to be Distributed to customers).  I put a bunch of checkboxes on the page next to the item information so the user could select which ones to approve.


So, this is a subset of the controller which, perhaps, will help.



First, define a helper class for the approvals on my Distributed_Items__c objects.


// Helper class to put an envelope around something for approval
	public class checkBoxEnv {
		public Boolean approve {get; set;}
		public Boolean deny {get; set;}
		public Distributed_Item__c distItem {get; set;}
		public List<ProcessInstance> process {get; set;}
		public List<ProcessInstanceHistory> stepOrWorkItem {get; set;}
		public Boolean hasProcess {get; set;}
		public Boolean hasStep {get; set;}
		public Boolean hasMyStep {get; set;}
		checkBoxEnv(Distributed_Item__c di) {
			distItem = di;
			approve = deny = false;
			process = [
				Select Id, TargetObjectId, isDeleted, Status,
						Select Id, ProcessInstanceId, ActorId, Actor.Name, StepStatus, Comments 
						From StepsAndWorkItems
							StepStatus = 'Pending'  and
							isDeleted = false 
						Order By 
							Createddate Desc
						Limit 1
				From ProcessInstance
					isDeleted = false and
					TargetObjectId = and
					Status = 'Pending'
				Order By 
					Createddate Desc
				Limit 1
			hasProcess = ! (process.isEmpty());
			hasStep = false;
			hasMyStep = false;
			if (hasProcess) {
				stepOrWorkItem = process[0].StepsAndWorkitems;
				hasStep = ! (stepOrWorkItem.isEmpty());	
				// Now, let's see if that step is for this user.
				hasMyStep = stepOrWorkItem[0].ActorId == UserInfo.getUserId(); 


Load my outstanding approvals... so ItemsForApproval can be used in a pageBlockTable to display information about the object as well and the acceptance and rejection etc.



	private void loadApprovalItems() {
		if (itemsForApproval == null) {
			itemsForApproval = new List<checkBoxEnv>(); 
		} else {
		for (Distributed_Item__c di: [
				Contact__c, Quantity__c, Status__c, isDeleted, Attribute_Value__c,
				Item__c, Item__r.Name, Item__r.Type__c, Item__r.User__c
			From Distributed_Item__c 
				isDeleted = False and 
				Contact__c = :client.Id and
				( Status__c = 'Pending Approval by Distributor' or 
				  Status__c = 'Pending Approval by Manager')
		]) {
			itemsForApproval.add(new checkBoxEnv(di));


Go through them and do the approvals the user has requested...


	public pageReference doApprovals() {
		// Go through the Items for approval and process them accordingly.
		Approval.ProcessWorkitemRequest req;
		Approval.ProcessResult result;	
		for (checkBoxEnv env: itemsForApproval) {
			if (!env.approve && !env.deny) continue; // If the user didn't select, skip this.
			req = new Approval.ProcessWorkitemRequest();
			req.setNextApproverIds(null);  // No further approvals for this step needed.
			if (env.approve) {
				req.setComments('Approving request.');
			if (env.deny) {
				req.setComments('Denying request.');
			result = Approval.process(req);
		// Reload the Approval Items.

		return null;


The portion of the page with the VF about Approvals...


	<apex:pageBlock title="Approve existing requests" mode="edit" id="approvals" rendered="{!areThereItemsToApprove}">
        <apex:pageBlockButtons location="top" >
        	<apex:commandButton action="{!doApprovals}" value="Do Approvals" rerender="approvals, distItemsRelList"/>
            <apex:commandButton action="{!doDone}" value="Done"/>
            <apex:commandButton action="{!doRefreshApprovalsDisplay}" value="Refresh Approvals Display" rerender="approvals"/>
		<apex:pageBlockSection showHeader="true" title="Approve Distribution Requests" columns="1">
		 	<apex:pageBlockTable value="{!itemsForApproval}" var="app">
				<apex:column value="{!app.distItem.Item__c}" />
              	<apex:column value="{!app.distItem.Quantity__c}" />
              	<apex:column value="{!app.distItem.Attribute_Value__c}" />
              	<apex:column headerValue="Comments">
              		<apex:outputField value="{!app.stepOrWorkItem[0].comments}" rendered="{!app.hasStep}"/>
              	<apex:column >
                	<apex:facet name="header">
                		Approve<br/><input type="checkbox" onClick="toggleAll('ToggleApproved_1', this.checked)"/>
                	<apex:inputCheckbox id="ToggleApproved_1" value="{!app.approve}" rendered="{!app.hasMyStep}"/>
              	<apex:column >
                  	<apex:facet name="header">
                       	Decline<br/><input type="checkbox" onClick="toggleAll('ToggleDeclined_1', this.checked)"/>
                    <apex:inputCheckbox id="ToggleDeclined_1" value="{!app.deny}" rendered="{!app.hasMyStep}"/>
				<apex:column headerValue="Approval Pending?">
					<apex:outputText >{!if(app.hasStep,'Yes','No')}</apex:outputText>
				<apex:column headerValue="Waiting for?">
					<apex:outputText rendered="{!app.hasMyStep == false}">{!app.stepOrWorkItem[0].Actor.Name}</apex:outputText>


Note that I'm not 100% certain this covers every case, etc.  but it did the portions that we needed.   And, I've extracted this out of a larger controller, so there may be some hanging references.   Either way, hope this helps to explain it... Best, Steve.










Thanks for your Solution.Can you please let me know if it is possible to navigate the user to visual force page upon clicking Approve/Reject link on the relatedlist of the detail page of the record instead of navigating standard Approve/Reject page.




 public void Accept(){
         Flag = false;
        update perform;
        Approval.ProcessWorkitemRequest req2 = new Approval.ProcessWorkitemRequest();
req2.setComments('Approving request.');
req2.setAction('Approve'); //This is the action that is approve in your case, you can set it to Reject also

req2.setNextApproverIds(new Id[] {UserInfo.getUserId()});
// Use the ID from the newly created item to specify the item to be worked  

// Submit the request for approval  
Approval.ProcessResult result2 =  Approval.process(req2);

I am facing this Error  

System.DmlException: Process failed. First exception on row 0; first error: INVALID_CROSS_REFERENCE_KEY, invalid cross reference id: []

please help me to resolve this 

Sab L 10Sab L 10
Hi Jerry, You might be setting wrong workitemid. Hope, you already fixed.
Ashley Sisti 11Ashley Sisti 11
Hi all - I'm trying to do something similar, but without the checkbox to approve/reject. I just want to display the pending approval requests for the logged in user, and show some of the custom fields on the record that has been submitted for approval. I'm trying to work with the code above but I'm not a developer and am running into some issues - specifically the snippet to load approvals is showing an error for itemsToApprove - says the variable doesn't exist. Is that defined somewhere else that isn't listed here? How do I do it?