PluginProbe ʕ •ᴥ•ʔ
Booking for Appointments and Events Calendar – Amelia / 1.2.31
Booking for Appointments and Events Calendar – Amelia v1.2.31
2.4.5 2.4.4 2.4.3 2.4.2 2.4.1 2.4 trunk 1.2.1 1.2.10 1.2.11 1.2.12 1.2.13 1.2.14 1.2.15 1.2.16 1.2.17 1.2.18 1.2.19 1.2.2 1.2.20 1.2.21 1.2.22 1.2.23 1.2.24 1.2.25 1.2.26 1.2.27 1.2.28 1.2.29 1.2.3 1.2.30 1.2.31 1.2.32 1.2.33 1.2.34 1.2.35 1.2.36 1.2.37 1.2.38 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 2.0 2.0.1 2.0.2 2.1 2.1.1 2.1.2 2.1.3 2.2 2.2.1 2.3
ameliabooking / src / Application / Commands / Booking / Appointment / AddAppointmentCommandHandler.php
ameliabooking / src / Application / Commands / Booking / Appointment Last commit date
AddAppointmentCommand.php 1 year ago AddAppointmentCommandHandler.php 1 year ago AddBookingCommand.php 1 year ago AddBookingCommandHandler.php 1 year ago ApproveBookingRemotelyCommand.php 1 year ago ApproveBookingRemotelyCommandHandler.php 1 year ago CancelBookingCommand.php 1 year ago CancelBookingCommandHandler.php 1 year ago CancelBookingRemotelyCommand.php 1 year ago CancelBookingRemotelyCommandHandler.php 2 years ago DeleteAppointmentCommand.php 1 year ago DeleteAppointmentCommandHandler.php 1 year ago DeleteBookingCommand.php 1 year ago DeleteBookingCommandHandler.php 1 year ago GetAppointmentCommand.php 7 years ago GetAppointmentCommandHandler.php 1 year ago GetAppointmentsCommand.php 1 year ago GetAppointmentsCommandHandler.php 1 year ago GetIcsCommand.php 1 year ago GetIcsCommandHandler.php 4 years ago GetPackageAppointmentsCommand.php 1 year ago GetPackageAppointmentsCommandHandler.php 1 year ago GetTimeSlotsCommand.php 1 year ago GetTimeSlotsCommandHandler.php 1 year ago ReassignBookingCommand.php 1 year ago ReassignBookingCommandHandler.php 1 year ago RejectBookingRemotelyCommand.php 1 year ago RejectBookingRemotelyCommandHandler.php 1 year ago SuccessfulBookingCommand.php 1 year ago SuccessfulBookingCommandHandler.php 1 year ago UpdateAppointmentCommand.php 1 year ago UpdateAppointmentCommandHandler.php 1 year ago UpdateAppointmentStatusCommand.php 1 year ago UpdateAppointmentStatusCommandHandler.php 1 year ago UpdateAppointmentTimeCommand.php 1 year ago UpdateAppointmentTimeCommandHandler.php 1 year ago UpdateBookingStatusCommand.php 1 year ago UpdateBookingStatusCommandHandler.php 1 year ago
AddAppointmentCommandHandler.php
398 lines
1 <?php
2
3 namespace AmeliaBooking\Application\Commands\Booking\Appointment;
4
5 use AmeliaBooking\Application\Commands\CommandHandler;
6 use AmeliaBooking\Application\Commands\CommandResult;
7 use AmeliaBooking\Application\Common\Exceptions\AccessDeniedException;
8 use AmeliaBooking\Application\Services\Bookable\BookableApplicationService;
9 use AmeliaBooking\Application\Services\Booking\AppointmentApplicationService;
10 use AmeliaBooking\Application\Services\Entity\EntityApplicationService;
11 use AmeliaBooking\Application\Services\User\UserApplicationService;
12 use AmeliaBooking\Domain\Common\Exceptions\AuthorizationException;
13 use AmeliaBooking\Domain\Common\Exceptions\BookingUnavailableException;
14 use AmeliaBooking\Domain\Common\Exceptions\CustomerBookedException;
15 use AmeliaBooking\Domain\Common\Exceptions\InvalidArgumentException;
16 use AmeliaBooking\Domain\Entity\Bookable\Service\Service;
17 use AmeliaBooking\Domain\Entity\Booking\Appointment\Appointment;
18 use AmeliaBooking\Domain\Entity\Booking\Appointment\CustomerBooking;
19 use AmeliaBooking\Domain\Entity\Entities;
20 use AmeliaBooking\Domain\Entity\Payment\Payment;
21 use AmeliaBooking\Domain\Entity\User\AbstractUser;
22 use AmeliaBooking\Domain\Services\Reservation\ReservationServiceInterface;
23 use AmeliaBooking\Domain\Services\Settings\SettingsService;
24 use AmeliaBooking\Domain\ValueObjects\PositiveDuration;
25 use AmeliaBooking\Domain\ValueObjects\String\BookingStatus;
26 use AmeliaBooking\Domain\ValueObjects\String\Description;
27 use AmeliaBooking\Infrastructure\Common\Exceptions\NotFoundException;
28 use AmeliaBooking\Infrastructure\Common\Exceptions\QueryExecutionException;
29 use AmeliaBooking\Infrastructure\Repository\Booking\Appointment\AppointmentRepository;
30 use Exception;
31 use Interop\Container\Exception\ContainerException;
32 use Slim\Exception\ContainerValueNotFoundException;
33
34 /**
35 * Class AddAppointmentCommandHandler
36 *
37 * @package AmeliaBooking\Application\Commands\Booking\Appointment
38 */
39 class AddAppointmentCommandHandler extends CommandHandler
40 {
41 /**
42 * @var array
43 */
44 public $mandatoryFields = [
45 'bookings',
46 'bookingStart',
47 'notifyParticipants',
48 'serviceId',
49 'providerId'
50 ];
51
52 /**
53 * @param AddAppointmentCommand $command
54 *
55 * @return CommandResult
56 * @throws NotFoundException
57 * @throws ContainerValueNotFoundException
58 * @throws InvalidArgumentException
59 * @throws QueryExecutionException
60 * @throws ContainerException
61 * @throws Exception
62 */
63 public function handle(AddAppointmentCommand $command)
64 {
65 $result = new CommandResult();
66
67 $this->checkMandatoryFields($command);
68
69 /** @var AppointmentRepository $appointmentRepo */
70 $appointmentRepo = $this->container->get('domain.booking.appointment.repository');
71 /** @var AppointmentApplicationService $appointmentAS */
72 $appointmentAS = $this->container->get('application.booking.appointment.service');
73 /** @var BookableApplicationService $bookableAS */
74 $bookableAS = $this->container->get('application.bookable.service');
75 /** @var UserApplicationService $userAS */
76 $userAS = $this->getContainer()->get('application.user.service');
77 /** @var SettingsService $settingsDS */
78 $settingsDS = $this->container->get('domain.settings.service');
79 /** @var EntityApplicationService $entityService */
80 $entityService = $this->container->get('application.entity.service');
81 /** @var ReservationServiceInterface $reservationService */
82 $reservationService = $this->container->get('application.reservation.service')->get(Entities::APPOINTMENT);
83
84 if ($missingEntity = $entityService->getMissingEntityForAppointment($command->getFields())) {
85 return $entityService->getMissingEntityResponse($missingEntity);
86 }
87
88 try {
89 /** @var AbstractUser $user */
90 $user = $command->getUserApplicationService()->authorization(
91 $command->getPage() === 'cabinet' ? $command->getToken() : null,
92 $command->getCabinetType()
93 );
94 } catch (AuthorizationException $e) {
95 $result->setResult(CommandResult::RESULT_ERROR);
96 $result->setData(
97 [
98 'reauthorize' => true
99 ]
100 );
101
102 return $result;
103 }
104
105 if ($userAS->isCustomer($user)) {
106 throw new AccessDeniedException('You are not allowed to update appointment');
107 }
108
109 if ($userAS->isProvider($user) && !$settingsDS->getSetting('roles', 'allowWriteAppointments')) {
110 throw new AccessDeniedException('You are not allowed to add an appointment');
111 }
112
113 $appointmentData = $command->getFields();
114
115 $paymentData = !empty($command->getField('payment')) ? array_merge($command->getField('payment'), ['isBackendBooking' => true]) :
116 ['amount' => 0, 'gateway' => 'onSite', 'isBackendBooking' => true];
117
118 /** @var Service $service */
119 $service = $bookableAS->getAppointmentService($appointmentData['serviceId'], $appointmentData['providerId']);
120
121 $appointmentData = apply_filters('amelia_before_appointment_added_filter', $appointmentData, $service ? $service->toArray() : null, $paymentData);
122
123 do_action('amelia_before_appointment_added', $appointmentData, $service ? $service->toArray() : null, $paymentData);
124
125 $maxDuration = 0;
126
127 foreach ($appointmentData['bookings'] as $booking) {
128 if ($booking['duration'] > $maxDuration && ($booking['status'] === BookingStatus::APPROVED || BookingStatus::PENDING)) {
129 $maxDuration = $booking['duration'];
130 }
131 }
132
133 if ($maxDuration) {
134 $service->setDuration(new PositiveDuration($maxDuration));
135 }
136
137 $appointmentAS->convertTime($appointmentData);
138
139 $reservationService->manageTaxes($appointmentData);
140
141 $appointmentRepo->beginTransaction();
142
143 $ignoredData = [];
144
145 /** @var Appointment $existingAppointment */
146 $existingAppointment = $appointmentAS->getAlreadyBookedAppointment($appointmentData, false, $service);
147
148 /** @var Appointment $appointment */
149 $appointment = $appointmentAS->build(
150 $existingAppointment ? $existingAppointment->toArray() : $appointmentData,
151 $service
152 );
153
154 if ($existingAppointment && !empty($appointmentData['internalNotes'])) {
155 if (
156 $existingAppointment->getInternalNotes() &&
157 $existingAppointment->getInternalNotes()->getValue()
158 ) {
159 $appointment->setInternalNotes(
160 new Description(
161 $existingAppointment->getInternalNotes()->getValue() .
162 PHP_EOL .
163 PHP_EOL .
164 $appointmentData['internalNotes']
165 )
166 );
167 } else {
168 $appointment->setInternalNotes(
169 new Description(
170 $appointmentData['internalNotes']
171 )
172 );
173 }
174 }
175
176 try {
177 $appointmentAS->addOrEditAppointment(
178 $appointment,
179 $existingAppointment,
180 $service,
181 $appointmentData,
182 $paymentData
183 );
184 } catch (CustomerBookedException $e) {
185 $appointmentRepo->rollback();
186
187 $result->setResult(CommandResult::RESULT_ERROR);
188 $result->setMessage($e->getMessage());
189 $result->setData(
190 [
191 'customerAlreadyBooked' => true
192 ]
193 );
194
195 return $result;
196 } catch (BookingUnavailableException $e) {
197 $appointmentRepo->rollback();
198
199 $result->setResult(CommandResult::RESULT_ERROR);
200 $result->setMessage($e->getMessage());
201 $result->setData(
202 [
203 'timeSlotUnavailable' => true
204 ]
205 );
206
207 return $result;
208 }
209
210 foreach ($appointmentData['bookings'] as $bookingData) {
211 $paymentData['customerPaymentParentId'][(int)$bookingData['customerId']] = null;
212 }
213
214 /** @var CustomerBooking $booking */
215 foreach ($appointment->getBookings()->getItems() as $booking) {
216 if (
217 $booking->getCustomerId() &&
218 $booking->getCustomerId()->getValue() &&
219 array_key_exists($booking->getCustomerId()->getValue(), $paymentData['customerPaymentParentId']) &&
220 $booking->getPayments() &&
221 $booking->getPayments()->keyExists(0)
222 ) {
223 /** @var Payment $payment */
224 $payment = $booking->getPayments()->getItem(0);
225
226 $paymentData['customerPaymentParentId'][$booking->getCustomerId()->getValue()]
227 = $payment->getId()->getValue();
228 }
229 }
230
231 if ($existingAppointment !== null) {
232 $existingAppointmentId = $existingAppointment->getId()->getValue();
233
234 $ignoredData[$existingAppointmentId] = [
235 'status' => $existingAppointment->getStatus()->getValue(),
236 'bookingsIds' => [],
237 ];
238
239 /** @var CustomerBooking $booking */
240 foreach ($existingAppointment->getBookings()->getItems() as $booking) {
241 $ignoredData[$existingAppointmentId]['bookingsIds'][$booking->getId()->getValue()] = true;
242 }
243 }
244
245 $error = false;
246
247 $recurringAppointments = [];
248
249 foreach ($command->getField('recurring') as $recurringData) {
250 $recurringAppointmentData = array_merge(
251 $appointmentData,
252 [
253 'bookingStart' => $recurringData['bookingStart'],
254 'locationId' => $recurringData['locationId'],
255 'parentId' => $appointment->getId()->getValue()
256 ]
257 );
258
259 $appointmentAS->convertTime($recurringAppointmentData);
260
261 /** @var Appointment $existingRecurringAppointment */
262 $existingRecurringAppointment = $appointmentAS->getAlreadyBookedAppointment(
263 $recurringAppointmentData,
264 false,
265 $service
266 );
267
268 /** @var Appointment $recurringAppointment */
269 $recurringAppointment = $appointmentAS->build(
270 $existingRecurringAppointment ? $existingRecurringAppointment->toArray() : $recurringAppointmentData,
271 $service
272 );
273
274 if ($existingRecurringAppointment && $recurringAppointmentData['internalNotes']) {
275 if (
276 $existingRecurringAppointment->getInternalNotes() &&
277 $existingRecurringAppointment->getInternalNotes()->getValue()
278 ) {
279 $recurringAppointment->setInternalNotes(
280 new Description(
281 $existingRecurringAppointment->getInternalNotes()->getValue() .
282 PHP_EOL .
283 PHP_EOL .
284 $recurringAppointmentData['internalNotes']
285 )
286 );
287 } else {
288 $recurringAppointment->setInternalNotes(
289 new Description(
290 $recurringAppointmentData['internalNotes']
291 )
292 );
293 }
294 }
295
296 try {
297 $appointmentAS->addOrEditAppointment(
298 $recurringAppointment,
299 $existingRecurringAppointment,
300 $service,
301 $recurringAppointmentData,
302 $paymentData
303 );
304 } catch (CustomerBookedException $e) {
305 $appointmentRepo->rollback();
306
307 $result->setResult(CommandResult::RESULT_ERROR);
308 $result->setMessage($e->getMessage());
309 $result->setData(
310 [
311 'customerAlreadyBooked' => true
312 ]
313 );
314
315 $error = true;
316 } catch (BookingUnavailableException $e) {
317 $appointmentRepo->rollback();
318
319 $result->setResult(CommandResult::RESULT_ERROR);
320 $result->setMessage($e->getMessage());
321 $result->setData(
322 [
323 'timeSlotUnavailable' => true
324 ]
325 );
326
327 $error = true;
328 }
329
330 if ($error) {
331 $appointmentAS->delete($appointment, $ignoredData);
332
333 if (
334 $appointment->getId() &&
335 $appointment->getId()->getValue() &&
336 !empty($ignoredData[$appointment->getId()->getValue()])
337 ) {
338 $appointmentRepo->updateFieldById(
339 $appointment->getId()->getValue(),
340 $ignoredData[$appointment->getId()->getValue()]['status'],
341 'status'
342 );
343 }
344
345 foreach ($recurringAppointments as $savedRecurringAppointment) {
346 $appointmentAS->delete(
347 $appointmentAS->build($savedRecurringAppointment[Entities::APPOINTMENT], $service),
348 $ignoredData
349 );
350
351 if (!empty($ignoredData[$savedRecurringAppointment[Entities::APPOINTMENT]['id']])) {
352 $appointmentRepo->updateFieldById(
353 $savedRecurringAppointment[Entities::APPOINTMENT]['id'],
354 $ignoredData[$savedRecurringAppointment[Entities::APPOINTMENT]['id']]['status'],
355 'status'
356 );
357 }
358 }
359
360 return $result;
361 }
362
363 if ($existingRecurringAppointment !== null) {
364 $existingAppointmentId = $existingRecurringAppointment->getId()->getValue();
365
366 $ignoredData[$existingAppointmentId] = [
367 'status' => $existingRecurringAppointment->getStatus()->getValue(),
368 'bookingsIds' => [],
369 ];
370
371 /** @var CustomerBooking $booking */
372 foreach ($existingRecurringAppointment->getBookings()->getItems() as $booking) {
373 $ignoredData[$existingAppointmentId]['bookingsIds'][$booking->getId()->getValue()] = true;
374 }
375 }
376
377 $recurringAppointments[] = [
378 Entities::APPOINTMENT => $recurringAppointment->toArray()
379 ];
380 }
381
382 $result->setResult(CommandResult::RESULT_SUCCESS);
383 $result->setMessage('Successfully added new appointment');
384 $result->setData(
385 [
386 Entities::APPOINTMENT => $appointment->toArray(),
387 'recurring' => $recurringAppointments
388 ]
389 );
390
391 $appointmentRepo->commit();
392
393 do_action('amelia_after_appointment_added', $appointment ? $appointment->toArray() : null, $service ? $service->toArray() : null, $paymentData);
394
395 return $result;
396 }
397 }
398