Questions and discussion about using ProcessMaker: user interface, running cases & functionality

Moderator: amosbatto

#814581
Good morning,

I was wondering is it possible to design a process which can reassign a "review task" to the manager if the supervisor hasn't made any actions(action by email) for his or her "review task" after 48 hours?

The current process is when requestor submits a request, it goes to the supervisor for approval, but sometimes the supervisor will be on leave and the ABE email will be in the mailbox for approval until he came back. Can I add a timer after supervisor review task? If the supervisor doesn't give any response for 48 hours, this task will be reassigned to the upper manager for approval. Or some workaround by doing this automatically instead of asking an admin to reassign the case.

Any ideas regarding this situation? Could you please provide a process map for a demo if possible?

Many thanks,
Yuan
#814587
cosyxu wrote: Tue May 29, 2018 7:55 pm Good morning,

I was wondering is it possible to design a process which can reassign a "review task" to the manager if the supervisor hasn't made any actions(action by email) for his or her "review task" after 48 hours?

The current process is when requestor submits a request, it goes to the supervisor for approval, but sometimes the supervisor will be on leave and the ABE email will be in the mailbox for approval until he came back. Can I add a timer after supervisor review task? If the supervisor doesn't give any response for 48 hours, this task will be reassigned to the upper manager for approval. Or some workaround by doing this automatically instead of asking an admin to reassign the case.

Any ideas regarding this situation? Could you please provide a process map for a demo if possible?

Many thanks,
Yuan
Forgot to attach the "example" process map which I want to achieve.
Attachments
2018-05-30_12-06-58.png
2018-05-30_12-06-58.png (26.07 KiB) Viewed 5539 times
#814637
I think that you should use parallel tasks. In your current process, the timer event (wait 48 hours) will only execute when the supervisor complete his task. But if he's not there, he can't do that.

With parallel tasks, the supervisor will have a task in his inbox and during this time, there is a timer that wait 48 hours. Once it's been 48 hours, it will execute the trigger.

In the trigger, you should verify if the task has been completed. The following code should tell you if there is an opened task 'Supervisor or Manager review'. If it's still open, your trigger should reassign, otherwise it shouldn't do anything. In PHP, the current APP_UID is the processmaker variable @@APPLICATION.
Code: Select all
SELECT AD.DEL_THREAD_STATUS FROM APP_DELEGATION AD
INNER JOIN TASK T ON T.TAS_UID=AD.TAS_UID 
WHERE T.TAS_UID=(id of your task) AND AD.APP_UID=(APP_UID of your current case)

To reassign, I would recommend using the Processmaker REST API:
http://wiki.processmaker.com/3.2/REST_A ... ssign-case

That's how I would personnaly do it
Attachments
reassign.PNG
reassign.PNG (42.85 KiB) Viewed 5069 times
#814644
stevensi1018 wrote: Thu May 31, 2018 11:21 am I think that you should use parallel tasks. In your current process, the timer event (wait 48 hours) will only execute when the supervisor complete his task. But if he's not there, he can't do that.

With parallel tasks, the supervisor will have a task in his inbox and during this time, there is a timer that wait 48 hours. Once it's been 48 hours, it will execute the trigger.

In the trigger, you should verify if the task has been completed. The following code should tell you if there is an opened task 'Supervisor or Manager review'. If it's still open, your trigger should reassign, otherwise it shouldn't do anything. In PHP, the current APP_UID is the processmaker variable @@APPLICATION.
Code: Select all
SELECT AD.DEL_THREAD_STATUS FROM APP_DELEGATION AD
INNER JOIN TASK T ON T.TAS_UID=AD.TAS_UID 
WHERE T.TAS_UID=(id of your task) AND AD.APP_UID=(APP_UID of your current case)

To reassign, I would recommend using the Processmaker REST API:
http://wiki.processmaker.com/3.2/REST_A ... ssign-case

That's how I would personnaly do it
Good morning Steven,

Thank you for providing the solution.

It makes sense for me, however, can I ask how to use API function?

I used the following code but it returned with the following error,

"undefined function pmRestRequest "
Code: Select all
$url = "/api/1.0/workflow/cases/'$app_number'/reassign-case";
$method = "PUT";
$aVars = array(
   'usr_uid_source'   => 'user_id_1',
   'usr_uid_target'   => 'user_id_2'
);

$oRet = pmRestRequest($method, $url, $aVars);

Any ides?
Thanks,
Yuan
#814645
Hi Amo,

It seems I have the same issue like to following post.
viewtopic.php?p=787305#p787305

My process map is same as Steven's process map as above. And the supervisor or manager review task is a ABE task. So I was trying to login Rest API and then run API End Point for "Reassign Case: PUT /cases/{app_uid}/reassign-case".

I have tested the TimerEvent and it works, could you please advise why this trigger didn't work?

Please see my attached trigger code:
Code: Select all

@@approval = '[email protected]';
@@subject  = 'Approval from Manager';

$app_number = @@APPLICATION; //application number
$case_number = '232323223230df8ace7e571sdsd72'; //task number


$query = executeQuery("SELECT AD.DEL_THREAD_STATUS FROM APP_DELEGATION AD INNER JOIN TASK T ON T.TAS_UID=AD.TAS_UID WHERE T.TAS_UID='$case_number' AND AD.APP_UID='$app_number'");
@@result = $query;


/*-------------------------------------------------------------------------------------------------

  Start the process
*/
$pmServer    = 'https://mywebsite.com';
$pmWorkspace = 'workflow';
 
function pmRestLogin($clientId, $clientSecret, $username, $password) {
   global $pmServer, $pmWorkspace;
   $postParams = array(
      'grant_type'    => 'password',
      'scope'         => '*',       //set to 'view_process' if not changing the process
      'client_id'     => $clientId,
      'client_secret' => $clientSecret,
      'username'      => $username,
      'password'      => $password
   );
 
   $ch = curl_init("$pmServer/$pmWorkspace/oauth2/token");
   curl_setopt($ch, CURLOPT_TIMEOUT, 30);
   curl_setopt($ch, CURLOPT_POST, 1);
   curl_setopt($ch, CURLOPT_POSTFIELDS, $postParams);
   curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
 
   $oToken = json_decode(curl_exec($ch));
   $httpStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);
   curl_close($ch);
 
   if ($httpStatus != 200) {
      print "Error in HTTP status code: $httpStatus\n";
      return null;
   }
   elseif (isset($oToken->error)) {
      print "Error logging into $pmServer:\n" .
         "Error:       {$oToken->error}\n" .
         "Description: {$oToken->error_description}\n";
   }
   else {
      //At this point $oToken->access_token can be used to call REST endpoints.
 
      //If planning to use the access_token later, either save the access_token
      //and refresh_token as cookies or save them to a file in a secure location.
 
      //If saving them as cookies:
      setcookie("access_token",  $oToken->access_token,  time() + 86400);
      setcookie("refresh_token", $oToken->refresh_token); //refresh token doesn't expire
      setcookie("client_id",     $clientId);
      setcookie("client_secret", $clientSecret);
 
      //If saving to a file:
      //file_put_contents("/secure/location/oauthAccess.json", json_encode($tokenData));
   }
 
   return $oToken;
}

//api function
$apiServer = "https://mywebsite.com";            //set to your ProcessMaker address
$app_number = @@APPLICATION; //application number

$accessToken = pmRestLogin("DSJKDSJKDJSKDJSsdsdsdKJSKD","21212121214578545678","admin","admin");
@@accessToken_label = $accessToken;

$postParams = array(
  'usr_uid_source'      => "232323123213213213212131",
  'usr_uid_target'      => "213123213213212323232131"
);


$ch = curl_init($apiServer . "/api/1.0/workflow/cases/" . $app_number . "/reassign-case");
curl_setopt($ch, CURLOPT_HTTPHEADER, array("Authorization: Bearer $accessToken"));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postParams));
$oResult = json_decode(curl_exec($ch));
$statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

curl_close($ch);



Thanks,
Yuan
#814647
Yuan,
The problem is that global variables can't be defined inside a function which is defined inside of a trigger. Instead of this:
Code: Select all
$pmServer    = 'https://mywebsite.com';
$pmWorkspace = 'workflow';
 
function pmRestLogin($clientId, $clientSecret, $username, $password) {
   global $pmServer, $pmWorkspace;
Do this:
Code: Select all
function pmRestLogin($clientId, $clientSecret, $username, $password) {
   $pmServer    = 'https://mywebsite.com';
   $pmWorkspace = 'workflow';
#814650
amosbatto wrote: Mon Jun 04, 2018 9:30 pm Yuan,
The problem is that global variables can't be defined inside a function which is defined inside of a trigger. Instead of this:
Code: Select all
$pmServer    = 'https://mywebsite.com';
$pmWorkspace = 'workflow';
 
function pmRestLogin($clientId, $clientSecret, $username, $password) {
   global $pmServer, $pmWorkspace;
Do this:
Code: Select all
function pmRestLogin($clientId, $clientSecret, $username, $password) {
   $pmServer    = 'https://mywebsite.com';
   $pmWorkspace = 'workflow';
Thanks, Amo I will test it and let you know.

Just let you know all my tasks are ABE task, so by using the above reassign function, will it resend the task? Is it possible to change the "Email variable" before resend so it can send to a different user?

Another approach that I am not sure if it is possible is:
Are there any triggers that I can use to cancel a specific task? For example, when it goes to the parallel gateway, timer event will wait for 48 hours and then cancel the "supervisor reivew task". And then it goes to the requestor task to select which manager to be route to and then route to manager. (please refer to the image below)

Thanks.
Yuan
Attachments
2018-06-05_11-49-16.png
2018-06-05_11-49-16.png (41.19 KiB) Viewed 2902 times
#814651
amosbatto wrote: Mon Jun 04, 2018 9:30 pm Yuan,
The problem is that global variables can't be defined inside a function which is defined inside of a trigger. Instead of this:
Code: Select all
$pmServer    = 'https://mywebsite.com';
$pmWorkspace = 'workflow';
 
function pmRestLogin($clientId, $clientSecret, $username, $password) {
   global $pmServer, $pmWorkspace;
Do this:
Code: Select all
function pmRestLogin($clientId, $clientSecret, $username, $password) {
   $pmServer    = 'https://mywebsite.com';
   $pmWorkspace = 'workflow';
I still got this information, "Error in HTTP status code: 0".

If this "Reassign Endpoints" works, I could update Email variable value in the trigger, will it resend the ABE task(supervisor task) with the new "Email Variable"? In this case, that task will be resent rather than cancel. :shock:

Thanks,
Yuan
#814668
Hi Amo,

I have also tested the ProcessMaker Connector 1.0 for the "Reassign API Endpoint".

And I got the following error message:

Error code : 400
"Client error: `PUT https://mywebsite.com/api/1.0/workflow/ ... 0888876420` resulted in a `400 Bad Request` response:\n{\"error\":{\"code\":400,\"message\":\"Bad Request: Invalid Case Delegation index for this user\"}}\n"

Both users have PM_REASSIGNCASE and PM_REASSIGNCASE_SUPERVISOR permission, so is there anything wrong with my URL? :?:

If both ways work, which one would you recommend? (Using the above trigger or PM connector?)

Thanks,
Yuan
#814675
Hi Amo,

It seems I found the issue but I'm not sure. :idea:

Please refer to the two process map below, the API Endpoints only works before the timer event starts.

If I run the pmConnector before the timer event, the supervisor review task can be reassigned, otherwise, it will return the error message: "400 Bad Request Bad Request: Invalid Case Delegation index for this user".

How can I fix this issue?

Many thanks,
Yuan
Attachments
r1.png
r1.png (50.15 KiB) Viewed 2523 times
r2.png
r2.png (74.55 KiB) Viewed 2523 times
#814686
The problem is that you have multiple open tasks in the case and the REST endpoint/connector automatically selects the most recently opened task to reassign, which is the correct one when executed before the intermediate timer event, but it is the wrong task when executed after the timer event.

I'm going to have to create a custom REST endpoint to solve this problem, but you don't need to use REST or a connector. I recommend using Cases::reassignCase() in a trigger.

Try using this trigger code in your script task:
Code: Select all
//set to ID of the "Supervisor Review" task:
$taskId = '232323223230df8ace7e571sdsd72'; 
//set to ID of the user who will be reassigned to task (user must be in assignment list for task):
$reassignUserId = '98123230559ff9jh52fab80888876420';

$caseId = @@APPLICATION;
$sql = "SELECT * FROM APP_CACHE_VIEW WHERE APP_UID='$caseId' AND TAS_UID='$taskId'
   ORDER BY DEL_DELEGATE_DATE DESC"; 
$aTasks = executeQuery($sql);

if (empty($aTasks)) {
   throw new Exception("Error finding Supervisor Review task in database");
}

//if task hasn't been completed, then reassign it to another user:
if ($aTasks[1]['DEL_THREAD_STATUS'] == 'OPEN' and empty($aTasks[1]['DEL_FINISH_DATE'])) {
   $oCase = new Cases();
   @@reassignResult = $oCase->reassignCase($caseId, $aTasks[1]['DEL_INDEX'], $aTasks[1]['USR_UID'], $reassignUserId, 'REASSIGN');
}
I wrote this off the top of my head, so let me know if it works for you.
#814691
amosbatto wrote: Wed Jun 06, 2018 7:48 pm The problem is that you have multiple open tasks in the case and the REST endpoint/connector automatically selects the most recently opened task to reassign, which is the correct one when executed before the intermediate timer event, but it is the wrong task when executed after the timer event.

I'm going to have to create a custom REST endpoint to solve this problem, but you don't need to use REST or a connector. I recommend using Cases::reassignCase() in a trigger.

Try using this trigger code in your script task:
Code: Select all
//set to ID of the "Supervisor Review" task:
$taskId = '232323223230df8ace7e571sdsd72'; 
//set to ID of the user who will be reassigned to task (user must be in assignment list for task):
$reassignUserId = '98123230559ff9jh52fab80888876420';

$caseId = @@APPLICATION;
$sql = "SELECT * FROM APP_CACHE_VIEW WHERE APP_UID='$caseId' AND TAS_UID='$taskId'
   ORDER BY DEL_DELEGATE_DATE DESC"; 
$aTasks = executeQuery($sql);

if (empty($aTasks)) {
   throw new Exception("Error finding Supervisor Review task in database");
}

//if task hasn't been completed, then reassign it to another user:
if ($aTasks[1]['DEL_THREAD_STATUS'] == 'OPEN' and empty($aTasks[1]['DEL_FINISH_DATE'])) {
   $oCase = new Cases();
   @@reassignResult = $oCase->reassignCase($caseId, $aTasks[1]['DEL_INDEX'], $aTasks[1]['USR_UID'], $reassignUserId, 'REASSIGN');
}
I wrote this off the top of my head, so let me know if it works for you.
Hi Amo,

You are a legend. Thanks for the solution. :mrgreen:

I have tested it and it works.

By using PM reassign function, even it is an ABE task, we will be able to reassign a case to the same person but the next assigned user's email address can be updated to make the ABE works.

Could you please post the custom API here when you completed?

Thanks for your help and thanks steven's idea of the process map.

Yuan
#814694
Hi Amo,

Do you know which PM function I can use to continue the "Supervisor Task"? (please refer to the same process map).

If the supervisor doesn't provide any feedbacks for 48 hours, which function that I can use to force "Supervisor Task" to route to next? Do I need to query the same table you are using? And put the parameters into a PM function?
Code: Select all
$sql = "SELECT * FROM APP_CACHE_VIEW WHERE APP_UID='$caseId' AND TAS_UID='$taskId'
   ORDER BY DEL_DELEGATE_DATE DESC"; 
Thanks,
Yuan
#814704
If you want to automatically route on the "Supervisor Review" task, then you can use this trigger code:
Code: Select all
//set to ID of the "Supervisor Review" task:
$taskId = '232323223230df8ace7e571sdsd72'; 
//set to ID of the user who will be reassigned to task (user must be in assignment list for task):
$reassignUserId = '98123230559ff9jh52fab80888876420';

$caseId = @@APPLICATION;
$sql = "SELECT * FROM APP_CACHE_VIEW WHERE APP_UID='$caseId' AND TAS_UID='$taskId'
   ORDER BY DEL_DELEGATE_DATE DESC"; 
$aTasks = executeQuery($sql);

if (empty($aTasks)) {
   throw new Exception("Error finding Supervisor Review task in database");
}

//if task hasn't been completed, then reassign it to another user:
if ($aTasks[1]['DEL_THREAD_STATUS'] == 'OPEN' and empty($aTasks[1]['DEL_FINISH_DATE'])) {
   $g = new G();
   $g->sessionVarSave();
   PMFDerivateCase($caseId, $aTasks[1]['DEL_INDEX'], true, $aTasks[1]['USR_UID']); 
   $g->sessionVarRestore(); 
}  
#814788
amosbatto wrote: Thu Jun 07, 2018 6:02 pm If you want to automatically route on the "Supervisor Review" task, then you can use this trigger code:
Code: Select all
//set to ID of the "Supervisor Review" task:
$taskId = '232323223230df8ace7e571sdsd72'; 
//set to ID of the user who will be reassigned to task (user must be in assignment list for task):
$reassignUserId = '98123230559ff9jh52fab80888876420';

$caseId = @@APPLICATION;
$sql = "SELECT * FROM APP_CACHE_VIEW WHERE APP_UID='$caseId' AND TAS_UID='$taskId'
   ORDER BY DEL_DELEGATE_DATE DESC"; 
$aTasks = executeQuery($sql);

if (empty($aTasks)) {
   throw new Exception("Error finding Supervisor Review task in database");
}

//if task hasn't been completed, then reassign it to another user:
if ($aTasks[1]['DEL_THREAD_STATUS'] == 'OPEN' and empty($aTasks[1]['DEL_FINISH_DATE'])) {
   $g = new G();
   $g->sessionVarSave();
   PMFDerivateCase($caseId, $aTasks[1]['DEL_INDEX'], true, $aTasks[1]['USR_UID']); 
   $g->sessionVarRestore(); 
}  
Hi Amo,

I have been testing regarding this trigger, it works. As long as the supervisor review task has been completed, the requestor review task will be routed to next (end of the process).

Thanks,
Yuan
Attachments
2018-06-18_10-19-02.png
2018-06-18_10-19-02.png (62.54 KiB) Viewed 849 times
#814837
cosyxu wrote: Sun Jun 17, 2018 8:18 pm I have been testing regarding this trigger, it works. As long as the supervisor review task has been completed, the requestor review task will be routed to next (end of the process).
Is that what you wanted? or are you asking a question?
#814839
amosbatto wrote: Wed Jun 20, 2018 12:01 am
cosyxu wrote: Sun Jun 17, 2018 8:18 pm I have been testing regarding this trigger, it works. As long as the supervisor review task has been completed, the requestor review task will be routed to next (end of the process).
Is that what you wanted? or are you asking a question?
Hi Amo,

Yes, that's what I want to achieve. Thanks for your help. :)

Please find the final process map, it contains both "reassign" function and "route-to-next" function.

Regards,
Yuan
Attachments
2018-06-18_15-16-19.png
2018-06-18_15-16-19.png (90.58 KiB) Viewed 617 times

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[…]