diff --git a/db/update18.1.sql b/db/update18.1.sql index 0f4b3dd000..aee37886fb 100644 --- a/db/update18.1.sql +++ b/db/update18.1.sql @@ -28,3 +28,37 @@ UPDATE `zt_activity` SET `order` = `id` * 5 WHERE `order` = '0'; ALTER table `zt_cmcl` ADD `projectType` varchar(255) NOT NULL DEFAULT '' AFTER `type`; UPDATE `zt_cmcl` SET `projectType` = 'waterfall' WHERE `projectType` = ''; + +REPLACE INTO `zt_process` (`model`, `name`, `type`, `abbr`, `desc`, `assignedTo`, `status`, `order`, `createdBy`, `createdDate`, `editedBy`, `editedDate`, `assignedBy`, `assignedDate`, `deleted`) VALUES +('waterfallplus', '立项管理', 'project', 'PIM', '', '', '', 55, 'admin', '2020-01-09 10:29:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +('waterfallplus', '项目规划', 'project', 'PP', '', '', '', 60, 'admin', '2020-01-09 10:31:16', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +('waterfallplus', '项目监控', 'project', 'PMC', '', '', '', 65, 'admin', '2020-01-09 10:31:16', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +('waterfallplus', '风险管理', 'project', 'RSKM', '', '', '', 70, 'admin', '2020-01-09 10:31:16', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +('waterfallplus', '结项管理', 'project', 'PCM', '', '', '', 75, 'admin', '2020-01-09 10:31:16', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +('waterfallplus', '量化项目管理', 'project', 'QPM', '', '', '', 80, 'admin', '2020-01-09 10:31:16', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +('waterfallplus', '需求开发', 'engineering', 'RDM', '', '', '', 85, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +('waterfallplus', '设计开发', 'engineering', '', '', '', '', 90, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +('waterfallplus', '实现与测试', 'engineering', 'EMBEDDED', '', '', '', 95, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +('waterfallplus', '系统测试', 'engineering', 'ST', '', '', '', 100, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +('waterfallplus', '客户验收', 'engineering', 'CA', '', '', '', 105, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +('waterfallplus', '质量保证', 'support', 'QA', '', '', '', 110, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +('waterfallplus', '配置管理', 'support', 'CM', '', '', '', 115, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +('waterfallplus', '度量分析', 'support', 'MA', '', '', '', 120, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +('waterfallplus', '原因分析与解决', 'support', 'CAR', '', '', '', 125, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +('waterfallplus', '决策分析', 'support', 'DAR', '', '', '', 130, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +('agileplus', '立项管理', 'project', 'PIM', '', '', '', 55, 'admin', '2020-01-09 10:29:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +('agileplus', '项目规划', 'project', 'PP', '', '', '', 60, 'admin', '2020-01-09 10:31:16', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +('agileplus', '项目监控', 'project', 'PMC', '', '', '', 65, 'admin', '2020-01-09 10:31:16', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +('agileplus', '风险管理', 'project', 'RSKM', '', '', '', 70, 'admin', '2020-01-09 10:31:16', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +('agileplus', '结项管理', 'project', 'PCM', '', '', '', 75, 'admin', '2020-01-09 10:31:16', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +('agileplus', '量化项目管理', 'project', 'QPM', '', '', '', 80, 'admin', '2020-01-09 10:31:16', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +('agileplus', '需求开发', 'engineering', 'RDM', '', '', '', 85, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +('agileplus', '设计开发', 'engineering', '', '', '', '', 90, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +('agileplus', '实现与测试', 'engineering', 'EMBEDDED', '', '', '', 95, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +('agileplus', '系统测试', 'engineering', 'ST', '', '', '', 100, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +('agileplus', '客户验收', 'engineering', 'CA', '', '', '', 105, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +('agileplus', '质量保证', 'support', 'QA', '', '', '', 110, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +('agileplus', '配置管理', 'support', 'CM', '', '', '', 115, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +('agileplus', '度量分析', 'support', 'MA', '', '', '', 120, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +('agileplus', '原因分析与解决', 'support', 'CAR', '', '', '', 125, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +('agileplus', '决策分析', 'support', 'DAR', '', '', '', 130, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'); diff --git a/db/zentao.sql b/db/zentao.sql index 9abe206715..2eebc0eebf 100755 --- a/db/zentao.sql +++ b/db/zentao.sql @@ -13305,7 +13305,39 @@ REPLACE INTO `zt_process` (`id`, `model`, `name`, `type`, `abbr`, `desc`, `assig (29, 'scrum', '项目监控', 'project', 'PMC', '', '', '', 65, 'admin', '2020-01-09 10:31:16', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), (28, 'scrum', '项目规划', 'project', 'PP', '', '', '', 60, 'admin', '2020-01-09 10:31:16', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), (27, 'scrum', '立项管理', 'project', 'PIM', '', '', '', 55, 'admin', '2020-01-09 10:29:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), -(42, 'scrum', '决策分析', 'support', 'DAR', '', '', '', 130, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'); +(42, 'scrum', '决策分析', 'support', 'DAR', '', '', '', 130, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +(43, 'waterfallplus', '立项管理', 'project', 'PIM', '', '', '', 55, 'admin', '2020-01-09 10:29:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +(44, 'waterfallplus', '项目规划', 'project', 'PP', '', '', '', 60, 'admin', '2020-01-09 10:31:16', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +(45, 'waterfallplus', '项目监控', 'project', 'PMC', '', '', '', 65, 'admin', '2020-01-09 10:31:16', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +(46, 'waterfallplus', '风险管理', 'project', 'RSKM', '', '', '', 70, 'admin', '2020-01-09 10:31:16', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +(47, 'waterfallplus', '结项管理', 'project', 'PCM', '', '', '', 75, 'admin', '2020-01-09 10:31:16', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +(48, 'waterfallplus', '量化项目管理', 'project', 'QPM', '', '', '', 80, 'admin', '2020-01-09 10:31:16', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +(49, 'waterfallplus', '需求开发', 'engineering', 'RDM', '', '', '', 85, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +(50, 'waterfallplus', '设计开发', 'engineering', '', '', '', '', 90, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +(51, 'waterfallplus', '实现与测试', 'engineering', 'EMBEDDED', '', '', '', 95, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +(52, 'waterfallplus', '系统测试', 'engineering', 'ST', '', '', '', 100, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +(53, 'waterfallplus', '客户验收', 'engineering', 'CA', '', '', '', 105, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +(54, 'waterfallplus', '质量保证', 'support', 'QA', '', '', '', 110, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +(55, 'waterfallplus', '配置管理', 'support', 'CM', '', '', '', 115, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +(56, 'waterfallplus', '度量分析', 'support', 'MA', '', '', '', 120, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +(57, 'waterfallplus', '原因分析与解决', 'support', 'CAR', '', '', '', 125, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +(58, 'waterfallplus', '决策分析', 'support', 'DAR', '', '', '', 130, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +(59, 'agileplus', '立项管理', 'project', 'PIM', '', '', '', 55, 'admin', '2020-01-09 10:29:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +(60, 'agileplus', '项目规划', 'project', 'PP', '', '', '', 60, 'admin', '2020-01-09 10:31:16', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +(61, 'agileplus', '项目监控', 'project', 'PMC', '', '', '', 65, 'admin', '2020-01-09 10:31:16', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +(62, 'agileplus', '风险管理', 'project', 'RSKM', '', '', '', 70, 'admin', '2020-01-09 10:31:16', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +(63, 'agileplus', '结项管理', 'project', 'PCM', '', '', '', 75, 'admin', '2020-01-09 10:31:16', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +(64, 'agileplus', '量化项目管理', 'project', 'QPM', '', '', '', 80, 'admin', '2020-01-09 10:31:16', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +(65, 'agileplus', '需求开发', 'engineering', 'RDM', '', '', '', 85, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +(66, 'agileplus', '设计开发', 'engineering', '', '', '', '', 90, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +(67, 'agileplus', '实现与测试', 'engineering', 'EMBEDDED', '', '', '', 95, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +(68, 'agileplus', '系统测试', 'engineering', 'ST', '', '', '', 100, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +(69, 'agileplus', '客户验收', 'engineering', 'CA', '', '', '', 105, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +(70, 'agileplus', '质量保证', 'support', 'QA', '', '', '', 110, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +(71, 'agileplus', '配置管理', 'support', 'CM', '', '', '', 115, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +(72, 'agileplus', '度量分析', 'support', 'MA', '', '', '', 120, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +(73, 'agileplus', '原因分析与解决', 'support', 'CAR', '', '', '', 125, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'), +(74, 'agileplus', '决策分析', 'support', 'DAR', '', '', '', 130, 'admin', '2020-01-09 13:14:55', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '0'); REPLACE INTO `zt_activity` (`id`, `process`, `name`, `optional`, `tailorNorm`, `content`, `assignedTo`, `status`, `createdBy`, `createdDate`, `editedBy`, `editedDate`, `assignedBy`, `assignedDate`, `order`, `deleted`) VALUES diff --git a/module/bug/model.php b/module/bug/model.php index 936ac36e97..119d5e1bb7 100644 --- a/module/bug/model.php +++ b/module/bug/model.php @@ -3704,6 +3704,11 @@ class bugModel extends model if($type == 'view' && $this->app->tab != 'product') { $tab = $this->app->tab == 'qa' ? 'product' : $this->app->tab; + if($tab == 'product') + { + $product = $this->loadModel('product')->getByID($bug->product); + if(!empty($product->shadow)) $tab = 'project'; + } $menu .= $this->buildMenu('bug', 'toStory', $toStoryParams, $bug, $type, $this->lang->icons['story'], '', '', '', "data-app='$tab' id='tostory'", $this->lang->bug->toStory); if(common::hasPriv('task', 'create') and !isonlybody()) $menu .= html::a('#toTask', "{$this->lang->bug->toTask}", '', "data-app='qa' data-toggle='modal' class='btn btn-link'"); $menu .= $this->buildMenu('bug', 'createCase', $convertParams, $bug, $type, 'sitemap'); diff --git a/module/common/model.php b/module/common/model.php index 095640bbb9..8b909187c6 100644 --- a/module/common/model.php +++ b/module/common/model.php @@ -1796,8 +1796,12 @@ EOD; $executionPairs = array(); $userCondition = !$app->user->admin ? " AND `id` " . helper::dbIN($app->user->view->sprints) : ''; $orderBy = $object->type == 'stage' ? 'ORDER BY `id` ASC' : 'ORDER BY `id` DESC'; + $executionList = $app->dbh->query("SELECT id,name,parent,project FROM " . TABLE_EXECUTION . " WHERE `project` = '{$object->project}' AND `deleted` = '0' $userCondition $orderBy")->fetchAll(); - $executionList = $app->control->loadModel('execution')->resetExecutionSorts($executionList); + $executions = array(); + foreach($executionList as $execution) $executions[$execution->id] = $execution; + + $executionList = $app->control->loadModel('execution')->resetExecutionSorts($executions); foreach($executionList as $execution) { if(isset($executionPairs[$execution->parent])) unset($executionPairs[$execution->parent]); diff --git a/module/execution/control.php b/module/execution/control.php index 9dcebbcacf..0cc50cc321 100644 --- a/module/execution/control.php +++ b/module/execution/control.php @@ -2615,19 +2615,26 @@ class execution extends control $execution = $this->commonAction($executionID); if($execution->type != 'kanban') return print(js::locate(inlink('view', "executionID=$executionID"))); - if($execution->lifetime == 'ops' or in_array($execution->attribute, array('request', 'review'))) - { - $browseType = 'task'; - unset($this->lang->kanban->group->task['story']); - } - /* Set Session. */ $this->session->set('execGroupBy', $groupBy); $this->session->set('storyList', $this->app->getURI(true), 'execution'); $this->session->set('rdSearchValue', ''); $this->session->set('execLaneType', $browseType); - $kanbanData = $this->loadModel('kanban')->getRDKanban($executionID, $browseType, $orderBy, 0, $groupBy); + $features = $this->execution->getExecutionFeatures($execution); + $kanbanData = $this->loadModel('kanban')->getRDKanban($executionID, $browseType, $orderBy, 0, $groupBy); + + /* Remove lanes if no feature. */ + foreach($kanbanData as $regionID => $region) + { + foreach($region->groups as $groupID => $group) + { + if(!$features['story'] and $group->lanes[0]->type == 'story') unset($kanbanData[$regionID]->groups[$groupID]); + if(!$features['qa'] and $group->lanes[0]->type == 'bug') unset($kanbanData[$regionID]->groups[$groupID]); + } + $kanbanData[$regionID]->groups = array_values($kanbanData[$regionID]->groups); + } + $executionActions = array(); foreach($this->config->execution->statusActions as $action) { @@ -2688,6 +2695,7 @@ class execution extends control $this->view->projectID = $projectID; $this->view->project = $this->loadModel('project')->getByID($projectID); $this->view->allPlans = $allPlans; + $this->view->features = $features; $this->view->kanbanData = $kanbanData; $this->view->executionActions = $executionActions; $this->view->kanban = $this->lang->execution->kanban; @@ -2744,7 +2752,7 @@ class execution extends control /* Show lanes of the attribute: no story&bug in request, no bug in design. */ if(!isset($this->lang->execution->menu->story)) unset($kanbanGroup['story']); - if(!isset($this->lang->execution->menu->qa)) unset($kanbanGroup['bug']); + if(!isset($this->lang->execution->menu->qa)) unset($kanbanGroup['bug']); /* Determines whether an object is editable. */ $canBeChanged = common::canModify('execution', $execution); @@ -2783,6 +2791,7 @@ class execution extends control $this->view->productNum = count($products); $this->view->allPlans = $allPlans; $this->view->browseType = $browseType; + $this->view->features = $this->execution->getExecutionFeatures($execution); $this->view->kanbanGroup = $kanbanGroup; $this->view->execution = $execution; $this->view->groupBy = $groupBy; @@ -3179,6 +3188,9 @@ class execution extends control $this->loadModel('product'); $execution = $this->execution->getById($executionID); + $project = $this->loadModel('project')->getByID($execution->project); + if(!$project->hasProduct) return print(js::error($this->lang->project->cannotManageProducts) . js::locate('back')); + if($project->model == 'waterfall' or $project->model == 'waterfallplus') return print(js::error(sprintf($this->lang->execution->cannotManageProducts, zget($this->lang->project->modelList, $project->model))) . js::locate('back')); if(!empty($_POST)) { diff --git a/module/execution/css/batchedit.css b/module/execution/css/batchedit.css index 604452605e..76393a2f7f 100644 --- a/module/execution/css/batchedit.css +++ b/module/execution/css/batchedit.css @@ -1,7 +1,7 @@ .c-id {width: 50px;} .c-team-name {width: 120px;} .c-project, .c-user, .c-code, .c-desc, .c-days {width: 150px;} -.c-method {width: 45px;} +.c-method {width: 70px;} .c-type > .icon-help {vertical-align: text-top;} .c-type > .popover .popover-content {font-weight: 400;} #executionForm tbody td {vertical-align: top;} diff --git a/module/execution/css/batchedit.en.css b/module/execution/css/batchedit.en.css index d4858d89b7..855a234699 100644 --- a/module/execution/css/batchedit.en.css +++ b/module/execution/css/batchedit.en.css @@ -1,4 +1,4 @@ .c-user {width: 150px !important;} .c-date {width: 125px;} -.c-method {width: 60px;} +.c-method {width: 145px;} .c-type {width: 130px;} diff --git a/module/execution/css/edit.css b/module/execution/css/edit.css index 69e41e254b..b02143f914 100644 --- a/module/execution/css/edit.css +++ b/module/execution/css/edit.css @@ -9,3 +9,5 @@ .form-date {min-width: 90px;} .productsBox div[id^='branch'].chosen-disabled {pointer-events: none;} + +#dataform th.c-name, #dataform th.c-projectName, #dataform th.c-method {width: 120px;} diff --git a/module/execution/css/edit.en.css b/module/execution/css/edit.en.css new file mode 100644 index 0000000000..89aae150fd --- /dev/null +++ b/module/execution/css/edit.en.css @@ -0,0 +1 @@ +#dataform th.c-method {width: 150px;} diff --git a/module/execution/lang/de.php b/module/execution/lang/de.php index 5dc2bca421..469f940368 100644 --- a/module/execution/lang/de.php +++ b/module/execution/lang/de.php @@ -139,7 +139,7 @@ $lang->execution->kanbanNoLinkProduct = "Kanban not linked {$lang->productCommon $lang->execution->myTask = "My Task"; $lang->execution->list = "{$lang->executionCommon} List"; $lang->execution->allProject = 'All'; -$lang->execution->method = 'Method'; +$lang->execution->method = 'Management Method'; $lang->execution->sameAsParent = "Same as parent"; /* Fields of zt_team. */ @@ -398,7 +398,7 @@ $lang->execution->errorCommonBegin = 'The start date of ' . $lang->e $lang->execution->errorCommonEnd = 'The deadline of ' . $lang->executionCommon . ' should be ≤ the deadline of project : %s.'; $lang->execution->errorLetterParent = 'The begin cannot be less than the begin of the parent stage to which it belongs: %s.'; $lang->execution->errorGreaterParent = 'The end cannot be greater than the end of the parent stage to which it belongs:%s.'; -$lang->execution->errorNameRepeat = 'Child stages of the same parent stage cannot have the same name.'; +$lang->execution->errorNameRepeat = "Child %s of the same parent stage cannot have the same name."; $lang->execution->errorAttrMatch = "Parent stage's attribute is [%s], the attribute needs to be consistent with the parent stage."; $lang->execution->errorLetterPlan = "『%s』cannot be less than the plan start time『%s』。"; $lang->execution->accessDenied = "Zugriff zu {$lang->executionCommon} verweigert!"; @@ -430,6 +430,7 @@ $lang->execution->hasStartedTaskOrSubStage = "Tasks or subphases under %s %s $lang->execution->hasSuspendedOrClosedChildren = "The sub-stages under stage %s are not all suspended or closed, cannot be modified, and have been filtered."; $lang->execution->hasNotClosedChildren = "The sub-stages under stage %s are not all closed, cannot be modified, and have been filtered."; $lang->execution->hasStartedTask = "The task under %s %s has already started, cannot be modified, and has been filtered."; +$lang->execution->cannotManageProducts = 'The ' . strtolower($lang->project->common). ' model of this ' . strtolower($lang->execution->common) . " is %s and this " . strtolower($lang->execution->common) . ' cannot be associated with products.'; /* Statistics. */ $lang->execution->charts = new stdclass(); diff --git a/module/execution/lang/en.php b/module/execution/lang/en.php index cf490b0dad..f1497a58f6 100644 --- a/module/execution/lang/en.php +++ b/module/execution/lang/en.php @@ -139,7 +139,7 @@ $lang->execution->kanbanNoLinkProduct = "Kanban not linked {$lang->productCommon $lang->execution->myTask = "My Task"; $lang->execution->list = 'List'; $lang->execution->allProject = 'All'; -$lang->execution->method = 'Method'; +$lang->execution->method = 'Management Method'; $lang->execution->sameAsParent = "Same as parent"; /* Fields of zt_team. */ @@ -398,7 +398,7 @@ $lang->execution->errorCommonBegin = 'The start date of ' . $lang->e $lang->execution->errorCommonEnd = 'The deadline of ' . $lang->executionCommon . ' should be ≤ the deadline of project : %s.'; $lang->execution->errorLetterParent = 'The begin cannot be less than the begin of the parent stage to which it belongs: %s.'; $lang->execution->errorGreaterParent = 'The end cannot be greater than the end of the parent stage to which it belongs:%s.'; -$lang->execution->errorNameRepeat = 'Child stages of the same parent stage cannot have the same name.'; +$lang->execution->errorNameRepeat = "Child %s of the same parent stage cannot have the same name."; $lang->execution->errorAttrMatch = "Parent stage's attribute is [%s], the attribute needs to be consistent with the parent stage."; $lang->execution->errorLetterPlan = "『%s』cannot be less than the plan start time『%s』。"; $lang->execution->accessDenied = "Your access to {$lang->executionCommon} is denied!"; @@ -430,6 +430,7 @@ $lang->execution->hasStartedTaskOrSubStage = "Tasks or subphases under %s %s $lang->execution->hasSuspendedOrClosedChildren = "The sub-stages under stage %s are not all suspended or closed, cannot be modified, and have been filtered."; $lang->execution->hasNotClosedChildren = "The sub-stages under stage %s are not all closed, cannot be modified, and have been filtered."; $lang->execution->hasStartedTask = "The task under %s %s has already started, cannot be modified, and has been filtered."; +$lang->execution->cannotManageProducts = 'The ' . strtolower($lang->project->common). ' model of this ' . strtolower($lang->execution->common) . " is %s and this " . strtolower($lang->execution->common) . ' cannot be associated with products.'; /* Statistics. */ $lang->execution->charts = new stdclass(); diff --git a/module/execution/lang/fr.php b/module/execution/lang/fr.php index d6292d3b82..abdc8a5b61 100644 --- a/module/execution/lang/fr.php +++ b/module/execution/lang/fr.php @@ -139,7 +139,7 @@ $lang->execution->kanbanNoLinkProduct = "Kanban not linked {$lang->productCommon $lang->execution->myTask = "My Task"; $lang->execution->list = "{$lang->executionCommon} List"; $lang->execution->allProject = 'Tous'; -$lang->execution->method = 'Method'; +$lang->execution->method = 'Management Method'; $lang->execution->sameAsParent = "Same as parent"; /* Fields of zt_team. */ @@ -398,7 +398,7 @@ $lang->execution->errorCommonBegin = 'The start date of ' . $lang->e $lang->execution->errorCommonEnd = 'The deadline of ' . $lang->executionCommon . ' should be ≤ the deadline of project : %s.'; $lang->execution->errorLetterParent = 'The begin cannot be less than the begin of the parent stage to which it belongs: %s.'; $lang->execution->errorGreaterParent = 'The end cannot be greater than the end of the parent stage to which it belongs:%s.'; -$lang->execution->errorNameRepeat = 'Child stages of the same parent stage cannot have the same name.'; +$lang->execution->errorNameRepeat = "Child %s of the same parent stage cannot have the same name."; $lang->execution->errorAttrMatch = "Parent stage's attribute is [%s], the attribute needs to be consistent with the parent stage."; $lang->execution->errorLetterPlan = "『%s』cannot be less than the plan start time『%s』。"; $lang->execution->accessDenied = "Votre accès au {$lang->executionCommon} est refusé ! Désolé."; @@ -430,6 +430,7 @@ $lang->execution->hasStartedTaskOrSubStage = "Tasks or subphases under %s %s $lang->execution->hasSuspendedOrClosedChildren = "The sub-stages under stage %s are not all suspended or closed, cannot be modified, and have been filtered."; $lang->execution->hasNotClosedChildren = "The sub-stages under stage %s are not all closed, cannot be modified, and have been filtered."; $lang->execution->hasStartedTask = "The task under %s %s has already started, cannot be modified, and has been filtered."; +$lang->execution->cannotManageProducts = 'The ' . strtolower($lang->project->common). ' model of this ' . strtolower($lang->execution->common) . " is %s and this " . strtolower($lang->execution->common) . ' cannot be associated with products.'; /* Statistics. */ $lang->execution->charts = new stdclass(); diff --git a/module/execution/lang/zh-cn.php b/module/execution/lang/zh-cn.php index 1096af7cc8..b1d7168093 100644 --- a/module/execution/lang/zh-cn.php +++ b/module/execution/lang/zh-cn.php @@ -139,7 +139,7 @@ $lang->execution->kanbanNoLinkProduct = "看板没有关联{$lang->productCommon $lang->execution->myTask = "我的任务"; $lang->execution->list = '列表'; $lang->execution->allProject = '全部项目'; -$lang->execution->method = '方法'; +$lang->execution->method = '管理方法'; $lang->execution->sameAsParent = "同父阶段"; /* Fields of zt_team. */ @@ -398,7 +398,7 @@ $lang->execution->errorCommonBegin = $lang->executionCommon . '开 $lang->execution->errorCommonEnd = $lang->executionCommon . '截止日期应小于等于项目的截止日期:%s。'; $lang->execution->errorLetterParent = '计划开始时间不能小于所属父阶段的计划开始时间:%s。'; $lang->execution->errorGreaterParent = '计划完成时间不能大于所属父阶段的计划完成时间:%s。'; -$lang->execution->errorNameRepeat = '相同父阶段的子阶段名称不能相同'; +$lang->execution->errorNameRepeat = "相同父阶段的子%s名称不能相同"; $lang->execution->errorAttrMatch = "父阶段类型为[%s],阶段类型需与父阶段一致"; $lang->execution->errorLetterPlan = "『%s』应当不小于计划开始时间『%s』。"; $lang->execution->accessDenied = "您无权访问该{$lang->executionCommon}!"; @@ -430,6 +430,7 @@ $lang->execution->hasStartedTaskOrSubStage = "%s%s下的任务或子阶段 $lang->execution->hasSuspendedOrClosedChildren = "阶段%s下的子阶段未全部挂起或关闭,无法修改,已过滤。"; $lang->execution->hasNotClosedChildren = "阶段%s下的子阶段未全部关闭,无法修改,已过滤。"; $lang->execution->hasStartedTask = "%s%s下的任务已经开始,无法修改,已过滤。"; +$lang->execution->cannotManageProducts = "当前{$lang->execution->common}的{$lang->project->common}为%s{$lang->project->common},不能关联产品。"; /* 统计。*/ $lang->execution->charts = new stdclass(); diff --git a/module/execution/model.php b/module/execution/model.php index d156eafa60..44a6cf11c9 100755 --- a/module/execution/model.php +++ b/module/execution/model.php @@ -50,6 +50,44 @@ class executionModel extends model return print(js::locate(helper::createLink('execution', 'all'))); } + /** + * Get features of execution. + * + * @param object $execution + * @access public + * @return array + */ + public function getExecutionFeatures($execution) + { + $features = array('story' => true, 'task' => true, 'qa' => true, 'devops' => true, 'burn' => true, 'build' => true, 'other' => true); + + /* Unset story, bug, build and testtask if type is ops. */ + if($execution->lifetime == 'ops') + { + $features['story'] = false; + $features['qa'] = false; + $features['build'] = false; + $features['burn'] = false; + } + elseif(!empty($execution->attribute)) + { + $features['other'] = false; + if(in_array($execution->attribute, array('request', 'design', 'review'))) + { + $features['qa'] = false; + $features['devops'] = false; + $features['build'] = false; + + if(in_array($execution->attribute, array('request', 'review'))) + { + $features['story'] = false; + } + } + } + + return $features; + } + /** * Set menu. * @@ -105,30 +143,16 @@ class executionModel extends model if(isset($execution->acl) and $execution->acl != 'private') unset($this->lang->execution->menu->settings['subMenu']->whitelist); - /* Unset story, bug, build and testtask if type is ops. */ - if($execution and $execution->lifetime == 'ops') - { - unset($this->lang->execution->menu->story); - unset($this->lang->execution->menu->qa); - unset($this->lang->execution->menu->build); - unset($this->lang->execution->menu->burn); - } - - $stageFilter = array('request', 'design', 'review'); - if(isset($execution->attribute) and in_array($execution->attribute, $stageFilter)) - { - if(in_array($execution->attribute, array('request', 'review'))) - { - unset($this->lang->execution->menu->story); - unset($this->lang->execution->menu->view['subMenu']->groupTask); - unset($this->lang->execution->menu->view['subMenu']->tree); - unset($this->lang->execution->menu->other); - } - - unset($this->lang->execution->menu->devops); - unset($this->lang->execution->menu->qa); - unset($this->lang->execution->menu->build); - } + /* Redjust menus. */ + $features = $this->getExecutionFeatures($execution); + if(!$features['story']) unset($this->lang->execution->menu->story); + if(!$features['story']) unset($this->lang->execution->menu->view['subMenu']->groupTask); + if(!$features['story']) unset($this->lang->execution->menu->view['subMenu']->tree); + if(!$features['qa']) unset($this->lang->execution->menu->qa); + if(!$features['devops']) unset($this->lang->execution->menu->devops); + if(!$features['build']) unset($this->lang->execution->menu->build); + if(!$features['burn']) unset($this->lang->execution->menu->burn); + if(!$features['other']) unset($this->lang->execution->menu->other); if($executions and (!isset($executions[$executionID]) or !$this->checkPriv($executionID))) $this->accessDenied(); @@ -383,6 +407,7 @@ class executionModel extends model ->setDefault('openedVersion', $this->config->version) ->setDefault('lastEditedBy', $this->app->user->account) ->setDefault('lastEditedDate', helper::now()) + ->setDefault('days', '0') ->setDefault('team', $this->post->name) ->setDefault('parent', $this->post->project) ->setIF($this->post->parent, 'parent', $this->post->parent) @@ -448,7 +473,7 @@ class executionModel extends model ->checkIF($sprint->end != '', 'end', 'ge', $sprint->begin) ->checkFlow() ->exec(); - + /* Add the creater to the team. */ if(!dao::isError()) { @@ -573,6 +598,7 @@ class executionModel extends model ->setIF($this->post->status == 'closed' and $oldExecution->status != 'closed', 'closedDate', helper::now()) ->setIF($this->post->status == 'suspended' and $oldExecution->status != 'suspended', 'suspendedDate', helper::today()) ->setIF($oldExecution->type == 'stage', 'project', $oldExecution->project) + ->setDefault('days', '0') ->setDefault('team', $this->post->name) ->join('whitelist', ',') ->stripTags($this->config->execution->editor->edit['id'], $this->config->allowedTags) @@ -719,6 +745,7 @@ class executionModel extends model { $this->loadModel('user'); $this->loadModel('project'); + $this->app->loadLang('programplan'); $executions = array(); $allChanges = array(); @@ -770,10 +797,10 @@ class executionModel extends model $executions[$executionID]->lastEditedBy = $this->app->user->account; $executions[$executionID]->lastEditedDate = helper::now(); - if(isset($data->codes)) $executions[$executionID]->code = $executionCode; - if(isset($data->projects)) $executions[$executionID]->project = zget($data->projects, $executionID, 0); - if(isset($data->attributes)) $executions[$executionID]->attribute = zget($data->attributes, $executionID, ''); - if(isset($data->lifetimes)) $executions[$executionID]->lifetime = $data->lifetimes[$executionID]; + if(isset($data->codes)) $executions[$executionID]->code = $executionCode; + if(isset($data->projects)) $executions[$executionID]->project = zget($data->projects, $executionID, 0); + if(isset($data->attributes[$executionID])) $executions[$executionID]->attribute = zget($data->attributes, $executionID, ''); + if(isset($data->lifetimes[$executionID])) $executions[$executionID]->lifetime = $data->lifetimes[$executionID]; $oldExecution = $oldExecutions[$executionID]; $projectID = isset($executions[$executionID]->project) ? $executions[$executionID]->project : $oldExecution->project; @@ -801,7 +828,8 @@ class executionModel extends model { if($parentID == $parents[$repeatID]) { - dao::$errors["names$executionID"][] = $this->lang->execution->errorNameRepeat; + $type = $oldExecution->type == 'stage' ? 'stage' : 'agileplus'; + dao::$errors["names$executionID"][] = sprintf($this->lang->execution->errorNameRepeat, strtolower(zget($this->lang->programplan->typeList, $type))); break; } } @@ -1991,10 +2019,15 @@ class executionModel extends model if($execution->parent) $parentList[$execution->parent] = $execution->parent; if($execution->projectName) $execution->name = $execution->projectName . ' / ' . $execution->name; } - elseif($param === 'hasParentName') + elseif(strpos($param, 'hasParentName') !== false) { $parentExecutions = $this->dao->select('id,name')->from(TABLE_EXECUTION)->where('id')->in(trim($execution->path, ','))->andWhere('type')->in('stage,kanban,sprint')->orderBy('grade')->fetchPairs(); $executions[$execution->id]->title = implode('/', $parentExecutions); + if(strpos($param, 'skipParent') !== false) + { + $children = $this->getChildExecutions($execution->id); + if(count($children) > 0) $parentList[$execution->id] = $execution->id; + } } elseif(isset($executions[$execution->parent])) { diff --git a/module/execution/view/create.html.php b/module/execution/view/create.html.php index 429ecf2cb4..dab4ad2d55 100644 --- a/module/execution/view/create.html.php +++ b/module/execution/view/create.html.php @@ -59,7 +59,8 @@
- + getClientLang(), 'zh-') === false and !empty($project->model) and $project->model == 'agileplus') ? 'w-150px' : 'w-120px';?> + diff --git a/module/execution/view/edit.html.php b/module/execution/view/edit.html.php index 5c89e3a012..18123bcfed 100644 --- a/module/execution/view/edit.html.php +++ b/module/execution/view/edit.html.php @@ -33,14 +33,14 @@ model == 'scrum'):?> - + model == 'kanban'):?> id);?> model == 'agileplus'):?> - + tab == 'project' and $project->model == 'waterfallplus'):?> @@ -51,7 +51,7 @@ - + setCode) and $config->setCode == 1):?> diff --git a/module/execution/view/kanban.html.php b/module/execution/view/kanban.html.php index f89f2e2f00..58293d2cde 100644 --- a/module/execution/view/kanban.html.php +++ b/module/execution/view/kanban.html.php @@ -61,40 +61,27 @@ js::set('rdSearchValue', ''); js::set('defaultMinColWidth', $this->config->minColWidth); js::set('defaultMaxColWidth', $this->config->maxColWidth); -$canSortRegion = (commonModel::hasPriv('kanban', 'sortRegion') and count($regions) > 1); -$canCreateRegion = (common::hasPriv('kanban', 'createRegion') and $groupBy == 'default'); +$canSortRegion = commonModel::hasPriv('kanban', 'sortRegion') && count($regions) > 1; +$canCreateRegion = common::hasPriv('kanban', 'createRegion') && $groupBy == 'default'; $canEditRegion = commonModel::hasPriv('kanban', 'editRegion'); $canDeleteRegion = commonModel::hasPriv('kanban', 'deleteRegion'); $canCreateLane = commonModel::hasPriv('kanban', 'createLane'); $canCreateTask = common::hasPriv('task', 'create'); $canBatchCreateTask = common::hasPriv('task', 'batchCreate'); -$canImportTask = (common::hasPriv('execution', 'importTask') and $execution->multiple); +$canImportTask = common::hasPriv('execution', 'importTask') && $execution->multiple; -if($execution->lifetime != 'ops' and !in_array($execution->attribute, array('request', 'review'))) -{ - $canCreateBug = ($productID and common::hasPriv('bug', 'create')); - $canBatchCreateBug = ($productID and common::hasPriv('bug', 'batchCreate') and $execution->multiple); - $canImportBug = ($productID and common::hasPriv('execution', 'importBug')); - $canCreateStory = ($productID and common::hasPriv('story', 'create')); - $canBatchCreateStory = ($productID and common::hasPriv('story', 'batchCreate')); - $canLinkStory = ($productID and common::hasPriv('execution', 'linkStory') and !empty($execution->hasProduct)); - $canLinkStoryByPlan = ($productID and common::hasPriv('execution', 'importplanstories') and !empty($project->hasProduct)); - $hasStoryButton = ($canCreateStory or $canBatchCreateStory or $canLinkStory or $canLinkStoryByPlan); - $hasBugButton = ($canCreateBug or $canBatchCreateBug); -} -else -{ - $canCreateBug = false; - $canBatchCreateBug = false; - $canImportBug = false; - $canCreateStory = false; - $canBatchCreateStory = false; - $canLinkStory = false; - $canLinkStoryByPlan = false; - $hasStoryButton = false; - $hasBugButton = false; -} -$hasTaskButton = ($canCreateTask or $canBatchCreateTask or $canImportBug); +$canCreateBug = $features['qa'] && $productID && common::hasPriv('bug', 'create'); +$canBatchCreateBug = $features['qa'] && $productID && common::hasPriv('bug', 'batchCreate') && $execution->multiple; +$canImportBug = $features['qa'] && $productID && common::hasPriv('execution', 'importBug'); +$hasBugButton = $features['qa'] && ($canCreateBug || $canBatchCreateBug); + +$canCreateStory = $features['story'] && $productID && common::hasPriv('story', 'create'); +$canBatchCreateStory = $features['story'] && $productID && common::hasPriv('story', 'batchCreate'); +$canLinkStory = $features['story'] && $productID && common::hasPriv('execution', 'linkStory') && !empty($execution->hasProduct); +$canLinkStoryByPlan = $features['story'] && $productID && common::hasPriv('execution', 'importplanstories') && !empty($project->hasProduct); +$hasStoryButton = $features['story'] && ($canCreateStory || $canBatchCreateStory || $canLinkStory || $canLinkStoryByPlan); + +$hasTaskButton = $canCreateTask || $canBatchCreateTask || $canImportBug; js::set('priv', array( @@ -134,7 +121,7 @@ js::set('priv', 'canDeleteStory' => common::hasPriv('story', 'delete'), 'canChangeStory' => common::hasPriv('story', 'change'), 'canCloseStory' => common::hasPriv('story', 'close'), - 'canUnlinkStory' => (common::hasPriv('execution', 'unlinkStory') and !empty($execution->hasProduct)), + 'canUnlinkStory' => (common::hasPriv('execution', 'unlinkStory') && !empty($execution->hasProduct)), 'canViewStory' => common::hasPriv('execution', 'storyView'), ) ); @@ -142,13 +129,17 @@ js::set('priv', -lifetime == 'ops' or in_array($execution->attribute, array('request', 'review'))):?> +
execution->projectName;?>execution->projectName;?>
execution->projectName;?>execution->projectName;?> project, "class='form-control chosen' onchange='changeProject(this.value)' required");?>
execution->method;?>execution->method;?> execution->typeList, $execution->type);?>
execution->name;?>execution->name;?> name, "class='form-control' required");?>