Merge branch 'master' of https://git.zcorp.cc/easycorp/zentaopms
This commit is contained in:
@@ -1816,7 +1816,7 @@ class block extends control
|
||||
/* load pager. */
|
||||
$this->app->loadClass('pager', $static = true);
|
||||
$pager = new pager(0, 3, 1);
|
||||
$this->view->projects = $this->loadModel('project')->getList('all', 'id_desc', 1, $pager);
|
||||
$this->view->projects = $this->loadModel('project')->getList('all', 'id_desc', true, $pager);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -73,7 +73,7 @@ class project extends control
|
||||
|
||||
if(isset($fields['hasProduct'])) $fields['hasProduct'] = $projectLang->type;
|
||||
|
||||
$projects = $this->project->getList($status, $orderBy, null);
|
||||
$projects = $this->project->getList($status, $orderBy);
|
||||
$users = $this->loadModel('user')->getPairs('noletter');
|
||||
|
||||
$this->loadModel('product');
|
||||
@@ -1930,8 +1930,8 @@ class project extends control
|
||||
}
|
||||
|
||||
/**
|
||||
* 管理项目下的关联产品
|
||||
* Manage products.
|
||||
* 管理项目的关联产品
|
||||
* Manage products under project.
|
||||
*
|
||||
* @param string $projectID
|
||||
* @param string $from project|program|programproject
|
||||
@@ -1941,6 +1941,7 @@ class project extends control
|
||||
*/
|
||||
public function manageProducts(string $projectID, $from = 'project'): mixed
|
||||
{
|
||||
/* Access the nonProduct project alter tips. */
|
||||
$projectID = (int)$projectID;
|
||||
$project = $this->project->getById($projectID);
|
||||
if(!$project->hasProduct) return print(js::error($this->lang->project->cannotManageProducts) . js::locate('back'));
|
||||
@@ -1957,6 +1958,7 @@ class project extends control
|
||||
return $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
}
|
||||
|
||||
/* Update linked products. */
|
||||
$this->projectZen->mergeProducts($projectID, $project, $executionIDs, $postData);
|
||||
|
||||
$locateLink = inLink('manageProducts', "projectID=$projectID");
|
||||
@@ -1964,9 +1966,10 @@ class project extends control
|
||||
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $locateLink));
|
||||
}
|
||||
|
||||
/* Set menu. */
|
||||
if($this->app->tab == 'program')
|
||||
{
|
||||
$this->program->setMenu($project->parent);
|
||||
$this->loadModel('program')->setMenu($project->parent);
|
||||
}
|
||||
else if($this->app->tab == 'project')
|
||||
{
|
||||
@@ -1974,7 +1977,12 @@ class project extends control
|
||||
}
|
||||
|
||||
$this->projectZen->dealLinkProduct($projectID, $project);
|
||||
$this->projectZen->buildMangedProductForm($projectID, $project, $executions);
|
||||
|
||||
$this->view->title = $this->lang->project->manageProducts . $this->lang->colon . $project->name;
|
||||
$this->view->project = $project;
|
||||
$this->view->executions = $executions;
|
||||
$this->view->branches = $this->project->getBranchesByProject($projectID);
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -236,12 +236,12 @@ class projectModel extends model
|
||||
*
|
||||
* @param string $status
|
||||
* @param string $orderBy
|
||||
* @param bool $involved
|
||||
* @param int $pager
|
||||
* @param int $involved
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getList($status = 'undone', $orderBy = 'order_desc', $pager = null, $involved = 0)
|
||||
public function getList(string $status = 'undone', string $orderBy = 'order_desc', bool $involved = false, object|null $pager = null): array
|
||||
{
|
||||
/* Init vars. */
|
||||
$projects = $this->projectTao->fetchProjectList($status, $orderBy, $involved, $pager);
|
||||
|
||||
@@ -517,18 +517,18 @@ class projectTao extends projectModel
|
||||
}
|
||||
|
||||
/**
|
||||
* 将旧的产品替换成新的
|
||||
* replace oldProduct
|
||||
* 查找项目执行下关联的产品
|
||||
* Get linked products with execution under the project.
|
||||
*
|
||||
* @param array $executionIDs
|
||||
*
|
||||
* @access protected
|
||||
* @return bool
|
||||
* @return array
|
||||
*/
|
||||
protected function replaceOldProduct(array $executionIDs): bool
|
||||
protected function getExecutionProductGroup(array $executionIDs): array
|
||||
{
|
||||
$oldExecutionProducts = $this->dao->select('project,product')->from(TABLE_PROJECTPRODUCT)->where('project')->in($executionIDs)->fetchGroup('project', 'product');
|
||||
return !dao::isError();
|
||||
return $oldExecutionProducts;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -537,12 +537,12 @@ class projectTao extends projectModel
|
||||
*
|
||||
* @param string $status
|
||||
* @param string $orderBy
|
||||
* @param int $involved
|
||||
* @param bool $involved
|
||||
* @param object $pager
|
||||
* @access protected
|
||||
* @return array
|
||||
*/
|
||||
protected function fetchProjectList(string $status, string $orderBy, int $involved, object|null $pager): array
|
||||
protected function fetchProjectList(string $status, string $orderBy, bool $involved, object|null $pager): array
|
||||
{
|
||||
return $this->dao->select('DISTINCT t1.*')->from(TABLE_PROJECT)->alias('t1')
|
||||
->leftJoin(TABLE_TEAM)->alias('t2')->on('t1.id=t2.root')
|
||||
|
||||
@@ -1,28 +1,59 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/project.class.php';
|
||||
su('admin');
|
||||
zdTable('project')->gen(90);
|
||||
|
||||
function initData()
|
||||
{
|
||||
$project = zdTable('project');
|
||||
$project->id->range('11-19');
|
||||
$project->project->range('11-19');
|
||||
$project->name->prefix("项目")->range('11-19');
|
||||
$project->code->prefix("project")->range('11-19');
|
||||
$project->model->range("scrum");
|
||||
$project->auth->range("[]");
|
||||
$project->path->range("[]");
|
||||
$project->type->range("project");
|
||||
$project->grade->range("1");
|
||||
$project->days->range("1");
|
||||
$project->status->range("wait,doing,suspended,closed");
|
||||
$project->desc->range("[]");
|
||||
$project->budget->range("100000,200000");
|
||||
$project->budgetUnit->range("CNY");
|
||||
$project->percent->range("0-0");
|
||||
$project->openedDate->range("`2023-05-01 10:00:10`");
|
||||
$project->gen(9);
|
||||
|
||||
zdTable('team')->gen(10);
|
||||
|
||||
$stakeholder = zdTable('stakeholder');
|
||||
$stakeholder->id->range('1-9');
|
||||
$stakeholder->objectID->range('11-19');
|
||||
$stakeholder->objectType->range('program,project');
|
||||
$stakeholder->user->range("admin");
|
||||
$stakeholder->type->range("inside");
|
||||
$stakeholder->from->range("[]");
|
||||
$stakeholder->createdBy->range("admin");
|
||||
$stakeholder->createdDate->range("`2023-05-01 10:00:10`");
|
||||
$stakeholder->gen(9);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
title=测试 projectModel::getInfoList;
|
||||
title=测试 projectModel::fetchProjectList();
|
||||
timeout=0
|
||||
cid=1
|
||||
|
||||
|
||||
*/
|
||||
|
||||
global $tester;
|
||||
$tester->loadModel('project');
|
||||
initData();
|
||||
$statusList = array('', 'all', 'undone', 'unclosed', 'error');
|
||||
|
||||
$doingProjects = $tester->project->getList('doing');
|
||||
$waitProjects = $tester->project->getList('wait');
|
||||
$suspendedProjects = $tester->project->getList('suspended');
|
||||
$closedProjects = $tester->project->getList('closed');
|
||||
$allProjects = $tester->project->getList('all');
|
||||
|
||||
r(count($doingProjects)) && p() && e('44'); //查询正在进行的项目数量
|
||||
r($waitProjects) && p('11:name') && e('项目1'); //查询wait状态的Id为11的项目名称
|
||||
r(count($suspendedProjects)) && p() && e('11'); //查询暂停状态的项目数量
|
||||
r(count($closedProjects)) && p() && e('11'); //查询关闭状态的项目数量
|
||||
r(count($allProjects)) && p() && e('90'); //查询所有状态的项目数量
|
||||
$projectTester = new Project();
|
||||
r($projectTester->testGetList($statusList[0])) && p() && e('0'); // 查询状态为空的项目
|
||||
r(count($projectTester->testGetList($statusList[1]))) && p() && e('9'); // 获取所有项目数量
|
||||
r($projectTester->testGetList($statusList[2])) && p('11:code') && e('project11'); // 查询未完成的第一个项目的code
|
||||
r($projectTester->testGetList($statusList[3], true)) && p('12:name') && e('项目12'); // 获取我参与的一个项目的项目名
|
||||
r($projectTester->testGetList($statusList[4])) && p() && e('0'); // 获取错误类型的项目
|
||||
|
||||
@@ -215,12 +215,25 @@ class Project
|
||||
* Test fetchProjectList function.
|
||||
*
|
||||
* @param int $status
|
||||
* @param string $orderBy
|
||||
* @param int $involved
|
||||
* @param bool $involved
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function testFetchProjectList($status, $involved = 0)
|
||||
public function testFetchProjectList($status, $involved = false)
|
||||
{
|
||||
$projects = $this->project->fetchProjectList($status, 'id_desc', $involved, null);
|
||||
return $projects;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getList function.
|
||||
*
|
||||
* @param int $status
|
||||
* @param bool $involved
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function testGetList($status, $involved = false)
|
||||
{
|
||||
$projects = $this->project->fetchProjectList($status, 'id_desc', $involved, null);
|
||||
return $projects;
|
||||
|
||||
@@ -55,5 +55,5 @@ $projectTester = new Project();
|
||||
r($projectTester->testFetchProjectList($statusList[0])) && p() && e('0'); // 查询状态为空的项目
|
||||
r(count($projectTester->testFetchProjectList($statusList[1]))) && p() && e('9'); // 获取所有项目数量
|
||||
r($projectTester->testFetchProjectList($statusList[2])) && p('11:code') && e('project11'); // 查询未完成的第一个项目的code
|
||||
r($projectTester->testFetchProjectList($statusList[3], 1)) && p('12:name') && e('项目12'); // 获取我参与的一个项目的项目名
|
||||
r($projectTester->testFetchProjectList($statusList[3], true)) && p('12:name') && e('项目12'); // 获取我参与的一个项目的项目名
|
||||
r($projectTester->testFetchProjectList($statusList[4])) && p() && e('0'); // 获取错误类型的项目
|
||||
|
||||
+90
-92
@@ -652,8 +652,8 @@ class projectZen extends project
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理并合并项目下的新旧产品
|
||||
* mergeProducts
|
||||
* 关联产品时,合并项目下的新旧产品
|
||||
* Merge old and new products under the project When link products.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @param object $project
|
||||
@@ -672,21 +672,20 @@ class projectZen extends project
|
||||
$this->project->updateProducts($projectID);
|
||||
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
|
||||
//判断是否为项目型项目并更新关联产品
|
||||
if(empty($project->multiple))
|
||||
{
|
||||
$executionID = $this->execution->getNoMultipleID($projectID);
|
||||
if($executionID) $this->execution->updateProducts($executionID);
|
||||
}
|
||||
|
||||
//将项目下关联的新旧产品合并
|
||||
/* Merge old and new linked products under the project. */
|
||||
$newProducts = $this->product->getProducts($projectID);
|
||||
$oldProductIDs = array_keys($oldProducts);
|
||||
$newProductIDs = array_keys($newProducts);
|
||||
$diffProducts = array_merge(array_diff($oldProductIDs, $newProductIDs), array_diff($newProductIDs, $oldProductIDs));
|
||||
if($diffProducts) $this->loadModel('action')->create('project', $projectID, 'Managed', '', !empty($postData->rawdata->products) ? implode(',', $postData->rawdata->products) : '');
|
||||
|
||||
//判断是否为产品型项目并更新关联产品
|
||||
/* Multiple and Division project update linked products. */
|
||||
if(empty($project->multiple))
|
||||
{
|
||||
$executionID = $this->execution->getNoMultipleID($projectID);
|
||||
if($executionID) $this->execution->updateProducts($executionID);
|
||||
}
|
||||
|
||||
if(empty($project->division))
|
||||
{
|
||||
foreach($executionIDs as $executionID)
|
||||
@@ -696,48 +695,47 @@ class projectZen extends project
|
||||
}
|
||||
}
|
||||
|
||||
//处理非瀑布及产品型项目
|
||||
$this->dealExecutionProduct($project, $oldProducts, $newProductIDs, $executionIDs);
|
||||
/* Record multiple and waterfall project unlinked products. */
|
||||
if($project->multiple and $project->model != 'waterfall' and $project->model != 'waterfallplus')
|
||||
{
|
||||
$this->dealUnlinkedProduct($project, $oldProducts, $newProductIDs, $executionIDs);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理项目执行下关联产品
|
||||
* deal execution product
|
||||
* 记录多迭代及瀑布类项目移除的产品
|
||||
* Record multiple and waterfall project unlinked products
|
||||
*
|
||||
* @param object $project
|
||||
* @param object $oldProducts
|
||||
* @param array $oldProducts
|
||||
* @param array $newProductIDs
|
||||
* @param int|array $executionIDs
|
||||
*
|
||||
* @access protected
|
||||
* @return void
|
||||
*/
|
||||
protected function dealExecutionProduct(object $project, object $oldProducts, array $newProductIDs, array $executionIDs): void
|
||||
protected function dealUnlinkedProduct(object $project, array $oldProducts, array $newProductIDs, array $executionIDs): void
|
||||
{
|
||||
//处理非瀑布及产品型项目
|
||||
if($project->multiple and $project->model != 'waterfall' and $project->model != 'waterfallplus')
|
||||
$oldExecutionProducts = $this->projectTao->getExecutionProductGroup($executionIDs);
|
||||
$unlinkedProducts = array_diff(array_keys($oldProducts), $newProductIDs);
|
||||
if(!empty($unlinkedProducts))
|
||||
{
|
||||
$oldExecutionProducts = $this->projectTao->replaceOldProduct($executionIDs);
|
||||
$unlinkedProducts = array_diff(array_keys($oldProducts), $newProductIDs);
|
||||
if(!empty($unlinkedProducts))
|
||||
$unlinkedProductPairs = array();
|
||||
foreach($unlinkedProducts as $unlinkedProduct) $unlinkedProductPairs[$unlinkedProduct] = $oldProducts[$unlinkedProduct]->name;
|
||||
|
||||
$unlinkExecutions = array();
|
||||
foreach($oldExecutionProducts as $executionID => $executionProducts)
|
||||
{
|
||||
$unlinkedProductPairs = array();
|
||||
foreach($unlinkedProducts as $unlinkedProduct) $unlinkedProductPairs[$unlinkedProduct] = $oldProducts[$unlinkedProduct]->name;
|
||||
|
||||
$unlinkExecutions = array();
|
||||
foreach($oldExecutionProducts as $executionID => $executionProducts)
|
||||
{
|
||||
$unlinkExecutionProducts = array_intersect_key($unlinkedProductPairs, $executionProducts);
|
||||
if($unlinkExecutionProducts) $unlinkExecutions[$executionID] = $unlinkExecutionProducts;
|
||||
}
|
||||
|
||||
foreach($unlinkExecutions as $executionID => $unlinkExecutionProducts) $this->loadModel('action')->create('execution', $executionID, 'unlinkproduct', '', implode(',', $unlinkExecutionProducts));
|
||||
$unlinkExecutionProducts = array_intersect_key($unlinkedProductPairs, $executionProducts);
|
||||
if($unlinkExecutionProducts) $unlinkExecutions[$executionID] = $unlinkExecutionProducts;
|
||||
}
|
||||
|
||||
foreach($unlinkExecutions as $executionID => $unlinkExecutionProducts) $this->loadModel('action')->create('execution', $executionID, 'unlinkproduct', '', implode(',', $unlinkExecutionProducts));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理项目关联需求的产品
|
||||
* 项目关联用户故事则无法移除产品
|
||||
* dealLinkProduct
|
||||
*
|
||||
* @param int $projectID
|
||||
@@ -759,7 +757,6 @@ class projectZen extends project
|
||||
$linkedProducts = $this->product->getProducts($projectID, 'all', '', true, $linkedProductIdList);
|
||||
$projectStories = $this->project->getStoriesByProject($projectID);
|
||||
$projectBranches = $this->project->getBranchGroupByProject($projectID, array_keys($linkedProducts));
|
||||
$branchGroups = $this->loadModel('branch')->getByProducts(array_keys($allProducts), 'ignoreNormal|noclosed', $linkedBranchIdList);
|
||||
|
||||
/* If the story of the product which linked the project,don't allow to remove the product. */
|
||||
$unmodifiableProducts = array();
|
||||
@@ -782,86 +779,87 @@ class projectZen extends project
|
||||
}
|
||||
}
|
||||
|
||||
$this->dealOtherLinkProduct($project, $branchGroups, $linkedBranches);
|
||||
/* Initializes the product from other linked products. */
|
||||
if($this->config->systemMode == 'ALM') $this->InitOtherLinkProduct($project, $allProducts, $linkedBranchIdList, $linkedBranches, $linkedProducts);
|
||||
|
||||
$this->view->allBranches = $this->loadModel('branch')->getByProducts(array_keys($allProducts), 'ignoreNormal');
|
||||
$this->view->allProducts = $allProducts;
|
||||
$this->view->unmodifiableProducts = $unmodifiableProducts;
|
||||
$this->view->unmodifiableBranches = $unmodifiableBranches;
|
||||
$this->view->unmodifiableMainBranches = $unmodifiableMainBranches;
|
||||
$this->view->linkedBranches = $linkedBranches;
|
||||
$this->view->branchGroups = $branchGroups;
|
||||
}
|
||||
|
||||
/**
|
||||
* dealOtherLinkProduct
|
||||
* 初始化项目集下其他关联产品中当前产品
|
||||
* Initializes the current product under the projectprogram.
|
||||
*
|
||||
* @param object $project
|
||||
* @param object $branchGroups
|
||||
* @param array $allProducts
|
||||
* @param array $linkedBranchIdList
|
||||
* @param array $linkedBranches
|
||||
* @param array $linkedProducts
|
||||
*
|
||||
* @access protected
|
||||
* @return void
|
||||
*/
|
||||
protected function dealOtherLinkProduct(object $project, object $branchGroups, array $linkedBranches): void
|
||||
protected function InitOtherLinkProduct(object $project, array $allProducts, array $linkedBranchIdList, array $linkedBranches, array $linkedProducts): void
|
||||
{
|
||||
$linkedProducts = $this->product->getProducts($projectID, 'all', '', true, $linkedProductIdList);
|
||||
$branchGroups = $this->loadModel('branch')->getByProducts(array_keys($allProducts), 'ignoreNormal|noclosed', $linkedBranchIdList);
|
||||
$topProgramID = $project->parent ? $this->program->getTopByPath($project->path) : 0;
|
||||
$productsGroupByProgram = $this->loadModel('product')->getProductsGroupByProgram();
|
||||
|
||||
if($this->config->systemMode == 'ALM')
|
||||
$currentProducts = array();
|
||||
foreach($productsGroupByProgram as $programID => $programProducts)
|
||||
{
|
||||
$topProgramID = $project->parent ? $this->program->getTopByPath($project->path) : 0;
|
||||
$productsGroupByProgram = $this->product->getProductsGroupByProgram();
|
||||
|
||||
$currentProducts = array();
|
||||
$otherProducts = array();
|
||||
foreach($productsGroupByProgram as $programID => $programProducts)
|
||||
if($programID != $topProgramID)
|
||||
{
|
||||
if($programID != $topProgramID)
|
||||
{
|
||||
foreach($programProducts as $productID => $productName)
|
||||
{
|
||||
if(!empty($branchGroups[$productID]))
|
||||
{
|
||||
foreach($branchGroups[$productID] as $branchID => $branchName)
|
||||
{
|
||||
if(isset($linkedProducts[$productID]) and isset($linkedBranches[$productID][$branchID])) continue;
|
||||
$otherProducts = $this->InitBranchProduct($programProducts, $branchGroups, $linkedBranches, $linkedProducts);
|
||||
}
|
||||
else
|
||||
{
|
||||
$currentProducts += $programProducts;
|
||||
}
|
||||
}
|
||||
$this->view->currentProducts = $currentProducts;
|
||||
$this->view->otherProducts = $otherProducts;
|
||||
|
||||
$otherProducts["{$productID}_{$branchID}"] = $productName . '_' . $branchName;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(isset($linkedProducts[$productID])) continue;
|
||||
$otherProducts[$productID] = $productName;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
$this->view->branchGroups = $branchGroups;
|
||||
$this->view->linkedBranches = $linkedBranches;
|
||||
$this->view->linkedProducts = $linkedProducts;
|
||||
$this->view->allProducts = $allProducts;
|
||||
$this->view->allBranches = $this->loadModel('branch')->getByProducts(array_keys($allProducts), 'ignoreNormal');
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化项目集下其他关联产品中多分支产品
|
||||
* Initializes the multi-branch product under the projectprogram.
|
||||
*
|
||||
* @param object $programProducts
|
||||
* @param array $branchGroups
|
||||
* @param array $linkedBranches
|
||||
* @param array $linkedProducts
|
||||
*
|
||||
* @access protected
|
||||
* @return array
|
||||
*/
|
||||
protected function InitBranchProduct(object $programProducts, array $branchGroups, array $linkedBranches, array $linkedProducts): array
|
||||
{
|
||||
$otherProducts = array();
|
||||
foreach($programProducts as $productID => $productName)
|
||||
{
|
||||
if(!empty($branchGroups[$productID]))
|
||||
{
|
||||
foreach($branchGroups[$productID] as $branchID => $branchName)
|
||||
{
|
||||
$currentProducts += $programProducts;
|
||||
if(isset($linkedProducts[$productID]) and isset($linkedBranches[$productID][$branchID])) continue;
|
||||
$otherProducts["{$productID}_{$branchID}"] = $productName . '_' . $branchName;
|
||||
}
|
||||
}
|
||||
$this->view->currentProducts = $currentProducts;
|
||||
$this->view->otherProducts = $otherProducts;
|
||||
else
|
||||
{
|
||||
if(isset($linkedProducts[$productID])) continue;
|
||||
$otherProducts[$productID] = $productName;
|
||||
}
|
||||
}
|
||||
$this->view->linkedProducts = $linkedProducts;
|
||||
}
|
||||
|
||||
/**
|
||||
* buildMangedProductForm
|
||||
*
|
||||
* @param int $projectID
|
||||
* @param object $project
|
||||
*
|
||||
* @access protected
|
||||
* @return void
|
||||
*/
|
||||
protected function buildMangedProductForm(int $projectID, $project, $executions): void
|
||||
{
|
||||
$this->view->title = $this->lang->project->manageProducts . $this->lang->colon . $project->name;
|
||||
$this->view->project = $project;
|
||||
$this->view->executions = $executions;
|
||||
$this->view->branches = $this->project->getBranchesByProject($projectID);
|
||||
$this->display();
|
||||
return $otherProducts;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user