cancel
Showing results for 
Search instead for 
Did you mean: 

Double Review Workflow

irenailievska
Champ on-the-rise
Champ on-the-rise
I am trying to create custom workflow that will be double approve and reject process. The diagram is included in attachment. How can I do this? I have some small understanding of how workflows in alfresco work, but not nearly enough. I want to be able when the workflow is supposed to go in Approve, to give the user that approved the task last (because that is how alfresco review task works - Approved is reached only when the number of approved is enough) another form where he will be able to choose the next people that are supposed to be the second approve/reject level. If anyone has any idea that would help solve this problem I would be very happy Smiley Very Happy. Any Idea will be accepted with open arms.

Thanks in advance,
Irena
2 REPLIES 2

irenailievska
Champ on-the-rise
Champ on-the-rise
Is this even possible? Any Ideas ?

irenailievska
Champ on-the-rise
Champ on-the-rise
I solved it - the final image of the diagram is in the attachment. The code for the workflow is below



<?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://alfresco.org">
  <process id="newDoubleDoc" name="Start workflow" isExecutable="true">
    <extensionElements>
      <activiti:executionListener event="start" class="org.alfresco.repo.workflow.activiti.listener.ScriptExecutionListener">
        <activiti:field name="script">
          <activiti:string><![CDATA[execution.setVariable('wf_approveCount', 0);
                        execution.setVariable('wf_rejectCount', 0);
                       
                        execution.setVariable('wf_actualPercent', 0);
                        execution.setVariable('wf_actualRejectPercent', 0);
                       
                          execution.setVariable('wf_reviewerCount', bpm_assignees.size());
                          execution.setVariable('wf_requiredPercent', wf_requiredApprovePercent);
                          
                          execution.setVariable('allowedRejectPercent', (100 - wf_requiredApprovePercent ));
                          
                          execution.setVariable('firstApproveCount', 0);
                        execution.setVariable('firstRejectCount', 0);
                        execution.setVariable('firstReviewerCount', bpm_assignees.size());
                          
                          execution.setVariable('secondApproveCount', 0);
                        execution.setVariable('secondRejectCount', 0);
                        execution.setVariable('secondReviewerCount', exwf_secondLevelAssignees.size());]]></activiti:string>
        </activiti:field>
      </activiti:executionListener>
    </extensionElements>
    <startEvent id="start" activiti:formKey="exwf:exSubmitReviewTask"></startEvent>
    <sequenceFlow id="flow1" sourceRef="start" targetRef="reviewTask"></sequenceFlow>
    <userTask id="reviewTask" name="Task" activiti:assignee="${reviewAssignee.properties.userName}" activiti:formKey="exwf:exReviewTask">
      <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;
                        if (typeof bpm_comment != 'undefined') task.comment = bpm_comment;]]></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('exwf_reviewOutcome') == 'Approve') {
                            var newApprovedCount = firstApproveCount + 1;
                           
                            execution.setVariable('firstApproveCount', newApprovedCount);
                        } else {
                            var newRejectCount = firstRejectCount + 1;
                           
                            execution.setVariable('firstRejectCount', newRejectCount);
                        }
                        execution.setVariable('reviewAssignee',person);]]></activiti:string>
          </activiti:field>
        </activiti:taskListener>
      </extensionElements>
      <multiInstanceLoopCharacteristics isSequential="false" activiti:collection="bpm_assignees" activiti:elementVariable="reviewAssignee">
        <completionCondition>${firstRejectCount != 0 || firstApproveCount == fisrtReviewerCount}</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[${firstApproveCount == firstReviewerCount}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="flow4" sourceRef="reviewDecision" targetRef="rejected"></sequenceFlow>
    <userTask id="approved" name="Документ одобрен" activiti:assignee="${reviewAssignee1.properties.userName}" activiti:formKey="exwf:exReviewTask">
      <documentation>Document is reviewed.</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;
                        if (typeof bpm_comment != 'undefined') task.comment = bpm_comment;
                       
                        // Set parallel review params on task, to be kept in history
                        task.setVariableLocal('wf_reviewerCount', wf_reviewerCount);
                        task.setVariableLocal('wf_requiredPercent', wf_requiredPercent);
                        task.setVariableLocal('wf_actualPercent', wf_actualPercent);
                        task.setVariableLocal('wf_approveCount', wf_approveCount);
                       
                           if (bpm_sendEMailNotifications)
                        {
                           var mail = actions.create("mail");
                           mail.parameters.to = initiator.properties.email;
                           mail.parameters.subject = "Задача - " + bpm_workflowDescription;
                           mail.parameters.from = person.properties.email;
                           mail.parameters.text = "some text";
                           mail.execute(bpm_package);
                        }
                        ]]></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('exwf_reviewOutcome') == 'Approve') {
                            var newApprovedCount = secondApproveCount + 1;
                           
                            execution.setVariable('secondApproveCount', newApprovedCount);
                        } else {
                            var newRejectCount = secondRejectCount + 1;
                           
                            execution.setVariable('secondRejectCount', newRejectCount);
                        }
                        execution.setVariable('reviewAssignee1',person);]]></activiti:string>
          </activiti:field>
        </activiti:taskListener>
      </extensionElements>
      <multiInstanceLoopCharacteristics isSequential="false" activiti:collection="exwf_secondLevelAssignees" activiti:elementVariable="reviewAssignee1">
        <completionCondition>${secondRejectCount != 0 || secondApproveCount == secondReviewerCount}</completionCondition>
      </multiInstanceLoopCharacteristics>
    </userTask>
    <userTask id="rejected" name="Rejected" activiti:assignee="${initiator.exists() ? initiator.properties.userName : 'admin'}" activiti:formKey="exwf:exRejectedTask">
      <documentation>Document is 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;
                        if (typeof bpm_comment != 'undefined') task.comment = bpm_comment;
                       
                        // Set parallel review params on task, to be kept in history
                        task.setVariableLocal('wf_reviewerCount', wf_reviewerCount);
                        task.setVariableLocal('wf_requiredPercent', wf_requiredPercent);
                        task.setVariableLocal('wf_actualPercent', wf_actualPercent);
                        task.setVariableLocal('wf_approveCount', wf_approveCount);
                       
                      
                           if (bpm_sendEMailNotifications)
                        {
                           var mail = actions.create("mail");
                           mail.parameters.to = initiator.properties.email;
                           mail.parameters.subject = "Задача - " + bpm_workflowDescription;
                           mail.parameters.from = person.properties.email;
                           mail.parameters.text = "Some text";
                           mail.execute(bpm_package);
                          
                        }]]></activiti:string>
          </activiti:field>
        </activiti:taskListener>
      </extensionElements>
    </userTask>
    <sequenceFlow id="flow5" sourceRef="approved" targetRef="secondReviewDecision"></sequenceFlow>
    <sequenceFlow id="flow6" sourceRef="rejected" targetRef="end"></sequenceFlow>
    <endEvent id="end"></endEvent>
    <exclusiveGateway id="secondReviewDecision" name="Second Review Decision"></exclusiveGateway>
    <userTask id="approved2" name="Document approved" activiti:assignee="${initiator.exists() ? initiator.properties.userName : 'admin'}" activiti:formKey="exwf:exApprovedTask"></userTask>
    <sequenceFlow id="flow7" sourceRef="secondReviewDecision" targetRef="approved2">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${secondApproveCount == secondReviewerCount}]]></conditionExpression>
    </sequenceFlow>
    <userTask id="rejected2" name="Document rejected" activiti:assignee="${initiator.exists() ? initiator.properties.userName : 'admin'}" activiti:formKey="exwf:exRejectedTask"></userTask>
    <sequenceFlow id="flow8" sourceRef="secondReviewDecision" targetRef="rejected2"></sequenceFlow>
    <sequenceFlow id="flow9" sourceRef="approved2" targetRef="end"></sequenceFlow>
    <sequenceFlow id="flow10" sourceRef="rejected2" targetRef="end"></sequenceFlow>
  </process>

….. HERE IS THE DEFINITION FOR THE DIAGRAM IMAGE
</definitions>



The content model




<?xml version="1.0" encoding="UTF-8"?>
   <!– Definition of new Model –>
   <model name="exwf:exwfmodel" xmlns="http://www.alfresco.org/model/dictionary/1.0">
      <!– Optional meta-data about the model –>
      <description>Example Workflow Model</description>
      <version>1.0</version>
      
      <!– Imports are required to allow references to definitions in other models –>
      <imports>
         <!– Import Alfresco Dictionary Definitions –>
         <import uri="http://www.alfresco.org/model/dictionary/1.0" prefix="d" />
         <!– Import Alfresco Content Domain Model Definitions –>
         <import uri="http://www.alfresco.org/model/system/1.0" prefix="sys" />
         <import uri="http://www.alfresco.org/model/bpm/1.0" prefix="bpm"/>
         <import uri="http://www.alfresco.org/model/workflow/1.0" prefix="wf"/>
           <import uri="http://www.alfresco.org/model/content/1.0" prefix="cm" />         
      </imports>
      
      <!– Introduction of new namespaces defined by this model –>
      <namespaces>
         <namespace uri="http://www.example.com/model/exworkflow/1.0" prefix="exwf" />
      </namespaces>
      
      <types>
         <type name="exwf:exSubmitReviewTask">
            <title>Task</title>
               <parent>wf:submitParallelReviewTask</parent>
               <mandatory-aspects>
                     <aspect>exwf:secondLevelAssignees</aspect>
                </mandatory-aspects>
         </type>
        
         <type name="exwf:exReviewTask">
            <title>Task</title>
            <parent>bpm:activitiOutcomeTask</parent>
            <properties>
                <property name="exwf:reviewOutcome">
                    <type>d:text</type>
                    <default>Reject</default>
                    <constraints>
                        <constraint name="exwf:reviewOutcomeOptions" type="LIST">
                            <parameter name="allowedValues">
                                <list>
                                    <value>Approve</value>
                                    <value>Reject</value>
                                </list>
                            </parameter>
                        </constraint>
                    </constraints>
                </property>
            </properties>
            <overrides>
                <property name="bpm:packageItemActionGroup">
                    <default>edit_package_item_actions</default>
                </property>
                <property name="bpm:outcomePropertyName">
                    <default>{http://www.example.com/model/exworkflow/1.0}reviewOutcome</default>
                </property>
            </overrides>
      </type>
       
     <type name="exwf:exApprovedTask">
         <title>Task Completed</title>
          <parent>bpm:workflowTask</parent>
         <mandatory-aspects>
            <aspect>wf:parallelReviewStats</aspect>
            <aspect>exwf:secondLevelAssignees</aspect>
           </mandatory-aspects>
      </type>
     
       <type name="exwf:exRejectedTask">
         <title>Task Completed</title>
          <parent>bpm:workflowTask</parent>
         <mandatory-aspects>
            <aspect>wf:parallelReviewStats</aspect>
         </mandatory-aspects>
      </type>
      </types>
     
      <aspects>
      <aspect name="exwf:secondLevelAssignees">
      <associations>
         <association name="exwf:secondLevelAssignees">
            <source>
               <mandatory>false</mandatory>
               <many>false</many>
            </source>
            <target>
               <class>cm:person</class>
               <mandatory>true</mandatory>
               <many>true</many>
            </target>
         </association>
      </associations>
      </aspect>
   </aspects>
   </model>




In order to see the Approve and Reject buttons in share-config-custom.xml you only need to change the transitions property with your property (exwf:reviewOutcome)



<field id="exwf:reviewOutcome" set="response" >
       <control template="/org/alfresco/components/form/controls/workflow/activiti-transitions.ftl" />
</field>



You need to register the workflow and the content model and that is it.