Loop back to any prior task in the process

From pmusers
Jump to: navigation, search

This example shows how to create a process where the user can select the next task in a dropdown box in order to return the case to any prior task in the process and assign that task to the same user who was previously assigned to it.



Process: Loop_back_to_any_task-1.pmx (right click and select Save Link As)
Author: Amos Batto (amos@processmaker.com)
Version: 1.0 (2018-06-29)
Tested in: ProcessMaker 3.2.1 Community in Debian 8.4 with PHP 5.6.20 and Firefox 51


It is not difficult to loop back to the starting task in a process, as shown in this example:

LoopAroundProcessWithValueBasedAssignment.png

In order to be able to loop back to a previous task and automatically assign it to same user as before, the task needs to use Value Based Assignment. This isn't a problem with starting tasks in the process, because they are automatically assigned to the user who initiated the case, so the assignment variable is not used with the first assignment of the task. Only if the case loops back a second time to the task will the variable be used for assignment of the task and that variable can be set in the first pass through the task with trigger code like this:

if (!isset(@@FirstUser) or empty(@@FirstUser)) {
   @@FirstUser = @@USER_LOGGED;
}

If the "Enter Complaint" task uses the @@FirstUser variable for task assignment, then the same user will be assigned when the case passes through the task a second time.

The problem is using Value Based Assignment in tasks don't initiate the case, because a user ID has to be set in the variable for task assignment in the first pass through the task. Consider the following process where a case in the "Select Path" task can then loop back to any prior task:

LoopBackToAnyTaskProcessMap.png

In this process, all the tasks use Value Based Assignment. The variables for "Task 1", "Task 2", "Task 3" and "Select Path" tasks are @@userTask1, @@userTask2, @@userTask3 and @@userSelectTask, respectively.

The @@userTask2 variable needs to be already set to the ID of a user before the assignment of Task 2. The following trigger which executes before assignment in "Task 1" will set the @@userTask2 variable:

$taskTitle = 'Task 2'; //set to the title of the second task

if (empty(@@userTask1)) {
   //set the assigned user for the next pass through "Task 1":
   @@userTask1 = @@USER_LOGGED;
}

if (empty(@@userTask2)) {
   $taskId = PMFGetTaskUID($taskTitle, @@PROCESS);
   $d = new Derivation();
   $aUsers = $d->getAllUsersFromAnyTask($taskId);
   $max = count($aUsers) - 1;
   if ($max < 0) {
      throw new Exception("No users assigned to $taskTitle");
   }
   //choose one user randomly from the assignment list:
   @@userTask2 = $aUsers[ rand(0, $max) ]; 
}

The PHP code first sets @@userTask1 to the ID of the logged-in user, so that "Task 1" will be reassigned to the same user if the case ever returns to "Task 1". Then the code checks if the @@userTask2 variable is empty, so it needs to be set. The Derivation::getAllUsersFromAnyTask() function is called to get an array of the IDs of users who are in the assignment list of "Task 2". Then, the rand() function is used to randomly select one of the users from the assignment list and assign that user to @@userTask2.

A similar trigger is used to set the value of the @@userTask3 variable:

$taskTitle = 'Task 3'; //set to the title of the third task

if (empty(@@userTask3)) {
   $taskId = PMFGetTaskUID($taskTitle, @@PROCESS);
   $d = new Derivation();
   $aUsers = $d->getAllUsersFromAnyTask($taskId);
   $max = count($aUsers) - 1;
   if ($max < 0) {
      throw new Exception("No users assigned to $taskTitle");
   }
   //choose one user randomly from the assignment list:
   @@userTask3 = $aUsers[ rand(0, $max) ]; 
}

This trigger is set to execute before assignment in "Task 2".

Then, the following trigger is used to set the user for the "Select Path" task in the @@userSelectPath variable:

//set to the title of the next task in the process:
$taskTitle = 'Select Path'; 
$taskId = PMFGetTaskUID($taskTitle, @@PROCESS);
if (empty($taskId)) {
   throw new Exception("Task '$taskTitle' doesn't exist.");
}

if (empty(@@userSelectPath)) {   
   $d = new Derivation();
   $aUsers = $d->getAllUsersFromAnyTask($taskId);
   $max = count($aUsers) - 1;
   if ($max < 0) {
      throw new Exception("No users assigned to $taskTitle");
   }
   //choose one user randomly from the assignment list:
   @@userSelectPath = $aUsers[ rand(0, $max) ]; 
}

This trigger is set to execute before assignment in "Task 3".

The "Select Path" task contains the following Dynaform:

SelectPathFormInDesigner.png

The "Select Next Task" dropdown allows the user to select the next task in the process. The datasource property of this dropdown is set to "array variable" and its data variable is set to @@pathList.

When a case is run, the "Select Next Task" dropdown will contain the "Continue" option and a list of all the previous tasks and their assigned user in reverse order:

selectNextTaskDropdown.png

The case will then route to the selected task that was chosen in the "Select Next Task" dropdown and assigned to its @@selectNextTask variable.

The following trigger is used to populate the list of options in the @=pathList variable:

//populate the list of available tasks for the user to select
@=pathList = array(
   array("continue", "Continue")
);

//set to the titles of tasks that can be looped back to:
$tasksForLoopBack = "'Task 1', 'Task 2', 'Task 3'";

$aTasksInList = array(); //array to prevent duplicate tasks in dropdown list
$caseId = @@APPLICATION;
$sql = "SELECT * FROM APP_CACHE_VIEW WHERE APP_UID='$caseId' 
   AND APP_TAS_TITLE in ($tasksForLoopBack) ORDER BY DEL_INDEX DESC";
$aTasks = executeQuery($sql);

foreach ($aTasks as $aTask) {
   if (!in_array($aTask['APP_TAS_TITLE'], $aTasksInList)) {
      @=pathList[] = array(
         $aTask['APP_TAS_TITLE'],
         $aTask['APP_TAS_TITLE'] .' ('. $aTask['APP_CURRENT_USER'] .')'
      );
      $aTasksInList[] = $aTask['APP_TAS_TITLE'];
   }  
}

This trigger is set to execute before the above Dynaform holding the "Select Next Task" dropdown.

The code creates the @=pathList array, with the first option containing the "Continue" option. Then, it uses executeQuery() to query the APP_CACHE_VIEW table in the database for the tasks whose titles are set in the $tasksForLoopBack variable. Then, it loops through the query results to place those tasks and their assigned user in the @=pathList array.

Finally, right click on the exclusive gateway and select Properties in the context menu in order to set the conditions to route the case:

routingRulesInExclusiveGateway.png