Unofficial documentation how to do interesting things and work around problems in ProcessMaker

Moderator: amosbatto

Forum rules: Unofficial documentation for features which have not been tested by Quality Assurance or may change in future versions of ProcessMaker
#813652
If needing a function to calculate the amount of time that a task takes, based on the calendar of the task or the assigned user, edit the source code found in workflow/engine/classes/class.pmFunctions.php with a plain text file. At the bottom of the file add the following code:
Code: Select all
/************************************************************
Function to break time in seconds into days, minutes, hours and seconds.
Parameters:
   int $seconds: The number of seconds.
   string $timeUnits: The unit of time which can be "seconds", "minutes", "hours", "days",
                      "array" or "string".
Return Value:
   Returns the time according to the $timeUnits. If "string", then returns something like
   "1 day 7 hours 0 minutes 34 seconds" or "45 minutes 1 second". Units which are set to 0 
   not included in the string.
   
   If "array", then returns something like:
   array(
     "days" => 1,
     "hours" => 7,
     "minutes" => 0,
     "seconds" => 34
   ) 
************************************************************/   
function timeBreakdown($seconds, $timeUnits='seconds') {
   $timeUnits = strtolower($timeUnits);
   switch ($timeUnits) {
      case 'seconds':
         return $seconds;
      case 'minutes':
         return $seconds/60;
      case 'hours':
         return $seconds/3600;
      case 'days':
         return $seconds/86400;
      case 'array':
      case 'string':
         $aTime = array();
         $aTime['days'] = (int) ($seconds / 86400);
         $remainder = $seconds % 86400;
         $aTime['hours'] = (int) ($remainder / 3600);
         $remainder = $remainder % 3600;
         $aTime['minutes'] = (int) ($remainder / 60);
         $aTime['seconds'] = $remainder % 60;
         if ($timeUnits == 'array')
            return $aTime;
         else {
            $sTime = '';
            if ($aTime['days'] > 1)
               $sTime = $aTime['days'].' days';
            elseif ($aTime['days'] == 1)
               $sTime = '1 day';             
            
            if ($aTime['hours'] > 1)
               $sTime .= (empty($sTime) ? '' : ' ') . $aTime['hours'].' hours';
            elseif ($aTime['hours'] == 1)
               $sTime .= (empty($sTime) ? '' : ' ') . '1 hour';
            elseif (!empty($sTime))
               $sTime .= ' 0 hours';  
               
            if ($aTime['minutes'] > 1)
               $sTime .= (empty($sTime) ? '' : ' ') . $aTime['minutes'].' minutes';
            elseif ($aTime['minutes'] == 1)
               $sTime .= (empty($sTime) ? '' : ' ') . '1 minute';
            elseif (!empty($sTime))
               $sTime .= ' 0 minutes';  
               
            if ($aTime['seconds'] > 1)
               $sTime .= (empty($sTime) ? '' : ' ') . $aTime['seconds'].' seconds';
            elseif ($aTime['seconds'] == 1)
               $sTime .= (empty($sTime) ? '' : ' ') . '1 second';
            elseif (!empty($sTime))
               $sTime .= ' 0 seconds';
               
            return $sTime;  
         }
      default: 
         throw new Exception("Unrecognized time unit '$timeUnits'");
   }
}            

/********************************
PMFTaskDuration() calculates the amount of time a task has taken, depending
on the calendar which is configured for the task or the assigned user.
Parameters:
  $userUid:    Unique ID of user assigned to the task. Default is the current logged-in user.
  $processUid: Unique ID of the process. Default is the current process.
  $taskUid:    Unique ID of the task whose duration will be calculated. 
  $startTime:  Time when task started in YYYY-MM-DD HH:MM:SS format.
  $endTime:    Time when the task ended in YYYY-MM-DD HH:MM:SS format. 
               If left blank or not included, then set to current time
  $timeUnits:  The unit of time which is returned by the function, which can be:
               "seconds" (default), "minutes", "hours", "days", "string" or "array"
**********************************************************************/
function PMFTaskDuration($userUid, $processUid, 
      $taskUid, $startTime, $endTime, $timeUnits = 'seconds') {
    
   if (empty($endTime)) {
      //change this line to work correctly for current time in the Enterprise Edition:
      $endTime = date("Y-m-d H:i:s"); 
   }
   
   $g = new G();       
   $g->LoadClass('calendar');
   $oCal = new Calendar();
   $oCal->getCalendar($userUid, $processUid, $taskUid);
   $oCal->getCalendarData();
   $seconds = $oCal->calculateDuration($startTime, $endTime);
   return timeBreakdown($seconds, $timeUnits);
}
 
Here are two examples for how to call the PMFTaskDuration() function in a trigger:

Example1: Check how much time has elapsed in the current task:
Code: Select all
$c = new Cases();
$aCase = $c->LoadCase(@@APPLICATION, @%INDEX);
@%TaskSeconds = PMFTaskDuration(@@USER_LOGGED, @@PROCESS, @@TASK, $aCase['DEL_DELEGATE_DATE']); 
Example2: Display a grid of tasks, sorted by task and user:
Code: Select all
$sql = "SELECT PRO_UID, TAS_UID, USR_UID, DEL_DELEGATE_DATE, DEL_FINISH_DATE
   FROM APP_DELEGATION WHERE DEL_THREAD_STATUS='CLOSED' GROUP BY TAS_UID, USR_UID";
$aTasks = executeQuery($sql);

//Calculate task times:
for ($i=1; $i <= count($aTasks); $i++) {
   $aTasks[$i]['TASK_TIME'] = PMFTaskDuration(
      $aTasks[$i]['USR_UID'],
      $aTasks[$i]['PRO_UID'],
      $aTasks[$i]['TAS_UID'],
      $aTasks[$i]['DEL_DELEGATE_DATE'],
      $aTasks[$i]['DEL_FINISH_DATE'],
      'string'
   );         
}
@=TasksGrid = $aTasks;
 
#813726
Hello amosbatto,

Nice work. Do you how to get the case duration and not task duration? I see in mySQL that the app_duration is by default zero. If you can guide me on how to get the case duration after it is first routed and not in draft state that would be awesome.
#813739
naapak wrote:Nice work. Do you how to get the case duration and not task duration? I see in mySQL that the app_duration is by default zero. If you can guide me on how to get the case duration after it is first routed and not in draft state that would be awesome.
You want the amount of time since the first task in the case was routed to the second task until the present time or until the end of the case?
#813751
Here is how to calculate the time since the first task was routed:
Code: Select all
$caseId = @@APPLICATION;
$sql = "SELECT * FROM APP_CACHE_VIEW WHERE APP_UID='$caseId' AND 
   DEL_FINISH_DATE IS NOT NULL ORDER BY DEL_INDEX";
$aTasks = executeQuery($sql)
if (!is_array($aTasks) or count($aTasks) == 0)
  throw new Exception("Have not completed first task in case.").
}
$firstTaskFinish = strtotime($aTasks[1]['DEL_FINISH_DATE']);
//if case is still open, then subtract from the current time:
If (in_array($aTasks[1]['APP_STATUS'], array('DRAFT', 'TO_DO'))) {
   $timeDiff = time() - $firstTaskFinish;  
}
else {
   $caseEndDate = $aTasks[ count($aTasks) ]['DEL_FINISH_DATE'];
   $timeDiff = strtotime($caseEndDate) - $firstTaskFinish;
}
@@caseDurationInHours = timeDiff / (60*60);
#813753
Perfect. I made it work with the task duration code and made modification to it as shown below. Let me know what you think.

But this one is even better. Thank you so much!
Code: Select all
$c = new Cases();
$aCase = $c->LoadCase(@@APPLICATION, @%INDEX);
$taskID = '3815789125ab019d771f2f5035184422';  // task id for the first task
@@caseAge = PMFTaskDuration(@@caseManger, @@PROCESS, $taskID, $aCase['DEL_DELEGATE_DATE'], $aCase['APP_FINISH_DATE'],'days'); 
@@finishDate = $aCase['APP_FINISH_DATE'];
@@caseDate = $aCase['DEL_DELEGATE_DATE'];
#813767
Since your current case is still open, I doubt that this line will return accurate information:
Code: Select all
@@finishDate = $aCase['APP_FINISH_DATE'];
Otherwise, it looks good.

Hello everyone in previous versions of PM the ca[…]

Buen día, a todos Hace un par de día[…]

Perfecto amigo muchas gracias.

hello to all, please your help to resolve this dou[…]