Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
96.77% covered (success)
96.77%
180 / 186
70.59% covered (warning)
70.59%
12 / 17
CRAP
0.00% covered (danger)
0.00%
0 / 1
ZmsApiClientService
96.77% covered (success)
96.77%
180 / 186
70.59% covered (warning)
70.59%
12 / 17
65
0.00% covered (danger)
0.00%
0 / 1
 fetchSourceData
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
5
 getOffices
85.71% covered (warning)
85.71%
6 / 7
0.00% covered (danger)
0.00%
0 / 1
3.03
 getScopes
85.71% covered (warning)
85.71%
6 / 7
0.00% covered (danger)
0.00%
0 / 1
3.03
 getServices
85.71% covered (warning)
85.71%
6 / 7
0.00% covered (danger)
0.00%
0 / 1
3.03
 getRequestRelationList
85.71% covered (warning)
85.71%
6 / 7
0.00% covered (danger)
0.00%
0 / 1
3.03
 getFreeDays
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
6
 getFreeTimeslots
100.00% covered (success)
100.00%
23 / 23
100.00% covered (success)
100.00%
1 / 1
8
 reserveTimeslot
100.00% covered (success)
100.00%
26 / 26
100.00% covered (success)
100.00%
1 / 1
6
 submitClientData
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
3
 preconfirmProcess
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
3
 confirmProcess
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
3
 cancelAppointment
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
3
 sendConfirmationEmail
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
3
 sendPreconfirmationEmail
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
3
 sendCancellationEmail
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
3
 getProcessById
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
3
 getScopesByProviderId
77.78% covered (warning)
77.78%
7 / 9
0.00% covered (danger)
0.00%
0 / 1
4.18
1<?php
2
3declare(strict_types=1);
4
5namespace BO\Zmscitizenapi\Services\Core;
6
7use BO\Zmscitizenapi\Helper\ClientIpHelper;
8use BO\Zmscitizenapi\Services\Core\LoggerService;
9use BO\Zmscitizenapi\Services\Core\ExceptionService;
10use BO\Zmsentities\Calendar;
11use BO\Zmsentities\Process;
12use BO\Zmsentities\Source;
13use BO\Zmsentities\Collection\DayList;
14use BO\Zmsentities\Collection\ProcessList;
15use BO\Zmsentities\Collection\ProviderList;
16use BO\Zmsentities\Collection\RequestList;
17use BO\Zmsentities\Collection\RequestRelationList;
18use BO\Zmsentities\Collection\ScopeList;
19
20class ZmsApiClientService
21{
22    private static function fetchSourceData(): Source
23    {
24        $cacheKey = 'source_' . \App::$source_name;
25        if (\App::$cache && ($data = \App::$cache->get($cacheKey))) {
26            return $data;
27        }
28
29        $result = \App::$http->readGetResult('/source/' . \App::$source_name . '/', [
30            'resolveReferences' => 2,
31        ]);
32        $entity = $result?->getEntity();
33        if (!$entity instanceof Source) {
34            return new Source();
35        }
36
37        if (\App::$cache) {
38            \App::$cache->set($cacheKey, $entity, \App::$SOURCE_CACHE_TTL);
39            LoggerService::logInfo('Cache set', [
40                'key' => $cacheKey,
41                'ttl' => \App::$SOURCE_CACHE_TTL,
42                'entity_type' => get_class($entity)
43            ]);
44        }
45
46        return $entity;
47    }
48
49    public static function getOffices(): ProviderList
50    {
51        try {
52            $sources = self::fetchSourceData();
53            $list = $sources?->getProviderList();
54            if (!$list instanceof ProviderList) {
55                return new ProviderList();
56            }
57            return $list;
58        } catch (\Exception $e) {
59            ExceptionService::handleException($e);
60        }
61    }
62
63    public static function getScopes(): ScopeList
64    {
65        try {
66            $sources = self::fetchSourceData();
67            $list = $sources?->getScopeList();
68            if (!$list instanceof ScopeList) {
69                return new ScopeList();
70            }
71            return $list;
72        } catch (\Exception $e) {
73            ExceptionService::handleException($e);
74        }
75    }
76
77    public static function getServices(): RequestList
78    {
79        try {
80            $sources = self::fetchSourceData();
81            $list = $sources?->getRequestList();
82            if (!$list instanceof RequestList) {
83                return new RequestList();
84            }
85            return $list;
86        } catch (\Exception $e) {
87            ExceptionService::handleException($e);
88        }
89    }
90
91    public static function getRequestRelationList(): RequestRelationList
92    {
93        try {
94            $sources = self::fetchSourceData();
95            $list = $sources?->getRequestRelationList();
96            if (!$list instanceof RequestRelationList) {
97                return new RequestRelationList();
98            }
99            return $list;
100        } catch (\Exception $e) {
101            ExceptionService::handleException($e);
102        }
103    }
104
105    public static function getFreeDays(ProviderList $providers, RequestList $requests, array $firstDay, array $lastDay): Calendar
106    {
107        try {
108            $calendar = new Calendar();
109            $calendar->firstDay = $firstDay;
110            $calendar->lastDay = $lastDay;
111            $calendar->providers = $providers;
112            $calendar->requests = $requests;
113            $result = \App::$http->readPostResult('/calendar/', $calendar);
114            $entity = $result?->getEntity();
115
116            if (!$entity instanceof Calendar) {
117                return new Calendar();
118            }
119            $bookableDays = new DayList();
120            foreach ($entity->days as $day) {
121                if (isset($day['status']) && $day['status'] === 'bookable') {
122                    $bookableDays->addEntity($day);
123                }
124            }
125            $entity->days = $bookableDays;
126
127            return $entity;
128        } catch (\Exception $e) {
129            ExceptionService::handleException($e);
130        }
131    }
132
133    public static function getFreeTimeslots(ProviderList $providers, RequestList $requests, array $firstDay, array $lastDay): ProcessList
134    {
135        try {
136            $calendar = new Calendar();
137            $calendar->firstDay = $firstDay;
138            $calendar->lastDay = $lastDay;
139            $calendar->providers = $providers;
140            $calendar->requests = $requests;
141            $result = \App::$http->readPostResult('/process/status/free/', $calendar);
142            $collection = $result?->getCollection();
143            if (!$collection instanceof ProcessList) {
144                return new ProcessList();
145            }
146
147            $uniqueProcesses = new ProcessList();
148            $seenKeys = [];
149            foreach ($collection as $process) {
150                $appointment = $process->appointments->getFirst();
151                $providerId = isset($process->scope->provider->id) ? $process->scope->provider->id : null;
152                if ($appointment && $providerId) {
153                    $key = $providerId . '_' . $appointment->date;
154                    if (!isset($seenKeys[$key])) {
155                        $uniqueProcesses->addEntity($process);
156                        $seenKeys[$key] = true;
157                    }
158                } else {
159                    $uniqueProcesses->addEntity($process);
160                }
161            }
162
163            return $uniqueProcesses;
164        } catch (\Exception $e) {
165            ExceptionService::handleException($e);
166        }
167    }
168
169    public static function reserveTimeslot(Process $appointmentProcess, array $serviceIds, array $serviceCounts): Process
170    {
171        try {
172            $requests = [];
173            foreach ($serviceIds as $index => $serviceId) {
174                $count = intval($serviceCounts[$index]);
175                for ($i = 0; $i < $count; $i++) {
176                    $requests[] = [
177                        'id' => $serviceId,
178                        'source' => \App::$source_name
179                    ];
180                }
181            }
182
183            $processEntity = new Process();
184            $processEntity->appointments = $appointmentProcess->appointments ?? [];
185            $processEntity->authKey = $appointmentProcess->authKey ?? null;
186            $processEntity->clients = $appointmentProcess->clients ?? [];
187            $processEntity->scope = $appointmentProcess->scope ?? null;
188            $processEntity->requests = $requests;
189            $processEntity->lastChange = $appointmentProcess->lastChange ?? time();
190            $processEntity->createIP = ClientIpHelper::getClientIp();
191            $processEntity->createTimestamp = time();
192            if (isset($appointmentProcess->queue)) {
193                $processEntity->queue = $appointmentProcess->queue;
194            }
195
196            $result = \App::$http->readPostResult('/process/status/reserved/', $processEntity);
197            $entity = $result?->getEntity();
198            if (!$entity instanceof Process) {
199                return new Process();
200            }
201            return $entity;
202        } catch (\Exception $e) {
203            ExceptionService::handleException($e);
204        }
205    }
206
207    public static function submitClientData(Process $process): Process
208    {
209        try {
210            $url = "/process/{$process->id}/{$process->authKey}/";
211            $result = \App::$http->readPostResult($url, $process);
212            $entity = $result?->getEntity();
213            if (!$entity instanceof Process) {
214                return new Process();
215            }
216            return $entity;
217        } catch (\Exception $e) {
218            ExceptionService::handleException($e);
219        }
220    }
221
222    public static function preconfirmProcess(Process $process): Process
223    {
224        try {
225            $url = '/process/status/preconfirmed/';
226            $result = \App::$http->readPostResult($url, $process);
227            $entity = $result?->getEntity();
228            if (!$entity instanceof Process) {
229                return new Process();
230            }
231            return $entity;
232        } catch (\Exception $e) {
233            ExceptionService::handleException($e);
234        }
235    }
236
237    public static function confirmProcess(Process $process): Process
238    {
239        try {
240            $url = '/process/status/confirmed/';
241            $result = \App::$http->readPostResult($url, $process);
242            $entity = $result?->getEntity();
243            if (!$entity instanceof Process) {
244                return new Process();
245            }
246            return $entity;
247        } catch (\Exception $e) {
248            ExceptionService::handleException($e);
249        }
250    }
251
252    public static function cancelAppointment(Process $process): Process
253    {
254        try {
255            $url = "/process/{$process->id}/{$process->authKey}/";
256            $result = \App::$http->readDeleteResult($url, []);
257            $entity = $result?->getEntity();
258            if (!$entity instanceof Process) {
259                return new Process();
260            }
261            return $entity;
262        } catch (\Exception $e) {
263            ExceptionService::handleException($e);
264        }
265    }
266
267    public static function sendConfirmationEmail(Process $process): Process
268    {
269        try {
270            $url = "/process/{$process->id}/{$process->authKey}/confirmation/mail/";
271            $result = \App::$http->readPostResult($url, $process);
272            $entity = $result?->getEntity();
273            if (!$entity instanceof Process) {
274                return new Process();
275            }
276            return $entity;
277        } catch (\Exception $e) {
278            ExceptionService::handleException($e);
279        }
280    }
281
282    public static function sendPreconfirmationEmail(Process $process): Process
283    {
284        try {
285            $url = "/process/{$process->id}/{$process->authKey}/preconfirmation/mail/";
286            $result = \App::$http->readPostResult($url, $process);
287            $entity = $result?->getEntity();
288            if (!$entity instanceof Process) {
289                return new Process();
290            }
291            return $entity;
292        } catch (\Exception $e) {
293            ExceptionService::handleException($e);
294        }
295    }
296
297    public static function sendCancellationEmail(Process $process): Process
298    {
299        try {
300            $url = "/process/{$process->id}/{$process->authKey}/delete/mail/";
301            $result = \App::$http->readPostResult($url, $process);
302            $entity = $result?->getEntity();
303            if (!$entity instanceof Process) {
304                return new Process();
305            }
306            return $entity;
307        } catch (\Exception $e) {
308            ExceptionService::handleException($e);
309        }
310    }
311
312    public static function getProcessById(int $processId, string $authKey): Process
313    {
314        try {
315            $resolveReferences = 2;
316            $result = \App::$http->readGetResult("/process/{$processId}/{$authKey}/", [
317                'resolveReferences' => $resolveReferences
318            ]);
319            $entity = $result?->getEntity();
320            if (!$entity instanceof Process) {
321                return new Process();
322            }
323            return $entity;
324        } catch (\Exception $e) {
325            ExceptionService::handleException($e);
326        }
327    }
328
329    public static function getScopesByProviderId(string $source, string|int $providerId): ScopeList
330    {
331        try {
332            $scopeList = self::getScopes();
333            if (!$scopeList instanceof ScopeList) {
334                return new ScopeList();
335            }
336            $result = $scopeList->withProviderID($source, (string) $providerId);
337            if (!$result instanceof ScopeList) {
338                return new ScopeList();
339            }
340            return $result;
341        } catch (\Exception $e) {
342            ExceptionService::handleException($e);
343        }
344    }
345}