Files
JobcardSystem/tests/ReportServicesFocusedTest.php
T

63 lines
3.6 KiB
PHP
Raw Normal View History

<?php
declare(strict_types=1);
require_once __DIR__ . '/../app/Domain/Reporting/ReportFilters.php';
require_once __DIR__ . '/../app/Domain/Reporting/ReportAudience.php';
require_once __DIR__ . '/../app/Domain/Reporting/ReportDataMapper.php';
require_once __DIR__ . '/../app/Domain/Reporting/ReportQuery.php';
require_once __DIR__ . '/../app/Domain/Reporting/HoursPerClientReport.php';
require_once __DIR__ . '/../app/Domain/Reporting/TechnicianWorkloadReport.php';
require_once __DIR__ . '/../app/Domain/Reporting/SlaReport.php';
require_once __DIR__ . '/../app/Domain/Reporting/PrintReportRenderer.php';
function report_services_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));
}
}
$filters = ReportFilters::fromArray([
'date_from' => '2026-09-01', 'date_to' => '2026-09-30', 'client_id' => 7,
'technician_id' => 4, 'status' => 'open', 'priority' => 'high', 'sla' => 'warning',
]);
$entries = [
['client_id' => 7, 'client_name' => 'Acme', 'technician_id' => 4, 'technician_name' => 'Tess', 'work_date' => '2026-09-10', 'status' => 'open', 'priority' => 'high', 'sla_status' => 'warning', 'hours' => 1.25],
['client_id' => 7, 'client_name' => 'Acme', 'technician_id' => 4, 'technician_name' => 'Tess', 'work_date' => '2026-09-11', 'status' => 'open', 'priority' => 'high', 'sla_status' => 'warning', 'hours' => 1.75],
['client_id' => 8, 'client_name' => 'Beta', 'technician_id' => 4, 'work_date' => '2026-09-12', 'status' => 'open', 'priority' => 'high', 'sla_status' => 'warning', 'hours' => 9],
];
report_services_assert_same(
[['client_id' => 7, 'client_name' => 'Acme', 'hours' => 3.0]],
(new HoursPerClientReport($filters))->build($entries, ReportAudience::CLIENT),
'Hours-per-client should apply the common filters before aggregation and return a client-safe projection.'
);
$workload = (new TechnicianWorkloadReport($filters))->build($entries, ReportAudience::INTERNAL);
report_services_assert_same(
[['technician_id' => 4, 'technician_name' => 'Tess', 'hours' => 3.0, 'sla_hours' => 0.0]],
$workload,
'Technician workload should aggregate filtered hours with deterministic internal fields.'
);
$clientWorkload = (new TechnicianWorkloadReport())->build($entries, ReportAudience::CLIENT);
report_services_assert_same(
[['client_id' => 7, 'client_name' => 'Acme', 'hours' => 3.0, 'sla_hours' => 0.0], ['client_id' => 8, 'client_name' => 'Beta', 'hours' => 9.0, 'sla_hours' => 0.0]],
$clientWorkload,
'Client workload rows should preserve client attribution without technician identity.'
);
$filtered = (new SlaReport(ReportFilters::fromArray(['sla' => 'critical'])))->build([
['client_id' => 1, 'client_name' => 'Acme', 'allocated_hours' => 10, 'hours' => [9]],
['client_id' => 2, 'client_name' => 'Beta', 'allocated_hours' => 10, 'hours' => [2]],
], ReportAudience::CLIENT);
report_services_assert_same(1, count($filtered), 'SLA status filtering should use the computed usage status.');
report_services_assert_same(1, $filtered[0]['client_id'], 'SLA status filtering should retain the critical agreement.');
$html = (new PrintReportRenderer())->renderRecords('Rows', [
['name' => '<b>Acme</b>', 'hours' => 3.0],
]);
if (!str_contains($html, 'application/pdf') || !str_contains($html, '&lt;b&gt;Acme&lt;/b&gt;') || !str_contains($html, '@page')) {
throw new RuntimeException('Print renderer should emit PDF-ready metadata, print CSS, and escaped record cells.');
}
printf("Focused report service tests: 5 passed\n");