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!!!!

No comments:

Post a Comment