|
|
|
@@ -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 '<div class="border-bottom py-2"><strong>' . e($entry['technician_name']) . '</strong> · ' . e($entry['work_date']) . ' · ' . e(number_format((float)$entry['hours'], 2)) . 'h<div class="small text-muted">' . e((string)($entry['notes'] ?? '')) . '</div>' . (can('time_entries.record') ? '<a class="small" href="/?route=time_entry&id=' . (int)$entry['id'] . '">Correct or void</a>' : '') . '</div>';
|
|
|
|
|
if (can('time_entries.record')) { echo '<hr><form method="post" class="row g-2"><input type="hidden" name="_csrf" value="' . e(csrf_token()) . '"><input type="hidden" name="action" value="time">'; if ($user['role_name'] !== 'Technician') { echo '<div class="col-md-4"><select class="form-select" name="technician_id" required><option value="">Technician</option>'; foreach ($technicians as $technician) echo '<option value="' . (int)$technician['id'] . '">' . e($technician['name']) . '</option>'; echo '</select></div>'; } echo '<div class="col-md-4"><label class="form-label">Date performed</label><input class="form-control" type="date" name="work_date" value="' . e(date('Y-m-d')) . '" required></div><div class="col-md-4"><input class="form-control" type="number" step="0.01" min="0.01" name="hours" placeholder="Hours"></div><div class="col-md-4 form-check pt-2"><input class="form-check-input" type="checkbox" name="counts_toward_sla" value="1" id="sla-time" checked><label class="form-check-label" for="sla-time">Counts toward SLA</label></div><div class="col-12"><label class="form-label">Technician notes / Work performed</label><textarea class="form-control" name="notes" rows="4" placeholder="Describe the work performed"></textarea></div><div class="col-12"><button class="btn btn-outline-primary">Add time</button></div></form>'; }
|
|
|
|
|
echo '</div></div></div><div class="col-lg-4"><div class="card mb-4"><div class="card-body"><h2 class="h5">Status</h2><form method="post"><input type="hidden" name="_csrf" value="' . e(csrf_token()) . '"><input type="hidden" name="action" value="status"><select class="form-select mb-2" name="status">';
|
|
|
|
|
foreach ((new \App\Domain\Jobcard\StatusTransitionValidator())->allowedFrom($jobcard['status']) as $status) if ($status !== 'closed' || can('jobcards.close')) echo '<option value="' . e($status) . '"' . ($status === $jobcard['status'] ? ' selected' : '') . '>' . e(ucwords(str_replace('_', ' ', $status))) . '</option>';
|
|
|
|
|
foreach ((new \App\Domain\Jobcard\StatusTransitionValidator())->allowedFrom($jobcard['status']) as $status) if (($status !== 'closed' || can('jobcards.close')) && ($jobcard['status'] !== 'closed' || $status === 'closed' || can('jobcards.reopen'))) echo '<option value="' . e($status) . '"' . ($status === $jobcard['status'] ? ' selected' : '') . '>' . e(ucwords(str_replace('_', ' ', $status))) . '</option>';
|
|
|
|
|
echo '</select><button class="btn btn-outline-primary w-100">Update status</button></form></div></div><div class="card"><div class="card-body"><h2 class="h5">Assigned technicians</h2>';
|
|
|
|
|
if (!$assigned) echo '<p class="text-muted">No technicians assigned.</p>'; foreach ($assigned as $assignment) echo '<div class="py-1">' . e($assignment['name']) . '</div>';
|
|
|
|
|
if (can('jobcards.assign')) { echo '<hr><form method="post"><input type="hidden" name="_csrf" value="' . e(csrf_token()) . '"><input type="hidden" name="action" value="assign"><select class="form-select mb-2" name="technician_id"><option value="">Select technician</option>'; foreach ($technicians as $technician) echo '<option value="' . (int)$technician['id'] . '">' . e($technician['name']) . '</option>'; echo '</select><button class="btn btn-outline-primary w-100">Assign</button></form>'; }
|
|
|
|
|