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