Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
92.41% covered (success)
92.41%
73 / 79
33.33% covered (danger)
33.33%
1 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
ProcessUpdate
92.41% covered (success)
92.41%
73 / 79
33.33% covered (danger)
33.33%
1 / 3
16.11
0.00% covered (danger)
0.00%
0 / 1
 readResponse
91.38% covered (success)
91.38%
53 / 58
0.00% covered (danger)
0.00%
0 / 1
10.06
 testProcessData
85.71% covered (warning)
85.71%
6 / 7
0.00% covered (danger)
0.00%
0 / 1
5.07
 syncOverviewCalendarFromProcess
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3/**
4 * @package ZMS API
5 * @copyright BerlinOnline Stadtportal GmbH & Co. KG
6 **/
7
8namespace BO\Zmsbackend\Process\Api;
9
10use BO\Slim\Render;
11use BO\Zmsbackend\Config\Service\Config;
12use BO\Zmsbackend\Log\Service\Log;
13use BO\Zmsbackend\Mail\Service\Mail;
14use BO\Mellon\Validator;
15use BO\Zmsbackend\Process\Service\Process;
16
17/**
18 * @SuppressWarnings(Coupling)
19 * @return \Psr\Http\Message\ResponseInterface
20 */
21class ProcessUpdate extends \BO\Zmsbackend\Api\BaseController
22{
23    /**
24     * @SuppressWarnings(Param)
25     * @SuppressWarnings(Complexity)
26     * @return \Psr\Http\Message\ResponseInterface
27     */
28    #[\Override]
29    public function readResponse(
30        \Psr\Http\Message\RequestInterface $request,
31        \Psr\Http\Message\ResponseInterface $response,
32        array $args
33    ) {
34        $slotsRequired = Validator::param('slotsRequired')->isNumber()->getValue();
35        $slotType = Validator::param('slotType')->isString()->getValue();
36        $clientKey = Validator::param('clientkey')->isString()->getValue();
37        $initiator = Validator::param('initiator')->isString()->getValue();
38        $resolveReferences = Validator::param('resolveReferences')->isNumber()->setDefault(2)->getValue();
39        $input = Validator::input()->isJson()->assertValid()->getValue();
40        $entity = new \BO\Zmsentities\Process($input);
41        $entity->testValid();
42        $this->testProcessData($entity, ! $initiator);
43
44        \BO\Zmsbackend\Connection\Select::setCriticalReadSession();
45        $workstation = (new \BO\Zmsbackend\Helper\User($request))->readWorkstation();
46
47        if ($slotType || $slotsRequired) {
48            $process = \BO\Zmsbackend\Process\Service\Process::init()->updateEntityWithSlots(
49                $entity,
50                \App::$now,
51                $slotType,
52                $slotsRequired,
53                $resolveReferences,
54                $workstation->getUseraccount()
55            );
56            \BO\Zmsbackend\Helper\Matching::testCurrentScopeHasRequest($process);
57            $this->syncOverviewCalendarFromProcess($entity, $process);
58        } elseif ($clientKey) {
59            $apiClient = (new \BO\Zmsbackend\Apikey\Service\Apiclient())->readEntity($clientKey);
60            if (!$apiClient || !isset($apiClient->accesslevel) || $apiClient->accesslevel == 'blocked') {
61                throw new \BO\Zmsbackend\Process\Exception\ApiclientInvalid();
62            }
63            $entity->apiclient = $apiClient;
64            $process = (new \BO\Zmsbackend\Process\Service\Process())->updateEntity(
65                $entity,
66                \App::$now,
67                $resolveReferences,
68                null,
69                $workstation->getUseraccount()
70            );
71        } else {
72            $process = (new \BO\Zmsbackend\Process\Service\Process())->updateEntity(
73                $entity,
74                \App::$now,
75                $resolveReferences,
76                null,
77                $workstation->getUseraccount()
78            );
79
80            \BO\Zmsbackend\Log\Service\Log::writeProcessLog(
81                "UPDATE (ProcessUpdate.php) $process ",
82                \BO\Zmsbackend\Log\Service\Log::ACTION_CALLED,
83                $process,
84                $workstation->getUseraccount()
85            );
86            $this->syncOverviewCalendarFromProcess($entity, $process);
87        }
88
89        if ($initiator && $process->hasScopeAdmin() && $process->sendAdminMailOnUpdated()) {
90            $config = (new \BO\Zmsbackend\Config\Service\Config())->readEntity();
91
92            $mail = (new \BO\Zmsentities\Mail())
93                    ->setTemplateProvider(new \BO\Zmsbackend\Helper\MailTemplateProvider($process))
94                    ->toResolvedEntity($process, $config, 'updated', $initiator);
95            (new \BO\Zmsbackend\Mail\Service\Mail())->writeInQueueWithAdmin($mail);
96        }
97        $message = \BO\Zmsbackend\Api\Response\Message::create($request);
98        $message->data = $process;
99
100        $response = Render::withLastModified($response, time(), '0');
101
102        return Render::withJson($response, $message->setUpdatedMetaData(), $message->getStatuscode());
103    }
104
105    /**
106     * @return void
107     */
108    protected function testProcessData(\BO\Zmsentities\Process $entity, bool $checkMailLimit = true)
109    {
110        $authCheck = (new \BO\Zmsbackend\Process\Service\Process())->readAuthKeyByProcessId($entity->id);
111
112        if ($checkMailLimit && ! (new \BO\Zmsbackend\Process\Service\Process())->isAppointmentAllowedWithSameMail($entity)) {
113            throw new \BO\Zmsbackend\Process\Exception\MoreThanAllowedAppointmentsPerMail();
114        }
115
116        /*if (! (new \BO\Zmsbackend\Process\Service\Process())->isAppointmentSlotCountAllowed($entity)) {
117            throw new \BO\Zmsbackend\Process\Exception\MoreThanAllowedSlotsPerAppointment();
118        } Should be moved to zmscitizenapi. */
119
120        // Note: isServiceQuantityAllowed is only checked in ProcessPreconfirm/ProcessConfirm
121        // to reduce DB queries on this frequently-called endpoint
122
123        if (! $authCheck) {
124            throw new \BO\Zmsbackend\Process\Exception\ProcessNotFound();
125        } elseif ($authCheck['authKey'] !== $entity->authKey) {
126            throw new \BO\Zmsbackend\Process\Exception\AuthKeyMatchFailed();
127        }
128    }
129
130    private function syncOverviewCalendarFromProcess(
131        \BO\Zmsentities\Process $entity,
132        \BO\Zmsentities\Process $process
133    ): void {
134        $appointment        = $entity->getFirstAppointment();
135        $connectionTimezone = new \DateTimeZone(\BO\Zmsbackend\Connection\Select::$connectionTimezone);
136
137        $startsAt = (new \DateTimeImmutable('@' . $appointment->date))
138            ->setTimezone($connectionTimezone);
139
140        $slotCount = (int) $appointment->slotCount;
141        $scopeId   = (int) $appointment->scope->id;
142
143        $slotTimeInMinutes = (int) $process->getFirstAppointment()->availability->slotTimeInMinutes;
144
145        $endsAt = $startsAt->modify('+' . ($slotCount * $slotTimeInMinutes) . ' minutes');
146
147        (new \BO\Zmsbackend\OverviewCalendar\Service\OverviewCalendar())->updateByProcess(
148            (int) $entity->id,
149            $scopeId,
150            $startsAt,
151            $endsAt
152        );
153    }
154}