145 lines
6.6 KiB
PHP
145 lines
6.6 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
require_once __DIR__ . '/../app/Domain/Jobcard/AssignmentValidator.php';
|
|
require_once __DIR__ . '/../app/Domain/Jobcard/TimeEntryCommand.php';
|
|
|
|
use App\Domain\Jobcard\AssignmentValidator;
|
|
use App\Domain\Jobcard\TimeEntryCommand;
|
|
|
|
function assignment_time_entry_assert_same(mixed $expected, mixed $actual, string $message): void
|
|
{
|
|
if ($expected !== $actual) {
|
|
throw new RuntimeException($message . "\nExpected: " . var_export($expected, true) . "\nActual: " . var_export($actual, true));
|
|
}
|
|
}
|
|
|
|
$assignment = (new AssignmentValidator())->validate([
|
|
'jobcard_id' => '12',
|
|
'user_ids' => ['7', 9, '7'],
|
|
]);
|
|
assignment_time_entry_assert_same(true, $assignment['valid'], 'Valid assignment payloads should be accepted.');
|
|
assignment_time_entry_assert_same(12, $assignment['jobcard_id'], 'Jobcard IDs should normalize to integers.');
|
|
assignment_time_entry_assert_same([7, 9], $assignment['user_ids'], 'Technician IDs should normalize and de-duplicate.');
|
|
assignment_time_entry_assert_same([], $assignment['errors'], 'Valid assignment payloads should not contain errors.');
|
|
|
|
$invalidJobcard = (new AssignmentValidator())->validate(['jobcard_id' => 0, 'user_ids' => [7]]);
|
|
assignment_time_entry_assert_same(false, $invalidJobcard['valid'], 'Jobcard IDs must be positive integers.');
|
|
if (!isset($invalidJobcard['errors']['jobcard_id'])) {
|
|
throw new RuntimeException('Invalid jobcard IDs should produce a jobcard_id error.');
|
|
}
|
|
|
|
$invalidTechnicians = (new AssignmentValidator())->validate([
|
|
'jobcard_id' => 12,
|
|
'user_ids' => [7, '0', true],
|
|
]);
|
|
assignment_time_entry_assert_same(false, $invalidTechnicians['valid'], 'Every technician ID must be a positive integer.');
|
|
if (!isset($invalidTechnicians['errors']['user_ids'])) {
|
|
throw new RuntimeException('Invalid technician assignment payloads should produce a user_ids error.');
|
|
}
|
|
|
|
$missingTechnicians = (new AssignmentValidator())->validate(['jobcard_id' => 12]);
|
|
assignment_time_entry_assert_same(false, $missingTechnicians['valid'], 'At least one assigned technician is required.');
|
|
if (!isset($missingTechnicians['errors']['user_ids'])) {
|
|
throw new RuntimeException('Missing technician assignments should produce a user_ids error.');
|
|
}
|
|
|
|
$timeEntry = (new TimeEntryCommand())->validate([
|
|
'jobcard_id' => '12',
|
|
'technician_id' => '7',
|
|
'work_date' => '2026-09-01',
|
|
'start_time' => '09:00',
|
|
'end_time' => '11:30',
|
|
'notes' => ' Replaced cable ',
|
|
'counts_toward_sla' => '0',
|
|
]);
|
|
assignment_time_entry_assert_same(true, $timeEntry['valid'], 'Valid time-entry commands should be accepted.');
|
|
assignment_time_entry_assert_same(12, $timeEntry['jobcard_id'], 'Time-entry jobcard IDs should normalize to integers.');
|
|
assignment_time_entry_assert_same(7, $timeEntry['technician_id'], 'Technician IDs should normalize to integers.');
|
|
assignment_time_entry_assert_same(2.5, $timeEntry['hours'], 'Start/end times should calculate normalized hours.');
|
|
assignment_time_entry_assert_same('Replaced cable', $timeEntry['notes'], 'Time-entry notes should be trimmed.');
|
|
assignment_time_entry_assert_same(false, $timeEntry['counts_toward_sla'], 'Boolean-like SLA values should normalize to booleans.');
|
|
assignment_time_entry_assert_same([], $timeEntry['errors'], 'Valid time-entry commands should not contain errors.');
|
|
|
|
$manualEntry = (new TimeEntryCommand())->validate([
|
|
'jobcard_id' => 12,
|
|
'technician_id' => 7,
|
|
'work_date' => '2026-09-02',
|
|
'hours' => '1.255',
|
|
]);
|
|
assignment_time_entry_assert_same(true, $manualEntry['valid'], 'Positive manual hours should be accepted without times.');
|
|
assignment_time_entry_assert_same(1.26, $manualEntry['hours'], 'Manual hours should reuse time-entry rounding.');
|
|
assignment_time_entry_assert_same(true, $manualEntry['counts_toward_sla'], 'SLA counting should default to true.');
|
|
|
|
$invalidIds = (new TimeEntryCommand())->validate([
|
|
'jobcard_id' => -1,
|
|
'technician_id' => '0',
|
|
'work_date' => '2026-09-02',
|
|
'hours' => 1,
|
|
]);
|
|
assignment_time_entry_assert_same(false, $invalidIds['valid'], 'Time-entry IDs must be positive integers.');
|
|
if (!isset($invalidIds['errors']['jobcard_id'], $invalidIds['errors']['technician_id'])) {
|
|
throw new RuntimeException('Invalid time-entry IDs should produce field errors.');
|
|
}
|
|
|
|
$ambiguousDuration = (new TimeEntryCommand())->validate([
|
|
'jobcard_id' => 12,
|
|
'technician_id' => 7,
|
|
'work_date' => '2026-09-02',
|
|
'hours' => 1,
|
|
'start_time' => '09:00',
|
|
'end_time' => '10:00',
|
|
]);
|
|
assignment_time_entry_assert_same(false, $ambiguousDuration['valid'], 'Manual hours and start/end times must be mutually exclusive.');
|
|
if (!isset($ambiguousDuration['errors']['time'])) {
|
|
throw new RuntimeException('Ambiguous duration input should produce a time error.');
|
|
}
|
|
|
|
$invalidEntry = (new TimeEntryCommand())->validate([
|
|
'jobcard_id' => 12,
|
|
'technician_id' => 7,
|
|
'work_date' => '2026-02-30',
|
|
'start_time' => '11:00',
|
|
'end_time' => '10:00',
|
|
]);
|
|
assignment_time_entry_assert_same(false, $invalidEntry['valid'], 'Invalid dates and time ranges should be rejected.');
|
|
if (!isset($invalidEntry['errors']['work_date'], $invalidEntry['errors']['time'])) {
|
|
throw new RuntimeException('TimeEntryValidator errors should be retained by the command.');
|
|
}
|
|
|
|
$longNotes = (new TimeEntryCommand())->validate([
|
|
'jobcard_id' => 12,
|
|
'technician_id' => 7,
|
|
'work_date' => '2026-09-02',
|
|
'hours' => 1,
|
|
'notes' => str_repeat('N', TimeEntryCommand::MAX_NOTES_LENGTH + 1),
|
|
]);
|
|
assignment_time_entry_assert_same(false, $longNotes['valid'], 'Overlong time-entry notes should be rejected.');
|
|
if (!isset($longNotes['errors']['notes'])) {
|
|
throw new RuntimeException('Overlong notes should produce a notes error.');
|
|
}
|
|
|
|
$invalidSlaFlag = (new TimeEntryCommand())->validate([
|
|
'jobcard_id' => 12,
|
|
'technician_id' => 7,
|
|
'work_date' => '2026-09-02',
|
|
'hours' => 1,
|
|
'counts_toward_sla' => 'sometimes',
|
|
]);
|
|
assignment_time_entry_assert_same(false, $invalidSlaFlag['valid'], 'Unknown SLA flag values should be rejected.');
|
|
if (!isset($invalidSlaFlag['errors']['counts_toward_sla'])) {
|
|
throw new RuntimeException('Invalid SLA flags should produce a counts_toward_sla error.');
|
|
}
|
|
|
|
$falseSlaFlag = (new TimeEntryCommand())->validate([
|
|
'jobcard_id' => 12,
|
|
'technician_id' => 7,
|
|
'work_date' => '2026-09-02',
|
|
'hours' => 1,
|
|
'counts_toward_sla' => ' false ',
|
|
]);
|
|
assignment_time_entry_assert_same(false, $falseSlaFlag['counts_toward_sla'], 'Recognized false-like SLA flags should normalize to false.');
|
|
assignment_time_entry_assert_same(true, $falseSlaFlag['valid'], 'Recognized false-like SLA flags should remain valid.');
|
|
|
|
printf("Assignment and time-entry tests: 12 passed\n");
|