Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
99.01% covered (success)
99.01%
100 / 101
83.33% covered (warning)
83.33%
5 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
ScopeAvailabilityDay
99.01% covered (success)
99.01%
100 / 101
83.33% covered (warning)
83.33%
5 / 6
18
0.00% covered (danger)
0.00%
0 / 1
 readResponse
93.33% covered (success)
93.33%
14 / 15
0.00% covered (danger)
0.00%
0 / 1
2.00
 getScope
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 getSlotBuckets
100.00% covered (success)
100.00%
27 / 27
100.00% covered (success)
100.00%
1 / 1
7
 getAvailabilityData
100.00% covered (success)
100.00%
31 / 31
100.00% covered (success)
100.00%
1 / 1
3
 readConflictList
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
2
 readAvailabilityList
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2
3/**
4 * @package Zmsadmin
5 * @copyright BerlinOnline Stadtportal GmbH & Co. KG
6 **/
7
8namespace BO\Zmsadmin;
9
10use BO\Slim\Render;
11use BO\Zmsentities\Helper\DateTime;
12use BO\Zmsentities\Collection\AvailabilityList;
13use BO\Zmsentities\Collection\ProcessList;
14use BO\Zmsentities\Exception\UserAccountMissingRights;
15
16class ScopeAvailabilityDay extends BaseController
17{
18    /**
19     * @SuppressWarnings(Param)
20     * @return \Psr\Http\Message\ResponseInterface
21     */
22    #[\Override]
23    public function readResponse(
24        \Psr\Http\Message\RequestInterface $request,
25        \Psr\Http\Message\ResponseInterface $response,
26        array $args
27    ): \Psr\Http\Message\ResponseInterface {
28        $workstation = \App::$http->readGetResult('/workstation/', ['resolveReferences' => 1])->getEntity();
29        if (!$workstation->getUseraccount()->hasPermissions(['availability'])) {
30            throw new UserAccountMissingRights();
31        }
32        $data = static::getAvailabilityData(intval($args['id']), $args['date']);
33        $data['title'] = 'Behörden und Standorte - Öffnungszeiten';
34        $data['menuActive'] = 'owner';
35        $data['workstation'] = $workstation;
36        $data['canViewAvailabilityHistory'] = ScopeAvailabilityHistory::canViewAvailabilityHistory(
37            $workstation->getUseraccount()
38        );
39        return Render::withHtml(
40            $response,
41            'page/availabilityday.twig',
42            $data
43        );
44    }
45
46    protected static function getScope($scopeId)
47    {
48        return \App::$http->readGetResult('/scope/' . $scopeId . '/', [
49            'resolveReferences' => 3
50        ])->getEntity();
51    }
52
53    /**
54     * @return (int|mixed)[][]
55     *
56     */
57    protected static function getSlotBuckets($availabilityList, $processList): array
58    {
59        $availability = $availabilityList->getFirst();
60
61        if (!$availability) {
62            return [];
63        }
64
65        $buckets = [];
66
67        $slotTimeInMinutes = $availability->getSlotTimeInMinutes();
68
69        foreach ($availabilityList->getSlotListByType('appointment') as $slot) {
70            $time = $slot->time;
71            $buckets[$time] = [
72                'time' => $time,
73                'timeString' => $slot->getTimeString(),
74                'public' => $slot->public,
75                'intern' => $slot->intern,
76                'occupiedCount' => 0,
77            ];
78        }
79
80        foreach ($processList as $process) {
81            $startTime = $process->getAppointments()->getFirst()->getStartTime()->format('H:i');
82            $endTime = $process->getAppointments()->getFirst()->getEndTimeWithCustomSlotTime($slotTimeInMinutes)->format('H:i');
83
84            $startDateTime = new \DateTime($startTime);
85            $endDateTime = new \DateTime($endTime);
86
87            foreach (array_keys($buckets) as $time) {
88                $slotDateTime = new \DateTime($time);
89                if ($slotDateTime >= $startDateTime && $slotDateTime < $endDateTime) {
90                    $buckets[$time]['occupiedCount']++;
91                }
92            }
93        }
94
95        uksort($buckets, function ($time1, $time2) {
96            return strtotime($time1) <=> strtotime($time2);
97        });
98
99        return $buckets;
100    }
101
102    /**
103     * @return (\BO\Zmsentities\Process[]|int|mixed|string)[]
104     *
105     */
106    protected static function getAvailabilityData(int $scopeId, $dateString): array
107    {
108        $scope = static::getScope($scopeId);
109        $dateTime = new DateTime($dateString);
110        $dateWithTime = $dateTime->setTime(\App::$now->format('H'), \App::$now->format('i'));
111        $availabilityList = static::readAvailabilityList($scopeId, $dateWithTime);
112        $processList = \App::$http
113            ->readGetResult('/scope/' . $scopeId . '/process/' . $dateWithTime->format('Y-m-d') . '/')
114                ->getCollection()
115                ->toQueueList($dateWithTime)
116                ->withoutStatus(['fake'])
117                ->toProcessList();
118        if (!$processList->count()) {
119            $processList = new ProcessList();
120        }
121
122
123        $conflictList = static::readConflictList($scopeId, $dateWithTime);
124        $maxSlots = $availabilityList->getSummerizedSlotCount();
125        $busySlots = $availabilityList->getCalculatedSlotCount($processList);
126
127        return [
128            'slotBuckets' => static::getSlotBuckets($availabilityList, $processList),
129            'scope' => $scope,
130            'availabilityList' => $availabilityList->getArrayCopy(),
131            'conflicts' => ($conflictList) ? $conflictList
132                ->setConflictAmendment()
133                ->getArrayCopy() : [],
134            'processList' => $processList->getArrayCopy(),
135            'dateString' => $dateString,
136            'timestamp' => $dateWithTime->getTimestamp(),
137            'menuActive' => 'availability',
138            'maxWorkstationCount' => $availabilityList->getMaxWorkstationCount(),
139            'maxSlotsForAvailabilities' => $maxSlots,
140            'busySlotsForAvailabilities' => $busySlots,
141            'today' => \App::$now->getTimestamp()
142        ];
143    }
144
145    public static function readConflictList($scopeId, \DateTimeInterface $dateTime)
146    {
147        $processConflictList = \App::$http
148            ->readGetResult('/scope/' . $scopeId . '/conflict/', [
149                'startDate' => $dateTime->format('Y-m-d'),
150                'endDate' => $dateTime->format('Y-m-d')
151            ])
152            ->getCollection();
153        return ($processConflictList) ? $processConflictList
154            ->sortByAppointmentDate()
155            ->withoutDublicatedConflicts()
156            ->toQueueList($dateTime)
157            ->withoutStatus(['fake', 'queued'])
158            ->toProcessList() : null;
159    }
160
161    public static function readAvailabilityList($scopeId, \DateTimeInterface $dateTime)
162    {
163        try {
164            $availabilityList = \App::$http
165                ->readGetResult(
166                    '/scope/' . $scopeId . '/availability/',
167                    [
168                        'startDate' => $dateTime->format('Y-m-d'), //for skipping old availabilities
169                    ]
170                )
171                ->getCollection()->sortByCustomKey('startDate');
172        } catch (\BO\Zmsclient\Exception $exception) {
173            if ($exception->template != 'BO\Zmsbackend\Availability\Exception\AvailabilityNotFound') {
174                throw $exception;
175            }
176            $availabilityList = new AvailabilityList();
177        }
178        return $availabilityList->withDateTime($dateTime); //withDateTime to check if opened
179    }
180}