tao.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. <?php
  2. /**
  3. * The tao file of my module of ZenTaoPMS.
  4. *
  5. * @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
  6. * @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
  7. * @author Mengyi Liu <liumengyi@easycorp.ltd>
  8. * @package my
  9. * @link https://www.zentao.net
  10. */
  11. class myTao extends myModel
  12. {
  13. /**
  14. * 获取产品相关的由我指派的数据。
  15. * Get the data related to the product assigned by me.
  16. *
  17. * @param array $objectIdList
  18. * @param string $objectType
  19. * @param string $orderBy
  20. * @param object $pager
  21. * @access protected
  22. * @return array
  23. * @param string $module
  24. */
  25. protected function getProductRelatedAssignedByMe($objectIdList, $objectType, $module, $orderBy, $pager = null)
  26. {
  27. $nameField = $objectType == 'bug' ? 'productName' : 'productTitle';
  28. $orderBy = strpos($orderBy, 'priOrder') !== false || strpos($orderBy, 'severityOrder') !== false || strpos($orderBy, $nameField) !== false ? $orderBy : "t1.{$orderBy}";
  29. $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");
  30. $objectList = $this->dao->select($select)->from($this->config->objectTables[$module])->alias('t1')
  31. ->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t1.product = t2.id')
  32. ->where('t1.deleted')->eq(0)
  33. ->andWhere('t2.deleted')->eq(0)
  34. ->andWhere('t1.id')->in($objectIdList)
  35. ->beginIF($module == 'story')->andWhere('t1.type')->eq($objectType)->fi()
  36. ->beginIF($module == 'story')->andWhere("FIND_IN_SET('{$this->config->vision}', t1.vision)")->fi()
  37. ->orderBy($orderBy)
  38. ->page($pager)
  39. ->fetchAll('id', false);
  40. if($module == 'story')
  41. {
  42. $planList = array();
  43. foreach($objectList as $story) $planList[$story->plan] = $story->plan;
  44. $planPairs = $this->dao->select('id,title')->from(TABLE_PRODUCTPLAN)->where('id')->in($planList)->fetchPairs('id');
  45. foreach($objectList as $story) $story->planTitle = zget($planPairs, $story->plan, '');
  46. }
  47. return $objectList;
  48. }
  49. /**
  50. * 通过搜索查找任务。
  51. * Fetch tasks by search.
  52. *
  53. * @param string $query
  54. * @param string $moduleName
  55. * @param string $account
  56. * @param array $taskIdList
  57. * @param string $orderBy
  58. * @param int $limit
  59. * @param object $pager
  60. * @access protected
  61. * @return array
  62. */
  63. protected function fetchTasksBySearch($query, $moduleName, $account, $taskIdList, $orderBy, $limit, $pager = null)
  64. {
  65. $query = preg_replace('/`(\w+)`/', 't1.`$1`', $query);
  66. $query = str_replace('t1.`project`', 't2.`project`', $query);
  67. $assignedToMatches = array();
  68. $assignedToCondition = '';
  69. $operatorAndAccount = '';
  70. if(strpos($query, '`assignedTo`') !== false)
  71. {
  72. preg_match("/`assignedTo`\s+(([^']*) ('([^']*)'))/", $query, $assignedToMatches);
  73. if(!empty($assignedToMatches))
  74. {
  75. $assignedToCondition = $assignedToMatches[0];
  76. $operatorAndAccount = $assignedToMatches[1];
  77. $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);
  78. }
  79. }
  80. if(strpos($query, "t2.`project` = 'all'") !== false) $query = str_replace("t2.`project` = 'all'", "t2.`project` != '0'", $query);
  81. if(strpos($query, "t2.`project` != 'all'") !== false) $query = str_replace("t2.`project` != 'all'", "t2.`project` = '0'", $query);
  82. if(strpos($query, "t1.`execution` = 'all'") !== false) $query = str_replace("t1.`execution` = 'all'", "t1.`execution` != '0'", $query);
  83. $orderBy = str_replace('pri_', 'priOrder_', $orderBy);
  84. 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")
  85. ->from(TABLE_TASK)->alias('t1')
  86. ->leftJoin(TABLE_EXECUTION)->alias('t2')->on("t1.execution = t2.id")
  87. ->leftJoin(TABLE_STORY)->alias('t3')->on('t1.story = t3.id')
  88. ->leftJoin(TABLE_PROJECT)->alias('t4')->on("t2.project = t4.id")
  89. ->leftJoin(TABLE_TASKTEAM)->alias('t5')->on("t1.id = t5.task")
  90. ->where($query)
  91. ->andWhere('t1.deleted')->eq(0)
  92. ->andWhere('t2.deleted')->eq(0)
  93. ->andWhere('(t2.status')->ne('suspended')->orWhere('t4.status')->ne('suspended')->markRight(1)
  94. ->beginIF($moduleName == 'workTask')
  95. ->beginIF(!empty($assignedToMatches))->andWhere("(t1.{$assignedToCondition} or (t1.mode = 'multi' and t5.`account` {$operatorAndAccount} and t1.status != 'closed' and t5.status != 'done') )")->fi()
  96. ->beginIF(empty($assignedToMatches))->andWhere("(t1.assignedTo = '{$account}' or (t1.mode = 'multi' and t5.`account` = '{$account}' and t1.status != 'closed' and t5.status != 'done') )")->fi()
  97. ->andWhere('t1.status')->notin('closed,cancel')
  98. ->fi()
  99. ->beginIF($moduleName == 'contributeTask')
  100. ->andWhere('t1.openedBy', 1)->eq($account)
  101. ->orWhere('t1.closedBy')->eq($account)
  102. ->orWhere('t1.canceledBy')->eq($account)
  103. ->orWhere('t1.finishedby')->eq($account)
  104. ->orWhere('t1.assignedTo')->eq($account)
  105. ->orWhere('t5.account')->eq($account)
  106. ->orWhere('t1.id')->in($taskIdList)
  107. ->markRight(1)
  108. ->fi()
  109. ->beginIF($this->config->vision)->andWhere('t1.vision')->eq($this->config->vision)->fi()
  110. ->beginIF($this->config->vision)->andWhere('t2.vision')->eq($this->config->vision)->fi()
  111. ->beginIF(!$this->app->user->admin)->andWhere('t1.execution')->in($this->app->user->view->sprints)->fi()
  112. ->orderBy($orderBy)
  113. ->beginIF($limit > 0)->limit($limit)->fi()
  114. ->page($pager, 't1.id')
  115. ->fetchAll('id');
  116. }
  117. /**
  118. * 通过搜索查找需求。
  119. * Fetch stories by search.
  120. *
  121. * @param string $myStoryQuery
  122. * @param string $type
  123. * @param string $orderBy
  124. * @param object $pager
  125. * @param array $storiesAssignedByMe
  126. * @access protected
  127. * @return array
  128. */
  129. protected function fetchStoriesBySearch($myStoryQuery, $type, $orderBy, $pager = null, $storiesAssignedByMe = array())
  130. {
  131. if($type == 'contribute')
  132. {
  133. $storyIdList = !empty($storiesAssignedByMe) ? array_keys($storiesAssignedByMe) : array();
  134. $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')
  135. ->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t1.product = t2.id')
  136. ->leftJoin(TABLE_PLANSTORY)->alias('t3')->on('t1.id = t3.plan')
  137. ->leftJoin(TABLE_PRODUCTPLAN)->alias('t4')->on('t3.plan = t4.id')
  138. ->leftJoin(TABLE_STORYREVIEW)->alias('t5')->on('t1.id = t5.story')
  139. ->where($myStoryQuery)
  140. ->andWhere('t1.type')->eq('story')
  141. ->andWhere('t1.openedBy',1)->eq($this->app->user->account)
  142. ->orWhere('t5.reviewer')->eq($this->app->user->account)
  143. ->orWhere('t1.closedBy')->eq($this->app->user->account)
  144. ->orWhere('t1.id')->in($storyIdList)
  145. ->markRight(1)
  146. ->andWhere('t1.deleted')->eq(0)
  147. ->orderBy($orderBy)
  148. ->page($pager, 't1.id')
  149. ->fetchAll('id');
  150. }
  151. else
  152. {
  153. $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')
  154. ->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t1.product = t2.id')
  155. ->leftJoin(TABLE_PLANSTORY)->alias('t3')->on('t1.id = t3.plan')
  156. ->leftJoin(TABLE_PRODUCTPLAN)->alias('t4')->on('t3.plan = t4.id')
  157. ->leftJoin(TABLE_STORYREVIEW)->alias('t5')->on('t1.id = t5.story AND t1.version=t5.version')
  158. ->where($myStoryQuery)
  159. ->andWhere('t1.type')->eq('story')
  160. ->andWhere('t1.assignedTo',1)->eq($this->app->user->account)
  161. ->orWhere("(t5.reviewer = '{$this->app->user->account}' AND t5.result = '' AND t1.status = 'reviewing')")
  162. ->markRight(1)
  163. ->andWhere('t1.product')->ne('0')
  164. ->andWhere('t1.deleted')->eq(0)
  165. ->orderBy($orderBy)
  166. ->page($pager, 't1.id')
  167. ->fetchAll('id');
  168. }
  169. return $stories;
  170. }
  171. /**
  172. * 通过搜索查找业务需求。
  173. * Fetch epics by search.
  174. *
  175. * @param string $myEpicQuery
  176. * @param string $type
  177. * @param string $orderBy
  178. * @param object $pager
  179. * @param array $epicIDList
  180. * @access protected
  181. * @return array
  182. */
  183. protected function fetchEpicsBySearch($myEpicQuery, $type, $orderBy, $pager = null, $epicIDList = array())
  184. {
  185. if($type == 'contribute')
  186. {
  187. $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')
  188. ->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t1.product = t2.id')
  189. ->leftJoin(TABLE_STORYREVIEW)->alias('t3')->on('t1.id = t3.story')
  190. ->where($myEpicQuery)
  191. ->andWhere('t1.type')->eq('epic')
  192. ->andWhere('t1.openedBy',1)->eq($this->app->user->account)
  193. ->orWhere('t1.closedBy')->eq($this->app->user->account)
  194. ->orWhere('(t3.reviewer')->eq($this->app->user->account)
  195. ->andWhere('t3.result')->eq('')
  196. ->andWhere('t1.status')->eq('reviewing')
  197. ->markRight(1)
  198. ->orWhere('t1.id')->in($epicIDList)
  199. ->markRight(1)
  200. ->andWhere('t1.deleted')->eq(0)
  201. ->andWhere("FIND_IN_SET('{$this->config->vision}', t1.vision)")
  202. ->orderBy($orderBy)
  203. ->page($pager, 't1.id')
  204. ->fetchAll('id');
  205. }
  206. else
  207. {
  208. $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')
  209. ->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t1.product = t2.id')
  210. ->leftJoin(TABLE_STORYREVIEW)->alias('t3')->on('t1.id = t3.story')
  211. ->where($myEpicQuery)
  212. ->andWhere('t1.type')->eq('epic')
  213. ->andWhere('t1.assignedTo',1)->eq($this->app->user->account)
  214. ->orWhere('(t3.reviewer')->eq($this->app->user->account)
  215. ->andWhere('t3.result')->eq('')
  216. ->andWhere('t1.status')->eq('reviewing')
  217. ->markRight(1)
  218. ->markRight(1)
  219. ->andWhere('t1.deleted')->eq(0)
  220. ->andWhere("FIND_IN_SET('{$this->config->vision}', t1.vision)")
  221. ->orderBy($orderBy)
  222. ->page($pager, 't1.id')
  223. ->fetchAll('id');
  224. }
  225. return $epics;
  226. }
  227. /**
  228. * 通过搜索查找用户需求。
  229. * Fetch requirements by search.
  230. *
  231. * @param string $myRequirementQuery
  232. * @param string $type
  233. * @param string $orderBy
  234. * @param object $pager
  235. * @param array $requirementIDList
  236. * @access protected
  237. * @return array
  238. */
  239. protected function fetchRequirementsBySearch($myRequirementQuery, $type, $orderBy, $pager = null, $requirementIDList = array())
  240. {
  241. if($type == 'contribute')
  242. {
  243. $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')
  244. ->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t1.product = t2.id')
  245. ->leftJoin(TABLE_STORYREVIEW)->alias('t3')->on('t1.id = t3.story')
  246. ->where($myRequirementQuery)
  247. ->andWhere('t1.type')->eq('requirement')
  248. ->andWhere('t1.openedBy',1)->eq($this->app->user->account)
  249. ->orWhere('t1.closedBy')->eq($this->app->user->account)
  250. ->orWhere('t3.reviewer')->eq($this->app->user->account)
  251. ->orWhere('t1.id')->in($requirementIDList)
  252. ->markRight(1)
  253. ->andWhere('t1.deleted')->eq(0)
  254. ->andWhere("FIND_IN_SET('{$this->config->vision}', t1.vision)")
  255. ->orderBy($orderBy)
  256. ->page($pager, 't1.id')
  257. ->fetchAll('id');
  258. }
  259. else
  260. {
  261. $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')
  262. ->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t1.product = t2.id')
  263. ->leftJoin(TABLE_STORYREVIEW)->alias('t3')->on('t1.id = t3.story')
  264. ->where($myRequirementQuery)
  265. ->andWhere('t1.type')->eq('requirement')
  266. ->andWhere('t1.assignedTo',1)->eq($this->app->user->account)
  267. ->orWhere('t3.reviewer')->eq($this->app->user->account)
  268. ->markRight(1)
  269. ->andWhere('t1.deleted')->eq(0)
  270. ->andWhere("FIND_IN_SET('{$this->config->vision}', t1.vision)")
  271. ->orderBy($orderBy)
  272. ->page($pager, 't1.id')
  273. ->fetchAll('id');
  274. }
  275. return $requirements;
  276. }
  277. /**
  278. * 构建待审批的审批数据。
  279. * Build the data of the approval to be approved.
  280. *
  281. * @param array $objectGroup
  282. * @param array $flows
  283. * @param array $objectNameFields
  284. * @access protected
  285. * @return array
  286. */
  287. protected function buildReviewingFlows($objectGroup, $flows, $objectNameFields)
  288. {
  289. $approvalList = array();
  290. foreach($objectGroup as $objectType => $objects)
  291. {
  292. $title = '';
  293. $titleFieldName = zget($objectNameFields, $objectType, '');
  294. $openedDateField = zget($this->config->my->openedDateField, $objectType, 'openedDate');
  295. if(empty($titleFieldName) && isset($flows[$objectType]))
  296. {
  297. if(!empty($flows[$objectType]->titleField)) $titleFieldName = $flows[$objectType]->titleField;
  298. if(empty($flows[$objectType]->titleField)) $title = $flows[$objectType]->name;
  299. $openedDateField = 'createdDate';
  300. }
  301. foreach($objects as $object)
  302. {
  303. $data = new stdclass();
  304. $data->id = $object->id;
  305. $data->title = empty($titleFieldName) || !isset($object->$titleFieldName) ? $title . " #{$object->id}" : $object->{$titleFieldName};
  306. $data->type = $objectType;
  307. $data->time = $object->{$openedDateField};
  308. $data->status = $objectType == 'charter' ? $object->reviewStatus : 'doing';
  309. $data->app = isset($flows[$objectType]->app) ? $flows[$objectType]->app : zget($this->lang->navGroup, $objectType, '');
  310. $data->product = isset($object->product) ? $object->product : 0;
  311. $data->project = isset($object->project) ? $object->project : 0;
  312. $approvalList[] = $data;
  313. }
  314. }
  315. return $approvalList;
  316. }
  317. }