diff --git a/module/upgrade/control.php b/module/upgrade/control.php index 93ae7084f3..360d1cafab 100644 --- a/module/upgrade/control.php +++ b/module/upgrade/control.php @@ -211,10 +211,11 @@ class upgrade extends control * * @param string $type * @param int $programID + * @param string $projectType project|execution * @access public * @return void */ - public function mergeProgram($type = 'productline', $programID = 0) + public function mergeProgram($type = 'productline', $programID = 0, $projectType = 'project') { $this->session->set('upgrading', true); $this->app->loadLang('program'); @@ -224,12 +225,14 @@ class upgrade extends control if($_POST) { + $projectType = isset($_POST['projectType']) ? $_POST['projectType'] : 'project'; if($type == 'productline') { $linkedProducts = array(); $linkedSprints = array(); $unlinkSprints = array(); $sprintProducts = array(); + $singleProducts = array(); /* Compute checked products and sprints, unchecked products and sprints. */ foreach($_POST['products'] as $lineID => $products) @@ -264,12 +267,20 @@ class upgrade extends control else { /* Use historical projects as project upgrades. */ + $singleProducts = array_diff($linkedProducts, $sprintProducts); foreach($linkedSprints as $sprint) { $this->upgrade->processMergedData($programID, $projectList[$sprint], $lineID, $sprintProducts[$sprint], array($sprint => $sprint)); } } + /* When upgrading historical data as a project, handle products that are not linked with the project. */ + if(!empty($singleProducts)) + { + $this->upgrade->computeProductAcl($singleProducts, $programID); + $this->upgrade->computeObjectMembers($programID, 0, $singleProducts); + } + /* Process unlinked sprint and product. */ foreach($linkedProducts as $productID => $product) { @@ -281,6 +292,8 @@ class upgrade extends control $linkedProducts = array(); $linkedSprints = array(); $unlinkSprints = array(); + $sprintProducts = array(); + $singleProducts = array(); foreach($_POST['products'] as $productID) { $linkedProducts[$productID] = $productID; @@ -289,7 +302,8 @@ class upgrade extends control { foreach($_POST['sprints'][$productID] as $sprintID) { - $linkedSprints[$sprintID] = $sprintID; + $linkedSprints[$sprintID] = $sprintID; + $sprintProducts[$sprintID] = $productID; unset($_POST['sprintIdList'][$productID][$sprintID]); } $unlinkSprints += $this->post->sprintIdList[$productID]; @@ -297,24 +311,57 @@ class upgrade extends control } /* Create Program. */ - list($programID, $projectID, $lineID) = $this->upgrade->createProgram($linkedProducts, $linkedSprints); + list($programID, $projectList, $lineID) = $this->upgrade->createProgram($linkedProducts, $linkedSprints); if(dao::isError()) die(js::error(dao::getError())); /* Process productline. */ $this->dao->delete()->from(TABLE_MODULE)->where('`root`')->eq(0)->andWhere('`type`')->eq('line')->exec(); /* Process merged products and projects. */ - $this->upgrade->processMergedData($programID, $projectID, $lineID, $linkedProducts, $linkedSprints); + if($_POST['projectType'] == 'execution') + { + /* Use historical projects as execution upgrades. */ + $this->upgrade->processMergedData($programID, $projectList, $lineID, $linkedProducts, $linkedSprints); + } + else + { + /* Use historical projects as project upgrades. */ + $singleProducts = array_diff($linkedProducts, $sprintProducts); + foreach($linkedSprints as $sprint) + { + $this->upgrade->processMergedData($programID, $projectList[$sprint], $lineID, $sprintProducts[$sprint], array($sprint => $sprint)); + } + } + + /* When upgrading historical data as a project, handle products that are not linked with the project. */ + if(!empty($singleProducts)) + { + $this->upgrade->computeProductAcl($singleProducts, $programID); + $this->upgrade->computeObjectMembers($programID, 0, $singleProducts); + } } elseif($type == 'sprint') { $linkedSprints = $this->post->sprints; /* Create Program. */ - list($programID, $projectID, $lineID) = $this->upgrade->createProgram(array(), $linkedSprints); + list($programID, $projectList, $lineID) = $this->upgrade->createProgram(array(), $linkedSprints); if(dao::isError()) die(js::error(dao::getError())); - $this->upgrade->processMergedData($programID, $projectID, $lineID, array(), $linkedSprints); + /* Process merged independent projects. */ + if($_POST['projectType'] == 'execution') + { + /* Use historical projects as execution upgrades. */ + $this->upgrade->processMergedData($programID, $projectList, $lineID, array(), $linkedSprints); + } + else + { + /* Use historical projects as project upgrades. */ + foreach($linkedSprints as $sprint) + { + $this->upgrade->processMergedData($programID, $projectList[$sprint], $lineID, array(), array($sprint => $sprint)); + } + } } elseif($type == 'moreLink') { @@ -327,7 +374,7 @@ class upgrade extends control } } - die(js::locate($this->createLink('upgrade', 'mergeProgram', "type=$type&programID=$programID"), 'parent')); + die(js::locate($this->createLink('upgrade', 'mergeProgram', "type=$type&programID=$programID&projectType=$projectType"), 'parent')); } /* Get no merged product and project count. */ @@ -499,13 +546,14 @@ class upgrade extends control $programs = $this->upgrade->getProgramPairs(); $currentProgramID = $programID ? $programID : key($programs); - $this->view->title = $this->lang->upgrade->mergeProgram; - $this->view->programs = $programs; - $this->view->programID = $programID; - $this->view->projects = array('' => '') + $this->upgrade->getProjectPairsByProgram($currentProgramID); - $this->view->lines = $currentProgramID ? array('' => '') + $this->loadModel('product')->getLinePairs($currentProgramID) : array('' => ''); - $this->view->users = $this->loadModel('user')->getPairs('noclosed|noempty'); - $this->view->groups = $this->loadModel('group')->getPairs(); + $this->view->title = $this->lang->upgrade->mergeProgram; + $this->view->programs = $programs; + $this->view->programID = $programID; + $this->view->projects = array('' => '') + $this->upgrade->getProjectPairsByProgram($currentProgramID); + $this->view->lines = $currentProgramID ? array('' => '') + $this->loadModel('product')->getLinePairs($currentProgramID) : array('' => ''); + $this->view->users = $this->loadModel('user')->getPairs('noclosed|noempty'); + $this->view->groups = $this->loadModel('group')->getPairs(); + $this->view->projectType = $projectType; $this->display(); } diff --git a/module/upgrade/css/mergeprogram.css b/module/upgrade/css/mergeprogram.css index 4ae38cfbfe..9ac8e4b412 100644 --- a/module/upgrade/css/mergeprogram.css +++ b/module/upgrade/css/mergeprogram.css @@ -17,11 +17,11 @@ div.divider {vertical-align: middle;} .main-row .side-col .nav li div a {width: 80%; display: inline-block; padding: 8px 15px;} #lineBox > .cell {height: 700px;} -#source > .cell {padding: 0; position: relative; height: 450px;} +#source > .cell {padding: 0; position: relative; height: 700px;} #source > .cell > .lineGroup-title {position: absolute; top: 0; left: 0; right: 0; padding: 10px;} #source > .cell > .line-groups {position: absolute; top: 40px; left: 0; bottom: 0; right: 0; overflow: auto; padding: 0 10px 10px 10px;} #source .lineGroup-title .item {float: left;} -#source .lineGroup-title .item:first-child {width: 176px;} +#source .lineGroup-title .item:first-child {width: 170px; margin-left: 6px;} #source .lineGroup>div {display: table-cell;} #source .lineGroup {background: #f1f1f1; border-radius: 4px; display: table; width: 100%;} #source .lineGroup+.lineGroup {margin-top: 10px;} diff --git a/module/upgrade/js/mergeprogram.js b/module/upgrade/js/mergeprogram.js index b1eac77dda..fd07149c97 100644 --- a/module/upgrade/js/mergeprogram.js +++ b/module/upgrade/js/mergeprogram.js @@ -86,6 +86,7 @@ $(function() $('.projectName').addClass('hidden'); $('.projectAcl').addClass('hidden'); $('.programAcl').removeClass('hidden'); + $('.projectStatus').addClass('hidden'); $('[name=projectAcl]').attr('disabled', 'disabled'); $('[name=programAcl]').removeAttr('disabled'); } @@ -94,6 +95,7 @@ $(function() $('.projectName').removeClass('hidden'); $('.programAcl').addClass('hidden'); $('.projectAcl').removeClass('hidden'); + $('.projectStatus').removeClass('hidden'); $('[name=programAcl]').attr('disabled', 'disabled'); $('[name=projectAcl]').removeAttr('disabled'); } @@ -143,14 +145,17 @@ $(function() $('.projectName').addClass('hidden'); $('.projectAcl').addClass('hidden'); $('.programAcl').removeClass('hidden'); + $('.projectStatus').addClass('hidden'); $('[name=projectAcl]').attr('disabled', 'disabled'); $('[name=programAcl]').removeAttr('disabled'); } + if(projectType == 'execution') { $('.projectName').removeClass('hidden'); $('.programAcl').addClass('hidden'); $('.projectAcl').removeClass('hidden'); + $('.projectStatus').removeClass('hidden'); $('[name=programAcl]').attr('disabled', 'disabled'); $('[name=projectAcl]').removeAttr('disabled'); } @@ -242,6 +247,7 @@ $(function() }) $('#checkAllLines').prop('checked', checked); + hiddenProject(); /* If the project is checked, the relevant form will be displayed according to the selected mode. */ $('[id^=sprints]').each(function() { @@ -253,6 +259,7 @@ $(function() $('.projectName').addClass('hidden'); $('.projectAcl').addClass('hidden'); $('.programAcl').removeClass('hidden'); + $('.projectStatus').addClass('hidden'); $('[name=projectAcl]').attr('disabled', 'disabled'); $('[name=programAcl]').removeAttr('disabled'); } @@ -261,14 +268,13 @@ $(function() $('.projectName').removeClass('hidden'); $('.programAcl').addClass('hidden'); $('.projectAcl').removeClass('hidden'); + $('.projectStatus').removeClass('hidden'); $('[name=programAcl]').attr('disabled', 'disabled'); $('[name=projectAcl]').removeAttr('disabled'); } - hiddenProject(); return false; } }) - hiddenProject(); }) $('[name^=lines]').change(function() @@ -383,6 +389,7 @@ $(function() $('.projectName').addClass('hidden'); $('.projectAcl').addClass('hidden'); $('.programAcl').removeClass('hidden'); + $('.projectStatus').addClass('hidden'); $('[name=projectAcl]').attr('disabled', 'disabled'); $('[name=programAcl]').removeAttr('disabled'); } @@ -391,6 +398,7 @@ $(function() $('.projectName').removeClass('hidden'); $('.programAcl').addClass('hidden'); $('.projectAcl').removeClass('hidden'); + $('.projectStatus').removeClass('hidden'); $('[name=programAcl]').attr('disabled', 'disabled'); $('[name=projectAcl]').removeAttr('disabled'); } @@ -481,17 +489,6 @@ $(function() /* Toggles data migration mode events. */ $('input[name="projectType"]').change(function() { - if($(this).val() == 'execution') - { - $('.createExecutionTip').removeClass('hidden'); - $('.createProjectTip').addClass('hidden'); - $('.projectName').removeClass('hidden'); - $('.programAcl').addClass('hidden'); - $('.projectAcl').removeClass('hidden'); - $('[name=programAcl]').attr('disabled', 'disabled'); - $('[name=projectAcl]').removeAttr('disabled'); - } - if($(this).val() == 'project') { $('.createProjectTip').removeClass('hidden'); @@ -499,10 +496,45 @@ $(function() $('.projectName').addClass('hidden'); $('.projectAcl').addClass('hidden'); $('.programAcl').removeClass('hidden'); + $('.projectStatus').addClass('hidden'); $('[name=projectAcl]').attr('disabled', 'disabled'); $('[name=programAcl]').removeAttr('disabled'); } + + if($(this).val() == 'execution') + { + $('.createExecutionTip').removeClass('hidden'); + $('.createProjectTip').addClass('hidden'); + $('.projectName').removeClass('hidden'); + $('.programAcl').addClass('hidden'); + $('.projectAcl').removeClass('hidden'); + $('.projectStatus').removeClass('hidden'); + $('[name=programAcl]').attr('disabled', 'disabled'); + $('[name=projectAcl]').removeAttr('disabled'); + } }) + + /* Hide project information. */ + var projectType = $('input[name="projectType"]:checked').val(); + if(projectType == 'project') + { + $('.projectName').addClass('hidden'); + $('.projectAcl').addClass('hidden'); + $('.programAcl').removeClass('hidden'); + $('.projectStatus').addClass('hidden'); + $('[name=projectAcl]').attr('disabled', 'disabled'); + $('[name=programAcl]').removeAttr('disabled'); + } + + if(projectType == 'execution') + { + $('.projectName').removeClass('hidden'); + $('.programAcl').addClass('hidden'); + $('.projectAcl').removeClass('hidden'); + $('.projectStatus').removeClass('hidden'); + $('[name=programAcl]').attr('disabled', 'disabled'); + $('[name=projectAcl]').removeAttr('disabled'); + } }); /** diff --git a/module/upgrade/model.php b/module/upgrade/model.php index 982d274eff..3bce2017f3 100644 --- a/module/upgrade/model.php +++ b/module/upgrade/model.php @@ -4263,6 +4263,7 @@ class upgradeModel extends model $program->openedVersion = $this->config->version; $program->acl = isset($data->programAcl) ? $data->programAcl : 'open'; $program->days = $this->computeDaysDelta($program->begin, $program->end); + $program->PM = $data->projectType == 'project' ? $data->PM : ''; $this->app->loadLang('program'); $this->app->loadLang('project'); @@ -4340,11 +4341,16 @@ class upgradeModel extends model else { /* Use historical projects as project upgrades. */ - $nameList = $this->dao->select('id,name')->from(TABLE_PROJECT)->where('id')->in($projectIdList)->fetchPairs(); - foreach($projectIdList as $project) + $projects = $this->dao->select('id,name,begin,end,status,PM')->from(TABLE_PROJECT)->where('id')->in($projectIdList)->fetchAll('id'); + foreach($projectIdList as $projectID) { - $data->projectName = $nameList[$project]; - $projectList[$project] = $this->createProject($programID, $data); + $data->projectName = $projects[$projectID]->name; + $data->begin = $projects[$projectID]->begin; + $data->end = $projects[$projectID]->end; + $data->projectStatus = $projects[$projectID]->status; + $data->PM = $projects[$projectID]->PM; + + $projectList[$projectID] = $this->createProject($programID, $data); } } } @@ -4465,17 +4471,7 @@ class upgradeModel extends model $this->dao->update(TABLE_RELEASE)->set('project')->eq($projectID)->where('product')->in($productIdList)->exec(); /* Compute product acl. */ - $products = $this->dao->select('id,program,acl')->from(TABLE_PRODUCT)->where('id')->in($productIdList)->fetchAll(); - foreach($products as $product) - { - if($product->program) continue; - - $data = new stdclass(); - $data->program = $programID; - $data->acl = $product->acl == 'custom' ? 'private' : $product->acl; - - $this->dao->update(TABLE_PRODUCT)->data($data)->where('id')->eq($product->id)->exec(); - } + $this->computeProductAcl($productIdList, $programID); /* No project is created when there are no sprints. */ if(!$sprintIdList) return; @@ -4582,6 +4578,30 @@ class upgradeModel extends model $this->computeObjectMembers($programID, $projectID, $productIdList, $sprintIdList); } + /** + * Compute product acl. + * + * @param array $productIdList + * @param int $programID + * @access public + * @return void + */ + public function computeProductAcl($productIdList = array(), $programID = 0) + { + /* Compute product acl. */ + $products = $this->dao->select('id,program,acl')->from(TABLE_PRODUCT)->where('id')->in($productIdList)->fetchAll(); + foreach($products as $product) + { + if($product->program) continue; + + $data = new stdclass(); + $data->program = $programID; + $data->acl = $product->acl == 'custom' ? 'private' : $product->acl; + + $this->dao->update(TABLE_PRODUCT)->data($data)->where('id')->eq($product->id)->exec(); + } + } + /** * Compute program and project members. * diff --git a/module/upgrade/view/createprogram.html.php b/module/upgrade/view/createprogram.html.php index a6b2c77f02..04bc318654 100644 --- a/module/upgrade/view/createprogram.html.php +++ b/module/upgrade/view/createprogram.html.php @@ -1,6 +1,6 @@
| lang->upgrade->projectType, 'project');?> | |
| lang->upgrade->projectType, $projectType);?> | |
| upgrade->createProjectTip?> | |
| project->status;?> | project->statusList, '', "class='form-control chosen'");?> |
|---|