From 9d2c296d329262554056db2de3de4c085134ec03 Mon Sep 17 00:00:00 2001 From: wangyidong Date: Wed, 6 Nov 2024 15:17:31 +0800 Subject: [PATCH] * [perf story #69157] Update children status by parent. --- module/task/model.php | 50 ++++++++++++++++++- module/task/tao.php | 4 +- module/task/test/lib/task.unittest.class.php | 16 ++++++ .../task/test/model/updatechildrenstatus.php | 50 +++++++++++++++++++ 4 files changed, 117 insertions(+), 3 deletions(-) create mode 100755 module/task/test/model/updatechildrenstatus.php diff --git a/module/task/model.php b/module/task/model.php index 9114934baf..c419294fa2 100755 --- a/module/task/model.php +++ b/module/task/model.php @@ -201,6 +201,7 @@ class taskModel extends model { /* Process other data. */ if($task->parent > 0) $this->updateParentStatus($task->id); + if($task->isParent) $this->updateChildrenStatus($task->id, $task->status); if($task->story) $this->loadModel('story')->setStage($task->story); $this->updateKanbanCell($task->id, $output, $task->execution); @@ -2231,7 +2232,7 @@ class taskModel extends model if($action == 'totask') return true; /* 父任务只能编辑、创建子任务和指派。 Parent task only can edit task, create children and assign to somebody. */ - if((!empty($task->isParent) || $task->parent < 0) && !in_array($action, array('edit', 'batchcreate', 'cancel', 'assignto'))) return false; + if((!empty($task->isParent) || $task->parent < 0) && !in_array($action, array('edit', 'batchcreate', 'cancel', 'assignto', 'pause', 'close', 'restart'))) return false; /* 子任务和多人任务不能创建子任务。Multi task and child task cannot create children. */ if($action == 'batchcreate' && (!empty($task->team) || $task->parent > 0)) return false; @@ -2469,6 +2470,9 @@ class taskModel extends model /* Update kanban status. */ $this->dao->update(TABLE_TASK)->data($task)->autoCheck()->checkFlow()->where('id')->eq($task->id)->exec(); + /* If task has parent task, update status of the parent task by the child task. */ + if($oldTask->isParent) $this->updateChildrenStatus($task->id); + /* If output is not empty, update kanban cell. */ $this->updateKanbanCell($task->id, $output, $oldTask->execution); @@ -3270,6 +3274,50 @@ class taskModel extends model } } + /** + * 更新子任务的状态. + * Update children status by taskID. + * + * @param int $taskID + * @param string $oldParentStatus + * @access public + * @return void + */ + public function updateChildrenStatus(int $taskID, string $oldParentStatus = '') :void + { + /* Get child task info. */ + $parentTask = $this->dao->select('id,status,isParent,parent,path')->from(TABLE_TASK)->where('id')->eq($taskID)->fetch(); + if(empty($parentTask)) return; + + $parentStatus = $parentTask->status; + if(!in_array($parentStatus, array('doing', 'pause', 'cancel', 'closed'))) return; + + $childrenTasks = $this->dao->select('*')->from(TABLE_TASK)->where('path')->like("{$parentTask->path}%")->andWhere('id')->ne($taskID)->fetchAll('id'); + if(empty($childrenTasks)) return; + + $autoActions = array(); + if($parentTask->status == 'doing' && $oldParentStatus == 'pause') $autoActions = $this->dao->select('objectID,extra')->from(TABLE_ACTION)->where('objectType')->eq("task")->andWhere('objectID')->in(array_keys($childrenTasks))->andWhere('action')->eq('paused')->orderBy('date')->fetchAll('objectID'); + + $this->loadModel('story'); + foreach($childrenTasks as $childID => $childTask) + { + if($childTask->status == $parentStatus) continue; + if($parentStatus == 'pause' && $childTask->status != 'doing') continue; + if($parentStatus == 'cancel' && in_array($childTask->status, array('done', 'closed'))) continue; + if($parentStatus == 'doing' && $childTask->status != 'pause') continue; + if(isset($autoActions[$childID]) && $autoActions[$childID]->extra != 'auto') continue; + + $this->taskTao->autoUpdateTaskByStatus($childTask, null, $parentStatus); + if(dao::isError()) return; + + if($childTask->story) $this->story->setStage($childTask->story); + + /* Create action record. */ + $this->taskTao->createAutoUpdateTaskAction($childTask); + if($this->config->edition != 'open' && $childTask->feedback) $this->loadModel('feedback')->updateStatus('task', $childTask->feedback, $status, $childTask->status); + } + } + /** * 更新团队信息。 * Update team. diff --git a/module/task/tao.php b/module/task/tao.php index f9d877d77c..f6d6235fdd 100644 --- a/module/task/tao.php +++ b/module/task/tao.php @@ -999,7 +999,7 @@ class taskTao extends taskModel * @access protected * @return void */ - protected function autoUpdateTaskByStatus(object $task, object $childTask, string $status) :void + protected function autoUpdateTaskByStatus(object $task, object|null $childTask, string $status) :void { $now = helper::now(); $account = $this->app->user->account; @@ -1037,7 +1037,7 @@ class taskTao extends taskModel { if($task->assignedTo == 'closed') { - $data->assignedTo = $childTask->assignedTo; + $data->assignedTo = !empty($childTask) ? $childTask->assignedTo : $task->openedBy; $data->assignedDate = $now; } diff --git a/module/task/test/lib/task.unittest.class.php b/module/task/test/lib/task.unittest.class.php index 3830330882..b095d0b74b 100755 --- a/module/task/test/lib/task.unittest.class.php +++ b/module/task/test/lib/task.unittest.class.php @@ -963,6 +963,22 @@ class taskTest } } + public function updateChildrenStatusTest($taskID, $status) + { + $task = $this->objectModel->dao->select('*')->from(TABLE_TASK)->where('id')->eq($taskID)->fetch(); + $this->objectModel->dao->update(TABLE_TASK)->set('status')->eq($status)->where('id')->eq($taskID)->exec(); + $this->objectModel->updateChildrenStatus($taskID, empty($task) ? '' : $task->status); + if(empty($taskID)) return 0; + + $child = $this->objectModel->dao->select('*')->from(TABLE_TASK)->where('parent')->eq($taskID)->fetch(); + if(empty($child)) return 0; + + $action = $this->objectModel->dao->select('*')->from(TABLE_ACTION)->where('objectType')->eq('task')->andWhere('objectID')->eq($child->id)->orderBy('id_desc')->limit(1)->fetch(); + $child->action = $action->action; + $child->extra = $action->extra; + return $child; + } + /** * Test judge an action is clickable or not. * diff --git a/module/task/test/model/updatechildrenstatus.php b/module/task/test/model/updatechildrenstatus.php new file mode 100755 index 0000000000..729b10a2fe --- /dev/null +++ b/module/task/test/model/updatechildrenstatus.php @@ -0,0 +1,50 @@ +#!/usr/bin/env php +updateChildrenStatus(); +timeout=0 +cid=1 + +*/ + +zenData('user')->loadYaml('user')->gen(3); +zenData('project')->loadYaml('project')->gen(3); +zenData('task')->loadYaml('task')->gen(9); + +su('user1'); +$_SERVER['HTTP_HOST'] = 'pms.zentao.com'; +$task = new taskTest(); + +$task->objectModel->dao->update(TABLE_TASK)->set("path = concat(',', id, ',')")->exec(); +$task->objectModel->dao->update(TABLE_TASK)->set("path = concat(',', parent, ',', id, ',')")->where('parent')->gt('0')->exec(); +$task->objectModel->dao->update(TABLE_TASK)->set('isParent')->eq('1')->where('parent')->eq('-1')->exec(); +$task->objectModel->dao->update(TABLE_TASK)->set('parent')->eq('0')->where('parent')->eq('-1')->exec(); + +r($task->updateChildrenStatusTest(0, 'pause')) && p() && e('0'); //任务参数为空 +r($task->updateChildrenStatusTest(1, 'pause')) && p() && e('0'); //不是父任务 +r($task->updateChildrenStatusTest(10, 'pause')) && p() && e('0'); //任务不存在 + +$task->objectModel->dao->update(TABLE_TASK)->set('status')->eq('wait')->where('id')->eq(7)->exec(); +r($task->updateChildrenStatusTest(6, 'pause')) && p('id,status') && e('7,wait'); //子任务的状态为wait,父任务的状态为pause,不更新子任务 + +$task->objectModel->dao->update(TABLE_TASK)->set('status')->eq('done')->where('id')->eq(7)->exec(); +r($task->updateChildrenStatusTest(6, 'pause')) && p('id,status') && e('7,done'); //子任务的状态为done,父任务的状态为pause,不更新子任务 + +$task->objectModel->dao->update(TABLE_TASK)->set('status')->eq('cancel')->where('id')->eq(7)->exec(); +r($task->updateChildrenStatusTest(6, 'pause')) && p('id,status') && e('7,cancel'); //子任务的状态为cancel,父任务的状态为pause,不更新子任务 + +$task->objectModel->dao->update(TABLE_TASK)->set('status')->eq('closed')->where('id')->eq(7)->exec(); +r($task->updateChildrenStatusTest(6, 'pause')) && p('id,status') && e('7,closed'); //子任务的状态为closed,父任务的状态为pause,不更新子任务 + +$task->objectModel->dao->update(TABLE_TASK)->set('status')->eq('doing')->where('id')->eq(7)->exec(); +r($task->updateChildrenStatusTest(6, 'pause')) && p('id,status,action,extra') && e('7,pause,paused,auto'); //子任务的状态为doing,父任务的状态为pause,更新子任务 + +$task->objectModel->dao->update(TABLE_ACTION)->set('extra')->eq('')->where('objectType')->eq('task')->andWhere('objectID')->eq(7)->exec(); +r($task->updateChildrenStatusTest(6, 'doing')) && p('id,status') && e('7,pause'); //子任务的状态为pause,父任务的状态为doing,不是自动暂停任务,不更新子任务 + +$task->objectModel->dao->update(TABLE_ACTION)->set('extra')->eq('auto')->where('objectType')->eq('task')->andWhere('objectID')->eq(7)->andWhere('action')->eq('paused')->exec(); +r($task->updateChildrenStatusTest(6, 'doing')) && p('id,status,action,extra') && e('7,doing,restarted,auto'); //子任务的状态为pause,父任务的状态为doing,自动暂停任务,更新子任务