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 string CUSTOMER_TYPE_GESAMT = 'gesamt';
21    private const string CUSTOMER_TYPE_TERMIN = 'termin';
22    private const string 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     */
45    private function createAndPopulateSheet(
46        Spreadsheet $spreadsheet,
47        string $sheetTitle,
48        array $args,
49        string $customerType,
50        bool $isFirstSheet = false
51    ): void {
52        if (!$isFirstSheet) {
53            $spreadsheet->createSheet()->setTitle($sheetTitle);
54        } else {
55            $spreadsheet->getActiveSheet()->setTitle($sheetTitle);
56        }
57        $spreadsheet->setActiveSheetIndexByName($sheetTitle);
58        $this->writeInfoHeader($args, $spreadsheet);
59        foreach ($args['reports'] as $report) {
60            $this->writeWaitingReport($report, $spreadsheet, $customerType, 'dd.MM.yyyy');
61        }
62    }
63
64    #[\Override]
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        string $datePatternCol = 'dd.MM.yyyy',
104    ): Spreadsheet {
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(
125        ReportEntity $report,
126        \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $sheet,
127        string $datePatternCol
128    ): void {
129        $reportHeader = [];
130        $reportHeader[] = null;
131        $reportHeader[] = 'Max.';
132        $dates = array_keys($report->data);
133        sort($dates);
134        foreach ($dates as $date) {
135            if (! in_array($date, static::$ignoreColumns)) {
136                $date = $this->getFormatedDates($this->setDateTime($date), $datePatternCol);
137                $reportHeader[] = $date;
138            }
139        }
140        $startRow = $sheet->getHighestRow() + 2;
141        $sheet->fromArray($reportHeader, null, 'A' . $startRow);
142        // Datumszellen (ab B) in dieser Zeile fett schreiben
143        $lastColIdx = count($reportHeader);              // Anzahl der geschriebenen Zellen
144        if ($lastColIdx >= 2) {
145            $start = "B{$startRow}";
146            $end   = Coordinate::stringFromColumnIndex($lastColIdx) . $startRow;
147            $sheet->getStyle("$start:$end")->getFont()->setBold(true);
148        }
149    }
150
151    private function getCustomerTypeKeys(string $customerType): array
152    {
153        $this->assertValidCustomerType($customerType);
154        $keyMappings = [
155            self::CUSTOMER_TYPE_TERMIN => [
156                'max' => 'max_waitingtime_termin',
157                'avg' => 'average_waitingtime_termin',
158                'avg_way' => 'average_waytime_termin',
159            ],
160            self::CUSTOMER_TYPE_SPONTAN => [
161                'max' => 'max_waitingtime',
162                'avg' => 'average_waitingtime',
163                'avg_way' => 'average_waytime',
164            ],
165            self::CUSTOMER_TYPE_GESAMT => [
166                'max' => 'max_waitingtime_total',
167                'avg' => 'average_waitingtime_total',
168                'avg_way' => 'average_waytime_total',
169            ],
170        ];
171
172        return $keyMappings[$customerType];
173    }
174
175    public function writeTotals(ReportEntity $report, \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $sheet, string $customerType): void
176    {
177        $this->assertValidCustomerType($customerType);
178
179        $entity = clone $report;
180        $totals = $entity->data['max'];
181        unset($entity->data['max']);
182
183        $keys = $this->getCustomerTypeKeys($customerType);
184
185        $reportTotal['max'][] = 'Stunden-Max (Spaltenmaximum) der Wartezeit in Min.';
186        $reportTotal['average'][] = 'Stundendurchschnitt (Spalten) der Wartezeit in Min.';
187        $reportTotal['average_waytime'][] = 'Stundendurchschnitt (Spalten) der Wegezeit in Min.';
188
189        $reportTotal['max'][] = ReportHelper::formatTimeValue($totals[$keys['max']]);
190        $reportTotal['average'][] = ReportHelper::formatTimeValue($totals[$keys['avg']]);
191        $reportTotal['average_waytime'][] = ReportHelper::formatTimeValue($totals[$keys['avg_way']]);
192
193        foreach ($entity->data as $entry) {
194            $reportTotal['max'][] = ReportHelper::formatTimeValue($entry[$keys['max']]);
195            $reportTotal['average'][] = ReportHelper::formatTimeValue($entry[$keys['avg']]);
196            $reportTotal['average_waytime'][] = ReportHelper::formatTimeValue($entry[$keys['avg_way']]);
197        }
198        $sheet->fromArray($reportTotal, null, 'A' . ($sheet->getHighestRow() + 1));
199    }
200
201    public function writeReportPart(
202        ReportEntity $report,
203        \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $sheet,
204        string $rangeName,
205        string $headline
206    ): void {
207        $entity = clone $report;
208        $totals = $entity->data['max'];
209        unset($entity->data['max']);
210        $reportData['headline'] = ['Zeitabschnitte','Tagesmaximum (Zeilenmaximum)',$headline];
211        $formatAsTime = strpos($rangeName, 'waitingcount') === false;
212        foreach ($entity->data as $entry) {
213            foreach ($entry as $hour => $item) {
214                if (5 < $hour && 19 > $hour) {
215                    if (! isset($reportData[$hour])) {
216                        $reportData[$hour] = [];
217                    }
218                    $range = $hour . '-' . ($hour + 1) . ' Uhr';
219                    if (! in_array($range, $reportData[$hour])) {
220                        $reportData[$hour][] = $range;
221                        $totalValue = $totals[$hour][$rangeName];
222                        $reportData[$hour][] = $formatAsTime
223                            ? ReportHelper::formatTimeValue($totalValue)
224                            : $totalValue;
225                    }
226                    $value = $item[$rangeName] ?? '-';
227                    $reportData[$hour][] = $formatAsTime
228                        ? ReportHelper::formatTimeValue($value)
229                        : $value;
230                }
231            }
232        }
233        $startRow = $sheet->getHighestRow() + 2;
234        $sheet->fromArray($reportData, null, 'A' . $startRow);
235        $sheet->getStyle("A{$startRow}:C{$startRow}")->getFont()->setBold(true);
236    }
237}