db = $database; $this->taskGateway = $taskGateway; $this->resubmissionGateway = $resubmissionGateway; } /** * Aufgabe auf "abgeschlossen" stellen * * @param int $taskId * @param int $resubmissionId * * @throws ResubmissionTaskNotFoundException * * @return void */ public function markTaskAsCompleted($taskId, $resubmissionId) { if (!$this->taskGateway->isTaskAssigendToResubmission($taskId, $resubmissionId)) { throw new ResubmissionTaskNotFoundException(sprintf( 'Task not found. Task-ID: %s - Resubmission-ID: %s', $taskId, $resubmissionId )); } $sql = 'UPDATE `aufgabe` SET `status` = :state, `abgeschlossen_am` = :completion_date, `logdatei` = NOW() WHERE `id` = :task_id LIMIT 1'; $this->db->perform($sql, [ 'state' => 'abgeschlossen', 'completion_date' => date('Y-m-d'), 'task_id' => (int)$taskId, ]); } /** * Aufgabe auf "offen" stellen * * @param int $taskId * @param int $resubmissionId * * @throws ResubmissionTaskNotFoundException * @throws TaskMustBeCompletedException * * @return void */ public function markTaskAsOpen($taskId, $resubmissionId) { if (!$this->taskGateway->isTaskAssigendToResubmission($taskId, $resubmissionId)) { throw new ResubmissionTaskNotFoundException(sprintf( 'Task not found. Task-ID: %s - Resubmission-ID: %s', $taskId, $resubmissionId )); } $task = $this->taskGateway->getTask($taskId); // Vor der Änderung prüfen ob Änderung überhaupt gültig wäre $check = $this->isTaskStageChangeAllowed( $task['stage_id'], $task['required_completion_stage_id'], ResubmissionTaskData::STATE_OPEN ); if (!$check) { $currentStage = $this->resubmissionGateway->getStage($task['stage_id']); $requiredStage = $this->resubmissionGateway->getStage($task['required_completion_stage_id']); throw TaskMustBeCompletedException::onChangingStateToOpen( $requiredStage['shortname'], $currentStage['shortname'] ); } $sql = 'UPDATE `aufgabe` SET `status` = :state, `abgeschlossen_am` = :completion_date, `logdatei` = NOW() WHERE `id` = :task_id LIMIT 1'; $this->db->fetchAffected($sql, [ 'state' => 'offen', 'completion_date' => '0000-00-00', 'task_id' => (int)$taskId, ]); } /** * @param ResubmissionTaskData $task * * @throws ResubmissionTaskNotFoundException * @throws TaskMustBeCompletedException * @throws DatabaseExceptionInterface * * @return void */ public function createTask(ResubmissionTaskData $task) { if (!$this->resubmissionGateway->existsResubmission($task->getResubmissionId())) { throw new ResubmissionNotFoundException(sprintf( 'Resubmission not found. ID: %s', $task->getResubmissionId() )); } // Vor der Erstellung prüfen ob Task-Status überhaupt gültig wäre $currentStage = $this->resubmissionGateway->getStageByResubmission($task->getResubmissionId()); $check = $this->isTaskStageChangeAllowed( $currentStage['id'], $task->getRequiredCompletionStageId(), $task->getState() ); if (!$check) { $requiredStage = $this->resubmissionGateway->getStage($task->getRequiredCompletionStageId()); throw TaskMustBeCompletedException::onCreation( $requiredStage['shortname'], $currentStage['shortname'] ); } $priority = $this->translatePriorityToDbValue($task->getPriority()); $state = $this->translateStateToDbValue($task->getState()); $insert = $this->db->insert(); $insert->into('aufgabe'); $insert->col('aufgabe', $task->getTitle()); $insert->col('prio', $priority); $insert->col('status', $state); $insert->col('initiator', (int)$task->getCreatorAddressId()); // Optionale Felder $insert->col('adresse', (int)$task->getEmployeeAddressId()); $insert->col('kunde', (int)$task->getCustomerAddressId()); $insert->col('projekt', (int)$task->getProjectId()); $insert->col('teilprojekt', (int)$task->getSubProjectId()); $insert->col('beschreibung', (string)$task->getDescription()); if ($task->getSubmissionDateTime() !== null) { $insert->col('abgabe_bis', $task->getSubmissionDateTime()->format('Y-m-d')); $insert->col('abgabe_bis_zeit', $task->getSubmissionDateTime()->format('H:i:s')); } else { $insert->col('abgabe_bis', '0000-00-00'); $insert->col('abgabe_bis_zeit', '00:00:00'); } $insert->col('angelegt_am', date('Y-m-d')); $insert->set('logdatei', 'NOW()'); $this->db->beginTransaction(); try { $this->db->perform($insert->getStatement(), $insert->getBindValues()); $insertId = $this->db->lastInsertId(); $this->db->perform( 'INSERT INTO `wiedervorlage_aufgabe` (`task_id`, `resubmission_id`, `required_completion_stage_id`) VALUES (:task_id, :resubmission_id, :required_completion_stage_id)', [ 'task_id' => $insertId, 'resubmission_id' => $task->getResubmissionId(), 'required_completion_stage_id' => $task->getRequiredCompletionStageId(), ] ); $this->db->commit(); // } catch (DatabaseExceptionInterface $exception) { $this->db->rollBack(); throw $exception; } } /** * @param ResubmissionTaskData $task * * @throws ResubmissionTaskNotFoundException * @throws TaskMustBeCompletedException * * @return void */ public function editTask(ResubmissionTaskData $task) { if (!$this->taskGateway->isTaskAssigendToResubmission($task->getId(), $task->getResubmissionId())) { throw new ResubmissionTaskNotFoundException(sprintf( 'Task not found. Task-ID: %s - Resubmission-ID: %s', $task->getId(), $task->getResubmissionId() )); } // Vor der Änderung prüfen ob Änderung überhaupt gültig wäre $currentStage = $this->resubmissionGateway->getStageByResubmission($task->getResubmissionId()); $check = $this->isTaskStageChangeAllowed( $currentStage['id'], $task->getRequiredCompletionStageId(), $task->getState() ); if (!$check) { $requiredStage = $this->resubmissionGateway->getStage($task->getRequiredCompletionStageId()); throw TaskMustBeCompletedException::onModification( $requiredStage['shortname'], $currentStage['shortname'] ); } $priority = $this->translatePriorityToDbValue($task->getPriority()); $state = $this->translateStateToDbValue($task->getState()); $update = $this->db->update(); $update->table('aufgabe'); $update->col('aufgabe', $task->getTitle()); $update->col('prio', $priority); $update->col('status', $state); if ($task->getEmployeeAddressId() !== null) { $update->col('adresse', $task->getEmployeeAddressId()); } if ($task->getProjectId() !== null) { $update->col('projekt', $task->getProjectId()); } if ($task->getSubProjectId() !== null) { $update->col('teilprojekt', $task->getSubProjectId()); } if ($task->getDescription() !== null) { $update->col('beschreibung', $task->getDescription()); } else { $update->col('beschreibung', ''); } if ($task->getCustomerAddressId() !== null) { $update->col('kunde', $task->getCustomerAddressId()); } else { $update->col('kunde', 0); } if ($task->getCompletionDateTime() !== null) { if ($task->getCompletionDateTime()->getTimestamp() > 0) { $update->col('abgeschlossen_am', $task->getCompletionDateTime()->format('Y-m-d')); } else { $update->col('abgeschlossen_am', '0000-00-00'); } } if ($task->getSubmissionDateTime() !== null) { $update->col('abgabe_bis', $task->getSubmissionDateTime()->format('Y-m-d')); $update->col('abgabe_bis_zeit', $task->getSubmissionDateTime()->format('H:i:s')); } else { $update->col('abgabe_bis', '0000-00-00'); $update->col('abgabe_bis_zeit', '00:00:00'); } $update->set('logdatei', 'NOW()'); $update->where('id = ?', $task->getId()); $update->limit(1); try { $this->db->beginTransaction(); $this->db->perform($update->getStatement(), $update->getBindValues()); $this->db->perform( 'UPDATE `wiedervorlage_aufgabe` SET `required_completion_stage_id` = :required_completion_stage_id WHERE `task_id` = :task_id AND `resubmission_id` = :resubmission_id LIMIT 1', [ 'task_id' => $task->getId(), 'resubmission_id' => $task->getResubmissionId(), 'required_completion_stage_id' => $task->getRequiredCompletionStageId(), ] ); $this->db->commit(); // } catch (DatabaseExceptionInterface $exception) { $this->db->rollBack(); throw $exception; } } /** * Aufgabe löschen * * @param int $taskId * @param int $resubmissionId * * @throws ResubmissionTaskNotFoundException * * @return void */ public function deleteTask($taskId, $resubmissionId) { $taskId = (int)$taskId; $resubmissionId = (int)$resubmissionId; if (!$this->taskGateway->isTaskAssigendToResubmission($taskId, $resubmissionId)) { throw new ResubmissionTaskNotFoundException(sprintf( 'Task not found. Task-ID: %s - Resubmission-ID: %s', $taskId, $resubmissionId )); } $this->db->beginTransaction(); try { // Aufgabe löschen $sql = 'DELETE FROM `aufgabe` WHERE `id` = :task_id LIMIT 1 '; $this->db->perform($sql, ['task_id' => $taskId]); // Verknüpfung zur Wiedervorlage löschen $sql = 'DELETE FROM `wiedervorlage_aufgabe` WHERE `task_id` = :task_id AND `resubmission_id` = :resubmission_id LIMIT 1 '; $this->db->perform($sql, [ 'resubmission_id' => $resubmissionId, 'task_id' => $taskId, ]); $this->db->commit(); } catch (DatabaseExceptionInterface $exception) { $this->db->rollBack(); throw $exception; } } /** * Ermittelt alle Aufgaben die das Verschieben einer Wiedervorlage blockieren * * @param int $resubmissionId * @param int $targetStageId * * @return array Empty array if none item is blocking */ public function getBlockingTasksForTargetStage($resubmissionId, $targetStageId) { $resubmissionId = (int)$resubmissionId; $targetStageId = (int)$targetStageId; $tasks = $this->taskGateway->getTasksByResubmission($resubmissionId); $blocking = []; foreach ($tasks as $task) { if ($task['state'] === ResubmissionTaskData::STATE_COMPLETED) { continue; // Aufgabe ist bereits abgeschlossen > Aufgabe darf in jede Stage geschoben werden } if ($task['required_completion_stage_id'] === 0) { continue; // Aufgabe hat keine Fertigstellungs-Stage hinterlegt > Aufgabe darf in jede Stage geschoben werden } $distance = $this->resubmissionGateway->getDistanceBetweenStages( $targetStageId, $task['required_completion_stage_id'] ); if ($distance <= 0) { $blocking[] = [ 'id' => $task['id'], 'title' => $task['title'], 'state' => $task['state'], ]; } } return $blocking; } /** * Prüft ob eine Aufgabe in die Target-Stage wecheln darf * * @param int $currentStageId ID der Stage von der aus verschoben wird * @param int $targetStageId ID der Stage in die verschoben werden soll * @param string $targetState Aufgaben-Status der zugewiesen soll bzw. aktuell gesetzt ist * * @throws InvalidArgumentException * * @return bool true = Aufgabe darf auf Target-Stage wechseln * false = Aufgabe muss abgeschlossen sein, um auf die Target-Stage wechseln zu dürfen */ private function isTaskStageChangeAllowed($currentStageId, $targetStageId, $targetState) { $currentStageId = (int)$currentStageId; $targetStageId = (int)$targetStageId; if (!in_array($targetState, ResubmissionTaskData::getValidStates(), true)) { throw new InvalidArgumentException(sprintf('Target state is invalid: "%s"', $targetState)); } // Aufgabe auf abgeschlossen stellen => Immer OK; solange die Aufgabe existiert if ($targetState === ResubmissionTaskData::STATE_COMPLETED) { return true; } // Es ist keine Stage-ID festgelegt bei der die Aufgabe abgeschlossen sein muss // > Alles Roger, solange die Aufgabe existiert if ($targetStageId === 0) { return true; } $distance = $this->resubmissionGateway->getDistanceBetweenStages($currentStageId, $targetStageId); return $distance > 0; } /** * @param string $state * * @return string|null */ private function translateStateToDbValue($state) { $dbValue = null; switch ($state) { case ResubmissionTaskData::STATE_COMPLETED: $dbValue = 'abgeschlossen'; break; case ResubmissionTaskData::STATE_PROCESSING: $dbValue = 'inbearbeitung'; break; case ResubmissionTaskData::STATE_OPEN: $dbValue = 'offen'; break; } return $dbValue; } /** * @param string $priority * * @return int|null */ private function translatePriorityToDbValue($priority) { $dbValue = null; switch ($priority) { case ResubmissionTaskData::PRIORITY_HIGH: $dbValue = 1; break; case ResubmissionTaskData::PRIORITY_LOW: $dbValue = -1; break; case ResubmissionTaskData::PRIORITY_MEDIUM: $dbValue = 0; break; } return $dbValue; } }