Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
73.68% covered (warning)
73.68%
154 / 209
64.52% covered (warning)
64.52%
20 / 31
CRAP
0.00% covered (danger)
0.00%
0 / 1
ProcessList
73.68% covered (warning)
73.68%
154 / 209
64.52% covered (warning)
64.52%
20 / 31
250.62
0.00% covered (danger)
0.00%
0 / 1
 toProcessListByTime
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
4
 withRequest
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 sortByScopeName
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
2
 sortByAppointmentDate
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 sortByArrivalTime
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 sortByEstimatedWaitingTime
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 sortByClientName
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 sortByTimeKey
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 toProcessListByStatusList
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
 toConflictListByDay
95.24% covered (success)
95.24%
20 / 21
0.00% covered (danger)
0.00%
0 / 1
5
 getScopeList
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 getRequestList
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 getAppointmentList
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
4
 setTempAppointmentToProcess
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
5
 toQueueList
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
2
 withAvailability
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 withAvailabilityStrict
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
 withDepartmentHasMailFrom
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 setConflictAmendment
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
3
 withOutAvailability
73.33% covered (warning)
73.33%
11 / 15
0.00% covered (danger)
0.00%
0 / 1
6.68
 withUniqueScope
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
4
 withAccess
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 withScopeId
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 withOutScopeId
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 withOutProcessId
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 withoutExpiredAppointmentDate
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
 withinExactDate
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
 withoutDublicatedConflicts
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
 testProcessListLength
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
4
 withoutProcessByStatus
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 withTimeRangeByAppointment
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
30
1<?php
2
3namespace BO\Zmsentities\Collection;
4
5use BO\Zmsentities\Helper\Sorter;
6use BO\Zmsentities\Helper\Property;
7use BO\Zmsentities\Helper\Messaging;
8use BO\Zmsentities\Process;
9
10/**
11 * @SuppressWarnings(Complexity)
12 * @SuppressWarnings(Public)
13 * @SuppressWarnings(Coupling)
14 *
15 * @extends Base<\BO\Zmsentities\Process>
16 */
17class ProcessList extends Base
18{
19    public const string ENTITY_CLASS = '\BO\Zmsentities\Process';
20
21    public function toProcessListByTime(string|null $format = null): self
22    {
23        $list = new self();
24        foreach ($this as $process) {
25            $appointment = $process->getFirstAppointment();
26            $formattedDate = $appointment['date'];
27            if ($format !== null && $format !== '') {
28                $formattedDate = $appointment->toDateTime()->format($format);
29            }
30            $list[$formattedDate][] = clone $process;
31        }
32        return $list;
33    }
34
35    public function withRequest(mixed $requestId): self
36    {
37        $list = new self();
38        foreach ($this as $process) {
39            if ($process->requests->hasEntity($requestId)) {
40                $list->addEntity(clone $process);
41            }
42        }
43        return $list;
44    }
45
46    public function sortByScopeName(): static
47    {
48        $this->uasort(function ($a, $b) {
49            return strcmp(
50                Sorter::toSortableString(ucfirst($a->scope['contact']['name'] ?? '')),
51                Sorter::toSortableString(ucfirst($b->scope['contact']['name'] ?? ''))
52            );
53        });
54        return $this;
55    }
56
57    public function sortByAppointmentDate(): static
58    {
59        $this->uasort(function ($a, $b) {
60            return ((int) $a->getFirstAppointment()->date - (int) $b->getFirstAppointment()->date);
61        });
62        return $this;
63    }
64
65    public function sortByArrivalTime(): static
66    {
67        $this->uasort(function ($a, $b): mixed {
68            return ($a->queue['arrivalTime'] - $b->queue['arrivalTime']);
69        });
70        return $this;
71    }
72
73    public function sortByEstimatedWaitingTime(): static
74    {
75        $this->uasort(function ($a, $b): mixed {
76            return ($a->queue['waitingTimeEstimate'] - $b->queue['waitingTimeEstimate']);
77        });
78        return $this;
79    }
80
81    public function sortByClientName(): static
82    {
83        $this->uasort(function ($a, $b) {
84            return strcmp(
85                Sorter::toSortableString($a->getFirstClient()['familyName']),
86                Sorter::toSortableString($b->getFirstClient()['familyName'])
87            );
88        });
89        return $this;
90    }
91
92    public function sortByTimeKey(): static
93    {
94        $this->uksort(function ($a, $b): mixed {
95            return ((int) $a - (int) $b);
96        });
97        return $this;
98    }
99
100    public function toProcessListByStatusList(array $statusList): self
101    {
102        $collection = new self();
103        foreach ($this as $process) {
104            if (in_array($process->getStatus(), $statusList)) {
105                $collection->addEntity($process);
106            }
107        }
108        return $collection;
109    }
110
111    /**
112     * @return ((mixed|null)[][]|mixed)[][][]
113     *
114     */
115    public function toConflictListByDay(): array
116    {
117        $list = [];
118        $oldList = clone $this;
119        foreach ($oldList as $process) {
120            $appointmentList = [];
121            if (!isset($list[$process->getFirstAppointment()->getStartTime()->format('Y-m-d')])) {
122                $list[$process->getFirstAppointment()->getStartTime()->format('Y-m-d')] = [];
123            }
124            foreach ($process->getAppointments() as $appointment) {
125                $availability = $appointment->getAvailability();
126                $availabilityId = $availability->getId()
127                    ? $availability->getId()
128                    : ($availability['tempId'] ?? null);
129                $appointmentList[] = [
130                    'startTime' => $appointment->getStartTime()->format('H:i'),
131                    'endTime' => $appointment->getEndTime()->format('H:i'),
132                    'availability' => $availabilityId
133                ];
134            }
135            $list[$process->getFirstAppointment()->getStartTime()->format('Y-m-d')][] = [
136                'message' => $process->amendment,
137                'appointments' => $appointmentList
138            ];
139        }
140        return $list;
141    }
142
143    public function getScopeList(): \BO\Zmsentities\Collection\ScopeList
144    {
145        $list = new ScopeList();
146        foreach ($this as $process) {
147            if (Property::__keyExists('scope', $process)) {
148                $list[] = new \BO\Zmsentities\Scope($process['scope']);
149            }
150        }
151        return $list->withUniqueScopes();
152    }
153
154    public function getRequestList(): \BO\Zmsentities\Collection\RequestList
155    {
156        $list = new RequestList();
157        foreach ($this as $process) {
158            if (Property::__keyExists('requests', $process)) {
159                $list->addList($process->getRequests());
160            }
161        }
162        return $list->withUniqueRequests();
163    }
164
165    public function getAppointmentList(): AppointmentList
166    {
167        $appointmentList = new AppointmentList();
168        foreach ($this as $process) {
169            if (Property::__keyExists('appointments', $process)) {
170                foreach ($process["appointments"] as $appointment) {
171                    $appointmentList->addEntity(new \BO\Zmsentities\Appointment($appointment));
172                }
173            }
174        }
175        return $appointmentList;
176    }
177
178    public function setTempAppointmentToProcess(mixed $dateTime, mixed $scopeId): static
179    {
180        $addedAppointment = false;
181        $appointment = (new \BO\Zmsentities\Appointment())->addDate($dateTime->getTimestamp())->addScope($scopeId);
182        foreach ($this as $process) {
183            if ($process->hasAppointment($dateTime->getTimestamp(), $scopeId) && !$addedAppointment) {
184                $entity = clone $process;
185                $this->addEntity($entity);
186                $addedAppointment = true;
187            }
188        }
189        if (!$addedAppointment) {
190            $entity = new \BO\Zmsentities\Process();
191            $entity->addAppointment($appointment);
192            $this->addEntity($entity);
193        }
194        return $this;
195    }
196
197    public function toQueueList(mixed $now): QueueList
198    {
199        $queueList = new QueueList();
200        foreach ($this as $process) {
201            $queue = $process->toQueue($now);
202            $queueList->addEntity($queue);
203        }
204        $queueList->setTransferedProcessList(true);
205        return $queueList;
206    }
207
208    public function withAvailability(\BO\Zmsentities\Availability $availability): static
209    {
210        $processList = new static();
211        foreach ($this as $process) {
212            if ($availability->hasAppointment($process->getFirstAppointment())) {
213                $processList[] = clone $process;
214            }
215        }
216        return $processList;
217    }
218
219    public function withAvailabilityStrict(\BO\Zmsentities\Availability $availability): static
220    {
221        $processList = new static();
222        $slotList = $availability->getSlotList();
223        foreach ($this as $process) {
224            if ($slotList->removeAppointment($process->getFirstAppointment())) {
225                $processList[] = clone $process;
226            }
227        }
228        return $processList;
229    }
230
231    public function withDepartmentHasMailFrom(): static
232    {
233        $processList = new static();
234        foreach ($this as $process) {
235            if ($process->getCurrentScope()->hasEmailFrom()) {
236                $entity = clone $process;
237                $processList->addEntity($entity);
238            }
239        }
240        return $processList;
241    }
242
243
244
245    public function setConflictAmendment(): static
246    {
247        foreach ($this as $process) {
248            $process->amendment = 'Die Slots für diesen Zeitraum wurden Ã¼berbucht';
249            if (! $process->getFirstAppointment()->availability->hasId()) {
250                $process->amendment = sprintf(
251                    'Der Vorgang (%s) befindet sich außerhalb der Ã–ffnungszeit!',
252                    $process->getId()
253                );
254            }
255        }
256        return $this;
257    }
258
259    public function withOutAvailability(\BO\Zmsentities\Collection\AvailabilityList $availabilityList): static
260    {
261        $processList = new static();
262        foreach ($this->toProcessListByTime('Y-m-d') as $processListByDate) {
263            $dateTime = $processListByDate[0]->getFirstAppointment()->toDateTime();
264            $slotList = $availabilityList->withType('appointment')->withDateTime($dateTime)->getSlotList();
265            foreach ($processListByDate as $process) {
266                if (!$process instanceof Process) {
267                    continue;
268                }
269                try {
270                    $slotList->withSlotsForAppointment($process->getFirstAppointment());
271                    if (!$slotList->removeAppointment($process->getFirstAppointment())) {
272                        $process->amendment = "";
273                        $processList[] = clone $process;
274                    }
275                } catch (\BO\Zmsentities\Exception\AppointmentNotFitInSlotList $exception) {
276                    $process->amendment = "";
277                    $processList[] = clone $process;
278                }
279            }
280        }
281        return $processList;
282    }
283
284    public function withUniqueScope(bool $oncePerHour = false): static
285    {
286        $processList = new static();
287        $scopeKeyList = [];
288        foreach ($this as $process) {
289            $scopeKey = $process->scope['id'] . '-';
290            if ($oncePerHour) {
291                $scopeKey .= $process->getFirstAppointment()->toDateTime()->format('H');
292            } else {
293                $scopeKey .= $process->getFirstAppointment()->toDateTime()->format('H:i');
294            }
295            if (!in_array($scopeKey, $scopeKeyList)) {
296                $processList[] = clone $process;
297                $scopeKeyList[] = $scopeKey;
298            }
299        }
300        return $processList;
301    }
302
303    public function withAccess(\BO\Zmsentities\Useraccount $useraccount): static
304    {
305        $list = new static();
306        foreach ($this as $process) {
307            $process = clone $process;
308            if ($process->getCurrentScope()->hasAccess($useraccount)) {
309                $list[] = $process;
310            }
311        }
312        return $list;
313    }
314
315    /** @psalm-api */
316    public function withScopeId(int|string $scopeId): static
317    {
318        $processList = new static();
319        foreach ($this as $process) {
320            if ($scopeId == $process->getScopeId()) {
321                $processList[] = clone $process;
322            }
323        }
324        return $processList;
325    }
326
327    /** @psalm-api */
328    public function withOutScopeId(int|string $scopeId): static
329    {
330        $processList = new static();
331        foreach ($this as $process) {
332            if ($scopeId != $process->getScopeId()) {
333                $processList[] = clone $process;
334            }
335        }
336        return $processList;
337    }
338
339    public function withOutProcessId(mixed $processId): static
340    {
341        $processList = new static();
342        foreach ($this as $process) {
343            if ($processId != $process->getId()) {
344                $processList[] = clone $process;
345            }
346        }
347        return $processList;
348    }
349
350    public function withoutExpiredAppointmentDate(\DateTimeInterface $now): self
351    {
352        $conflictList = new self();
353        foreach ($this as $process) {
354            if ($process->getFirstAppointment()->date > $now->getTimestamp()) {
355                $conflictList->addEntity(clone $process);
356            }
357        }
358        return $conflictList;
359    }
360
361    public function withinExactDate(\DateTimeInterface $now): self
362    {
363        $processList = new self();
364        foreach ($this as $process) {
365            if ($process->getFirstAppointment()->toDateTime()->format('Y-m-d') == $now->format('Y-m-d')) {
366                $processList->addEntity(clone $process);
367            }
368        }
369        return $processList;
370    }
371
372    public function withoutDublicatedConflicts(): self
373    {
374        $collection = new self();
375        foreach ($this as $conflict) {
376            if (! $collection->getAppointmentList()->hasAppointment($conflict->getFirstAppointment())) {
377                $collection->addEntity(clone $conflict);
378            }
379        }
380        return $collection;
381    }
382
383    /**
384     * @param Process|self $processList
385     */
386    public function testProcessListLength(self|Process $processList, bool $isEmptyAllowed = false): ProcessList
387    {
388        if ($processList instanceof Process) {
389            $collection = new self();
390            $collection->addEntity($processList);
391        } else {
392            $collection = $processList;
393        }
394
395        if (0 === $collection->count() && ! $isEmptyAllowed) {
396            throw new \BO\Zmsentities\Exception\ProcessListEmpty();
397        }
398        return $collection;
399    }
400
401    public function withoutProcessByStatus(Process $process, string $status): static
402    {
403        $collection = clone $this;
404        $collection = (1 <= $collection->count() && ! Messaging::isEmptyProcessListAllowed($status)) ?
405            $collection->withOutProcessId($process->getId()) :
406            $collection;
407        return $collection;
408    }
409
410    /*
411    * reduce process list to items with appointment time in range of given appointment
412    */
413    public function withTimeRangeByAppointment(\BO\Zmsentities\Appointment $appointment): self
414    {
415        $processList = new self();
416        if ($this->count()) {
417            foreach ($this as $process) {
418                if (
419                    $appointment->getEndTime() > $process->getFirstAppointment()->getStartTime() &&
420                    $appointment->getStartTime() < $process->getFirstAppointment()->getEndTime()
421                ) {
422                    $processList->addEntity(clone $process);
423                }
424            }
425        }
426        return $processList;
427    }
428}