Lines 94.44% 34 / 36
Methods 71.42% 5 / 7
Classes 0.00% 0 / 1
Name Lines Methods CRAP
 processCancel 94.11% 16 / 17 0.00% 0 / 1 6.01
 extractClientData 100.00% 8 / 8 100.00% 1 / 1 6
 validateClientData 100.00% 1 / 1 100.00% 1 / 1 1
 getProcess 100.00% 1 / 1 100.00% 1 / 1 1
 canBeCancelled 100.00% 2 / 2 100.00% 1 / 1 1
 cancelProcess 80.00% 4 / 5 0.00% 0 / 1 3.07
 sendCancellationEmail 100.00% 2 / 2 100.00% 1 / 1 1
13class AppointmentCancelService
14{
15    public function processCancel(array $body, ?AuthenticatedUser $authenticatedUser): ThinnedProcess|array
16    {
17        $clientData = $this->extractClientData($body);
18        $errors = $this->validateClientData($clientData);
19        if (!empty($errors['errors'])) {
20            return $errors;
21        }
22
23        $process = $this->getProcess($clientData->processId, $clientData->authKey, $authenticatedUser);
24
25        if (is_array($process) && !empty($process['errors'])) {
26            return $process;
27        }
28
29        if (!$this->canBeCancelled($process)) {
30            return ['errors' => [
31                [
32                    'errorCode' => 'appointmentCanNotBeCanceled',
33                    'statusCode' => 406
34                ]
35            ]];
36        }
37
38        if ($process->status !== 'reserved') {
39            // Todo: check if the email template cancelled exists for the scope before submitting and sending
40            $this->sendCancellationEmail($process);
41        }
42
43        return $this->cancelProcess($process);
44    }
45
46    private function extractClientData(array $body): object
47    {
48        return (object) [
49            'processId' => isset($body['processId']) && is_numeric($body['processId'])
50                ? (int) $body['processId']
51                : null,
52            'authKey' => isset($body['authKey']) && is_string($body['authKey']) && trim($body['authKey']) !== ''
53                ? htmlspecialchars(trim($body['authKey']), ENT_QUOTES, 'UTF-8')
54                : null
55        ];
56    }
57
58    private function validateClientData(object $data): array
59    {
60        return ValidationService::validateGetProcessById($data->processId, $data->authKey);
61    }
62
63    private function getProcess(int $processId, ?string $authKey, ?AuthenticatedUser $user): ThinnedProcess|array
64    {
65        return ZmsApiFacadeService::getThinnedProcessById($processId, $authKey, $user);
66    }
67
68    private function canBeCancelled(ThinnedProcess $process): bool
69    {
70        $appointmentTime = new \DateTimeImmutable("@{$process->timestamp}");
71        return $appointmentTime > \App::$now;
72    }
73
74    private function cancelProcess(ThinnedProcess $process): ThinnedProcess|array
75    {
76        $processEntity = MapperService::thinnedProcessToProcess($process);
77        $result = ZmsApiFacadeService::cancelAppointment($processEntity);
78        if (is_array($result) && !empty($result['errors'])) {
79            return $result;
80        }
81
82        return MapperService::processToThinnedProcess($result);
83    }
84
85    private function sendCancellationEmail(ThinnedProcess $process): void
86    {
87        $processEntity = MapperService::thinnedProcessToProcess($process);
88        ZmsApiFacadeService::sendCancellationEmail($processEntity);
89    }
90}