Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
73.79% covered (warning)
73.79%
152 / 206
64.52% covered (warning)
64.52%
20 / 31
CRAP
0.00% covered (danger)
0.00%
0 / 1
ProcessList
73.79% covered (warning)
73.79%
152 / 206
64.52% covered (warning)
64.52%
20 / 31
240.16
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
3
 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
76.92% covered (warning)
76.92%
10 / 13
0.00% covered (danger)
0.00%
0 / 1
5.31
 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%
6 / 6
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) {
28                $formattedDate = $appointment->toDateTime()->format($format);
29            }
30            $list[$formattedDate][] = clone $process;
31        }
32        return $list;
33    }
34
35    public function withRequest($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 ($a->getFirstAppointment()->date - $b->getFirstAppointment()->date);
61        });
62        return $this;
63    }
64
65    public function sortByArrivalTime(): static
66    {
67        $this->uasort(function ($a, $b) {
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) {
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) {
95            return ($a - $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()
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()
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($dateTime, $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($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->scope->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                try {
267                    $slotList->withSlotsForAppointment($process->getFirstAppointment());
268                    if (!$slotList->removeAppointment($process->getFirstAppointment())) {
269                        $process->amendment = "";
270                        $processList[] = clone $process;
271                    }
272                } catch (\BO\Zmsentities\Exception\AppointmentNotFitInSlotList $exception) {
273                    $process->amendment = "";
274                    $processList[] = clone $process;
275                }
276            }
277        }
278        return $processList;
279    }
280
281    public function withUniqueScope($oncePerHour = false): static
282    {
283        $processList = new static();
284        $scopeKeyList = [];
285        foreach ($this as $process) {
286            $scopeKey = $process->scope->id . '-';
287            if ($oncePerHour) {
288                $scopeKey .= $process->getFirstAppointment()->toDateTime()->format('H');
289            } else {
290                $scopeKey .= $process->getFirstAppointment()->toDateTime()->format('H:i');
291            }
292            if (!in_array($scopeKey, $scopeKeyList)) {
293                $processList[] = clone $process;
294                $scopeKeyList[] = $scopeKey;
295            }
296        }
297        return $processList;
298    }
299
300    public function withAccess(\BO\Zmsentities\Useraccount $useraccount): static
301    {
302        $list = new static();
303        foreach ($this as $process) {
304            $process = clone $process;
305            if ($process->getCurrentScope()->hasAccess($useraccount)) {
306                $list[] = $process;
307            }
308        }
309        return $list;
310    }
311
312    /** @psalm-api */
313    public function withScopeId(int|string $scopeId): static
314    {
315        $processList = new static();
316        foreach ($this as $process) {
317            if ($scopeId == $process->getScopeId()) {
318                $processList[] = clone $process;
319            }
320        }
321        return $processList;
322    }
323
324    /** @psalm-api */
325    public function withOutScopeId(int|string $scopeId): static
326    {
327        $processList = new static();
328        foreach ($this as $process) {
329            if ($scopeId != $process->getScopeId()) {
330                $processList[] = clone $process;
331            }
332        }
333        return $processList;
334    }
335
336    public function withOutProcessId($processId): static
337    {
338        $processList = new static();
339        foreach ($this as $process) {
340            if ($processId != $process->getId()) {
341                $processList[] = clone $process;
342            }
343        }
344        return $processList;
345    }
346
347    public function withoutExpiredAppointmentDate(\DateTimeInterface $now): self
348    {
349        $conflictList = new self();
350        foreach ($this as $process) {
351            if ($process->getFirstAppointment()->date > $now->getTimestamp()) {
352                $conflictList->addEntity(clone $process);
353            }
354        }
355        return $conflictList;
356    }
357
358    public function withinExactDate(\DateTimeInterface $now): self
359    {
360        $processList = new self();
361        foreach ($this as $process) {
362            if ($process->getFirstAppointment()->toDateTime()->format('Y-m-d') == $now->format('Y-m-d')) {
363                $processList->addEntity(clone $process);
364            }
365        }
366        return $processList;
367    }
368
369    public function withoutDublicatedConflicts(): self
370    {
371        $collection = new self();
372        foreach ($this as $conflict) {
373            if (! $collection->getAppointmentList()->hasAppointment($conflict->getFirstAppointment())) {
374                $collection->addEntity(clone $conflict);
375            }
376        }
377        return $collection;
378    }
379
380    public function testProcessListLength($processList, bool $isEmptyAllowed = false): ProcessList
381    {
382        $collection = ($processList instanceof Process) ?
383            (new self())->addEntity($processList) :
384            $processList;
385
386        if (0 === $collection->count() && ! $isEmptyAllowed) {
387            throw new \BO\Zmsentities\Exception\ProcessListEmpty();
388        }
389        return $collection;
390    }
391
392    public function withoutProcessByStatus(Process $process, $status)
393    {
394        $collection = clone $this;
395        $collection = (1 <= $collection->count() && ! Messaging::isEmptyProcessListAllowed($status)) ?
396            $collection->withOutProcessId($process->getId()) :
397            $collection;
398        return $collection;
399    }
400
401    /*
402    * reduce process list to items with appointment time in range of given appointment
403    */
404    public function withTimeRangeByAppointment(\BO\Zmsentities\Appointment $appointment): self
405    {
406        $processList = new self();
407        if ($this->count()) {
408            foreach ($this as $process) {
409                if (
410                    $appointment->getEndTime() > $process->getFirstAppointment()->getStartTime() &&
411                    $appointment->getStartTime() < $process->getFirstAppointment()->getEndTime()
412                ) {
413                    $processList->addEntity(clone $process);
414                }
415            }
416        }
417        return $processList;
418    }
419}