diff --git a/app/Domain/Jobcard/StatusTransitionValidator.php b/app/Domain/Jobcard/StatusTransitionValidator.php index 063954a..f08e1ef 100644 --- a/app/Domain/Jobcard/StatusTransitionValidator.php +++ b/app/Domain/Jobcard/StatusTransitionValidator.php @@ -14,7 +14,7 @@ final class StatusTransitionValidator 'awaiting_client' => ['in_progress', 'completed'], 'awaiting_parts' => ['in_progress', 'completed'], 'completed' => ['closed'], - 'closed' => [], + 'closed' => ['in_progress'], ]; public function canTransition(string $from, string $to): bool diff --git a/database/schema.sql b/database/schema.sql index 9b73b20..7a1db94 100644 --- a/database/schema.sql +++ b/database/schema.sql @@ -247,6 +247,7 @@ INSERT IGNORE INTO permissions (name, description) VALUES ('jobcards.view', 'View jobcards'), ('jobcards.manage', 'Create and update jobcards'), ('jobcards.close', 'Close jobcards'), + ('jobcards.reopen', 'Reopen closed jobcards'), ('jobcards.assign', 'Assign technicians to jobcards'), ('jobcards.internal_notes', 'View and edit internal jobcard notes'), ('time_entries.record', 'Record technician time entries'), diff --git a/database/upgrade.sql b/database/upgrade.sql index de267c5..48a919d 100644 --- a/database/upgrade.sql +++ b/database/upgrade.sql @@ -92,6 +92,7 @@ INSERT IGNORE INTO permissions (name, description) VALUES ('technical.view', 'View client technical information'), ('technical.manage', 'Manage client technical information'), ('jobcards.close', 'Close jobcards'), + ('jobcards.reopen', 'Reopen closed jobcards'), ('credentials.view', 'View protected credentials'), ('credentials.manage', 'Manage protected credentials'), ('attachments.view', 'View jobcard attachments'), diff --git a/public/index.php b/public/index.php index bb8a871..c74635f 100644 --- a/public/index.php +++ b/public/index.php @@ -209,9 +209,11 @@ if ($route === 'jobcard') { $lockedStmt->execute(['id' => $jobcardId]); $locked = $lockedStmt->fetch(); if (!$locked) throw new RuntimeException('Jobcard no longer exists.'); + if ($locked['status'] === 'closed' && $to !== 'closed') require_permission('jobcards.reopen'); $now = date('Y-m-d H:i:s'); $completedAt = $to === 'completed' ? $now : ($locked['completed_at'] ?: null); $closedAt = $to === 'closed' ? $now : ($locked['closed_at'] ?: null); + if ($locked['status'] === 'closed' && $to === 'in_progress') { $completedAt = null; $closedAt = null; } if ($to === 'closed' && $completedAt === null) $completedAt = $now; $transition = (new \App\Domain\Jobcard\JobcardWorkflow())->validateTransition($locked['status'], $to, $completedAt, $closedAt); if (!$transition['valid']) { @@ -330,7 +332,7 @@ if ($route === 'jobcard') { foreach ($timeEntries as $entry) echo '
No technicians assigned.
'; foreach ($assigned as $assignment) echo '