04-12-2017 05:52 AM
I have a workflow in Alfresco Share where I need 4 parallel reviews / approval tasks. I am currently able to create 4 tasks but they all go to the same candidate group. Members of that group are able to approve, but they have all 4 tasks in their "My Tasks". Each of these tasks is unassigned. The remaining 3 groups receive no tasks.
Do I need to include code in the multiInstanceLoopCharacteristics that assigns the tasks to the pooled actors? I have read the documentation Activiti User Guide and see that a list of users can be created. Where would I set that variable and would that be with execution.setVariable()? Any help would be greatly appreciated.
<userTask id="miTasks" name="My Task ${loopCounter}" activiti:assignee="${assignee}">
<multiInstanceLoopCharacteristics isSequential="false">
<loopDataInputRef>assigneeList</loopDataInputRef>
<inputDataItem name="assignee" />
</multiInstanceLoopCharacteristics>
</userTask>
Here is my code:
<userTask id="userTask10" name="Approvers Review" activiti:candidateGroups="GROUP_accountsManager,GROUP_manfacturingManager,GROUP_engineeringManager,GROUP_qualityManager" activiti:formKey="lec:appoversreview">
<documentation>Review task
Note: When a reject occurs, workflow is routed back to Originator assign, bypassing other approvers.
</documentation>
<extensionElements>
<activiti:taskListener event="create" class="org.alfresco.repo.workflow.activiti.tasklistener.ScriptTaskListener">
<activiti:field name="script">
<activiti:string>
<![CDATA[if (typeof bpm_workflowDueDate != 'undefined') task.dueDate = bpm_workflowDueDate;
if (typeof bpm_workflowPriority != 'undefined') task.priority = bpm_workflowPriority;;]]>
</activiti:string>
</activiti:field>
</activiti:taskListener>
<activiti:taskListener event="complete" class="org.alfresco.repo.workflow.activiti.tasklistener.ScriptTaskListener">
<activiti:field name="script">
<activiti:string>
<![CDATA[execution.setVariable('lec_appoversreviewtransitions',task.getVariableLocal('lec_appoversreviewtransitions') );
if(task.getVariableLocal('lec_appoversreviewtransitions') == 'Approve') {
execution.setVariable('lec_appoversreviewapprovalcount', lec_appoversreviewapprovalcount + 1);
}
if(task.getVariableLocal('lec_appoversreviewtransitions') == 'Reject') {
execution.setVariable('lec_appoversreviewapprovalcount',5);
execution.setVariable('lec_appoversreviewtransitions', task.getVariableLocal('lec_appoversreviewtransitions'));
}
logger.info("Count: " + execution.getVariable('lec_appoversreviewapprovalcount') )]]>
</activiti:string>
</activiti:field>
</activiti:taskListener>
</extensionElements>
<multiInstanceLoopCharacteristics isSequential="false">
<loopCardinality>4</loopCardinality>
<completionCondition>${lec_appoversreviewapprovalcount >= lec_appoversreviewrequiredapprovalcount}</completionCondition>
</multiInstanceLoopCharacteristics>
</userTask>
<exclusiveGateway id="exclusiveGateway1"></exclusiveGateway>
<sequenceFlow id="sequenceFlow22" sourceRef="userTask10" targetRef="exclusiveGateway1"></sequenceFlow>
<sequenceFlow id="sequenceFlow23" name="Rejected" sourceRef="exclusiveGateway1" targetRef="userTask9">
<conditionExpression xsi:type="tFormalExpression">
<![CDATA[${lec_appoversreviewtransitions == 'Rejected'}]]>
</conditionExpression>
</sequenceFlow>
<sequenceFlow id="sequenceFlow24" name="Approved" sourceRef="exclusiveGateway1" targetRef="exclusiveGateway2"></sequenceFlow>
<exclusiveGateway id="exclusiveGateway2"></exclusiveGateway>
04-12-2017 02:28 PM
David,
One slightly more simple way around the multi-instance loop situation would be to just create a parallel gateway that splits into those 4 tasks and rejoins after they're completed; each task could use the same form and be directly assigned to those individual candidate groups that you're assigning. The functionality of rerouting after a rejection that you've shown above is entirely still plausible with this configuration as well.
There are a couple of other posts, particularly this one, where people have discussed the multi-instance functionality before and highlighted a couple points in getting it working. But yes, you are correct - the multi-instance is probably a solid route to go here and has the potential capabilities you're looking for.
The Activiti Modeler has assign functionality or you can establish the list of users as a variable.
Hope this helps,
-JEarles
bp3
04-12-2017 04:02 PM
Thanks for your reply. I am testing now ..
04-13-2017 05:52 AM
I am still a bit confused. I have assigned bpm_GroupAssignees to the activiti:collection and created and activiti:elementVariable "reviewGroup", my assumption being that the foreach loop would use bpm_groupAssignees as the source collection and reviewGroup at the variable. When I start the review step the workflow throws an exception "java.lang.NullPointerException: null".
I've seen other code that uses but I thought that the activiti:elementVariable would achieve the same thing.
<resourceAssignmentExpression>
<formalExpression>${groupAssignee.properties.authorityName}</formalExpression>
</resourceAssignmentExpression>
Any insight would be greatly appreciated.
My updated code:
<userTask id="userTask1" name="Review step" activiti:candidateGroups="GROUP_approver_accounts,GROUP_approver_engineering,GROUP_approver_document" activiti:formKey="agsystemselect:reviewstep">
<documentation>Review task</documentation>
<extensionElements>
<activiti:taskListener event="create" class="org.alfresco.repo.workflow.activiti.tasklistener.ScriptTaskListener">
<activiti:field name="script">
<activiti:string><![CDATA[if (typeof bpm_workflowDueDate != 'undefined') task.dueDate = bpm_workflowDueDate;
if (typeof bpm_workflowPriority != 'undefined') task.priority = bpm_workflowPriority;;]]></activiti:string>
</activiti:field>
</activiti:taskListener>
<activiti:taskListener event="complete" class="org.alfresco.repo.workflow.activiti.tasklistener.ScriptTaskListener">
<activiti:field name="script">
<activiti:string><![CDATA[if(task.getVariableLocal('agsystemselect_reviewsteptransitions') == 'Approve') {
execution.setVariable('agsystemselect_reviewstepapprovalcount', agsystemselect_reviewstepapprovalcount + 1);
}
if(task.getVariableLocal('agsystemselect_reviewsteptransitions') == 'Reject'){
execution.setVariable('agsystemselect_reviewstepapprovalcount', 4);
}]]></activiti:string>
</activiti:field>
</activiti:taskListener>
</extensionElements>
<multiInstanceLoopCharacteristics isSequential="false" activiti:collection="bpm_groupAssignees" activiti:elementVariable="reviewGroup">
<loopCardinality>3</loopCardinality>
<completionCondition>${agsystemselect_reviewstepapprovalcount >= agsystemselect_reviewsteprequiredapprovalcount}</completionCondition>
</multiInstanceLoopCharacteristics>
</userTask>
Explore our Alfresco products with the links below. Use labels to filter content by product module.