feat(helpdesk): align module with core UI standards and fix KPI accuracy
- Add server-side ticket summary endpoint for exact KPI counts instead of client-side calculation from first 200 tickets - Extract summarizeTickets() as shared static method to avoid duplication - Replace custom .helpdesk-spinner CSS with core [aria-busy] pattern - Migrate settings connection-test feedback to showAsyncFlash() - Replace helpdesk-clickable-rows.js with delegated event handling - Remove unused helpdesk-search.js (dead code, never loaded) - Harmonize German wording: Debitoren → Kunden (8 i18n keys) - Add 6 PHPUnit tests for loadTicketSummary() Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -104,6 +104,57 @@ class DebitorDetailService
|
||||
return ['ok' => true, 'tickets' => $tickets];
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a summary of ticket KPIs for a customer (exact counts, not sampled).
|
||||
*
|
||||
* @return array{ok: bool, total?: int, open?: int, last_activity?: string, error?: string}
|
||||
*/
|
||||
public function loadTicketSummary(string $customerNo, string $customerName): array
|
||||
{
|
||||
$result = $this->loadTickets($customerNo, $customerName);
|
||||
|
||||
if (!$result['ok']) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return self::summarizeTickets($result['tickets'] ?? []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Aggregate ticket KPIs from a raw ticket array.
|
||||
*
|
||||
* Used by both the service method and the data endpoint (which has its own cache layer).
|
||||
*
|
||||
* @param array<int, array<string, mixed>> $tickets
|
||||
* @return array{ok: true, total: int, open: int, last_activity: string}
|
||||
*/
|
||||
public static function summarizeTickets(array $tickets): array
|
||||
{
|
||||
$closedStates = ['Erledigt', 'Resolved', 'Closed', 'Geschlossen'];
|
||||
|
||||
$openCount = 0;
|
||||
$lastActivity = '';
|
||||
|
||||
foreach ($tickets as $ticket) {
|
||||
$state = (string) ($ticket['Ticket_State'] ?? '');
|
||||
if (!in_array($state, $closedStates, true)) {
|
||||
$openCount++;
|
||||
}
|
||||
|
||||
$activityDate = (string) ($ticket['Last_Activity_Date'] ?? '');
|
||||
if ($activityDate !== '' && $activityDate !== '0001-01-01T00:00:00Z' && $activityDate > $lastActivity) {
|
||||
$lastActivity = $activityDate;
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'ok' => true,
|
||||
'total' => count($tickets),
|
||||
'open' => $openCount,
|
||||
'last_activity' => $lastActivity,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Load activity log for a ticket (for async data endpoint).
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user