Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
86.90% covered (warning)
86.90%
73 / 84
14.29% covered (danger)
14.29%
1 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
ReportClientService
86.90% covered (warning)
86.90%
73 / 84
14.29% covered (danger)
14.29%
1 / 7
29.76
0.00% covered (danger)
0.00%
0 / 1
 getExchangeClientData
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
4
 getExchangeClientForDateRange
82.35% covered (warning)
82.35%
14 / 17
0.00% covered (danger)
0.00%
0 / 1
5.14
 getExchangeClientForPeriod
75.00% covered (warning)
75.00%
6 / 8
0.00% covered (danger)
0.00%
0 / 1
2.06
 getClientPeriod
60.00% covered (warning)
60.00%
3 / 5
0.00% covered (danger)
0.00%
0 / 1
2.26
 fetchAndCombineDataFromYears
96.43% covered (success)
96.43%
27 / 28
0.00% covered (danger)
0.00%
0 / 1
7
 createFilteredExchangeClient
81.82% covered (warning)
81.82%
9 / 11
0.00% covered (danger)
0.00%
0 / 1
3.05
 prepareDownloadArgs
87.50% covered (warning)
87.50%
7 / 8
0.00% covered (danger)
0.00%
0 / 1
5.05
1<?php
2
3/**
4 * @package Zmsstatistic
5 * @copyright BerlinOnline Stadtportal GmbH & Co. KG
6 **/
7
8namespace BO\Zmsstatistic\Service;
9
10use BO\Zmsentities\Day;
11use BO\Zmsstatistic\Helper\ReportHelper;
12use DateTime;
13use DateTimeImmutable;
14use Exception;
15
16class ReportClientService
17{
18    protected array $totals = [
19        'clientscount',
20        'missed',
21        'withappointment',
22        'missedwithappointment',
23        'noappointment',
24        'missednoappointment',
25        'ticketprinter',
26        'ticketprintermissed',
27        'requestscount'
28    ];
29
30    /**
31     * Get exchange client data based on date range or period
32     */
33    public function getExchangeClientData(string $scopeId, ?array $dateRange, array $args): mixed
34    {
35        if ($scopeId === '') {
36            return null;
37        }
38
39        if (ReportHelper::hasValues($dateRange)) {
40            return $this->getExchangeClientForDateRange($scopeId, $dateRange);
41        }
42
43        return isset($args['period'])
44            ? $this->getExchangeClientForPeriod($scopeId, $args['period'])
45            : null;
46    }
47
48    /**
49     * Get exchange client data for a specific date range
50     */
51    public function getExchangeClientForDateRange(string $scopeId, array $dateRange): mixed
52    {
53        if (!isset($dateRange['from']) || !isset($dateRange['to'])) {
54            return null;
55        }
56        $fromDate = $dateRange['from'];
57        $toDate = $dateRange['to'];
58
59        try {
60            $reportHelper = new ReportHelper();
61            $years = $reportHelper->getYearsForDateRange($fromDate, $toDate);
62            $combinedData = $this->fetchAndCombineDataFromYears($reportHelper, $scopeId, $years, $fromDate, $toDate);
63
64            if (empty($combinedData['data'])) {
65                return null;
66            }
67
68            return $this->createFilteredExchangeClient(
69                $combinedData['entity'],
70                $combinedData['data'],
71                $fromDate,
72                $toDate
73            );
74        } catch (Exception $exception) {
75            return null;
76        }
77    }
78
79    /**
80     * Get exchange client data for a specific period (legacy functionality)
81     */
82    public function getExchangeClientForPeriod(string $scopeId, string $period): mixed
83    {
84        try {
85            $exchangeClient = \App::http()
86                ->readGetResult('/warehouse/clientscope/' . $scopeId . '/' . $period . '/')
87                ->getEntity();
88            /** @var mixed $exchangeClient */
89            return $exchangeClient
90                ->withCalculatedTotals($this->totals, 'date')
91                ->toHashed();
92        } catch (Exception $exception) {
93            return null;
94        }
95    }
96
97    /**
98     * Get client period data for the current scope
99     */
100    public function getClientPeriod(string $scopeId): mixed
101    {
102        try {
103            return \App::http()
104                ->readGetResult('/warehouse/clientscope/' . $scopeId . '/')
105                ->getEntity();
106        } catch (Exception $exception) {
107            return null;
108        }
109    }
110
111    /**
112     * Fetch and combine data from multiple years
113     */
114    private function fetchAndCombineDataFromYears(ReportHelper $reportHelper, string $scopeId, array $years, string $fromDate, string $toDate): array
115    {
116        $combinedData = [];
117        $baseEntity = null;
118
119        foreach ($years as $year) {
120            $bounds = $reportHelper->getYearDateBounds($year, $fromDate, $toDate);
121            if ($bounds === null) {
122                continue;
123            }
124            try {
125                $exchangeClient = \App::http()
126                    ->readGetResult(
127                        '/warehouse/clientscope/' . $scopeId . '/' . $year . '/',
128                        [
129                            'groupby' => 'day',
130                            'fromDate' => $bounds['from'],
131                            'toDate' => $bounds['to'],
132                        ]
133                    )
134                    ->getEntity();
135
136                // Use the first successfully fetched entity as the base
137                if ($baseEntity === null) {
138                    $baseEntity = $exchangeClient;
139                }
140
141                // Combine data from all years
142                if (isset($exchangeClient->data) && is_array($exchangeClient->data)) {
143                    $combinedData = array_merge($combinedData, $exchangeClient->data);
144                }
145            } catch (Exception $exception) {
146                // Continue with other years - don't fail completely if one year is missing
147            }
148        }
149
150        usort($combinedData, static function ($a, $b) {
151            return strcmp($a[1] ?? '', $b[1] ?? '');
152        });
153
154        return [
155            'entity' => $baseEntity,
156            'data' => $combinedData
157        ];
158    }
159
160    /**
161     * Create filtered exchange client with updated properties
162     */
163    private function createFilteredExchangeClient(
164        mixed $exchangeClientBasic,
165        array $filteredData,
166        string $fromDate,
167        string $toDate
168    ): mixed {
169        $exchangeClient = $exchangeClientBasic;
170        $exchangeClient->data = $filteredData;
171
172        if (!isset($exchangeClient->period)) {
173            $exchangeClient->period = 'day';
174        }
175
176        $exchangeClient->firstDay = (new Day())->setDateTime(new DateTime($fromDate));
177        $exchangeClient->lastDay = (new Day())->setDateTime(new DateTime($toDate));
178
179        if (!empty($filteredData)) {
180            return $exchangeClient
181                ->withCalculatedTotals($this->totals, 'date')
182                ->toHashed();
183        }
184
185        return $exchangeClient->toHashed();
186    }
187
188    /**
189     * Prepare download arguments for client report
190     */
191    public function prepareDownloadArgs(
192        array $args,
193        mixed $exchangeClient,
194        ?array $dateRange,
195        array $selectedScopes = []
196    ): array {
197        $args['category'] = 'clientscope';
198
199        if (ReportHelper::hasValues($dateRange)) {
200            $args['period'] = $dateRange['from'] . '_' . $dateRange['to'];
201        }
202
203        if (!empty($selectedScopes)) {
204            $args['selectedScopes'] = $selectedScopes;
205        }
206
207        if ($exchangeClient && count($exchangeClient->data)) {
208            $args['reports'][] = $exchangeClient;
209        }
210
211        return $args;
212    }
213}