Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
97.30% covered (success)
97.30%
108 / 111
87.50% covered (warning)
87.50%
7 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
WaitingReport
97.30% covered (success)
97.30%
108 / 111
87.50% covered (warning)
87.50%
7 / 8
26
0.00% covered (danger)
0.00%
0 / 1
 createAndPopulateSheet
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
3
 readResponse
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
1
 assertValidCustomerType
66.67% covered (warning)
66.67%
6 / 9
0.00% covered (danger)
0.00%
0 / 1
2.15
 writeWaitingReport
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
4
 writeHeader
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
1 / 1
4
 getCustomerTypeKeys
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
1 / 1
1
 writeTotals
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
1 / 1
2
 writeReportPart
100.00% covered (success)
100.00%
24 / 24
100.00% covered (success)
100.00%
1 / 1
9
1<?php
2
3/**
4 * @package zmsstatistic
5 * @copyright BerlinOnline Stadtportal GmbH & Co. KG
6 **/
7
8namespace BO\Zmsstatistic\Download;
9
10use BO\Zmsentities\Exchange as ReportEntity;
11use BO\Zmsstatistic\Helper\Download;
12use BO\Zmsstatistic\Helper\ReportHelper;
13use PhpOffice\PhpSpreadsheet\Spreadsheet;
14use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
15use Psr\Http\Message\RequestInterface;
16use Psr\Http\Message\ResponseInterface;
17
18class WaitingReport extends Base
19{
20    private const CUSTOMER_TYPE_GESAMT = 'gesamt';
21    private const CUSTOMER_TYPE_TERMIN = 'termin';
22    private const CUSTOMER_TYPE_SPONTAN = 'spontan';
23
24    protected $reportPartsGesamt = [
25        'waitingtime_total' => 'Durchschnittliche Wartezeit in Min. (Gesamt)',
26        'waitingcount_total' => 'Wartende Gesamtkunden',
27        'waytime_total' => 'Durchschnittliche Wegezeit in Min. (Gesamt)',
28    ];
29
30    protected $reportPartsTermin = [
31        'waitingtime_termin' => 'Durchschnittliche Wartezeit in Min. (Terminkunden)',
32        'waitingcount_termin' => 'Wartende Terminkunden',
33        'waytime_termin' => 'Durchschnittliche Wegezeit in Min. (Terminkunden)',
34    ];
35
36    protected $reportPartsSpontan = [
37        'waitingtime' => 'Durchschnittliche Wartezeit in Min. (Spontankunden)',
38        'waitingcount' => 'Wartende Spontankunden',
39        'waytime' => 'Durchschnittliche Wegezeit in Min. (Spontankunden)',
40    ];
41
42    /**
43     * @SuppressWarnings(Param)
44     * @return ResponseInterface
45     */
46    private function createAndPopulateSheet(
47        Spreadsheet $spreadsheet,
48        string $sheetTitle,
49        array $args,
50        string $customerType,
51        bool $isFirstSheet = false
52    ): void {
53        if (!$isFirstSheet) {
54            $spreadsheet->createSheet()->setTitle($sheetTitle);
55        } else {
56            $spreadsheet->getActiveSheet()->setTitle($sheetTitle);
57        }
58        $spreadsheet->setActiveSheetIndexByName($sheetTitle);
59        $this->writeInfoHeader($args, $spreadsheet);
60        foreach ($args['reports'] as $report) {
61            $this->writeWaitingReport($report, $spreadsheet, $customerType, 'dd.MM.yyyy');
62        }
63    }
64
65    public function readResponse(
66        RequestInterface $request,
67        ResponseInterface $response,
68        array $args
69    ) {
70        $title = 'waitingstatistic_' . $args['period'];
71        $download = (new Download($request))->setSpreadSheet($title);
72        $spreadsheet = $download->getSpreadSheet();
73
74        $this->createAndPopulateSheet($spreadsheet, 'Gesamt', $args, self::CUSTOMER_TYPE_GESAMT, true);
75        $this->createAndPopulateSheet($spreadsheet, 'Terminkunden', $args, self::CUSTOMER_TYPE_TERMIN);
76        $this->createAndPopulateSheet($spreadsheet, 'Spontankunden', $args, self::CUSTOMER_TYPE_SPONTAN);
77
78        // Für den Download das erste Blatt aktiv lassen
79        $spreadsheet->setActiveSheetIndexByName('Gesamt');
80
81        return $download->writeDownload($response);
82    }
83
84    private function assertValidCustomerType(string $customerType): void
85    {
86        $validTypes = [
87            self::CUSTOMER_TYPE_GESAMT,
88            self::CUSTOMER_TYPE_TERMIN,
89            self::CUSTOMER_TYPE_SPONTAN,
90        ];
91
92        if (!in_array($customerType, $validTypes, true)) {
93            throw new \InvalidArgumentException(
94                "Invalid customer type: {$customerType}. Must be one of: " . implode(', ', $validTypes)
95            );
96        }
97    }
98
99    public function writeWaitingReport(
100        ReportEntity $report,
101        Spreadsheet $spreadsheet,
102        string $customerType,
103        $datePatternCol = 'dd.MM.yyyy',
104    ) {
105        $this->assertValidCustomerType($customerType);
106
107        $sheet = $spreadsheet->getActiveSheet();
108        $this->writeHeader($report, $sheet, $datePatternCol);
109        $this->writeTotals($report, $sheet, $customerType);
110        if ($customerType === self::CUSTOMER_TYPE_TERMIN) {
111            $parts = $this->reportPartsTermin;
112        } elseif ($customerType === self::CUSTOMER_TYPE_SPONTAN) {
113            $parts = $this->reportPartsSpontan;
114        } else {
115            $parts = $this->reportPartsGesamt;
116        }
117        foreach ($parts as $partName => $headline) {
118            $this->writeReportPart($report, $sheet, $partName, $headline);
119        }
120
121        return $spreadsheet;
122    }
123
124    public function writeHeader(ReportEntity $report, $sheet, $datePatternCol)
125    {
126        $reportHeader = [];
127        $reportHeader[] = null;
128        $reportHeader[] = 'Max.';
129        $dates = array_keys($report->data);
130        sort($dates);
131        foreach ($dates as $date) {
132            if (! in_array($date, static::$ignoreColumns)) {
133                $date = $this->getFormatedDates($this->setDateTime($date), $datePatternCol);
134                $reportHeader[] = $date;
135            }
136        }
137        $startRow = $sheet->getHighestRow() + 2;
138        $sheet->fromArray($reportHeader, null, 'A' . $startRow);
139        // Datumszellen (ab B) in dieser Zeile fett schreiben
140        $lastColIdx = count($reportHeader);              // Anzahl der geschriebenen Zellen
141        if ($lastColIdx >= 2) {
142            $start = "B{$startRow}";
143            $end   = Coordinate::stringFromColumnIndex($lastColIdx) . $startRow;
144            $sheet->getStyle("$start:$end")->getFont()->setBold(true);
145        }
146    }
147
148    private function getCustomerTypeKeys(string $customerType): array
149    {
150        $this->assertValidCustomerType($customerType);
151        $keyMappings = [
152            self::CUSTOMER_TYPE_TERMIN => [
153                'max' => 'max_waitingtime_termin',
154                'avg' => 'average_waitingtime_termin',
155                'avg_way' => 'average_waytime_termin',
156            ],
157            self::CUSTOMER_TYPE_SPONTAN => [
158                'max' => 'max_waitingtime',
159                'avg' => 'average_waitingtime',
160                'avg_way' => 'average_waytime',
161            ],
162            self::CUSTOMER_TYPE_GESAMT => [
163                'max' => 'max_waitingtime_total',
164                'avg' => 'average_waitingtime_total',
165                'avg_way' => 'average_waytime_total',
166            ],
167        ];
168
169        return $keyMappings[$customerType];
170    }
171
172    public function writeTotals(ReportEntity $report, $sheet, string $customerType)
173    {
174        $this->assertValidCustomerType($customerType);
175
176        $entity = clone $report;
177        $totals = $entity->data['max'];
178        unset($entity->data['max']);
179
180        $keys = $this->getCustomerTypeKeys($customerType);
181
182        $reportTotal['max'][] = 'Stunden-Max (Spaltenmaximum) der Wartezeit in Min.';
183        $reportTotal['average'][] = 'Stundendurchschnitt (Spalten) der Wartezeit in Min.';
184        $reportTotal['average_waytime'][] = 'Stundendurchschnitt (Spalten) der Wegezeit in Min.';
185
186        $reportTotal['max'][] = ReportHelper::formatTimeValue($totals[$keys['max']]);
187        $reportTotal['average'][] = ReportHelper::formatTimeValue($totals[$keys['avg']]);
188        $reportTotal['average_waytime'][] = ReportHelper::formatTimeValue($totals[$keys['avg_way']]);
189
190        foreach ($entity->data as $entry) {
191            $reportTotal['max'][] = ReportHelper::formatTimeValue($entry[$keys['max']]);
192            $reportTotal['average'][] = ReportHelper::formatTimeValue($entry[$keys['avg']]);
193            $reportTotal['average_waytime'][] = ReportHelper::formatTimeValue($entry[$keys['avg_way']]);
194        }
195        $sheet->fromArray($reportTotal, null, 'A' . ($sheet->getHighestRow() + 1));
196    }
197
198    public function writeReportPart(ReportEntity $report, $sheet, $rangeName, $headline)
199    {
200        $entity = clone $report;
201        $totals = $entity->data['max'];
202        unset($entity->data['max']);
203        $reportData['headline'] = ['Zeitabschnitte','Tagesmaximum (Zeilenmaximum)',$headline];
204        $formatAsTime = strpos($rangeName, 'waitingcount') === false;
205        foreach ($entity->data as $entry) {
206            foreach ($entry as $hour => $item) {
207                if (5 < $hour && 19 > $hour) {
208                    if (! isset($reportData[$hour])) {
209                        $reportData[$hour] = [];
210                    }
211                    $range = $hour . '-' . ($hour + 1) . ' Uhr';
212                    if (! in_array($range, $reportData[$hour])) {
213                        $reportData[$hour][] = $range;
214                        $totalValue = $totals[$hour][$rangeName];
215                        $reportData[$hour][] = $formatAsTime
216                            ? ReportHelper::formatTimeValue($totalValue)
217                            : $totalValue;
218                    }
219                    $value = $item[$rangeName] ?? '-';
220                    $reportData[$hour][] = $formatAsTime
221                        ? ReportHelper::formatTimeValue($value)
222                        : $value;
223                }
224            }
225        }
226        $startRow = $sheet->getHighestRow() + 2;
227        $sheet->fromArray($reportData, null, 'A' . $startRow);
228        $sheet->getStyle("A{$startRow}:C{$startRow}")->getFont()->setBold(true);
229    }
230}