Merge branch feature/workflowgroup of zentao/zentaopms (#11852)

This commit is contained in:
刘刚
2025-10-15 08:55:56 +08:00
committed by Gitfox
18 changed files with 598 additions and 98 deletions
+17
View File
@@ -100,6 +100,23 @@ ALTER TABLE `zt_approvalnode` CHANGE `result` `result` varchar(20) NOT NULL DEFA
DELETE FROM `zt_workflowgroup` WHERE `projectModel` = 'kanban';
UPDATE `zt_project` SET `workflowGroup` = '0' WHERE `model` = 'kanban';
CREATE TABLE IF NOT EXISTS `zt_decision` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`workflowGroup` mediumint(8) unsigned NOT NULL DEFAULT '0',
`stage` mediumint(8) unsigned NOT NULL DEFAULT '0',
`order` mediumint(8) unsigned NOT NULL DEFAULT '0',
`title` varchar(255) NOT NULL DEFAULT '',
`type` varchar(30) NOT NULL DEFAULT '',
`category` varchar(30) NOT NULL DEFAULT '',
`builtin` enum('0','1') NOT NULL DEFAULT '0',
`createdBy` char(30) NOT NULL DEFAULT '',
`createdDate` datetime NULL,
`editedBy` char(30) NOT NULL DEFAULT '',
`editedDate` datetime NULL,
`deleted` enum('0','1') NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
ALTER TABLE `zt_stage` ADD `workflowGroup` mediumint(8) unsigned NOT NULL DEFAULT '0' AFTER `id`;
CREATE TABLE IF NOT EXISTS `zt_decision` (
+1
View File
@@ -628,6 +628,7 @@ CREATE TABLE IF NOT EXISTS `zt_decision` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`workflowGroup` mediumint(8) unsigned NOT NULL DEFAULT '0',
`stage` mediumint(8) unsigned NOT NULL DEFAULT '0',
`order` mediumint(8) unsigned NOT NULL DEFAULT '0',
`title` varchar(255) NOT NULL DEFAULT '',
`type` varchar(30) NOT NULL DEFAULT '',
`category` varchar(30) NOT NULL DEFAULT '',
+1
View File
@@ -1255,6 +1255,7 @@ class projectModel extends model
if($project->acl != 'open') $this->loadModel('user')->updateUserView(array($projectID), 'project');
if(empty($project->multiple) and $project->model != 'waterfall' and $project->model != 'waterfallplus') $this->loadModel('execution')->createDefaultSprint($projectID);
if(!empty($project->workflowGroup) && $project->model == 'ipd') $this->loadModel('stage')->addBuiltinPoint($project->workflowGroup);
return $projectID;
}
+4
View File
@@ -26,3 +26,7 @@ if(isset($config->setPercent) && $config->setPercent == 1) $config->stage->form-
$config->stage->form->settype['lang'] = array('type' => 'string', 'required' => false, 'default' => '');
$config->stage->form->settype['keys'] = array('type' => 'array', 'required' => false, 'default' => array());
$config->stage->form->settype['values'] = array('type' => 'array', 'required' => false, 'default' => array());
$config->stage->form->setpoint['id'] = array('type' => 'int', 'required' => false, 'default' => 0);
$config->stage->form->setpoint['title'] = array('type' => 'string', 'required' => true, 'default' => '', 'base' => true, 'filter' => 'trim');
$config->stage->form->setpoint['flow'] = array('type' => 'int', 'required' => true, 'default' => 1);
+13
View File
@@ -235,6 +235,19 @@ class stage extends control
*/
public function setPoint(string $type, int $stageID)
{
$this->app->loadLang('review');
if(!empty($_POST))
{
$points = form::batchData()->get();
$this->stage->setPoint($type, $stageID, $points);
if(dao::isError()) return $this->sendError(dao::getError());
return $this->sendSuccess(array('closeModal' => true, 'load' => true));
}
$this->view->type = $type;
$this->view->approvals = $this->loadModel('approvalflow')->getPairs('project');
$this->view->stagePoints = $this->stage->getStagePoints($type, $stageID);
$this->display();
}
}
+10
View File
@@ -0,0 +1,10 @@
window.refreshApproval = function()
{
$.getJSON($.createLink('review', 'ajaxGetApproval'), function(data)
{
$('[name^=flow]').each(function()
{
$(this).zui('picker').render({items: data});
});
});
}
+10 -7
View File
@@ -21,13 +21,16 @@ $lang->stage->setTRpoint = 'Set TR Point';
$lang->stage->setDCPpoint = 'Set DCP Point';
/* Fields. */
$lang->stage->id = 'ID';
$lang->stage->name = 'Name';
$lang->stage->type = 'Type';
$lang->stage->percent = 'Workload %';
$lang->stage->setType = 'Set Type';
$lang->stage->TRpoint = 'TR Point';
$lang->stage->DCPpoint = 'DCP Point';
$lang->stage->id = 'ID';
$lang->stage->name = 'Name';
$lang->stage->type = 'Type';
$lang->stage->percent = 'Workload %';
$lang->stage->setType = 'Set Type';
$lang->stage->TRpoint = 'TR Point';
$lang->stage->DCPpoint = 'DCP Point';
$lang->stage->TRname = 'TR Point Name';
$lang->stage->DCPname = 'DCP Point Name';
$lang->stage->pointFlow = 'Approval Flow';
$lang->stage->typeList['mix'] = 'Mix';
$lang->stage->typeList['request'] = 'Story';
+10 -7
View File
@@ -21,13 +21,16 @@ $lang->stage->setTRpoint = 'Set TR Point';
$lang->stage->setDCPpoint = 'Set DCP Point';
/* Fields. */
$lang->stage->id = 'ID';
$lang->stage->name = 'Name';
$lang->stage->type = 'Type';
$lang->stage->percent = 'Workload %';
$lang->stage->setType = 'Set Type';
$lang->stage->TRpoint = 'TR Point';
$lang->stage->DCPpoint = 'DCP Point';
$lang->stage->id = 'ID';
$lang->stage->name = 'Name';
$lang->stage->type = 'Type';
$lang->stage->percent = 'Workload %';
$lang->stage->setType = 'Set Type';
$lang->stage->TRpoint = 'TR Point';
$lang->stage->DCPpoint = 'DCP Point';
$lang->stage->TRname = 'TR Point Name';
$lang->stage->DCPname = 'DCP Point Name';
$lang->stage->pointFlow = 'Approval Flow';
$lang->stage->typeList['mix'] = 'Mix';
$lang->stage->typeList['request'] = 'Story';
+10 -7
View File
@@ -21,13 +21,16 @@ $lang->stage->setTRpoint = 'Set TR Point';
$lang->stage->setDCPpoint = 'Set DCP Point';
/* Fields. */
$lang->stage->id = 'ID';
$lang->stage->name = 'Name';
$lang->stage->type = 'Type';
$lang->stage->percent = 'Workload %';
$lang->stage->setType = 'Set Type';
$lang->stage->TRpoint = 'TR Point';
$lang->stage->DCPpoint = 'DCP Point';
$lang->stage->id = 'ID';
$lang->stage->name = 'Name';
$lang->stage->type = 'Type';
$lang->stage->percent = 'Workload %';
$lang->stage->setType = 'Set Type';
$lang->stage->TRpoint = 'TR Point';
$lang->stage->DCPpoint = 'DCP Point';
$lang->stage->TRname = 'TR Point Name';
$lang->stage->DCPname = 'DCP Point Name';
$lang->stage->pointFlow = 'Approval Flow';
$lang->stage->typeList['mix'] = 'Mix';
$lang->stage->typeList['request'] = 'Story';
+10 -7
View File
@@ -21,13 +21,16 @@ $lang->stage->setTRpoint = 'TR评审点配置';
$lang->stage->setDCPpoint = 'DCP评审点配置';
/* Fields. */
$lang->stage->id = 'ID';
$lang->stage->name = '阶段名称';
$lang->stage->type = '阶段类型';
$lang->stage->percent = '工作量占比';
$lang->stage->setType = '阶段类型';
$lang->stage->TRpoint = 'TR评审点';
$lang->stage->DCPpoint = 'DCP评审点';
$lang->stage->id = 'ID';
$lang->stage->name = '阶段名称';
$lang->stage->type = '阶段类型';
$lang->stage->percent = '工作量占比';
$lang->stage->setType = '阶段类型';
$lang->stage->TRpoint = 'TR评审点';
$lang->stage->DCPpoint = 'DCP评审点';
$lang->stage->TRname = 'TR评审点名称';
$lang->stage->DCPname = 'DCP评审点名称';
$lang->stage->pointFlow = '审批流';
$lang->stage->typeList['mix'] = '综合';
$lang->stage->typeList['request'] = '需求';
+193 -1
View File
@@ -164,11 +164,29 @@ class stageModel extends model
->fetchAll('id');
}
return $this->dao->select('*')->from(TABLE_STAGE)
$stages = $this->dao->select('*')->from(TABLE_STAGE)
->where('deleted')->eq(0)
->andWhere('workflowGroup')->eq($groupID)
->orderBy($orderBy)
->fetchAll('id');
$stagePoints = $this->dao->select('*')->from(TABLE_DECISION)->where('stage')->in(array_keys($stages))->orderBy('order_asc')->fetchGroup('stage');
$pointList = array();
foreach($stagePoints as $stageID => $points)
{
if(!isset($pointList[$stageID])) $pointList[$stageID] = array();
foreach($points as $point)
{
if(!isset($pointList[$stageID][$point->type])) $pointList[$stageID][$point->type] = array();
$pointList[$stageID][$point->type][$point->id] = $point->title;
}
}
foreach($stages as $stage)
{
$stage->TRpoint = isset($pointList[$stage->id]['TR']) ? implode(', ', $pointList[$stage->id]['TR']) : '';
$stage->DCPpoint = isset($pointList[$stage->id]['DCP']) ? implode(', ', $pointList[$stage->id]['DCP']) : '';
}
return $stages;
}
/**
@@ -195,4 +213,178 @@ class stageModel extends model
{
return (float)$this->dao->select('sum(percent) as total')->from(TABLE_STAGE)->where('deleted')->eq('0')->andWhere('workflowGroup')->eq($groupID)->fetch('total');
}
/**
* 添加内置评审点。
* Add the builtin point.
*
* @param int $groupID
* @return void
*/
public function addBuiltinPoint(int $groupID)
{
$workflowGroup = $this->dao->select('*')->from(TABLE_WORKFLOWGROUP)->where('id')->eq($groupID)->fetch();
if($workflowGroup->projectModel != 'ipd') return;
$builtinPoints = $this->dao->select('*')->from(TABLE_DECISION)->where('workflowGroup')->eq($groupID)->andWhere('builtin')->eq('1')->fetchAll();
if(!empty($builtinPoints)) return;
$this->app->loadConfig('review');
$this->app->loadConfig('project');
$stageList = $this->dao->select('*')->from(TABLE_STAGE)->where('workflowGroup')->eq($groupID)->fetchAll('id');
if(empty($stageList))
{
$stageTypeList = array();
if($workflowGroup->projectType == 'ipd') $stageTypeList = $this->config->project->categoryStages['IPD'];
if($workflowGroup->projectType == 'tpd') $stageTypeList = $this->config->project->categoryStages['TPD'];
if($workflowGroup->projectType == 'cbb') $stageTypeList = $this->config->project->categoryStages['CBB'];
if(in_array($workflowGroup->projectType, array('cpdproduct', 'cpdproject'))) $stageTypeList= $this->config->project->categoryStages['CPD'];
foreach($stageTypeList as $stageType)
{
$builtinStage = new stdClass();
$builtinStage->workflowGroup = $groupID;
$builtinStage->createdBy = 'system';
$builtinStage->createdDate = helper::now();
$builtinStage->name = zget($this->lang->stage->ipdTypeList, $stageType, '');
$builtinStage->type = $stageType;
$this->dao->insert(TABLE_STAGE)->data($builtinStage)->exec();
$stageID = $this->dao->lastInsertID();
$stageList[$stageID] = $builtinStage;
}
}
$decision = new stdClass();
$decision->builtin = '1';
$decision->createdBy = 'system';
$decision->createdDate = helper::now();
$decision->workflowGroup = $groupID;
$decisionFlow = new stdClass();
$decisionFlow->flow = 1;
$decisionFlow->objectType = 'point';
$decisionFlow->relatedBy = 'system';
$decisionFlow->relatedDate = helper::now();
foreach($stageList as $id => $stage)
{
foreach($this->config->review->ipdReviewPoint->{$stage->type} as $index => $point)
{
$decision->stage = $id;
$decision->order = $index + 1;
$decision->title = $point;
$decision->type = strpos($point, 'TR') !== false ? 'TR' : 'DCP';
$decision->category = $point;
$this->dao->insert(TABLE_DECISION)->data($decision)->exec();
$decisionID = $this->dao->lastInsertID();
$decisionFlow->root = $stage->workflowGroup;
$decisionFlow->objectID = $decisionID;
$this->dao->insert(TABLE_APPROVALFLOWOBJECT)->data($decisionFlow)->exec();
}
}
}
/**
* 获取阶段的评审点。
* Get points of stage.
*
* @param string $type TR|DCP
* @param int $stageID
* @access public
* @return bool
*/
public function getStagePoints(string $type, int $stageID)
{
$stage = $this->dao->select('*')->from(TABLE_STAGE)->where('id')->eq($stageID)->fetch();
return $this->dao->select('t1.*,t2.flow')->from(TABLE_DECISION)->alias('t1')
->leftJoin(TABLE_APPROVALFLOWOBJECT)->alias('t2')->on("t1.id = t2.objectID AND t2.objectType = 'point'")
->where('t1.stage')->eq($stageID)
->andWhere('t1.type')->eq($type)
->andWhere('t2.root')->eq($stage->workflowGroup)
->orderBy('order_asc')
->fetchAll('id');
}
/**
* 设置阶段的评审点。
* Set point of stage.
*
* @param string $type TR|DCP
* @param int $stageID
* @param array $stageID
* @access public
* @return bool
*/
public function setPoint(string $type, int $stageID, array $points): bool
{
$stage = $this->getByID($stageID);
$oldStagePoints = $this->getStagePoints($type, $stageID);
foreach($points as $index => $point)
{
if(!empty($point->id) && isset($oldStagePoints[$point->id]))
{
$oldPoint = $oldStagePoints[$point->id];
if($oldPoint->title != $point->title || $oldPoint->order != $index)
{
$this->dao->update(TABLE_DECISION)
->set('title')->eq($point->title)
->set('order')->eq($index)
->set('editedBy')->eq($this->app->user->account)
->set('editedDate')->eq(helper::now())
->where('id')->eq($point->id)
->exec();
if(dao::isError()) return false;
}
if($oldPoint->flow != $point->flow)
{
$this->dao->update(TABLE_APPROVALFLOWOBJECT)
->set('flow')->eq($point->flow)
->where('objectID')->eq($point->id)
->andWhere('objectType')->eq('point')
->andWhere('root')->eq($stage->workflowGroup)
->exec();
if(dao::isError()) return false;
}
unset($oldStagePoints[$point->id]);
}
else
{
$newPoint = new stdClass();
$newPoint->workflowGroup = $stage->workflowGroup;
$newPoint->stage = $stageID;
$newPoint->title = $point->title;
$newPoint->type = $type;
$newPoint->builtin = '0';
$newPoint->createdBy = $this->app->user->account;
$newPoint->createdDate = helper::now();
$newPoint->order = $index;
$this->dao->insert(TABLE_DECISION)->data($newPoint)->exec();
$newPointID = $this->dao->lastInsertID();
if(dao::isError()) return false;
$approvalFlowObject = new stdClass();
$approvalFlowObject->root = $stage->workflowGroup;
$approvalFlowObject->flow = $point->flow;
$approvalFlowObject->objectType = 'point';
$approvalFlowObject->objectID = $newPointID;
$approvalFlowObject->relatedBy = $this->app->user->account;
$approvalFlowObject->relatedDate = helper::now();
$this->dao->insert(TABLE_APPROVALFLOWOBJECT)->data($approvalFlowObject)->exec();
if(dao::isError()) return false;
}
}
if(!empty($oldStagePoints))
{
$this->dao->delete()->from(TABLE_DECISION)->where('id')->in(array_keys($oldStagePoints))->exec();
$this->dao->delete()->from(TABLE_APPROVALFLOWOBJECT)
->where('objectID')->in(array_keys($oldStagePoints))
->andWhere('objectType')->eq('point')
->andWhere('root')->eq($stage->workflowGroup)
->exec();
}
return true;
}
}
+85
View File
@@ -0,0 +1,85 @@
#!/usr/bin/env php
<?php
/**
title=测试 stageModel->addBuiltinPoint();
cid=1
- 获取TR1评审点
- 第1条的title属性 @TR1
- 第1条的type属性 @TR
- 第1条的category属性 @TR1
- 获取CDCP评审点
- 第2条的title属性 @CDCP
- 第2条的type属性 @DCP
- 第2条的category属性 @CDCP
- 获取TR2评审点
- 第3条的title属性 @TR2
- 第3条的type属性 @TR
- 第3条的category属性 @TR2
- 获取TR3评审点
- 第4条的title属性 @TR3
- 第4条的type属性 @TR
- 第4条的category属性 @TR3
- 获取PDCP评审点
- 第5条的title属性 @PDCP
- 第5条的type属性 @DCP
- 第5条的category属性 @PDCP
- 获取TR4评审点
- 第6条的title属性 @TR4
- 第6条的type属性 @TR
- 第6条的category属性 @TR4
- 获取TR4A评审点
- 第7条的title属性 @TR4A
- 第7条的type属性 @TR
- 第7条的category属性 @TR4A
- 获取TR5评审点
- 第8条的title属性 @TR5
- 第8条的type属性 @TR
- 第8条的category属性 @TR5
- 获取TR6评审点
- 第9条的title属性 @TR6
- 第9条的type属性 @TR
- 第9条的category属性 @TR6
- 获取ADCP评审点
- 第10条的title属性 @ADCP
- 第10条的type属性 @DCP
- 第10条的category属性 @ADCP
- 获取LDCP评审点
- 第11条的title属性 @LDCP
- 第11条的type属性 @DCP
- 第11条的category属性 @LDCP
*/
include dirname(__FILE__, 5) . '/test/lib/init.php';
zenData('user')->gen(5);
zenData('decision')->gen(0);
$workflowGroup = zenData('workflowgroup');
$workflowGroup->id->range('1-5');
$workflowGroup->type->range('project');
$workflowGroup->projectModel->range('ipd');
$workflowGroup->projectType->range('ipd,tpd,cbb,cpdproduct,cpdproject');
$workflowGroup->name->range('IPD集成产品研发,IPD预研产品研发,IPD平台产品研发,IPD定制产品研发,IPD定制项目研发');
$workflowGroup->code->range('ipdproduct,tpdproduct,cbbproduct,cpdproduct,cpdproject');
$workflowGroup->status->range('normal');
$workflowGroup->main->range('1');
$workflowGroup->gen(5);
global $tester;
$stageTester = $tester->loadModel('stage');
$stageTester->addBuiltinPoint(1);
$IPDpoint = $stageTester->dao->select('*')->from(TABLE_DECISION)->where('workflowGroup')->eq(1)->fetchAll('id');
r($IPDpoint) && p('1:title,type,category') && e('TR1,TR,TR1'); //获取TR1评审点
r($IPDpoint) && p('2:title,type,category') && e('CDCP,DCP,CDCP'); //获取CDCP评审点
r($IPDpoint) && p('3:title,type,category') && e('TR2,TR,TR2'); //获取TR2评审点
r($IPDpoint) && p('4:title,type,category') && e('TR3,TR,TR3'); //获取TR3评审点
r($IPDpoint) && p('5:title,type,category') && e('PDCP,DCP,PDCP'); //获取PDCP评审点
r($IPDpoint) && p('6:title,type,category') && e('TR4,TR,TR4'); //获取TR4评审点
r($IPDpoint) && p('7:title,type,category') && e('TR4A,TR,TR4A'); //获取TR4A评审点
r($IPDpoint) && p('8:title,type,category') && e('TR5,TR,TR5'); //获取TR5评审点
r($IPDpoint) && p('9:title,type,category') && e('TR6,TR,TR6'); //获取TR6评审点
r($IPDpoint) && p('10:title,type,category') && e('ADCP,DCP,ADCP'); //获取ADCP评审点
r($IPDpoint) && p('11:title,type,category') && e('LDCP,DCP,LDCP'); //获取LDCP评审点
+54
View File
@@ -0,0 +1,54 @@
#!/usr/bin/env php
<?php
/**
title=测试 stageModel->getStagePoints();
cid=1
- 获取阶段1的TR评审点
- 第1条的stage属性 @1
- 第1条的title属性 @TR1
- 获取阶段2的TR评审点
- 第2条的stage属性 @2
- 第2条的title属性 @TR2
- 获取阶段2的TR评审点
- 第3条的stage属性 @3
- 第3条的title属性 @TR3
- 获取阶段4的DCP评审点
- 第4条的stage属性 @4
- 第4条的title属性 @CDCP
- 获取阶段5的DCP评审点
- 第5条的stage属性 @5
- 第5条的title属性 @PDCP
*/
include dirname(__FILE__, 5) . '/test/lib/init.php';
include dirname(__FILE__, 2) . '/lib/stage.unittest.class.php';
zenData('stage')->loadYaml('stage')->gen(5);
zenData('user')->gen(5);
$decision = zenData('decision');
$decision->id->range('1-5');
$decision->workflowGroup->range('1-5');
$decision->stage->range('1-5');
$decision->title->range('TR1,TR2,TR3,CDCP,PDCP');
$decision->type->range('TR{3},DCP{2}');
$decision->gen(5);
$approvalFlowObject = zenData('approvalflowobject');
$approvalFlowObject->id->range('1-5');
$approvalFlowObject->root->range('4');
$approvalFlowObject->objectID->range('1-5');
$approvalFlowObject->objectType->range('point');
$approvalFlowObject->extra->range('review');
$approvalFlowObject->gen(5);
global $tester;
$stageTester = $tester->loadModel('stage');
r($stageTester->getStagePoints('TR', 1)) && p('1:stage,title') && e('1,TR1'); //获取阶段1的TR评审点
r($stageTester->getStagePoints('TR', 2)) && p('2:stage,title') && e('2,TR2'); //获取阶段2的TR评审点
r($stageTester->getStagePoints('TR', 3)) && p('3:stage,title') && e('3,TR3'); //获取阶段2的TR评审点
r($stageTester->getStagePoints('DCP', 4)) && p('4:stage,title') && e('4,CDCP'); //获取阶段4的DCP评审点
r($stageTester->getStagePoints('DCP', 5)) && p('5:stage,title') && e('5,PDCP'); //获取阶段5的DCP评审点
+7 -11
View File
@@ -12,8 +12,7 @@ cid=1
- 测试获取有stage数据的waterfallplus类型总百分比 @60
- 测试获取不存在的项目类型总百分比 @0
- 测试获取scrum类型的总百分比 @0
- 测试获取空字符串类型的总百分比 @0
- 测试已删除stage的百分比不被计算 @60
- 测试已删除stage的百分比不被计算 @0
*/
@@ -24,22 +23,19 @@ $stageTester = new stageTest();
// 步骤1:测试空数据库情况
zenData('stage')->gen(0);
r($stageTester->getTotalPercentTest('waterfall')) && p() && e('0'); // 测试空数据库中waterfall类型的总百分比
r($stageTester->getTotalPercentTest(4)) && p() && e('0'); // 测试空数据库中waterfall类型的总百分比
// 步骤2和3:准备测试数据,测试有数据情况
zenData('user')->gen(5);
zenData('stage')->loadYaml('stage')->gen(12);
r($stageTester->getTotalPercentTest('waterfall')) && p() && e('60'); // 测试获取有stage数据的waterfall类型总百分比
r($stageTester->getTotalPercentTest('waterfallplus')) && p() && e('60'); // 测试获取有stage数据的waterfallplus类型总百分比
r($stageTester->getTotalPercentTest(4)) && p() && e('60'); // 测试获取有stage数据的waterfall类型总百分比
r($stageTester->getTotalPercentTest(8)) && p() && e('60'); // 测试获取有stage数据的waterfallplus类型总百分比
// 步骤4:测试不存在的项目类型
r($stageTester->getTotalPercentTest('nonexistent')) && p() && e('0'); // 测试获取不存在的项目类型总百分比
r($stageTester->getTotalPercentTest(0)) && p() && e('0'); // 测试获取不存在的项目类型总百分比
// 步骤5:测试scrum类型(应该没有数据)
r($stageTester->getTotalPercentTest('scrum')) && p() && e('0'); // 测试获取scrum类型的总百分比
// 步骤6:测试空字符串类型
r($stageTester->getTotalPercentTest('')) && p() && e('0'); // 测试获取空字符串类型的总百分比
r($stageTester->getTotalPercentTest(2)) && p() && e('0'); // 测试获取scrum类型的总百分比
// 步骤7:测试已删除的stage不被计算(需要准备包含已删除数据的测试数据)
$table = zenData('stage');
@@ -50,4 +46,4 @@ $table->type->range('request,design');
$table->percent->range('15,25');
$table->deleted->range('1{2}');
$table->gen(2);
r($stageTester->getTotalPercentTest('waterfall')) && p() && e('60'); // 测试已删除stage的百分比不被计算
r($stageTester->getTotalPercentTest(2)) && p() && e('0'); // 测试已删除stage的百分比不被计算
+77
View File
@@ -0,0 +1,77 @@
#!/usr/bin/env php
<?php
/**
title=测试 stageModel->setPoint();
cid=1
- 测试修改评审点标题 @TR1 change
- 测试修改评审点的审批流 @2
- 测试修改评审点的顺序 @2
- 测试删除评审点 @0
- 测试添加评审点第6条的title属性 @test add point
*/
include dirname(__FILE__, 5) . '/test/lib/init.php';
include dirname(__FILE__, 2) . '/lib/stage.unittest.class.php';
zenData('stage')->loadYaml('stage')->gen(5);
zenData('user')->gen(5);
$decision = zenData('decision');
$decision->id->range('1-5');
$decision->workflowGroup->range('1-5');
$decision->stage->range('1-5');
$decision->order->range('1');
$decision->title->range('TR1,TR2,TR3,CDCP,PDCP');
$decision->type->range('TR{3},DCP{2}');
$decision->gen(5);
$approvalFlowObject = zenData('approvalflowobject');
$approvalFlowObject->id->range('1-5');
$approvalFlowObject->root->range('4');
$approvalFlowObject->flow->range('1');
$approvalFlowObject->objectID->range('1-5');
$approvalFlowObject->objectType->range('point');
$approvalFlowObject->extra->range('review');
$approvalFlowObject->gen(5);
global $tester;
$stageTester = $tester->loadModel('stage');
$changeTitle = new stdClass();
$changeTitle->id = 1;
$changeTitle->title = 'TR1 change';
$changeTitle->flow = '1';
$stageTester->setPoint('TR', 1, array(1 => $changeTitle));
$result = $stageTester->dao->select('title')->from(TABLE_DECISION)->where('id')->eq(1)->fetch('title');
r($result) && p() && e('TR1 change'); //测试修改评审点标题
$changeFlow = new stdClass();
$changeFlow->id = 2;
$changeFlow->title = 'TR2';
$changeFlow->flow = 2;
$stageTester->setPoint('TR', 2, array(1 => $changeFlow));
$result = $stageTester->dao->select('flow')->from(TABLE_APPROVALFLOWOBJECT)->where('objectType')->eq('point')->andWhere('objectID')->eq(2)->fetch('flow');
r($result) && p() && e('2'); //测试修改评审点的审批流
$changeOrder = new stdClass();
$changeOrder->id = 3;
$changeOrder->title = 'TR3';
$changeOrder->flow = 1;
$stageTester->setPoint('TR', 3, array(2 => $changeOrder));
$result = $stageTester->dao->select('`order`')->from(TABLE_DECISION)->where('id')->eq(3)->fetch('order');
r($result) && p() && e('2'); //测试修改评审点的顺序
$stageTester->setPoint('DCP', 4, array());
$result = $stageTester->dao->select('*')->from(TABLE_DECISION)->where('stage')->eq(4)->fetchAll();
r(count($result)) && p() && e('0'); //测试删除评审点
$addPoint = new stdClass();
$addPoint->id = 0;
$addPoint->title = 'test add point';
$addPoint->flow = 1;
$stageTester->setPoint('DCP', 4, array(1 => $addPoint));
$result = $stageTester->dao->select('*')->from(TABLE_DECISION)->where('stage')->eq(4)->fetchAll('id');
r($result) && p('6:title') && e('test add point'); //测试添加评审点
+60
View File
@@ -0,0 +1,60 @@
<?php
declare(strict_types=1);
/**
* Set point view of stage module of ZenTaoPMS.
*
* @copyright Copyright 2009-2025 禅道软件(青岛)集团有限公司
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @author xieqiyu <xieqiyu@chandao.com>
* @package stage
* @link https://www.zentao.net
*/
namespace zin;
modalHeader
(
set::title($type == 'TR' ? $lang->stage->setTRpoint : $lang->stage->setDCPpoint),
set::titleClass('text-md font-semibold')
);
formBatchPanel
(
setID('setPointForm'),
set::minRows(1),
set::sortable(true),
set::data(array_values($stagePoints)),
set::idKey('index'),
formBatchItem
(
set::name('id'),
set::hidden(true)
),
formBatchItem
(
set::name('title'),
set::required(true),
set::label($type == 'TR' ? $lang->stage->TRname : $lang->stage->DCPname)
),
formBatchItem
(
set::name('flow'),
set::label($lang->stage->pointFlow),
set::required(true),
set::control('inputGroup'),
inputGroup
(
picker
(
set::name('flow'),
set::required(true),
set::items($approvals),
set::value(1)
),
hasPriv('approvalflow', 'create') ? div
(
a(set::className('btn secondary ml-1'), set::href(createLink('approvalflow', 'create', 'workflow=&callback=refreshApproval')), setData(array('toggle' => 'modal')), $lang->review->createApproval)
) : null
)
)
);
+1 -1
View File
@@ -112,7 +112,7 @@ $config->upgrade->execFlow['21_6_beta'] = array('functions' => 'processCharter
$config->upgrade->execFlow['21_6_1'] = array('xxsqls' => "$appRoot/db/upgradexuanxuan9.1.2.sql");
$config->upgrade->execFlow['21_7'] = array('functions' => 'fixWorkflowNameForExecution');
$config->upgrade->execFlow['21_7_1'] = array('functions' => 'convertCharset,processActionProduct');
$config->upgrade->execFlow['21_7_3'] = array('functions' => 'modifyProjectWorkflowGroup,upgradeProcessAndActivity,addWorkflowGroupOtherActivity,addDefaultDeliverableModule,upgradeDesignToDeliverable,buildinTestcaseStageDeliverable,upgradeDeliverable,buildinBaselineReview,upgradeReviewclCategory,upgradeBaselineObjects,upgradeReviewToDeliverable,upgradeBaseline,addDeliverablePrivs');
$config->upgrade->execFlow['21_7_3'] = array('functions' => 'modifyProjectWorkflowGroup,upgradeProcessAndActivity,addWorkflowGroupOtherActivity,addDefaultDeliverableModule,upgradeDesignToDeliverable,buildinTestcaseStageDeliverable,upgradeDeliverable,buildinBaselineReview,upgradeReviewclCategory,upgradeBaselineObjects,upgradeReviewToDeliverable,upgradeBaseline,addDeliverablePrivs,upgradeStageAndPoint');
$config->upgrade->execFlow['21_7_5'] = array('functions' => 'weekly-addBuiltinWeeklyTemplate,adjustPriv21_7_5');
if(!empty($config->isINT))
+35 -57
View File
@@ -12505,18 +12505,19 @@ class upgradeModel extends model
}
/**
* 升级阶段列表。
* Update stage list.
* 升级阶段列表及评审点。
* Update stage and point.
*
* @access public
* @return void
*/
public function upgradeStageList()
public function upgradeStageAndPoint()
{
$stageGroup = $this->dao->select('*')->from(TABLE_STAGE)->where('workflowGroup')->eq(0)->fetchGroup('projectType', 'id');
if(empty($stageGroup)) return true;
$this->app->loadConfig('project');
$this->app->loadConfig('review');
$typeCodeGroup = $this->dao->select('projectModel, code, id')->from(TABLE_WORKFLOWGROUP)->where('main')->eq('1')->andWhere('projectModel')->in('waterfall,waterfallplus,ipd')->fetchGroup('projectModel', 'code');
foreach($typeCodeGroup as $projectModel => $flowList)
{
@@ -12532,6 +12533,37 @@ class upgradeModel extends model
$stage->workflowGroup = $typeCodeGroup[$projectModel][$flowCode]->id;
if(empty($stage->editedDate)) $stage->editedDate = null;
$this->dao->insert(TABLE_STAGE)->data($stage)->exec();
$stageID = $this->dao->lastInsertID();
/* 添加IPD项目流程阶段的评审点。*/
if($projectModel == 'ipd')
{
$decision = new stdClass();
$decision->builtin = '1';
$decision->createdBy = 'system';
$decision->createdDate = helper::now();
$decisionFlow = new stdClass();
$decisionFlow->flow = 1;
$decisionFlow->objectType = 'point';
$decisionFlow->relatedBy = 'system';
$decisionFlow->relatedDate = helper::now();
foreach($this->config->review->ipdReviewPoint->{$stage->type} as $index => $point)
{
$decision->workflowGroup = $stage->workflowGroup;
$decision->stage = $stageID;
$decision->order = $index + 1;
$decision->title = $point;
$decision->type = strpos($point, 'TR') !== false ? 'TR' : 'DCP';
$decision->category = $point;
$this->dao->insert(TABLE_DECISION)->data($decision)->exec();
$decisionID = $this->dao->lastInsertID();
$decisionFlow->root = $stage->workflowGroup;
$decisionFlow->objectID = $decisionID;
$this->dao->insert(TABLE_APPROVALFLOWOBJECT)->data($decisionFlow)->exec();
}
}
}
}
}
@@ -12540,60 +12572,6 @@ class upgradeModel extends model
$this->dao->exec('ALTER TABLE ' . TABLE_STAGE . ' DROP COLUMN `projectType`');
}
/**
* TR和DCP评审对象升级到技术与决策评审流程。
* Upgrade TR and DCP objects to decision flows.
*
* @access public
* @return void
*/
public function upgradeDecision()
{
$ipdProjectGroups = $this->dao->select('id')->from(TABLE_WORKFLOWGROUP)->where('type')->eq('project')->andWhere('projectModel')->eq('ipd')->andWhere('builtin')->eq('1')->fetchPairs();
$ipdProjectStages = $this->dao->select('id,workflowGroup,type')->from(TABLE_STAGE)->where('projectType')->eq('ipd')->fetchGroup('workflowGroup');
$object = new stdclass();
$object->createdBy = $this->app->user->account;
$object->createdDate = helper::now();
$decisionFlow = new stdclass();
$decisionFlow->flow = 1;
$decisionFlow->objectType = 'decision';
$decisionFlow->relatedBy = $this->app->user->account;
$decisionFlow->relatedDate = helper::now();
$decisionFlow->extra = 'review';
foreach($ipdProjectGroups as $ipdProjectGroupID)
{
if(empty($ipdProjectStages[$ipdProjectGroupID])) continue;
$object->workflowgroup = $ipdProjectGroupID;
$decisionFlow->root = $ipdProjectGroupID;
foreach($ipdProjectStages[$ipdProjectGroupID] as $stages)
{
foreach($stages as $stage)
{
$object->stage = $stage->id;
$stageType = $stage->type;
foreach($this->config->review->ipdReviewPoint->$stageType as $category)
{
$object->title = $this->lang->review->reviewPoint->titleList[$category];
$object->type = strpos($category, 'TR') === 0 ? 'TR' : 'DCP';
$object->category = $category;
$this->dao->insert(TABLE_DECISION)->data($object)->autoCheck()->exec();
$decisionFlow->objectID = $this->dao->lastInsertID();
$this->dao->insert(TABLE_APPROVALFLOWOBJECT)->data($decisionFlow)->autoCheck()->exec();
}
}
}
}
return !dao::isError();
}
/**
* 调整 21.7.5 版本的权限
* Adjust priv 21.7.5.