diff --git a/module/branch/control.php b/module/branch/control.php index e96b1fc105..6ebe913c09 100644 --- a/module/branch/control.php +++ b/module/branch/control.php @@ -66,14 +66,14 @@ class branch extends control */ public function ajaxGetDropMenu($productID, $branch = 0, $module, $method, $extra = '') { - $this->view->link = $this->loadModel('product')->getProductLink($module, $method, $extra, true); - $this->view->productID = $productID; - $this->view->projectID = $this->session->project; - $this->view->module = $module; - $this->view->method = $method; - $this->view->extra = $extra; + $branches = $this->branch->getPairs($productID, 'all'); - $branches = $this->branch->getPairs($productID); + $this->view->link = $this->loadModel('product')->getProductLink($module, $method, $extra, true); + $this->view->productID = $productID; + $this->view->projectID = $this->session->project; + $this->view->module = $module; + $this->view->method = $method; + $this->view->extra = $extra; $this->view->branches = $branches; $this->view->currentBranchID = $branch; $this->view->branchesPinyin = common::convert2Pinyin($branches); diff --git a/module/branch/model.php b/module/branch/model.php index e2a4b000ad..d9f119ce03 100644 --- a/module/branch/model.php +++ b/module/branch/model.php @@ -89,8 +89,12 @@ class branchModel extends model { $product = $this->loadModel('product')->getById($productID); if(!$product or $product->type == 'normal') return array(); + $branches = array('0' => $this->lang->branch->main) + $branches; + } - $branches = array('all' => $this->lang->branch->all, '0' => $this->lang->branch->main) + $branches; + if(strpos($params, 'all') !== false) + { + $branches = array('all' => $this->lang->branch->all) + $branches; } return $branches; } diff --git a/module/bug/control.php b/module/bug/control.php index 63a3446018..d3d9486b1f 100644 --- a/module/bug/control.php +++ b/module/bug/control.php @@ -226,7 +226,7 @@ class bug extends control $this->view->moduleID = $moduleID; $this->view->memberPairs = $this->user->getPairs('noletter|nodeleted'); $this->view->branch = $branch; - $this->view->branches = $this->loadModel('branch')->getPairs($productID, 'noempty'); + $this->view->branches = $this->loadModel('branch')->getPairs($productID); $this->view->executions = $executions; $this->view->plans = $this->loadModel('productplan')->getPairs($productID); $this->view->stories = $storyList; diff --git a/module/productplan/control.php b/module/productplan/control.php index fcd0b36611..68ebf9bbad 100644 --- a/module/productplan/control.php +++ b/module/productplan/control.php @@ -413,7 +413,7 @@ class productplan extends control else { $this->config->product->search['fields']['branch'] = $this->lang->product->branch; - $branches = array('' => '') + $this->loadModel('branch')->getPairs($plan->product, 'noempty'); + $branches = array('' => '', $this->loadModel('branch')->getPairs($plan->product); if($plan->branch) $branches = array('' => '', $plan->branch => $branches[$plan->branch]); $this->config->product->search['params']['branch']['values'] = $branches; } @@ -554,7 +554,7 @@ class productplan extends control else { $this->config->bug->search['fields']['branch'] = $this->lang->product->branch; - $branches = array('' => '') + $this->loadModel('branch')->getPairs($productID, 'noempty'); + $branches = array('' => '') + $this->loadModel('branch')->getPairs($productID); if($plan->branch) $branches = array('' => '', $plan->branch => $branches[$plan->branch]); $this->config->bug->search['params']['branch']['values'] = $branches; } diff --git a/module/productplan/model.php b/module/productplan/model.php index 0e76645121..8fcbd05056 100644 --- a/module/productplan/model.php +++ b/module/productplan/model.php @@ -237,7 +237,6 @@ class productplanModel extends model $plans = $this->dao->select('id,title,parent,begin,end')->from(TABLE_PRODUCTPLAN) ->where('product')->in($product) ->andWhere('deleted')->eq(0) - ->andWhere('end')->ge($date) ->beginIF($branch)->andWhere("branch")->in("0,$branch")->fi() ->beginIF($skipParent)->andWhere('parent')->ne(-1)->fi() ->orderBy('begin desc') @@ -319,6 +318,45 @@ class productplanModel extends model return $this->dao->select('*')->from(TABLE_PRODUCTPLAN)->where('parent')->eq((int)$planID)->andWhere('deleted')->eq('0')->fetchAll(); } + /** + * Get plan list by story id list. + * + * @param string|array $storyIdList + * @access public + * @return array + */ + public function getPlansByStories($storyIdList) + { + if(empty($storyIdList)) return array(); + return $this->dao->select('t1.id as storyID, t3.*')->from(TABLE_STORY)->alias('t1') + ->leftJoin(TABLE_PLANSTORY)->alias('t2')->on('t1.id=t2.story') + ->leftJoin(TABLE_PRODUCTPLAN)->alias('t3')->on('t2.plan=t3.id') + ->where('t1.id')->in($storyIdList) + ->fetchGroup('storyID', 'id'); + } + + /** + * Get branch plan pairs. + * + * @param int $productID + * @access public + * @return array + */ + public function getBranchPlanPairs($productID) + { + $plans = $this->dao->select('branch,id,title,begin,end')->from(TABLE_PRODUCTPLAN) + ->where('deleted')->eq(0) + ->andWhere('product')->eq($productID) + ->fetchAll('id'); + + $planPairs = array(); + foreach($plans as $planID => $plan) + { + $planPairs[$plan->branch][$planID] = $plan->title . ' [' . $plan->begin . '~' . $plan->end . ']'; + } + return $planPairs; + } + /** * Create a plan. * diff --git a/module/story/control.php b/module/story/control.php index 90da967309..3a406dd2b6 100644 --- a/module/story/control.php +++ b/module/story/control.php @@ -626,6 +626,7 @@ class story extends control $this->view->stories = $stories; $this->view->users = $users; $this->view->product = $product; + $this->view->plans = $this->loadModel('productplan')->getPairsForStory($story->product, $story->branch, true); $this->view->products = $myProducts + $othersProducts; $this->view->branches = $product->type == 'normal' ? array() : $this->loadModel('branch')->getPairs($story->product); $this->view->reviewers = implode(',', $reviewerList); @@ -705,15 +706,12 @@ class story extends control $product = $this->product->getByID($productID); $branchProduct = $product->type == 'normal' ? false : true; - /* Set modules and productPlans. */ - $modules = $this->tree->getOptionMenu($productID, $viewType = 'story', 0, $branch); - $modules = array('ditto' => $this->lang->story->ditto) + $modules; - $productPlans = $this->productplan->getPairs($productID, $branch, '', true); - $productPlans = array('' => '', 'ditto' => $this->lang->story->ditto) + $productPlans; + /* Set modules. */ + $modules = array('ditto' => $this->lang->story->ditto) + $this->tree->getOptionMenu($productID, $viewType = 'story', 0, $branch); $this->view->modules = $modules; $this->view->branches = $product->type == 'normal' ? array() : $this->loadModel('branch')->getPairs($product->id); - $this->view->productPlans = $productPlans; + $this->view->plans = $this->productplan->getBranchPlanPairs($productID); $this->view->position[] = html::a($this->createLink('product', 'browse', "product=$product->id&branch=$branch"), $product->name); $this->view->title = $product->name . $this->lang->colon . $this->lang->story->batchEdit; } @@ -1376,14 +1374,55 @@ class story extends control * Batch change branch. * * @param int $branchID + * @param string $confirm yes|no + * @param string $storyIdList * @access public * @return void */ - public function batchChangeBranch($branchID) + public function batchChangeBranch($branchID, $confirm = '', $storyIdList = '') { - $storyIdList = !empty($_POST['storyIdList']) ? $this->post->storyIdList : die(js::locate($this->session->storyList, 'parent')); + if(!empty($_POST['storyIdList'])) $storyIdList = $_POST['storyIdList']; + $storyIdList = !empty($storyIdList) ? $storyIdList : die(js::locate($this->session->storyList, 'parent')); + $plans = $this->loadModel('productplan')->getPlansByStories($storyIdList); + if(empty($confirm)) + { + $stories = $this->story->getByList($storyIdList); + $normalStotyIdList = ''; + $conflictStoryIdList = ''; + $conflictStoryArray = array(); + + /* Determine whether there is a conflict between the branch of the story and the linked plan. */ + foreach($storyIdList as $storyID) + { + if($stories[$storyID]->branch != $branchID and $branchID != BRANCH_MAIN and isset($plans[$storyID])) + { + foreach($plans[$storyID] as $plan) + { + if($plan->branch != BRANCH_MAIN and $plan->branch != $branchID) + { + $conflictStoryIdList .= '[' . $storyID . ']'; + $conflictStoryArray[] = $storyID; + break; + } + } + } + } + + /* Prompt the user whether to continue to modify the conflicting stories branch. */ + if($conflictStoryIdList) + { + $normalStotyIdList = array_diff($storyIdList, $conflictStoryArray); + $normalStotyIdList = implode(',', $normalStotyIdList); + $storyIdList = implode(',', $storyIdList); + $confirmURL = $this->createLink('story', 'batchChangeBranch', "branchID=$branchID&confirm=yes&storyIdList=$storyIdList"); + $cancelURL = $this->createLink('story', 'batchChangeBranch', "branchID=$branchID&confirm=no&storyIdList=$normalStotyIdList"); + die(js::confirm(sprintf($this->lang->story->confirmChangeBranch, $conflictStoryIdList ), $confirmURL, $cancelURL)); + } + } + + if(is_string($storyIdList)) $storyIdList = array_filter(explode(',', $storyIdList)); $storyIdList = array_unique($storyIdList); - $allChanges = $this->story->batchChangeBranch($storyIdList, $branchID); + $allChanges = $this->story->batchChangeBranch($storyIdList, $branchID, $confirm, $plans); if(dao::isError()) die(js::error(dao::getError())); foreach($allChanges as $storyID => $changes) { diff --git a/module/story/lang/en.php b/module/story/lang/en.php index 9424fb6cdd..75cfdb335c 100644 --- a/module/story/lang/en.php +++ b/module/story/lang/en.php @@ -277,6 +277,7 @@ $lang->story->moveChildrenTips = "Its Child {$lang->SRCommon} will be moved $lang->story->changeTips = 'The story associated with the requirements to change, click "Cancel" ignore this change, click "Confirm" to change the story.'; $lang->story->estimateMustBeNumber = 'Estimate value must be number.'; $lang->story->estimateMustBePlus = 'Estimated value cannot be negative'; +$lang->story->confirmChangeBranch = $lang->SRCommon . ' %s is linked to the plan of its linked branch. If the branch is edited, ' . $lang->SRCommon . ' will be removed from the plan of its linked branch. Do you want to continue edit ' . $lang->SRCommon . '?'; $lang->story->form = new stdclass(); $lang->story->form->area = 'Scope'; diff --git a/module/story/lang/zh-cn.php b/module/story/lang/zh-cn.php index 1d34df98bd..6c485b6e94 100644 --- a/module/story/lang/zh-cn.php +++ b/module/story/lang/zh-cn.php @@ -277,6 +277,7 @@ $lang->story->moveChildrenTips = "修改父{$lang->SRCommon}的所属产品 $lang->story->changeTips = '该软件需求关联的用户需求有变更,点击“不变更”忽略此条变更,点击“变更”来进行该软件需求的变更。'; $lang->story->estimateMustBeNumber = '估算值必须是数字'; $lang->story->estimateMustBePlus = '估算值不能是负数'; +$lang->story->confirmChangeBranch = $lang->SRCommon . '%s已关联在之前所属分支的计划中,调整分支后,' . $lang->SRCommon . '将从之前所属分支的计划中移除,请确认是否继续修改上述' . $lang->SRCommon . '的分支。'; $lang->story->form = new stdclass(); $lang->story->form->area = "该{$lang->SRCommon}所属范围"; diff --git a/module/story/model.php b/module/story/model.php index 186f2642d6..e2e03ccf98 100644 --- a/module/story/model.php +++ b/module/story/model.php @@ -1619,6 +1619,7 @@ class storyModel extends model foreach($storyIdList as $storyID) { $oldStory = $oldStories[$storyID]; + if($oldStory->branch != BRANCH_MAIN and $oldStory->branch != $plan->branch and $plan->branch != BRANCH_MAIN) continue; /* Ignore parent story, closed story and story linked to this plan already. */ if($oldStory->parent < 0) continue; @@ -1674,10 +1675,12 @@ class storyModel extends model * * @param array $storyIdList * @param int $branchID + * @param string $confirm + * @param array $plans * @access public - * @return void + * @return array */ - public function batchChangeBranch($storyIdList, $branchID) + public function batchChangeBranch($storyIdList, $branchID, $confirm = '', $plans = array()) { $now = helper::now(); $allChanges = array(); @@ -1692,7 +1695,38 @@ class storyModel extends model $story->branch = $branchID; $this->dao->update(TABLE_STORY)->data($story)->autoCheck()->where('id')->eq((int)$storyID)->exec(); - if(!dao::isError()) $allChanges[$storyID] = common::createChanges($oldStory, $story); + if(!dao::isError()) + { + if($confirm == 'yes') + { + $planIdList = ''; + $conflictPlanIdList = ''; + /* Determine whether there is a conflict between the branch of the story and the linked plan. */ + if($oldStory->branch != $branchID and $branchID != BRANCH_MAIN and isset($plans[$storyID])) + { + foreach($plans[$storyID] as $planID => $plan) + { + if($plan->branch != BRANCH_MAIN and $plan->branch != $branchID) + { + $conflictPlanIdList .= $planID . ','; + } + else + { + $planIdList .= $planID . ','; + } + } + + /* If there is a conflict in the linked plan when the branch story to be modified, the linked with the conflicting plan will be removed. */ + if($conflictPlanIdList) + { + $story->plan = $planIdList; + $this->dao->delete()->from(TABLE_PLANSTORY)->where('story')->eq($storyID)->andWhere('plan')->in($conflictPlanIdList)->exec(); + $this->dao->update(TABLE_STORY)->set('plan')->eq($planIdList)->where('id')->eq($storyID)->exec(); + } + } + } + $allChanges[$storyID] = common::createChanges($oldStory, $story); + } } return $allChanges; } diff --git a/module/story/view/batchedit.html.php b/module/story/view/batchedit.html.php index 5cc967b16b..fee5c7e5bc 100644 --- a/module/story/view/batchedit.html.php +++ b/module/story/view/batchedit.html.php @@ -100,6 +100,18 @@ foreach(explode(',', $showFields) as $field) module, "class='form-control chosen'");?>