diff --git a/workflow/engine/classes/class.case.php b/workflow/engine/classes/class.case.php index b069420d4..cce1a7c42 100644 --- a/workflow/engine/classes/class.case.php +++ b/workflow/engine/classes/class.case.php @@ -1225,6 +1225,40 @@ class Cases } } + + /* + * Determines if the all threads of a multiinstance task are closed + * + * @$appUid string appUid of the instance to be tested + * @$tasUid string task uid of the multiinstance task + * @$previousDelIndex int previous del index of the instance corresponding to the multiinstance task + */ + + public function multiInstanceIsCompleted($appUid, $tasUid, $previousDelIndex) + { + $result = false; + try { + $c = new Criteria(); + $c->clearSelectColumns(); + $c->add(AppDelegationPeer::APP_UID, $appUid); + $c->add(AppDelegationPeer::TAS_UID, $tasUid); + $c->add(AppDelegationPeer::DEL_PREVIOUS, $previousDelIndex); + $c->add(AppDelegationPeer::DEL_THREAD_STATUS, 'OPEN'); + $rs = AppDelegationPeer::doSelectRs($c); + + if ($rs->next()) { + $result = false; + } else { + $result = true; + } + + } catch (exception $e) { + throw ($e); + } finally { + return $result; + } + } + /* * GetOpenThreads * diff --git a/workflow/engine/classes/class.derivation.php b/workflow/engine/classes/class.derivation.php index a753716c4..a67fc0ed6 100644 --- a/workflow/engine/classes/class.derivation.php +++ b/workflow/engine/classes/class.derivation.php @@ -269,7 +269,7 @@ class Derivation $arrayNextTaskData = $value; $this->node[$value['TAS_UID']]['out'][$value['ROU_NEXT_TASK']] = $value['ROU_TYPE']; if ($arrayNextTaskData["NEXT_TASK"]["TAS_UID"] != "-1" && - preg_match("/^(?:" . $this->regexpTaskTypeToInclude . ")$/", $arrayNextTaskData["NEXT_TASK"]["TAS_TYPE"]) + preg_match("/^(?:" . $this->regexpTaskTypeToInclude . ")$/", $arrayNextTaskData["NEXT_TASK"]["TAS_TYPE"]) && $arrayNextTaskData['ROU_TYPE'] != "SEC-JOIN" ) { $arrayAux = $this->prepareInformation($arrayData, $arrayNextTaskData["NEXT_TASK"]["TAS_UID"]); $this->node[$value['ROU_NEXT_TASK']]['in'][$value['TAS_UID']] = $value['ROU_TYPE']; @@ -832,6 +832,38 @@ class Derivation /*----------------------------------********---------------------------------*/ } + /** + * This function prepare the information before call the derivate function + * + * We can route a case from differents ways from cases_Derivate and derivateCase used in PMFDerivateCase + * before this we need to process the information + * + * @param array $aDataForPrepareInfo + * @param array $tasks + * @param string $rouType + * @param array $aCurrentDerivation + * @return array $arrayDerivationResult + */ + function beforeDerivate($aDataForPrepareInfo, $tasks, $rouType, $aCurrentDerivation) + { + $aPInformation = $this->prepareInformation($aDataForPrepareInfo); + $oRoute = new \ProcessMaker\Core\RoutingScreen(); + $nextTasks = $oRoute->mergeDataDerivation($tasks, $aPInformation, $rouType); + + //Get all route types + $aRouteTypes = array(); + foreach ($aPInformation as $key => $value) { + $aRouteTypes[$key]['ROU_NEXT_TASK'] = $value['ROU_NEXT_TASK']; + $aRouteTypes[$key]['ROU_TYPE'] = $value['ROU_TYPE']; + } + $aCurrentDerivation['ROUTE_TYPES'] = $aRouteTypes; + + //Derivate the case + $arrayDerivationResult = $this->derivate($aCurrentDerivation, $nextTasks); + + return $arrayDerivationResult; + } + /** Derivate * * @param array $currentDelegation @@ -971,12 +1003,26 @@ class Derivation case TASK_FINISH_TASK: $iAppThreadIndex = $appFields['DEL_THREAD']; $this->case->closeAppThread($currentDelegation['APP_UID'], $iAppThreadIndex); + if (isset($nextDel["TAS_UID_DUMMY"]) && !$flagTaskAssignTypeIsMultipleInstance) { $taskDummy = TaskPeer::retrieveByPK($nextDel["TAS_UID_DUMMY"]); if (preg_match("/^(?:END-MESSAGE-EVENT|END-EMAIL-EVENT)$/", $taskDummy->getTasType())) { $this->executeEvent($nextDel["TAS_UID_DUMMY"], $appFields, $flagFirstIteration, true); } } + + //if the next task is an end event and the multiinstance threads are finished the end event + //is triggered: + if (isset($nextDel["TAS_UID_DUMMY"]) && $flagTaskAssignTypeIsMultipleInstance) { + $taskDummy = TaskPeer::retrieveByPK($nextDel["TAS_UID_DUMMY"]); + if ($this->case->multiInstanceIsCompleted($appFields['APP_UID'], + $appFields['TAS_UID'], + $appFields['DEL_PREVIOUS']) + && preg_match("/^(?:END-MESSAGE-EVENT|END-EMAIL-EVENT)$/", $taskDummy->getTasType())) { + $this->executeEvent($nextDel["TAS_UID_DUMMY"], $appFields, $flagFirstIteration, true); + } + } + $this->case->closeAppThread($currentDelegation['APP_UID'], $iAppThreadIndex); $aContext['action'] = 'finish-task'; //Logger @@ -1418,21 +1464,24 @@ class Derivation $application = new Application(); $result = $application->update(['APP_UID' => $currentDelegation['APP_UID'], 'APP_ROUTING_DATA' => serialize($arrayRoutingData)]); - //APP_THREAD + //We updated the information relate to APP_THREAD $iAppThreadIndex = $appFields['DEL_THREAD']; - - switch ($currentDelegation['ROU_TYPE']) { - case 'PARALLEL': - case 'PARALLEL-BY-EVALUATION': - $this->case->closeAppThread( $currentDelegation['APP_UID'], $iAppThreadIndex ); - $iNewThreadIndex = $this->case->newAppThread( $currentDelegation['APP_UID'], $iNewDelIndex, $iAppThreadIndex ); - $this->case->updateAppDelegation( $currentDelegation['APP_UID'], $iNewDelIndex, $iNewThreadIndex, $appFields['APP_NUMBER'] ); - break; - default: - $this->case->updateAppThread( $currentDelegation['APP_UID'], $iAppThreadIndex, $iNewDelIndex ); - break; - } //en switch - + $isUpdatedThread = false; + if (isset($currentDelegation['ROUTE_TYPES']) && sizeof($currentDelegation['ROUTE_TYPES']) > 1) { + //If the next is more than one thread: Parallel or other + foreach ($currentDelegation['ROUTE_TYPES'] as $key => $value) { + if ($value['ROU_NEXT_TASK'] === $nextDel['TAS_UID']) { + $isUpdatedThread = true; + $routeType = ($value['ROU_TYPE'] === 'EVALUATE') ? 'PARALLEL-AND-EXCLUSIVE' : $value['ROU_TYPE']; + $this->updateAppThread($routeType, $currentDelegation['APP_UID'], $iAppThreadIndex, $iNewDelIndex); + } + } + } + if (!$isUpdatedThread) { + //If the next is a sequential derivation + $this->updateAppThread($currentDelegation['ROU_TYPE'], $currentDelegation['APP_UID'], $iAppThreadIndex, $iNewDelIndex); + } + //if there are subprocess to create if (isset( $aSP )) { //Check if is Selfservice the task in the subprocess @@ -1550,6 +1599,28 @@ class Derivation return $iNewDelIndex; } + /** + * This function create, update and closed a new record related to appThread + * + * Related to route type we can change the records in the APP_THREAD table + * @param string $routeType this variable recibe information about the derivation + * @return void + */ + function updateAppThread($routeType, $appUid, $iAppThreadIndex, $iNewDelIndex) { + switch ($routeType) { + case 'PARALLEL': + case 'PARALLEL-BY-EVALUATION': + case 'PARALLEL-AND-EXCLUSIVE': + $this->case->closeAppThread($appUid, $iAppThreadIndex); + $iNewThreadIndex = $this->case->newAppThread($appUid, $iNewDelIndex, $iAppThreadIndex); + $this->case->updateAppDelegation($appUid, $iNewDelIndex, $iNewThreadIndex); + break; + default: + $this->case->updateAppThread($appUid, $iAppThreadIndex, $iNewDelIndex); + break; + } + } + /* verifyIsCaseChild * * @param string $sApplicationUID diff --git a/workflow/engine/classes/class.wsBase.php b/workflow/engine/classes/class.wsBase.php index db292454e..7744da3b3 100644 --- a/workflow/engine/classes/class.wsBase.php +++ b/workflow/engine/classes/class.wsBase.php @@ -2268,10 +2268,6 @@ class wsBase $oPMScript = new PMScript(); foreach ($aTriggers as $aTrigger) { - //$appFields = $oCase->loadCase( $caseId ); - //$appFields['APP_DATA']['APPLICATION'] = $caseId; - - //Set variables $params = new stdClass(); $params->appData = $appFields["APP_DATA"]; @@ -2320,10 +2316,6 @@ class wsBase $oPMScript = new PMScript(); foreach ($aTriggers as $aTrigger) { - //$appFields = $oCase->loadCase( $caseId ); - //$appFields['APP_DATA']['APPLICATION'] = $caseId; - - //Set variables $params = new stdClass(); $params->appData = $appFields["APP_DATA"]; @@ -2416,12 +2408,6 @@ class wsBase $appFields['TAS_UID'] = $derive['TAS_UID']; } - //Save data - Start - //$appFields = $oCase->loadCase( $caseId ); - //$oCase->updateCase ( $caseId, $appFields ); - //Save data - End - - $row = array (); $oCriteria = new Criteria( 'workflow' ); $del = DBAdapter::getStringDelimiter(); @@ -2433,25 +2419,33 @@ class wsBase $oDataset->next(); while ($aRow = $oDataset->getRow()) { - $row[] = array ('ROU_TYPE' => $aRow['ROU_TYPE'],'ROU_NEXT_TASK' => $aRow['ROU_NEXT_TASK'] - ); + $row[] = array('ROU_TYPE' => $aRow['ROU_TYPE'], 'ROU_NEXT_TASK' => $aRow['ROU_NEXT_TASK']); $oDataset->next(); } - //derivate case - $aCurrentDerivation = array ('APP_UID' => $caseId,'DEL_INDEX' => $delIndex,'APP_STATUS' => $sStatus,'TAS_UID' => $appdel['TAS_UID'],'ROU_TYPE' => $row[0]['ROU_TYPE'] + $aCurrentDerivation = array ( + 'APP_UID' => $caseId, + 'DEL_INDEX' => $delIndex, + 'APP_STATUS' => $sStatus, + 'TAS_UID' => $appdel['TAS_UID'], + 'ROU_TYPE' => $row[0]['ROU_TYPE'] ); - $oRoute = new \ProcessMaker\Core\RoutingScreen(); - $nextTasks = $oRoute->mergeDataDerivation($nextDelegations, $oDerivation->prepareInformation($aData), $row[0]['ROU_TYPE']); - $oDerivation->derivate( $aCurrentDerivation, $nextTasks ); + + //We define some parameters in the before the derivation + //Then this function will be route the case + $oDerivation->beforeDerivate( + $aData, + $nextDelegations, + $row[0]['ROU_TYPE'], + $aCurrentDerivation + ); + $appFields = $oCase->loadCase( $caseId ); //Execute triggers after derivation $aTriggers = $oCase->loadTriggers( $appdel['TAS_UID'], 'ASSIGN_TASK', - 2, 'AFTER' ); if (count( $aTriggers ) > 0) { - //$appFields['APP_DATA']['APPLICATION'] = $caseId; - //Set variables $params = new stdClass(); diff --git a/workflow/engine/methods/cases/cases_Derivate.php b/workflow/engine/methods/cases/cases_Derivate.php index 00d88efe3..b7fee6e51 100644 --- a/workflow/engine/methods/cases/cases_Derivate.php +++ b/workflow/engine/methods/cases/cases_Derivate.php @@ -126,15 +126,29 @@ try { $oCase->updateCase($_SESSION["APPLICATION"], $appFields); //Save data - //derivate case + //Prepare information for the derivation $oDerivation = new Derivation(); - $aCurrentDerivation = array ('APP_UID' => $_SESSION['APPLICATION'],'DEL_INDEX' => $_SESSION['INDEX'],'APP_STATUS' => $sStatus,'TAS_UID' => $_SESSION['TASK'],'ROU_TYPE' => $_POST['form']['ROU_TYPE'] + $aCurrentDerivation = array ( + 'APP_UID' => $_SESSION['APPLICATION'], + 'DEL_INDEX' => $_SESSION['INDEX'], + 'APP_STATUS' => $sStatus, + 'TAS_UID' => $_SESSION['TASK'], + 'ROU_TYPE' => $_POST['form']['ROU_TYPE'] ); - $aPInformation = $oDerivation->prepareInformation( array ('USER_UID' => $_SESSION['USER_LOGGED'],'APP_UID' => $_SESSION['APPLICATION'],'DEL_INDEX' => $_SESSION['INDEX']) + $aDataForPrepareInfo = array ( + 'USER_UID' => $_SESSION['USER_LOGGED'], + 'APP_UID' => $_SESSION['APPLICATION'], + 'DEL_INDEX' => $_SESSION['INDEX'] + ); + + //We define some parameters in the before the derivation + //Then this function will be route the case + $arrayDerivationResult = $oDerivation->beforeDerivate( + $aDataForPrepareInfo, + $_POST['form']['TASKS'], + $_POST['form']['ROU_TYPE'], + $aCurrentDerivation ); - $oRoute = new \ProcessMaker\Core\RoutingScreen(); - $nextTasks = $oRoute->mergeDataDerivation($_POST['form']['TASKS'], $aPInformation, $_POST['form']['ROU_TYPE']); - $arrayDerivationResult = $oDerivation->derivate($aCurrentDerivation, $nextTasks); if (!empty($arrayDerivationResult)) { foreach ($_POST['form']['TASKS'] as $key => $value) { diff --git a/workflow/engine/methods/cases/cases_Step.php b/workflow/engine/methods/cases/cases_Step.php index 24f085044..e66fed660 100644 --- a/workflow/engine/methods/cases/cases_Step.php +++ b/workflow/engine/methods/cases/cases_Step.php @@ -826,7 +826,7 @@ try { throw (new Exception( G::LoadTranslation( 'ID_NO_DERIVATION_RULE' ) )); } - //take the first derivation rule as the task derivation rule type. + //Take the first derivation rule as the task derivation rule type. $aFields['PROCESS']['ROU_TYPE'] = $aFields['TASK'][1]['ROU_TYPE']; $aFields['PROCESS']['ROU_FINISH_FLAG'] = false; @@ -1106,12 +1106,22 @@ try { $title = htmlentities($aFields['TASK'][$sKey]['NEXT_TASK']['TAS_TITLE'], ENT_QUOTES, 'UTF-8'); $aFields['TASK'][$sKey]['NEXT_TASK']['TAS_TITLE'] = $title; + //todo These two conditions must go to the RoutingScreen class if (!preg_match("/\-1$/", $aFields["TASK"][$sKey]["NEXT_TASK"]["TAS_UID"]) && $aFields["TASK"][$sKey]["NEXT_TASK"]["TAS_TYPE"] == "INTERMEDIATE-CATCH-MESSAGE-EVENT" ) { $aFields["TASK"][$sKey]["NEXT_TASK"]["TAS_TITLE"] = G::LoadTranslation("ID_ROUTE_TO_TASK_INTERMEDIATE_CATCH_MESSAGE_EVENT"); } + if (!empty($aFields["TASK"][$sKey]['NEXT_TASK']["TAS_TYPE"]) && + ($aFields["TASK"][$sKey]['NEXT_TASK']["TAS_TYPE"] === "END-EMAIL-EVENT" || $aFields["TASK"][$sKey]['NEXT_TASK']["TAS_TYPE"] === "END-MESSAGE-EVENT") + ) { + $aFields["TASK"][$sKey]["NEXT_TASK"]["TAS_TITLE"] = G::LoadTranslation("ID_END_OF_PROCESS"); + //Value of $aFields["TASK"][$sKey]["NEXT_TASK"]["USR_UID"] is not used in routing template when is an end event. + $aFields["TASK"][$sKey]["NEXT_TASK"]["USR_UID"] = $_SESSION['USR_FULLNAME']; + $aFields["TASK"][$sKey]["NEXT_TASK"]["USR_USERNAME"] = $_SESSION['USR_FULLNAME']; + } + $G_PUBLISH->AddContent( 'smarty', $tplFile, '', '', $aFields ); /* if (isset( $aFields['TASK'][1]['NEXT_TASK']['USER_ASSIGNED'])){