In process business management, tasks are usually handled by one person, and multiple people handle a task at the same time. We call this task a countersignature task. This kind of business requirement is also very common. For example, a payment request form needs to be signed by the leaders of multiple departments during the approval process of the leader. In the process business, we can define the link of each leader's signature as a task, but if so, one thing of this process business is fixed, that is, the signer is fixed. The task is signed by one leader and then transferred to another leader. Of course, multiple leaders can sign at the same time.
The traditional solution with process business can adopt the following approaches:
The former is called serial countersignature in process business, that is, one leader signs and then another leader signs. The latter is called a parallel countersignature, which means that several leaders are issuing at the same time, and it is not clear who will sign first.
The above solutions cannot be met under two major business requirements. If the leader of the countersignature is not fixed, the approver of the previous task can choose at will before submitting it. The other is for the countersignature business. Approved by the leaders, that is, go straight down, and do not need all leaders to approve. In addition, in this case, it is also difficult to count the results of the final leaders' countersignature, that is, there is no way to know whether the opinions on the approval form are agree or veto. The above two business requirements are also very common daily requirements, but if we use fixed process nodes, we cannot achieve them. Here, multiple instances of Activiti nodes can be used for processing, and the above process can be simplified as follows:
<userTask activiti:assignee="${assignee}" id="SignTask1" name="领导会签"> <extensionElements> <activiti:taskListener class="com.hotent.platform.service.bpm.listener.TaskSignCreateListener" event="create"/> <activiti:taskListener class="com.hotent.platform.service.bpm.listener.TaskAssignListener" event="assignment"/> <activiti:taskListener class="com.hotent.platform.service.bpm.listener.TaskCompleteListener" event="complete"/> </extensionElements> <multiInstanceLoopCharacteristics activiti:elementVariable="assignee" isSequential="false" activiti:collection="${taskUserAssignService.getSignUser(execution)}"> <completionCondition>${signComplete.isComplete(execution)}</completionCondition> </multiInstanceLoopCharacteristics> </userTask>
public boolean isComplete(ActivityExecution execution) { logger.debug("entert the SignComplete isComplete method..."); String nodeId=execution.getActivity().getId(); String actInstId=execution.getProcessInstanceId(); ProcessDefinition processDefinition=bpmService.getProcessDefinitionByProcessInanceId(actInstId); //取得会签设置的规则 BpmNodeSign bpmNodeSign=bpmNodeSignService.getByDefIdAndNodeId(processDefinition.getId(), nodeId); //完成会签的次数 Integer completeCounter=(Integer)execution.getVariable("nrOfCompletedInstances"); //总循环次数 Integer instanceOfNumbers=(Integer)execution.getVariable("nrOfInstances"); //计算投票结果。 VoteResult voteResult=calcResult(bpmNodeSign, actInstId, nodeId, completeCounter,instanceOfNumbers); String signResult=voteResult.getSignResult(); boolean isCompleted=voteResult.getIsComplete(); /** * 会签完成做的动作。 * 1.删除会签的流程变量。 * 2.将会签数据更新为完成。 * 3.设置会签结果变量。 * 4.更新会签节点结果。 * 5.清除会签用户。 */ if(isCompleted){ //删除会签的变量。 //删除 assignee,loopCounter变量。 bpmService.delLoopAssigneeVars(execution.getId()); logger.debug("set the sign result + " + signResult); //将会签数据更新为完成。 taskSignDataService.batchUpdateCompleted(actInstId, nodeId); //设置会签的结果 execution.setVariable("signResult_" + nodeId , signResult); //更新会签节点的状态。 Short status=TaskOpinion.STATUS_PASSED; if(signResult.equals(SIGN_RESULT_REFUSE)){ status=TaskOpinion.STATUS_NOT_PASSED; } //更新会签节点的状态。 bpmProStatusDao.updStatus(actInstId, nodeId,status); //清除会签用户。 taskUserAssignService.clearSignUser(); } return isCompleted; } ** * 根据会签规则计算投票结果。 * <pre> * 1.如果会签规则为空,那么需要所有的人同意通过会签,否则不通过。 * 2.否则按照规则计算投票结果。 * </pre> * @param bpmNodeSign 会签规则 * @param actInstId 流程实例ID * @param nodeId 节点id名称 * @param completeCounter 循环次数 * @param instanceOfNumbers 总的会签次数。 * @return */ private VoteResult calcResult(BpmNodeSign bpmNodeSign,String actInstId,String nodeId,Integer completeCounter,Integer instanceOfNumbers){ VoteResult voteResult=new VoteResult(); //没有会签实例 if(instanceOfNumbers==0){ return voteResult; } //投同意票数 Integer agreeVotesCounts=taskSignDataService.getAgreeVoteCount(actInstId, nodeId); //没有设置会签规则 //(那么得全部会签通过才通过,否则不通过) if(bpmNodeSign==null){ //还没有完成可以退出。 if(completeCounter<instanceOfNumbers){ return voteResult; } else{ //完成了 (全部同意才通过) if(agreeVotesCounts.equals(instanceOfNumbers)){ return new VoteResult(SIGN_RESULT_PASS,true); } else{ return new VoteResult(SIGN_RESULT_REFUSE,true); } } } //投反对票数 Integer refuseVotesCounts=taskSignDataService.getRefuseVoteCount(actInstId, nodeId); //检查投票是否完成 if(BpmNodeSign.VOTE_TYPE_PERCENT.equals(bpmNodeSign.getVoteType())){ float percents=0; //按同意票数进行决定 if(BpmNodeSign.DECIDE_TYPE_PASS.equals(bpmNodeSign.getDecideType())){ percents=agreeVotesCounts/instanceOfNumbers; //投票同意票符合条件 if(percents>=bpmNodeSign.getVoteAmount()){ voteResult=new VoteResult(SIGN_RESULT_PASS, true); } //投票已经全部完成 else if(completeCounter.equals(instanceOfNumbers)){ voteResult=new VoteResult(SIGN_RESULT_REFUSE, true); } } //按反对票数进行决定 else{ percents=refuseVotesCounts/instanceOfNumbers; //vote if(percents>=bpmNodeSign.getVoteAmount()){ voteResult=new VoteResult(SIGN_RESULT_REFUSE, true); } // Voting has been completed else if(completeCounter.equals(instanceOfNumbers)){ voteResult=new VoteResult(SIGN_RESULT_PASS, true); } } } //Vote by absolute number of votes else{ //decide by the number of votes if(BpmNodeSign.DECIDE_TYPE_PASS.equals(bpmNodeSign.getDecideType())){ //Vote yes votes are eligible if(agreeVotesCounts>=bpmNodeSign.getVoteAmount()){ voteResult=new VoteResult(SIGN_RESULT_PASS, true); } // Voting has been completed else if(completeCounter.equals(instanceOfNumbers)){ voteResult=new VoteResult(SIGN_RESULT_REFUSE, true); } } //decide by the number of negative votes else{ //vote if(refuseVotesCounts>=bpmNodeSign.getVoteAmount()){ voteResult=new VoteResult(SIGN_RESULT_REFUSE, true); } // Voting has been completed else if(completeCounter.equals(instanceOfNumbers)){ voteResult=new VoteResult(SIGN_RESULT_PASS, true); } } } return voteResult; }