tao.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. <?php
  2. /**
  3. * The tao file of report 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 report
  9. * @link https://www.zentao.net
  10. */
  11. class reportTao extends reportModel
  12. {
  13. /**
  14. * 获取某年的年度产品数据。
  15. * Get annual product stat.
  16. *
  17. * @param array $accounts
  18. * @param string $year
  19. * @access public
  20. * @return array
  21. */
  22. protected function getAnnualProductStat($accounts, $year)
  23. {
  24. /* Get created plans, created stories and closed stories in this year. */
  25. $planGroups = $this->dao->select('t1.id,t1.product')->from(TABLE_PRODUCTPLAN)->alias('t1')
  26. ->leftJoin(TABLE_ACTION)->alias('t2')->on("t1.id=t2.objectID and t2.objectType='productplan'")
  27. ->where('t1.deleted')->eq(0)
  28. ->andWhere('LEFT(t2.date, 4)')->eq($year)
  29. ->beginIF($accounts)->andWhere('t2.actor')->in($accounts)->fi()
  30. ->andWhere('t2.action')->eq('opened')
  31. ->fetchGroup('product', 'id');
  32. $createdStoryStats = $this->dao->select("product,sum(if((type = 'requirement'), 1, 0)) as requirement, sum(if((type = 'story'), 1, 0)) as story, sum(if((type = 'epic'), 1, 0)) as epic")->from(TABLE_STORY)
  33. ->where('deleted')->eq(0)
  34. ->andWhere('LEFT(openedDate, 4)')->eq($year)
  35. ->beginIF($accounts)->andWhere('openedBy')->in($accounts)->fi()
  36. ->groupBy('product')
  37. ->fetchAll('product');
  38. $closedStoryStats = $this->dao->select("product,sum(if((status = 'closed'), 1, 0)) as closed")->from(TABLE_STORY)
  39. ->where('deleted')->eq(0)
  40. ->andWhere('LEFT(closedDate, 4)')->eq($year)
  41. ->beginIF($accounts)->andWhere('closedBy')->in($accounts)->fi()
  42. ->groupBy('product')
  43. ->fetchAll('product');
  44. /* Get products created or operated in this year. */
  45. $products = $this->dao->select('id,name')->from(TABLE_PRODUCT)
  46. ->where('deleted')->eq(0)
  47. ->andWhere('LEFT(createdDate, 4)', true)->eq($year)
  48. ->beginIF($accounts)
  49. ->andWhere('createdBy', true)->in($accounts)
  50. ->orWhere('PO')->in($accounts)
  51. ->orWhere('QD')->in($accounts)
  52. ->orWhere('RD')->in($accounts)
  53. ->markRight(1)
  54. ->fi()
  55. ->orWhere('id')->in(array_merge(array_keys($planGroups), array_keys($createdStoryStats), array_keys($closedStoryStats)))
  56. ->markRight(1)
  57. ->andWhere('shadow')->eq(0)
  58. ->fetchAll('id');
  59. return array($products, $planGroups, $createdStoryStats, $closedStoryStats);
  60. }
  61. /**
  62. * 获取某年的年度执行数据。
  63. * Get annual execution stat.
  64. *
  65. * @param array $accounts
  66. * @param string $year
  67. * @access public
  68. * @return array
  69. */
  70. protected function getAnnualExecutionStat($accounts, $year)
  71. {
  72. /* Get count of finished task and stories. */
  73. $finishedMultiTasks = $this->dao->select('distinct t1.root')->from(TABLE_TEAM)->alias('t1')
  74. ->leftJoin(TABLE_EXECUTION)->alias('t2')->on('t1.root=t2.id')
  75. ->where('t1.type')->eq('execution')
  76. ->beginIF($accounts)->andWhere('account')->in($accounts)->fi()
  77. ->andWhere('t2.multiple')->eq('1')
  78. ->andWhere('LEFT(`join`, 4)')->eq($year)
  79. ->fetchPairs();
  80. $taskStats = $this->dao->select('execution, COUNT(1) AS finishedTask')->from(TABLE_TASK)
  81. ->where('deleted')->eq(0)
  82. ->andWhere('(finishedBy', true)->ne('')
  83. ->andWhere('LEFT(finishedDate, 4)')->eq($year)
  84. ->beginIF($accounts)->andWhere('finishedBy')->in($accounts)->fi()
  85. ->markRight(1)
  86. ->orWhere('id')->in($finishedMultiTasks)
  87. ->markRight(1)
  88. ->groupBy('execution')
  89. ->fetchAll('execution');
  90. $finishedTask = array();
  91. if(!empty($taskStats)) foreach($taskStats as $executionID => $taskStat) $finishedTask[$executionID] = $taskStat->finishedTask;
  92. /* Get changed executions in this year. */
  93. $executions = $this->dao->select('id,name')->from(TABLE_EXECUTION)->where('deleted')->eq(0)
  94. ->andwhere('type')->eq('sprint')
  95. ->andwhere('multiple')->eq('1')
  96. ->andWhere('LEFT(`begin`, 4)', true)->eq($year)
  97. ->orWhere('LEFT(`end`, 4)')->eq($year)
  98. ->markRight(1)
  99. ->beginIF($accounts)
  100. ->andWhere('openedBy', true)->in($accounts)
  101. ->orWhere('PO')->in($accounts)
  102. ->orWhere('PM')->in($accounts)
  103. ->orWhere('QD')->in($accounts)
  104. ->orWhere('RD')->in($accounts)
  105. ->orWhere('id')->in(array_keys($taskStats))
  106. ->markRight(1)
  107. ->fi()
  108. ->orderBy('`order` desc')
  109. ->fetchAll('id');
  110. $finishedStory = $this->dao->select('t1.project, COUNT(1) as count')->from(TABLE_PROJECTSTORY)->alias('t1')
  111. ->leftJoin(TABLE_STORY)->alias('t2')->on('t1.story = t2.id')
  112. ->where('t1.project')->in(array_keys($executions))
  113. ->andWhere('t2.stage', true)->in(array('verified', 'released'))
  114. ->orWhere('t2.closedReason')->eq('done')
  115. ->markRight(1)
  116. ->groupBy('t1.project')
  117. ->fetchPairs();
  118. /* Get resolved bugs in this year. */
  119. $resolvedBugs = $this->dao->select('execution, COUNT(1) AS count')->from(TABLE_BUG)
  120. ->where('deleted')->eq(0)
  121. ->andWhere('status')->eq('closed')
  122. ->andWhere('resolution')->eq('fixed')
  123. ->andWhere('execution')->in(array_keys($executions))
  124. ->andWhere('LEFT(resolvedDate, 4)')->eq($year)
  125. ->beginIF($accounts)->andWhere('resolvedBy')->in($accounts)->fi()
  126. ->groupBy('execution')
  127. ->fetchPairs();
  128. return array($executions, $finishedTask, $finishedStory, $resolvedBugs);
  129. }
  130. /**
  131. * 构建年度报告的用例数据。
  132. * Build annual case stat.
  133. *
  134. * @param array $accounts
  135. * @param string $year
  136. * @param array $actionStat
  137. * @param array $resultStat
  138. * @access protected
  139. * @return array
  140. */
  141. protected function buildAnnualCaseStat($accounts, $year, $actionStat, $resultStat)
  142. {
  143. /* Build create case stat. */
  144. $stmt = $this->dao->select('t1.*')->from(TABLE_ACTION)->alias('t1')
  145. ->leftJoin(TABLE_CASE)->alias('t2')->on('t1.objectID=t2.id')
  146. ->where('t1.objectType')->eq('case')
  147. ->andWhere('t2.deleted')->eq(0)
  148. ->andWhere('t1.action')->eq('opened')
  149. ->andWhere('LEFT(t1.date, 4)')->eq($year)
  150. ->beginIF($accounts)->andWhere('t1.actor')->in($accounts)->fi()
  151. ->query();
  152. while($action = $stmt->fetch())
  153. {
  154. $month = substr($action->date, 0, 7);
  155. $actionStat['opened'][$month] += 1;
  156. }
  157. /* Build testcase result stat and run case stat. */
  158. $stmt = $this->dao->select('*')->from(TABLE_CASE)
  159. ->where('LEFT(lastRunDate, 4)')->eq($year)
  160. ->andWhere('deleted')->eq('0')
  161. ->beginIF($accounts)->andWhere('lastRunner')->in($accounts)->fi()
  162. ->query();
  163. while($testResult = $stmt->fetch())
  164. {
  165. if(!isset($resultStat[$testResult->lastRunResult])) $resultStat[$testResult->lastRunResult] = 0;
  166. $resultStat[$testResult->lastRunResult] += 1;
  167. $month = substr($testResult->lastRunDate, 0, 7);
  168. $actionStat['run'][$month] += 1;
  169. }
  170. /* Build testcase create bug stat. */
  171. $stmt = $this->dao->select('t1.*')->from(TABLE_ACTION)->alias('t1')
  172. ->leftJoin(TABLE_BUG)->alias('t2')->on('t1.objectID=t2.id')
  173. ->where('t1.objectType')->eq('bug')
  174. ->andWhere('t2.deleted')->eq(0)
  175. ->andWhere('LEFT(t1.date, 4)')->eq($year)
  176. ->andWhere('t1.action')->eq('opened')
  177. ->andWhere('t2.case')->ne('0')
  178. ->beginIF($accounts)->andWhere('t1.actor')->in($accounts)->fi()
  179. ->query();
  180. while($action = $stmt->fetch())
  181. {
  182. $month = substr($action->date, 0, 7);
  183. $actionStat['createBug'][$month] += 1;
  184. }
  185. return array('resultStat' => $resultStat, 'actionStat' => $actionStat);
  186. }
  187. /**
  188. * 获取要输出的数据。
  189. * Get output data.
  190. *
  191. * @param array $accounts
  192. * @param string $year
  193. * @access protected
  194. * @return array
  195. */
  196. protected function getOutputData($accounts, $year)
  197. {
  198. /* Get output actions. */
  199. $outputData = $actionGroup = $objectIdList = array();
  200. $stmt = $this->dao->select('id,objectType,objectID,action,extra')->from(TABLE_ACTION)
  201. ->where('objectType')->in(array_keys($this->config->report->outputData))
  202. ->andWhere('LEFT(date, 4)')->eq($year)
  203. ->beginIF($accounts)->andWhere('actor')->in($accounts)->fi()
  204. ->query();
  205. while($action = $stmt->fetch())
  206. {
  207. if($action->objectType == 'release' && $action->action == 'changestatus')
  208. {
  209. if($action->extra == 'terminate') $action->action = 'stoped';
  210. if($action->extra == 'normal') $action->action = 'activated';
  211. }
  212. unset($action->extra);
  213. if(!isset($this->config->report->outputData[$action->objectType][$action->action])) continue;
  214. if(!isset($outputData[$action->objectType][$action->action])) $outputData[$action->objectType][$action->action] = 0;
  215. $objectIdList[$action->objectType][$action->objectID] = $action->objectID;
  216. $actionGroup[$action->objectType][$action->id] = $action;
  217. }
  218. foreach($actionGroup as $objectType => $actions)
  219. {
  220. $deletedIdList = $this->dao->select('id')->from($this->config->objectTables[$objectType])->where('deleted')->eq(1)->andWhere('id')->in($objectIdList[$objectType])->fetchPairs('id', 'id');
  221. foreach($actions as $action)
  222. {
  223. if(!isset($deletedIdList[$action->objectID])) $outputData[$action->objectType][$action->action] += 1;
  224. }
  225. }
  226. /* Get output case data. */
  227. $outputData['case']['createBug'] = $this->dao->select('count(t2.id) as count')->from(TABLE_ACTION)->alias('t1')
  228. ->leftJoin(TABLE_BUG)->alias('t2')->on('t1.objectID=t2.id')
  229. ->where('t1.objectType')->eq('bug')
  230. ->andWhere('t2.deleted')->eq(0)
  231. ->andWhere('LEFT(t1.date, 4)')->eq($year)
  232. ->andWhere('t1.action')->eq('opened')
  233. ->andWhere('t2.case')->ne('0')
  234. ->beginIF($accounts)->andWhere('t1.actor')->in($accounts)->fi()
  235. ->fetch('count');
  236. $outputData['case']['run'] = $this->dao->select('COUNT(1) AS count')->from(TABLE_TESTRESULT)->alias('t1')
  237. ->leftJoin(TABLE_CASE)->alias('t2')->on('t1.case=t2.id')
  238. ->where('LEFT(t1.date, 4)')->eq($year)
  239. ->andWhere('t2.deleted')->eq(0)
  240. ->beginIF($accounts)->andWhere('t1.lastRunner')->in($accounts)->fi()
  241. ->fetch('count');
  242. return $outputData;
  243. }
  244. }