Files
breadcrumb-the-shire/modules/helpdesk/pages/helpdesk/updates-data().php
fs da0abc824a feat(helpdesk): add software updates tracking with BC ticket integration
New Updates page in the Helpdesk module that fetches UPDATE/UPDATE-HF tickets
from Business Central (PBI_LV_Tickets) and allows assigning a domain and Gitea
link via a dialog. Ticket status (from BC) and assignment status (local) are
shown as separate columns with filters for both plus type and free-text search.
Assigned updates also appear on the domain detail page. Includes session-cached
BC fetch with refresh button, admin permissions, migration, and 16 unit tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 13:21:40 +02:00

99 lines
3.4 KiB
PHP

<?php
use MintyPHP\Http\SessionStoreInterface;
use MintyPHP\Module\Helpdesk\HelpdeskAuthorizationPolicy;
use MintyPHP\Module\Helpdesk\Service\UpdateService;
use MintyPHP\Router;
use MintyPHP\Support\Guard;
Guard::requireLogin();
Guard::requireAbilityOrForbidden(HelpdeskAuthorizationPolicy::ABILITY_UPDATES_VIEW);
gridRequireGetRequest();
use MintyPHP\Module\Helpdesk\Service\DebitorCacheControl;
$request = requestInput();
$filters = [
'status' => trim((string) $request->query('status', '')),
'category' => trim((string) $request->query('category', '')),
'ticket_state' => trim((string) $request->query('ticket_state', '')),
'search' => trim((string) $request->query('search', '')),
];
$sessionStore = app(SessionStoreInterface::class);
$session = $sessionStore->all();
$tenantId = (int) ($session['current_tenant']['id'] ?? 0);
$refreshRequested = DebitorCacheControl::parseRefreshFlag($request->query('refresh', ''));
if ($refreshRequested) {
$tenantScope = DebitorCacheControl::resolveTenantScope($session);
$sessionStore->remove(DebitorCacheControl::updateTicketsKey($tenantScope));
}
$service = app(UpdateService::class);
try {
$result = $service->getUpdatesList($tenantId, $filters);
} catch (\Throwable) {
Router::json(['rows' => [], 'total' => 0, 'error' => true]);
return;
}
$rows = $result['rows'] ?? [];
$debitorBaseUrl = lurl('helpdesk/debitor/');
$ticketBaseUrl = lurl('helpdesk/ticket/');
$formatBcDate = static function (string $raw): string {
$raw = trim($raw);
if ($raw === '') {
return '';
}
try {
return (new \DateTimeImmutable($raw))->format('d.m.Y H:i');
} catch (\Throwable) {
return $raw;
}
};
$preparedRows = [];
foreach ($rows as $row) {
$ticketNo = (string) ($row['ticket_no'] ?? '');
$status = (string) ($row['status'] ?? 'open');
$categoryCode = (string) ($row['category_code'] ?? '');
$debitorNo = (string) ($row['debitor_no'] ?? '');
$ticketState = (string) ($row['ticket_state'] ?? '');
$preparedRows[] = [
'ticket_no' => $ticketNo,
'ticket_url' => $ticketNo !== '' ? $ticketBaseUrl . rawurlencode($ticketNo) : '',
'ticket_description' => (string) ($row['ticket_description'] ?? ''),
'category_code' => $categoryCode,
'category_label' => UpdateService::categoryLabel($categoryCode),
'category_variant' => UpdateService::categoryVariant($categoryCode),
'debitor_no' => $debitorNo,
'debitor_name' => (string) ($row['debitor_name'] ?? ''),
'debitor_url' => $debitorNo !== '' ? $debitorBaseUrl . rawurlencode($debitorNo) : '',
'domain_no' => (string) ($row['domain_no'] ?? ''),
'domain_url' => (string) ($row['domain_url'] ?? ''),
'gitea_path' => (string) ($row['gitea_path'] ?? ''),
'notes' => (string) ($row['notes'] ?? ''),
'created_on' => $formatBcDate((string) ($row['created_on'] ?? '')),
'ticket_state' => $ticketState,
'ticket_state_label' => UpdateService::ticketStateLabel($ticketState),
'ticket_state_variant' => UpdateService::ticketStateVariant($ticketState),
'status' => $status,
'status_label' => UpdateService::statusLabel($status),
'status_variant' => UpdateService::statusVariant($status),
'local_id' => $row['local_id'] ?? null,
];
}
Router::json([
'rows' => $preparedRows,
'total' => count($preparedRows),
'truncated' => $result['truncated'] ?? false,
]);