35 lines
4.4 KiB
PHP
35 lines
4.4 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
$root = dirname(__DIR__);
|
|
$schema = file_get_contents($root . '/database/schema.sql');
|
|
$upgrade = file_get_contents($root . '/database/upgrade.sql');
|
|
$front = file_get_contents($root . '/public/index.php');
|
|
$validator = file_get_contents($root . '/app/Domain/Jobcard/StatusTransitionValidator.php');
|
|
if ($schema === false || $upgrade === false || $front === false || $validator === false) throw new RuntimeException('Fixtures must be readable.');
|
|
function jobcard_feature_assert(bool $ok, string $message): void { if (!$ok) throw new RuntimeException($message); }
|
|
jobcard_feature_assert(str_contains($schema, "('jobcards.reopen', 'Reopen closed jobcards')"), 'Fresh schema must seed jobcards.reopen.');
|
|
jobcard_feature_assert(str_contains($upgrade, "('jobcards.reopen', 'Reopen closed jobcards')"), 'Upgrade must seed jobcards.reopen.');
|
|
jobcard_feature_assert(str_contains($front, "if (\$locked['status'] === 'closed' && \$to !== 'closed') require_permission('jobcards.reopen');"), 'Reopening must require jobcards.reopen.');
|
|
jobcard_feature_assert(str_contains($validator, "'closed' => ['in_progress']"), 'Closed jobcards must support reopening to in progress.');
|
|
|
|
jobcard_feature_assert(str_contains($front, "if (\$to === 'closed') require_permission('jobcards.close');"), 'Closing a jobcard must require jobcards.close.');
|
|
jobcard_feature_assert(str_contains($front, "name=\"q\"") && str_contains($front, "name=\"status_filter\""), 'Jobcards page must expose search and status filters.');
|
|
jobcard_feature_assert(str_contains($front, "j.status <> 'closed'"), 'Default Jobcards filter must exclude closed records.');
|
|
jobcard_feature_assert(str_contains($front, "j.status = 'closed'"), 'Closed filter must explicitly select closed records.');
|
|
jobcard_feature_assert(str_contains($front, 'All clients') && str_contains($front, '$reportClient'), 'Reports must use a client-name dropdown.');
|
|
jobcard_feature_assert(str_contains($front, 'format=xls&detail=1'), 'Reports must expose detailed XLS export.');
|
|
jobcard_feature_assert(str_contains($front, "if (\$user['role_name'] === 'Technician') {") && str_contains($front, '$reportClientsStmt->execute'), 'Report client dropdown must bind parameters only on the technician prepared-query branch.');
|
|
jobcard_feature_assert(str_contains($front, '$reportClientsStmt->execute([(int)$user[\'id\']])'), 'Technician report client lookup must use a positional bound parameter.');
|
|
foreach (['Technician notes / Work performed', 'totalReportHours'] as $heading) jobcard_feature_assert(str_contains($front, $heading), "Detailed report must include {$heading}.");
|
|
jobcard_feature_assert(!str_contains($front, 'name=\"technician_notes\"') && !str_contains($front, 'Hours notes'), 'Jobcards must use time-entry technician notes only.');
|
|
jobcard_feature_assert(str_contains($front, 'remaining_hours') && str_contains($front, 'SLA hours remaining'), 'Client pages must show remaining SLA hours.');
|
|
jobcard_feature_assert(str_contains($front, 'j.client_id = :client') && str_contains($front, 'te.counts_toward_sla = 1'), 'Client SLA usage must aggregate active-period SLA time entries regardless of jobcard status.');
|
|
jobcard_feature_assert(str_contains($front, "['TOTAL HOURS'") && str_contains($front, 'totalReportHours'), 'Detailed report downloads must include total hours.');
|
|
jobcard_feature_assert(str_contains($front, "if (\$route === 'settings')") && str_contains($front, "role_name'] ?? '') !== 'Administrator'"), 'Branding settings must be Administrator-only.');
|
|
jobcard_feature_assert(str_contains($front, "if (\$route === 'search')") && str_contains($front, 'attachments') && str_contains($front, 'client_contacts'), 'Global search must cover jobcards, clients, contacts and attachments.');
|
|
jobcard_feature_assert(str_contains($front, "if (\$route === 'saved_filter_save')") && str_contains($front, 'saved_filters'), 'Users must be able to save Jobcards filters.');
|
|
jobcard_feature_assert(str_contains($front, 'LIMIT 25 OFFSET') && str_contains($front, 'LIMIT 50 OFFSET'), 'Large list pages must use bounded pagination.');
|
|
jobcard_feature_assert(str_contains($front, 'technician-bottom-nav') && str_contains($front, 'sidebarMenu'), 'Mobile navigation controls must be present.');
|
|
jobcard_feature_assert(str_contains($front, "if (\$route === 'email_settings')") && str_contains($front, 'smtp_password_ciphertext'), 'Administrator email settings must include encrypted SMTP credential storage.');
|