328 lines
16 KiB
PHP
328 lines
16 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
/**
|
|
* The tao file of my module of ZenTaoPMS.
|
|
*
|
|
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
|
|
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
|
* @author Mengyi Liu <liumengyi@easycorp.ltd>
|
|
* @package my
|
|
* @link https://www.zentao.net
|
|
*/
|
|
class myTao extends myModel
|
|
{
|
|
|
|
/**
|
|
* 获取产品相关的由我指派的数据。
|
|
* Get the data related to the product assigned by me.
|
|
*
|
|
* @param array $objectIdList
|
|
* @param string $objectType
|
|
* @param string $orderBy
|
|
* @param object $pager
|
|
* @access protected
|
|
* @return array
|
|
*/
|
|
protected function getProductRelatedAssignedByMe(array $objectIdList, string $objectType, string $module, string $orderBy, ?object $pager = null): array
|
|
{
|
|
$nameField = $objectType == 'bug' ? 'productName' : 'productTitle';
|
|
$orderBy = strpos($orderBy, 'priOrder') !== false || strpos($orderBy, 'severityOrder') !== false || strpos($orderBy, $nameField) !== false ? $orderBy : "t1.{$orderBy}";
|
|
$select = "t1.*, t2.name AS {$nameField}, t2.shadow AS shadow, " . (strpos($orderBy, 'severity') !== false ? "IF(t1.`severity` = 0, {$this->config->maxPriValue}, t1.`severity`) AS severityOrder" : "IF(t1.`pri` = 0, {$this->config->maxPriValue}, t1.`pri`) AS priOrder");
|
|
$objectList = $this->dao->select($select)->from($this->config->objectTables[$module])->alias('t1')
|
|
->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t1.product = t2.id')
|
|
->where('t1.deleted')->eq(0)
|
|
->andWhere('t2.deleted')->eq(0)
|
|
->andWhere('t1.id')->in($objectIdList)
|
|
->beginIF($module == 'story')->andWhere('t1.type')->eq($objectType)->fi()
|
|
->beginIF($module == 'story')->andWhere("FIND_IN_SET('{$this->config->vision}', t1.vision)")->fi()
|
|
->orderBy($orderBy)
|
|
->page($pager)
|
|
->fetchAll('id', false);
|
|
|
|
if($module == 'story')
|
|
{
|
|
$planList = array();
|
|
foreach($objectList as $story) $planList[$story->plan] = $story->plan;
|
|
$planPairs = $this->dao->select('id,title')->from(TABLE_PRODUCTPLAN)->where('id')->in($planList)->fetchPairs('id');
|
|
foreach($objectList as $story) $story->planTitle = zget($planPairs, $story->plan, '');
|
|
}
|
|
return $objectList;
|
|
}
|
|
|
|
/**
|
|
* 通过搜索查找任务。
|
|
* Fetch tasks by search.
|
|
*
|
|
* @param string $query
|
|
* @param string $moduleName
|
|
* @param string $account
|
|
* @param array $taskIdList
|
|
* @param string $orderBy
|
|
* @param int $limit
|
|
* @param object $pager
|
|
* @access protected
|
|
* @return array
|
|
*/
|
|
protected function fetchTasksBySearch(string $query, string $moduleName, string $account, array $taskIdList, string $orderBy, int $limit, ?object $pager = null): array
|
|
{
|
|
$query = preg_replace('/`(\w+)`/', 't1.`$1`', $query);
|
|
$query = str_replace('t1.`project`', 't2.`project`', $query);
|
|
|
|
$assignedToMatches = array();
|
|
$assignedToCondition = '';
|
|
$operatorAndAccount = '';
|
|
if(strpos($query, '`assignedTo`') !== false)
|
|
{
|
|
preg_match("/`assignedTo`\s+(([^']*) ('([^']*)'))/", $query, $assignedToMatches);
|
|
if(!empty($assignedToMatches))
|
|
{
|
|
$assignedToCondition = $assignedToMatches[0];
|
|
$operatorAndAccount = $assignedToMatches[1];
|
|
$query = str_replace("t1.{$assignedToMatches[0]}", "(t1.{$assignedToCondition} or (t1.mode = 'multi' and t5.`account` {$operatorAndAccount} and t1.status != 'closed' and t5.status != 'done') )", $query);
|
|
}
|
|
}
|
|
if(strpos($query, "t2.`project` = 'all'") !== false) $query = str_replace("t2.`project` = 'all'", "t2.`project` != '0'", $query);
|
|
if(strpos($query, "t2.`project` != 'all'") !== false) $query = str_replace("t2.`project` != 'all'", "t2.`project` = '0'", $query);
|
|
if(strpos($query, "t1.`execution` = 'all'") !== false) $query = str_replace("t1.`execution` = 'all'", "t1.`execution` != '0'", $query);
|
|
|
|
$orderBy = str_replace('pri_', 'priOrder_', $orderBy);
|
|
return $this->dao->select("t1.*, t4.id as project, t2.id as executionID, t2.name as executionName, t2.multiple as executionMultiple, t4.name as projectName, t2.type as executionType, t3.id as storyID, t3.title as storyTitle, t3.status AS storyStatus, t3.version AS latestStoryVersion, IF(t1.`pri` = 0, {$this->config->maxPriValue}, t1.`pri`) as priOrder")
|
|
->from(TABLE_TASK)->alias('t1')
|
|
->leftJoin(TABLE_EXECUTION)->alias('t2')->on("t1.execution = t2.id")
|
|
->leftJoin(TABLE_STORY)->alias('t3')->on('t1.story = t3.id')
|
|
->leftJoin(TABLE_PROJECT)->alias('t4')->on("t2.project = t4.id")
|
|
->leftJoin(TABLE_TASKTEAM)->alias('t5')->on("t1.id = t5.task")
|
|
->where($query)
|
|
->andWhere('t1.deleted')->eq(0)
|
|
->andWhere('t2.deleted')->eq(0)
|
|
->andWhere('(t2.status')->ne('suspended')->orWhere('t4.status')->ne('suspended')->markRight(1)
|
|
->beginIF($moduleName == 'workTask')
|
|
->beginIF(!empty($assignedToMatches))->andWhere("(t1.{$assignedToCondition} or (t1.mode = 'multi' and t5.`account` {$operatorAndAccount} and t1.status != 'closed' and t5.status != 'done') )")->fi()
|
|
->beginIF(empty($assignedToMatches))->andWhere("(t1.assignedTo = '{$account}' or (t1.mode = 'multi' and t5.`account` = '{$account}' and t1.status != 'closed' and t5.status != 'done') )")->fi()
|
|
->andWhere('t1.status')->notin('closed,cancel')
|
|
->fi()
|
|
->beginIF($moduleName == 'contributeTask')
|
|
->andWhere('t1.openedBy', 1)->eq($account)
|
|
->orWhere('t1.closedBy')->eq($account)
|
|
->orWhere('t1.canceledBy')->eq($account)
|
|
->orWhere('t1.finishedby')->eq($account)
|
|
->orWhere('t1.assignedTo')->eq($account)
|
|
->orWhere('t5.account')->eq($account)
|
|
->orWhere('t1.id')->in($taskIdList)
|
|
->markRight(1)
|
|
->fi()
|
|
->beginIF($this->config->vision)->andWhere('t1.vision')->eq($this->config->vision)->fi()
|
|
->beginIF($this->config->vision)->andWhere('t2.vision')->eq($this->config->vision)->fi()
|
|
->beginIF(!$this->app->user->admin)->andWhere('t1.execution')->in($this->app->user->view->sprints)->fi()
|
|
->orderBy($orderBy)
|
|
->beginIF($limit > 0)->limit($limit)->fi()
|
|
->page($pager, 't1.id')
|
|
->fetchAll('id');
|
|
}
|
|
|
|
/**
|
|
* 通过搜索查找需求。
|
|
* Fetch stories by search.
|
|
*
|
|
* @param string $myStoryQuery
|
|
* @param string $type
|
|
* @param string $orderBy
|
|
* @param object $pager
|
|
* @param array $storiesAssignedByMe
|
|
* @access protected
|
|
* @return array
|
|
*/
|
|
protected function fetchStoriesBySearch(string $myStoryQuery, string $type, string $orderBy, ?object $pager = null, array $storiesAssignedByMe = array()): array
|
|
{
|
|
if($type == 'contribute')
|
|
{
|
|
$storyIdList = !empty($storiesAssignedByMe) ? array_keys($storiesAssignedByMe) : array();
|
|
$stories = $this->dao->select("distinct t1.*, IF(t1.`pri` = 0, {$this->config->maxPriValue}, t1.`pri`) as priOrder, t2.name as productTitle, t2.shadow as shadow, t4.title as planTitle")->from(TABLE_STORY)->alias('t1')
|
|
->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t1.product = t2.id')
|
|
->leftJoin(TABLE_PLANSTORY)->alias('t3')->on('t1.id = t3.plan')
|
|
->leftJoin(TABLE_PRODUCTPLAN)->alias('t4')->on('t3.plan = t4.id')
|
|
->leftJoin(TABLE_STORYREVIEW)->alias('t5')->on('t1.id = t5.story')
|
|
->where($myStoryQuery)
|
|
->andWhere('t1.type')->eq('story')
|
|
->andWhere('t1.openedBy',1)->eq($this->app->user->account)
|
|
->orWhere('t5.reviewer')->eq($this->app->user->account)
|
|
->orWhere('t1.closedBy')->eq($this->app->user->account)
|
|
->orWhere('t1.id')->in($storyIdList)
|
|
->markRight(1)
|
|
->andWhere('t1.deleted')->eq(0)
|
|
->orderBy($orderBy)
|
|
->page($pager, 't1.id')
|
|
->fetchAll('id');
|
|
}
|
|
else
|
|
{
|
|
$stories = $this->dao->select("distinct t1.*, IF(t1.`pri` = 0, {$this->config->maxPriValue}, t1.`pri`) as priOrder, t2.name as productTitle, t2.shadow as shadow, t4.title as planTitle")->from(TABLE_STORY)->alias('t1')
|
|
->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t1.product = t2.id')
|
|
->leftJoin(TABLE_PLANSTORY)->alias('t3')->on('t1.id = t3.plan')
|
|
->leftJoin(TABLE_PRODUCTPLAN)->alias('t4')->on('t3.plan = t4.id')
|
|
->leftJoin(TABLE_STORYREVIEW)->alias('t5')->on('t1.id = t5.story AND t1.version=t5.version')
|
|
->where($myStoryQuery)
|
|
->andWhere('t1.type')->eq('story')
|
|
->andWhere('t1.assignedTo',1)->eq($this->app->user->account)
|
|
->orWhere("(t5.reviewer = '{$this->app->user->account}' AND t5.result = '' AND t1.status = 'reviewing')")
|
|
->markRight(1)
|
|
->andWhere('t1.product')->ne('0')
|
|
->andWhere('t1.deleted')->eq(0)
|
|
->orderBy($orderBy)
|
|
->page($pager, 't1.id')
|
|
->fetchAll('id');
|
|
}
|
|
return $stories;
|
|
}
|
|
|
|
/**
|
|
* 通过搜索查找业务需求。
|
|
* Fetch epics by search.
|
|
*
|
|
* @param string $myEpicQuery
|
|
* @param string $type
|
|
* @param string $orderBy
|
|
* @param object $pager
|
|
* @param array $epicIDList
|
|
* @access protected
|
|
* @return array
|
|
*/
|
|
protected function fetchEpicsBySearch(string $myEpicQuery, string $type, string $orderBy, ?object $pager = null, array $epicIDList = array()): array
|
|
{
|
|
if($type == 'contribute')
|
|
{
|
|
$epics = $this->dao->select("distinct t1.*, IF(t1.`pri` = 0, {$this->config->maxPriValue}, t1.`pri`) as priOrder, t2.name as productTitle")->from(TABLE_STORY)->alias('t1')
|
|
->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t1.product = t2.id')
|
|
->leftJoin(TABLE_STORYREVIEW)->alias('t3')->on('t1.id = t3.story')
|
|
->where($myEpicQuery)
|
|
->andWhere('t1.type')->eq('epic')
|
|
->andWhere('t1.openedBy',1)->eq($this->app->user->account)
|
|
->orWhere('t1.closedBy')->eq($this->app->user->account)
|
|
->orWhere('(t3.reviewer')->eq($this->app->user->account)
|
|
->andWhere('t3.result')->eq('')
|
|
->andWhere('t1.status')->eq('reviewing')
|
|
->markRight(1)
|
|
->orWhere('t1.id')->in($epicIDList)
|
|
->markRight(1)
|
|
->andWhere('t1.deleted')->eq(0)
|
|
->andWhere("FIND_IN_SET('{$this->config->vision}', t1.vision)")
|
|
->orderBy($orderBy)
|
|
->page($pager, 't1.id')
|
|
->fetchAll('id');
|
|
}
|
|
else
|
|
{
|
|
$epics = $this->dao->select("distinct t1.*, IF(t1.`pri` = 0, {$this->config->maxPriValue}, t1.`pri`) as priOrder, t2.name as productTitle")->from(TABLE_STORY)->alias('t1')
|
|
->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t1.product = t2.id')
|
|
->leftJoin(TABLE_STORYREVIEW)->alias('t3')->on('t1.id = t3.story')
|
|
->where($myEpicQuery)
|
|
->andWhere('t1.type')->eq('epic')
|
|
->andWhere('t1.assignedTo',1)->eq($this->app->user->account)
|
|
->orWhere('(t3.reviewer')->eq($this->app->user->account)
|
|
->andWhere('t3.result')->eq('')
|
|
->andWhere('t1.status')->eq('reviewing')
|
|
->markRight(1)
|
|
->markRight(1)
|
|
->andWhere('t1.deleted')->eq(0)
|
|
->andWhere("FIND_IN_SET('{$this->config->vision}', t1.vision)")
|
|
->orderBy($orderBy)
|
|
->page($pager, 't1.id')
|
|
->fetchAll('id');
|
|
}
|
|
return $epics;
|
|
}
|
|
|
|
/**
|
|
* 通过搜索查找用户需求。
|
|
* Fetch requirements by search.
|
|
*
|
|
* @param string $myRequirementQuery
|
|
* @param string $type
|
|
* @param string $orderBy
|
|
* @param object $pager
|
|
* @param array $requirementIDList
|
|
* @access protected
|
|
* @return array
|
|
*/
|
|
protected function fetchRequirementsBySearch(string $myRequirementQuery, string $type, string $orderBy, ?object $pager = null, array $requirementIDList = array()): array
|
|
{
|
|
if($type == 'contribute')
|
|
{
|
|
$requirements = $this->dao->select("distinct t1.*, IF(t1.`pri` = 0, {$this->config->maxPriValue}, t1.`pri`) as priOrder, t2.name as productTitle")->from(TABLE_STORY)->alias('t1')
|
|
->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t1.product = t2.id')
|
|
->leftJoin(TABLE_STORYREVIEW)->alias('t3')->on('t1.id = t3.story')
|
|
->where($myRequirementQuery)
|
|
->andWhere('t1.type')->eq('requirement')
|
|
->andWhere('t1.openedBy',1)->eq($this->app->user->account)
|
|
->orWhere('t1.closedBy')->eq($this->app->user->account)
|
|
->orWhere('t3.reviewer')->eq($this->app->user->account)
|
|
->orWhere('t1.id')->in($requirementIDList)
|
|
->markRight(1)
|
|
->andWhere('t1.deleted')->eq(0)
|
|
->andWhere("FIND_IN_SET('{$this->config->vision}', t1.vision)")
|
|
->orderBy($orderBy)
|
|
->page($pager, 't1.id')
|
|
->fetchAll('id');
|
|
}
|
|
else
|
|
{
|
|
$requirements = $this->dao->select("distinct t1.*, IF(t1.`pri` = 0, {$this->config->maxPriValue}, t1.`pri`) as priOrder, t2.name as productTitle")->from(TABLE_STORY)->alias('t1')
|
|
->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t1.product = t2.id')
|
|
->leftJoin(TABLE_STORYREVIEW)->alias('t3')->on('t1.id = t3.story')
|
|
->where($myRequirementQuery)
|
|
->andWhere('t1.type')->eq('requirement')
|
|
->andWhere('t1.assignedTo',1)->eq($this->app->user->account)
|
|
->orWhere('t3.reviewer')->eq($this->app->user->account)
|
|
->markRight(1)
|
|
->andWhere('t1.deleted')->eq(0)
|
|
->andWhere("FIND_IN_SET('{$this->config->vision}', t1.vision)")
|
|
->orderBy($orderBy)
|
|
->page($pager, 't1.id')
|
|
->fetchAll('id');
|
|
}
|
|
return $requirements;
|
|
}
|
|
|
|
/**
|
|
* 构建待审批的审批数据。
|
|
* Build the data of the approval to be approved.
|
|
*
|
|
* @param array $objectGroup
|
|
* @param array $flows
|
|
* @param array $objectNameFields
|
|
* @access protected
|
|
* @return array
|
|
*/
|
|
protected function buildReviewingFlows(array $objectGroup, array $flows, array $objectNameFields): array
|
|
{
|
|
$approvalList = array();
|
|
foreach($objectGroup as $objectType => $objects)
|
|
{
|
|
$title = '';
|
|
$titleFieldName = zget($objectNameFields, $objectType, '');
|
|
$openedDateField = zget($this->config->my->openedDateField, $objectType, 'openedDate');
|
|
if(empty($titleFieldName) && isset($flows[$objectType]))
|
|
{
|
|
if(!empty($flows[$objectType]->titleField)) $titleFieldName = $flows[$objectType]->titleField;
|
|
if(empty($flows[$objectType]->titleField)) $title = $flows[$objectType]->name;
|
|
$openedDateField = 'createdDate';
|
|
}
|
|
|
|
foreach($objects as $object)
|
|
{
|
|
$data = new stdclass();
|
|
$data->id = $object->id;
|
|
$data->title = empty($titleFieldName) || !isset($object->$titleFieldName) ? $title . " #{$object->id}" : $object->{$titleFieldName};
|
|
$data->type = $objectType;
|
|
$data->time = $object->{$openedDateField};
|
|
$data->status = $objectType == 'charter' ? $object->reviewStatus : 'doing';
|
|
$data->app = isset($flows[$objectType]->app) ? $flows[$objectType]->app : zget($this->lang->navGroup, $objectType, '');
|
|
$data->product = isset($object->product) ? $object->product : 0;
|
|
$data->project = isset($object->project) ? $object->project : 0;
|
|
$approvalList[] = $data;
|
|
}
|
|
}
|
|
return $approvalList;
|
|
}
|
|
}
|