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