tao.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. <?php
  2. /**
  3. * The tao file of todo 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 lanzongjun <lanzongjun@easycorp.ltd>
  8. * @link https://www.zentao.net
  9. */
  10. class todoTao extends todoModel
  11. {
  12. /**
  13. * 获取单条待办。
  14. * Get a todo.
  15. *
  16. * @param int $todoID
  17. * @access protected
  18. * @return object
  19. */
  20. protected function fetch($todoID)
  21. {
  22. return $this->dao->select('*')->from(TABLE_TODO)->where('id')->eq($todoID)->fetch();
  23. }
  24. /**
  25. * 获取一个或多个待办。
  26. * Get a or more todo.
  27. *
  28. * @param array $todoIdList
  29. * @access protected
  30. * @return array
  31. */
  32. protected function fetchRows($todoIdList)
  33. {
  34. return $this->dao->select('*')->from(TABLE_TODO)->where('id')->in(array_keys($todoIdList))->fetchAll('id');
  35. }
  36. /**
  37. * 获取待办数量。
  38. * Get todo count.
  39. *
  40. * @param string $account
  41. * @param string $vision
  42. * @access protected
  43. * @return int
  44. */
  45. protected function getCountByAccount($account, $vision = 'rnd')
  46. {
  47. return $this->dao->select('COUNT(1) AS count')->from(TABLE_TODO)
  48. ->where('cycle')->eq('0')
  49. ->andWhere('deleted')->eq('0')
  50. ->andWhere('vision')->eq($vision)
  51. ->andWhere('account', true)->eq($account)
  52. ->orWhere('assignedTo')->eq($account)
  53. ->orWhere('finishedBy')->eq($account)
  54. ->markRight(1)
  55. ->fetch('count');
  56. }
  57. /**
  58. * 获取各模块project列表。
  59. * Get project list.
  60. *
  61. * @param string $table
  62. * @param array $idList
  63. * @access protected
  64. * @return array
  65. */
  66. protected function getProjectList($table, $idList)
  67. {
  68. return $this->dao->select('id,project')->from($table)->where('id')->in($idList)->fetchPairs('id', 'project');
  69. }
  70. /**
  71. * 插入待办数据。
  72. * Insert todo data.
  73. *
  74. * @param object $todo
  75. * @access protected
  76. * @return int
  77. */
  78. protected function insert($todo)
  79. {
  80. $isModuleType = isset($todo->type) && in_array($todo->type, $this->config->todo->moduleList);
  81. $this->dao->insert(TABLE_TODO)->data($todo)
  82. ->autoCheck()
  83. ->check($this->config->todo->create->requiredFields, 'notempty')
  84. ->checkIF($isModuleType, 'objectID', 'notempty')
  85. ->exec();
  86. if(dao::isError() && $isModuleType)
  87. {
  88. $errors = dao::getError();
  89. if(isset($errors['name']) && isset($errors['objectID']))
  90. {
  91. dao::$errors[$todo->type] = $errors['name'];
  92. }
  93. else
  94. {
  95. dao::$errors = $errors;
  96. }
  97. }
  98. return (int)$this->dao->lastInsertID();
  99. }
  100. /**
  101. * 更新待办数据。
  102. * Update todo data.
  103. *
  104. * @param int $todoID
  105. * @param object $todo
  106. * @access protected
  107. * @return bool
  108. */
  109. protected function updateRow($todoID, $todo)
  110. {
  111. $requiredFields = isset($todo->type) && in_array($todo->type, $this->config->todo->moduleList) ? str_replace(',name,', ',objectID,', ",{$this->config->todo->edit->requiredFields},") : $this->config->todo->edit->requiredFields;
  112. $this->dao->update(TABLE_TODO)->data($todo)
  113. ->autoCheck()
  114. ->checkIF($requiredFields, $requiredFields, 'notempty')
  115. ->where('id')->eq($todoID)
  116. ->exec();
  117. return !dao::isError();
  118. }
  119. /**
  120. * 关闭一个待办。
  121. * Close one todo.
  122. *
  123. * @param int $todoID
  124. * @access protected
  125. * @return bool
  126. */
  127. protected function closeTodo($todoID)
  128. {
  129. $now = helper::now();
  130. $this->dao->update(TABLE_TODO)
  131. ->set('status')->eq('closed')
  132. ->set('closedBy')->eq($this->app->user->account)
  133. ->set('closedDate')->eq($now)
  134. ->set('assignedTo')->eq('closed')
  135. ->set('assignedDate')->eq($now)
  136. ->where('id')->eq($todoID)
  137. ->exec();
  138. return !dao::isError();
  139. }
  140. /**
  141. * 获取周期待办列表。
  142. * Get cycle list.
  143. *
  144. * @param array $todoList
  145. * @param string $orderBy
  146. * @access protected
  147. * @return array
  148. */
  149. protected function getCycleList($todoList, $orderBy = 'date_asc')
  150. {
  151. if(empty($todoList)) return [];
  152. return $this->dao->select('*')->from(TABLE_TODO)
  153. ->where('type')->eq('custom')
  154. ->andWhere('deleted')->eq('0')
  155. ->andWhere('objectID')->in(array_keys($todoList))
  156. ->orderBy($orderBy)
  157. ->fetchAll('objectID');
  158. }
  159. /**
  160. * 通过待办构建周期待办数据。
  161. * Build cycle todo.
  162. *
  163. * @param object $todo
  164. * @access protected
  165. * @return object
  166. */
  167. protected function buildCycleTodo($todo)
  168. {
  169. $newTodo = new stdclass();
  170. $newTodo->account = $todo->account;
  171. $newTodo->begin = $todo->begin;
  172. $newTodo->end = $todo->end;
  173. $newTodo->type = 'custom';
  174. $newTodo->objectID = $todo->id;
  175. $newTodo->pri = $todo->pri;
  176. $newTodo->name = $todo->name;
  177. $newTodo->desc = $todo->desc;
  178. $newTodo->status = 'wait';
  179. $newTodo->private = $todo->private;
  180. $newTodo->assignedTo = $todo->assignedTo;
  181. $newTodo->assignedBy = $todo->assignedBy ;
  182. return $newTodo;
  183. }
  184. /**
  185. * 通过周期待办,获取要生成待办的日期。
  186. * Gets the date by the cycle todo.
  187. *
  188. * @param object $todo
  189. * @param object|string $lastCycle
  190. * @param string $today
  191. * @access protected
  192. * @return false|string
  193. */
  194. protected function getCycleTodoDate($todo, $lastCycle, $today)
  195. {
  196. $date = '';
  197. if($todo->config->type == 'day')
  198. {
  199. return $this->getCycleDailyTodoDate($todo, $lastCycle, $today);
  200. }
  201. elseif($todo->config->type == 'week')
  202. {
  203. $week = date('w', strtotime($today));
  204. if(strpos(",{$todo->config->week},", ",{$week},") !== false)
  205. {
  206. if(empty($lastCycle)) $date = $today;
  207. if($lastCycle && $lastCycle->date < $today) $date = $today;
  208. }
  209. }
  210. elseif($todo->config->type == 'month')
  211. {
  212. $day = date('j', strtotime($today));
  213. if(strpos(",{$todo->config->month},", ",{$day},") !== false)
  214. {
  215. if(empty($lastCycle)) $date = $today;
  216. if($lastCycle && $lastCycle->date < $today) $date = $today;
  217. }
  218. }
  219. return $date;
  220. }
  221. /**
  222. * 获取批量创建待办的有效数据。
  223. * Get valid todos of batch create.
  224. *
  225. * @param object $todos
  226. * @param int $loop
  227. * @param string $assignedTo
  228. * @access protected
  229. * @return object
  230. */
  231. protected function getValidsOfBatchCreate($todos, $loop , $assignedTo)
  232. {
  233. $todo = new stdclass();
  234. $todo->account = $this->app->user->account;
  235. $todo->date = $todos->date[$loop];
  236. $todo->type = $todos->type[$loop];
  237. $todo->pri = $todos->pri[$loop];
  238. $todo->name = isset($todos->name[$loop]) ? $todos->name[$loop] : '';
  239. $todo->desc = $todos->desc[$loop];
  240. $todo->begin = !empty($todos->begin[$loop]) ? $todos->begin[$loop] : 2400;
  241. $todo->end = !empty($todos->end[$loop]) ? $todos->end[$loop] : 2400;
  242. $todo->status = 'wait';
  243. $todo->private = 0;
  244. $todo->objectID = 0;
  245. $todo->assignedTo = $assignedTo;
  246. $todo->assignedBy = $this->app->user->account;
  247. $todo->assignedDate = helper::now();
  248. $todo->vision = $this->config->vision;
  249. if(in_array($todo->type, $this->config->todo->moduleList))
  250. {
  251. $todo->objectID = isset($todos->{$this->config->todo->objectList[$todo->type]}[$loop + 1]) ? $todos->{$this->config->todo->objectList[$todo->type]}[$loop + 1] : 0;
  252. }
  253. if($todo->type != 'custom' && $todo->objectID)
  254. {
  255. $type = $todo->type;
  256. $object = $this->loadModel($type)->getByID($todo->objectID);
  257. if(isset($object->name)) $todo->name = $object->name;
  258. if(isset($object->title)) $todo->name = $object->title;
  259. }
  260. if($todo->end < $todo->begin) dao::$errors["end[$loop]"] = sprintf($this->lang->error->gt, $this->lang->todo->end, $this->lang->todo->begin);
  261. return $todo;
  262. }
  263. /**
  264. * 通过周期待办,获取要生成每日待办的日期。
  265. * Gets the daily todo date by the cycle todo.
  266. *
  267. * @param object $todo
  268. * @param object|string $lastCycle
  269. * @param string $today
  270. * @access protected
  271. * @return false|string
  272. */
  273. private function getCycleDailyTodoDate($todo, $lastCycle, $today)
  274. {
  275. $date = '';
  276. if(isset($todo->config->day))
  277. {
  278. $day = (int)$todo->config->day;
  279. if($day <= 0) return false;
  280. /* If no data, judge the interval from the beginning time. */
  281. if(empty($lastCycle))
  282. {
  283. $todayTime = new DateTime($today);
  284. $beginTime = new DateTime($todo->config->begin);
  285. $interval = $todayTime->diff($beginTime)->days;
  286. if($interval != $day) return false;
  287. $date = $today;
  288. }
  289. /* If data is available, determine the interval of time since the previous cycle. */
  290. if(!empty($lastCycle->date))
  291. {
  292. $todayTime = new DateTime($today);
  293. $lastCycleTime = new DateTime($lastCycle->date);
  294. $interval = $todayTime->diff($lastCycleTime)->days;
  295. if($interval != $day) return false;
  296. $date = date('Y-m-d', strtotime("{$lastCycle->date} +{$day} days"));
  297. }
  298. }
  299. if(isset($todo->config->specifiedDate))
  300. {
  301. $date = $today;
  302. $specifiedDate = $todo->config->specify->month + 1 . '-' . $todo->config->specify->day;
  303. /* If not set cycle every year and have data, continue. */
  304. if(!empty($lastCycle) and !isset($todo->config->cycleYear))
  305. {
  306. /* Delete a one-time todo. */
  307. $this->todo->delete(TABLE_TODO, $todo->id);
  308. return false;
  309. }
  310. /* If set specified date, only judge month and day. */
  311. if(date('m-d', strtotime($date)) != $specifiedDate) return false;
  312. }
  313. return $date;
  314. }
  315. /**
  316. * 修改待办事项的时间。
  317. * Update the date of todo.
  318. *
  319. * @param array $todoIdList
  320. * @param string $date
  321. * @return bool
  322. */
  323. protected function updateDate($todoIdList, $date)
  324. {
  325. $this->dao->update(TABLE_TODO)->set('date')->eq($date)->where('id')->in($todoIdList)->exec();
  326. return !dao::isError();
  327. }
  328. /**
  329. * 获取用户的待办事项数量。
  330. * Get todo count on the account.
  331. *
  332. * @param string $account
  333. * @access protected
  334. * @return int
  335. */
  336. protected function getTodoCountByAccount($account)
  337. {
  338. return $this->dao->select('COUNT(1) AS count')->from(TABLE_TODO)
  339. ->where('cycle')->eq('0')
  340. ->andWhere('deleted')->eq('0')
  341. ->andWhere('vision')->eq($this->config->vision)
  342. ->andWhere('account', true)->eq($account)
  343. ->orWhere('assignedTo')->eq($account)
  344. ->orWhere('finishedBy')->eq($account)
  345. ->markRight(1)
  346. ->fetch('count');
  347. }
  348. /**
  349. * 根据待办类型设置待办名称。
  350. * Set todo name by its type.
  351. *
  352. * @param object $todo
  353. * @access protected
  354. * @return object
  355. */
  356. protected function setTodoNameByType($todo)
  357. {
  358. $savedTodoName = $todo->name;
  359. if(in_array($todo->type, array('story', 'epic', 'requirement')))
  360. {
  361. $story = $this->dao->findByID($todo->objectID)->from(TABLE_STORY)->fetch();
  362. $todo->object = $story;
  363. $todo->name = zget($story, 'title', '');
  364. }
  365. if($todo->type == 'task')
  366. {
  367. $task = $this->dao->findByID($todo->objectID)->from(TABLE_TASK)->fetch();
  368. $todo->object = $task;
  369. $todo->name = zget($task, 'name', '');
  370. }
  371. if($todo->type == 'bug')
  372. {
  373. $bug = $this->dao->findByID($todo->objectID)->from(TABLE_BUG)->fetch();
  374. $todo->object = $bug;
  375. $todo->name = zget($bug, 'title', '');
  376. }
  377. /*
  378. if($todo->type == 'story') $todo->name = $this->dao->findByID($todo->objectID)->from(TABLE_STORY)->fetch('title');
  379. if($todo->type == 'task') $todo->name = $this->dao->findByID($todo->objectID)->from(TABLE_TASK)->fetch('name');
  380. if($todo->type == 'bug') $todo->name = $this->dao->findByID($todo->objectID)->from(TABLE_BUG)->fetch('title');
  381. */
  382. if($todo->type == 'testtask') $todo->name = $this->dao->findByID($todo->objectID)->from(TABLE_TESTTASK)->fetch('name');
  383. if($this->config->edition == 'max')
  384. {
  385. if($todo->type == 'risk' ) $todo->name = $this->dao->findByID($todo->objectID)->from(TABLE_RISK)->fetch('name');
  386. if($todo->type == 'issue') $todo->name = $this->dao->findByID($todo->objectID)->from(TABLE_ISSUE)->fetch('title');
  387. if($todo->type == 'review') $todo->name = $this->dao->findByID($todo->objectID)->from(TABLE_REVIEW)->fetch('title');
  388. if($todo->type == 'opportunity') $todo->name = $this->dao->findByID($todo->objectID)->from(TABLE_OPPORTUNITY)->fetch('name');
  389. }
  390. if($this->config->edition != 'open' && $todo->type == 'feedback') $todo->name = $this->dao->findByID($todo->objectID)->from(TABLE_FEEDBACK)->fetch('title');
  391. if(empty($todo->name)) $todo->name = $savedTodoName;
  392. return $todo;
  393. }
  394. /**
  395. * 获取待办列表数据。
  396. * Get the todo list data.
  397. *
  398. * @param string $type
  399. * @param string $account
  400. * @param string|array $status
  401. * @param string $begin
  402. * @param string $end
  403. * @param int $limit
  404. * @param string $orderBy
  405. * @param object $pager
  406. * @access protected
  407. * @return array
  408. */
  409. protected function getListBy($type, $account, $status, $begin, $end, $limit, $orderBy, $pager = null)
  410. {
  411. return $this->dao->select('*')->from(TABLE_TODO)
  412. ->where('deleted')->eq('0')
  413. ->andWhere('vision')->eq($this->config->vision)
  414. ->beginIF($type == 'assignedtoother')->andWhere('account', true)->eq($account)->fi()
  415. ->beginIF($type != 'assignedtoother')->andWhere('assignedTo', true)->eq($account)->fi()
  416. ->orWhere('finishedBy')->eq($account)
  417. ->orWhere('closedBy')->eq($account)
  418. ->markRight(1)
  419. ->beginIF($begin && $type != 'future')->andWhere('date')->ge($begin)->fi()
  420. ->beginIF($end && $type != 'future')->andWhere('date')->le($end)->fi()
  421. ->beginIF($status != 'all' and $status != 'undone')->andWhere('status')->in($status)->fi()
  422. ->beginIF($status == 'undone')->andWhere('status')->notin('done,closed')->fi()
  423. ->beginIF($type == 'cycle')->andWhere('cycle')->eq('1')->fi()
  424. ->beginIF($type != 'cycle')->andWhere('cycle')->eq('0')->fi()
  425. ->beginIF($type == 'assignedtoother')->andWhere('assignedTo')->notin(array($account, ''))->fi()
  426. ->beginIF($type == 'future')
  427. ->andWhere('(date')->eq(FUTURE_TIME)
  428. ->orWhere('(begin')->eq('2400')
  429. ->andWhere('end')->eq('2400')
  430. ->markRight(2)
  431. ->fi()
  432. ->orderBy($orderBy)
  433. ->beginIF($limit > 0)->limit($limit)->fi()
  434. ->page($pager)
  435. ->fetchAll();
  436. }
  437. }