forked from fa/breadcrumb-the-shire
227 lines
7.7 KiB
PHP
227 lines
7.7 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
namespace MintyPHP\Module\Helpdesk\Service;
|
||
|
|
|
||
|
|
use MintyPHP\Module\Helpdesk\Repository\HandoverRepository;
|
||
|
|
use MintyPHP\Module\Helpdesk\Repository\UpdateRepository;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Service for loading domain detail data (master data, customer, contract, handovers).
|
||
|
|
*
|
||
|
|
* Provides loadDomain() for the synchronous page load and loadDomainDetails()
|
||
|
|
* for the async data endpoint.
|
||
|
|
*/
|
||
|
|
class DomainDetailService
|
||
|
|
{
|
||
|
|
public function __construct(
|
||
|
|
private readonly BcODataGateway $bcODataGateway,
|
||
|
|
private readonly EffectiveHelpdeskSettingsService $settingsGateway,
|
||
|
|
private readonly HandoverRepository $handoverRepository,
|
||
|
|
private readonly ?UpdateRepository $updateRepository = null
|
||
|
|
) {
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Load domain master data (1 OData call).
|
||
|
|
*
|
||
|
|
* Used by the main page load — customer, contract, handovers loaded async.
|
||
|
|
*
|
||
|
|
* @api Called from domain($id) action
|
||
|
|
* @return array{status: string, domain?: array<string, mixed>, error?: string}
|
||
|
|
*/
|
||
|
|
public function loadDomain(string $domainNo): array
|
||
|
|
{
|
||
|
|
$domainNo = trim($domainNo);
|
||
|
|
if ($domainNo === '') {
|
||
|
|
return ['status' => 'not_found'];
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!$this->settingsGateway->isConfigured()) {
|
||
|
|
return ['status' => 'not_configured', 'error' => 'BC connection not configured'];
|
||
|
|
}
|
||
|
|
|
||
|
|
try {
|
||
|
|
$domain = $this->bcODataGateway->getDomain($domainNo);
|
||
|
|
} catch (\Throwable) {
|
||
|
|
return ['status' => 'error', 'error' => 'BC connection failed'];
|
||
|
|
}
|
||
|
|
|
||
|
|
if ($domain === null) {
|
||
|
|
return ['status' => 'not_found'];
|
||
|
|
}
|
||
|
|
|
||
|
|
return [
|
||
|
|
'status' => 'success',
|
||
|
|
'domain' => $domain,
|
||
|
|
];
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Load all detail data for a domain (for async data endpoint).
|
||
|
|
*
|
||
|
|
* @api Called from domain-detail-data endpoint
|
||
|
|
* @return array{
|
||
|
|
* ok: bool,
|
||
|
|
* customer?: array<string, mixed>|null,
|
||
|
|
* contract?: array<string, mixed>|null,
|
||
|
|
* handovers?: list<array<string, mixed>>,
|
||
|
|
* handover_stats?: array{total: int, draft: int, in_progress: int, completed: int, archived: int},
|
||
|
|
* related_domains?: list<array<string, mixed>>,
|
||
|
|
* error?: string
|
||
|
|
* }
|
||
|
|
*/
|
||
|
|
public function loadDomainDetails(string $domainNo, string $customerNo, int $tenantId): array
|
||
|
|
{
|
||
|
|
$domainNo = trim($domainNo);
|
||
|
|
$customerNo = trim($customerNo);
|
||
|
|
|
||
|
|
if ($domainNo === '') {
|
||
|
|
return ['ok' => false, 'error' => 'Missing domain number'];
|
||
|
|
}
|
||
|
|
|
||
|
|
$customer = null;
|
||
|
|
if ($customerNo !== '') {
|
||
|
|
try {
|
||
|
|
$customer = $this->bcODataGateway->getCustomer($customerNo);
|
||
|
|
} catch (\Throwable) {
|
||
|
|
// Best-effort — continue without customer data
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
$contract = $this->loadContractForDomain($domainNo);
|
||
|
|
|
||
|
|
$handovers = $this->handoverRepository->findByDomainNo($tenantId, $domainNo);
|
||
|
|
$handoverStats = $this->aggregateHandoverStats($handovers);
|
||
|
|
|
||
|
|
$relatedDomains = [];
|
||
|
|
if ($customerNo !== '') {
|
||
|
|
try {
|
||
|
|
$allCustomerDomains = $this->bcODataGateway->getDomainsForCustomer($customerNo);
|
||
|
|
$relatedDomains = array_values(array_filter(
|
||
|
|
$allCustomerDomains,
|
||
|
|
static fn (array $d): bool => trim((string) ($d['No'] ?? '')) !== $domainNo
|
||
|
|
));
|
||
|
|
} catch (\Throwable) {
|
||
|
|
// Best-effort — continue without related domains
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
$updates = [];
|
||
|
|
if ($this->updateRepository !== null) {
|
||
|
|
$updates = $this->prepareUpdatesForResponse(
|
||
|
|
$this->updateRepository->findByDomainNo($tenantId, $domainNo)
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
return [
|
||
|
|
'ok' => true,
|
||
|
|
'customer' => $customer,
|
||
|
|
'contract' => $contract,
|
||
|
|
'handovers' => $this->prepareHandoversForResponse($handovers),
|
||
|
|
'handover_stats' => $handoverStats,
|
||
|
|
'updates' => $updates,
|
||
|
|
'related_domains' => $relatedDomains,
|
||
|
|
];
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Load contract line info for a specific domain from BC.
|
||
|
|
*
|
||
|
|
* @return array<string, mixed>|null
|
||
|
|
*/
|
||
|
|
private function loadContractForDomain(string $domainNo): ?array
|
||
|
|
{
|
||
|
|
try {
|
||
|
|
$contractLines = $this->bcODataGateway->listDomainContractLines();
|
||
|
|
} catch (\Throwable) {
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
foreach ($contractLines as $line) {
|
||
|
|
$lineNo = trim((string) ($line['No'] ?? ''));
|
||
|
|
if ($lineNo === $domainNo) {
|
||
|
|
return [
|
||
|
|
'contract_type' => trim((string) ($line['PI_Header_Type'] ?? '')),
|
||
|
|
'contract_no' => trim((string) ($line['Header_No'] ?? '')),
|
||
|
|
'contract_description' => trim((string) ($line['PI_Header_Description'] ?? '')),
|
||
|
|
'header_state' => trim((string) ($line['PI_Header_State'] ?? '')),
|
||
|
|
'line_state' => trim((string) ($line['Line_State'] ?? '')),
|
||
|
|
];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @param list<array<string, mixed>> $handovers
|
||
|
|
* @return array{total: int, draft: int, in_progress: int, completed: int, archived: int}
|
||
|
|
*/
|
||
|
|
private function aggregateHandoverStats(array $handovers): array
|
||
|
|
{
|
||
|
|
$stats = ['total' => 0, 'draft' => 0, 'in_progress' => 0, 'completed' => 0, 'archived' => 0];
|
||
|
|
|
||
|
|
foreach ($handovers as $handover) {
|
||
|
|
$stats['total']++;
|
||
|
|
$status = trim((string) ($handover['status'] ?? ''));
|
||
|
|
if (isset($stats[$status])) {
|
||
|
|
$stats[$status]++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return $stats;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Prepare update rows for the JSON response.
|
||
|
|
*
|
||
|
|
* @param list<array<string, mixed>> $updates
|
||
|
|
* @return list<array<string, mixed>>
|
||
|
|
*/
|
||
|
|
private function prepareUpdatesForResponse(array $updates): array
|
||
|
|
{
|
||
|
|
$prepared = [];
|
||
|
|
foreach ($updates as $update) {
|
||
|
|
$categoryCode = (string) ($update['category_code'] ?? '');
|
||
|
|
$status = (string) ($update['status'] ?? '');
|
||
|
|
$prepared[] = [
|
||
|
|
'ticket_no' => (string) ($update['ticket_no'] ?? ''),
|
||
|
|
'category_code' => $categoryCode,
|
||
|
|
'category_label' => UpdateService::categoryLabel($categoryCode),
|
||
|
|
'category_variant' => UpdateService::categoryVariant($categoryCode),
|
||
|
|
'gitea_path' => (string) ($update['gitea_path'] ?? ''),
|
||
|
|
'status' => $status,
|
||
|
|
'status_label' => UpdateService::statusLabel($status),
|
||
|
|
'status_variant' => UpdateService::statusVariant($status),
|
||
|
|
'created_at' => (string) ($update['created_at'] ?? ''),
|
||
|
|
];
|
||
|
|
}
|
||
|
|
|
||
|
|
return $prepared;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Prepare handover rows for the JSON response (strip internal fields).
|
||
|
|
*
|
||
|
|
* @param list<array<string, mixed>> $handovers
|
||
|
|
* @return list<array<string, mixed>>
|
||
|
|
*/
|
||
|
|
private function prepareHandoversForResponse(array $handovers): array
|
||
|
|
{
|
||
|
|
$prepared = [];
|
||
|
|
foreach ($handovers as $handover) {
|
||
|
|
$prepared[] = [
|
||
|
|
'id' => (int) ($handover['id'] ?? 0),
|
||
|
|
'product_code' => (string) ($handover['product_code'] ?? ''),
|
||
|
|
'product_name' => (string) ($handover['product_name'] ?? ''),
|
||
|
|
'product_bc_description' => (string) ($handover['product_bc_description'] ?? ''),
|
||
|
|
'status' => (string) ($handover['status'] ?? ''),
|
||
|
|
'created_by_name' => (string) ($handover['created_by_name'] ?? ''),
|
||
|
|
'created_at' => (string) ($handover['created_at'] ?? ''),
|
||
|
|
];
|
||
|
|
}
|
||
|
|
|
||
|
|
return $prepared;
|
||
|
|
}
|
||
|
|
}
|