52 lines
3.4 KiB
PHP
52 lines
3.4 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
require_once __DIR__ . '/../app/Domain/Client/ContactEditCommand.php';
|
|
require_once __DIR__ . '/../app/Domain/Reporting/ClientHistoryService.php';
|
|
require_once __DIR__ . '/../app/Domain/Jobcard/TimeEntryCorrectionCommand.php';
|
|
|
|
use App\Domain\Client\ContactEditCommand;
|
|
use App\Domain\Reporting\ClientHistoryService;
|
|
use App\Domain\Jobcard\TimeEntryCorrectionCommand;
|
|
|
|
function domain_command_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));
|
|
}
|
|
|
|
$contacts = [
|
|
['id' => 1, 'client_id' => 7, 'name' => 'Jane', 'email' => 'jane@example.test', 'is_primary' => true],
|
|
['id' => 2, 'client_id' => 7, 'name' => 'John', 'email' => 'john@example.test', 'is_primary' => false],
|
|
];
|
|
$contactCommand = new ContactEditCommand();
|
|
$edit = $contactCommand->validateEdit(2, ['client_id' => 7, 'name' => ' John Smith ', 'is_primary' => 'yes'], $contacts);
|
|
domain_command_assert_same(true, $edit['valid'], 'A contact edit should validate.');
|
|
domain_command_assert_same([1], $edit['replace_primary_contact_ids'], 'Promoting an edited contact should demote the old primary.');
|
|
$delete = $contactCommand->validateDelete(1, $contacts);
|
|
domain_command_assert_same(true, $delete['valid'], 'A primary contact may be deleted when a replacement exists.');
|
|
domain_command_assert_same(2, $delete['replacement_primary_contact_id'], 'Deleting the primary should nominate a replacement.');
|
|
$last = $contactCommand->validateDelete(2, [['id' => 2, 'client_id' => 7, 'is_primary' => true]]);
|
|
domain_command_assert_same(false, $last['valid'], 'Deleting the only contact must be rejected.');
|
|
|
|
$history = new ClientHistoryService();
|
|
$rows = [
|
|
['id' => 2, 'client_id' => 7, 'changed_at' => '2026-09-03', 'to_status' => 'closed'],
|
|
['id' => 1, 'client_id' => 8, 'changed_at' => '2026-09-02', 'to_status' => 'open'],
|
|
['id' => 3, 'client_id' => 7, 'changed_at' => '2026-10-01', 'to_status' => 'open'],
|
|
];
|
|
domain_command_assert_same([2], array_column($history->filter($rows, ['client_id' => 7, 'date_to' => '2026-09-30']), 'id'), 'History filtering should apply client and date bounds.');
|
|
|
|
$correction = new TimeEntryCorrectionCommand();
|
|
$existing = ['id' => 9, 'jobcard_id' => 12, 'technician_id' => 4, 'work_date' => '2026-09-01', 'hours' => 2, 'notes' => 'old', 'counts_toward_sla' => true, 'voided' => false];
|
|
$fixed = $correction->validateCorrection($existing, ['hours' => '3.25', 'notes' => ' corrected ']);
|
|
domain_command_assert_same(true, $fixed['valid'], 'A time correction should validate against the existing entry.');
|
|
domain_command_assert_same(3.25, $fixed['entry']['hours'], 'A time correction should normalize replacement hours.');
|
|
domain_command_assert_same(12, $fixed['entry']['jobcard_id'], 'A correction must retain the existing jobcard.');
|
|
$void = $correction->validateVoid($existing, ['reason' => 'Duplicate entry']);
|
|
domain_command_assert_same(true, $void['valid'], 'Voiding should require and retain a reason.');
|
|
domain_command_assert_same('void', $void['action'], 'Voiding should be an explicit logical action.');
|
|
$voided = $correction->validateVoid([...$existing, 'voided' => true], ['reason' => 'again']);
|
|
domain_command_assert_same(false, $voided['valid'], 'An already voided entry cannot be voided twice.');
|
|
|
|
printf("Domain command/service tests: 10 passed\n");
|