From 848b5c19cb0bbccb11e29df68cd9ac2328c8bc01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julio=20Cesar=20Laura=20Avenda=C3=B1o?= Date: Mon, 9 Nov 2020 15:29:09 +0000 Subject: [PATCH 1/3] PMCORE-2390 --- .../src/ProcessMaker/BusinessModel/Lists.php | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/workflow/engine/src/ProcessMaker/BusinessModel/Lists.php b/workflow/engine/src/ProcessMaker/BusinessModel/Lists.php index 0302f2c20..b53f082ab 100644 --- a/workflow/engine/src/ProcessMaker/BusinessModel/Lists.php +++ b/workflow/engine/src/ProcessMaker/BusinessModel/Lists.php @@ -6,6 +6,7 @@ use G; use Criteria; use PMLicensedFeatures; use ProcessMaker\Model\Delegation; +use ProcessMaker\Model\User; use UsersPeer; /** @@ -213,30 +214,51 @@ class Lists $result = $list->loadList($userUid, $filters); if (!empty($result)) { foreach ($result as &$value) { + // For backward compatibility with "light" endpoints, we need to cast to string + $value['APP_NUMBER'] = (string)$value['APP_NUMBER']; + $value['DEL_INDEX'] = (string)$value['DEL_INDEX']; + if (isset($value['DEL_PREVIOUS_USR_UID'])) { $value['PREVIOUS_USR_UID'] = $value['DEL_PREVIOUS_USR_UID']; $value['PREVIOUS_USR_USERNAME'] = $value['DEL_PREVIOUS_USR_USERNAME']; $value['PREVIOUS_USR_FIRSTNAME'] = $value['DEL_PREVIOUS_USR_FIRSTNAME']; $value['PREVIOUS_USR_LASTNAME'] = $value['DEL_PREVIOUS_USR_LASTNAME']; + } elseif (!empty($value["USR_ID"])) { + $user = User::where("USR_ID", $value["USR_ID"])->first(); + $value["PREVIOUS_USR_UID"] = $value["DEL_PREVIOUS_USR_UID"] = $user->USR_UID; + $value["PREVIOUS_USR_USERNAME"] = $value["DEL_PREVIOUS_USR_USERNAME"] = $user->USR_USERNAME; + $value["PREVIOUS_USR_FIRSTNAME"] = $value["DEL_PREVIOUS_USR_FIRSTNAME"] = $user->USR_FIRSTNAME; + $value["PREVIOUS_USR_LASTNAME"] = $value["DEL_PREVIOUS_USR_LASTNAME"] = $user->USR_LASTNAME; } + if (isset($value['DEL_DUE_DATE'])) { $value['DEL_TASK_DUE_DATE'] = $value['DEL_DUE_DATE']; } + if (isset($value['APP_PAUSED_DATE'])) { $value['APP_UPDATE_DATE'] = $value['APP_PAUSED_DATE']; } + if (isset($value['DEL_CURRENT_USR_USERNAME'])) { $value['USR_USERNAME'] = $value['DEL_CURRENT_USR_USERNAME']; $value['USR_FIRSTNAME'] = $value['DEL_CURRENT_USR_FIRSTNAME']; $value['USR_LASTNAME'] = $value['DEL_CURRENT_USR_LASTNAME']; $value['APP_UPDATE_DATE'] = $value['DEL_DELEGATE_DATE']; } + + if (isset($value['DEL_CURRENT_TAS_TITLE']) && $value['DEL_CURRENT_TAS_TITLE'] != '') { + $value['APP_TAS_TITLE'] = $value['DEL_CURRENT_TAS_TITLE']; + } elseif (!empty($value["TAS_TITLE"]) && empty($value["APP_TAS_TITLE"])) { + $value["APP_TAS_TITLE"] = $value["TAS_TITLE"]; + } + if (isset($value['APP_STATUS'])) { $value['APP_STATUS_LABEL'] = G::LoadTranslation("ID_{$value['APP_STATUS']}"); } - - //$value = array_change_key_case($value, CASE_LOWER); + if (!empty($value["PRO_TITLE"]) && empty($value["APP_PRO_TITLE"])) { + $value["APP_PRO_TITLE"] = $value["PRO_TITLE"]; + } } } $response = array(); From 83e62fda6777a4b39fb0d6a7c1d9a78601410251 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julio=20Cesar=20Laura=20Avenda=C3=B1o?= Date: Mon, 30 Nov 2020 20:01:43 +0000 Subject: [PATCH 2/3] Solving conflicts in cherry-pick for PMCORE-2424 --- .../ProcessMaker/BusinessModel/CasesTest.php | 149 +++++++++++++++- workflow/engine/classes/Cases.php | 5 +- .../src/ProcessMaker/BusinessModel/Cases.php | 168 ++++++++++++++++++ 3 files changed, 318 insertions(+), 4 deletions(-) diff --git a/tests/unit/workflow/engine/src/ProcessMaker/BusinessModel/CasesTest.php b/tests/unit/workflow/engine/src/ProcessMaker/BusinessModel/CasesTest.php index 55c762947..2597bc732 100644 --- a/tests/unit/workflow/engine/src/ProcessMaker/BusinessModel/CasesTest.php +++ b/tests/unit/workflow/engine/src/ProcessMaker/BusinessModel/CasesTest.php @@ -4,16 +4,21 @@ namespace ProcessMaker\BusinessModel; use Exception; use G; -use ProcessMaker\BusinessModel\Cases; +use Illuminate\Support\Facades\DB; use ProcessMaker\Model\Application; use ProcessMaker\Model\Delegation; use ProcessMaker\Model\Documents; +use ProcessMaker\Model\ListUnassigned; +use ProcessMaker\Model\Process; +use ProcessMaker\Model\Step; +use ProcessMaker\Model\Task; +use ProcessMaker\Model\Triggers; use ProcessMaker\Model\User; use RBAC; use Tests\TestCase; /** - * Class DelegationTest + * Class CasesTest * * @coversDefaultClass \ProcessMaker\BusinessModel\Cases */ @@ -233,4 +238,144 @@ class CasesTest extends TestCase // Call the uploadFiles method $case->uploadFiles($user->USR_UID, $application->APP_UID, $varName, -1, null, $delegation->DEL_INDEX); } + + /** + * This test the execution of trigger from cases related to the self services timeout + * + * @covers \ProcessMaker\BusinessModel\Cases::executeSelfServiceTimeout() + * @test + */ + public function it_execute_trigger_from_cases_with_self_service_timeout_every_time() + { + ListUnassigned::truncate(); + // Define the Execute Trigger = EVERY_TIME + $application = factory(Application::class)->states('foreign_keys')->create(); + // Create a trigger + $trigger = factory(Triggers::class)->create([ + 'PRO_UID' => $application->PRO_UID, + 'TRI_WEBBOT' => 'echo(1);' + ]); + // Create a task with the configuration trigger execution + $task = factory(Task::class)->states('sef_service_timeout')->create([ + 'PRO_UID' => $application->PRO_UID, + 'TAS_SELFSERVICE_EXECUTION' => 'EVERY_TIME', + 'TAS_SELFSERVICE_TRIGGER_UID' => $trigger->TRI_UID + ]); + // Create a unassigned cases + factory(ListUnassigned::class)->create([ + 'TAS_UID' => $task->TAS_UID, + 'TAS_ID' => $task->TAS_ID, + 'APP_NUMBER' => $application->APP_NUMBER, + 'APP_UID' => $application->APP_UID, + 'PRO_UID' => $application->PRO_UID + ]); + // Define the session + $_SESSION["PROCESS"] = $application->PRO_UID; + + // todo: the function Cases::loadCase is using propel we need to change this + DB::commit(); + $casesExecuted = Cases::executeSelfServiceTimeout(); + $this->assertTrue(is_array($casesExecuted)); + } + + /** + * This test the execution of trigger from cases related to the self services timeout + * + * @covers \ProcessMaker\BusinessModel\Cases::executeSelfServiceTimeout() + * @test + */ + public function it_execute_trigger_from_cases_with_self_service_timeout_once() + { + ListUnassigned::truncate(); + // Define the Execute Trigger = ONCE + $application = factory(Application::class)->states('foreign_keys')->create(); + // Create a trigger + $trigger = factory(Triggers::class)->create([ + 'PRO_UID' => $application->PRO_UID, + 'TRI_WEBBOT' => 'echo(1);' + ]); + // Create a task with the configuration trigger execution + $task = factory(Task::class)->states('sef_service_timeout')->create([ + 'PRO_UID' => $application->PRO_UID, + 'TAS_SELFSERVICE_EXECUTION' => 'ONCE', + 'TAS_SELFSERVICE_TRIGGER_UID' => $trigger->TRI_UID + ]); + // Create a unassigned cases + factory(ListUnassigned::class)->create([ + 'TAS_UID' => $task->TAS_UID, + 'TAS_ID' => $task->TAS_ID, + 'APP_NUMBER' => $application->APP_NUMBER, + 'APP_UID' => $application->APP_UID, + 'PRO_UID' => $application->PRO_UID + ]); + // Define the session + $_SESSION["PROCESS"] = $application->PRO_UID; + + // todo: the function Cases::loadCase is using propel we need to change this + DB::commit(); + $casesExecuted = Cases::executeSelfServiceTimeout(); + $this->assertTrue(is_array($casesExecuted)); + } + + /** + * It test get assigned DynaForms as steps by application Uid + * + * @covers \ProcessMaker\BusinessModel\Cases::dynaFormsByApplication() + * @test + */ + public function it_should_test_get_dynaforms_by_application() + { + // Create a process + $process = factory(Process::class)->create(); + + // Create a task related to the process + $task1 = factory(Task::class)->create([ + 'PRO_UID' => $process->PRO_UID + ]); + + // Created another task related to the process + $task2 = factory(Task::class)->create([ + 'PRO_UID' => $process->PRO_UID + ]); + + // Created a step related to the first task + factory(Step::class)->create([ + 'PRO_UID' => $process->PRO_UID, + 'TAS_UID' => $task1->TAS_UID, + 'STEP_TYPE_OBJ' => 'DYNAFORM', + 'STEP_UID_OBJ' => G::generateUniqueID(), + 'STEP_POSITION' => 1 + ]); + + // Created a step related to the second task and with a specific DynaForm Uid + $dynUid = G::generateUniqueID(); + factory(Step::class)->create([ + 'PRO_UID' => $process->PRO_UID, + 'TAS_UID' => $task2->TAS_UID, + 'STEP_TYPE_OBJ' => 'DYNAFORM', + 'STEP_UID_OBJ' => $dynUid, + 'STEP_POSITION' => 1 + ]); + + // Create an application related to the process in draft status + $application = factory(Application::class)->create([ + 'PRO_UID' => $process->PRO_UID, + 'APP_STATUS' => 'DRAFT' + ]); + + // Get all DynaForms assigned as steps + self::assertCount(2, Cases::dynaFormsByApplication($application->APP_UID)); + + // Get DynaForms assigned as steps for the first task + self::assertCount(1, Cases::dynaFormsByApplication($application->APP_UID, $task1->TAS_UID)); + + // Get DynaForms assigned as steps sending a specific DynaForm Uid + self::assertCount(1, Cases::dynaFormsByApplication($application->APP_UID, '', $dynUid)); + + // Get DynaForms assigned as steps for the second task when the application status is DRAFT + self::assertCount(1, Cases::dynaFormsByApplication($application->APP_UID, $task2->TAS_UID, '', 'TO_DO')); + + // Get DynaForms assigned as steps for the second task when the application status is COMPLETED + self::assertCount(2, Cases::dynaFormsByApplication($application->APP_UID, $task2->TAS_UID, '', 'COMPLETED')); + } } diff --git a/workflow/engine/classes/Cases.php b/workflow/engine/classes/Cases.php index 114d178fb..8d9bc5579 100644 --- a/workflow/engine/classes/Cases.php +++ b/workflow/engine/classes/Cases.php @@ -1,6 +1,7 @@ objectPermissionByDynaform( + $listDynaform = BusinessModelCases::dynaFormsByApplication( $appUid, $opTaskSource, $opObjUid, @@ -6149,7 +6150,7 @@ class Cases $resultMessages = array_merge($resultMessages, $listMessage); break; case 'DYNAFORM': - $listDynaform = $objectPermission->objectPermissionByDynaform( + $listDynaform = BusinessModelCases::dynaFormsByApplication( $appUid, $opTaskSource, $opObjUid, diff --git a/workflow/engine/src/ProcessMaker/BusinessModel/Cases.php b/workflow/engine/src/ProcessMaker/BusinessModel/Cases.php index b41f880f6..b74bba652 100644 --- a/workflow/engine/src/ProcessMaker/BusinessModel/Cases.php +++ b/workflow/engine/src/ProcessMaker/BusinessModel/Cases.php @@ -31,6 +31,7 @@ use Exception; use G; use Groups; use GroupUserPeer; +use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Log; use InputDocument; use InvalidIndexSearchTextException; @@ -4107,4 +4108,171 @@ class Cases return true; } + + /** + * Get the cases related to the self services timeout that needs to execute the trigger related + * + * @return array + * @throws Exception + */ + public static function executeSelfServiceTimeout() + { + try { + $casesSelfService = ListUnassigned::selfServiceTimeout(); + $casesExecuted = []; + foreach ($casesSelfService as $row) { + $appUid = $row["APP_UID"]; + $appNumber = $row["APP_NUMBER"]; + $delIndex = $row["DEL_INDEX"]; + $delegateDate = $row["DEL_DELEGATE_DATE"]; + $proUid = $row["PRO_UID"]; + $taskUid = $row["TAS_UID"]; + $taskSelfServiceTime = intval($row["TAS_SELFSERVICE_TIME"]); + $taskSelfServiceTimeUnit = $row["TAS_SELFSERVICE_TIME_UNIT"]; + $triggerUid = $row["TAS_SELFSERVICE_TRIGGER_UID"]; + + /*----------------------------------********---------------------------------*/ + $typeOfExecution = $row["TAS_SELFSERVICE_EXECUTION"]; + $flagExecuteOnce = true; + // This option will be executed just once, can check if was executed before + if ($typeOfExecution == 'ONCE') { + $appTimeout = new AppTimeoutAction(); + $appTimeout->setCaseUid($appUid); + $appTimeout->setIndex($delIndex); + $caseExecuted = $appTimeout->cases(); + $flagExecuteOnce = !empty($caseExecuted) ? false : true; + } + /*----------------------------------********---------------------------------*/ + + // Add the time in the corresponding unit to the delegation date + $delegateDate = calculateDate($delegateDate, $taskSelfServiceTimeUnit, $taskSelfServiceTime); + + // Define the current time + $datetime = new DateTime('now'); + $currentDate = $datetime->format('Y-m-d H:i:s'); + + // Check if the triggers to be executed + if ($currentDate >= $delegateDate && $flagExecuteOnce) { + // Review if the session process is defined + $sessProcess = null; + $sessProcessSw = false; + if (isset($_SESSION["PROCESS"])) { + $sessProcess = $_SESSION["PROCESS"]; + $sessProcessSw = true; + } + // Load case data + $case = new ClassesCases(); + $appFields = $case->loadCase($appUid); + $appFields["APP_DATA"]["APPLICATION"] = $appUid; + // Set the process defined in the case related + $_SESSION["PROCESS"] = $appFields["PRO_UID"]; + + // Get the trigger related and execute + $triggersList = []; + if (!empty($triggerUid)) { + $trigger = new Triggers(); + $trigger->setTrigger($triggerUid); + $triggersList = $trigger->triggers(); + } + + // If the trigger exist, let's to execute + if (!empty($triggersList)) { + // Execute the trigger defined in the self service timeout + $fieldsCase['APP_DATA'] = $case->executeTriggerFromList( + $triggersList, + $appFields['APP_DATA'], + 'SELF_SERVICE_TIMEOUT', + '', + '', + '', + false + ); + + // Update the case + $case->updateCase($appUid, $fieldsCase); + + /*----------------------------------********---------------------------------*/ + if ($typeOfExecution == 'ONCE') { + // Saving the case`s data if the 'Execution' is set in ONCE. + $appTimeoutActionExecuted = new AppTimeoutActionExecuted(); + $dataSelf = []; + $dataSelf["APP_UID"] = $appUid; + $dataSelf["DEL_INDEX"] = $delIndex; + $dataSelf["EXECUTION_DATE"] = time(); + $appTimeoutActionExecuted->create($dataSelf); + } + /*----------------------------------********---------------------------------*/ + + array_push($casesExecuted, $appNumber); // Register the cases executed + + // Logging this action + $context = [ + 'appUid' => $appUid, + 'appNumber' => $appNumber, + 'triUid' => $triggerUid, + 'proUid' => $proUid, + 'tasUid' => $taskUid, + 'selfServiceTime' => $taskSelfServiceTime, + 'selfServiceTimeUnit' => $taskSelfServiceTimeUnit, + ]; + Log::channel(':TriggerExecution')->info('Timeout trigger execution', Bootstrap::context($context)); + } + + unset($_SESSION["PROCESS"]); + + if ($sessProcessSw) { + $_SESSION["PROCESS"] = $sessProcess; + } + } + } + + return $casesExecuted; + } catch (Exception $e) { + throw $e; + } + } + + /** + * Get DynaForms Uids assigned as steps in the related process by application Uid + * + * @param string $appUid + * @param int $sourceTask + * @param string $dynUid + * @param string $caseStatus + * @return array + */ + public static function dynaFormsByApplication($appUid, $sourceTask = 0, $dynUid = '', $caseStatus = '') + { + // Select distinct DYN_UID + $query = ModelApplication::query()->select('STEP.STEP_UID_OBJ AS DYN_UID')->distinct(); + + // Join with STEP table + $query->join('STEP', function ($join) { + $join->on('APPLICATION.PRO_UID', '=', 'STEP.PRO_UID'); + $join->on('STEP.STEP_TYPE_OBJ', '=', DB::raw("'DYNAFORM'")); + }); + + // Filter by application Uid + $query->where('APPLICATION.APP_UID', '=', $appUid); + + // Filter by source task + if ($caseStatus != 'COMPLETED' && $sourceTask != '' && (int)$sourceTask != 0) { + $query->where('STEP.TAS_UID', '=', $sourceTask); + } + + // Filter by DynaForm Uid + if ($dynUid != '' && $dynUid != '0') { + $query->where('STEP.STEP_UID_OBJ', '=', $dynUid); + } + + // Get results + $dynaForms = []; + $items = $query->get(); + $items->each(function ($item) use (&$dynaForms) { + $dynaForms[] = $item->DYN_UID; + }); + + // Return results + return $dynaForms; + } } From fc2c83eba2c1cb25dcd8ee204d5ff69197ab340e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julio=20Cesar=20Laura=20Avenda=C3=B1o?= Date: Thu, 17 Dec 2020 18:42:19 +0000 Subject: [PATCH 3/3] PMCORE-2551 --- workflow/engine/methods/mails/emailsAjax.php | 2 -- workflow/engine/templates/mails/emailList.js | 3 +++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/workflow/engine/methods/mails/emailsAjax.php b/workflow/engine/methods/mails/emailsAjax.php index d8bd64e2b..d83cf5d07 100644 --- a/workflow/engine/methods/mails/emailsAjax.php +++ b/workflow/engine/methods/mails/emailsAjax.php @@ -133,8 +133,6 @@ switch ($req) { $row = $result->getRow(); $row['APP_MSG_STATUS'] = ucfirst($row['APP_MSG_STATUS']); $row['APP_MSG_DATE'] = DateTime::convertUtcToTimeZone($row['APP_MSG_DATE']); - $row['APP_MSG_TO'] = htmlentities($row['APP_MSG_TO'], ENT_HTML5, "UTF-8"); - $row['APP_MSG_ERROR'] = htmlentities($row['APP_MSG_ERROR'], ENT_HTML5, "UTF-8"); switch ($filterBy) { case 'CASES': diff --git a/workflow/engine/templates/mails/emailList.js b/workflow/engine/templates/mails/emailList.js index 0a9650bf6..0600f8f0e 100644 --- a/workflow/engine/templates/mails/emailList.js +++ b/workflow/engine/templates/mails/emailList.js @@ -54,6 +54,9 @@ Ext.onReady(function(){ data = PMExt.emailConst.numberColumn.defaultValue; } } + if (metadata.id === 'APP_MSG_TO' || metadata.id === 'APP_MSG_ERROR') { + return Ext.util.Format.htmlEncode(data); + } var new_text = metadata.style.split(';'); var style = ''; for (var i = 0; i < new_text.length -1 ; i++) {