Files
breadcrumb-the-shire/modules/helpdesk/pages/helpdesk/debitor-summary-data().php
fs aee9cb10f3 feat(helpdesk): add dashboards, communication feed, settings UI and fix routing
Add support/sales/controlling dashboards with KPIs, trend charts and
risk indicators. Add debitor communication timeline, contact filters,
system recommendations engine, and configurable controlling risk rules.

Rename search→index to fix query-string preservation on back navigation.
Remove fake escalation rate metric, add KPI info tooltips, and switch
trend chart colors to red (created) / green (closed) for clarity.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-04 18:34:03 +02:00

83 lines
2.5 KiB
PHP

<?php
use MintyPHP\Module\Helpdesk\HelpdeskAuthorizationPolicy;
use MintyPHP\Module\Helpdesk\Service\DebitorCacheControl;
use MintyPHP\Module\Helpdesk\Service\DebitorDetailService;
use MintyPHP\Http\SessionStoreInterface;
use MintyPHP\Router;
use MintyPHP\Support\Guard;
Guard::requireLogin();
Guard::requireAbilityOrForbidden(HelpdeskAuthorizationPolicy::ABILITY_ACCESS);
gridRequireGetRequest();
$request = requestInput();
$customerNo = trim((string) $request->query('customerNo', ''));
$customerName = trim((string) $request->query('customerName', ''));
$refreshRequested = DebitorCacheControl::parseRefreshFlag($request->query('refresh', ''));
if ($customerNo === '' || $customerName === '') {
http_response_code(400);
Router::json(['ok' => false, 'error' => 'Missing parameters']);
return;
}
// Reuse session cache from tickets endpoint when available (avoids duplicate OData call)
$sessionStore = app(SessionStoreInterface::class);
$session = $sessionStore->all();
$tenantScope = DebitorCacheControl::resolveTenantScope($session);
if ($refreshRequested) {
DebitorCacheControl::invalidateDebitorCaches($sessionStore, $tenantScope, $customerNo, true);
}
$cacheKey = DebitorCacheControl::ticketsKey($tenantScope, $customerNo);
$cacheTtl = DebitorCacheControl::TTL_STANDARD_SECONDS;
$cached = $sessionStore->get($cacheKey);
if (!$refreshRequested && is_array($cached) && isset($cached['fetched_at']) && (time() - (int) $cached['fetched_at']) < $cacheTtl) {
$cachedTickets = $cached['tickets'] ?? [];
if (!is_array($cachedTickets)) {
$cachedTickets = [];
}
$summary = DebitorDetailService::summarizeTickets($cachedTickets);
$summary['meta'] = [
'cache_used' => true,
'cache_bypassed' => false,
'cache_refreshed' => false,
];
Router::json($summary);
return;
}
// Cache miss — load via service, populate cache, then summarize
$service = app(DebitorDetailService::class);
$ticketsResult = $service->loadTickets($customerNo, $customerName);
if (!($ticketsResult['ok'] ?? false)) {
Router::json(['ok' => false, 'error' => $ticketsResult['error'] ?? 'Failed to load tickets']);
return;
}
$tickets = $ticketsResult['tickets'] ?? [];
if (!is_array($tickets)) {
$tickets = [];
}
$sessionStore->set($cacheKey, [
'tickets' => $tickets,
'fetched_at' => time(),
]);
$summary = DebitorDetailService::summarizeTickets($tickets);
$summary['meta'] = [
'cache_used' => false,
'cache_bypassed' => $refreshRequested,
'cache_refreshed' => $refreshRequested,
];
Router::json($summary);