Merge branch 'release/21.7.5' into feature/workflowgroup

This commit is contained in:
sunguangming
2025-09-01 05:41:47 +00:00
622 changed files with 20057 additions and 2716 deletions
+1 -1
View File
@@ -63,7 +63,7 @@ class programplan extends control
{
$this->loadModel('doc');
$projects = $this->loadModel('project')->getPairsByModel(array('ipd', 'waterfall', 'waterfallplus'));
if(empty($projects)) return $this->send(array('result' => 'fail', 'message' => $this->lang->doc->tips->noProject));
if(empty($projects)) return $this->send(array('result' => 'fail', 'message' => $this->lang->programplan->error->noProject));
if(!$projectID) $projectID = key($projects);
$this->view->projects = $projects;
+1
View File
@@ -148,6 +148,7 @@ $lang->programplan->error->planDrag = 'The %s stage cannot be dragged';
$lang->programplan->error->notStage = $lang->executionCommon . '/Kanban cannot create a sub stage.';
$lang->programplan->error->sameType = 'Type of the stage must be as same as parent: "%s"';
$lang->programplan->error->emptyParentName = "Contains sub stages, stage names cannot be empty.";
$lang->programplan->error->noProject = "When there are no waterfall, waterfall plus, or IPD {$lang->projectCommon} in the system, Gantt charts cannot be added.";
$lang->programplan->ganttBrowseType['gantt'] = 'Group by Stage';
$lang->programplan->ganttBrowseType['assignedTo'] = 'Group by AssignedTo';
+1
View File
@@ -148,6 +148,7 @@ $lang->programplan->error->planDrag = 'The %s stage cannot be dragged';
$lang->programplan->error->notStage = $lang->executionCommon . '/Kanban cannot create a sub stage.';
$lang->programplan->error->sameType = 'Type of the stage must be as same as parent: "%s"';
$lang->programplan->error->emptyParentName = "Contains sub stages, stage names cannot be empty.";
$lang->programplan->error->noProject = "When there are no waterfall, waterfall plus, or IPD {$lang->projectCommon} in the system, Gantt charts cannot be added.";
$lang->programplan->ganttBrowseType['gantt'] = 'Group by Stage';
$lang->programplan->ganttBrowseType['assignedTo'] = 'Group by AssignedTo';
+1
View File
@@ -148,6 +148,7 @@ $lang->programplan->error->planDrag = 'The %s stage cannot be dragged';
$lang->programplan->error->notStage = $lang->executionCommon . '/Kanban cannot create a sub stage.';
$lang->programplan->error->sameType = 'Type of the stage must be as same as parent: "%s"';
$lang->programplan->error->emptyParentName = "Contains sub stages, stage names cannot be empty.";
$lang->programplan->error->noProject = "When there are no waterfall, waterfall plus, or IPD {$lang->projectCommon} in the system, Gantt charts cannot be added.";
$lang->programplan->ganttBrowseType['gantt'] = 'Group by Stage';
$lang->programplan->ganttBrowseType['assignedTo'] = 'Group by AssignedTo';
+1
View File
@@ -148,6 +148,7 @@ $lang->programplan->error->planDrag = '%s的阶段不可以拖动';
$lang->programplan->error->notStage = $lang->executionCommon . '/看板不支持创建子阶段';
$lang->programplan->error->sameType = '父阶段类型为"%s",阶段类型需与父阶段一致';
$lang->programplan->error->emptyParentName = "包含子阶段,阶段名称不能为空。";
$lang->programplan->error->noProject = "系统中没有瀑布、融合瀑布、ipd{$lang->projectCommon}时,无法添加甘特图。";
$lang->programplan->ganttBrowseType['gantt'] = '按阶段分组';
$lang->programplan->ganttBrowseType['assignedTo'] = '按指派给分组';
+1
View File
@@ -235,6 +235,7 @@ class programplanModel extends model
$workingDays = $this->loadModel('holiday')->getActualWorkingDays($begin, $end);
foreach($tasksGroup as $group => $tasks)
{
if(!$group) $group = '/'; // 未指派
$groupID ++;
$groupKey = $groupID . $group;
$datas['data'][$groupKey] = $this->programplanTao->buildGroupDataForGantt($groupID, $group, $users);
+9 -1
View File
@@ -572,6 +572,14 @@ class programplanTao extends programplanModel
$this->setTreePath($stageID);
$this->computeProgress($stageID, 'create');
/* Add the execution team members to parent executions. */
$stagePath = $this->dao->findByID($stageID)->from(TABLE_PROJECT)->fetch('path');
foreach(explode(',', $stagePath) as $stageParentID)
{
if(empty($stageParentID) || $stageParentID == $projectID) continue;
$this->execution->addExecutionMembers((int)$stageParentID, array($plan->PM));
}
return $stageID;
}
@@ -733,7 +741,7 @@ class programplanTao extends programplanModel
{
$this->app->loadLang('task');
$groupName = $group;
$groupName = $group ? zget($users, $group) : $this->lang->task->noAssigned;
$groupName = $group != '/' ? zget($users, $group) : $this->lang->task->noAssigned;
$dataGroup = new stdclass();
$dataGroup->id = $groupID;
@@ -7,13 +7,13 @@ title=测试 programplanModel->getDataForGanttGroupByAssignedTo();
timeout=0
cid=0
- 测试获取阶段数据第0条的type属性 @task
- 测试获取阶段数据第0条的type属性 @group
- 测试获取任务数据
- 第1条的id属性 @1-4
- 第1条的id属性 @1-1
- 第1条的type属性 @task
- 测试获取阶段数据(JSON类型返回值)第2条的type属性 @task
- 测试获取任务数据(JSON类型返回值)
- 第3条的id属性 @1-8
- 第3条的id属性 @1-5
- 第3条的type属性 @task
- 测试自定义参数为空的情况获取任务数据 @1
@@ -30,8 +30,8 @@ $programplan = new programplanTest();
$selectCustom = 'date,task';
$selectNoneCustom = '';
r($programplan->getDataForGanttGroupByAssignedToTest(1, 1, 0, $selectCustom, false)) && p('0:type') && e('task'); // 测试获取阶段数据
r($programplan->getDataForGanttGroupByAssignedToTest(1, 1, 0, $selectCustom, false)) && p('1:id,type') && e('1-4,task'); // 测试获取任务数据
r($programplan->getDataForGanttGroupByAssignedToTest(1, 1, 0, $selectCustom, false)) && p('0:type') && e('group'); // 测试获取阶段数据
r($programplan->getDataForGanttGroupByAssignedToTest(1, 1, 0, $selectCustom, false)) && p('1:id,type') && e('1-1,task'); // 测试获取任务数据
r($programplan->getDataForGanttGroupByAssignedToTest(1, 1, 0, $selectCustom, true)) && p('2:type') && e('task'); // 测试获取阶段数据(JSON类型返回值)
r($programplan->getDataForGanttGroupByAssignedToTest(1, 1, 0, $selectCustom, true)) && p('3:id,type') && e('1-8,task'); // 测试获取任务数据(JSON类型返回值)
r(count($programplan->getDataForGanttGroupByAssignedToTest(1, 1, 0, $selectNoneCustom, false))) && p() && e('1'); // 测试自定义参数为空的情况获取任务数据
r($programplan->getDataForGanttGroupByAssignedToTest(1, 1, 0, $selectCustom, true)) && p('3:id,type') && e('1-5,task'); // 测试获取任务数据(JSON类型返回值)
r(count($programplan->getDataForGanttGroupByAssignedToTest(1, 1, 0, $selectNoneCustom, false))) && p() && e('1'); // 测试自定义参数为空的情况获取任务数据
+23 -1
View File
@@ -4,6 +4,7 @@
/**
title=测试 programplanModel->getGanttTasks();
timeout=0
cid=0
- 测试查询项目 11 执行 101 browseType 空 queryID 0 的甘特图任务 @1
@@ -15,6 +16,27 @@ cid=0
- 测试查询项目 12 执行 102 browseType bysearch queryID 0 的甘特图任务 @0
- 测试查询项目 12 执行 102 browseType bysearch queryID 1 的甘特图任务 @0
- 测试查询不存在的项目 101 执行 101 browseType 空 queryID 0 的甘特图任务 @0
- 测试查询项目 11 执行 101 browseType 空 queryID 0 的甘特图任务
- 第1条的storyVersion属性 @1
- 第1条的storyStatus属性 @active
- 第1条的needConfirm属性 @~~
- 测试查询项目 11 执行 101 browseType 空 queryID 1 的甘特图任务
- 第1条的storyVersion属性 @1
- 第1条的storyStatus属性 @active
- 第1条的needConfirm属性 @~~
- 测试查询项目 11 执行 101 browseType bysearch queryID 0 的甘特图任务 @0
- 测试查询项目 11 执行 101 browseType bysearch queryID 1 的甘特图任务 @0
- 测试查询项目 12 执行 102 browseType 空 queryID 0 的甘特图任务
- 第2条的storyVersion属性 @1
- 第2条的storyStatus属性 @active
- 第2条的needConfirm属性 @~~
- 测试查询项目 12 执行 102 browseType 空 queryID 1 的甘特图任务
- 第2条的storyVersion属性 @1
- 第2条的storyStatus属性 @active
- 第2条的needConfirm属性 @~~
- 测试查询项目 12 执行 102 browseType bysearch queryID 0 的甘特图任务 @0
- 测试查询项目 12 执行 102 browseType bysearch queryID 1 的甘特图任务 @0
- 测试查询不存在的项目 101 执行 101 browseType 空 queryID 0 的甘特图任务 @0
*/
include dirname(__FILE__, 5) . '/test/lib/init.php';
@@ -58,4 +80,4 @@ r($programplan->getGanttTasksTest($projectID[1], $planIdList[1], $browseType[0],
r($programplan->getGanttTasksTest($projectID[1], $planIdList[1], $browseType[0], $queryID[1], false)) && p('2:storyVersion,storyStatus,needConfirm') && e('1,active,~~'); // 测试查询项目 12 执行 102 browseType 空 queryID 1 的甘特图任务
r($programplan->getGanttTasksTest($projectID[1], $planIdList[1], $browseType[1], $queryID[0], false)) && p() && e('0'); // 测试查询项目 12 执行 102 browseType bysearch queryID 0 的甘特图任务
r($programplan->getGanttTasksTest($projectID[1], $planIdList[1], $browseType[1], $queryID[1], false)) && p() && e('0'); // 测试查询项目 12 执行 102 browseType bysearch queryID 1 的甘特图任务
r($programplan->getGanttTasksTest($projectID[2], $planIdList[0], $browseType[0], $queryID[0], false)) && p() && e('0'); // 测试查询不存在的项目 101 执行 101 browseType 空 queryID 0 的甘特图任务
r($programplan->getGanttTasksTest($projectID[2], $planIdList[0], $browseType[0], $queryID[0], false)) && p() && e('0'); // 测试查询不存在的项目 101 执行 101 browseType 空 queryID 0 的甘特图任务
+5 -4
View File
@@ -4,6 +4,7 @@
/**
title=测试 loadModel->buildGroupDataForGantt()
timeout=0
cid=0
- 检查构建分组Gantt数据。
@@ -17,12 +18,12 @@ cid=0
- 检查空组构建情况。
- 属性id @3
- 属性type @group
- 属性text @''
- 属性text @未指派
- 检查自定义组ID。
- 属性id @99
- 属性type @group
- 属性text @产品
- 检查无用户列表时。
- 检查无用户列表。
- 属性id @5
- 属性type @group
- 属性text @设计
@@ -50,7 +51,7 @@ $group = '测试';
r((array)$tester->programplan->buildGroupDataForGantt($groupID, $group, $users)) && p('id,type,text') && e("2,group,测试"); //检查另一个分组。
$groupID = 3;
$group = '';
$group = '/';
r((array)$tester->programplan->buildGroupDataForGantt($groupID, $group, $users)) && p('id,type,text') && e("3,group,未指派"); //检查空组构建情况。
$groupID = 99;
@@ -59,4 +60,4 @@ r((array)$tester->programplan->buildGroupDataForGantt($groupID, $group, $users))
$groupID = 5;
$group = '设计';
r((array)$tester->programplan->buildGroupDataForGantt($groupID, $group, $emptyUsers)) && p('id,type,text') && e("5,group,设计"); //检查无用户列表。
r((array)$tester->programplan->buildGroupDataForGantt($groupID, $group, $emptyUsers)) && p('id,type,text') && e("5,group,设计"); //检查无用户列表。
+76
View File
@@ -0,0 +1,76 @@
#!/usr/bin/env php
<?php
/**
title=测试 loadModel->checkLegallyDate()
timeout=0
cid=0
- 不能超过项目的起止日期属性end[0] @阶段的结束时间不能大于所属项目的结束时间2025-02-01
- 没有错误 @0
- 不能超过父阶段起止日期属性end[0] @子阶段计划完成不能超过父阶段的计划完成时间 2025-01-15
- 不能超过父阶段起止日期属性begin[0] @子阶段计划开始不能小于父阶段的计划开始时间 2025-01-02
- 模板类型的项目没有错误 @0
*/
include dirname(__FILE__, 5). '/test/lib/init.php';
su('admin');
$project = new stdclass();
$project->begin = '2025-01-01';
$project->end = '2025-02-01';
$plan = new stdclass();
$plan->begin = '2025-01-01';
$plan->end = '2025-02-02';
global $tester;
$zen = initReference('programplan');
$func = $zen->getMethod('checkLegallyDate');
$func->invokeArgs($zen->newInstance(), [$plan, $project, null, 0]);
r(dao::getError()) && p('end[0]') && e('阶段的结束时间不能大于所属项目的结束时间2025-02-01'); // 不能超过项目的起止日期
dao::$errors = array();
$project = new stdclass();
$project->begin = '2025-01-01';
$project->end = '2025-02-01';
$plan = new stdclass();
$plan->begin = '2025-01-01';
$plan->end = '2025-02-01';
$func->invokeArgs($zen->newInstance(), [$plan, $project, null, 0]);
r(dao::getError()) && p('') && e('0'); // 没有错误
dao::$errors = array();
$parent = new stdclass();
$parent->begin = '2025-01-01';
$parent->end = '2025-01-15';
$func->invokeArgs($zen->newInstance(), [$plan, $project, $parent, 0]);
r(dao::getError()) && p('end[0]') && e('子阶段计划完成不能超过父阶段的计划完成时间 2025-01-15'); // 不能超过父阶段起止日期
dao::$errors = array();
$parent = new stdclass();
$parent->begin = '2025-01-02';
$parent->end = '2025-02-15';
$func->invokeArgs($zen->newInstance(), [$plan, $project, $parent, 0]);
r(dao::getError()) && p('begin[0]') && e('子阶段计划开始不能小于父阶段的计划开始时间 2025-01-02'); // 不能超过父阶段起止日期
dao::$errors = array();
$project->isTpl = '1';
$func->invokeArgs($zen->newInstance(), [$plan, $project, $parent, 0]);
r(dao::getError()) && p('') && e('0'); // 模板类型的项目没有错误
+3 -5
View File
@@ -22,6 +22,7 @@ class programplanZen extends programplan
private function checkLegallyDate(object $plan, object $project, object|null $parent, int $rowID): void
{
if(isset($plan->enabled) && $plan->enabled == 'off') return;
if(!empty($project->isTpl)) return; // 模板不校验日期
$beginIsZeroDate = helper::isZeroDate($plan->begin);
$endIsZeroDate = helper::isZeroDate($plan->end);
@@ -441,12 +442,9 @@ class programplanZen extends programplan
if($hasSearch)
{
/* Build the search form. */
$this->config->execution->search['module'] = 'projectTask';
$actionURL = $this->createLink('programplan', 'browse', "projectID=$projectID&productID=$productID&type=$type&orderBy=$orderBy&baselineID=$baselineID&browseType=bysearch&queryID=myQueryID");
unset($this->config->execution->search['fields']['project']);
$actionURL = $this->createLink('programplan', 'browse', "projectID=$projectID&productID=$productID&type=$type&orderBy=$orderBy&baselineID=$baselineID&browseType=bysearch&queryID=myQueryID");
$executions = $this->programplan->getPairs($projectID, $productID, 'all');
$this->loadModel('execution')->buildTaskSearchForm($projectID, $executions, $queryID, $actionURL);
$this->loadModel('execution')->buildTaskSearchForm($projectID, $executions, $queryID, $actionURL, 'projectTask');
}
$this->view->title = $this->lang->programplan->browse;