diff --git a/db/update16.5.sql b/db/update16.5.sql index cc8ec8e1e1..73162f6d57 100644 --- a/db/update16.5.sql +++ b/db/update16.5.sql @@ -90,6 +90,16 @@ DELETE FROM `zt_config` WHERE `section` = 'customMenu'; UPDATE `zt_story` SET `plan` = '' WHERE `plan` = 0; +UPDATE `zt_workflowfield` set `control` = 'datetime' WHERE `module` = 'testcase' and `field` IN ('openedDate','reviewedDate','lastEditedDate','lastRunDate'); + +UPDATE `zt_workflowfield` set `control` = 'date' WHERE `module` = 'testtask' and `field` IN ('begin','end'); +UPDATE `zt_workflowfield` set `control` = 'richtext' WHERE `module` = 'testtask' and `field` = 'desc'; + +UPDATE `zt_workflowfield` set `control` = 'datetime' WHERE `module` IN ('testsuite','caselib') and `field` IN ('addedDate','lastEditedDate'); +UPDATE `zt_workflowfield` set `control` = 'richtext' WHERE `module` = 'testsuite' and `field` = 'desc'; + +UPDATE `zt_workflowfield` set `control` = 'datetime' WHERE `module` = 'feedback' and `field` IN ('openedDate','reviewedDate','processedDate','closedDate','editedDate','assignedDate'); + UPDATE `zt_workflowfield` SET `control` = 'datetime' WHERE `module` = 'product' and `field` = 'createdDate'; UPDATE `zt_workflowfield` SET `control` = 'date' WHERE `module` = 'productplan' and `field` = 'begin'; UPDATE `zt_workflowfield` SET `control` = 'date' WHERE `module` = 'productplan' and `field` = 'end'; diff --git a/module/custom/model.php b/module/custom/model.php index aa725021d4..a8ffc88a32 100644 --- a/module/custom/model.php +++ b/module/custom/model.php @@ -251,7 +251,9 @@ class customModel extends model foreach($item['subMenu'] as $subMenu) { if(!isset($subMenu['link']) or strpos($subMenu['link'], '|') === false) continue; - list($subLabel, $module, $method, $vars) = explode('|', $subMenu['link']); + list($subLabel, $module, $method) = explode('|', $subMenu['link']); + if(count(explode('|', $subMenu['link'])) > 3) list($subLabel, $module, $method, $vars) = explode('|', $subMenu['link']); + $hasPriv = commonModel::hasPriv($module, $method); if($hasPriv) break; } diff --git a/module/execution/js/kanban.js b/module/execution/js/kanban.js index ff3a64f56c..b125445210 100644 --- a/module/execution/js/kanban.js +++ b/module/execution/js/kanban.js @@ -328,6 +328,10 @@ if(!window.kanbanDropRules) { backlog: ['ready', 'backlog'], ready: ['backlog', 'ready'], + tested: ['verified'], + verified: ['tested', 'released'], + released: ['verified', 'closed'], + closed: ['released'], }, bug: { @@ -957,7 +961,12 @@ function changeCardColType(cardID, fromColID, toColID, fromLaneID, toLaneID, car /* Story lane. */ if(cardType == 'story') { - if(toColType == 'ready' || toColType == 'backlog') + if(toColType == 'closed' && priv.canCloseStory) + { + var link = createLink('story', 'close', 'storyID=' + objectID, '', true); + showIframe = true; + } + else { if(toColType == 'ready' && typeof(reviewStoryParis[objectID]) != 'undefined') { diff --git a/module/execution/js/taskkanban.js b/module/execution/js/taskkanban.js index 8df8beb996..56a6cf5af4 100644 --- a/module/execution/js/taskkanban.js +++ b/module/execution/js/taskkanban.js @@ -480,6 +480,10 @@ if(!window.kanbanDropRules) { backlog: ['ready'], ready: ['backlog'], + tested: ['verified'], + verified: ['tested', 'released'], + released: ['verified', 'closed'], + closed: ['released'], }, bug: { @@ -495,7 +499,7 @@ if(!window.kanbanDropRules) { 'wait': ['developing', 'developed', 'canceled', 'closed'], 'developing': ['developed', 'pause', 'canceled'], - 'developed': ['closed'], + 'developed': ['developing', 'closed'], 'pause': ['developing'], 'canceled': ['developing'], 'closed': ['developing'], @@ -683,7 +687,12 @@ function changeCardColType(cardID, fromColID, toColID, fromLaneID, toLaneID, car /* Story lane. */ if(cardType == 'story') { - if(toColType == 'ready' || toColType == 'backlog') + if(toColType == 'closed' && priv.canCloseStory) + { + var link = createLink('story', 'close', 'storyID=' + objectID, '', true); + showIframe = true; + } + else { if(toColType == 'ready' && typeof(reviewStoryParis[objectID]) != 'undefined') { @@ -706,7 +715,7 @@ function changeCardColType(cardID, fromColID, toColID, fromLaneID, toLaneID, car updateKanban(browseType, kanbanGroup[groupBy]); } } - }) + }); } } diff --git a/module/execution/view/burn.html.php b/module/execution/view/burn.html.php index 71da19f850..2d0bd26ae7 100644 --- a/module/execution/view/burn.html.php +++ b/module/execution/view/burn.html.php @@ -22,7 +22,7 @@
' . $lang->execution->computeBurn, 'hiddenwin', "title='{$lang->execution->computeBurn}{$lang->execution->burn}' class='btn btn-primary' id='computeBurn'"); + common::printLink('execution', 'computeBurn', 'reload=yes', ' ' . $lang->execution->computeBurn, 'hiddenwin', "title='{$lang->execution->computeBurn}' class='btn btn-primary' id='computeBurn'"); echo '
'; echo html::a($this->createLink('execution', 'burn', "executionID=$executionID&type=$weekend&interval=$interval"), $lang->execution->$weekend, '', "class='btn btn-link'"); if(common::canModify('execution', $execution)) common::printLink('execution', 'fixFirst', "execution=$execution->id", $lang->execution->fixFirst, '', "class='btn btn-link iframe' data-width='700'"); diff --git a/module/execution/view/kanban.html.php b/module/execution/view/kanban.html.php index cfddc793bd..ec45f38420 100644 --- a/module/execution/view/kanban.html.php +++ b/module/execution/view/kanban.html.php @@ -105,6 +105,7 @@ js::set('priv', 'canEditStory' => common::hasPriv('story', 'edit'), 'canDeleteStory' => common::hasPriv('story', 'delete'), 'canChangeStory' => common::hasPriv('story', 'change'), + 'canCloseStory' => common::hasPriv('story', 'close'), 'canUnlinkStory' => common::hasPriv('execution', 'unlinkStory'), ) ); diff --git a/module/execution/view/taskkanban.html.php b/module/execution/view/taskkanban.html.php index 4d86ea58cd..7ec69b0041 100644 --- a/module/execution/view/taskkanban.html.php +++ b/module/execution/view/taskkanban.html.php @@ -193,7 +193,8 @@ js::set('priv', 'canStartTask' => common::hasPriv('task', 'start'), 'canAssignBug' => common::hasPriv('bug', 'assignto'), 'canConfirmBug' => common::hasPriv('bug', 'confirmBug'), - 'canActivateBug' => common::hasPriv('bug', 'activate') + 'canActivateBug' => common::hasPriv('bug', 'activate'), + 'canCloseStory' => common::hasPriv('story', 'close') ) ); ?> diff --git a/module/kanban/control.php b/module/kanban/control.php index eeb922a87d..ae243b271c 100644 --- a/module/kanban/control.php +++ b/module/kanban/control.php @@ -1663,6 +1663,20 @@ class kanban extends control ->andWhere('`column`')->eq($toColID) ->exec(); + $toColumn = $this->kanban->getColumnByID($toColID); + if($toColumn->laneType == 'story' and in_array($toColumn->type, array('tested', 'verified', 'released', 'closed'))) + { + $data = new stdclass(); + $data->stage = $toColumn->type; + if($toColumn->type == 'released') + { + $fromColumn = $this->kanban->getColumnByID($fromColID); + if($fromColumn->type == 'closed') $data->status = 'active'; + } + $this->dao->update(TABLE_STORY)->data($data)->where('id')->eq($cardID)->exec(); + $this->dao->update(TABLE_STORYSTAGE)->set('stage')->eq($toColumn->type)->where('story')->eq($cardID)->exec(); + } + $kanbanGroup = $regionID == 0 ? $this->kanban->getExecutionKanban($executionID, $browseType, $groupBy) : $this->kanban->getRDKanban($executionID, $browseType, $orderBy, $regionID, $groupBy); echo json_encode($kanbanGroup); } diff --git a/module/story/control.php b/module/story/control.php index 64527571e3..70dcd47022 100644 --- a/module/story/control.php +++ b/module/story/control.php @@ -1351,7 +1351,7 @@ class story extends control if(isonlybody()) { $execution = $this->execution->getByID($this->session->execution); - if($this->app->tab == 'execution' and $execution->type == 'kanban' and $this->app->tab == 'execution') + if($this->app->tab == 'execution' and $execution->type == 'kanban') { $this->loadModel('kanban')->updateLane($this->session->execution, 'story', $storyID); $kanbanData = $this->kanban->getRDKanban($this->session->execution, $this->session->execLaneType ? $this->session->execLaneType : 'all'); diff --git a/module/story/model.php b/module/story/model.php index eb728e444e..3f5d681686 100644 --- a/module/story/model.php +++ b/module/story/model.php @@ -3038,6 +3038,8 @@ class storyModel extends model public function closeParentRequirement($storyID) { $parentID = $this->dao->select('BID')->from(TABLE_RELATION)->where('AID')->eq($storyID)->fetch(); + if(empty($parentID)) return; + $stories = $this->dao->select('t2.id, t2.status')->from(TABLE_RELATION)->alias('t1') ->leftJoin(TABLE_STORY)->alias('t2')->on('t2.id=t1.AID') ->where('t1.BType')->eq('requirement')