feat: complete jobcard management workflows and UI
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/ReportFilters.php';
|
||||
require_once __DIR__ . '/ReportDataMapper.php';
|
||||
require_once __DIR__ . '/ReportQuery.php';
|
||||
require_once __DIR__ . '/ReportAudience.php';
|
||||
|
||||
/** Deterministic technician workload totals, with a client-safe projection. */
|
||||
final class TechnicianWorkloadReport implements ReportQuery
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ?ReportFilters $filters = null,
|
||||
private readonly ?ReportDataMapper $mapper = null,
|
||||
) {}
|
||||
|
||||
/** @param list<array<string,mixed>> $rows @return list<array<string,mixed>> */
|
||||
public function build(array $rows, string $audience = ReportAudience::INTERNAL): array
|
||||
{
|
||||
ReportAudience::validate($audience);
|
||||
$filters = $this->filters ?? new ReportFilters();
|
||||
$totals = [];
|
||||
foreach ($rows as $row) {
|
||||
if (!$filters->matches($row)) continue;
|
||||
$technicianId = (int)($row['technician_id'] ?? 0);
|
||||
$clientId = (int)($row['client_id'] ?? 0);
|
||||
$key = $audience === ReportAudience::CLIENT ? 'client:' . $clientId : 'technician:' . $technicianId;
|
||||
if (!isset($totals[$key])) {
|
||||
$totals[$key] = $audience === ReportAudience::CLIENT
|
||||
? ['client_id' => $clientId, 'client_name' => (string)($row['client_name'] ?? ''), 'hours' => 0.0, 'sla_hours' => 0.0]
|
||||
: ['technician_id' => $technicianId, 'technician_name' => (string)($row['technician_name'] ?? ''), 'hours' => 0.0, 'sla_hours' => 0.0];
|
||||
}
|
||||
$hours = max(0.0, (float)($row['hours'] ?? 0));
|
||||
$totals[$key]['hours'] += $hours;
|
||||
if (!empty($row['counts_toward_sla'])) $totals[$key]['sla_hours'] += $hours;
|
||||
}
|
||||
$result = array_values($totals);
|
||||
foreach ($result as &$item) {
|
||||
$item['hours'] = round($item['hours'], 2);
|
||||
$item['sla_hours'] = round($item['sla_hours'], 2);
|
||||
}
|
||||
unset($item);
|
||||
usort($result, static fn (array $a, array $b): int => array_key_exists('client_id', $a)
|
||||
? (strcmp((string)($a['client_name'] ?? ''), (string)($b['client_name'] ?? '')) ?: ((int)$a['client_id'] <=> (int)$b['client_id']))
|
||||
: (strcmp((string)($a['technician_name'] ?? ''), (string)($b['technician_name'] ?? '')) ?: ((int)$a['technician_id'] <=> (int)$b['technician_id'])));
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function query(array $rows, string $audience = ReportAudience::INTERNAL): array { return $this->build($rows, $audience); }
|
||||
}
|
||||
Reference in New Issue
Block a user