Questions and discussion about developing processes and programming in PHP, JavaScript, web services & REST API.

Moderator: amosbatto

Forum rules: Please search to see if a question has already asked before creating a new topic. Please don't post the same question in multiple forums.
By dannyng
#814732
hi there,

I'm using Processmaker 3.1.3 and I was wondering can processmaker assign approval from grid's using array and remove all those duplicate approval name if exist. For eg: User pick item and the different items lead to different approvals,

Grid : Item | Approval
Table Marcus
Pen Celia
Pencil Marcus

Based on above table, I would like to remove duplicate approval Marcus and send the approval task on parallel evaluation
for 2 approval instead of sending 3 approval task. i hope some one understand my requirement and able to help me as I was struggling for weeks on this method. thanks in advance.
By amosbatto
#814743
There are two ways to deal with this problem, and each has their drawbacks, so you will have to decide which you want to use:
1. Create an approval task with a parallel marker like this:
processWithParallelApproval.png
processWithParallelApproval.png (8.13 KiB) Viewed 2289 times
Set the variable for the parallel approval task to be: @@approversList

Your "Approval" dropdown in the grid needs to have the IDs of the users as the keys of each option. You can do this by creating a group named "Approvers" whose members are the users who can do the approval.

Then, set the "Approval" dropdown to use a datasource which is an array variable and set its variable to be
@@availableApproversList

Then create the following trigger to populate the list of options in the "Approval" dropdown:
Code: Select all
$groupName = "Approvers";
$groupId = PMFGetGroupUID($groupName);
if (empty($groupId)) {
  throw new Exception("Group '$groupName' doesn't exist.");
}
$aUsers = PMFGetGroupUsers($groupId);
@=availableApproversList = array();

foreach ($aUsers as $aUser) {
   $fullName = $aUser['USR_FIRSTNAME'] .' '. $aUser['USR_LASTNAME'];
   @=availableApproversList[] = array($aUser['USR_UID'], $fullName);
}
Set this trigger to execute before the Dynaform holding the grid.

Then, create a second trigger to set the @@approversList variable:
Code: Select all
if (!isset(@=itemsToApprove or empty(@=itemsToApprove)) {
   throw new Exception("User didn't fill the itemsToApprove grid");  
}

@=approversList = array();

foreach (@=itemsToApprove as $aItem) {
   @=approversList[] = $aItem['approval']; //this should be the ID of the user
}

@=approversList = array_unique(@=approversList);
Set this trigger to execute before assignment in Task 1.

The drawback with this method is that ProcessMaker doesn't create different variables for each user assigned to the parallel task. This means that each user assigned to the parallel task will overwrite the variables set by the previous user.

For a way around this problem, see the trigger code in the attached process in this post:
viewtopic.php?f=41&t=710262&p=789936#p789936

2. The second way to do this is to create multiple approval tasks. The idea is explained here:
http://wiki.processmaker.com/3.0/Trigge ... llel_Tasks

Each parallel approval task will use Value Based Assignment with a different variable:
@@userForApproval1, @@userForApproval2, @@userForApproval3, @@userForApproval4. etc.

The following trigger can be used before assignment in Task 1:
Code: Select all
if (!isset(@=itemsToApprove or empty(@=itemsToApprove)) {
   throw new Exception("User didn't fill the itemsToApprove grid");  
}

$aApprovers = array();

foreach (@=itemsToApprove as $aItem) {
   $aApprovers[] = $aItem['approval']; //this should be the ID of the user
}

$aApprovers = array_unique($aApprovers);
@%numberApprovers = count($aApprovers);
$aVars = array(); //variables to save to case

//create a different variable for the assignment of the user and a different grid variable for each parallel task:
for ($i = 0; $i  < @%numberApprovers; $i++) {
    $varName = 'userForTask' . ($i+1);
    $aVars[ $varName ] = $aApprovers[$i];
    
    //new itemstoApproveX for each parallel task:
    $gridName = 'itemsToApprove' . ($i + 1);
    $itemsToApproveX = array();
 
    //only include the rows in the grid for single approver:
    $rowNo = 1;
    foreach (@=itemsToApprove as $aItem) {
         if ($aItem['approval'] == $aApprovers[$i]) {
             $itemsToApproveX[ $rowNo ] = $aItem;
             $rowNo++;
         }
    }
    $aVars[ $gridName ] =  $itemsToApproveX;
}  

//save variables to case:    
PMFSendVariables(@@APPLICATION, $aVars);
Set this trigger to fire before assignment in Task 1.

You will have to create separate dynaforms for each parallel approval task with a grid whose variable is named:
itemsToApprove1, itemsToApprove2, itemsToApprove3, itemsToApprove4, etc.

In the task afterwards, you will probably want to create another trigger that will integrate all the grids into 1 grid, like this:
Code: Select all
@=completeItemsToApprove = array();
$oCase = new Cases(@@APPLICATION);
$aCaseVars = $oCase->LoadCase(@APPLICATION)['APP_DATA'];
$rowNo = 1;

for ($i = 1; $i <= @%numberApprovers; $i) {
    $gridName = 'itemsToApprove' . $i;
    
    foreach ($aCaseVars[ $gridName ] as $aRow) {
        @=completeItemsToApprove[ $rowNo ] = $aRow; 
        $rowNo++;
    }
}
Then use "completeItemsToApprove" as the variable for the final grid to show all the approved Items in the final task.
By dannyng
#814751
Hi Amos,

Thanks for the prompt reply and solution. As I'm just a beginner on programming, I'm not quite understand the triggers you have provided. Which variable should I put as the condition for the parallel evaluation gateway and what if I only need to route the task based on the approval name only and not the item? If there's duplicate approval name appeared, how do I remove it like the example I've given earlier so that it won't flow to same approval twice at the same time? Oh yes, I'm decided to go for the second option, Thanks.
By amosbatto
#814768
The conditions in your inclusive gateway will be:
@%numberApprovers >= 1
@%numberApprovers >= 2
@%numberApprovers >= 3
@%numberApprovers >= 4
etc.

This line in the code eliminates duplicates in the list of users who are assigned to the parallel approval tasks:
Code: Select all
$aApprovers = array_unique($aApprovers);
By dannyng
#814791
Hi Amos,

I think I'm almost there but every time I've submitted the form, below error prompt out. Do I missed out something?
Untitled.png
Untitled.png (7.35 KiB) Viewed 1259 times
By amosbatto
#814811
Turn on "Debug Mode" in your process properties and check that your variables "userForApproval1", "userForApproval2", "userForApproval3" have unique IDs (which are 32 character hexadecimal numbers). I looks like you are assigning the names and not the ID numbers to the variables.

How are you populating your "approval" dropdown box in the grid. The keys need to have the unique IDs of the users as the keys for each option. You can either manually look up the unique IDs of each user and put them the options of the dropdown box or you use the "availableApproversList" variable to populate the list of available users. You need to use the trigger as I explained in the first post to do.
Also remember that all the users that are in your approval list also need to be in the assignment list of all the parallel approval tasks.
By dannyng
#814815
Hi Amos,

I'm using the sql to populate the approval field (not dropdown), the user will select the dropdown(item field) and approver will be populate immediately depending on which item they choose. The item and appointed approval already setup in the pm table. I know the script for assigning single approver using the usr_uid but not multiple based on the script you have given to me.
By amosbatto
#814836
If you are looking up the user to assign in PM Table, then you need to use trigger code like this:
Code: Select all
if (!isset(@=itemsToApprove or empty(@=itemsToApprove)) {
   throw new Exception("User didn't fill the itemsToApprove grid");  
}

$aApprovers = array();

foreach (@=itemsToApprove as $aItem) {
   $item = $aItem['item']; 
   $sql = "SELECT USR_UID FROM PMT_ITEM_APPROVERS WHERE ITEM_ID = '$item'";
   $result = executeQuery($sql);
   if (empty(result)) {
       throw new Exception("There is no user for item '$item'");
    }
    $aApprovers[] = $result[1]['USR_UID'];
}

$aApprovers = array_unique($aApprovers);
@%numberApprovers = count($aApprovers);
$aVars = array(); //variables to save to case

//create a different variable for the assignment of the user and a different grid variable for each parallel task:
for ($i = 0; $i  < @%numberApprovers; $i++) {
    $varName = 'userForTask' . ($i+1);
    $aVars[ $varName ] = $aApprovers[$i];
    
    //new itemstoApproveX for each parallel task:
    $gridName = 'itemsToApprove' . ($i + 1);
    $itemsToApproveX = array();
 
    //only include the rows in the grid for single approver:
    $rowNo = 1;
    foreach (@=itemsToApprove as $aItem) {
         if ($aItem['approval'] == $aApprovers[$i]) {
             $itemsToApproveX[ $rowNo ] = $aItem;
             $rowNo++;
         }
    }
    $aVars[ $gridName ] =  $itemsToApproveX;
}  

//save variables to case:    
PMFSendVariables(@@APPLICATION, $aVars);
where your PM Table is named "PMT_ITEM_APPROVERS" and it has the fields USR_UID and ITEM_ID.
By dannyng
#814838
Hi Amos,

Your script works well, now I left with a final question to complete the workflow. There's another issue which whenever there's a same approver for 2 continuous rows and above and adding the following row with a different approver, below error will prompt out and this won't happen if each row have a different approvers, I wonder what can caused this error:

Untitled.png
Untitled.png (13.87 KiB) Viewed 1057 times
By amosbatto
#814857
Turn on Debug Mode and check whether the "taskForApproval2" variable has the unique ID of a user (which is a 32 character hexidecimal number). Also, all the users who can be selected in the "approval" dropdown box in the grid are in the assignment list for all the parallel approval tasks. If the user in the variable is not in the assignment list for the task, then it won't work.
By dannyng
#814868
Hi Amos,

I think this has nothing to do with the unique ID of the user, it's more to the looping through the Grid. For eg:

- row 1 : Marcus, row 2 : Thomas, row 3 : Celia > Approval assigned.
- row 1 : Marcus, row 2 : Thomas, row 3 : Thomas > Approval assigned.
- row 1 : Marcus, row 2 : Marcus, row 3 : Thomas > Approval not assigned.

No matter how many rows with same approver and then follow by one row different approver, the loop will halt. The reversed way is not working, i hope you understand my explanation here. thanks.
By amosbatto
#814884
From the code, I don't see how that is happening.
When you have:
- row 1 : Marcus, row 2 : Marcus, row 3 : Thomas > Approval not assigned.

In the debugger, you should see the following variables defined:
numberApprovers: 2
userForTask1: 123456789abcdef1234567890abcedf (ID for Marcus)
userForTask2: abcdef1234567890abcedf123456789 (ID for Thomas)

If you see these variables, then the problem is your conditions in the inclusive gateway. What are your conditions?
By amosbatto
#814905
For some strange reason, it wasn't able to access the last element in the array.
Using this trigger code, I got it to work correctly:
Code: Select all
$aApprovers = array();

foreach (@=safGrid as $aItem) {
    if (!empty($aItem['marketing'])) { 
       $aApprovers[] = $aItem['marketing'];
    }
}

$aApprovers = array_unique($aApprovers);
@%numberApprovers = count($aApprovers);
@=aApprovers = $aApprovers;
$aVars = array(); //variables to save to case
$countApprovers = 0;

//create a different variable for the assignment of the user and a different grid variable for each parallel task:
foreach ($aApprovers as $approverId) {
	$countApprovers++;
	$varName = 'userForApproval' . $countApprovers;
 	$aVars[ $varName ] = $approverId;
}  
@=aVars = $aVars;
//save variables to case:    
PMFSendVariables(@@APPLICATION, $aVars);
Here is the modified process:
(292.53 KiB) Downloaded 9 times
I changed the ID of the "Marketing" dropdown in the safGrid from "markeiting" to "marketing" and I created a "Marketing" group to populate it and assign users to the parallel tasks. See the SQL query in dropdown.

Thanks Amos, it kinda of worked. But the API respo[…]

Data table in the panel

Create a hidden field associated with the variab[…]

Timo, that code has been moved to: workflow/engine[…]

routeCase SOAP API error

There is no web service function to get all the va[…]