* Split task completion method.
This commit is contained in:
+26
-73
@@ -672,81 +672,35 @@ class task extends control
|
||||
public function finish($taskID, $extra = '')
|
||||
{
|
||||
$this->taskZen->commonAction($taskID);
|
||||
|
||||
$extra = str_replace(array(',', ' '), array('&', ''), $extra);
|
||||
parse_str($extra, $output);
|
||||
$task = $this->task->getById($taskID);
|
||||
$currentTeam = empty($task->team) ? $this->task->getTeamByAccount($task->team) : '';
|
||||
|
||||
if(!empty($_POST))
|
||||
{
|
||||
$this->loadModel('action');
|
||||
$changes = $this->task->finish($taskID, $extra);
|
||||
if(dao::isError())
|
||||
{
|
||||
if($this->viewType == 'json' or (defined('RUN_MODE') && RUN_MODE == 'api')) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
return print(js::error(dao::getError()));
|
||||
}
|
||||
$files = $this->loadModel('file')->saveUpload('task', $taskID);
|
||||
$taskData = $this->taskZen->buildTaskForFinish($task);
|
||||
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
|
||||
$task = $this->task->getById($taskID);
|
||||
if($this->post->comment != '' or !empty($changes))
|
||||
{
|
||||
$fileAction = !empty($files) ? $this->lang->addFiles . implode(',', $files) . "\n" : '';
|
||||
$actionID = $this->action->create('task', $taskID, 'Finished', $fileAction . $this->post->comment);
|
||||
$this->action->logHistory($actionID, $changes);
|
||||
}
|
||||
/* Get and record esitimate for task. */
|
||||
$effort = $this->buildEffortForStart($task, $taskData);
|
||||
if($this->post->comment) $effort->work = $this->post->comment;
|
||||
if($effort->consumed > 0) $effortID = $this->task->addTaskEffort($effort);
|
||||
if($task->mode == 'linear' && !empty($effortID)) $this->task->updateEstimateOrder($effortID, $currentTeam->order);
|
||||
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
|
||||
$this->executeHooks($taskID);
|
||||
$this->loadModel('common')->syncPPEStatus($taskID);
|
||||
$changes = $this->task->finish($oldTask, $taskData, $extra);
|
||||
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
|
||||
if($this->task->needUpdateBugStatus($task))
|
||||
{
|
||||
foreach($changes as $change)
|
||||
{
|
||||
if($change['field'] == 'status')
|
||||
{
|
||||
$confirmURL = $this->createLink('bug', 'view', "id=$task->fromBug", '', true);
|
||||
unset($_GET['onlybody']);
|
||||
$cancelURL = $this->createLink('task', 'view', "taskID=$taskID");
|
||||
return print(js::confirm(sprintf($this->lang->task->remindBug, $task->fromBug), $confirmURL, $cancelURL, 'parent', 'parent.parent'));
|
||||
}
|
||||
}
|
||||
}
|
||||
$extra = str_replace(array(',', ' '), array('&', ''), $extra);
|
||||
parse_str($extra, $output);
|
||||
|
||||
if(isonlybody())
|
||||
{
|
||||
$execution = $this->execution->getByID($task->execution);
|
||||
$executionLaneType = $this->session->executionLaneType ? $this->session->executionLaneType : 'all';
|
||||
$executionGroupBy = $this->session->executionGroupBy ? $this->session->executionGroupBy : 'default';
|
||||
if(($this->app->tab == 'execution' or ($this->config->vision == 'lite' and $this->app->tab == 'project')) and $execution->type == "kanban")
|
||||
{
|
||||
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
|
||||
$regionID = !empty($output['regionID']) ? $output['regionID'] : 0;
|
||||
$kanbanData = $this->loadModel('kanban')->getRDKanban($task->execution, $executionLaneType, 'id_desc', $regionID, $executionGroupBy, $rdSearchValue);
|
||||
$kanbanData = json_encode($kanbanData);
|
||||
/* Update other data related to the task after it is started. */
|
||||
$result = $this->task->afterStart($task, $taskData, $changes, $this->post->comment, $output);
|
||||
if(is_array($result)) $this->send($result);
|
||||
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData, $regionID)"));
|
||||
}
|
||||
if($output['from'] == "taskkanban")
|
||||
{
|
||||
$taskSearchValue = $this->session->taskSearchValue ? $this->session->taskSearchValue : '';
|
||||
$kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $executionLaneType, $executionGroupBy, $taskSearchValue);
|
||||
$kanbanType = $executionLaneType == 'all' ? 'task' : key($kanbanData);
|
||||
$kanbanData = $kanbanData[$kanbanType];
|
||||
$kanbanData = json_encode($kanbanData);
|
||||
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"task\", $kanbanData)"));
|
||||
}
|
||||
return print(js::closeModal('parent.parent', 'this', "function(){parent.parent.location.reload();}"));
|
||||
}
|
||||
|
||||
if(defined('RUN_MODE') && RUN_MODE == 'api')
|
||||
{
|
||||
return $this->send(array('result' => 'success', 'data' => $taskID));
|
||||
}
|
||||
else
|
||||
{
|
||||
return print(js::locate($this->createLink('task', 'view', "taskID=$taskID"), 'parent'));
|
||||
}
|
||||
/* Get the information returned after a task is started. */
|
||||
$from = zget($output, 'from');
|
||||
$response = $this->taskZen->responseAfterChangeStatus($taskData, $from);
|
||||
return $this->send($response);
|
||||
}
|
||||
|
||||
$task = $this->view->task;
|
||||
@@ -756,14 +710,13 @@ class task extends control
|
||||
if(!empty($task->team))
|
||||
{
|
||||
$task->nextBy = $this->task->getAssignedTo4Multi($task->team, $task, 'next');
|
||||
$task->myConsumed = 0;
|
||||
$currentTeam = $this->task->getTeamByAccount($task->team);
|
||||
if($currentTeam) $task->myConsumed = $currentTeam->consumed;
|
||||
$task->myConsumed = zget($currentTeam, 'consumed', 0);
|
||||
}
|
||||
|
||||
$this->view->title = $this->view->execution->name . $this->lang->colon .$this->lang->task->finish;
|
||||
$this->view->members = $members;
|
||||
$this->view->users = $this->loadModel('user')->getPairs('noletter');
|
||||
$this->view->title = $this->view->execution->name . $this->lang->colon .$this->lang->task->finish;
|
||||
$this->view->members = $members;
|
||||
$this->view->users = $this->loadModel('user')->getPairs('noletter');
|
||||
$this->view->canRecordEffort = $this->taskZen->checkRecordEffort($task);
|
||||
$this->display();
|
||||
}
|
||||
|
||||
|
||||
+30
-85
@@ -1261,7 +1261,7 @@ class taskModel extends model
|
||||
{
|
||||
/* Process data for multiple tasks. */
|
||||
$currentTeam = !empty($oldTask->team) ? $this->getTeamByAccount($oldTask->team) : array();
|
||||
if(!empty($oldTask->team) && $currentTeam)
|
||||
if($currentTeam)
|
||||
{
|
||||
/* Update task team. */
|
||||
$team = new stdclass();
|
||||
@@ -1547,102 +1547,47 @@ class taskModel extends model
|
||||
* Finish a task.
|
||||
*
|
||||
* @param int $taskID
|
||||
* @param string $extra
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function finish($taskID, $extra = '')
|
||||
public function finish(object $oldTask, object $task)
|
||||
{
|
||||
$extra = str_replace(array(',', ' '), array('&', ''), $extra);
|
||||
parse_str($extra, $output);
|
||||
$currentTeam = !empty($oldTask->team) ? $this->getTeamByAccount($oldTask->team) : array();
|
||||
if($currentTeam) $task = $this->computeMultipleHours($oldTask, $task);
|
||||
|
||||
$oldTask = $this->getById($taskID);
|
||||
$now = helper::now();
|
||||
|
||||
if($extra != 'DEVOPS' and strpos($this->config->task->finish->requiredFields, 'comment') !== false and !$this->post->comment)
|
||||
{
|
||||
dao::$errors[] = sprintf($this->lang->error->notempty, $this->lang->comment);
|
||||
return false;
|
||||
}
|
||||
|
||||
$task = fixer::input('post')
|
||||
->add('id', $taskID)
|
||||
->setIF(is_numeric($this->post->consumed), 'consumed', (float)$this->post->consumed)
|
||||
->setIF(!$this->post->realStarted and helper::isZeroDate($oldTask->realStarted), 'realStarted', $now)
|
||||
->setDefault('left', 0)
|
||||
->setDefault('assignedTo', $oldTask->openedBy)
|
||||
->setDefault('assignedDate', $now)
|
||||
->setDefault('status', 'done')
|
||||
->setDefault('finishedBy, lastEditedBy', $this->app->user->account)
|
||||
->setDefault('finishedDate, lastEditedDate', $now)
|
||||
->stripTags($this->config->task->editor->finish['id'], $this->config->allowedTags)
|
||||
->removeIF(!empty($oldTask->team), 'finishedBy,status,left')
|
||||
->remove('comment,files,labels,currentConsumed')
|
||||
->get();
|
||||
|
||||
$currentConsumed = trim($this->post->currentConsumed);
|
||||
if(!is_numeric($currentConsumed)) return dao::$errors[] = $this->lang->task->error->consumedNumber;
|
||||
if(empty($currentConsumed) and $oldTask->consumed == '0') return dao::$errors[] = $this->lang->task->error->consumedEmpty;
|
||||
if(!$this->post->realStarted) return dao::$errors[] = $this->lang->task->error->realStartedEmpty;
|
||||
if(!$this->post->finishedDate) return dao::$errors[] = $this->lang->task->error->finishedDateEmpty;
|
||||
if($this->post->realStarted > $this->post->finishedDate) return dao::$errors[] = $this->lang->task->error->finishedDateSmall;
|
||||
|
||||
/* Record consumed and left. */
|
||||
if(empty($oldTask->team))
|
||||
{
|
||||
$consumed = $task->consumed - $oldTask->consumed;
|
||||
if($consumed < 0) return dao::$errors[] = $this->lang->task->error->consumedSmall;
|
||||
}
|
||||
else
|
||||
{
|
||||
$currentTeam = $this->getTeamByAccount($oldTask->team);
|
||||
$consumed = $currentTeam ? $task->consumed - $currentTeam->consumed : $task->consumed;
|
||||
if($consumed < 0) return dao::$errors[] = $this->lang->task->error->consumedSmall;
|
||||
}
|
||||
|
||||
$estimate = new stdclass();
|
||||
$estimate->date = helper::isZeroDate($task->finishedDate) ? helper::today() : substr($task->finishedDate, 0, 10);
|
||||
$estimate->task = $taskID;
|
||||
$estimate->left = 0;
|
||||
$estimate->work = zget($task, 'work', '');
|
||||
$estimate->account = $this->app->user->account;
|
||||
$estimate->consumed = $consumed;
|
||||
if($this->post->comment) $estimate->work = $this->post->comment;
|
||||
if($estimate->consumed) $estimateID = $this->addTaskEffort($estimate);
|
||||
|
||||
if(!empty($oldTask->team) and $currentTeam)
|
||||
{
|
||||
$this->dao->update(TABLE_TASKTEAM)->set('left')->eq(0)->set('consumed')->eq($task->consumed)->set('status')->eq('done')->where('id')->eq($currentTeam->id)->exec();
|
||||
if($oldTask->mode == 'linear' and isset($estimateID)) $this->updateEstimateOrder($estimateID, $currentTeam->order);
|
||||
$task = $this->computeMultipleHours($oldTask, $task);
|
||||
}
|
||||
|
||||
if($task->finishedDate == substr($now, 0, 10)) $task->finishedDate = $now;
|
||||
|
||||
$task = $this->loadModel('file')->processImgURL($task, $this->config->task->editor->finish['id'], $this->post->uid);
|
||||
$this->dao->update(TABLE_TASK)->data($task)->autoCheck()->checkFlow()
|
||||
->where('id')->eq((int)$taskID)
|
||||
->exec();
|
||||
|
||||
if(!dao::isError())
|
||||
if(!dao::isError()) return false;
|
||||
return common::createChanges($oldTask, $task);
|
||||
}
|
||||
|
||||
public function afterFinish()
|
||||
{
|
||||
$files = $this->loadModel('file')->saveUpload('task', $taskID);
|
||||
if($this->post->comment != '' or !empty($changes))
|
||||
{
|
||||
if($oldTask->parent > 0) $this->updateParentStatus($taskID);
|
||||
if($oldTask->story) $this->loadModel('story')->setStage($oldTask->story);
|
||||
if($task->status == 'done')
|
||||
{
|
||||
$this->loadModel('score')->create('task', 'finish', $taskID);
|
||||
|
||||
$this->loadModel('kanban');
|
||||
if(!isset($output['toColID'])) $this->kanban->updateLane($oldTask->execution, 'task', $taskID);
|
||||
if(isset($output['toColID'])) $this->kanban->moveCard($taskID, $output['fromColID'], $output['toColID'], $output['fromLaneID'], $output['toLaneID']);
|
||||
}
|
||||
|
||||
if(($this->config->edition == 'biz' || $this->config->edition == 'max') && $oldTask->feedback) $this->loadModel('feedback')->updateStatus('task', $oldTask->feedback, $task->status, $oldTask->status);
|
||||
|
||||
return common::createChanges($oldTask, $task);
|
||||
$fileAction = !empty($files) ? $this->lang->addFiles . implode(',', $files) . "\n" : '';
|
||||
$actionID = $this->loadModel('action')->create('task', $taskID, 'Finished', $fileAction . $this->post->comment);
|
||||
$this->action->logHistory($actionID, $changes);
|
||||
}
|
||||
|
||||
return false;
|
||||
$this->executeHooks($taskID);
|
||||
$this->loadModel('common')->syncPPEStatus($taskID);
|
||||
|
||||
if($this->task->needUpdateBugStatus($task))
|
||||
{
|
||||
foreach($changes as $change)
|
||||
{
|
||||
if($change['field'] == 'status')
|
||||
{
|
||||
$confirmURL = $this->createLink('bug', 'view', "id=$task->fromBug");
|
||||
$cancelURL = $this->createLink('task', 'view', "taskID=$taskID");
|
||||
return array('result' => 'success', 'load' => array('confirm' => sprintf($this->lang->task->remindBug, $oldTask->fromBug), 'confirmed' => $confirmURL, 'canceled' => $cancelURL));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1356,4 +1356,59 @@ class taskZen extends task
|
||||
if(!isset($task->members[$this->app->user->account])) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建并检查完成任务所需的数据。
|
||||
* Build and check the request data for the finish task.
|
||||
*
|
||||
* @param object $oldTask
|
||||
* @access protected
|
||||
* @return object
|
||||
*/
|
||||
protected function buildTaskForFinish(object $oldTask): object
|
||||
{
|
||||
$now = helper::now();
|
||||
$task = form::data($this->config->task->form->finish)
|
||||
->setIF(!$this->post->realStarted and helper::isZeroDate($oldTask->realStarted), 'realStarted', $now)
|
||||
->setDefault('assignedTo', $oldTask->openedBy)
|
||||
->get();
|
||||
|
||||
if(empty($task->currentConsumed)) dao::$errors['currentConsumed'][] = $this->lang->task->error->consumedEmpty;
|
||||
if($task->realStarted > $task->finishedDate) dao::$errors['realStarted'][] = $this->lang->task->error->finishedDateSmall;
|
||||
return $task;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理开始任务的日志数据。
|
||||
* Process the effort data for the start task.
|
||||
*
|
||||
* @param object $oldTask
|
||||
* @param object $task
|
||||
* @access protected
|
||||
* @return object
|
||||
*/
|
||||
protected function buildEffortForFinish(object $oldTask, object $task): object
|
||||
{
|
||||
/* Record consumed and left. */
|
||||
if(empty($oldTask->team))
|
||||
{
|
||||
$task->consumed = $task->consumed - $oldTask->consumed;
|
||||
}
|
||||
else
|
||||
{
|
||||
$currentTeam = $this->task->getTeamByAccount($oldTask->team);
|
||||
$task->consumed = $currentTeam ? $task->consumed - $currentTeam->consumed : $task->consumed;
|
||||
}
|
||||
if($task->consumed < 0) dao::$errors[] = $this->lang->task->error->consumedSmall;
|
||||
|
||||
$estimate = new stdclass();
|
||||
$estimate->date = helper::isZeroDate($task->finishedDate) ? helper::today() : substr($task->finishedDate, 0, 10);
|
||||
$estimate->task = $taskID;
|
||||
$estimate->left = 0;
|
||||
$estimate->work = zget($task, 'work', '');
|
||||
$estimate->account = $this->app->user->account;
|
||||
$estimate->consumed = $consumed;
|
||||
|
||||
return $effort;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user