diff --git a/db/update20.2.0.sql b/db/update20.2.0.sql index f529a333ff..a7e86794e5 100644 --- a/db/update20.2.0.sql +++ b/db/update20.2.0.sql @@ -1,5 +1,13 @@ +UPDATE zt_demand SET status = 'active' WHERE status in ('launched','distributed','pass'); +UPDATE zt_story SET status = 'active' WHERE status in ('launched','developing'); + +ALTER TABLE `zt_demand` ADD `parentVersion` smallint NOT NULL DEFAULT 0 AFTER `version`; +ALTER TABLE `zt_story` ADD `demandVersion` smallint NOT NULL DEFAULT 0 AFTER `parentVersion`; +UPDATE `zt_demand` AS t1 JOIN `zt_demand` AS t2 ON t1.parent = t2.id SET t1.parentVersion = t2.version WHERE t1.parent > 0; +UPDATE `zt_story` AS t1 JOIN `zt_demand` AS t2 ON t1.demand = t2.id SET t1.demandVersion = t2.version WHERE t1.demand > 0; + ALTER TABLE `zt_approvalnode` ADD `forwardBy` char(30) NOT NULL DEFAULT '' AFTER `extra`; -ALTER TABLE `zt_approvalnode` ADD `revertTo` char(30) NOT NULL DEFAULT '' AFTER `extra`; +ALTER TABLE `zt_approvalnode` ADD `revertTo` char(30) NOT NULL DEFAULT '' AFTER `extra`; UPDATE `zt_workflowaction` SET conditions = '' WHERE `action` = 'approvalreview' AND `conditions` = '[{"conditionType":"data","fields":[{"field":"deleted","operator":"equal","param":"0","logicalOperator":"and"},{"field":"reviewStatus","operator":"equal","param":"doing","logicalOperator":"and"},{"field":"reviewers","operator":"include","param":"currentUser"}]}]'; UPDATE `zt_workflowaction` SET conditions = '' WHERE `action` = 'approvalcancel' AND `conditions` = '[{"conditionType":"data","fields":[{"field":"deleted","operator":"equal","param":"0","logicalOperator":"and"},{"field":"reviewStatus","operator":"equal","param":"doing","logicalOperator":"and"},{"field":"openedBy","operator":"equal","param":"currentUser"}]}]'; diff --git a/lib/zin/wg/dropdown/v1.php b/lib/zin/wg/dropdown/v1.php index f2891ed33d..b1d34a8b43 100644 --- a/lib/zin/wg/dropdown/v1.php +++ b/lib/zin/wg/dropdown/v1.php @@ -117,6 +117,8 @@ class dropdown extends wg if(is_array($menu) && $menu) $menu = $menu[0]; + if(is_array($menu) && $menu) $menu = $menu[0]; + if($menu instanceof menu) { list($id, $menuProps, $menuClass) = $this->prop(array('id', 'menu', 'menuClass')); diff --git a/lib/zin/wg/productroadmapbox/css/v1.css b/lib/zin/wg/productroadmapbox/css/v1.css index e419705188..71fee86b02 100644 --- a/lib/zin/wg/productroadmapbox/css/v1.css +++ b/lib/zin/wg/productroadmapbox/css/v1.css @@ -1,4 +1,4 @@ -.productBox {position: relative; padding-top: 5px;} +.productBox {position: relative;} .productBox .distributeProduct, .productsBox .addProductBox .form-group{padding-left: 0px;} .productBox .roadmapBox{padding-right: 0px;} .productBox .c-actions {position: absolute; width: 100px; right: -100px;} diff --git a/module/action/model.php b/module/action/model.php index 5a1fe56bc0..8350866a00 100755 --- a/module/action/model.php +++ b/module/action/model.php @@ -1356,6 +1356,11 @@ class actionModel extends model $this->recoverRelatedData($action, $object); + /* 还原已删除的需求时重算OR需求和业用研需的阶段。 */ + /* The stage of recalculating OR requirements and industrial research needs when restoring deleted requirements. */ + if(in_array($action->objectType, array('story', 'epic', 'requirement'))) $this->loadModel('story')->setStage($action->objectID); + if($action->objectType == 'demand' && !empty($object->parent)) $this->loadModel('demand')->updateParentDemandStage($object->parent); + /* 在action表中更新action记录。 */ /* Update action record in action table. */ $this->dao->update(TABLE_ACTION)->set('extra')->eq(actionModel::BE_UNDELETED)->where('id')->eq($actionID)->exec(); diff --git a/module/action/test/model/getlist.php b/module/action/test/model/getlist.php index 8b261798ea..4e5738db7e 100755 --- a/module/action/test/model/getlist.php +++ b/module/action/test/model/getlist.php @@ -183,10 +183,10 @@ r($action->getListTest($objectType[2], $bugID[1])) && p() && e('link'); // 测 r($action->getListTest($objectType[2], $bugID[2])) && p() && e('link'); // 测试获取对象类型 bug 对象ID 3 的动态信息 // 操作是 tostory 对象类型 feedback -r($action->getListTest($objectType[3], $feedbackID[0])) && p() && e('link'); // 测试获取对象类型 feedback 对象ID 1 的动态信息 +r($action->getListTest($objectType[3], $feedbackID[0])) && p() && e('nochanged'); // 测试获取对象类型 feedback 对象ID 1 的动态信息 // 操作是 tostory 对象类型 ticket -r($action->getListTest($objectType[4], $hasOneID[0])) && p() && e('link'); // 测试获取对象类型 ticket 对象ID 1 的动态信息 +r($action->getListTest($objectType[4], $hasOneID[0])) && p() && e('nochanged'); // 测试获取对象类型 ticket 对象ID 1 的动态信息 // 操作是 moved 对象类型是 task r($action->getListTest($objectType[1], $taskID[0])) && p() && e('link'); // 测试获取对象类型 task 对象ID 1 的动态信息 @@ -285,7 +285,7 @@ r($action->getListTest($objectType[1], $taskID[9])) && p() && e('link'); // 测 r($action->getListTest($objectType[1], $taskID[10])) && p() && e('link'); // 测试获取对象类型 task 对象ID 11 的动态信息 // 操作 totask 对象类型 feedback -r($action->getListTest($objectType[3], $feedbackID[1])) && p() && e('link'); // 测试获取对象类型 feedback 对象ID 2 的动态信息 +r($action->getListTest($objectType[3], $feedbackID[1])) && p() && e('nochanged'); // 测试获取对象类型 feedback 对象ID 2 的动态信息 // 操作 linkchildtask 对象类型 feedback r($action->getListTest($objectType[3], $feedbackID[2])) && p() && e('nochanged'); // 测试获取对象类型 feedback 对象ID 3 的动态信息 diff --git a/module/action/test/model/getobjectlabel.php b/module/action/test/model/getobjectlabel.php index 462243111d..ab09b41b23 100755 --- a/module/action/test/model/getobjectlabel.php +++ b/module/action/test/model/getobjectlabel.php @@ -72,6 +72,6 @@ r($action->getObjectLabelTest($objectType[18], $objectId[18], $actionType[18], $ r($action->getObjectLabelTest($objectType[19], $objectId[19], $actionType[19], $requirements, $epics)) && p() && e('报告|testreport|view|report=%s'); // 测试获取objectType testreport objectId 20的动态信息 r($action->getObjectLabelTest($objectType[20], $objectId[20], $actionType[20], $requirements, $epics)) && p() && e('应用|entry|browse|'); // 测试获取objectType entry objectId 21的动态信息 r($action->getObjectLabelTest($objectType[21], $objectId[21], $actionType[21], $requirements, $epics)) && p() && e('Webhook|webhook|browse|'); // 测试获取objectType webhook objectId 22的动态信息 -r($action->getObjectLabelTest($objectType[22], $objectId[22], $actionType[22], $requirements, $epics)) && p() && e('评审|review|view|reviewID=%s'); // 测试获取objectType review objectId 23的动态信息 +r($action->getObjectLabelTest($objectType[22], $objectId[22], $actionType[22], $requirements, $epics)) && p() && e('review'); // 测试获取objectType review objectId 23的动态信息 r($action->getObjectLabelTest($objectType[1], $objectId[23], $actionType[23], $requirements, $epics)) && p() && e('用户需求|story|storyView|storyID=%s'); // 测试获取objectType story objectId 25的动态信息 r($action->getObjectLabelTest($objectType[1], $objectId[24], $actionType[23], $requirements, $epics)) && p() && e('业务需求|story|storyView|storyID=%s'); // 测试获取objectType story objectId 26的动态信息 diff --git a/module/branch/test/lib/branch.unittest.class.php b/module/branch/test/lib/branch.unittest.class.php index 40d7ba1401..3c49ae12a5 100644 --- a/module/branch/test/lib/branch.unittest.class.php +++ b/module/branch/test/lib/branch.unittest.class.php @@ -382,10 +382,10 @@ class branchTest public function changeBranchLanguageTest($productID) { global $tester; - global $lang; + global $app; - $filePath = dirname(__FILE__, 2) . DS . 'lang' . DS . 'zh-cn.php'; - include $filePath; + $app::$loadedLangs = array(); + $app->loadLang('branch'); $this->objectModel->changeBranchLanguage($productID); diff --git a/module/bug/test/model/getactivatedbugs.php b/module/bug/test/model/getactivatedbugs.php index 7cf21e92dd..ada7cc3cd2 100644 --- a/module/bug/test/model/getactivatedbugs.php +++ b/module/bug/test/model/getactivatedbugs.php @@ -25,9 +25,9 @@ $buildIdList = array('1,0,trunk', '1,trunk', '0,trunk'); $bug = new bugTest(); -r($bug->getActivatedBugsTest($productIdList[0], $beginList[0], $endList[0], $buildIdList[0])) && p() && e('2,5,6,9'); // 测试获取产品 1 2 3 类型 空 开始日期 上月 结束日期 下月 的bug +r($bug->getActivatedBugsTest($productIdList[0], $beginList[0], $endList[0], $buildIdList[0])) && p() && e('1,2,5,6,9'); // 测试获取产品 1 2 3 类型 空 开始日期 上月 结束日期 下月 的bug r($bug->getActivatedBugsTest($productIdList[0], $beginList[1], $endList[1], $buildIdList[0])) && p() && e('0'); // 测试获取产品 1 2 3 类型 空 开始日期 上周 结束日期 下周 的bug -r($bug->getActivatedBugsTest($productIdList[0], $beginList[0], $endList[0], $buildIdList[1])) && p() && e('5,6,9'); // 测试获取产品 1 2 3 类型 resolved 开始日期 上月 结束日期 下月 的bug +r($bug->getActivatedBugsTest($productIdList[0], $beginList[0], $endList[0], $buildIdList[1])) && p() && e('1,5,6,9'); // 测试获取产品 1 2 3 类型 resolved 开始日期 上月 结束日期 下月 的bug r($bug->getActivatedBugsTest($productIdList[0], $beginList[1], $endList[1], $buildIdList[1])) && p() && e('0'); // 测试获取产品 1 2 3 类型 resolved 开始日期 上周 结束日期 下周 的bug r($bug->getActivatedBugsTest($productIdList[0], $beginList[0], $endList[0], $buildIdList[2])) && p() && e('2,5,6,9'); // 测试获取产品 1 2 3 类型 opened 开始日期 上月 结束日期 下月 的bug r($bug->getActivatedBugsTest($productIdList[0], $beginList[1], $endList[1], $buildIdList[2])) && p() && e('0'); // 测试获取产品 1 2 3 类型 opened 开始日期 上周 结束日期 下周 的bug diff --git a/module/common/test/model/checkpriv.php b/module/common/test/model/checkpriv.php index 5c3aabd058..18f6b5b203 100755 --- a/module/common/test/model/checkpriv.php +++ b/module/common/test/model/checkpriv.php @@ -23,6 +23,8 @@ $app->methodName = 'create'; $config->webRoot = ''; $config->requestType = 'PATH_INFO'; +$_SERVER['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'; + try { $result = $tester->loadModel('common')->checkPriv(); @@ -47,3 +49,5 @@ catch (Exception $e) } r($result) && p() && e('1'); // 用户有权限时,返回TRUE + +unset($_SERVER['HTTP_X_REQUESTED_WITH']); diff --git a/module/common/test/model/deny.php b/module/common/test/model/deny.php index 0c95612362..44f4e92724 100755 --- a/module/common/test/model/deny.php +++ b/module/common/test/model/deny.php @@ -9,7 +9,7 @@ timeout=0 cid=1 - deny中鉴权,有权限时返回TRUE @1 -- deny中鉴权,无权限时返回跳转的URL @{"load":"-deny.php?m=user&f=deny&module=execution&method=create"}0 +- deny中鉴权,无权限时返回0 @0 */ su('admin'); @@ -33,4 +33,4 @@ try{ $result2 = $e->getMessage(); } -r($result2) && p() && e('{"load":"user-deny-execution-create.html"}0'); // deny中鉴权,无权限时返回跳转的URL +r($result2) && p() && e('0'); // deny中鉴权,无权限时返回0 diff --git a/module/common/test/model/replacemenulang.php b/module/common/test/model/replacemenulang.php index 3d72a7aecb..0931550577 100644 --- a/module/common/test/model/replacemenulang.php +++ b/module/common/test/model/replacemenulang.php @@ -21,11 +21,11 @@ $tester->loadModel('common'); $tester->common->lang->db->custom = array(); r($tester->common->replaceMenuLang()) && p() && e('0'); //没有 db->custom 数据。 -$tester->common->lang->db->custom['myMenu']['menu']['execution'] = '执行1'; -$tester->common->lang->db->custom['mySubMenu']['work']['task'] = '任务1'; -$tester->common->lang->db->custom['executionMenu']['storyGroupDropMenu']['story'] = '需求1'; +$tester->common->lang->db->custom['myMenu']['menu']['execution'] = '执行1'; +$tester->common->lang->db->custom['mySubMenu']['work']['task'] = '任务1'; +$tester->common->lang->db->custom['executionMenu']['menu']['story'] = '需求1'; $tester->common->replaceMenuLang(); -r($tester->common->lang->my->menu->execution) && p('link') && e("执行1|my|execution|type=undone"); // 替换二级导航语言项。 -r($tester->common->lang->my->menu->work['subMenu']->task) && p('link') && e("任务1|my|work|mode=task"); // 替换三级导航语言项。 -r($tester->common->lang->execution->menu->storyGroup['dropMenu']->story) && p('link') && e("需求1|execution|story|executionID=%s"); // 替换二级导航下拉的语言项。 +r($tester->common->lang->my->menu->execution) && p('link') && e("执行1|my|execution|type=undone"); // 替换二级导航语言项。 +r($tester->common->lang->my->menu->work['subMenu']->task) && p('link') && e("任务1|my|work|mode=task"); // 替换三级导航语言项。 +r($tester->common->lang->execution->menu->story) && p('link') && e("需求1|execution|story|executionID=%s"); // 替换二级导航下拉的语言项。 diff --git a/module/custom/test/model/computefeatures.php b/module/custom/test/model/computefeatures.php index 1fe5239930..2da59b8f89 100644 --- a/module/custom/test/model/computefeatures.php +++ b/module/custom/test/model/computefeatures.php @@ -78,12 +78,12 @@ $openFeatures = $customTester->computeFeaturesTest($editionList[0]); $ipdFeatures = $customTester->computeFeaturesTest($editionList[1]); $maxFeatures = $customTester->computeFeaturesTest($editionList[2]); -r($openFeatures[0]) && p('0,1,2,3,4') && e('program,productLine,productUR,projectWaterfall,projectWaterfallplus'); // 计算无相关数据时,开源版不启用的功能 -r($openFeatures[1]) && p() && e('0'); // 计算无相关数据时,开源版敏捷项目启用的功能 -r($openFeatures[2]) && p() && e('0'); // 计算无相关数据时,开源版敏捷项目不启用的功能 -r($ipdFeatures[0]) && p('0,1,2,3,4') && e('program,productLine,productUR,projectWaterfall,projectWaterfallplus'); // 计算无相关数据时,ipd版不启用的功能 -r($ipdFeatures[1]) && p() && e('0'); // 计算无相关数据时,ipd版敏捷项目启用的功能 -r($ipdFeatures[2]) && p() && e('0'); // 计算无相关数据时,ipd版敏捷项目不启用的功能 -r($maxFeatures[0]) && p('0,1,2,3,4') && e('program,productLine,productUR,projectWaterfall,projectWaterfallplus'); // 计算无相关数据时,旗舰版不启用的功能 -r($maxFeatures[1]) && p() && e('0'); // 计算无相关数据时,旗舰版敏捷项目启用的功能 -r($maxFeatures[2]) && p() && e('0'); // 计算无相关数据时,旗舰版敏捷项目不启用的功能 +r($openFeatures[0]) && p('0,1,2,3,4') && e('program,productLine,productER,productUR,projectWaterfall'); // 计算无相关数据时,开源版不启用的功能 +r($openFeatures[1]) && p() && e('0'); // 计算无相关数据时,开源版敏捷项目启用的功能 +r($openFeatures[2]) && p() && e('0'); // 计算无相关数据时,开源版敏捷项目不启用的功能 +r($ipdFeatures[0]) && p('0,1,2,3,4') && e('program,productLine,productER,productUR,projectWaterfall'); // 计算无相关数据时,ipd版不启用的功能 +r($ipdFeatures[1]) && p() && e('0'); // 计算无相关数据时,ipd版敏捷项目启用的功能 +r($ipdFeatures[2]) && p() && e('0'); // 计算无相关数据时,ipd版敏捷项目不启用的功能 +r($maxFeatures[0]) && p('0,1,2,3,4') && e('program,productLine,productER,productUR,projectWaterfall'); // 计算无相关数据时,旗舰版不启用的功能 +r($maxFeatures[1]) && p() && e('0'); // 计算无相关数据时,旗舰版敏捷项目启用的功能 +r($maxFeatures[2]) && p() && e('0'); // 计算无相关数据时,旗舰版敏捷项目不启用的功能 diff --git a/module/custom/test/model/disablefeaturesbymode.php b/module/custom/test/model/disablefeaturesbymode.php index 42867d7472..a5d446d088 100644 --- a/module/custom/test/model/disablefeaturesbymode.php +++ b/module/custom/test/model/disablefeaturesbymode.php @@ -20,5 +20,5 @@ cid=1 $modeList = array('ALM', 'light'); $customTester = new customTest(); -r($customTester->disableFeaturesByModeTest($modeList[0])) && p() && e('0'); // 将模式设置为全生命周期管理模式 -r($customTester->disableFeaturesByModeTest($modeList[1], ';')) && p() && e('productUR,waterfall,waterfallplus,scrumMeasrecord,agileplusMeasrecord,productTrack,productRoadmap'); // 将模式设置为轻量级管理模式 +r($customTester->disableFeaturesByModeTest($modeList[0])) && p() && e('0'); // 将模式设置为全生命周期管理模式 +r($customTester->disableFeaturesByModeTest($modeList[1], ';')) && p() && e('productER,productUR,waterfall,waterfallplus,scrumMeasrecord,agileplusMeasrecord,productTrack,productRoadmap'); // 将模式设置为轻量级管理模式 diff --git a/module/custom/test/model/setstorygrade.php b/module/custom/test/model/setstorygrade.php deleted file mode 100755 index 24248c3b7b..0000000000 --- a/module/custom/test/model/setstorygrade.php +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env php -setStoryGrade(); -timeout=0 -cid=1 - -- 查看插入的等级数量 @5 -- 查看插入的等级1详情 - - 第0条的grade属性 @1 - - 第0条的name属性 @一级 - - 第0条的status属性 @enable -- 查看插入的等级5详情 - - 第4条的grade属性 @5 - - 第4条的name属性 @五级 - - 第4条的status属性 @enable - -*/ - -$data['grade'] = array( - 0 => 1, - 1 => 2, - 2 => 3, - 3 => 4, - 4 => 5 -); - -$data['gradeName'] = array( - 0 => '一级', - 1 => '二级', - 2 => '三级', - 3 => '四级', - 4 => '五级' -); - -global $tester; -$tester->loadModel('custom')->setStoryGrade('story', $data); -$gradeSetting = $tester->loadModel('story')->getGradeList(); - -r(count($gradeSetting)) && p() && e('5'); // 查看插入的等级数量 -r($gradeSetting) && p('0:grade,name,status') && e('1,一级,enable'); // 查看插入的等级1详情 -r($gradeSetting) && p('4:grade,name,status') && e('5,五级,enable'); // 查看插入的等级5详情 diff --git a/module/custom/test/model/updateurandsr.php b/module/custom/test/model/updateurandsr.php index 455e70d8d9..13bb44efe4 100755 --- a/module/custom/test/model/updateurandsr.php +++ b/module/custom/test/model/updateurandsr.php @@ -18,9 +18,9 @@ su('admin'); $key = array(1, 0); $SRName = array('', '软件需求', '软件需求1'); -$dataList[] = array('SRName' => $SRName[0], 'URName' => '用户需求'); -$dataList[] = array('SRName' => $SRName[1], 'URName' => '用户需求'); -$dataList[] = array('SRName' => $SRName[2], 'URName' => '用户需求'); +$dataList[] = array('SRName' => $SRName[0], 'URName' => '用户需求', 'ERName' => '业务需求'); +$dataList[] = array('SRName' => $SRName[1], 'URName' => '用户需求', 'ERName' => '业务需求'); +$dataList[] = array('SRName' => $SRName[2], 'URName' => '用户需求', 'ERName' => '业务需求'); $customTester = new customTest(); r($customTester->updateURAndSRTest($key[0], $dataList[2])) && p('SRName') && e('软件需求1'); // 测试修改key为1,SRName值更改为软件需求1 diff --git a/module/execution/model.php b/module/execution/model.php index 2bb23c10c5..e30f8f765e 100755 --- a/module/execution/model.php +++ b/module/execution/model.php @@ -2944,7 +2944,7 @@ class executionModel extends model foreach($planStories as $id => $story) { - if(!in_array($story->status, array('active', 'launched')) || (!empty($story->branch) && !empty($executionBranches) && !isset($executionBranches[$story->branch]))) unset($planStories[$id]); + if($story->status != 'active' || (!empty($story->branch) && !empty($executionBranches) && !isset($executionBranches[$story->branch]))) unset($planStories[$id]); if(strpos($project->storyType, $story->type) === false) unset($planStories[$id]); if(!in_array($execution->attribute, array('mix', 'request', 'design')) && $story->type != 'story' && $execution->multiple) unset($planStories[$id]); } @@ -2981,9 +2981,6 @@ class executionModel extends model } $this->dao->delete()->from(TABLE_PROJECTSTORY)->where('project')->eq($executionID)->andWhere('story')->eq($storyID)->limit(1)->exec(); - /* In ipd project, unlink stories change it's status to launched. */ - if($execution->model == 'ipd' and $storyType == 'requirement') $this->dao->update(TABLE_STORY)->set('status')->eq('launched')->where('id')->eq($storyID)->exec(); - /* Resolve TABLE_KANBANCELL's field cards. */ if($execution->type == 'kanban') { diff --git a/module/group/packagemanager.php b/module/group/packagemanager.php index c0e8086575..02f26dc19f 100644 --- a/module/group/packagemanager.php +++ b/module/group/packagemanager.php @@ -3749,16 +3749,17 @@ $config->group->package->manageDemand = new stdclass(); $config->group->package->manageDemand->order = 5; $config->group->package->manageDemand->subset = 'demand'; $config->group->package->manageDemand->privs = array(); -$config->group->package->manageDemand->privs['demand-create'] = array('edition' => 'ipd', 'vision' => 'or', 'order' => 20, 'depend' => array('demand-browse', 'demand-view'), 'recommend' => array('demand-assignTo', 'demand-batchCreate', 'demand-change', 'demand-edit', 'demand-recall', 'demand-submitReview')); -$config->group->package->manageDemand->privs['demand-batchCreate'] = array('edition' => 'ipd', 'vision' => 'or', 'order' => 30, 'depend' => array('demand-browse', 'demand-view'), 'recommend' => array('demand-create')); -$config->group->package->manageDemand->privs['demand-edit'] = array('edition' => 'ipd', 'vision' => 'or', 'order' => 40, 'depend' => array('demand-browse'), 'recommend' => array('demand-assignTo', 'demand-batchCreate')); -$config->group->package->manageDemand->privs['demand-assignTo'] = array('edition' => 'ipd', 'vision' => 'or', 'order' => 60, 'depend' => array('demand-browse'), 'recommend' => array('demand-activate', 'demand-close', 'demand-create', 'demand-edit')); -$config->group->package->manageDemand->privs['demand-change'] = array('edition' => 'ipd', 'vision' => 'or', 'order' => 70, 'depend' => array('demand-browse', 'demand-view'), 'recommend' => array('demand-activate', 'demand-assignTo', 'demand-batchCreate', 'demand-close', 'demand-create', 'demand-edit')); -$config->group->package->manageDemand->privs['demand-manageTree'] = array('edition' => 'ipd', 'vision' => 'or', 'order' => 120, 'depend' => array('demand-browse'), 'recommend' => array()); -$config->group->package->manageDemand->privs['demand-close'] = array('edition' => 'ipd', 'vision' => 'or', 'order' => 180, 'depend' => array('demand-browse', 'demand-view'), 'recommend' => array('demand-activate', 'demand-assignTo', 'demand-batchCreate', 'demand-create', 'demand-edit')); -$config->group->package->manageDemand->privs['demand-activate'] = array('edition' => 'ipd', 'vision' => 'or', 'order' => 190, 'depend' => array('demand-browse', 'demand-view'), 'recommend' => array('demand-assignTo', 'demand-batchCreate', 'demand-close', 'demand-create', 'demand-edit')); -$config->group->package->manageDemand->privs['demand-distribute'] = array('edition' => 'ipd', 'vision' => 'or', 'order' => 200, 'depend' => array('demand-browse', 'demand-view'), 'recommend' => array('demand-assignTo', 'demand-batchCreate', 'demand-create', 'demand-edit')); -$config->group->package->manageDemand->privs['demand-retract'] = array('edition' => 'ipd', 'vision' => 'or', 'order' => 210, 'depend' => array('demandpool-browse', 'demand-browse', 'demand-view'), 'recommend' => array('demand-distribute')); +$config->group->package->manageDemand->privs['demand-create'] = array('edition' => 'ipd', 'vision' => 'or', 'order' => 20, 'depend' => array('demand-browse', 'demand-view'), 'recommend' => array('demand-assignTo', 'demand-batchCreate', 'demand-change', 'demand-edit', 'demand-recall', 'demand-submitReview')); +$config->group->package->manageDemand->privs['demand-batchCreate'] = array('edition' => 'ipd', 'vision' => 'or', 'order' => 30, 'depend' => array('demand-browse', 'demand-view'), 'recommend' => array('demand-create')); +$config->group->package->manageDemand->privs['demand-edit'] = array('edition' => 'ipd', 'vision' => 'or', 'order' => 40, 'depend' => array('demand-browse'), 'recommend' => array('demand-assignTo', 'demand-batchCreate')); +$config->group->package->manageDemand->privs['demand-assignTo'] = array('edition' => 'ipd', 'vision' => 'or', 'order' => 60, 'depend' => array('demand-browse'), 'recommend' => array('demand-activate', 'demand-close', 'demand-create', 'demand-edit')); +$config->group->package->manageDemand->privs['demand-change'] = array('edition' => 'ipd', 'vision' => 'or', 'order' => 70, 'depend' => array('demand-browse', 'demand-view'), 'recommend' => array('demand-activate', 'demand-assignTo', 'demand-batchCreate', 'demand-close', 'demand-create', 'demand-edit')); +$config->group->package->manageDemand->privs['demand-manageTree'] = array('edition' => 'ipd', 'vision' => 'or', 'order' => 120, 'depend' => array('demand-browse'), 'recommend' => array()); +$config->group->package->manageDemand->privs['demand-close'] = array('edition' => 'ipd', 'vision' => 'or', 'order' => 180, 'depend' => array('demand-browse', 'demand-view'), 'recommend' => array('demand-activate', 'demand-assignTo', 'demand-batchCreate', 'demand-create', 'demand-edit')); +$config->group->package->manageDemand->privs['demand-activate'] = array('edition' => 'ipd', 'vision' => 'or', 'order' => 190, 'depend' => array('demand-browse', 'demand-view'), 'recommend' => array('demand-assignTo', 'demand-batchCreate', 'demand-close', 'demand-create', 'demand-edit')); +$config->group->package->manageDemand->privs['demand-distribute'] = array('edition' => 'ipd', 'vision' => 'or', 'order' => 200, 'depend' => array('demand-browse', 'demand-view'), 'recommend' => array('demand-assignTo', 'demand-batchCreate', 'demand-create', 'demand-edit')); +$config->group->package->manageDemand->privs['demand-retract'] = array('edition' => 'ipd', 'vision' => 'or', 'order' => 210, 'depend' => array('demandpool-browse', 'demand-browse', 'demand-view'), 'recommend' => array('demand-distribute')); +$config->group->package->manageDemand->privs['demand-processDemandChange'] = array('edition' => 'ipd', 'vision' => 'or', 'order' => 220, 'depend' => array('demand-browse'), 'recommend' => array('demand-activate', 'demand-assignTo')); $config->group->package->reviewDemand = new stdclass(); $config->group->package->reviewDemand->order = 5; diff --git a/module/product/model.php b/module/product/model.php index 60e31b3bd8..c24ab46f51 100755 --- a/module/product/model.php +++ b/module/product/model.php @@ -663,7 +663,14 @@ class productModel extends model { $unclosedStatus = $this->lang->story->statusList; unset($unclosedStatus['closed']); - return $this->story->getProductStories($productID, $branch, $modules, array_keys($unclosedStatus), $type, $sort, true, '', $pager); + $stories = $this->story->getProductStories($productID, $branch, $modules, array_keys($unclosedStatus), $type, $sort, true, '', $pager); + foreach($stories as $storyID => $story) + { + if($story->type != 'story' && $story->stage == 'closed') unset($stories[$storyID]); + } + $this->app->loadClass('pager', true); + $pager = new pager(count($stories), $pager->recPerPage, $pager->pageID); + return $stories ? current(array_chunk($stories, $pager->recPerPage, true)) : array(); } /* Set default function called, when browseType is (draftstory, activestory, changingstory, reviewingstory, closedstory, developingstory, launchedstory). */ diff --git a/module/product/test/model/getstories.php b/module/product/test/model/getstories.php index fb7adce453..1ceac98421 100755 --- a/module/product/test/model/getstories.php +++ b/module/product/test/model/getstories.php @@ -35,6 +35,7 @@ cid=0 include dirname(__FILE__, 5) . '/test/lib/init.php'; include dirname(__FILE__, 2) . '/lib/product.unittest.class.php'; +zenData('product')->gen(5); zenData('story')->gen(100); $productIDList = array(1, 2, 3, 4, 5, 1000001); diff --git a/module/product/zen.php b/module/product/zen.php index c7a16858cc..313e16b1db 100644 --- a/module/product/zen.php +++ b/module/product/zen.php @@ -1434,8 +1434,8 @@ class productZen extends product $this->view->storyCases = $this->loadModel('testcase')->getStoryCaseCounts($storyIdList); $this->view->reports = in_array($this->config->edition, array('max', 'ipd')) ? $this->loadModel('researchreport')->getPairs() : array(); - $this->view->roadmaps = ($this->config->edition == 'ipd' && $storyType == 'requirement') ? array(0 => '') + $this->loadModel('roadmap')->getPairs($product->id) : array(); - $this->view->noclosedRoadmaps = ($this->config->edition == 'ipd' && $storyType == 'requirement') ? array(0 => '') + $this->loadModel('roadmap')->getPairs($product->id, '', 'noclosed') : array(); + $this->view->roadmaps = ($this->config->edition == 'ipd' && $storyType != 'story') ? array(0 => '') + $this->loadModel('roadmap')->getPairs($product->id) : array(); + $this->view->noclosedRoadmaps = ($this->config->edition == 'ipd' && $storyType != 'story') ? array(0 => '') + $this->loadModel('roadmap')->getPairs($product->id, '', 'noclosed') : array(); $this->display(); } diff --git a/module/productplan/control.php b/module/productplan/control.php index 61fbb392f4..8a83cd561c 100644 --- a/module/productplan/control.php +++ b/module/productplan/control.php @@ -584,7 +584,7 @@ class productplan extends control } else { - $allStories = $this->story->getProductStories($this->view->product->id, $plan->branch ? "0,{$plan->branch}" : 0, '0', 'draft,reviewing,active,changing,launched', 'all', 'id_desc', true, array_keys($planStories), $pager); + $allStories = $this->story->getProductStories($this->view->product->id, $plan->branch ? "0,{$plan->branch}" : 0, '0', 'draft,reviewing,active,changing', 'all', 'id_desc', true, array_keys($planStories), $pager); } $modules = $this->loadModel('tree')->getOptionMenu($plan->product, 'story', 0, 'all'); diff --git a/module/story/control.php b/module/story/control.php index 5334d00e86..6648bd99b1 100755 --- a/module/story/control.php +++ b/module/story/control.php @@ -1486,7 +1486,10 @@ class story extends control */ public function processStoryChange(int $storyID) { - $story = $this->story->fetchByID($storyID); + $story = $this->story->fetchByID($storyID); + + if($story->parent <= 0 && $this->config->edition == 'ipd') return $this->fetch('demand', 'processDemandChange', "objectID=$storyID&type=story"); + $parent = $this->story->fetchByID($story->parent); $this->dao->update(TABLE_STORY)->set('parentVersion')->eq($parent->version)->where('id')->eq($storyID)->exec(); diff --git a/module/story/lang/de.php b/module/story/lang/de.php index 693748298b..c3c75b49a9 100644 --- a/module/story/lang/de.php +++ b/module/story/lang/de.php @@ -245,12 +245,6 @@ $lang->story->statusList['active'] = 'Aktiv'; $lang->story->statusList['closed'] = 'Geschlossen'; $lang->story->statusList['changing'] = 'Geändert'; -if($config->systemMode == 'PLM') -{ - $lang->story->statusList['launched'] = 'Launched'; - $lang->story->statusList['developing'] = 'Developing'; -} - $lang->story->stageList[''] = ''; $lang->story->stageList['wait'] = 'Wartend'; $lang->story->stageList['planned'] = 'Geplant'; diff --git a/module/story/lang/en.php b/module/story/lang/en.php index 4ff43e2f86..5d412d1122 100644 --- a/module/story/lang/en.php +++ b/module/story/lang/en.php @@ -245,12 +245,6 @@ $lang->story->statusList['active'] = 'Active'; $lang->story->statusList['closed'] = 'Closed'; $lang->story->statusList['changing'] = 'Changing'; -if($config->systemMode == 'PLM') -{ - $lang->story->statusList['launched'] = 'Launched'; - $lang->story->statusList['developing'] = 'Developing'; -} - $lang->story->stageList[''] = ''; $lang->story->stageList['wait'] = 'Waiting'; $lang->story->stageList['planned'] = 'Planned'; diff --git a/module/story/lang/fr.php b/module/story/lang/fr.php index 303996cd43..711783af2f 100644 --- a/module/story/lang/fr.php +++ b/module/story/lang/fr.php @@ -245,12 +245,6 @@ $lang->story->statusList['active'] = 'Active'; $lang->story->statusList['closed'] = 'Fermée'; $lang->story->statusList['changing'] = 'Changée'; -if($config->systemMode == 'PLM') -{ - $lang->story->statusList['launched'] = 'Launched'; - $lang->story->statusList['developing'] = 'Developing'; -} - $lang->story->stageList[''] = ''; $lang->story->stageList['wait'] = 'En Attente'; $lang->story->stageList['planned'] = 'Plannifée'; diff --git a/module/story/lang/zh-cn.php b/module/story/lang/zh-cn.php index 69112d66b3..ce101f52da 100644 --- a/module/story/lang/zh-cn.php +++ b/module/story/lang/zh-cn.php @@ -245,12 +245,6 @@ $lang->story->statusList['active'] = '激活'; $lang->story->statusList['closed'] = '已关闭'; $lang->story->statusList['changing'] = '变更中'; -if($config->systemMode == 'PLM') -{ - $lang->story->statusList['launched'] = '已立项'; - $lang->story->statusList['developing'] = '研发中'; -} - $lang->story->stageList[''] = ''; $lang->story->stageList['wait'] = '未开始'; $lang->story->stageList['planned'] = "已计划"; diff --git a/module/story/model.php b/module/story/model.php index d7bfd46c46..a484ddda47 100644 --- a/module/story/model.php +++ b/module/story/model.php @@ -966,8 +966,8 @@ class storyModel extends model $this->computeEstimate($parentID); $status = $oldParentStory->status; - if(count($childrenStatus) == 1 and current($childrenStatus) == 'closed') $status = current($childrenStatus); // Close parent story. - if($oldParentStory->status == 'closed' && in_array($childStory->status, array('launched', 'active'))) $status = $this->getActivateStatus($parentID); // Activate parent story. + if(count($childrenStatus) == 1 and current($childrenStatus) == 'closed') $status = current($childrenStatus); // Close parent story. + if($oldParentStory->status == 'closed' && $childStory->status == 'active') $status = $this->getActivateStatus($parentID); // Activate parent story. $action = ''; $preStatus = ''; @@ -977,7 +977,7 @@ class storyModel extends model if(dao::isError()) return false; if(!$createAction) return $story; - if(strpos('launched,active,draft,changing', $status) !== false) $action = 'Activated'; + if(strpos('active,draft,changing', $status) !== false) $action = 'Activated'; if($status == 'closed') { /* Record the status before closed. */ @@ -1336,7 +1336,7 @@ class storyModel extends model $story = new stdclass(); $story->title = $titleList[$twinID]->title; $story->version = $oldStory->version - 1; - $story->status = ($this->config->systemMode == 'PLM' and $oldStory->type == 'requirement' and $this->config->vision == 'rnd') ? 'launched' : 'active'; + $story->status = 'active'; $this->dao->update(TABLE_STORY)->set('title')->eq($story->title)->set('version')->eq($story->version)->set('status')->eq($story->status)->where('id')->eq($storyID)->exec(); } @@ -1373,7 +1373,6 @@ class storyModel extends model $story->reviewer = implode(',', $story->reviewer); if($story->reviewer) $story->status = 'reviewing'; - if($this->config->systemMode == 'PLM' && $this->config->vision == 'rnd' && $oldStory->type == 'requirement' && $story->status == 'active') $story->status = 'launched'; $this->dao->update(TABLE_STORY)->data($story, 'reviewer')->where('id')->in($twinsIdList)->exec(); @@ -2095,9 +2094,6 @@ class storyModel extends model $story = $postData; $story->status = $this->getActivateStatus($storyID); - /* If in ipd mode, set requirement status = 'launched'. */ - if($this->config->systemMode == 'PLM' and $oldStory->type == 'requirement' and $story->status == 'active' and $this->config->vision == 'rnd') $story->status = 'launched'; - $this->dao->update(TABLE_STORY)->data($story, 'comment')->autoCheck()->checkFlow()->where('id')->eq($storyID)->exec(); /* Update parent story status. */ @@ -2737,6 +2733,15 @@ class storyModel extends model $story->planTitle = ''; $storyPlans = explode(',', trim($story->plan, ',')); foreach($storyPlans as $planID) $story->planTitle .= zget($plans, $planID, '') . ' '; + + $story->parent = array(); + foreach(explode(',', trim((string)$story->path, ',')) as $parentID) + { + if(!$parentID) continue; + if($parentID == $story->id) continue; + $story->parent[] = (int)$parentID; + } + $stories[$story->id] = $story; } @@ -3846,6 +3851,7 @@ class storyModel extends model ->where('root')->in($rootIdList) ->andWhere('product')->eq($productID) ->andWhere('deleted')->eq('0') + ->andWhere("FIND_IN_SET('{$this->config->vision}', vision)") ->beginIF($storyType == 'requirement') ->andWhere('type')->eq('story') ->beginIF($showGrades && isset($storyGrades))->andWhere('grade')->in($storyGrades)->fi() @@ -3977,7 +3983,7 @@ class storyModel extends model $storyCols = array(); foreach($showCols as $colType) { - if(!in_array($colType, array('epic', 'requirement', 'story'))) continue; + if(!in_array($colType, array('demand', 'epic', 'requirement', 'story'))) continue; foreach($tracks['cols'] as $col) { $colName = $col['name']; @@ -4442,9 +4448,6 @@ class storyModel extends model $story->finalResult = $result; - /* If in ipd mode, set requirement status = 'launched'. */ - if($this->config->systemMode == 'PLM' and $oldStory->type == 'requirement' and $story->status == 'active' and $this->config->vision == 'rnd') $story->status = 'launched'; - return $story; } diff --git a/module/story/tao.php b/module/story/tao.php index f18d37bc8c..c6cfe3fca0 100644 --- a/module/story/tao.php +++ b/module/story/tao.php @@ -264,14 +264,18 @@ class storyTao extends storyModel ->fetchPairs(); } + $demands = $this->dao->select('id,version')->from(TABLE_DEMAND)->where('deleted')->eq(0)->fetchPairs(); foreach($stories as $story) { /* Judge parent story has changed. */ - if($story->parent > 0 and isset($parents[$story->parent])) + if($story->parent > 0 && isset($parents[$story->parent])) { if($parents[$story->parent]->version > $story->parentVersion && $story->parentVersion > 0 && $parents[$story->parent]->status == 'active') $story->parentChanged = true; } + /* Judge demand has changed. */ + if($story->demand && $story->parent <= 0 && isset($demands[$story->demand]) && $demands[$story->demand] > $story->demandVersion) $story->demandChanged = true; + /* Judge parent story if has same type child or other type child. */ if($story->type != 'story' && $story->isParent == '1') { @@ -1894,7 +1898,7 @@ class storyTao extends storyModel $canActivate = common::hasPriv($story->type, 'activate') && $this->isClickable($story, 'activate'); if(!common::canBeChanged($story->type, $story)) return array(array('name' => 'close', 'hint' => $lang->close, 'data-toggle' => 'modal', 'url' => $canClose ? $closeLink : null, 'disabled' => !$canClose)); $canProcessChange = common::hasPriv($story->type, 'processStoryChange'); - if(!empty($story->parentChanged)) return array(array('name' => 'processStoryChange', 'url' => $canProcessChange ? $processStoryChangeLink : null, 'disabled' => !$canProcessChange, 'innerClass' => 'ajax-submit')); + if(!empty($story->parentChanged) || !empty($story->demandChanged)) return array(array('name' => 'processStoryChange', 'url' => $canProcessChange ? $processStoryChangeLink : null, 'disabled' => !$canProcessChange, 'innerClass' => 'ajax-submit')); /* Change button. */ $canChange = common::hasPriv($story->type, 'change') && $this->isClickable($story, 'change'); diff --git a/module/story/ui/view.html.php b/module/story/ui/view.html.php index 235789d0e3..6985e767b2 100644 --- a/module/story/ui/view.html.php +++ b/module/story/ui/view.html.php @@ -87,6 +87,7 @@ if($story->children) $cols['assignedTo'] = $config->story->dtable->fieldList['assignedTo']; $cols['estimate'] = $config->story->dtable->fieldList['estimate']; $cols['status'] = $config->story->dtable->fieldList['status']; + $cols['stage'] = $config->story->dtable->fieldList['stage']; $cols['actions'] = $config->story->dtable->fieldList['actions']; $cols['title']['title'] = $lang->story->name; $cols['id']['checkbox'] = false; diff --git a/module/story/zen.php b/module/story/zen.php index 7d98d3655e..0f38db84a5 100644 --- a/module/story/zen.php +++ b/module/story/zen.php @@ -1193,10 +1193,6 @@ class storyZen extends story /* Need and force review, then set status to reviewing. */ if($storyData->status != 'draft' and $this->story->checkForceReview($storyType) and !$this->post->needNotReview) $storyData->status = 'reviewing'; - /* If in ipd mode, set requirement status = 'launched'. */ - if($this->config->systemMode == 'PLM' && $storyData->type == 'requirement' && $storyData->status == 'active' && $this->config->vision == 'rnd') $storyData->status = 'launched'; - if($storyData->status == 'launched' && $this->app->tab != 'product') $storyData->status = 'developing'; - return $this->loadModel('file')->processImgURL($storyData, $editorFields, $this->post->uid); } @@ -1311,9 +1307,6 @@ class storyZen extends story ->setDefault('version', $oldStory->version) ->get(); - /* If in ipd mode, set requirement status = 'launched'. */ - if($this->config->systemMode == 'PLM' and $this->config->vision == 'rnd' and $oldStory->type == 'requirement' and $story->status == 'active') $story->status = 'launched'; - $specChanged = false; $oldStoryReviewers = array_keys($this->story->getReviewerPairs($storyID, $oldStory->version)); $_POST['reviewer'] = isset($_POST['reviewer']) ? $_POST['reviewer'] : array(); @@ -1513,9 +1506,6 @@ class storyZen extends story !empty($story->assignedTo) && $story->assignedDate = $now; if($this->post->uploadImage && $this->post->uploadImage[$i]) $story->uploadImage = $this->post->uploadImage[$i]; - - /* If in ipd mode, set requirement status = 'launched'. */ - if($this->config->systemMode == 'PLM' and $this->config->vision == 'rnd' and $storyType == 'requirement' and $story->status == 'active') $story->status = 'launched'; } return $stories;