| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448 |
- <?php
- /**
- * The model file of stage module of ZenTaoPMS.
- *
- * @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.cnezsoft.com)
- * @license ZPL(http://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
- * @author Chunsheng Wang <chunsheng@cnezsoft.com>
- * @package stage
- * @version $Id: model.php 5079 2013-07-10 00:44:34Z chencongzhi520@gmail.com $
- * @link https://www.zentao.net
- */
- ?>
- <?php
- class stageModel extends model
- {
- /**
- * 创建一个阶段。
- * Create a stage.
- *
- * @param object $stage
- * @access public
- * @return int|bool
- */
- public function create($stage)
- {
- if(isset($this->config->setPercent) && $this->config->setPercent == 1)
- {
- $totalPercent = $this->getTotalPercent($stage->workflowGroup);
- if(!is_numeric($stage->percent))
- {
- dao::$errors['percent'] = $this->lang->stage->error->notNum;
- return false;
- }
- if(round($totalPercent + $stage->percent) > 100)
- {
- dao::$errors['percent'] = $this->lang->stage->error->percentOver;
- return false;
- }
- }
- $this->lang->error->unique = $this->lang->error->repeat;
- if(!empty($stage->percent)) $stage->percent = (float)$stage->percent;
- $this->dao->insert(TABLE_STAGE)
- ->data($stage)
- ->autoCheck()
- ->batchCheck($this->config->stage->create->requiredFields, 'notempty')
- ->checkIF(!empty($stage->name), 'name', 'unique', "`workflowGroup` = '$stage->workflowGroup' AND `deleted` = '0'")
- ->exec();
- $stageID = $this->dao->lastInsertID();
- $maxOrder = $this->dao->select('MAX(`order`) AS maxOrder')->from(TABLE_STAGE)->where('workflowGroup')->eq($stage->workflowGroup)->andWhere('deleted')->eq('0')->fetch('maxOrder');
- $this->dao->update(TABLE_STAGE)->set('order')->eq((int)$maxOrder + 1)->where('id')->eq($stageID)->exec();
- if(dao::isError()) return false;
- return $this->dao->lastInsertID();
- }
- /**
- * 批量创建阶段。
- * Batch create stages.
- *
- * @param int $groupID
- * @param array $stages
- * @access public
- * @return bool
- */
- public function batchCreate($groupID = 0, $stages = array())
- {
- $setPercent = (isset($this->config->setPercent) && $this->config->setPercent == 1) ? true : false;
- if($setPercent)
- {
- $oldTotalPercent = $this->getTotalPercent($groupID);
- $totalPercent = 0;
- foreach($stages as $stage)
- {
- if($totalPercent > 100) break;
- $totalPercent += (float)$stage->percent;
- }
- if(round($oldTotalPercent + $totalPercent) > 100)
- {
- dao::$errors['message'] = $this->lang->stage->error->percentOver;
- return false;
- }
- }
- $stageNames = $this->dao->select('id,name')->from(TABLE_STAGE)->where('workflowGroup')->eq($groupID)->andWhere('deleted')->eq('0')->fetchPairs('name');
- foreach($stages as $rowID => $stage)
- {
- if(in_array($stage->name, $stageNames))
- {
- dao::$errors["name[$rowID]"] = sprintf($this->lang->error->repeat, $this->lang->stage->name, $stage->name);
- return false;
- }
- $stageNames[] = $stage->name;
- }
- $maxOrder = $this->dao->select('MAX(`order`) AS maxOrder')->from(TABLE_STAGE)->where('workflowGroup')->eq($groupID)->andWhere('deleted')->eq('0')->fetch('maxOrder');
- $this->loadModel('action');
- $now = helper::now();
- foreach($stages as $rowID => $stage)
- {
- $stage->workflowGroup = $groupID;
- $stage->createdBy = $this->app->user->account;
- $stage->createdDate = $now;
- if(!empty($stage->percent)) $stage->percent = (float)$stage->percent;
- $this->dao->insert(TABLE_STAGE)->data($stage)->autoCheck()
- ->batchCheck($this->config->stage->create->requiredFields, 'notempty')
- ->exec();
- if(dao::isError())
- {
- foreach(dao::getError() as $field => $error) dao::$errors["{$field}[{$rowID}]"] = $error;
- return false;
- }
- $stageID = $this->dao->lastInsertID();
- $this->action->create('stage', $stageID, 'Opened');
- $stageOrder = empty($maxOrder) ? 1 : ++ $maxOrder;
- $this->dao->update(TABLE_STAGE)->set('order')->eq($stageOrder)->where('id')->eq($stageID)->exec();
- }
- return true;
- }
- /**
- * 编辑一个阶段。
- * Update a stage.
- *
- * @param int $stageID
- * @param object $stage
- * @access public
- * @return bool|array
- */
- public function update($stageID, $stage)
- {
- $oldStage = $this->dao->select('*')->from(TABLE_STAGE)->where('id')->eq((int)$stageID)->fetch();
- if(!$oldStage) return false;
- if(isset($this->config->setPercent) && $this->config->setPercent == 1)
- {
- $totalPercent = $this->getTotalPercent($oldStage->workflowGroup);
- if(round($totalPercent + (float)$stage->percent - (float)$oldStage->percent) > 100)
- {
- dao::$errors['percent'] = $this->lang->stage->error->percentOver;
- return false;
- }
- }
- $this->lang->error->unique = $this->lang->error->repeat;
- $this->dao->update(TABLE_STAGE)
- ->data($stage)
- ->autoCheck()
- ->batchCheck($this->config->stage->edit->requiredFields, 'notempty')
- ->checkIF(isset($stage->percent) && $stage->percent != '', 'percent', 'float')->where('id')->eq((int)$stageID)
- ->checkIF(!empty($stage->name), 'name', 'unique', "`id` != '$stageID' AND `workflowGroup` = '$oldStage->workflowGroup' AND `deleted` = '0'")
- ->exec();
- if(dao::isError()) return false;
- return common::createChanges($oldStage, $stage);
- }
- /**
- * 获取阶段列表信息。
- * Get stage list info.
- *
- * @param string $orderBy
- * @param int $projectID
- * @param int $groupID
- * @param int $grade
- * @access public
- * @return array
- */
- public function getStages($orderBy = 'order_desc', $projectID = 0, $groupID = 0, $grade = 0)
- {
- if(common::isTutorialMode()) return $this->loadModel('tutorial')->getStages();
- if($projectID)
- {
- return $this->dao->select('`id`,name,type,percent,openedBy as createdBy,`begin` as createdDate,lastEditedBy as editedBy,`end` as editedDate,deleted')
- ->from(TABLE_EXECUTION)
- ->where('type')->in('sprint,stage,kanban')
- ->andWhere('deleted')->eq('0')
- ->andWhere('vision')->eq($this->config->vision)
- ->beginIF(!$this->app->user->admin)->andWhere('id')->in($this->app->user->view->sprints)->fi()
- ->beginIF($grade)->andWhere('grade')->eq($grade)->fi()
- ->andWhere('project')->eq($projectID)
- ->orderBy($orderBy)
- ->fetchAll('id');
- }
- $stages = $this->dao->select('*')->from(TABLE_STAGE)
- ->where('deleted')->eq(0)
- ->andWhere('workflowGroup')->eq($groupID)
- ->beginIF($this->config->edition != 'ipd')->andWhere('projectType')->ne('ipd')->fi()
- ->andWhere('type')->ne('lifecycle')
- ->orderBy($orderBy)
- ->fetchAll('id');
- $stagePoints = $this->dao->select('*')->from(TABLE_DECISION)->where('stage')->in(array_keys($stages))->andWhere('deleted')->eq('0')->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']) : '';
- $stage->pointList = zget($pointList, $stage->id, array());
- }
- return $stages;
- }
- /**
- * 通过ID获取阶段信息。
- * Get stage info by ID.
- *
- * @param int $stageID
- * @access public
- * @return object|bool
- */
- public function getByID($stageID)
- {
- return $this->dao->select('*')->from(TABLE_STAGE)->where('deleted')->eq(0)->andWhere('id')->eq((int)$stageID)->fetch();
- }
- /**
- * 获取给定模型下的阶段总百分比。
- * Get total percent of the type.
- *
- * @param string $type waterfall|waterfallplus
- * @return float
- * @param int $groupID
- */
- public function getTotalPercent($groupID)
- {
- 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($groupID)
- {
- $workflowGroup = $this->dao->select('*')->from(TABLE_WORKFLOWGROUP)->where('id')->eq($groupID)->fetch();
- $this->app->loadConfig('project');
- $stageList = $this->dao->select('*')->from(TABLE_STAGE)->where('workflowGroup')->eq($groupID)->fetchAll('id');
- if(empty($stageList))
- {
- $stageTypeList = array();
- if($workflowGroup->projectModel == 'ipd')
- {
- 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'];
- }
- if(in_array($workflowGroup->projectModel, array('waterfall', 'waterfallplus'))) $stageTypeList = $this->config->project->categoryStages['waterfall'];
- foreach($stageTypeList as $stageType)
- {
- $builtinStage = new stdClass();
- $builtinStage->workflowGroup = $groupID;
- $builtinStage->createdBy = 'system';
- $builtinStage->createdDate = helper::now();
- $builtinStage->name = in_array($workflowGroup->projectModel, array('waterfall', 'waterfallplus')) ? zget($this->lang->stage->typeList, $stageType, '') : zget($this->lang->stage->ipdTypeList, $stageType, '');
- $builtinStage->type = $stageType;
- $builtinStage->projectType = $workflowGroup->projectModel;
- $this->dao->insert(TABLE_STAGE)->data($builtinStage)->exec();
- $stageID = $this->dao->lastInsertID();
- $stageList[$stageID] = $builtinStage;
- }
- }
- 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;
- $decision = new stdClass();
- $decision->builtin = '1';
- $decision->createdBy = 'system';
- $decision->createdDate = helper::now();
- $decision->workflowGroup = $groupID;
- $decisionFlow = new stdClass();
- $decisionFlow->flow = 1;
- $decisionFlow->objectType = 'decision';
- $decisionFlow->relatedBy = 'system';
- $decisionFlow->relatedDate = helper::now();
- foreach($stageList as $id => $stage)
- {
- foreach($this->config->stage->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($type, $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 = 'decision'")
- ->where('t1.deleted')->eq('0')
- ->andWhere('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
- * @param mixed[] $points
- */
- public function setPoint($type, $stageID, $points)
- {
- $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('decision')
- ->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 = 'decision';
- $approvalFlowObject->objectID = $newPointID;
- $approvalFlowObject->relatedBy = $this->app->user->account;
- $approvalFlowObject->relatedDate = helper::now();
- $approvalFlowObject->extra = $type;
- $this->dao->insert(TABLE_APPROVALFLOWOBJECT)->data($approvalFlowObject)->exec();
- if(dao::isError()) return false;
- }
- }
- if(!empty($oldStagePoints))
- {
- $this->dao->update(TABLE_DECISION)->set('deleted')->eq('1')->where('id')->in(array_keys($oldStagePoints))->exec();
- $approvalFlowObjectIDList = $this->dao->select('id')->from(TABLE_APPROVALFLOWOBJECT)
- ->where('objectID')->in(array_keys($oldStagePoints))
- ->andWhere('objectType')->eq('decision')
- ->andWhere('root')->eq($stage->workflowGroup)
- ->fetchPairs();
- $this->dao->delete()->from(TABLE_APPROVALFLOWOBJECT)->where('id')->in($approvalFlowObjectIDList)->exec(); // 删除评审流程
- $this->dao->delete()->from(TABLE_REVIEWCL)->where('object')->in($approvalFlowObjectIDList)->exec(); // 删除检查清单
- }
- return true;
- }
- /**
- * 更新排序。
- * Update order.
- *
- * @param array $sortedIdList
- * @access public
- * @return void
- */
- public function updateOrder($sortedIdList)
- {
- foreach($sortedIdList as $stageID => $order)
- {
- $this->dao->update(TABLE_STAGE)->set('order')->eq($order + 1)->where('id')->eq($stageID)->exec();
- }
- }
- }
|