* Finish task #84583.

This commit is contained in:
hufangzhou
2023-02-18 16:04:53 +00:00
parent 74a7615cca
commit 75b5b2562c
15 changed files with 725 additions and 215 deletions
+291 -3
View File
@@ -754,7 +754,6 @@ class executionModel extends model
$executions[$executionID]->PO = $data->POs[$executionID];
$executions[$executionID]->QD = $data->QDs[$executionID];
$executions[$executionID]->RD = $data->RDs[$executionID];
$executions[$executionID]->status = $data->statuses[$executionID];
$executions[$executionID]->begin = $data->begins[$executionID];
$executions[$executionID]->end = $data->ends[$executionID];
$executions[$executionID]->team = $data->teams[$executionID];
@@ -767,8 +766,6 @@ class executionModel extends model
if(isset($data->projects)) $executions[$executionID]->project = zget($data->projects, $executionID, 0);
if(isset($data->attributes)) $executions[$executionID]->attribute = zget($data->attributes, $executionID, '');
if(isset($data->lifetimes)) $executions[$executionID]->lifetime = $data->lifetimes[$executionID];
if($executions[$executionID]->status == 'closed' and $oldExecutions[$executionID]->status != 'closed') $executions[$executionID]->closedDate = helper::now();
if($executions[$executionID]->status == 'suspended' and $oldExecutions[$executionID]->status != 'suspended') $executions[$executionID]->suspendedDate = helper::today();
$oldExecution = $oldExecutions[$executionID];
$projectID = isset($executions[$executionID]->project) ? $executions[$executionID]->project : $oldExecution->project;
@@ -975,6 +972,245 @@ class executionModel extends model
return $allChanges;
}
/**
* Batch change status.
*
* @param array $executionIdList
* @param string $status
* @access public
* @return void
*/
public function batchChangeStatus($executionIdList, $status)
{
$this->loadModel('programplan');
$this->loadModel('action');
$selfAndChildrenList = $this->programplan->getSelfAndChildrenList($executionIdList);
$siblingStages = $this->programplan->getSiblings($executionIdList);
$pointOutStages = '';
foreach($executionIdList as $executionID)
{
$selfAndChildren = $selfAndChildrenList[$executionID];
$execution = $selfAndChildren[$executionID];
$executionType = $execution->type;
$siblingList = array();
if($executionType == 'stage') $siblingList = $siblingStages[$executionID];
if($status == 'wait' and $execution->status != 'wait')
{
$pointOutStages .= $this->changeStatus2Wait($executionID, $selfAndChildren, $siblingList);
}
if($status == 'doing' and $execution->status != 'doing')
{
$this->changeStatus2Doing($executionID, $selfAndChildren);
}
if(($status == 'suspended' and $execution->status != 'suspended') or ($status == 'closed' and $execution->status != 'closed'))
{
$pointOutStages .= $this->changeStatus2Inactived($executionID, $status, $selfAndChildren, $siblingList);
}
}
return trim($pointOutStages, ',');
}
/**
* Change status to wait.
*
* @param int $executionID
* @param array $selfAndChildren
* @param array $siblingStages
* @access public
* @return string
*/
public function changeStatus2Wait($executionID, $selfAndChildren, $siblingStages)
{
$parentID = $selfAndChildren[$executionID]->parent;
/* There are already tasks consuming work in this phase or its sub-phases already have start times. */
$hasStartedChildren = $this->dao->select('id')->from(TABLE_EXECUTION)->where('deleted')->eq(0)->andWhere('realBegan')->ne('0000-00-00')->andWhere('id')->in(array_keys($selfAndChildren))->andWhere('id')->ne($executionID)->fetchPairs();
$hasConsumedTasks = $this->dao->select('count(consumed) as count')->from(TABLE_TASK)->where('deleted')->eq(0)->andWhere('execution')->in(array_keys($selfAndChildren))->andWhere('consumed')->gt(0)->fetch('count');
if($hasStartedChildren or $hasConsumedTasks) return "'{$selfAndChildren[$executionID]->name}',";
$newExecution = $this->buildExecutionBySstatus('wait');
$this->dao->update(TABLE_EXECUTION)->data($newExecution)->where('id')->eq($executionID)->exec();
if(!dao::isError())
{
/* Action. */
$changes = common::createChanges($selfAndChildren[$executionID], $newExecution);
$actionID = $this->action->create('execution', $executionID, 'Edited');
$this->action->logHistory($actionID, $changes);
/* This stage has a parent stage. */
$checkTopStage = $this->programplan->checkTopStage($executionID);
$siblingsAllWait = true;
if(!$checkTopStage)
{
/* Check sibling stages are all wait. */
foreach($siblingStages as $siblingID => $sibling)
{
if($siblingID == $executionID) continue;
if($sibling->status != 'wait')
{
$siblingsAllWait = false;
return $pointOutStages;
}
}
if($siblingsAllWait)
{
/* Actual start or consumed work exists for the parent phase. */
$parent = $this->dao->select('*')->from(TABLE_EXECUTION)->where('id')->eq($parentID)->fetch();
$parentsChildren = $this->dao->select('id')->from(TABLE_EXECUTION)->where('deleted')->eq(0)->andWhere('path')->like("%,$executionID,%")->andWhere('id')->ne($parentID)->fetchPairs();
$parentHasConsumedTasks = $this->dao->select('count(id) as count')->from(TABLE_TASK)->where('deleted')->eq(0)->andWhere('execution')->in($parentsChildren)->andWhere('consumed')->gt(0)->fetch('count');
$parentStatus = (!helper::isZeroDate($parent->realBegan) or $parentHasConsumedTasks) ? 'doing' : 'wait';
if($parent->status == $parentStatus) return '';
$newParent = $this->buildExecutionBySstatus($parentStatus);
$this->dao->update(TABLE_EXECUTION)->data($newParent)->where('id')->eq($parentID)->exec();
if(!dao::isError())
{
$changes = common::createChanges($parent, $newParent);
$actionType = $parentStatus == 'doing' ? 'startbychildedit' : 'waitbychild';
$actionID = $this->action->create('execution', $parentID, $actionType, '', $actionType);
$this->action->logHistory($actionID, $changes);
if($parent->status == 'wait' and $parentStatus == 'doing') $this->loadModel('common')->syncPPEStatus($parentID);
}
}
}
}
}
/**
* Change status to doing.
*
* @param int $executionID
* @param array $selfAndChildren
* @access public
* @return string
*/
public function changeStatus2Doing($executionID, $selfAndChildren)
{
$type = $selfAndChildren[$executionID]->type;
$parentID = $selfAndChildren[$executionID]->parent;
$newExecution = $this->buildExecutionBySstatus('doing');
$this->dao->update(TABLE_EXECUTION)->data($newExecution)->where('id')->eq($executionID)->exec();
if(!dao::isError())
{
$changes = common::createChanges($selfAndChildren[$executionID], $newExecution);
$actionID = $this->action->create('execution', $executionID, 'Edited');
$this->action->logHistory($actionID, $changes);
if($type != 'stage') return '';
/* This stage has a parent stage. */
$checkTopStage = $this->programplan->checkTopStage($executionID);
if(!$checkTopStage)
{
$parent = $this->dao->select('*')->from(TABLE_EXECUTION)->where('id')->eq($parentID)->fetch();
if($parent->status == 'doing') return '';
$newParent = $this->buildExecutionBySstatus('doing');
$this->dao->update(TABLE_EXECUTION)->data($newParent)->where('id')->eq($parentID)->exec();
if(!dao::isError())
{
$changes = common::createChanges($parent, $newParent);
$actionID = $this->action->create('execution', $parentID, 'startbychildedit', '', 'startbychildedit');
$this->action->logHistory($actionID, $changes);
if($parent->status == 'wait') $this->loadModel('common')->syncPPEStatus($parentID);
}
}
}
}
/**
* Change status to suspended or closed.
*
* @param int $executionID
* @param strint $status
* @param array $selfAndChildren
* @param array $siblingStages
* @access public
* @return string
*/
public function changeStatus2Inactived($executionID, $status, $selfAndChildren, $siblingStages)
{
$type = $selfAndChildren[$executionID]->type;
$parentID = $selfAndChildren[$executionID]->parent;
$checkedStatus = $status == 'suspended' ? 'wait,doing' : 'wait,doing,suspended';
/* If status is suspended, the rules is there are sub-stages under this stage, and not all sub-stages are suspended or closed. */
/* If status is closed, the rules is there are sub-stages under this stage, and not all sub-stages are closed. */
$checkLeafStage = $this->programplan->checkLeafStage($executionID);
if(!$checkLeafStage)
{
foreach($selfAndChildren as $childID => $child)
{
if($childID == $executionID) continue;
if(strpos($checkedStatus, $child->status) !== false) return "'{$selfAndChildren[$executionID]->name}',";
}
}
$newExecution = $this->buildExecutionBySstatus($status);
$this->dao->update(TABLE_EXECUTION)->data($newExecution)->where('id')->eq($executionID)->exec();
if(!dao::isError())
{
$changes = common::createChanges($selfAndChildren[$executionID], $newExecution);
$actionID = $this->action->create('execution', $executionID, 'Edited');
$this->action->logHistory($actionID, $changes);
if($type != 'stage') return '';
/* Suspended: When all child stages at the same level are suspended or closed, the status of the parent stage becomes "suspended". */
/* Closed: When all child stages at the same level are closed, the status of the parent stage becomes "closed". */
$checkTopStage = $this->programplan->checkTopStage($executionID);
$siblingsAllInactived = true;
if(!$checkTopStage)
{
foreach($siblingStages as $siblingID => $sibling)
{
if($siblingID == $executionID) continue;
if(strpos($checkedStatus, $sibling->status) !== false)
{
$siblingsAllInactived = false;
break;
}
}
if($siblingsAllInactived)
{
$parent = $this->dao->select('*')->from(TABLE_EXECUTION)->where('id')->eq($parentID)->fetch();
if($parent->status == $status) return '';
$newParent = $this->buildExecutionBySstatus($status);
$this->dao->update(TABLE_EXECUTION)->data($newParent)->where('id')->eq($parentID)->exec();
if(!dao::isError())
{
$changes = common::createChanges($parent, $newParent);
$actionType = $status == 'suspended' ? 'suspendbychild' : 'closebychild';
$actionID = $this->action->create('execution', $parentID, $actionType, '', $actionType);
$this->action->logHistory($actionID, $changes);
}
}
}
}
}
/**
* Start execution.
*
@@ -5613,4 +5849,56 @@ class executionModel extends model
return $executionIdList;
}
/**
* Build execution object by status.
*
* @param string $status
* @access public
* @return object
*/
public function buildExecutionBySstatus($status)
{
$execution = new stdclass();
$execution->status = $status;
$execution->lastEditedBy = $this->app->user->account;
$execution->lastEditedDate = helper::now();
if($status == 'wait')
{
$execution->realBegan = '';
$execution->realEnd = '';
$execution->closedBy = '';
$execution->closedDate = '';
$execution->canceledBy = '';
$execution->canceledDate = '';
$execution->suspendedDate = '';
}
if($status == 'doing')
{
$execution->realBegan = helper::today();
$execution->realEnd = '';
$execution->closedBy = '';
$execution->closedDate = '';
$execution->canceledBy = '';
$execution->canceledDate = '';
$execution->suspendedDate = '';
}
if($status == 'suspended')
{
$execution->suspendedDate = helper::now();
$execution->closedBy = '';
$execution->closedDate = '';
}
if($status == 'closed')
{
$execution->closedBy = $this->app->user->account;
$execution->closedDate = helper::now();
}
return $execution;
}
}