Alfresco Community v5.2 includes some of preconfigured workflows that available on the page /share/page/start-workflow
Among others, there is one that is interested to me - is "Review and Approve (one or more reviewers) - Assign a review task to multiple reviewers".
This business process is well suited to the requirements of one of our customers.
The only difference is that is needed to see the table of all the performers on the ReviewTask screens.
I decided to start with this wonderful article by Muralidharan Deenathayalan: Alfresco community 5.1.x workflow form add input fields dynamically
For start, I would like to see the table on my screens.
But I faced with the problem - the table is not displayed (even the static header).
And when I try to approve or reject the document, an exception occurs:
org.activiti.engine.ActivitiException: Exception while invoking TaskListener: 02100034 Mandatory task properties have not been provided! {http://www......com/model/workflow/1.0}userDetails
Some of the details below.
workflow-model.xml:
<?xml version="1.0" encoding="UTF-8"?>
<model name="mswf:workflowmodel" xmlns="http://www.alfresco.org/model/dictionary/1.0">
<imports>
<import uri="http://www.alfresco.org/model/dictionary/1.0" prefix="d"/>
<import uri="http://www.alfresco.org/model/bpm/1.0" prefix="bpm"/>
</imports>
<namespaces>
<namespace uri="http://www.........../model/workflow/1.0" prefix="mswf" />
</namespaces>
<types>
<type name="mswf:submitConcurrentReviewTask">
<parent>bpm:startTask</parent>
<properties>
<property name="mswf:requiredApprovePercent">
<type>d:int</type>
<mandatory>true</mandatory>
<default>50</default>
<constraints>
<constraint type="MINMAX">
<parameter name="minValue"><value>1</value></parameter>
<parameter name="maxValue"><value>100</value></parameter>
</constraint>
</constraints>
</property>
</properties>
</type>
<type name="mswf:submitParallelReviewTask">
<parent>mswf:submitConcurrentReviewTask</parent>
<mandatory-aspects>
<aspect>bpm:assignees</aspect>
</mandatory-aspects>
</type>
<type name="mswf:activitiReviewTask">
<parent>bpm:activitiOutcomeTask</parent>
<properties>
<property name="mswf:reviewOutcome">
<type>d:text</type>
<default>Reject</default>
<constraints>
<constraint name="mswf:reviewOutcomeOptions" type="LIST">
<parameter name="allowedValues">
<list>
<value>Approve|...</value>
<value>Reject|...</value>
</list>
</parameter>
</constraint>
</constraints>
</property>
<property name="mswf:userDetails">
<title> User Details</title>
<type>d:text</type>
<mandatory>true</mandatory>
</property>
</properties>
<overrides>
<property name="bpm:packageItemActionGroup">
<default>edit_package_item_actions</default>
</property>
<property name="bpm:outcomePropertyName">
<default>{http://www......../model/workflow/1.0}reviewOutcome</default>
</property>
</overrides>
</type>
<type name="mswf:rejectedParallelTask">
<parent>bpm:workflowTask</parent>
<mandatory-aspects>
<aspect>mswf:parallelReviewStats</aspect>
</mandatory-aspects>
</type>
<type name="mswf:approvedParallelTask">
<parent>bpm:workflowTask</parent>
<mandatory-aspects>
<aspect>mswf:parallelReviewStats</aspect>
</mandatory-aspects>
</type>
</types>
<aspects>
<aspect name="mswf:parallelReviewStats">
<properties>
<property name="mswf:reviewerCount">
<type>d:int</type>
</property>
<property name="mswf:requiredPercent">
<type>d:int</type>
</property>
<property name="mswf:approveCount">
<type>d:int</type>
</property>
<property name="mswf:actualPercent">
<type>d:int</type>
</property>
</properties>
</aspect>
</aspects>
</model>
contractsApproval.bpmn:
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/....-10.0">
<process id="contractsApproval" name="..... Approval " isExecutable="true">
<extensionElements>
<activiti:executionListener event="start" class="org.alfresco.repo.workflow.activiti.listener.ScriptExecutionListener">
<activiti:field name="script">
<activiti:string><![CDATA[execution.setVariable('mswf_approveCount', 0);
execution.setVariable('mswf_rejectCount', 0);
execution.setVariable('mswf_actualPercent', 0);
execution.setVariable('mswf_actualRejectPercent', 0);
execution.setVariable('mswf_reviewerCount', bpm_assignees.size());
execution.setVariable('mswf_requiredPercent', mswf_requiredApprovePercent);]]></activiti:string>
</activiti:field>
</activiti:executionListener>
</extensionElements>
<startEvent id="start" activiti:formKey="mswf:submitParallelReviewTask"></startEvent>
<sequenceFlow id="flow1" sourceRef="start" targetRef="reviewTask"></sequenceFlow>
<userTask id="reviewTask" name="Review Task" activiti:assignee="${reviewAssignee.properties.userName}" activiti:formKey="mswf:activitiReviewTask">
<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('mswf_reviewOutcome') == 'Approve') {
var newApprovedCount = mswf_approveCount + 1;
var newApprovedPercentage = (newApprovedCount / mswf_reviewerCount) * 100;
execution.setVariable('mswf_approveCount', newApprovedCount);
execution.setVariable('mswf_actualPercent', newApprovedPercentage);
} else {
var newRejectCount = mswf_rejectCount + 1;
var newRejectPercentage = (newRejectCount / mswf_reviewerCount) * 100;
execution.setVariable('mswf_rejectCount', newRejectCount);
execution.setVariable('mswf_actualRejectPercent', newRejectPercentage);
}]]></activiti:string>
</activiti:field>
</activiti:taskListener>
</extensionElements>
<multiInstanceLoopCharacteristics isSequential="false" activiti:collection="bpm_assignees" activiti:elementVariable="reviewAssignee">
<completionCondition>${mswf_actualPercent >= mswf_requiredApprovePercent || mswf_requiredApprovePercent > (100 - mswf_actualRejectPercent)}</completionCondition>
</multiInstanceLoopCharacteristics>
</userTask>
<sequenceFlow id="flow2" sourceRef="reviewTask" targetRef="reviewDecision"></sequenceFlow>
<exclusiveGateway id="reviewDecision" name="Review Decision"></exclusiveGateway>
<sequenceFlow id="flow3" sourceRef="reviewDecision" targetRef="approved">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${mswf_actualPercent >= mswf_requiredApprovePercent}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="flow4" sourceRef="reviewDecision" targetRef="rejected"></sequenceFlow>
<userTask id="approved" name="Document Approved" activiti:assignee="${initiator.exists() ? initiator.properties.userName : 'admin'}" activiti:formKey="mswf:approvedParallelTask">
<documentation>The document was reviewed and approved.</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;
// Set parallel review params on task, to be kept in history
task.setVariableLocal('mswf_reviewerCount', mswf_reviewerCount);
task.setVariableLocal('mswf_requiredPercent', mswf_requiredPercent);
task.setVariableLocal('mswf_actualPercent', mswf_actualPercent);
task.setVariableLocal('mswf_approveCount', mswf_approveCount);]]></activiti:string>
</activiti:field>
</activiti:taskListener>
</extensionElements>
</userTask>
<userTask id="rejected" name="Document Rejected" activiti:assignee="${initiator.exists() ? initiator.properties.userName : 'admin'}" activiti:formKey="mswf:rejectedParallelTask">
<documentation>The document was reviewed and rejected.</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;
// Set parallel review params on task, to be kept in history
task.setVariableLocal('mswf_reviewerCount', mswf_reviewerCount);
task.setVariableLocal('mswf_requiredPercent', mswf_requiredPercent);
task.setVariableLocal('mswf_actualPercent', mswf_actualPercent);
task.setVariableLocal('mswf_approveCount', mswf_approveCount);]]></activiti:string>
</activiti:field>
</activiti:taskListener>
</extensionElements>
</userTask>
<sequenceFlow id="flow5" sourceRef="approved" targetRef="end"></sequenceFlow>
<sequenceFlow id="flow6" sourceRef="rejected" targetRef="end"></sequenceFlow>
<endEvent id="end"></endEvent>
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_contractsApproval">
...
</bpmndi:BPMNDiagram>
</definitions>
share-config-custom.xml (some fields are not specified):
<alfresco-config>
<config evaluator="string-compare" condition="activiti$activitiReview">
<forms>
<form>
<field-visibility>
<show id="bpm:workflowDescription" />
<show id="bpm:workflowDueDate" />
<show id="bpm:workflowPriority" />
<show id="bpm:assignee" />
<show id="packageItems" />
<show id="bpm:sendEMailNotifications" />
</field-visibility>
<appearance>
<set id="" appearance="title" label-id="workflow.set.general" />
<set id="info" appearance="" template="/org/alfresco/components/form/2-column-set.ftl" />
<set id="assignee" appearance="title" label-id="workflow.set.assignee" />
<set id="items" appearance="title" label-id="workflow.set.items" />
<set id="other" appearance="title" label-id="workflow.set.other" />
<field id="bpm:assignee" label-id="workflow.field.reviewer" set="assignee" />
<field id="mswf:userDetails" set="userDetails" label="User Details" read-only="true">
<control template="/org/alfresco/components/form/controls/workflow/userdetails.ftl" />
</field>
</appearance>
</form>
</forms>
</config>
<config evaluator="string-compare" condition="activiti$contractsApproval">
<forms>
<form>
<field-visibility>
<show id="bpm:workflowDescription" />
<show id="bpm:workflowDueDate" />
<show id="bpm:workflowPriority" />
<show id="bpm:assignees" />
<show id="mswf:requiredApprovePercent" />
<show id="packageItems" />
</field-visibility>
<appearance>
<set id="" appearance="title" label-id="workflow.set.general" />
<set id="info" appearance="" template="/org/alfresco/components/form/2-column-set.ftl" />
<set id="assignee" appearance="title" label-id="workflow.set.assignees" />
<set id="items" appearance="title" label-id="workflow.set.items" />
<set id="other" appearance="title" label-id="workflow.set.other" />
<field id="bpm:assignees" label-id="workflow.field.reviewers" set="assignee" />
<field id="mswf:userDetails" set="userDetails" label="User Details" read-only="true">
<control template="/org/alfresco/components/form/controls/workflow/userdetails.ftl" />
</field>
<field id="packageItems" set="items" />
</appearance>
</form>
</forms>
</config>
<config evaluator="string-compare" condition="activiti$activitiLifecycleApproval">
<forms>
<form>
<field-visibility>
<show id="bpm:workflowDescription" />
<show id="bpm:workflowDueDate" />
<show id="bpm:workflowPriority" />
<show id="bpm:assignee" />
<show id="packageItems" />
<show id="bpm:sendEMailNotifications" />
</field-visibility>
<appearance>
<set id="" appearance="title" label-id="workflow.set.general" />
<set id="info" appearance="" template="/org/alfresco/components/form/2-column-set.ftl" />
<set id="assignee" appearance="title" label-id="workflow.set.assignee" />
<set id="items" appearance="title" label-id="workflow.set.items" />
<set id="other" appearance="title" label-id="workflow.set.other" />
<field id="mswf:userDetails" set="userDetails" label="User Details" read-only="true">
<control template="/org/alfresco/components/form/controls/workflow/userdetails.ftl" />
</field>
</appearance>
</form>
</forms>
</config>
<config evaluator="task-type" condition="bpm:startTask">
<forms>
<form id="workflow-details">
<field-visibility>
<show id="bpm:sendEMailNotifications" />
<show id="packageItems" />
</field-visibility>
<appearance>
<set id="" appearance="title" label-id="workflow.set.workflow.more_info" />
<set id="items" appearance="title" label-id="workflow.set.items" />
<field id="packageItems" set="items" />
</appearance>
</form>
<form>
<field-visibility>
<show id="message" />
<show id="taskOwner" />
<show id="bpm:workflowPriority" />
<show id="bpm:workflowDueDate" />
<show id="bpm:taskId" />
<show id="bpm:status" />
<show id="packageItems" />
<show id="bpm:sendEMailNotifications" />
</field-visibility>
<appearance>
<set id="" appearance="title" label-id="workflow.set.task.info" />
<set id="info" appearance="" template="/org/alfresco/components/form/3-column-set.ftl" />
<set id="progress" appearance="title" label-id="workflow.set.task.progress" />
<set id="items" appearance="title" label-id="workflow.set.items" />
<set id="other" appearance="title" label-id="workflow.set.other" />
<field id="mswf:userDetails" set="userDetails" label="User Details" read-only="true">
<control template="/org/alfresco/components/form/controls/workflow/userdetails.ftl" />
</field>
</appearance>
</form>
</forms>
</config>
<config evaluator="task-type" condition="mswf:submitParallelReviewTask">
<forms>
<form id="workflow-details">
<field-visibility>
<show id="mswf:requiredApprovePercent" />
<show id="bpm:sendEMailNotifications" />
<show id="packageItems" />
</field-visibility>
<appearance>
<set id="" appearance="title" label-id="workflow.set.workflow.more_info" />
<set id="items" appearance="title" label-id="workflow.set.items" />
<field id="packageItems" set="items" />
</appearance>
</form>
<form>
<field-visibility>
<show id="message" />
<show id="taskOwner" />
<show id="bpm:workflowPriority" />
<show id="bpm:workflowDueDate" />
<show id="bpm:taskId" />
<show id="mswf:requiredApprovePercent" />
<show id="bpm:status" />
<show id="packageItems" />
<show id="bpm:sendEMailNotifications" />
</field-visibility>
<appearance>
<set id="" appearance="title" label-id="workflow.set.task.info" />
<set id="info" appearance="" template="/org/alfresco/components/form/3-column-set.ftl" />
<set id="progress" appearance="title" label-id="workflow.set.task.progress" />
<set id="items" appearance="title" label-id="workflow.set.items" />
<set id="other" appearance="title" label-id="workflow.set.other" />
<field id="mswf:userDetails" set="userDetails" label="User Details" read-only="true">
<control template="/org/alfresco/components/form/controls/workflow/userdetails.ftl" />
</field>
</appearance>
</form>
</forms>
</config>
<config evaluator="task-type" condition="bpm:workflowTask">
<forms>
<form>
<field-visibility>
<show id="message" />
<show id="taskOwner" />
<show id="bpm:priority" />
<show id="bpm:dueDate" />
<show id="bpm:taskId" />
<show id="bpm:status" />
<show id="packageItems" />
<show id="bpm:comment" />
<show id="transitions" />
</field-visibility>
<appearance>
<set id="" appearance="title" label-id="workflow.set.task.info" />
<set id="info" appearance="" template="/org/alfresco/components/form/3-column-set.ftl" />
<set id="progress" appearance="title" label-id="workflow.set.task.progress" />
<set id="items" appearance="title" label-id="workflow.set.items" />
<set id="response" appearance="title" label-id="workflow.set.response" />
<field id="mswf:userDetails" set="userDetails" label="User Details" read-only="true">
<control template="/org/alfresco/components/form/controls/workflow/userdetails.ftl" />
</field>
</appearance>
</form>
</forms>
</config>
<config evaluator="task-type" condition="mswf:reviewTask">
<forms>
<form>
<field-visibility>
<show id="message" />
<show id="taskOwner" />
<show id="bpm:priority" />
<show id="bpm:dueDate" />
<show id="bpm:taskId" />
<show id="packageItems" />
<show id="bpm:comment" />
<show id="transitions" />
</field-visibility>
<appearance>
<set id="" appearance="title" label-id="workflow.set.task.info" />
<set id="info" appearance="" template="/org/alfresco/components/form/3-column-set.ftl" />
<set id="progress" appearance="title" label-id="workflow.set.task.progress" />
<set id="items" appearance="title" label-id="workflow.set.items" />
<set id="response" appearance="title" label-id="workflow.set.response" />
<field id="mswf:userDetails" set="userDetails" label="User Details" read-only="true">
<control template="/org/alfresco/components/form/controls/workflow/userdetails.ftl" />
</field>
</appearance>
</form>
</forms>
</config>
<config evaluator="task-type" condition="mswf:activitiReviewTask">
<forms>
<form>
<field-visibility>
<show id="message" />
<show id="taskOwner" />
<show id="bpm:priority" />
<show id="bpm:dueDate" />
<show id="bpm:taskId" />
<show id="packageItems" />
<show id="bpm:comment" />
<show id="mswf:reviewOutcome" />
</field-visibility>
<appearance>
<set id="" appearance="title" label-id="workflow.set.task.info" />
<set id="info" appearance="" template="/org/alfresco/components/form/3-column-set.ftl" />
<set id="progress" appearance="title" label-id="workflow.set.task.progress" />
<set id="items" appearance="title" label-id="workflow.set.items" />
<set id="response" appearance="title" label-id="workflow.set.response" />
<field id="mswf:userDetails" set="userDetails" label="User Details" read-only="true">
<control template="/org/alfresco/components/form/controls/workflow/userdetails.ftl" />
</field>
</appearance>
</form>
</forms>
</config>
<config evaluator="task-type" condition="mswf:approvedParallelTask">
<forms>
<form>
<field-visibility>
<show id="message" />
<show id="taskOwner" />
<show id="bpm:priority" />
<show id="bpm:dueDate" />
<show id="bpm:taskId" />
<show id="mswf:reviewerCount" />
<show id="mswf:approveCount" />
<show id="mswf:requiredPercent" />
<show id="mswf:actualPercent" />
<show id="packageItems" />
<show id="bpm:comment" />
<show id="transitions" />
</field-visibility>
<appearance>
<set id="" appearance="title" label-id="workflow.set.task.info" />
<set id="info" appearance="" template="/org/alfresco/components/form/3-column-set.ftl" />
<set id="progress" appearance="title" label-id="workflow.set.task.progress" />
<set id="outcome" appearance="title" label-id="workflow.set.outcome"
template="/org/alfresco/components/form/2-column-set.ftl" />
<set id="items" appearance="title" label-id="workflow.set.items" />
<set id="response" appearance="title" label-id="workflow.set.response" />
<field id="mswf:userDetails" set="userDetails" label="User Details" read-only="true">
<control template="/org/alfresco/components/form/controls/workflow/userdetails.ftl" />
</field>
</appearance>
</form>
</forms>
</config>
<config evaluator="task-type" condition="mswf:rejectedParallelTask">
<forms>
<form>
<field-visibility>
<show id="message" />
<show id="taskOwner" />
<show id="bpm:priority" />
<show id="bpm:dueDate" />
<show id="bpm:taskId" />
<show id="mswf:reviewerCount" />
<show id="mswf:approveCount" />
<show id="mswf:requiredPercent" />
<show id="mswf:actualPercent" />
<show id="packageItems" />
<show id="bpm:comment" />
<show id="transitions" />
</field-visibility>
<appearance>
<set id="" appearance="title" label-id="workflow.set.task.info" />
<set id="info" appearance="" template="/org/alfresco/components/form/3-column-set.ftl" />
<set id="progress" appearance="title" label-id="workflow.set.task.progress" />
<set id="outcome" appearance="title" label-id="workflow.set.outcome"
template="/org/alfresco/components/form/2-column-set.ftl" />
<set id="items" appearance="title" label-id="workflow.set.items" />
<set id="response" appearance="title" label-id="workflow.set.response" />
<field id="mswf:userDetails" set="userDetails" label="User Details" read-only="true">
<control template="/org/alfresco/components/form/controls/workflow/userdetails.ftl" />
</field>
</appearance>
</form>
</forms>
</config>
</alfresco-config>
Where I'm wrong?..
I would be very grateful for the information. Thanks to all.