feat: add administration reporting and correction services

This commit is contained in:
Marco0300
2026-09-01 21:03:38 +02:00
parent de2bf277c4
commit b983f90dcb
24 changed files with 1392 additions and 31 deletions
+30 -12
View File
@@ -1,29 +1,36 @@
<?php
declare(strict_types=1);
require_once __DIR__ . '/ReportFilters.php';
require_once __DIR__ . '/ReportDataMapper.php';
require_once __DIR__ . '/ReportAudience.php';
final class SlaReport
{
public function __construct(
private readonly ?ReportFilters $filters = null,
private readonly ?ReportDataMapper $mapper = null,
) {}
/** @param list<array<string, mixed>> $agreements
* @return list<array<string, mixed>>
*/
public function rows(array $agreements): array
public function rows(array $agreements, string $audience = ReportAudience::INTERNAL): array
{
ReportAudience::validate($audience);
$filters = $this->filters ?? new ReportFilters();
$mapper = $this->mapper ?? new ReportDataMapper();
$rows = [];
foreach ($agreements as $agreement) {
if (!$filters->matches($agreement)) continue;
$allocated = max(0.0, (float)($agreement['allocated_hours'] ?? 0));
$used = 0.0;
foreach ((array)($agreement['hours'] ?? []) as $hours) {
$used += max(0.0, (float)$hours);
}
foreach ((array)($agreement['hours'] ?? []) as $hours) $used += max(0.0, (float)$hours);
$used = round($used, 2);
$remaining = round(max(0.0, $allocated - $used), 2);
$percentage = $allocated > 0
? round(($used / $allocated) * 100, 2)
: ($used > 0 ? 100.0 : 0.0);
$status = $used > $allocated
? 'exceeded'
: ($percentage >= 90 ? 'critical' : ($percentage >= 75 ? 'warning' : 'within_limit'));
$rows[] = [
$percentage = $allocated > 0 ? round(($used / $allocated) * 100, 2) : ($used > 0 ? 100.0 : 0.0);
$status = $used > $allocated ? 'exceeded' : ($percentage >= 90 ? 'critical' : ($percentage >= 75 ? 'warning' : 'within_limit'));
$record = [
'client_id' => (int)($agreement['client_id'] ?? 0),
'client_name' => (string)($agreement['client_name'] ?? ''),
'allocated_hours' => $allocated,
@@ -32,8 +39,19 @@ final class SlaReport
'usage_percentage' => $percentage,
'status' => $status,
];
$rows[] = $audience === ReportAudience::CLIENT ? $mapper->clientSla($record) : $mapper->internalSla($record);
}
usort($rows, static fn (array $a, array $b): int => strcmp($a['client_name'], $b['client_name']) ?: $a['client_id'] <=> $b['client_id']);
usort($rows, static fn(array $a, array $b): int => strcmp((string)$a['client_name'], (string)$b['client_name']) ?: ((int)$a['client_id'] <=> (int)$b['client_id']));
return $rows;
}
public function build(array $agreements, string $audience = ReportAudience::INTERNAL): array
{
return $this->rows($agreements, $audience);
}
public function query(array $agreements, string $audience = ReportAudience::INTERNAL): array
{
return $this->rows($agreements, $audience);
}
}