feat: complete jobcard client management foundation

This commit is contained in:
Marco0300
2026-09-01 20:43:24 +02:00
parent 168c15c6ae
commit de2bf277c4
34 changed files with 2072 additions and 74 deletions
+60
View File
@@ -0,0 +1,60 @@
<?php
declare(strict_types=1);
require_once __DIR__ . '/../app/Domain/Client/ClientUpdateCommand.php';
require_once __DIR__ . '/../app/Domain/Client/ContactUpdateCommand.php';
use App\Domain\Client\ClientUpdateCommand;
use App\Domain\Client\ContactUpdateCommand;
function client_crud_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));
}
}
$clients = [
['id' => 7, 'name' => 'Acme IT', 'status' => 'active'],
['id' => 9, 'name' => 'Other Client', 'status' => 'inactive'],
];
$clientCommand = new ClientUpdateCommand();
$created = $clientCommand->validateForCreate([
'name' => ' New Client ',
'support_email' => ' NEW@EXAMPLE.TEST ',
], $clients);
client_crud_assert_same(true, $created['valid'], 'A unique client should be accepted for creation.');
client_crud_assert_same('New Client', $created['name'], 'Client names should be normalized before duplicate checks.');
client_crud_assert_same('new@example.test', $created['support_email'], 'Client email should be normalized.');
$duplicate = $clientCommand->validateForCreate(['name' => ' acme it '], $clients);
client_crud_assert_same(false, $duplicate['valid'], 'Normalized duplicate client names should be rejected.');
if (!isset($duplicate['errors']['name'])) throw new RuntimeException('Duplicate client names should produce a name error.');
$edited = $clientCommand->validateForEdit(7, ['name' => ' ACME IT ', 'status' => 'active'], $clients);
client_crud_assert_same(true, $edited['valid'], 'Editing a client should ignore its own duplicate row.');
$deactivated = $clientCommand->validateDeactivate(['id' => 7, 'status' => 'active']);
client_crud_assert_same(['valid' => true, 'id' => 7, 'status' => 'inactive', 'errors' => []], $deactivated, 'Active clients should be deactivatable.');
$reactivated = $clientCommand->validateReactivate(['id' => 9, 'status' => 'inactive']);
client_crud_assert_same(['valid' => true, 'id' => 9, 'status' => 'active', 'errors' => []], $reactivated, 'Inactive clients should be reactivatable.');
$contacts = [
['id' => 11, 'client_id' => 7, 'name' => 'Jane Doe', 'email' => 'jane@example.test', 'is_primary' => true],
];
$contactCommand = new ContactUpdateCommand();
$contact = $contactCommand->validateForCreate([
'client_id' => '7', 'name' => ' John Doe ', 'email' => ' JOHN@EXAMPLE.TEST ', 'is_primary' => 'yes',
], $contacts);
client_crud_assert_same(true, $contact['valid'], 'A unique contact should be accepted.');
client_crud_assert_same(7, $contact['client_id'], 'Contact client IDs should normalize to integers.');
client_crud_assert_same(true, $contact['is_primary'], 'Primary flags should normalize to booleans.');
client_crud_assert_same([11], $contact['replace_primary_contact_ids'], 'Promoting a contact should identify the prior primary contact.');
$contactDuplicate = $contactCommand->validateForCreate(['client_id' => 7, 'name' => ' jane doe ', 'email' => 'other@example.test'], $contacts);
client_crud_assert_same(false, $contactDuplicate['valid'], 'Duplicate contacts should be rejected after normalization.');
if (!isset($contactDuplicate['errors']['name'])) throw new RuntimeException('Duplicate contact names should produce a name error.');
$contactDisplay = $contactCommand->display(['id' => 11, 'client_id' => 7, 'name' => 'Jane Doe', 'email' => 'jane@example.test', 'phone' => null, 'is_primary' => true, 'password' => 'secret', 'credentials' => 'token', 'internal_secret' => 'omit']);
client_crud_assert_same(['id' => 11, 'client_id' => 7, 'name' => 'Jane Doe', 'email' => 'jane@example.test', 'phone' => null, 'is_primary' => true], $contactDisplay, 'Contact display projections must exclude credentials and internal secrets.');
printf("Client CRUD tests: 10 passed\n");