Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
93.94% covered (success)
93.94%
31 / 33
71.43% covered (warning)
71.43%
5 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
AppointmentCancelService
93.94% covered (success)
93.94%
31 / 33
71.43% covered (warning)
71.43%
5 / 7
18.07
0.00% covered (danger)
0.00%
0 / 1
 processCancel
93.75% covered (success)
93.75%
15 / 16
0.00% covered (danger)
0.00%
0 / 1
5.01
 extractClientData
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
6
 validateClientData
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getProcess
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 canBeCancelled
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 cancelProcess
80.00% covered (warning)
80.00%
4 / 5
0.00% covered (danger)
0.00%
0 / 1
3.07
 sendCancellationEmail
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4
5namespace BO\Zmscitizenapi\Services\Appointment;
6
7use BO\Zmscitizenapi\Models\ThinnedProcess;
8use BO\Zmscitizenapi\Services\Core\ValidationService;
9use BO\Zmscitizenapi\Services\Core\ZmsApiFacadeService;
10use BO\Zmscitizenapi\Services\Core\MapperService;
11
12class AppointmentCancelService
13{
14    public function processCancel(array $body): ThinnedProcess|array
15    {
16        $clientData = $this->extractClientData($body);
17        $errors = $this->validateClientData($clientData);
18        if (!empty($errors['errors'])) {
19            return $errors;
20        }
21
22        $process = $this->getProcess($clientData->processId, $clientData->authKey);
23        if (is_array($process) && !empty($process['errors'])) {
24            return $process;
25        }
26
27        if (!$this->canBeCancelled($process)) {
28            return ['errors' => [
29                [
30                    'errorCode' => 'appointmentCanNotBeCanceled',
31                    'statusCode' => 406
32                ]
33            ]];
34        }
35
36        $this->sendCancellationEmail($process);
37        return $this->cancelProcess($process);
38    }
39
40    private function extractClientData(array $body): object
41    {
42        return (object) [
43            'processId' => isset($body['processId']) && is_numeric($body['processId'])
44                ? (int) $body['processId']
45                : null,
46            'authKey' => isset($body['authKey']) && is_string($body['authKey']) && trim($body['authKey']) !== ''
47                ? htmlspecialchars(trim($body['authKey']), ENT_QUOTES, 'UTF-8')
48                : null
49        ];
50    }
51
52    private function validateClientData(object $data): array
53    {
54        return ValidationService::validateGetProcessById($data->processId, $data->authKey);
55    }
56
57    private function getProcess(int $processId, string $authKey): ThinnedProcess|array
58    {
59        return ZmsApiFacadeService::getThinnedProcessById($processId, $authKey);
60    }
61
62    private function canBeCancelled(ThinnedProcess $process): bool
63    {
64        $appointmentTime = new \DateTimeImmutable("@{$process->timestamp}");
65        return $appointmentTime > \App::$now;
66    }
67
68    private function cancelProcess(ThinnedProcess $process): ThinnedProcess|array
69    {
70        $processEntity = MapperService::thinnedProcessToProcess($process);
71        $result = ZmsApiFacadeService::cancelAppointment($processEntity);
72        if (is_array($result) && !empty($result['errors'])) {
73            return $result;
74        }
75
76        return MapperService::processToThinnedProcess($result);
77    }
78
79    private function sendCancellationEmail(ThinnedProcess $process): void
80    {
81        $processEntity = MapperService::thinnedProcessToProcess($process);
82        ZmsApiFacadeService::sendCancellationEmail($processEntity);
83    }
84}