Showing posts with label Approval Process on VF Page. Show all posts
Showing posts with label Approval Process on VF Page. Show all posts

Sunday, January 23, 2011

Approval Process on VF Page

Take action approve/reject through custom VF page.
Generally to approve or reject an approval process standard way is used, but it’s quite interesting to access a record on custom VF page & approve/reject the record from this page. Here is the sample for this –
For this two objects are required one is master & other is detail. Let's say these two objects are professional object [Master] & review object [detail].
In the detail object there will be a field "Submitted_For__c" lookup (user) field. This field will be used for mapping to which user this review will be submitted.
Now coming to the code
===============================================
To access all review object for currently logged in user –
List listOfAllReviewObjects = new List([Select r.Proffesional_Info__c, r.Name, r.Id From Review__c r where r.User_SumittedFor__c = : UserInfo.getUserId() order by Id asc limit 1000 ]);
//iterate this list & create a set of listOfAllReviewObjects id’s. Let’s say name is “setOfAllReviewObjects”
now to access all approval process for currently logged in user
List listProcessInstance = new List([Select p.Id, p.Status, p.TargetObjectId, (Select ActorId, Comments, OriginalActorId, StepStatus From Steps order by CreatedDate asc) from ProcessInstance p where p.TargetObjectId in : setOfAllReviewObjects limit 1000]);
for(ProcessInstance pi:listProcessInstance){
objPi = new processInst();//here processInst is a custom class
objPi.apprProcId = pi.Id;
objPi.status = pi.Status;
if(pi.Steps.Size()>0)
{
//if object is approved/rejected, than Process Steps will have two entries
if(pi.Steps.Size()>1)
{ //these are the approved or pending records & size of steps will be greater than 1 in this case, initially there will be one entry in steps if no action taken on the record by approver
objPi.actorUserId = pi.Steps.get(1).ActorId;
objPi.reviewerName = mapReview.get(pi.TargetObjectId).Name;
objPi.reviwerId = pi.TargetObjectId;
objPi.originalActorUserId = pi.Steps.get(1).OriginalActorId;
objPi.comments = pi.Steps.get(1).Comments;
}
else
{ //all records which are submitted but pending to approve.
objPi.actorUserId = pi.Steps.get(0).ActorId;
objPi.reviewerName = mapReview.get(pi.TargetObjectId).Name;
objPi.reviwerId = pi.TargetObjectId;
objPi.originalActorUserId = pi.Steps.get(0).OriginalActorId;
objPi.comments = pi.Steps.get(0).Comments;

}

}
if(objPi.status == 'Approved' || objPi.status == 'Rejected'){
objPi.isApproved = true;
}
else {
objPi.isApproved = false;
}
to show the all records for current user, VF page code is as below-
<apex:pageBlockTable value="{!listProIns}" var="lpi" rendered="{!IF(listProIns.Size>0,true,false)}">
<apex:column headerValue="Approval Id" value="{!lpi.apprProcId}" />
<apex:column headerValue="Reviewer Name" value="{!lpi.reviewerName}" />
<apex:column headerValue="OriginalActorId" value="{!lpi.originalActorUserId}" rendered="false" />
<apex:column headerValue="Assigned Approver Name" value="{!lpi.originalActorUserName}" />
<apex:column headerValue="ActorId" value="{!lpi.actorUserId}" rendered="false" />
<apex:column headerValue="Actual Approver Name" value="{!lpi.actorUserName}" />
<apex:column headerValue="Comments">
<apex:inputTextArea id="txtComments" value="{!lpi.comments}" rendered="{!NOT(lpi.isApproved)}" cols="40" />
<apex:outputLabel value="{!lpi.comments}" rendered="{!lpi.isApproved}" />
</apex:column>>
<apex:column headerValue="Status" >
<apex:selectList value="{!lpi.Status}" multiselect="false" rendered="{!NOT(lpi.isApproved)}" size="1">
<apex:selectOption itemValue="NONE" itemLabel="--Action--" />
<apex:selectOption itemValue="Approve" itemLabel="Approve" />
<apex:selectOption itemValue="Reject" itemLabel="Reject" />
</apex:selectList>
<apex:outputlabel value="{!lpi.Status}" rendered="{!lpi.isApproved}"/>
</apex:column>
</apex:pageBlockTable>
<apex:pageBlockButtons id="blockButton" location="bottom">
<apex:CommandButton id="cmdButton" action="{!approvalProcessAction}" value="Save" rendered="{!IF(listProIns.Size>0,true,false)}"/>
</apex:pageBlockButtons>
On the VF page the records which are in pending state will show a drop down to take action while other records are not editable.
Finally to approve or reject a particular record, user will select a value from drop down & click on save button, the save button apex code will be-
Map mapStepIds = new Map();
List lstReview = new List([Select (Select ID,ProcessInstanceId from ProcessSteps where isPending=true) from Review__c where Id in :setPendingReviewObjects]);
if(lstReview.size()>0)
{
string id = '';
integer i = 0;
for(Review__c rv:lstReview)
{
if(rv.ProcessSteps.size() > 0)
{
id = rv.ProcessSteps[0].ID;
if(id != null && id != '')
{
mapStepIds.put(rv.ProcessSteps[0].ProcessInstanceId, id);
}
}
}

}
List listReq = new List();
for(processInst pi :listProIns)
{
if(!pi.isApproved && pi.status != 'NONE')
{
Approval.Processworkitemrequest objReq = new Approval.Processworkitemrequest();
objReq.setAction(pi.status);
objReq.setComments(pi.comments);
objReq.setWorkitemId(mapStepIds.get(pi.apprProcId));
listReq.add(objReq);

}
}
if(listReq.size()>0)
{
List res = Approval.process(listReq);
}
While submitting the action “setWorkitemId” is the most important part, this is the process instance id.

Enjoy!!!!