From 0badaaf140859c613c90b9d6fa0d85151751bf2b Mon Sep 17 00:00:00 2001 From: Andrea Adamczyk Date: Thu, 5 Aug 2021 12:55:47 -0400 Subject: [PATCH 01/36] PMCORE-573 --- workflow/engine/classes/model/map/StepTriggerMapBuilder.php | 2 +- workflow/engine/classes/model/om/BaseStepTrigger.php | 4 ++-- workflow/engine/config/schema.xml | 2 +- workflow/engine/data/mysql/schema.sql | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/workflow/engine/classes/model/map/StepTriggerMapBuilder.php b/workflow/engine/classes/model/map/StepTriggerMapBuilder.php index 5ee3667be..ef927f666 100644 --- a/workflow/engine/classes/model/map/StepTriggerMapBuilder.php +++ b/workflow/engine/classes/model/map/StepTriggerMapBuilder.php @@ -73,7 +73,7 @@ class StepTriggerMapBuilder $tMap->addPrimaryKey('ST_TYPE', 'StType', 'string', CreoleTypes::VARCHAR, true, 20); - $tMap->addColumn('ST_CONDITION', 'StCondition', 'string', CreoleTypes::VARCHAR, true, 255); + $tMap->addColumn('ST_CONDITION', 'StCondition', 'string', CreoleTypes::LONGVARCHAR, true, null); $tMap->addColumn('ST_POSITION', 'StPosition', 'int', CreoleTypes::INTEGER, true, null); diff --git a/workflow/engine/classes/model/om/BaseStepTrigger.php b/workflow/engine/classes/model/om/BaseStepTrigger.php index 52e62f2dd..7630714a5 100644 --- a/workflow/engine/classes/model/om/BaseStepTrigger.php +++ b/workflow/engine/classes/model/om/BaseStepTrigger.php @@ -55,7 +55,7 @@ abstract class BaseStepTrigger extends BaseObject implements Persistent * The value for the st_condition field. * @var string */ - protected $st_condition = ''; + protected $st_condition; /** * The value for the st_position field. @@ -246,7 +246,7 @@ abstract class BaseStepTrigger extends BaseObject implements Persistent $v = (string) $v; } - if ($this->st_condition !== $v || $v === '') { + if ($this->st_condition !== $v) { $this->st_condition = $v; $this->modifiedColumns[] = StepTriggerPeer::ST_CONDITION; } diff --git a/workflow/engine/config/schema.xml b/workflow/engine/config/schema.xml index 27e16ae9d..a4b9f8231 100755 --- a/workflow/engine/config/schema.xml +++ b/workflow/engine/config/schema.xml @@ -1385,7 +1385,7 @@ - + Date: Thu, 5 Aug 2021 17:15:56 -0400 Subject: [PATCH 02/36] PMCORE-562 --- .../classes/model/om/BaseBpmnActivity.php | 4 ++-- workflow/engine/config/schema.xml | 2 +- workflow/engine/data/mysql/schema.sql | 2 +- .../Project/Adapter/BpmnWorkflow.php | 18 ++++++++++-------- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/workflow/engine/classes/model/om/BaseBpmnActivity.php b/workflow/engine/classes/model/om/BaseBpmnActivity.php index fee1ba3ce..b409d27a7 100644 --- a/workflow/engine/classes/model/om/BaseBpmnActivity.php +++ b/workflow/engine/classes/model/om/BaseBpmnActivity.php @@ -109,7 +109,7 @@ abstract class BaseBpmnActivity extends BaseObject implements Persistent * The value for the act_loop_type field. * @var string */ - protected $act_loop_type = 'NONE'; + protected $act_loop_type = 'EMPTY'; /** * The value for the act_test_before field. @@ -870,7 +870,7 @@ abstract class BaseBpmnActivity extends BaseObject implements Persistent $v = (string) $v; } - if ($this->act_loop_type !== $v || $v === 'NONE') { + if ($this->act_loop_type !== $v || $v === 'EMPTY') { $this->act_loop_type = $v; $this->modifiedColumns[] = BpmnActivityPeer::ACT_LOOP_TYPE; } diff --git a/workflow/engine/config/schema.xml b/workflow/engine/config/schema.xml index 27e16ae9d..47be40f27 100755 --- a/workflow/engine/config/schema.xml +++ b/workflow/engine/config/schema.xml @@ -3815,7 +3815,7 @@ - + diff --git a/workflow/engine/data/mysql/schema.sql b/workflow/engine/data/mysql/schema.sql index cd1647c3c..b10b58167 100644 --- a/workflow/engine/data/mysql/schema.sql +++ b/workflow/engine/data/mysql/schema.sql @@ -1918,7 +1918,7 @@ CREATE TABLE `BPMN_ACTIVITY` `ACT_INSTANTIATE` TINYINT default 0, `ACT_SCRIPT_TYPE` VARCHAR(255), `ACT_SCRIPT` MEDIUMTEXT, - `ACT_LOOP_TYPE` VARCHAR(20) default 'NONE' NOT NULL, + `ACT_LOOP_TYPE` VARCHAR(20) default 'EMPTY' NOT NULL, `ACT_TEST_BEFORE` TINYINT default 0, `ACT_LOOP_MAXIMUM` INTEGER default 0, `ACT_LOOP_CONDITION` VARCHAR(100), diff --git a/workflow/engine/src/ProcessMaker/Project/Adapter/BpmnWorkflow.php b/workflow/engine/src/ProcessMaker/Project/Adapter/BpmnWorkflow.php index 12c997f6c..f928a47c2 100644 --- a/workflow/engine/src/ProcessMaker/Project/Adapter/BpmnWorkflow.php +++ b/workflow/engine/src/ProcessMaker/Project/Adapter/BpmnWorkflow.php @@ -1316,7 +1316,7 @@ class BpmnWorkflow extends Project\Bpmn $diagramData = array_change_key_case($projectData["diagrams"][0], CASE_UPPER); if ($generateUid) { - $result[1]["old_uid"] = $diagramData["DIA_UID"]; + $result[1]["old_uid"] = isset($diagramData["DIA_UID"]) ? $diagramData["DIA_UID"] : ''; $diagramData["DIA_UID"] = Util\Common::generateUID(); $result[1]["new_uid"] = $diagramData["DIA_UID"]; $result[1]["object"] = "diagram"; @@ -1408,13 +1408,15 @@ class BpmnWorkflow extends Project\Bpmn try { unset($arrayObjectData["BOU_UID"]); - if ($arrayObjectData["BOU_CONTAINER"] == "bpmnPool" || + if (isset($arrayObjectData["BOU_CONTAINER"])) { + if ($arrayObjectData["BOU_CONTAINER"] == "bpmnPool" || $arrayObjectData["BOU_CONTAINER"] == "bpmnLane" || $arrayObjectData["BOU_CONTAINER"] == "bpmnActivity" - ) { - foreach ($arrayUid as $value) { - if ($arrayObjectData["BOU_ELEMENT"] == $value["old_uid"]) { - $arrayObjectData["BOU_ELEMENT"] = $value["new_uid"]; + ) { + foreach ($arrayUid as $value) { + if ($arrayObjectData["BOU_ELEMENT"] == $value["old_uid"]) { + $arrayObjectData["BOU_ELEMENT"] = $value["new_uid"]; + } } } } @@ -1615,13 +1617,13 @@ class BpmnWorkflow extends Project\Bpmn unset($activityData["_EXTENDED"], $activityData["BOU_ELEMENT_ID"]); $activityData = Util\ArrayUtil::boolToIntValues($activityData); - $activity = $bwp->getActivity($activityData["ACT_UID"]); + $activity = $bwp->getActivity(isset($activityData["ACT_UID"]) ? $activityData["ACT_UID"] : ''); if ($forceInsert || is_null($activity)) { if ($generateUid) { //Generate and update UID $activityData = $bwp->updateBoundByArrayUid($activityData, $result); - $uidOld = $activityData["ACT_UID"]; + $uidOld = isset($activityData["ACT_UID"]) ? $activityData["ACT_UID"] : ''; $activityData["ACT_UID"] = Util\Common::generateUID(); $result[] = array( From 475d6baf5b3a1805b4e71ba47c4862dd46fb7c36 Mon Sep 17 00:00:00 2001 From: Roly Gutierrez Date: Mon, 16 Aug 2021 13:03:11 -0400 Subject: [PATCH 03/36] PMCORE-3173 The case details is not showed correctly --- workflow/engine/src/ProcessMaker/BusinessModel/Cases/Search.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow/engine/src/ProcessMaker/BusinessModel/Cases/Search.php b/workflow/engine/src/ProcessMaker/BusinessModel/Cases/Search.php index 2c3b4bf01..16f1cb16c 100644 --- a/workflow/engine/src/ProcessMaker/BusinessModel/Cases/Search.php +++ b/workflow/engine/src/ProcessMaker/BusinessModel/Cases/Search.php @@ -172,7 +172,7 @@ class Search extends AbstractCases switch ($status) { case 'DRAFT': case 'TO_DO': - $taskPending = Delegation::getPendingThreads($item['APP_NUMBER']); + $taskPending = Delegation::getPendingThreads($item['APP_NUMBER'], false); break; case 'COMPLETED': case 'CANCELLED': From 743d26a47edbc6dc9a0e4e4448eb77f1d3f166cf Mon Sep 17 00:00:00 2001 From: Rodrigo Quelca Date: Mon, 16 Aug 2021 19:05:45 +0000 Subject: [PATCH 04/36] PMCORE-3212: UI implement Error handling component --- .../customCaseList/CaseListSketch.vue | 87 +++++++++++++++---- .../translations/english/processmaker.en.po | 31 +++++++ workflow/engine/data/mysql/insert.sql | 5 ++ 3 files changed, 108 insertions(+), 15 deletions(-) diff --git a/resources/assets/js/admin/settings/customCaseList/CaseListSketch.vue b/resources/assets/js/admin/settings/customCaseList/CaseListSketch.vue index 741574867..9b2800fcb 100644 --- a/resources/assets/js/admin/settings/customCaseList/CaseListSketch.vue +++ b/resources/assets/js/admin/settings/customCaseList/CaseListSketch.vue @@ -237,17 +237,37 @@ :checked="props.row.selected" :value="props.row.field" /> - - +
+ + + + + + + + + + + + +
+
{ this.$emit("closeSketch"); - }) .catch((err) => { + this.makeToast('danger', this.$i18n.t('ID_ERROR'), err.response.statusText); console.error(err); }); } else { @@ -596,6 +639,7 @@ export default { }) .catch((err) => { + this.makeToast('danger',this.$i18n.t('ID_ERROR') ,err.response.statusText); console.error(err); }); } @@ -622,7 +666,20 @@ export default { onTongleFilter(field){ let objIndex = this.dataCaseList.findIndex((obj => obj.field === field)); this.dataCaseList[objIndex].enableFilter = !this.dataCaseList[objIndex].enableFilter - } + }, + /** + * Make the toast component + * @param {string} variant + * @param {string} title + * @param {string} message + */ + makeToast(variant = null, title, message) { + this.$bvToast.toast(message, { + title: `${title || variant}`, + variant: variant, + solid: true + }) + } }, }; diff --git a/workflow/engine/content/translations/english/processmaker.en.po b/workflow/engine/content/translations/english/processmaker.en.po index 0d0fd93de..ba3d16059 100755 --- a/workflow/engine/content/translations/english/processmaker.en.po +++ b/workflow/engine/content/translations/english/processmaker.en.po @@ -1693,6 +1693,18 @@ msgstr "You can open only files with the .html extension" msgid "3 days at least" msgstr "3 days at least" +# TRANSLATION +# LABEL/ID_A_RANGE_OF_VALUES +#: LABEL/ID_A_RANGE_OF_VALUES +msgid "a range of values" +msgstr "a range of values" + +# TRANSLATION +# LABEL/ID_A_TEXT_SEARCH +#: LABEL/ID_A_TEXT_SEARCH +msgid "a Text Search" +msgstr "a Text Search" + # TRANSLATION # LABEL/ID_ABE_ANSWER_SUBMITTED #: LABEL/ID_ABE_ANSWER_SUBMITTED @@ -5819,6 +5831,13 @@ msgstr "The value '{0}' is not a valid date for the format '{1}'." msgid "Date Created" msgstr "Date Created" + +# TRANSLATION +# LABEL/ID_DATE_TO_DATE +#: LABEL/ID_DATE_TO_DATE +msgid "Date to Date" +msgstr "Date to Date" + # TRANSLATION # LABEL/ID_DAY #: LABEL/ID_DAY @@ -20315,6 +20334,12 @@ msgstr "License installed successfully" msgid "No" msgstr "No" +# TRANSLATION +# LABEL/ID_NO_SEARCHING_METHOD +#: LABEL/ID_NO_SEARCHING_METHOD +msgid "No searching method" +msgstr "No searching method" + # TRANSLATION # LABEL/ID_NODELETEOPTIONALL #: LABEL/ID_NODELETEOPTIONALL @@ -26309,6 +26334,12 @@ msgstr "Please complete the reassign reason." msgid "The report table is regenerating please come back in a few minutes." msgstr "The report table is regenerating please come back in a few minutes." +# TRANSLATION +# LABEL/ID_THE_SEARCH_WILL_BE_FROM +#: LABEL/ID_THE_SEARCH_WILL_BE_FROM +msgid "The search will be from" +msgstr "The search will be from" + # TRANSLATION # LABEL/ID_THE_UPLOAD_OF_PHP_FILES_WAS_DISABLED #: LABEL/ID_THE_UPLOAD_OF_PHP_FILES_WAS_DISABLED diff --git a/workflow/engine/data/mysql/insert.sql b/workflow/engine/data/mysql/insert.sql index 4c09f2da4..99ab41996 100755 --- a/workflow/engine/data/mysql/insert.sql +++ b/workflow/engine/data/mysql/insert.sql @@ -57082,6 +57082,8 @@ INSERT INTO TRANSLATION (TRN_CATEGORY,TRN_ID,TRN_LANG,TRN_VALUE,TRN_UPDATE_DATE ( 'LABEL','ESTABLISHING_CON_HOST','en','Establishing connection to host','2014-01-15') , ( 'LABEL','HTML_FILES','en','You can open only files with the .html extension','2014-01-15') , ( 'LABEL','ID_3DAYSMINIMUM','en','3 days at least','2014-01-15') , +( 'LABEL','ID_A_RANGE_OF_VALUES','en','a range of values','2021-08-16') , +( 'LABEL','ID_A_TEXT_SEARCH','en','a Text Search','2021-08-16') , ( 'LABEL','ID_ABE_ANSWER_SUBMITTED','en','The answer has been submitted. Thank you.','2017-06-19') , ( 'LABEL','ID_ABE_CASE_NOTE_ANSWER','en','Answer: {optionLabel}','2018-11-20') , ( 'LABEL','ID_ABE_CASE_NOTE_COMMENT','en','Comment: {emailBody}','2018-11-20') , @@ -57793,6 +57795,7 @@ INSERT INTO TRANSLATION (TRN_CATEGORY,TRN_ID,TRN_LANG,TRN_VALUE,TRN_UPDATE_DATE ( 'LABEL','ID_DATE_LABEL','en','Date','2014-01-15') , ( 'LABEL','ID_DATE_NOT_VALID','en','The value ''{0}'' is not a valid date for the format ''{1}''.','2014-05-29') , ( 'LABEL','ID_DATE_UPDATED','en','Date Updated','2021-07-26') , +( 'LABEL','ID_DATE_TO_DATE','en','Date to Date','2021-07-26') , ( 'LABEL','ID_DAY','en','Day','2014-01-15') , ( 'LABEL','ID_DAYS','en','Days','2014-01-15') , ( 'LABEL','ID_DAY_DAYS','en','Day(s)','2020-10-02') , @@ -60276,6 +60279,7 @@ INSERT INTO TRANSLATION (TRN_CATEGORY,TRN_ID,TRN_LANG,TRN_VALUE,TRN_UPDATE_DATE ( 'LABEL','ID_NEXT_TASK','en','Next Task/Event','2016-07-29') , ( 'LABEL','ID_NLIC','en','License installed successfully','2014-12-02') , ( 'LABEL','ID_NO','en','No','2014-01-15') , +( 'LABEL','ID_NO_SEARCHING_METHOD','en','No searching method','2021-08-16') , ( 'LABEL','ID_NODELETEOPTIONALL','en','You must add all the days that you have selected in work days, otherwise you should leave at least an "-- ALL --" option.','2014-01-15') , ( 'LABEL','ID_NONE','en','None','2014-01-15') , ( 'LABEL','ID_NONEC','en','@# Replace the value with no change','2014-01-15') , @@ -61340,6 +61344,7 @@ INSERT INTO TRANSLATION (TRN_CATEGORY,TRN_ID,TRN_LANG,TRN_VALUE,TRN_UPDATE_DATE ( 'LABEL','ID_THE_PHP_FILES_EXECUTION_WAS_DISABLED','en','The PHP files execution was disabled please contact the system administrator.','2018-04-20') , ( 'LABEL','ID_THE_REASON_REASSIGN_USER_EMPTY','en','Please complete the reassign reason.','2016-10-20') , ( 'LABEL','ID_THE_REPORT_TABLE_IS_REGENERATING_PLEASE_COME_BACK_IN_A_FEW_MINUTES','en','The report table is regenerating please come back in a few minutes.','2020-06-01') , +( 'LABEL','ID_THE_SEARCH_WILL_BE_FROM','en','The search will be from','2021-08-16') , ( 'LABEL','ID_THE_UPLOAD_OF_PHP_FILES_WAS_DISABLED','en','The upload of PHP files was disabled please contact the system administrator.','2018-04-20') , ( 'LABEL','ID_THE_USER_ROLES_FOR_ATTRIBUTE_HAS_BEEN_DELETED_PLEASE_CONFIRM','en','The user roles for attribute {0} has been modified, if you proceed to save this attribute, all information for users stored in the attribute will be deleted for the removed role, please confirm.','2020-12-15') , ( 'LABEL','ID_THE_USERNAME_EMAIL_IS_INCORRECT','en','The username or email is incorrect','2018-01-18') , From 393871d73edd9afdcc04b47b46175eeda1813932 Mon Sep 17 00:00:00 2001 From: Rodrigo Quelca Date: Tue, 17 Aug 2021 21:48:08 +0000 Subject: [PATCH 05/36] PMCORE-3224: Enable custom sidebar --- .../components/menu/CustomSidebarMenuItem.vue | 25 +++++++++++---- .../js/components/utils/CustomTooltip.vue | 7 ++-- resources/assets/js/home/Home.vue | 32 +++++++++++++++++++ .../src/ProcessMaker/Services/Api/Home.php | 14 ++------ 4 files changed, 58 insertions(+), 20 deletions(-) diff --git a/resources/assets/js/components/menu/CustomSidebarMenuItem.vue b/resources/assets/js/components/menu/CustomSidebarMenuItem.vue index 1f9f49ba9..d3e2ec8d9 100644 --- a/resources/assets/js/components/menu/CustomSidebarMenuItem.vue +++ b/resources/assets/js/components/menu/CustomSidebarMenuItem.vue @@ -6,7 +6,7 @@ :class="item.class" v-bind="item.attributes" > - {{ item.title }} + {{ item.title }}
-
0); }, isItemHidden() { - return false; + if (this.isCollapsed) { + if (this.item.hidden && this.item.hiddenOnCollapse === undefined) { + return true + } else { + return this.item.hiddenOnCollapse === true + } + } else { + return this.item.hidden === true + } }, }, watch: { @@ -374,7 +381,6 @@ export default { */ initState() { this.initActiveState(); - this.initShowState(); }, /** * Initalize the active state of the menu item @@ -427,6 +433,7 @@ export default { * @param {object} event */ mouseOverEvent(event) { + console.log("over"); if (this.item.disabled) return; event.stopPropagation(); this.itemHover = true; @@ -439,6 +446,7 @@ export default { * @param {object} event */ mouseOutEvent(event) { + event.stopPropagation(); this.itemHover = false; }, @@ -454,6 +462,7 @@ export default { * @param {object} el */ expandAfterEnter(el) { + console.log("ebnter"); el.style.height = "auto"; }, /** @@ -473,16 +482,18 @@ export default { * @param {object} itemEl */ emitMobileItem(event, itemEl) { + debugger; if (this.hover) return; if (!this.isCollapsed || !this.isFirstLevel || this.isMobileItem) return; this.$emit("unset-mobile-item", true); setTimeout(() => { - if (this.mobileItem !== this.item) { - this.$emit("set-mobile-item", { item: this.item, itemEl }); + + if (this.$parent.mobileItem !== this.item) { + this.$parent.$emit("set-mobile-item", { item: this.item, itemEl }); } if (event.type === "click" && !this.itemHasChild) { - this.$emit("unset-mobile-item", false); + this.$parent.$emit("unset-mobile-item", false); } }, 0); }, diff --git a/resources/assets/js/components/utils/CustomTooltip.vue b/resources/assets/js/components/utils/CustomTooltip.vue index 670ec7c37..3a5708836 100644 --- a/resources/assets/js/components/utils/CustomTooltip.vue +++ b/resources/assets/js/components/utils/CustomTooltip.vue @@ -1,6 +1,6 @@ diff --git a/workflow/engine/src/ProcessMaker/Model/UserConfig.php b/workflow/engine/src/ProcessMaker/Model/UserConfig.php index c76a8339d..1977f07f8 100644 --- a/workflow/engine/src/ProcessMaker/Model/UserConfig.php +++ b/workflow/engine/src/ProcessMaker/Model/UserConfig.php @@ -53,7 +53,7 @@ class UserConfig extends Model $model = new UserConfig(); $model->USR_ID = $id; $model->USC_NAME = $name; - $model->USC_SETTING = json_encode($setting, JSON_FORCE_OBJECT); + $model->USC_SETTING = json_encode($setting); $model->save(); $userConfig = UserConfig::getSetting($id, $name); return $userConfig; From dfd7588dcb68b6d630789e63f2d8b85552e5cd5c Mon Sep 17 00:00:00 2001 From: Rodrigo Quelca Date: Fri, 20 Aug 2021 04:08:57 +0000 Subject: [PATCH 15/36] update inbox scree --- .../js/components/utils/CustomTooltip.vue | 3 +- resources/assets/js/home/Home.vue | 10 +- resources/assets/js/home/Inbox/Todo.vue | 731 ------------------ 3 files changed, 7 insertions(+), 737 deletions(-) delete mode 100644 resources/assets/js/home/Inbox/Todo.vue diff --git a/resources/assets/js/components/utils/CustomTooltip.vue b/resources/assets/js/components/utils/CustomTooltip.vue index 05f85d0db..f653bc30f 100644 --- a/resources/assets/js/components/utils/CustomTooltip.vue +++ b/resources/assets/js/components/utils/CustomTooltip.vue @@ -54,7 +54,8 @@ export default { */ setTooltip() { let that = this; - api.menu.getTooltip(that.menuMap[that.data.id]).then((response) => { + debugger; + api.menu.getTooltip(that.data.id).then((response) => { let key = `tooltip-${that.data.id}`; that.labelTooltip = response.data.label; that.$refs[key].$emit("open"); diff --git a/resources/assets/js/home/Home.vue b/resources/assets/js/home/Home.vue index e9de04800..26b578a4d 100644 --- a/resources/assets/js/home/Home.vue +++ b/resources/assets/js/home/Home.vue @@ -43,7 +43,7 @@ import CustomSidebar from "./../components/menu/CustomSidebar"; import CustomSidebarMenuItem from "./../components/menu/CustomSidebarMenuItem"; import MyCases from "./MyCases/MyCases.vue"; import MyDocuments from "./MyDocuments"; -import Todo from "./Inbox/Todo.vue"; +import Inbox from "./Inbox/Inbox.vue"; import Paused from "./Paused/Paused.vue"; import Draft from "./Draft/Draft.vue"; import Unassigned from "./Unassigned/Unassigned.vue"; @@ -66,7 +66,7 @@ export default { BatchRouting, TaskReassignments, XCase, - Todo, + Inbox, Draft, Paused, Unassigned, @@ -97,7 +97,7 @@ export default { CASES_MY_CASES: "MyCases", CASES_SENT: "MyCases", CASES_SEARCH: "advanced-search", - CASES_INBOX: "todo", + CASES_INBOX: "inbox", CASES_DRAFT: "draft", CASES_PAUSED: "paused", CASES_SELFSERVICE: "unassigned", @@ -138,7 +138,7 @@ export default { eventer(messageEvent, function(e) { if ( e.data === "redirect=todo" || e.message === "redirect=todo"){ - that.page = "todo"; + that.page = "inbox"; } if ( e.data === "update=debugger" || e.message === "update=debugger"){ if(that.$refs["component"].updateView){ @@ -267,7 +267,7 @@ export default { } } } - if (data[i].id === "todo" || data[i].id === "draft" + if (data[i].id === "inbox" || data[i].id === "draft" || data[i].id === "paused" || data[i].id === "unassigned") { data[i]["child"] = this.sortCustomCasesList(data[i].customCasesList, this.config.setting[this.page] && this.config.setting[this.page].customCasesList ? this.config.setting[this.page].customCasesList: []) data[i]["sortable"] = data[i].customCasesList.length > 1; diff --git a/resources/assets/js/home/Inbox/Todo.vue b/resources/assets/js/home/Inbox/Todo.vue deleted file mode 100644 index 76b7dab93..000000000 --- a/resources/assets/js/home/Inbox/Todo.vue +++ /dev/null @@ -1,731 +0,0 @@ - - - - \ No newline at end of file From 9e1ee91a97d59533b3190913745ddf60b3b15a94 Mon Sep 17 00:00:00 2001 From: Rodrigo Quelca Date: Fri, 20 Aug 2021 04:10:55 +0000 Subject: [PATCH 16/36] add missed files --- resources/assets/js/home/EventBus/eventBus.js | 4 + resources/assets/js/home/Inbox/Inbox.vue | 731 ++++++++++++++++++ 2 files changed, 735 insertions(+) create mode 100644 resources/assets/js/home/EventBus/eventBus.js create mode 100644 resources/assets/js/home/Inbox/Inbox.vue diff --git a/resources/assets/js/home/EventBus/eventBus.js b/resources/assets/js/home/EventBus/eventBus.js new file mode 100644 index 000000000..20eecd8c8 --- /dev/null +++ b/resources/assets/js/home/EventBus/eventBus.js @@ -0,0 +1,4 @@ +import Vue from 'vue' +const eventBus = new Vue() + +export default eventBus \ No newline at end of file diff --git a/resources/assets/js/home/Inbox/Inbox.vue b/resources/assets/js/home/Inbox/Inbox.vue new file mode 100644 index 000000000..07eaee8e4 --- /dev/null +++ b/resources/assets/js/home/Inbox/Inbox.vue @@ -0,0 +1,731 @@ + + + + \ No newline at end of file From 4985d3a7882b7412f468a7d93144785b94119494 Mon Sep 17 00:00:00 2001 From: Rodrigo Quelca Date: Fri, 20 Aug 2021 04:16:37 +0000 Subject: [PATCH 17/36] add comments --- .../components/menu/CustomSidebarMenuItem.vue | 38 ++++++++++++------- resources/assets/js/home/Home.vue | 11 ++++++ 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/resources/assets/js/components/menu/CustomSidebarMenuItem.vue b/resources/assets/js/components/menu/CustomSidebarMenuItem.vue index d50054e9a..4a937b359 100644 --- a/resources/assets/js/components/menu/CustomSidebarMenuItem.vue +++ b/resources/assets/js/components/menu/CustomSidebarMenuItem.vue @@ -6,7 +6,11 @@ :class="item.class" v-bind="item.attributes" > - {{ item.title }} + {{ item.title }} +
{ if (this.$parent.mobileItem !== this.item) { - this.$parent.$emit("set-mobile-item", { item: this.item, itemEl }); + this.$parent.$emit("set-mobile-item", { + item: this.item, + itemEl, + }); } if (event.type === "click" && !this.itemHasChild) { this.$parent.$emit("unset-mobile-item", false); diff --git a/resources/assets/js/home/Home.vue b/resources/assets/js/home/Home.vue index 26b578a4d..f77256ed2 100644 --- a/resources/assets/js/home/Home.vue +++ b/resources/assets/js/home/Home.vue @@ -283,6 +283,12 @@ export default { } return newData; }, + /** + * Sort the custom case list menu items + * @param {array} list + * @param {array} ref + * @returns {array} + */ sortCustomCasesList(list, ref) { let item, newList = [], @@ -301,6 +307,11 @@ export default { return [...newList, ...temp]; }, + /** + * Util to compare an oobject by id + * @param {array} otherArray + * @returns {object} + */ comparerById(otherArray){ return function(current){ return otherArray.filter(function(other){ From 4d40c112652743259c8b77a5480e6865b67829c9 Mon Sep 17 00:00:00 2001 From: Rodrigo Quelca Date: Fri, 20 Aug 2021 04:18:00 +0000 Subject: [PATCH 18/36] fix comments --- resources/assets/js/home/Home.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/assets/js/home/Home.vue b/resources/assets/js/home/Home.vue index f77256ed2..c87f572f8 100644 --- a/resources/assets/js/home/Home.vue +++ b/resources/assets/js/home/Home.vue @@ -308,7 +308,7 @@ export default { }, /** - * Util to compare an oobject by id + * Util to compare an array by id * @param {array} otherArray * @returns {object} */ From 0c33badff7c7680d4bf167e1e725d9ffd101e582 Mon Sep 17 00:00:00 2001 From: Roly Gutierrez Date: Fri, 20 Aug 2021 08:06:13 -0400 Subject: [PATCH 19/36] PMCORE-3232 Service /api/1.0/workflow/home/config/1/test return 400 if there is not this setting --- workflow/engine/src/ProcessMaker/Model/UserConfig.php | 6 +++++- workflow/engine/src/ProcessMaker/Services/Api/Home.php | 5 ++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/workflow/engine/src/ProcessMaker/Model/UserConfig.php b/workflow/engine/src/ProcessMaker/Model/UserConfig.php index 1977f07f8..5d383048d 100644 --- a/workflow/engine/src/ProcessMaker/Model/UserConfig.php +++ b/workflow/engine/src/ProcessMaker/Model/UserConfig.php @@ -34,10 +34,14 @@ class UserConfig extends Model if (empty($userConfig)) { return null; } + $setting = json_decode($userConfig->USC_SETTING); + if (empty($setting)) { + $setting = new stdClass(); + } return [ "id" => $userConfig->USR_ID, "name" => $userConfig->USC_NAME, - "setting" => json_decode($userConfig->USC_SETTING) + "setting" => $setting ]; } diff --git a/workflow/engine/src/ProcessMaker/Services/Api/Home.php b/workflow/engine/src/ProcessMaker/Services/Api/Home.php index e2c87f706..f584de9c7 100644 --- a/workflow/engine/src/ProcessMaker/Services/Api/Home.php +++ b/workflow/engine/src/ProcessMaker/Services/Api/Home.php @@ -904,7 +904,10 @@ class Home extends Api { $setting = UserConfig::getSetting($id, $name); if (is_null($setting)) { - throw new RestException(Api::STAT_APP_EXCEPTION, G::LoadTranslation('ID_DOES_NOT_EXIST')); + $setting = [ + "status" => 404, + "message" => G::LoadTranslation('ID_DOES_NOT_EXIST') + ]; } return $setting; } From 9f00e42dcca05396de50b2f414247cdc7cdb160c Mon Sep 17 00:00:00 2001 From: Rodrigo Quelca Date: Fri, 20 Aug 2021 13:39:35 +0000 Subject: [PATCH 20/36] remove debugger --- resources/assets/js/components/utils/CustomTooltip.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/resources/assets/js/components/utils/CustomTooltip.vue b/resources/assets/js/components/utils/CustomTooltip.vue index f653bc30f..abb42dd3d 100644 --- a/resources/assets/js/components/utils/CustomTooltip.vue +++ b/resources/assets/js/components/utils/CustomTooltip.vue @@ -54,7 +54,6 @@ export default { */ setTooltip() { let that = this; - debugger; api.menu.getTooltip(that.data.id).then((response) => { let key = `tooltip-${that.data.id}`; that.labelTooltip = response.data.label; From 20de2f3649be1c1cb882763405b0d139a255726a Mon Sep 17 00:00:00 2001 From: Rodrigo Quelca Date: Fri, 20 Aug 2021 15:33:39 +0000 Subject: [PATCH 21/36] PMCORE-3235: Sectional icon must change dinamically in the my cases panel --- .../js/components/vuetable/extends/VtSortControl.vue | 9 +++++---- resources/assets/js/home/main.js | 3 --- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/resources/assets/js/components/vuetable/extends/VtSortControl.vue b/resources/assets/js/components/vuetable/extends/VtSortControl.vue index ad6f47149..56dbb49e7 100644 --- a/resources/assets/js/components/vuetable/extends/VtSortControl.vue +++ b/resources/assets/js/components/vuetable/extends/VtSortControl.vue @@ -1,5 +1,6 @@ \ No newline at end of file diff --git a/resources/assets/js/home/main.js b/resources/assets/js/home/main.js index e1ace4103..0b578cafb 100644 --- a/resources/assets/js/home/main.js +++ b/resources/assets/js/home/main.js @@ -9,12 +9,10 @@ import VtSortControl from './../components/vuetable/extends/VtSortControl'; import SettingsPopover from "../components/vuetable/SettingsPopover.vue"; import Sortable from 'sortablejs'; import "@fortawesome/fontawesome-free/css/all.css"; -import "@fortawesome/fontawesome-free/js/all.js"; import 'bootstrap/dist/css/bootstrap-grid.css'; import 'bootstrap/dist/css/bootstrap.min.css' import 'bootstrap-vue/dist/bootstrap-vue.css' -import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'; import Home from "./Home"; Vue.use(VueRouter); @@ -22,7 +20,6 @@ Vue.use(VueSidebarMenu); Vue.use(BootstrapVue); Vue.use(BootstrapVueIcons); Vue.use(VueI18n); -Vue.component('font-awesome-icon', FontAwesomeIcon); Vue.use(ServerTable, {}, false, 'bootstrap3', { tableHeading: VtTableHeadingCustom, From d7bedf099d9263c28b2f07edb52eaddb74582364 Mon Sep 17 00:00:00 2001 From: Rodrigo Quelca Date: Fri, 20 Aug 2021 15:35:31 +0000 Subject: [PATCH 22/36] code style --- .../vuetable/extends/VtSortControl.vue | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/resources/assets/js/components/vuetable/extends/VtSortControl.vue b/resources/assets/js/components/vuetable/extends/VtSortControl.vue index 56dbb49e7..89a864af5 100644 --- a/resources/assets/js/components/vuetable/extends/VtSortControl.vue +++ b/resources/assets/js/components/vuetable/extends/VtSortControl.vue @@ -1,18 +1,19 @@ \ No newline at end of file +export default { + name: "VtSortControl", + props: ["props"], + computed: { + icon() { + // if not sorted return base icon + if (!this.props.sortStatus.sorted) return "fas fa-sort"; + // return sort direction icon + return this.props.sortStatus.asc + ? "fas fa-sort-amount-up" + : "fas fa-sort-amount-down"; + }, + }, +}; + From b23acbffc9805a3686fbdb224fe5dcc97bd29edf Mon Sep 17 00:00:00 2001 From: Rodrigo Quelca Date: Fri, 20 Aug 2021 15:49:08 +0000 Subject: [PATCH 23/36] remove font awesome js tools --- resources/assets/js/home/main.js | 1 - resources/assets/sass/menu.scss | 1 - 2 files changed, 2 deletions(-) diff --git a/resources/assets/js/home/main.js b/resources/assets/js/home/main.js index 0b578cafb..1f35d38a2 100644 --- a/resources/assets/js/home/main.js +++ b/resources/assets/js/home/main.js @@ -13,7 +13,6 @@ import 'bootstrap/dist/css/bootstrap-grid.css'; import 'bootstrap/dist/css/bootstrap.min.css' import 'bootstrap-vue/dist/bootstrap-vue.css' - import Home from "./Home"; Vue.use(VueRouter); Vue.use(VueSidebarMenu); diff --git a/resources/assets/sass/menu.scss b/resources/assets/sass/menu.scss index 752ff9598..badd7792d 100755 --- a/resources/assets/sass/menu.scss +++ b/resources/assets/sass/menu.scss @@ -76,7 +76,6 @@ width: 30px; text-align: center; border-radius: 3px; - margin-top: 8px; margin-right: 0px; margin-left: 10px; } From 3c09f703b97888ae847b2ac8402f45e400ca3c86 Mon Sep 17 00:00:00 2001 From: Rodrigo Quelca Date: Fri, 20 Aug 2021 16:09:30 +0000 Subject: [PATCH 24/36] fix sort menu --- resources/assets/js/home/Home.vue | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/resources/assets/js/home/Home.vue b/resources/assets/js/home/Home.vue index c87f572f8..25ad73215 100644 --- a/resources/assets/js/home/Home.vue +++ b/resources/assets/js/home/Home.vue @@ -111,7 +111,6 @@ export default { mounted() { let that = this; this.onResize(); - this.getMenu(); this.getUserSettings(); this.listenerIframe(); window.setInterval( @@ -176,7 +175,9 @@ export default { this.createUserSettings(); } else if (response.data) { this.config = response.data; + this.getMenu(); } + }) .catch((e) => { console.error(e); @@ -269,7 +270,13 @@ export default { } if (data[i].id === "inbox" || data[i].id === "draft" || data[i].id === "paused" || data[i].id === "unassigned") { - data[i]["child"] = this.sortCustomCasesList(data[i].customCasesList, this.config.setting[this.page] && this.config.setting[this.page].customCasesList ? this.config.setting[this.page].customCasesList: []) + data[i]["child"] = this.sortCustomCasesList( + data[i].customCasesList, + this.config.setting[this.page] && + this.config.setting[this.page].customCasesList + ? this.config.setting[this.page].customCasesList + : [] + ); data[i]["sortable"] = data[i].customCasesList.length > 1; data[i]["sortIcon"] = "gear-fill"; data[i] = { From 7e306ecc2d194bbf3bd030a3fbeb50013aff6046 Mon Sep 17 00:00:00 2001 From: Rodrigo Quelca Date: Fri, 20 Aug 2021 16:10:40 +0000 Subject: [PATCH 25/36] fix sort --- resources/assets/js/home/Home.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/resources/assets/js/home/Home.vue b/resources/assets/js/home/Home.vue index 25ad73215..42f3a47cf 100644 --- a/resources/assets/js/home/Home.vue +++ b/resources/assets/js/home/Home.vue @@ -177,7 +177,6 @@ export default { this.config = response.data; this.getMenu(); } - }) .catch((e) => { console.error(e); From 6907587402375471f330af98d2e04755cb1a8ffa Mon Sep 17 00:00:00 2001 From: Andrea Adamczyk Date: Thu, 19 Aug 2021 16:36:29 -0400 Subject: [PATCH 26/36] PMCORE-3136 --- .../BusinessModel/Cases/DraftTest.php | 114 ++++++++++ .../BusinessModel/Cases/InboxTest.php | 96 ++++++++ .../BusinessModel/Cases/PausedTest.php | 213 ++++++++++++++++++ .../BusinessModel/Cases/UnassignedTest.php | 147 ++++++++++++ .../src/ProcessMaker/Model/DelegationTest.php | 24 +- .../BusinessModel/Cases/AbstractCases.php | 74 ++++++ .../src/ProcessMaker/Model/Delegation.php | 4 +- .../src/ProcessMaker/Services/Api/Metrics.php | 42 ++++ 8 files changed, 710 insertions(+), 4 deletions(-) diff --git a/tests/unit/workflow/engine/src/ProcessMaker/BusinessModel/Cases/DraftTest.php b/tests/unit/workflow/engine/src/ProcessMaker/BusinessModel/Cases/DraftTest.php index 8b60300ab..6c7931c4c 100644 --- a/tests/unit/workflow/engine/src/ProcessMaker/BusinessModel/Cases/DraftTest.php +++ b/tests/unit/workflow/engine/src/ProcessMaker/BusinessModel/Cases/DraftTest.php @@ -2,6 +2,8 @@ namespace Tests\unit\workflow\engine\src\ProcessMaker\BusinessModel\Cases; +use DateInterval; +use Datetime; use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Support\Facades\DB; use ProcessMaker\BusinessModel\Cases\Draft; @@ -766,4 +768,116 @@ class DraftTest extends TestCase $this->assertEquals($additionalTables->ADD_TAB_NAME, $res['tableName']); $this->assertEquals(3, $res['total']); } + + /** + * This tests the getCasesRisk() method with on time filter + * + * @covers \ProcessMaker\BusinessModel\Cases\Draft::getCasesRisk() + * @test + */ + public function it_tests_get_cases_risk_on_time() + { + $date = new DateTime('now'); + $currentDate = $date->format('Y-m-d H:i:s'); + $diff1Day = new DateInterval('P1D'); + $diff2Days = new DateInterval('P2D'); + $process = factory(Process::class)->create(); + $user = factory(User::class)->create(); + $application = factory(Application::class, 14)->states('draft')->create([ + 'APP_INIT_USER' => $user->USR_UID, + 'APP_CUR_USER' => $user->USR_UID, + ]); + factory(Delegation::class)->states('foreign_keys')->create([ + 'DEL_THREAD_STATUS' => 'OPEN', + 'DEL_INDEX' => 1, + 'USR_UID' => $application[0]->APP_INIT_USER, + 'USR_ID' => $user->USR_ID, + 'APP_UID' => $application[0]->APP_UID, + 'APP_NUMBER' => $application[0]->APP_NUMBER, + 'PRO_ID' => $process->PRO_ID, + 'PRO_UID' => $process->PRO_UID, + 'DEL_DELEGATE_DATE' => $currentDate, + 'DEL_RISK_DATE' => $date->add($diff1Day), + 'DEL_TASK_DUE_DATE' => $date->add($diff2Days) + ]); + $draft = new Draft(); + $draft->setUserId($user->USR_ID); + $draft->setUserUid($user->USR_ID); + $res = $draft->getCasesRisk($process->PRO_ID); + $this->assertCount(1, $res); + } + + /** + * This tests the getCasesRisk() method with at risk filter + * + * @covers \ProcessMaker\BusinessModel\Cases\Draft::getCasesRisk() + * @test + */ + public function it_tests_get_cases_risk_at_risk() + { + $date = new DateTime('now'); + $currentDate = $date->format('Y-m-d H:i:s'); + $diff2Days = new DateInterval('P2D'); + $process = factory(Process::class)->create(); + $user = factory(User::class)->create(); + $application = factory(Application::class, 14)->states('draft')->create([ + 'APP_INIT_USER' => $user->USR_UID, + 'APP_CUR_USER' => $user->USR_UID, + ]); + factory(Delegation::class)->states('foreign_keys')->create([ + 'DEL_THREAD_STATUS' => 'OPEN', + 'DEL_INDEX' => 1, + 'USR_UID' => $application[0]->APP_INIT_USER, + 'USR_ID' => $user->USR_ID, + 'APP_UID' => $application[0]->APP_UID, + 'APP_NUMBER' => $application[0]->APP_NUMBER, + 'PRO_ID' => $process->PRO_ID, + 'PRO_UID' => $process->PRO_UID, + 'DEL_DELEGATE_DATE' => $currentDate, + 'DEL_RISK_DATE' => $currentDate, + 'DEL_TASK_DUE_DATE' => $date->add($diff2Days) + ]); + $draft = new Draft(); + $draft->setUserId($user->USR_ID); + $draft->setUserUid($user->USR_ID); + $res = $draft->getCasesRisk($process->PRO_ID, null, null, 'AT_RISK'); + $this->assertCount(1, $res); + } + + /** + * This tests the getCasesRisk() method with overdue filter + * + * @covers \ProcessMaker\BusinessModel\Cases\Draft::getCasesRisk() + * @test + */ + public function it_tests_get_cases_risk_overdue() + { + $date = new DateTime('now'); + $currentDate = $date->format('Y-m-d H:i:s'); + $diff2Days = new DateInterval('P2D'); + $process = factory(Process::class)->create(); + $user = factory(User::class)->create(); + $application = factory(Application::class, 14)->states('draft')->create([ + 'APP_INIT_USER' => $user->USR_UID, + 'APP_CUR_USER' => $user->USR_UID, + ]); + factory(Delegation::class)->states('foreign_keys')->create([ + 'DEL_THREAD_STATUS' => 'OPEN', + 'DEL_INDEX' => 1, + 'USR_UID' => $application[0]->APP_INIT_USER, + 'USR_ID' => $user->USR_ID, + 'APP_UID' => $application[0]->APP_UID, + 'APP_NUMBER' => $application[0]->APP_NUMBER, + 'PRO_ID' => $process->PRO_ID, + 'PRO_UID' => $process->PRO_UID, + 'DEL_DELEGATE_DATE' => $currentDate, + 'DEL_RISK_DATE' => $currentDate, + 'DEL_TASK_DUE_DATE' => $date->sub($diff2Days) + ]); + $draft = new Draft(); + $draft->setUserId($user->USR_ID); + $draft->setUserUid($user->USR_ID); + $res = $draft->getCasesRisk($process->PRO_ID, null, null, 'OVERDUE'); + $this->assertCount(1, $res); + } } diff --git a/tests/unit/workflow/engine/src/ProcessMaker/BusinessModel/Cases/InboxTest.php b/tests/unit/workflow/engine/src/ProcessMaker/BusinessModel/Cases/InboxTest.php index 84fe7cd68..6cf613c60 100644 --- a/tests/unit/workflow/engine/src/ProcessMaker/BusinessModel/Cases/InboxTest.php +++ b/tests/unit/workflow/engine/src/ProcessMaker/BusinessModel/Cases/InboxTest.php @@ -2,6 +2,8 @@ namespace Tests\unit\workflow\engine\src\ProcessMaker\BusinessModel\Cases; +use DateInterval; +use Datetime; use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Support\Facades\DB; use ProcessMaker\BusinessModel\Cases\Inbox; @@ -659,4 +661,98 @@ class InboxTest extends TestCase $this->assertEquals($additionalTables->ADD_TAB_NAME, $res['tableName']); $this->assertEquals(3, $res['total']); } + + /** + * This tests the getCasesRisk() method with on time filter + * + * @covers \ProcessMaker\BusinessModel\Cases\Inbox::getCasesRisk() + * @test + */ + public function it_tests_get_cases_risk_on_time() + { + $date = new DateTime('now'); + $currentDate = $date->format('Y-m-d H:i:s'); + $diff1Day = new DateInterval('P1D'); + $diff2Days = new DateInterval('P2D'); + $user = factory(User::class)->create(); + $process = factory(Process::class)->create(); + factory(Delegation::class)->states('foreign_keys')->create([ + 'DEL_THREAD_STATUS' => 'OPEN', + 'DEL_INDEX' => 2, + 'USR_UID' => $user->USR_UID, + 'USR_ID' => $user->USR_ID, + 'PRO_ID' => $process->PRO_ID, + 'PRO_UID' => $process->PRO_UID, + 'DEL_DELEGATE_DATE' => $currentDate, + 'DEL_RISK_DATE' => $date->add($diff1Day), + 'DEL_TASK_DUE_DATE' => $date->add($diff2Days) + ]); + $inbox = new Inbox(); + $inbox->setUserId($user->USR_ID); + $inbox->setUserUid($user->USR_UID); + $res = $inbox->getCasesRisk($process->PRO_ID); + $this->assertCount(1, $res); + } + + /** + * This tests the getCasesRisk() method with at risk filter + * + * @covers \ProcessMaker\BusinessModel\Cases\Inbox::getCasesRisk() + * @test + */ + public function it_tests_get_cases_risk_at_risk() + { + $date = new DateTime('now'); + $currentDate = $date->format('Y-m-d H:i:s'); + $diff2Days = new DateInterval('P2D'); + $user = factory(User::class)->create(); + $process = factory(Process::class)->create(); + factory(Delegation::class)->states('foreign_keys')->create([ + 'DEL_THREAD_STATUS' => 'OPEN', + 'DEL_INDEX' => 2, + 'USR_UID' => $user->USR_UID, + 'USR_ID' => $user->USR_ID, + 'PRO_ID' => $process->PRO_ID, + 'PRO_UID' => $process->PRO_UID, + 'DEL_DELEGATE_DATE' => $currentDate, + 'DEL_RISK_DATE' => $currentDate, + 'DEL_TASK_DUE_DATE' => $date->add($diff2Days) + ]); + $inbox = new Inbox(); + $inbox->setUserId($user->USR_ID); + $inbox->setUserUid($user->USR_UID); + $res = $inbox->getCasesRisk($process->PRO_ID, null, null, "AT_RISK"); + $this->assertCount(1, $res); + } + + /** + * This tests the getCasesRisk() method with overdue filter + * + * @covers \ProcessMaker\BusinessModel\Cases\Inbox::getCasesRisk() + * @test + */ + public function it_tests_get_cases_risk_overdue() + { + $date = new DateTime('now'); + $currentDate = $date->format('Y-m-d H:i:s'); + $diff2Days = new DateInterval('P2D'); + $user = factory(User::class)->create(); + $process = factory(Process::class)->create(); + factory(Delegation::class)->states('foreign_keys')->create([ + 'DEL_THREAD_STATUS' => 'OPEN', + 'DEL_INDEX' => 2, + 'USR_UID' => $user->USR_UID, + 'USR_ID' => $user->USR_ID, + 'PRO_ID' => $process->PRO_ID, + 'PRO_UID' => $process->PRO_UID, + 'DEL_DELEGATE_DATE' => $currentDate, + 'DEL_RISK_DATE' => $currentDate, + 'DEL_TASK_DUE_DATE' => $date->sub($diff2Days) + ]); + $inbox = new Inbox(); + $inbox->setUserId($user->USR_ID); + $inbox->setUserUid($user->USR_UID); + $res = $inbox->getCasesRisk($process->PRO_ID, null, null, "OVERDUE"); + $this->assertCount(1, $res); + } } diff --git a/tests/unit/workflow/engine/src/ProcessMaker/BusinessModel/Cases/PausedTest.php b/tests/unit/workflow/engine/src/ProcessMaker/BusinessModel/Cases/PausedTest.php index 65f05310c..80456429e 100644 --- a/tests/unit/workflow/engine/src/ProcessMaker/BusinessModel/Cases/PausedTest.php +++ b/tests/unit/workflow/engine/src/ProcessMaker/BusinessModel/Cases/PausedTest.php @@ -2,6 +2,8 @@ namespace Tests\unit\workflow\engine\src\ProcessMaker\BusinessModel\Cases; +use DateInterval; +use Datetime; use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Support\Facades\DB; use ProcessMaker\BusinessModel\Cases\Paused; @@ -653,4 +655,215 @@ class PausedTest extends TestCase $this->assertEquals($additionalTables->ADD_TAB_NAME, $res['tableName']); $this->assertEquals(3, $res['total']); } + + /** + * It tests the getCasesRisk() method with the ontime filter + * + * @covers \ProcessMaker\BusinessModel\Cases\Paused::getCasesRisk() + * @test + */ + public function it_should_test_get_cases_risk_on_time() + { + $date = new DateTime('now'); + $currentDate = $date->format('Y-m-d H:i:s'); + $diff1Day = new DateInterval('P1D'); + $diff2Days = new DateInterval('P2D'); + $user = factory(User::class)->create(); + $process1 = factory(Process::class)->create(); + + $task = factory(Task::class)->create([ + 'TAS_ASSIGN_TYPE' => '', + 'TAS_GROUP_VARIABLE' => '', + 'PRO_UID' => $process1->PRO_UID, + 'TAS_TYPE' => 'NORMAL' + ]); + + $application1 = factory(Application::class)->create(); + + factory(Delegation::class)->create([ + 'APP_UID' => $application1->APP_UID, + 'APP_NUMBER' => $application1->APP_NUMBER, + 'TAS_ID' => $task->TAS_ID, + 'DEL_THREAD_STATUS' => 'CLOSED', + 'USR_UID' => $user->USR_UID, + 'USR_ID' => $user->USR_ID, + 'PRO_ID' => $process1->PRO_ID, + 'PRO_UID' => $process1->PRO_UID, + 'DEL_PREVIOUS' => 0, + 'DEL_INDEX' => 1, + 'DEL_DELEGATE_DATE' => $currentDate, + 'DEL_RISK_DATE' => $date->add($diff1Day), + 'DEL_TASK_DUE_DATE' => $date->add($diff2Days) + ]); + $delegation1 = factory(Delegation::class)->create([ + 'APP_UID' => $application1->APP_UID, + 'APP_NUMBER' => $application1->APP_NUMBER, + 'TAS_ID' => $task->TAS_ID, + 'DEL_THREAD_STATUS' => 'OPEN', + 'USR_UID' => $user->USR_UID, + 'USR_ID' => $user->USR_ID, + 'PRO_ID' => $process1->PRO_ID, + 'PRO_UID' => $process1->PRO_UID, + 'DEL_PREVIOUS' => 1, + 'DEL_INDEX' => 2, + 'DEL_DELEGATE_DATE' => $currentDate, + 'DEL_RISK_DATE' => $date->add($diff1Day), + 'DEL_TASK_DUE_DATE' => $date->add($diff2Days) + ]); + + factory(AppDelay::class)->create([ + 'APP_DELEGATION_USER' => $user->USR_UID, + 'PRO_UID' => $process1->PRO_UID, + 'APP_NUMBER' => $delegation1->APP_NUMBER, + 'APP_DEL_INDEX' => $delegation1->DEL_INDEX, + 'APP_DISABLE_ACTION_USER' => 0, + 'APP_TYPE' => 'PAUSE' + ]); + $this->createMultiplePaused(3, 2, $user); + $paused = new Paused(); + $paused->setUserId($user->USR_ID); + $paused->setUserUid($user->USR_UID); + $res = $paused->getCasesRisk($process1->PRO_ID); + $this->assertCount(1, $res); + } + + /** + * It tests the getCasesRisk() method with the at risk filter + * + * @covers \ProcessMaker\BusinessModel\Cases\Paused::getCasesRisk() + * @test + */ + public function it_should_test_get_cases_risk_at_risk() + { + $date = new DateTime('now'); + $currentDate = $date->format('Y-m-d H:i:s'); + $diff2Days = new DateInterval('P2D'); + $user = factory(User::class)->create(); + $process1 = factory(Process::class)->create(); + + $task = factory(Task::class)->create([ + 'TAS_ASSIGN_TYPE' => '', + 'TAS_GROUP_VARIABLE' => '', + 'PRO_UID' => $process1->PRO_UID, + 'TAS_TYPE' => 'NORMAL' + ]); + + $application1 = factory(Application::class)->create(); + + factory(Delegation::class)->create([ + 'APP_UID' => $application1->APP_UID, + 'APP_NUMBER' => $application1->APP_NUMBER, + 'TAS_ID' => $task->TAS_ID, + 'DEL_THREAD_STATUS' => 'CLOSED', + 'USR_UID' => $user->USR_UID, + 'USR_ID' => $user->USR_ID, + 'PRO_ID' => $process1->PRO_ID, + 'PRO_UID' => $process1->PRO_UID, + 'DEL_PREVIOUS' => 0, + 'DEL_INDEX' => 1, + 'DEL_DELEGATE_DATE' => $currentDate, + 'DEL_RISK_DATE' => $currentDate, + 'DEL_TASK_DUE_DATE' => $date->add($diff2Days) + ]); + $delegation1 = factory(Delegation::class)->create([ + 'APP_UID' => $application1->APP_UID, + 'APP_NUMBER' => $application1->APP_NUMBER, + 'TAS_ID' => $task->TAS_ID, + 'DEL_THREAD_STATUS' => 'OPEN', + 'USR_UID' => $user->USR_UID, + 'USR_ID' => $user->USR_ID, + 'PRO_ID' => $process1->PRO_ID, + 'PRO_UID' => $process1->PRO_UID, + 'DEL_PREVIOUS' => 1, + 'DEL_INDEX' => 2, + 'DEL_DELEGATE_DATE' => $currentDate, + 'DEL_RISK_DATE' => $currentDate, + 'DEL_TASK_DUE_DATE' => $date->add($diff2Days) + ]); + + factory(AppDelay::class)->create([ + 'APP_DELEGATION_USER' => $user->USR_UID, + 'PRO_UID' => $process1->PRO_UID, + 'APP_NUMBER' => $delegation1->APP_NUMBER, + 'APP_DEL_INDEX' => $delegation1->DEL_INDEX, + 'APP_DISABLE_ACTION_USER' => 0, + 'APP_TYPE' => 'PAUSE' + ]); + $this->createMultiplePaused(3, 2, $user); + $paused = new Paused(); + $paused->setUserId($user->USR_ID); + $paused->setUserUid($user->USR_UID); + $res = $paused->getCasesRisk($process1->PRO_ID, null, null, 'AT_RISK'); + $this->assertCount(1, $res); + } + + /** + * It tests the getCasesRisk() method with the overdue filter + * + * @covers \ProcessMaker\BusinessModel\Cases\Paused::getCasesRisk() + * @test + */ + public function it_should_test_get_cases_risk_overdue() + { + $date = new DateTime('now'); + $currentDate = $date->format('Y-m-d H:i:s'); + $diff2Days = new DateInterval('P2D'); + $user = factory(User::class)->create(); + $process1 = factory(Process::class)->create(); + + $task = factory(Task::class)->create([ + 'TAS_ASSIGN_TYPE' => '', + 'TAS_GROUP_VARIABLE' => '', + 'PRO_UID' => $process1->PRO_UID, + 'TAS_TYPE' => 'NORMAL' + ]); + + $application1 = factory(Application::class)->create(); + + factory(Delegation::class)->create([ + 'APP_UID' => $application1->APP_UID, + 'APP_NUMBER' => $application1->APP_NUMBER, + 'TAS_ID' => $task->TAS_ID, + 'DEL_THREAD_STATUS' => 'CLOSED', + 'USR_UID' => $user->USR_UID, + 'USR_ID' => $user->USR_ID, + 'PRO_ID' => $process1->PRO_ID, + 'PRO_UID' => $process1->PRO_UID, + 'DEL_PREVIOUS' => 0, + 'DEL_INDEX' => 1, + 'DEL_DELEGATE_DATE' => $currentDate, + 'DEL_RISK_DATE' => $currentDate, + 'DEL_TASK_DUE_DATE' => $date->sub($diff2Days) + ]); + $delegation1 = factory(Delegation::class)->create([ + 'APP_UID' => $application1->APP_UID, + 'APP_NUMBER' => $application1->APP_NUMBER, + 'TAS_ID' => $task->TAS_ID, + 'DEL_THREAD_STATUS' => 'OPEN', + 'USR_UID' => $user->USR_UID, + 'USR_ID' => $user->USR_ID, + 'PRO_ID' => $process1->PRO_ID, + 'PRO_UID' => $process1->PRO_UID, + 'DEL_PREVIOUS' => 1, + 'DEL_INDEX' => 2, + 'DEL_DELEGATE_DATE' => $currentDate, + 'DEL_RISK_DATE' => $currentDate, + 'DEL_TASK_DUE_DATE' => $date->sub($diff2Days) + ]); + + factory(AppDelay::class)->create([ + 'APP_DELEGATION_USER' => $user->USR_UID, + 'PRO_UID' => $process1->PRO_UID, + 'APP_NUMBER' => $delegation1->APP_NUMBER, + 'APP_DEL_INDEX' => $delegation1->DEL_INDEX, + 'APP_DISABLE_ACTION_USER' => 0, + 'APP_TYPE' => 'PAUSE' + ]); + $this->createMultiplePaused(3, 2, $user); + $paused = new Paused(); + $paused->setUserId($user->USR_ID); + $paused->setUserUid($user->USR_UID); + $res = $paused->getCasesRisk($process1->PRO_ID, null, null, 'OVERDUE'); + $this->assertCount(1, $res); + } } diff --git a/tests/unit/workflow/engine/src/ProcessMaker/BusinessModel/Cases/UnassignedTest.php b/tests/unit/workflow/engine/src/ProcessMaker/BusinessModel/Cases/UnassignedTest.php index 5f940b329..c0475f04e 100644 --- a/tests/unit/workflow/engine/src/ProcessMaker/BusinessModel/Cases/UnassignedTest.php +++ b/tests/unit/workflow/engine/src/ProcessMaker/BusinessModel/Cases/UnassignedTest.php @@ -2,6 +2,8 @@ namespace Tests\unit\workflow\engine\src\ProcessMaker\BusinessModel\Cases; +use DateInterval; +use Datetime; use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Support\Facades\DB; use ProcessMaker\BusinessModel\Cases\Unassigned; @@ -723,4 +725,149 @@ class UnassignedTest extends TestCase $this->assertEquals($additionalTables->ADD_TAB_NAME, $res['tableName']); $this->assertEquals(0, $res['total']); } + + /** + * It tests the getCasesRisk() method with ontime filter + * + * @covers \ProcessMaker\BusinessModel\Cases\Unassigned::getCasesRisk() + * @test + */ + public function it_should_test_get_cases_risk_on_time() + { + $date = new DateTime('now'); + $currentDate = $date->format('Y-m-d H:i:s'); + $diff1Day = new DateInterval('P1D'); + $diff2Days = new DateInterval('P2D'); + $user = factory(User::class)->create(); + $process1 = factory(Process::class)->create([ + 'CATEGORY_ID' => 2 + ]); + $application = factory(Application::class)->create([ + 'APP_STATUS_ID' => 2 + ]); + $task = factory(Task::class)->create([ + 'TAS_ASSIGN_TYPE' => 'SELF_SERVICE', + 'TAS_GROUP_VARIABLE' => '', + 'PRO_UID' => $process1->PRO_UID, + 'PRO_ID' => $process1->PRO_ID, + ]); + factory(TaskUser::class)->create([ + 'TAS_UID' => $task->TAS_UID, + 'USR_UID' => $user->USR_UID, + 'TU_RELATION' => 1, + 'TU_TYPE' => 1 + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application->APP_NUMBER, + 'TAS_ID' => $task->TAS_ID, + 'PRO_ID' => $process1->PRO_ID, + 'DEL_THREAD_STATUS' => 'OPEN', + 'USR_ID' => 0, + 'DEL_DELEGATE_DATE' => $currentDate, + 'DEL_RISK_DATE' => $date->add($diff1Day), + 'DEL_TASK_DUE_DATE' => $date->add($diff2Days) + ]); + $unassigned = new Unassigned(); + $unassigned->setUserId($user->USR_ID); + $unassigned->setUserUid($user->USR_UID); + + $res = $unassigned->getCasesRisk($process1->PRO_ID); + $this->assertCount(1, $res); + } + + /** + * It tests the getCasesRisk() method with at risk filter + * + * @covers \ProcessMaker\BusinessModel\Cases\Unassigned::getCasesRisk() + * @test + */ + public function it_should_test_get_cases_risk_at_risk() + { + $date = new DateTime('now'); + $currentDate = $date->format('Y-m-d H:i:s'); + $diff2Days = new DateInterval('P2D'); + $user = factory(User::class)->create(); + $process1 = factory(Process::class)->create([ + 'CATEGORY_ID' => 2 + ]); + $application = factory(Application::class)->create([ + 'APP_STATUS_ID' => 2 + ]); + $task = factory(Task::class)->create([ + 'TAS_ASSIGN_TYPE' => 'SELF_SERVICE', + 'TAS_GROUP_VARIABLE' => '', + 'PRO_UID' => $process1->PRO_UID, + 'PRO_ID' => $process1->PRO_ID, + ]); + factory(TaskUser::class)->create([ + 'TAS_UID' => $task->TAS_UID, + 'USR_UID' => $user->USR_UID, + 'TU_RELATION' => 1, + 'TU_TYPE' => 1 + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application->APP_NUMBER, + 'TAS_ID' => $task->TAS_ID, + 'PRO_ID' => $process1->PRO_ID, + 'DEL_THREAD_STATUS' => 'OPEN', + 'USR_ID' => 0, + 'DEL_DELEGATE_DATE' => $currentDate, + 'DEL_RISK_DATE' => $currentDate, + 'DEL_TASK_DUE_DATE' => $date->add($diff2Days) + ]); + $unassigned = new Unassigned(); + $unassigned->setUserId($user->USR_ID); + $unassigned->setUserUid($user->USR_UID); + + $res = $unassigned->getCasesRisk($process1->PRO_ID, null, null, 'AT_RISK'); + $this->assertCount(1, $res); + } + + /** + * It tests the getCasesRisk() method with overdue filter + * + * @covers \ProcessMaker\BusinessModel\Cases\Unassigned::getCasesRisk() + * @test + */ + public function it_should_test_get_cases_risk_overdue() + { + $date = new DateTime('now'); + $currentDate = $date->format('Y-m-d H:i:s'); + $diff2Days = new DateInterval('P2D'); + $user = factory(User::class)->create(); + $process1 = factory(Process::class)->create([ + 'CATEGORY_ID' => 2 + ]); + $application = factory(Application::class)->create([ + 'APP_STATUS_ID' => 2 + ]); + $task = factory(Task::class)->create([ + 'TAS_ASSIGN_TYPE' => 'SELF_SERVICE', + 'TAS_GROUP_VARIABLE' => '', + 'PRO_UID' => $process1->PRO_UID, + 'PRO_ID' => $process1->PRO_ID, + ]); + factory(TaskUser::class)->create([ + 'TAS_UID' => $task->TAS_UID, + 'USR_UID' => $user->USR_UID, + 'TU_RELATION' => 1, + 'TU_TYPE' => 1 + ]); + factory(Delegation::class)->create([ + 'APP_NUMBER' => $application->APP_NUMBER, + 'TAS_ID' => $task->TAS_ID, + 'PRO_ID' => $process1->PRO_ID, + 'DEL_THREAD_STATUS' => 'OPEN', + 'USR_ID' => 0, + 'DEL_DELEGATE_DATE' => $currentDate, + 'DEL_RISK_DATE' => $currentDate, + 'DEL_TASK_DUE_DATE' => $date->sub($diff2Days) + ]); + $unassigned = new Unassigned(); + $unassigned->setUserId($user->USR_ID); + $unassigned->setUserUid($user->USR_UID); + + $res = $unassigned->getCasesRisk($process1->PRO_ID, null, null, 'OVERDUE'); + $this->assertCount(1, $res); + } } diff --git a/tests/unit/workflow/engine/src/ProcessMaker/Model/DelegationTest.php b/tests/unit/workflow/engine/src/ProcessMaker/Model/DelegationTest.php index ae8b1edca..9f254318e 100644 --- a/tests/unit/workflow/engine/src/ProcessMaker/Model/DelegationTest.php +++ b/tests/unit/workflow/engine/src/ProcessMaker/Model/DelegationTest.php @@ -2,6 +2,8 @@ namespace Tests\unit\workflow\src\ProcessMaker\Model; +use DateInterval; +use Datetime; use G; use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Support\Facades\DB; @@ -446,7 +448,16 @@ class DelegationTest extends TestCase */ public function it_return_scope_at_risk() { - $table = factory(Delegation::class)->states('closed')->create(); + $date = new DateTime('now'); + $currentDate = $date->format('Y-m-d H:i:s'); + $diff2Days = new DateInterval('P2D'); + + $table = factory(Delegation::class)->create([ + 'DEL_THREAD_STATUS' => 'CLOSED', + 'DEL_DELEGATE_DATE' => $currentDate, + 'DEL_RISK_DATE' => $currentDate, + 'DEL_TASK_DUE_DATE' => $date->add($diff2Days) + ]); $this->assertCount(1, $table->atRisk($table->DEL_DELEGATE_DATE)->get()); } @@ -458,7 +469,16 @@ class DelegationTest extends TestCase */ public function it_return_scope_overdue() { - $table = factory(Delegation::class)->states('closed')->create(); + $date = new DateTime('now'); + $currentDate = $date->format('Y-m-d H:i:s'); + $diff2Days = new DateInterval('P2D'); + + $table = factory(Delegation::class)->create([ + 'DEL_THREAD_STATUS' => 'CLOSED', + 'DEL_DELEGATE_DATE' => $currentDate, + 'DEL_RISK_DATE' => $currentDate, + 'DEL_TASK_DUE_DATE' => $date->sub($diff2Days) + ]); $this->assertCount(1, $table->overdue($table->DEL_DELEGATE_DATE)->get()); } diff --git a/workflow/engine/src/ProcessMaker/BusinessModel/Cases/AbstractCases.php b/workflow/engine/src/ProcessMaker/BusinessModel/Cases/AbstractCases.php index cc9d47f4d..69de97702 100644 --- a/workflow/engine/src/ProcessMaker/BusinessModel/Cases/AbstractCases.php +++ b/workflow/engine/src/ProcessMaker/BusinessModel/Cases/AbstractCases.php @@ -1583,4 +1583,78 @@ class AbstractCases implements CasesInterface } return $query->get()->values()->toArray(); } + + /** + * Get cases risk by process + * + * @param int $processId + * @param string $dateFrom + * @param string $dateTo + * @param string $riskStatus + * @param int $topCases + * + * @return array + */ + public function getCasesRisk($processId, $dateFrom = null, $dateTo = null, $riskStatus = 'ON_TIME', $topCases = null) + { + $date = new DateTime('now'); + $currentDate = $date->format('Y-m-d H:i:s'); + $query = Delegation::selectRaw(' + APP_DELEGATION.APP_NUMBER as number_case, + APP_DELEGATION.DEL_DELEGATE_DATE as delegated, + APP_DELEGATION.DEL_RISK_DATE as at_risk, + APP_DELEGATION.DEL_TASK_DUE_DATE as due_date, + APP_DELEGATION.APP_UID as app_uid, + APP_DELEGATION.DEL_INDEX as del_index, + APP_DELEGATION.TAS_UID as tas_uid + '); + $listArray = explode("\\", get_class($this)); + $list = end($listArray); + switch ($list) { + case 'Inbox': + $query->inbox($this->getUserId()); + break; + case 'Draft': + $query->draft($this->getUserId()); + break; + case 'Paused': + $query->paused($this->getUserId()); + break; + case 'Unassigned': + $query->selfService($this->getUserUid()); + break; + } + $query->joinProcess(); + $query->processInList([$processId]); + + if (!is_null($dateFrom)) { + $query->where('APP_DELEGATION.DEL_DELEGATE_DATE', '>=', $dateFrom); + } + if (!is_null($dateTo)) { + $query->where('APP_DELEGATION.DEL_DELEGATE_DATE', '<=', $dateTo); + } + if (!is_null($topCases)) { + $query->orderBy('APP_DELEGATION.DEL_DELEGATE_DATE', 'ASC')->limit($topCases); + } + $value = 'due_date'; + switch ($riskStatus) { + case 'ON_TIME': + $query->onTime($currentDate); + $value = 'at_risk'; + break; + case 'AT_RISK': + $query->atRisk($currentDate); + break; + case 'OVERDUE': + $query->overdue($currentDate); + break; + } + $res = $query->get()->values()->toArray(); + foreach ($res as $key => $values) { + $riskDate = new DateTime($values[$value]); + $days = ['days' => $date->diff($riskDate)->days]; + $res[$key] = $days + $res[$key]; + } + return $res; + } } diff --git a/workflow/engine/src/ProcessMaker/Model/Delegation.php b/workflow/engine/src/ProcessMaker/Model/Delegation.php index 95a65027b..d0b44bf10 100644 --- a/workflow/engine/src/ProcessMaker/Model/Delegation.php +++ b/workflow/engine/src/ProcessMaker/Model/Delegation.php @@ -388,7 +388,7 @@ class Delegation extends Model */ public function scopeAtRisk($query, $now) { - return $query->where('DEL_RISK_DATE', '>=', $now)->where('DEL_TASK_DUE_DATE', '>=', $now); + return $query->where('DEL_RISK_DATE', '<=', $now)->where('DEL_TASK_DUE_DATE', '>=', $now); } /** @@ -401,7 +401,7 @@ class Delegation extends Model */ public function scopeOverdue($query, $now) { - return $query->where('DEL_TASK_DUE_DATE', '>', $now); + return $query->where('DEL_TASK_DUE_DATE', '<', $now); } /** diff --git a/workflow/engine/src/ProcessMaker/Services/Api/Metrics.php b/workflow/engine/src/ProcessMaker/Services/Api/Metrics.php index 8128507d2..ee1acf8e5 100644 --- a/workflow/engine/src/ProcessMaker/Services/Api/Metrics.php +++ b/workflow/engine/src/ProcessMaker/Services/Api/Metrics.php @@ -157,4 +157,46 @@ class Metrics extends Api throw new RestException(Api::STAT_APP_EXCEPTION, $e->getMessage()); } } + + /** + * Get total cases risk + * + * @url GET /cases-risk + * + * @param string $caseList + * @param int $process + * @param string $dateFrom + * @param string $dateTo + * @param string $riskStatus + * @param int $topCases + * + * @return array + * + * @throws RestException + */ + public function getCasesRiskByProcess($caseList = 'inbox', $process, $dateFrom = null, $dateTo = null, $riskStatus = 'ON_TIME', $topCases = null) + { + try { + $usrId = $this->getUserId(); + switch ($caseList) { + case 'inbox': + $list = new Inbox(); + break; + case 'draft': + $list = new Draft(); + break; + case 'paused': + $list = new Paused(); + break; + case 'unassigned': + $list = new Unassigned(); + break; + } + $list->setUserId($usrId); + $result = $list->getCasesRisk($process, $dateFrom, $dateTo, $riskStatus, $topCases); + return $result; + } catch (Exception $e) { + throw new RestException(Api::STAT_APP_EXCEPTION, $e->getMessage()); + } + } } From d80b4022168608dbf1616ec3a507676c85ec3ba5 Mon Sep 17 00:00:00 2001 From: Rodrigo Quelca Date: Mon, 23 Aug 2021 13:35:51 +0000 Subject: [PATCH 27/36] PMCORE-3236: Review pagination in all lists because some improvement in the rest services --- resources/assets/js/home/AdvancedSearch/AdvancedSearch.vue | 7 +++++-- resources/assets/js/home/Draft/Draft.vue | 6 ++---- resources/assets/js/home/Inbox/Inbox.vue | 7 +++---- resources/assets/js/home/MyCases/MyCases.vue | 4 ++-- resources/assets/js/home/Paused/Paused.vue | 6 ++---- resources/assets/js/home/Unassigned/Unassigned.vue | 6 ++---- 6 files changed, 16 insertions(+), 20 deletions(-) diff --git a/resources/assets/js/home/AdvancedSearch/AdvancedSearch.vue b/resources/assets/js/home/AdvancedSearch/AdvancedSearch.vue index a9be8eba0..653e9c7fd 100644 --- a/resources/assets/js/home/AdvancedSearch/AdvancedSearch.vue +++ b/resources/assets/js/home/AdvancedSearch/AdvancedSearch.vue @@ -221,8 +221,11 @@ export default { limit = data.limit, filters = {}, start = data.page === 1 ? 0 : limit * (data.page - 1); - paged = start + "," + limit; - filters["paged"] = paged; + paged = start + "," + limit ; + filters = { + limit: limit, + offset: start + }; _.forIn(this.filters, function (item, key) { if(filters && item.value) { filters[item.filterVar] = item.value; diff --git a/resources/assets/js/home/Draft/Draft.vue b/resources/assets/js/home/Draft/Draft.vue index dd27b1c6d..5a8de6de0 100644 --- a/resources/assets/js/home/Draft/Draft.vue +++ b/resources/assets/js/home/Draft/Draft.vue @@ -418,12 +418,10 @@ export default { start = data.page === 1 ? 0 : limit * (data.page - 1), filters = {}, sort = ""; - paged = start + "," + limit; - filters = { - paged: paged, + limit: limit, + offset: start }; - _.forIn(this.filters, function (item, key) { if(filters && item.value) { filters[item.filterVar] = item.value; diff --git a/resources/assets/js/home/Inbox/Inbox.vue b/resources/assets/js/home/Inbox/Inbox.vue index 07eaee8e4..a8c3ae1f2 100644 --- a/resources/assets/js/home/Inbox/Inbox.vue +++ b/resources/assets/js/home/Inbox/Inbox.vue @@ -462,11 +462,10 @@ export default { start = data.page === 1 ? 0 : limit * (data.page - 1), filters = {}, sort = ""; - paged = start + "," + limit; - filters = { - paged: paged, - } + limit: limit, + offset: start + }; _.forIn(this.filters, function (item, key) { if(filters && item.value) { filters[item.filterVar] = item.value; diff --git a/resources/assets/js/home/MyCases/MyCases.vue b/resources/assets/js/home/MyCases/MyCases.vue index f672ebad0..424451e7b 100644 --- a/resources/assets/js/home/MyCases/MyCases.vue +++ b/resources/assets/js/home/MyCases/MyCases.vue @@ -368,10 +368,10 @@ export default { start = data.page === 1 ? 0 : limit * (data.page - 1), filters = {}, sort = ""; - paged = start + "," + limit; filters = { filter: that.filterHeader, - paged: paged, + limit: limit, + offset: start }; _.forIn(this.filters, function(item, key) { if (filters && item.value) { diff --git a/resources/assets/js/home/Paused/Paused.vue b/resources/assets/js/home/Paused/Paused.vue index d04516d66..a0d991dd5 100644 --- a/resources/assets/js/home/Paused/Paused.vue +++ b/resources/assets/js/home/Paused/Paused.vue @@ -461,12 +461,10 @@ export default { start = data.page === 1 ? 0 : limit * (data.page - 1), filters = {}, sort = ""; - paged = start + "," + limit; - filters = { - paged: paged, + limit: limit, + offset: start }; - _.forIn(this.filters, function (item, key) { if(filters && item.value) { filters[item.filterVar] = item.value; diff --git a/resources/assets/js/home/Unassigned/Unassigned.vue b/resources/assets/js/home/Unassigned/Unassigned.vue index d74f94f20..1b1961806 100644 --- a/resources/assets/js/home/Unassigned/Unassigned.vue +++ b/resources/assets/js/home/Unassigned/Unassigned.vue @@ -427,12 +427,10 @@ export default { start = data.page === 1 ? 0 : limit * (data.page - 1), filters = {}, sort = ""; - paged = start + "," + limit; - filters = { - paged: paged, + limit: limit, + offset: start }; - _.forIn(this.filters, function (item, key) { if(filters && item.value) { filters[item.filterVar] = item.value; From d01a5cac8ea964868958c4781390677e5d2279e0 Mon Sep 17 00:00:00 2001 From: Paula Quispe Date: Mon, 23 Aug 2021 10:26:42 -0400 Subject: [PATCH 28/36] PMCORE-3239 --- workflow/engine/src/ProcessMaker/BusinessModel/Cases.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/workflow/engine/src/ProcessMaker/BusinessModel/Cases.php b/workflow/engine/src/ProcessMaker/BusinessModel/Cases.php index b4270196b..af167f8a0 100644 --- a/workflow/engine/src/ProcessMaker/BusinessModel/Cases.php +++ b/workflow/engine/src/ProcessMaker/BusinessModel/Cases.php @@ -1050,7 +1050,8 @@ class Cases } // Check if the case is unassigned - if ($this->isUnassignedPauseCase($appUid, $index)) { + $classCases = new ClassesCases(); + if ($classCases->isUnassignedPauseCase($appUid, $index)) { throw new Exception(G::LoadTranslation("ID_CASE_NOT_PAUSED", [G::LoadTranslation("ID_UNASSIGNED_STATUS")])); } From 1cfba144c8041bf07e4cca8f47ac10922d9e4e24 Mon Sep 17 00:00:00 2001 From: Roly Gutierrez Date: Mon, 23 Aug 2021 11:05:58 -0400 Subject: [PATCH 29/36] PMCORE-3237 Service - Validation import custom case list --- .../src/ProcessMaker/Model/CaseListTest.php | 11 ++- .../translations/english/processmaker.en.po | 18 +++++ workflow/engine/data/mysql/insert.sql | 3 + .../src/ProcessMaker/Model/CaseList.php | 69 +++++++++++++++++-- 4 files changed, 93 insertions(+), 8 deletions(-) diff --git a/tests/unit/workflow/engine/src/ProcessMaker/Model/CaseListTest.php b/tests/unit/workflow/engine/src/ProcessMaker/Model/CaseListTest.php index 5deceb05c..87f500e3c 100644 --- a/tests/unit/workflow/engine/src/ProcessMaker/Model/CaseListTest.php +++ b/tests/unit/workflow/engine/src/ProcessMaker/Model/CaseListTest.php @@ -281,15 +281,17 @@ class CaseListTest extends TestCase */ public function it_should_test_import() { + $additionalTables = factory(AdditionalTables::class)->create(); $data = [ 'type' => 'inbox', 'name' => 'test1', 'description' => 'my description', - 'tableUid' => '', + 'tableUid' => $additionalTables->ADD_TAB_UID, 'columns' => [], 'iconList' => 'deafult.png', 'iconColor' => 'red', - 'iconColorScreen' => 'blue' + 'iconColorScreen' => 'blue', + 'tableName' => $additionalTables->ADD_TAB_NAME ]; $json = json_encode($data); $tempFile = sys_get_temp_dir() . '/test_' . random_int(10000, 99999); @@ -300,7 +302,10 @@ class CaseListTest extends TestCase 'error' => 0 ] ]; - $request_data = []; + $request_data = [ + 'invalidFields' => 'continue', + 'duplicateName' => 'continue' + ]; $ownerId = 1; $result = CaseList::import($request_data, $ownerId); diff --git a/workflow/engine/content/translations/english/processmaker.en.po b/workflow/engine/content/translations/english/processmaker.en.po index 0d0fd93de..7481705ff 100755 --- a/workflow/engine/content/translations/english/processmaker.en.po +++ b/workflow/engine/content/translations/english/processmaker.en.po @@ -3515,6 +3515,12 @@ msgstr "No actions available for this case." msgid "Case Demo" msgstr "Case Demo" +# TRANSLATION +# LABEL/ID_CASELIST_CAN_NOT_BE_IMPORTED_THE_PMTABLE_NOT_EXIST +#: LABEL/ID_CASELIST_CAN_NOT_BE_IMPORTED_THE_PMTABLE_NOT_EXIST +msgid "Custom Case List {0} can not be imported because the PM Table does not exist in this Workspace." +msgstr "Custom Case List {0} can not be imported because the PM Table does not exist in this Workspace." + # TRANSLATION # LABEL/ID_CASE_DELETE_SUCCESFULLY #: LABEL/ID_CASE_DELETE_SUCCESFULLY @@ -10043,6 +10049,12 @@ msgstr "Group already exists. You need set an action to continue. Available acti msgid "Project already exists. Set an action to continue. Available actions: [{0}]." msgstr "Project already exists. Set an action to continue. Available actions: [{0}]." +# TRANSLATION +# LABEL/ID_IMPORTING_CASELIST_WITH_THE_SAME_NAME_SELECT_OPTION +#: LABEL/ID_IMPORTING_CASELIST_WITH_THE_SAME_NAME_SELECT_OPTION +msgid "You are about importing a Case List with the same name {0}, please select an option." +msgstr "You are about importing a Case List with the same name {0}, please select an option." + # TRANSLATION # LABEL/ID_IMPORTING_ERROR #: LABEL/ID_IMPORTING_ERROR @@ -21929,6 +21941,12 @@ msgstr "The PM Table associated with this DynaForm could not be found." msgid "The data from this case was saved in the database, but it was not saved in the PM Table, which it couldn't be found." msgstr "The data from this case was saved in the database, but it was not saved in the PM Table, which it couldn't be found." +# TRANSLATION +# LABEL/ID_PMTABLE_NOT_HAVE_ALL_CASELIST_FIELDS_WOULD_YOU_LIKE_CONTINUE +#: LABEL/ID_PMTABLE_NOT_HAVE_ALL_CASELIST_FIELDS_WOULD_YOU_LIKE_CONTINUE +msgid "The PM Table {0} does not have all the Custom Case List fields for file {1}. Would you like continue?" +msgstr "The PM Table {0} does not have all the Custom Case List fields for file {1}. Would you like continue?" + # TRANSLATION # LABEL/ID_PMTABLE_NOT_IMPORT_HAS_ERRORS #: LABEL/ID_PMTABLE_NOT_IMPORT_HAS_ERRORS diff --git a/workflow/engine/data/mysql/insert.sql b/workflow/engine/data/mysql/insert.sql index 4c09f2da4..ab16e55a8 100755 --- a/workflow/engine/data/mysql/insert.sql +++ b/workflow/engine/data/mysql/insert.sql @@ -57392,6 +57392,7 @@ INSERT INTO TRANSLATION (TRN_CATEGORY,TRN_ID,TRN_LANG,TRN_VALUE,TRN_UPDATE_DATE ( 'LABEL','ID_CASE','en','Case','2014-01-15') , ( 'LABEL','ID_CASECANCEL','en','No actions available for this case.','2014-01-15') , ( 'LABEL','ID_CASEDEMO','en','Case Demo','2014-01-15') , +( 'LABEL','ID_CASELIST_CAN_NOT_BE_IMPORTED_THE_PMTABLE_NOT_EXIST','en','Custom Case List {0} can not be imported because the PM Table does not exist in this Workspace.','2021-08-20') , ( 'LABEL','ID_CASE_DELETE_SUCCESFULLY','en','The Case was deleted successfully.','2020-01-08') , ( 'LABEL','ID_CASE_UID','en','Case Uid','2021-04-04') , ( 'LABEL','ID_CASES','en','HOME','2014-01-15') , @@ -58523,6 +58524,7 @@ INSERT INTO TRANSLATION (TRN_CATEGORY,TRN_ID,TRN_LANG,TRN_VALUE,TRN_UPDATE_DATE ( 'LABEL','ID_IMPORTER_FILE_PROCESSMAKER_PROJECT_VERSION_IS_MISSING','en','ProcessMaker Project version is missing on file source.','2014-05-20') , ( 'LABEL','ID_IMPORTER_GROUP_ALREADY_EXISTS_SET_ACTION_TO_CONTINUE','en','Group already exists. You need set an action to continue. Available actions: [{0}].','2014-10-21') , ( 'LABEL','ID_IMPORTER_PROJECT_ALREADY_EXISTS_SET_ACTION_TO_CONTINUE','en','Project already exists. Set an action to continue. Available actions: [{0}].','2014-10-21') , +( 'LABEL','ID_IMPORTING_CASELIST_WITH_THE_SAME_NAME_SELECT_OPTION','en','You are about importing a Case List with the same name {0}, please select an option.','2021-08-20') , ( 'LABEL','ID_IMPORTING_ERROR','en','Importing Error','2014-01-15') , ( 'LABEL','ID_IMPORTING_USERS','en','Importing Users...','2015-09-15') , ( 'LABEL','ID_IMPORT_ALREADY_EXISTS','en','The process you are trying to import already exists. Please select one of the following options to continue:','2014-10-21') , @@ -60553,6 +60555,7 @@ INSERT INTO TRANSLATION (TRN_CATEGORY,TRN_ID,TRN_LANG,TRN_VALUE,TRN_UPDATE_DATE ( 'LABEL','ID_PMTABLE_INVALID_NAME','en','Could not create the table with the name "{0}" because it is a reserved word.','2014-01-15') , ( 'LABEL','ID_PMTABLE_NOT_FOUND','en','The PM Table associated with this DynaForm could not be found.','2014-11-12') , ( 'LABEL','ID_PMTABLE_NOT_FOUNDED_SAVED_DATA','en','The data from this case was saved in the database, but it was not saved in the PM Table, which it couldn''t be found.','2014-11-12') , +( 'LABEL','ID_PMTABLE_NOT_HAVE_ALL_CASELIST_FIELDS_WOULD_YOU_LIKE_CONTINUE','en','The PM Table {0} does not have all the Custom Case List fields for file {1}. Would you like continue?','2014-11-12') , ( 'LABEL','ID_PMTABLE_NOT_IMPORT_HAS_ERRORS','en','File "{0}" was not imported has errors:','2016-02-18') , ( 'LABEL','ID_PMTABLE_PRIMARY_KEY_FIELD_IS_MISSING_IN_ATTRIBUTE','en','The primary key field {0} of the PM Table is missing in the attribute {1}.','2014-05-20') , ( 'LABEL','ID_PMTABLE_REQUIRED','en','It is required to select a PM table','2014-10-27') , diff --git a/workflow/engine/src/ProcessMaker/Model/CaseList.php b/workflow/engine/src/ProcessMaker/Model/CaseList.php index 690307326..7c4148be5 100644 --- a/workflow/engine/src/ProcessMaker/Model/CaseList.php +++ b/workflow/engine/src/ProcessMaker/Model/CaseList.php @@ -7,6 +7,7 @@ use G; use ProcessMaker\BusinessModel\Table; use ProcessMaker\Core\System; use ProcessMaker\Model\AdditionalTables; +use ProcessMaker\Model\Fields; use ProcessMaker\Model\User; use Illuminate\Database\Eloquent\Model; @@ -246,7 +247,8 @@ class CaseList extends Model ->leftJoin('USERS', 'USERS.USR_ID', '=', 'CASE_LIST.USR_ID') ->leftJoin('ADDITIONAL_TABLES', 'ADDITIONAL_TABLES.ADD_TAB_UID', '=', 'CASE_LIST.ADD_TAB_UID') ->select([ - 'CASE_LIST.*' + 'CASE_LIST.*', + 'ADDITIONAL_TABLES.ADD_TAB_NAME' ]) ->get() ->first(); @@ -256,6 +258,7 @@ class CaseList extends Model $result = CaseList::getAliasFromColumnName($model->toArray()); $result['columns'] = json_decode($result['columns']); + $result['tableName'] = $model->ADD_TAB_NAME; //clean invalid items unset($result['id']); @@ -275,21 +278,77 @@ class CaseList extends Model /** * The import requires a $ _FILES content in json format to create a record. - * @param array $request_data + * @param array $requestData * @param int $ownerId * @return array * @throws Exception */ - public static function import(array $request_data, int $ownerId) + public static function import(array $requestData, int $ownerId) { if ($_FILES['file_content']['error'] !== UPLOAD_ERR_OK || $_FILES['file_content']['tmp_name'] === '') { - throw new Exception(G::LoadTranslation('ID_ERROR_UPLOADING_FILENAME')); + throw new Exception(G::LoadTranslation('ID_ERROR_UPLOAD_FILE_CONTACT_ADMINISTRATOR')); } $content = file_get_contents($_FILES['file_content']['tmp_name']); try { $array = json_decode($content, true); - $caseList = CaseList::createSetting($array, $ownerId); + + $tableName = $array['tableName']; + unset($array['tableName']); + + //the pmtable not exist + $table = AdditionalTables::where('ADD_TAB_NAME', '=', $tableName) + ->get() + ->first(); + if ($table === null) { + return [ + 'status' => 'tableNotExist', + 'message' => G::LoadTranslation('ID_CASELIST_CAN_NOT_BE_IMPORTED_THE_PMTABLE_NOT_EXIST', [$_FILES['file_content']['name']]) + ]; + } + $array['tableUid'] = $table->ADD_TAB_UID; + + //the fields have differences between the import file and the current table + $requestData['invalidFields'] = $requestData['invalidFields'] ?? ''; + if ($requestData['invalidFields'] !== 'continue') { + $fields = Fields::where('ADD_TAB_UID', '=', $array['tableUid']) + ->whereNotIn('FLD_NAME', self::$excludeColumns) + ->select('FLD_NAME') + ->get() + ->transform(function ($object) { + return $object->FLD_NAME; + }) + ->toArray(); + foreach ($array['columns'] as $value) { + if (!in_array($value['field'], $fields)) { + return [ + 'status' => 'invalidFields', + 'message' => G::LoadTranslation('ID_PMTABLE_NOT_HAVE_ALL_CASELIST_FIELDS_WOULD_YOU_LIKE_CONTINUE', [$tableName, $_FILES['file_content']['name']]) + ]; + } + } + } + + //the name of the case list already exist + $list = CaseList::where('CAL_NAME', '=', $array['name']) + ->get() + ->first(); + $requestData['duplicateName'] = $requestData['duplicateName'] ?? ''; + if ($requestData['duplicateName'] !== 'continue') { + if ($list !== null) { + return [ + 'status' => 'duplicateName', + 'message' => G::LoadTranslation('ID_IMPORTING_CASELIST_WITH_THE_SAME_NAME_SELECT_OPTION', [$array['name']]) + ]; + } + } + + if ($requestData['duplicateName'] === 'continue' && $list !== null) { + $caseList = CaseList::updateSetting($list->CAL_ID, $array, $ownerId); + } else { + $caseList = CaseList::createSetting($array, $ownerId); + } + $result = CaseList::getAliasFromColumnName($caseList->toArray()); return $result; } catch (Exception $e) { From da3dab37f4c07a46d113b7703af7f49f5e7b355a Mon Sep 17 00:00:00 2001 From: Rodrigo Quelca Date: Mon, 23 Aug 2021 15:49:14 +0000 Subject: [PATCH 30/36] PMCORE-3234: The "Case Details" view provides the option of Unpause instead of Continue --- config/app.php | 2 +- resources/assets/js/home/CaseDetail.vue | 23 ++++++++++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/config/app.php b/config/app.php index 1ffcf358c..1bae114c9 100644 --- a/config/app.php +++ b/config/app.php @@ -8,7 +8,7 @@ return [ 'name' => env('APP_NAME', 'ProcessMaker'), 'url' => env('APP_URL', 'http://localhost'), 'env' => env('APP_ENV', 'production'), - 'debug' => env('APP_DEBUG', false), + 'debug' => env('APP_DEBUG', true), 'cache_lifetime' => env('APP_CACHE_LIFETIME', 60), 'key' => env('APP_KEY', 'base64:rU28h/tElUn/eiLY0qC24jJq1rakvAFRoRl1DWxj/kM='), 'cipher' => 'AES-256-CBC', diff --git a/resources/assets/js/home/CaseDetail.vue b/resources/assets/js/home/CaseDetail.vue index 60f033310..7ef96d278 100644 --- a/resources/assets/js/home/CaseDetail.vue +++ b/resources/assets/js/home/CaseDetail.vue @@ -48,9 +48,15 @@ {{ $t("ID_CONTINUE") }} + {{ $t("ID_INPAUSE") }}
@@ -428,6 +434,9 @@ export default { that.dataComments.noPerms = response.data.noPerms || 0; }) .catch((err) => { + if (err.response.data) { + that.showAlert(err.response.data.error.message, "danger"); + } throw new Error(err); }); }, @@ -576,6 +585,18 @@ export default { this.$emit("onUpdatePage", "XCase"); } }, + /** + * Unpause click handler + * + * @param {object} data + */ + onClickUnpause(data) { + Api.cases.unpause(data).then((response) => { + if (response.statusText === "OK") { + this.$refs["vueTable"].getData(); + } + }); + }, /** * Claim case * From 111b1ecc99db6478e3721756e19912d1a906d037 Mon Sep 17 00:00:00 2001 From: Rodrigo Quelca Date: Mon, 23 Aug 2021 15:51:10 +0000 Subject: [PATCH 31/36] restore app config --- config/app.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/app.php b/config/app.php index 1bae114c9..1ffcf358c 100644 --- a/config/app.php +++ b/config/app.php @@ -8,7 +8,7 @@ return [ 'name' => env('APP_NAME', 'ProcessMaker'), 'url' => env('APP_URL', 'http://localhost'), 'env' => env('APP_ENV', 'production'), - 'debug' => env('APP_DEBUG', true), + 'debug' => env('APP_DEBUG', false), 'cache_lifetime' => env('APP_CACHE_LIFETIME', 60), 'key' => env('APP_KEY', 'base64:rU28h/tElUn/eiLY0qC24jJq1rakvAFRoRl1DWxj/kM='), 'cipher' => 'AES-256-CBC', From 35af0a98267bfee410ed11324572143314afac44 Mon Sep 17 00:00:00 2001 From: fabio Date: Mon, 23 Aug 2021 12:43:10 -0400 Subject: [PATCH 32/36] PMCORE-3213:Review the default columns in the new case list panel Corrections --- .../settings/customCaseList/Api/CaseList.js | 9 ++++++-- .../settings/customCaseList/Api/Services.js | 1 + .../customCaseList/CaseListSketch.vue | 21 ++++++++++++++++--- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/resources/assets/js/admin/settings/customCaseList/Api/CaseList.js b/resources/assets/js/admin/settings/customCaseList/Api/CaseList.js index 552e5dcaf..c41382739 100644 --- a/resources/assets/js/admin/settings/customCaseList/Api/CaseList.js +++ b/resources/assets/js/admin/settings/customCaseList/Api/CaseList.js @@ -56,8 +56,13 @@ class caseListApi extends Api { keys: {} }); } - getDefault(module){ - return Defaults[module] + getDefault(type){ + return this.get({ + service: 'DEFAULT_COLUMNS', + keys: { + type: type + } + }); } createCaseList(data) { return this.post({ diff --git a/resources/assets/js/admin/settings/customCaseList/Api/Services.js b/resources/assets/js/admin/settings/customCaseList/Api/Services.js index e6cc594f4..f21b65475 100644 --- a/resources/assets/js/admin/settings/customCaseList/Api/Services.js +++ b/resources/assets/js/admin/settings/customCaseList/Api/Services.js @@ -5,5 +5,6 @@ export default { CASE_LIST_PAUSED: "/caseList/paused", REPORT_TABLES: "/caseList/report-tables", CASE_LIST: "/caseList", + DEFAULT_COLUMNS: "/caseList/{type}/default-columns", PUT_CASE_LIST: "/caseList/{id}" }; diff --git a/resources/assets/js/admin/settings/customCaseList/CaseListSketch.vue b/resources/assets/js/admin/settings/customCaseList/CaseListSketch.vue index be8d4f598..97bf78754 100644 --- a/resources/assets/js/admin/settings/customCaseList/CaseListSketch.vue +++ b/resources/assets/js/admin/settings/customCaseList/CaseListSketch.vue @@ -367,7 +367,7 @@ export default { count: "", }, }, - defaultCaseList: null, + defaultCaseList: [], isValidName: null, isValidTable: null, pmTable: null @@ -379,8 +379,7 @@ export default { }, }, mounted() { - this.defaultCaseList = Api.getDefault(this.module.key); - this.dataCaseList = this.defaultCaseList; + this.getDefaultColumns(this.module.key); if(this.params.id) { this.editMode(); } @@ -675,6 +674,22 @@ export default { variant: variant, solid: true }) + }, + /** + * Get default Columns + * @param {string} type + */ + getDefaultColumns(type) { + let that = this; + if (!this.params.columns) { + Api.getDefault(type) + .then((response) => { + that.dataCaseList = response.data; + }) + .catch((e) => { + console.error(e); + }) + } } }, }; From 0234fcc59c2a347e4ce0743f60d96763c46a0f63 Mon Sep 17 00:00:00 2001 From: Andrea Adamczyk Date: Mon, 23 Aug 2021 15:19:23 -0400 Subject: [PATCH 33/36] PMCORE-3238 --- workflow/engine/src/ProcessMaker/BusinessModel/Cases.php | 2 +- workflow/engine/src/ProcessMaker/Model/Delegation.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/workflow/engine/src/ProcessMaker/BusinessModel/Cases.php b/workflow/engine/src/ProcessMaker/BusinessModel/Cases.php index af167f8a0..99b3829a5 100644 --- a/workflow/engine/src/ProcessMaker/BusinessModel/Cases.php +++ b/workflow/engine/src/ProcessMaker/BusinessModel/Cases.php @@ -882,7 +882,7 @@ class Cases public function participation($usrUid, $caseNumber, $index) { $userId = User::getId($usrUid); - $query = Delegation::query()->select(['APP_NUMBER'])->case($caseNumber)->index($index)->threadOpen(); + $query = Delegation::query()->select(['APP_NUMBER'])->case($caseNumber)->index($index)->openAndPause(); $query1 = clone $query; $result = $query->userId($userId)->limit(1)->get()->values()->toArray(); $permission = empty($result) ? false : true; diff --git a/workflow/engine/src/ProcessMaker/Model/Delegation.php b/workflow/engine/src/ProcessMaker/Model/Delegation.php index d0b44bf10..22d9772b3 100644 --- a/workflow/engine/src/ProcessMaker/Model/Delegation.php +++ b/workflow/engine/src/ProcessMaker/Model/Delegation.php @@ -1989,8 +1989,8 @@ class Delegation extends Model ]); // Join with task $query->joinTask(); - // Get the open threads - $query->threadOpen(); + // Get the open and paused threads + $query->openAndPause(); // Related to the specific case number $query->case($appNumber); // Get the results From f18e47519657a9c18032f3b3654be1553b67bb75 Mon Sep 17 00:00:00 2001 From: Paula Quispe Date: Thu, 19 Aug 2021 15:23:25 -0400 Subject: [PATCH 34/36] PMCORE-3104 --- .../methods/cases/CasesMenuHighlightTest.php | 8 ++-- .../BusinessModel/Cases/CasesListTest.php | 37 +++++++++++++++++++ .../methods/cases/casesMenuHighlight.php | 25 ++++--------- .../BusinessModel/Cases/AbstractCases.php | 10 +++++ .../BusinessModel/Cases/BatchRouting.php | 11 ++++++ .../BusinessModel/Cases/Canceled.php | 11 ++++++ .../BusinessModel/Cases/CasesList.php | 25 +++++++++++++ .../BusinessModel/Cases/Completed.php | 14 ++++++- .../BusinessModel/Cases/Draft.php | 18 +++++++++ .../BusinessModel/Cases/Inbox.php | 18 +++++++++ .../BusinessModel/Cases/Participated.php | 11 ++++++ .../BusinessModel/Cases/Paused.php | 18 +++++++++ .../BusinessModel/Cases/Search.php | 11 ++++++ .../BusinessModel/Cases/Supervising.php | 11 ++++++ .../BusinessModel/Cases/Unassigned.php | 18 +++++++++ .../src/ProcessMaker/Model/Application.php | 18 +++++++++ .../src/ProcessMaker/Services/Api/Home.php | 23 +++++++++++- 17 files changed, 262 insertions(+), 25 deletions(-) diff --git a/tests/unit/workflow/engine/methods/cases/CasesMenuHighlightTest.php b/tests/unit/workflow/engine/methods/cases/CasesMenuHighlightTest.php index 21333f1d1..042bc07e1 100644 --- a/tests/unit/workflow/engine/methods/cases/CasesMenuHighlightTest.php +++ b/tests/unit/workflow/engine/methods/cases/CasesMenuHighlightTest.php @@ -96,9 +96,9 @@ class CasesMenuHighlightTest extends TestCase // Check if the object is valid $this->assertNotEmpty($result); - $this->assertArrayHasKey('item', $result[0]); - $this->assertArrayHasKey('highlight', $result[0]); - $this->assertEquals('CASES_SELFSERVICE', $result[0]['item']); - $this->assertEquals(true, $result[0]['highlight']); + $this->assertArrayHasKey('item', $result[7]); + $this->assertArrayHasKey('highlight', $result[7]); + $this->assertEquals('CASES_SELFSERVICE', $result[7]['item']); + $this->assertEquals(true, $result[7]['highlight']); } } diff --git a/tests/unit/workflow/engine/src/ProcessMaker/BusinessModel/Cases/CasesListTest.php b/tests/unit/workflow/engine/src/ProcessMaker/BusinessModel/Cases/CasesListTest.php index 4711632b0..961c455bd 100644 --- a/tests/unit/workflow/engine/src/ProcessMaker/BusinessModel/Cases/CasesListTest.php +++ b/tests/unit/workflow/engine/src/ProcessMaker/BusinessModel/Cases/CasesListTest.php @@ -42,6 +42,18 @@ class CasesListTest extends TestCase return $delegation; } + /** + * This test construct + * + * @covers \ProcessMaker\BusinessModel\Cases\CasesList::__construct() + * @test + */ + public function it_test_construct() + { + $casesList = new CasesList(); + $this->assertInstanceOf(CasesList::class, $casesList); + } + /** * This test getAllCounters * @@ -57,4 +69,29 @@ class CasesListTest extends TestCase $this->assertArrayHasKey('CASES_INBOX', $result); $this->assertArrayHasKey('CASES_DRAFT', $result); } + + /** + * This test getAllCounters + * + * @covers \ProcessMaker\BusinessModel\Cases\CasesList::atLeastOne() + * @covers \ProcessMaker\BusinessModel\Cases\BatchRouting::atLeastOne() + * @covers \ProcessMaker\BusinessModel\Cases\Canceled::atLeastOne() + * @covers \ProcessMaker\BusinessModel\Cases\Completed::atLeastOne() + * @covers \ProcessMaker\BusinessModel\Cases\Draft::atLeastOne() + * @covers \ProcessMaker\BusinessModel\Cases\Inbox::atLeastOne() + * @covers \ProcessMaker\BusinessModel\Cases\Participated::atLeastOne() + * @covers \ProcessMaker\BusinessModel\Cases\Paused::atLeastOne() + * @covers \ProcessMaker\BusinessModel\Cases\Unassigned::atLeastOne() + * @test + */ + public function it_return_at_least_one() + { + $delegation = factory(Delegation::class)->states('foreign_keys')->create(); + $count = new CasesList(); + $result = $count->atLeastOne($delegation->USR_UID); + $this->assertNotEmpty($result); + $firstItem = head($result); + $this->assertArrayHasKey('item', $firstItem); + $this->assertArrayHasKey('highlight', $firstItem); + } } \ No newline at end of file diff --git a/workflow/engine/methods/cases/casesMenuHighlight.php b/workflow/engine/methods/cases/casesMenuHighlight.php index b58ab1a13..9ae2b12f0 100644 --- a/workflow/engine/methods/cases/casesMenuHighlight.php +++ b/workflow/engine/methods/cases/casesMenuHighlight.php @@ -1,27 +1,16 @@ limit(1); - $items = $query->get(); - $atLeastOne = $items->count() > 0; -} else { - $query .= " LIMIT 1"; - $items = DB::select($query); - $atLeastOne = !empty($items); -} - -// Initializing the response variable +// Get the user logged +$usrUid = $_SESSION['USER_LOGGED']; +// Instance the class +$casesList = new CasesList(); $response = []; - -// The scope for the first version of this feature is only for unassigned list, so, this value is currently fixed -$response[] = ['item' => 'CASES_SELFSERVICE', 'highlight' => $atLeastOne]; +// Get highlight for all task list +$response = $casesList->atLeastOne($usrUid); // Print the response in JSON format header('Content-Type: application/json'); diff --git a/workflow/engine/src/ProcessMaker/BusinessModel/Cases/AbstractCases.php b/workflow/engine/src/ProcessMaker/BusinessModel/Cases/AbstractCases.php index cc9d47f4d..b040b0f86 100644 --- a/workflow/engine/src/ProcessMaker/BusinessModel/Cases/AbstractCases.php +++ b/workflow/engine/src/ProcessMaker/BusinessModel/Cases/AbstractCases.php @@ -1480,6 +1480,16 @@ class AbstractCases implements CasesInterface throw new Exception("Method '" . __FUNCTION__ . "' should be implemented in the extended class '" . get_class($this) . "'."); } + /** + * Get true if the user has at least one case + * + * @throws Exception + */ + public function atLeastOne() + { + throw new Exception("Method '" . __FUNCTION__ . "' should be implemented in the extended class '" . get_class($this) . "'."); + } + /** * Get the list counter * diff --git a/workflow/engine/src/ProcessMaker/BusinessModel/Cases/BatchRouting.php b/workflow/engine/src/ProcessMaker/BusinessModel/Cases/BatchRouting.php index e095c43a6..449accfbd 100644 --- a/workflow/engine/src/ProcessMaker/BusinessModel/Cases/BatchRouting.php +++ b/workflow/engine/src/ProcessMaker/BusinessModel/Cases/BatchRouting.php @@ -56,4 +56,15 @@ class BatchRouting extends AbstractCases // Return the number of rows return $query->count(['APP_DELEGATION.APP_NUMBER']); } + + /** + * Count if the user has at least one case in the list + * + * @return bool + */ + public function atLeastOne() + { + // This class does not require this value + return false; + } } \ No newline at end of file diff --git a/workflow/engine/src/ProcessMaker/BusinessModel/Cases/Canceled.php b/workflow/engine/src/ProcessMaker/BusinessModel/Cases/Canceled.php index 3c69cf2b3..2fba4fe06 100644 --- a/workflow/engine/src/ProcessMaker/BusinessModel/Cases/Canceled.php +++ b/workflow/engine/src/ProcessMaker/BusinessModel/Cases/Canceled.php @@ -61,4 +61,15 @@ class Canceled extends AbstractCases // Return the number of rows return $query->count(['APP_DELEGATION.APP_NUMBER']); } + + /** + * Count if the user has at least one case in the list + * + * @return bool + */ + public function atLeastOne() + { + // This class does not require this value + return false; + } } diff --git a/workflow/engine/src/ProcessMaker/BusinessModel/Cases/CasesList.php b/workflow/engine/src/ProcessMaker/BusinessModel/Cases/CasesList.php index 44d3ce220..c8c45c85e 100644 --- a/workflow/engine/src/ProcessMaker/BusinessModel/Cases/CasesList.php +++ b/workflow/engine/src/ProcessMaker/BusinessModel/Cases/CasesList.php @@ -41,6 +41,7 @@ class CasesList 'inbox' => 'CASES_INBOX', 'participated' => 'CASES_SENT', 'paused' => 'CASES_PAUSED', + 'unassigned' => 'CASES_SELFSERVICE', ]; /*----------------------------------********---------------------------------*/ @@ -83,4 +84,28 @@ class CasesList return $response; } + + /** + * Count if the user has at least one case in the list + * + * @param string $usrUid + * + * @return array + */ + public function atLeastOne(string $usrUid) + { + // Get the usrId key + $usrId = User::getId($usrUid); + // Get the classes + $list = $this->mapList; + $response = []; + foreach ($list as $listObject => $item) { + $this->$listObject->setUserUid($usrUid); + $this->$listObject->setUserId($usrId); + $atLeastOne = $this->$listObject->atLeastOne($usrUid); + $response[] = ['item' => $item, 'highlight' => $atLeastOne]; + } + + return $response; + } } diff --git a/workflow/engine/src/ProcessMaker/BusinessModel/Cases/Completed.php b/workflow/engine/src/ProcessMaker/BusinessModel/Cases/Completed.php index ada994487..896817b90 100644 --- a/workflow/engine/src/ProcessMaker/BusinessModel/Cases/Completed.php +++ b/workflow/engine/src/ProcessMaker/BusinessModel/Cases/Completed.php @@ -53,8 +53,18 @@ class Completed extends AbstractCases $participated->setParticipatedStatus('COMPLETED'); $participated->setUserUid($this->getUserUid()); $participated->setUserId($this->getUserId()); - $count = $participated->getCounter(); - return $count; + return $participated->getCounter(); + } + + /** + * Count if the user has at least one case in the list + * + * @return bool + */ + public function atLeastOne() + { + // This class does not require this value + return false; } } diff --git a/workflow/engine/src/ProcessMaker/BusinessModel/Cases/Draft.php b/workflow/engine/src/ProcessMaker/BusinessModel/Cases/Draft.php index dc560506c..3238ec292 100644 --- a/workflow/engine/src/ProcessMaker/BusinessModel/Cases/Draft.php +++ b/workflow/engine/src/ProcessMaker/BusinessModel/Cases/Draft.php @@ -152,6 +152,24 @@ class Draft extends AbstractCases return $query->count(['APPLICATION.APP_NUMBER']); } + /** + * Count if the user has at least one case in the list + * + * @return bool + */ + public function atLeastOne() + { + $query = Application::query()->select(['APPLICATION.APP_NUMBER']); + // Add the initial scope for draft cases for specific user + $query->draft($this->getUserUid()); + // Get only one case + $query->limit(1); + // Get result + $items = $query->get(); + + return $items->count() > 0; + } + /** * Count how many cases the user has in DRAFT, needs to apply filters * diff --git a/workflow/engine/src/ProcessMaker/BusinessModel/Cases/Inbox.php b/workflow/engine/src/ProcessMaker/BusinessModel/Cases/Inbox.php index f31a5eb63..82de3e43f 100644 --- a/workflow/engine/src/ProcessMaker/BusinessModel/Cases/Inbox.php +++ b/workflow/engine/src/ProcessMaker/BusinessModel/Cases/Inbox.php @@ -165,6 +165,24 @@ class Inbox extends AbstractCases return $query->count(['APP_DELEGATION.APP_NUMBER']); } + /** + * Count if the user has at least one case in the list + * + * @return bool + */ + public function atLeastOne() + { + $query = Delegation::query()->select(['APP_DELEGATION.APP_NUMBER']); + // Scope that sets the queries for List Inbox for specific user + $query->inbox($this->getUserId()); + // Get only one case + $query->limit(1); + // Get the result + $items = $query->get(); + + return $items->count() > 0; + } + /** * Count how many cases the user has in TO_DO, needs to apply filters * diff --git a/workflow/engine/src/ProcessMaker/BusinessModel/Cases/Participated.php b/workflow/engine/src/ProcessMaker/BusinessModel/Cases/Participated.php index 951f18cc1..6881e6680 100644 --- a/workflow/engine/src/ProcessMaker/BusinessModel/Cases/Participated.php +++ b/workflow/engine/src/ProcessMaker/BusinessModel/Cases/Participated.php @@ -266,6 +266,17 @@ class Participated extends AbstractCases return $query->count(['APP_DELEGATION.APP_NUMBER']); } + /** + * Count if the user has at least one case in the list + * + * @return bool + */ + public function atLeastOne() + { + // This class does not require this value + return false; + } + /** * Count how many cases the user has Participation, needs to apply filters * diff --git a/workflow/engine/src/ProcessMaker/BusinessModel/Cases/Paused.php b/workflow/engine/src/ProcessMaker/BusinessModel/Cases/Paused.php index 1b920bb3f..6edcdd483 100644 --- a/workflow/engine/src/ProcessMaker/BusinessModel/Cases/Paused.php +++ b/workflow/engine/src/ProcessMaker/BusinessModel/Cases/Paused.php @@ -159,6 +159,24 @@ class Paused extends AbstractCases return $query->count(['APP_DELEGATION.APP_NUMBER']); } + /** + * Count if the user has at least one case in the list + * + * @return bool + */ + public function atLeastOne() + { + $query = Delegation::query()->select(['APP_DELEGATION.APP_NUMBER']); + // Scope that set the paused cases + $query->paused($this->getUserId()); + // Get only one case + $query->limit(1); + // Get result + $items = $query->get(); + + return $items->count() > 0; + } + /** * Count how many cases the user has in PAUSED, needs to apply filters * diff --git a/workflow/engine/src/ProcessMaker/BusinessModel/Cases/Search.php b/workflow/engine/src/ProcessMaker/BusinessModel/Cases/Search.php index 16f1cb16c..e52cc980f 100644 --- a/workflow/engine/src/ProcessMaker/BusinessModel/Cases/Search.php +++ b/workflow/engine/src/ProcessMaker/BusinessModel/Cases/Search.php @@ -215,6 +215,17 @@ class Search extends AbstractCases return 0; } + /** + * Count if the user has at least one case in the list + * + * @return bool + */ + public function atLeastOne() + { + // This class does not require this value + return false; + } + /** * Get the number of rows corresponding to the advanced search, needs to apply filters * diff --git a/workflow/engine/src/ProcessMaker/BusinessModel/Cases/Supervising.php b/workflow/engine/src/ProcessMaker/BusinessModel/Cases/Supervising.php index 1f7c08c6a..08b500421 100644 --- a/workflow/engine/src/ProcessMaker/BusinessModel/Cases/Supervising.php +++ b/workflow/engine/src/ProcessMaker/BusinessModel/Cases/Supervising.php @@ -203,6 +203,17 @@ class Supervising extends AbstractCases return $query->count(['APP_DELEGATION.APP_NUMBER']); } + /** + * Count if the user has at least one case in the list + * + * @return bool + */ + public function atLeastOne() + { + // This class does not require this value + return false; + } + /** * Count how many cases the user has in Supervising, needs to apply filters * diff --git a/workflow/engine/src/ProcessMaker/BusinessModel/Cases/Unassigned.php b/workflow/engine/src/ProcessMaker/BusinessModel/Cases/Unassigned.php index 5c86ea9c1..706849d00 100644 --- a/workflow/engine/src/ProcessMaker/BusinessModel/Cases/Unassigned.php +++ b/workflow/engine/src/ProcessMaker/BusinessModel/Cases/Unassigned.php @@ -167,6 +167,24 @@ class Unassigned extends AbstractCases return $query->count(['APP_DELEGATION.APP_NUMBER']); } + /** + * Count if the user has at least one case in the list + * + * @return bool + */ + public function atLeastOne() + { + $query = Delegation::query()->select(['APP_DELEGATION.APP_NUMBER']); + // Add the initial scope for self-service cases + $query->selfService($this->getUserUid()); + // Get only one case + $query->limit(1); + // Get result + $items = $query->get(); + + return $items->count() > 0; + } + /** * Count how many cases the user has in SELF_SERVICE, needs to apply filters * diff --git a/workflow/engine/src/ProcessMaker/Model/Application.php b/workflow/engine/src/ProcessMaker/Model/Application.php index bf89d021e..51359490e 100644 --- a/workflow/engine/src/ProcessMaker/Model/Application.php +++ b/workflow/engine/src/ProcessMaker/Model/Application.php @@ -355,6 +355,24 @@ class Application extends Model return $query; } + /** + * Scope the Draft cases + * + * @param \Illuminate\Database\Eloquent\Builder $query + * @param string $user + * + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeDraft($query, $user) + { + // Filter the status draft + $query->statusId(Application::STATUS_DRAFT); + // Filter the creator + $query->creator($user); + + return $query; + } + /** * Get Applications by PRO_UID, ordered by APP_NUMBER. * diff --git a/workflow/engine/src/ProcessMaker/Services/Api/Home.php b/workflow/engine/src/ProcessMaker/Services/Api/Home.php index e2c87f706..e03948c9c 100644 --- a/workflow/engine/src/ProcessMaker/Services/Api/Home.php +++ b/workflow/engine/src/ProcessMaker/Services/Api/Home.php @@ -6,6 +6,7 @@ use Exception; use G; use Luracast\Restler\RestException; use Menu; +use ProcessMaker\BusinessModel\Cases\CasesList; use ProcessMaker\BusinessModel\Cases\Draft; use ProcessMaker\BusinessModel\Cases\Filter; use ProcessMaker\BusinessModel\Cases\Inbox; @@ -795,7 +796,7 @@ class Home extends Api } /** - * Get the tasks counters for todo, draft, paused and unassigned + * Get the tasks counters for all task list: todo, draft, paused and unassigned * * @url GET /tasks/counter * @@ -833,6 +834,26 @@ class Home extends Api return $result; } + /** + * Get the tasks highlight for all task list + * + * @url GET /tasks/highlight + * + * @return array + * + * @access protected + * @class AccessControl {@permission PM_CASES} + */ + public function getHighlight() + { + $usrUid = $this->getUserId(); + $casesList = new CasesList(); + $result = []; + $result = $casesList->atLeastOne($usrUid); + + return $result; + } + /** * Get all tasks, paged optionally, can be sent a text to filter results by "TAS_TITLE" * From 50de512dfb1e3638edf138e7832eeec5cba93b3f Mon Sep 17 00:00:00 2001 From: fabio Date: Mon, 23 Aug 2021 20:17:07 -0400 Subject: [PATCH 35/36] PMCORE-3113:UI - Import a custom Case list JSON COrrection --- .../js/admin/Modals/ModalDeleteCaseList.vue | 6 +- .../assets/js/admin/Modals/ModalImport.vue | 187 ++++++++++++++++++ .../settings/customCaseList/Api/CaseList.js | 14 ++ .../settings/customCaseList/Api/Services.js | 3 +- .../customCaseList/CaseListSketch.vue | 17 +- .../admin/settings/customCaseList/Tables.vue | 43 +++- 6 files changed, 255 insertions(+), 15 deletions(-) create mode 100644 resources/assets/js/admin/Modals/ModalImport.vue diff --git a/resources/assets/js/admin/Modals/ModalDeleteCaseList.vue b/resources/assets/js/admin/Modals/ModalDeleteCaseList.vue index 2448a41a6..48cda9943 100644 --- a/resources/assets/js/admin/Modals/ModalDeleteCaseList.vue +++ b/resources/assets/js/admin/Modals/ModalDeleteCaseList.vue @@ -10,7 +10,7 @@

- {{ $t("ID_ARE_YOU_SURE_DELETE_CUSTOM_CASE_LIST") }} + {{ $t("ID_ARE_YOU_SURE_DELETE_CUSTOM_CASE_LIST", {'CUSTOM_NAME': data.name}) }}