zentaomax.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. <?php
  2. /**
  3. * Process a task, judge it's status.
  4. * Extend for php warning.
  5. *
  6. * @param object $task
  7. * @param bool $convertParent
  8. * @param array $workingDays
  9. * @access public
  10. * @return object
  11. */
  12. public function processTask($task, $convertParent = true, $workingDays = array())
  13. {
  14. $task = parent::processTask($task, $convertParent, $workingDays);
  15. $design = $task->design > 0 ? $this->loadModel('design')->fetchById($task->design) : '';
  16. $task->designName = !empty($design->name) ? $design->name : '';
  17. if($convertParent)
  18. {
  19. $task->parent = array();
  20. foreach(explode(',', trim((string)$task->path, ',')) as $parentID)
  21. {
  22. if(!$parentID) continue;
  23. if($parentID == $task->id) continue;
  24. $task->parent[] = (int)$parentID;
  25. }
  26. }
  27. return $task;
  28. }
  29. public function printCell($col, $task, $users, $browseType, $branchGroups, $modulePairs = array(), $mode = 'datatable', $child = false, $showBranch = false, $privs = array())
  30. {
  31. if(!empty($privs))
  32. {
  33. $canBatchEdit = $privs['canBatchEdit'];
  34. $canBatchClose = $privs['canBatchClose'];
  35. $canBatchCancel = $privs['canBatchCancel'];
  36. $canBatchChangeModule = $privs['canBatchChangeModule'];
  37. $canBatchAssignTo = $privs['canBatchAssignTo'];
  38. }
  39. else
  40. {
  41. $canBatchEdit = common::hasPriv('task', 'batchEdit', !empty($task) ? $task : null);
  42. $canBatchClose = (common::hasPriv('task', 'batchClose', !empty($task) ? $task : null) && strtolower($browseType) != 'closedBy');
  43. $canBatchCancel = common::hasPriv('task', 'batchCancel', !empty($task) ? $task : null);
  44. $canBatchChangeModule = common::hasPriv('task', 'batchChangeModule', !empty($task) ? $task : null);
  45. $canBatchAssignTo = common::hasPriv('task', 'batchAssignTo', !empty($task) ? $task : null);
  46. }
  47. $canBatchAction = ($canBatchEdit or $canBatchClose or $canBatchCancel or $canBatchChangeModule or $canBatchAssignTo);
  48. $storyChanged = (!empty($task->storyStatus) and $task->storyStatus == 'active' and $task->latestStoryVersion > $task->storyVersion and !in_array($task->status, array('cancel', 'closed')));
  49. $designChange = ($task->designName && $task->latestDesignVersion > $task->designVersion);
  50. $canView = common::hasPriv('task', 'view');
  51. if($this->config->vision == 'lite')
  52. {
  53. $taskLink = helper::createLink('task', 'view', "taskID=$task->id", '', true);
  54. $linkClass = 'class="iframe"';
  55. }
  56. else
  57. {
  58. $taskLink = helper::createLink('task', 'view', "taskID=$task->id");
  59. $linkClass = '';
  60. }
  61. $account = $this->app->user->account;
  62. $id = $col->id;
  63. if($col->show)
  64. {
  65. $class = "c-{$id}";
  66. if($id == 'status') $class .= ' task-' . $task->status;
  67. if($id == 'id') $class .= ' cell-id';
  68. if($id == 'name') $class .= ' text-left';
  69. if($id == 'deadline' and isset($task->delay)) $class .= ' text-center delayed';
  70. if($id == 'assignedTo') $class .= ' has-btn text-left';
  71. if($id == 'lane') $class .= ' text-left';
  72. if(strpos('progress', $id) !== false) $class .= ' text-right';
  73. $title = '';
  74. if($id == 'name')
  75. {
  76. $title = " title='{$task->name}'";
  77. if(!empty($task->children)) $class .= ' has-child';
  78. }
  79. if($id == 'story') $title = " title='{$task->storyTitle}'";
  80. if($id == 'estimate' || $id == 'consumed' || $id == 'left')
  81. {
  82. $value = round($task->$id, 1);
  83. $title = " title='{$value} {$this->lang->execution->workHour}'";
  84. }
  85. if($id == 'lane') $title = " title='{$task->lane}'";
  86. echo "<td class='" . $class . "'" . $title . ">";
  87. if($this->config->edition != 'open') $this->loadModel('flow')->printFlowCell('task', $task, $id);
  88. switch($id)
  89. {
  90. case 'id':
  91. if($canBatchAction)
  92. {
  93. echo html::checkbox('taskIDList', array($task->id => '')) . html::a(helper::createLink('task', 'view', "taskID=$task->id"), sprintf('%03d', $task->id));
  94. }
  95. else
  96. {
  97. printf('%03d', $task->id);
  98. }
  99. break;
  100. case 'pri':
  101. echo "<span class='label-pri label-pri-" . $task->pri . "' title='" . zget($this->lang->task->priList, $task->pri, $task->pri) . "'>";
  102. echo zget($this->lang->task->priList, $task->pri, $task->pri);
  103. echo "</span>";
  104. break;
  105. case 'name':
  106. if($showBranch) $showBranch = isset($this->config->execution->task->showBranch) ? $this->config->execution->task->showBranch : 1;
  107. if($task->parent > 0 and isset($task->parentName)) $task->name = "{$task->parentName} / {$task->name}";
  108. if(!empty($task->product) and isset($branchGroups[$task->product][$task->branch]) and $showBranch) echo "<span class='label label-badge label-outline'>" . $branchGroups[$task->product][$task->branch] . '</span> ';
  109. if($task->module and isset($modulePairs[$task->module])) echo "<span class='label label-gray label-badge'>" . $modulePairs[$task->module] . '</span> ';
  110. if($task->parent > 0) echo '<span class="label label-badge label-light" title="' . $this->lang->task->children . '">' . $this->lang->task->childrenAB . '</span> ';
  111. if(!empty($task->team)) echo '<span class="label label-badge label-light" title="' . $this->lang->task->multiple . '">' . $this->lang->task->multipleAB . '</span> ';
  112. echo $canView ? html::a($taskLink, $task->name, null, "$linkClass style='color: $task->color' title='$task->name'") : "<span style='color: $task->color'>$task->name</span>";
  113. if(!empty($task->children)) echo '<a class="task-toggle" data-id="' . $task->id . '"><i class="icon icon-angle-right"></i></a>';
  114. if($task->fromBug) echo html::a(helper::createLink('bug', 'view', "id=$task->fromBug"), "[BUG#$task->fromBug]", '', "class='bug'");
  115. break;
  116. case 'type':
  117. echo zget($this->lang->task->typeList, $task->type, $task->type);
  118. break;
  119. case 'status':
  120. if($storyChanged)
  121. {
  122. print("<span class='status-story status-changed' title='{$this->lang->story->changed}'>{$this->lang->story->changed}</span>");
  123. }
  124. elseif($designChange)
  125. {
  126. print("<span class='status-design status-changed' title='{$this->lang->task->designChanged}'>{$this->lang->task->designChanged}</span>");
  127. }
  128. else
  129. {
  130. $statusLabel = $this->processStatus('task', $task);
  131. print("<span class='status-task status-{$task->status}' title='{$statusLabel}'> " . $statusLabel . "</span>");
  132. }
  133. break;
  134. case 'estimate':
  135. echo round($task->estimate, 1) . ' ' . $this->lang->execution->workHourUnit;
  136. break;
  137. case 'consumed':
  138. echo round($task->consumed, 1) . ' ' . $this->lang->execution->workHourUnit;
  139. break;
  140. case 'left':
  141. echo round($task->left, 1) . ' ' . $this->lang->execution->workHourUnit;
  142. break;
  143. case 'design':
  144. echo $task->designName ? html::a(helper::createLink('design', 'view', "id=$task->design"), $task->designName) : '';
  145. break;
  146. case 'progress':
  147. echo "{$task->progress}%";
  148. break;
  149. case 'deadline':
  150. if(!helper::isZeroDate($task->deadline)) echo '<span>' . substr($task->deadline, 5, 6). '</span>';
  151. break;
  152. case 'openedBy':
  153. echo zget($users, $task->openedBy);
  154. break;
  155. case 'openedDate':
  156. echo substr($task->openedDate, 5, 11);
  157. break;
  158. case 'estStarted':
  159. echo helper::isZeroDate($task->estStarted) ? '' : substr($task->estStarted, 5, 11);
  160. break;
  161. case 'realStarted':
  162. echo helper::isZeroDate($task->realStarted) ? '' : substr($task->realStarted, 5, 11);
  163. break;
  164. case 'assignedTo':
  165. $this->printAssignedHtml($task, $users);
  166. break;
  167. case 'lane':
  168. echo mb_substr($task->lane, 0, 8);
  169. break;
  170. case 'assignedDate':
  171. echo helper::isZeroDate($task->assignedDate) ? '' : substr($task->assignedDate, 5, 11);
  172. break;
  173. case 'finishedBy':
  174. echo zget($users, $task->finishedBy);
  175. break;
  176. case 'finishedDate':
  177. echo helper::isZeroDate($task->finishedDate) ? '' : substr($task->finishedDate, 5, 11);
  178. break;
  179. case 'canceledBy':
  180. echo zget($users, $task->canceledBy);
  181. break;
  182. case 'canceledDate':
  183. echo helper::isZeroDate($task->canceledDate) ? '' : substr($task->canceledDate, 5, 11);
  184. break;
  185. case 'closedBy':
  186. echo zget($users, $task->closedBy);
  187. break;
  188. case 'closedDate':
  189. echo helper::isZeroDate($task->closedDate) ? '' : substr($task->closedDate, 5, 11);
  190. break;
  191. case 'closedReason':
  192. echo $this->lang->task->reasonList[$task->closedReason];
  193. break;
  194. case 'story':
  195. if(!empty($task->storyID))
  196. {
  197. if(common::hasPriv('story', 'view'))
  198. {
  199. echo html::a(helper::createLink('story', 'view', "storyid=$task->storyID", 'html', true), "<i class='icon icon-{$this->lang->icons['story']}'></i>", '', "class='iframe' title='{$task->storyTitle}'");
  200. }
  201. else
  202. {
  203. echo "<i class='icon icon-{$this->lang->icons['story']}' title='{$task->storyTitle}'></i>";
  204. }
  205. }
  206. break;
  207. case 'mailto':
  208. $mailto = explode(',', $task->mailto);
  209. foreach($mailto as $account)
  210. {
  211. $account = trim($account);
  212. if(empty($account)) continue;
  213. echo zget($users, $account) . ' &nbsp;';
  214. }
  215. break;
  216. case 'lastEditedBy':
  217. echo zget($users, $task->lastEditedBy);
  218. break;
  219. case 'lastEditedDate':
  220. echo helper::isZeroDate($task->lastEditedDate) ? '' : substr($task->lastEditedDate, 5, 11);
  221. break;
  222. case 'actions':
  223. echo $this->buildOperateMenu($task, 'browse');
  224. break;
  225. }
  226. echo '</td>';
  227. }
  228. }
  229. /**
  230. * Build task browse action menu.
  231. *
  232. * @param object $task
  233. * @param string $execution
  234. * @access public
  235. * @return void
  236. */
  237. public function buildOperateBrowseMenu($task, $execution = '')
  238. {
  239. $menu = '';
  240. $params = "taskID=$task->id";
  241. $storyChanged = !empty($task->storyStatus) && $task->storyStatus == 'active' && $task->latestStoryVersion > $task->storyVersion && !in_array($task->status, array('cancel', 'closed'));
  242. $designChange = isset($task->designName) ? $task->designName && $task->latestDesignVersion > $task->designVersion : false;
  243. if($storyChanged) return $this->buildMenu('task', 'confirmStoryChange', $params, $task, 'browse', '', 'hiddenwin');
  244. if($designChange) return $this->buildMenu('task', 'confirmDesignChange', $params, $task, 'browse', 'search', 'hiddenwin');
  245. $canStart = ($task->status != 'pause' and common::hasPriv('task', 'start'));
  246. $canRestart = ($task->status == 'pause' and common::hasPriv('task', 'restart'));
  247. $canFinish = common::hasPriv('task', 'finish');
  248. $canClose = common::hasPriv('task', 'close');
  249. $canRecordEstimate = common::hasPriv('task', 'recordEstimate');
  250. $canEdit = common::hasPriv('task', 'edit');
  251. $canBatchCreate = ($this->config->vision != 'lite' and common::hasPriv('task', 'batchCreate'));
  252. $this->app->loadLang('stage');
  253. $disabled = '';
  254. $taskStartTip = '';
  255. $taskFinishTip = '';
  256. $taskRecordTip = '';
  257. if(!empty($execution) and !$execution->parallel and $execution->status == 'wait' and $this->config->systemMode == 'PLM' and isset($execution->ipdStage) and !$execution->ipdStage['canStart'])
  258. {
  259. if(in_array($execution->attribute, array_keys($this->lang->stage->ipdTypeList)))
  260. {
  261. $disabled = 'disabled';
  262. if(!$execution->ipdStage['isFirst']) $taskStartTip = sprintf($this->lang->execution->disabledTip->taskStartTip, $this->lang->stage->ipdTypeList[$execution->ipdStage['preAttribute']], $this->lang->stage->ipdTypeList[$execution->attribute]);
  263. if(!$execution->ipdStage['isFirst']) $taskFinishTip = sprintf($this->lang->execution->disabledTip->taskFinishTip, $this->lang->stage->ipdTypeList[$execution->ipdStage['preAttribute']], $this->lang->stage->ipdTypeList[$execution->attribute]);
  264. if(!$execution->ipdStage['isFirst']) $taskRecordTip = sprintf($this->lang->execution->disabledTip->taskRecordTip, $this->lang->stage->ipdTypeList[$execution->ipdStage['preAttribute']], $this->lang->stage->ipdTypeList[$execution->attribute]);
  265. }
  266. }
  267. if(isset($task->ipdStage->canStart) and empty($task->ipdStage->canStart))
  268. {
  269. $disabled = 'disabled';
  270. if(isset($execution->ipdStage) and !$execution->ipdStage['isFirst']) $taskStartTip = $task->ipdStage->taskStartTip;
  271. if(isset($execution->ipdStage) and !$execution->ipdStage['isFirst']) $taskFinishTip = $task->ipdStage->taskFinishTip;
  272. if(isset($execution->ipdStage) and !$execution->ipdStage['isFirst']) $taskRecordTip = $task->ipdStage->taskRecordTip;
  273. }
  274. if($task->status != 'pause') $menu .= $this->buildMenu('task', 'start', $params, $task, 'browse', '', '', "iframe $disabled", true, $disabled ? 'disabled data-toggle=""' : '', $taskStartTip);
  275. if($task->status == 'pause') $menu .= $this->buildMenu('task', 'restart', $params, $task, 'browse', '', '', 'iframe', true);
  276. $menu .= $this->buildMenu('task', 'finish', $params, $task, 'browse', '', '', "iframe $disabled", true, $disabled ? 'disabled data-toggle=""' : '', $taskFinishTip);
  277. $menu .= $this->buildMenu('task', 'close', $params, $task, 'browse', '', '', 'iframe', true);
  278. if(($canStart or $canRestart or $canFinish or $canClose) and ($canRecordEstimate or $canEdit or $canBatchCreate) and $this->app->rawModule == 'task')
  279. {
  280. $menu .= "<div class='dividing-line'></div>";
  281. }
  282. $menu .= $this->buildMenu('task', 'recordEstimate', $params, $task, 'browse', 'time', '', "iframe $disabled", true, $disabled ? 'disabled data-toggle=""' : '', $taskRecordTip);
  283. $menu .= $this->buildMenu('task', 'edit', $params, $task, 'browse', 'edit', '', '', false);
  284. if($this->config->vision != 'lite')
  285. {
  286. $menu .= $this->buildMenu('task', 'batchCreate', "execution=$task->execution&storyID=$task->story&moduleID=$task->module&taskID=$task->id&ifame=0", $task, 'browse', 'split', '', '', '', '', $this->lang->task->children);
  287. }
  288. return $menu;
  289. }
  290. /**
  291. * Gets the version record of the task.
  292. *
  293. * @param $taskID
  294. * @param $version
  295. * @access public
  296. * @return void
  297. */
  298. public function getTaskSpec($taskID, $version)
  299. {
  300. return $this->dao->select('*')->from(TABLE_TASKSPEC)
  301. ->where('task')->eq($taskID)
  302. ->andWhere('version')->eq($version)
  303. ->fetch();
  304. }
  305. /**
  306. * @param object $task
  307. * @param object $teamData
  308. * @param string $comment
  309. * @param mixed[] $drag
  310. */
  311. public function activate($task, $comment, $teamData, $drag = array())
  312. {
  313. $changes = parent::activate($task, $comment, $teamData, $drag);
  314. $now = helper::now();
  315. $this->dao->update(TABLE_TASK)->set('activatedDate')->eq($now)->where('id')->eq($task->id)->exec();
  316. return $changes;
  317. }
  318. /**
  319. * @return mixed[]|string|false
  320. * @param object $task
  321. */
  322. public function update($task, $teamData = null)
  323. {
  324. $result = parent::update($task, $teamData);
  325. /* Update planDuration. */
  326. if($result)
  327. {
  328. $estStarted = $this->post->estStarted;
  329. $deadline = $this->post->deadline;
  330. $planDuration = $this->loadModel('holiday')->getActualWorkingDays($estStarted, $deadline);
  331. $planDuration = count($planDuration);
  332. $this->dao->update(TABLE_TASK)->set('planDuration')->eq($planDuration)->where('id')->eq($task->id)->exec();
  333. }
  334. return $result;
  335. }