PluginProbe ʕ •ᴥ•ʔ
Booking for Appointments and Events Calendar – Amelia / trunk
Booking for Appointments and Events Calendar – Amelia vtrunk
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 2 months ago AddBookingCommand.php 1 year ago AddBookingCommandHandler.php 1 year ago ApproveBookingRemotelyCommand.php 1 year ago ApproveBookingRemotelyCommandHandler.php 2 months ago CancelBookingCommand.php 1 year ago CancelBookingCommandHandler.php 6 months ago CancelBookingRemotelyCommand.php 1 year ago CancelBookingRemotelyCommandHandler.php 1 month ago DeleteAppointmentCommand.php 1 year ago DeleteAppointmentCommandHandler.php 1 year ago DeleteBookingCommand.php 1 year ago DeleteBookingCommandHandler.php 10 months ago DeleteBookingRemotelyCommand.php 10 months ago DeleteBookingRemotelyCommandHandler.php 6 months ago GetAppointmentBookingsCommand.php 6 months ago GetAppointmentBookingsCommandHandler.php 2 months ago GetAppointmentCommand.php 7 years ago GetAppointmentCommandHandler.php 2 weeks ago GetAppointmentsCommand.php 1 year ago GetAppointmentsCommandHandler.php 2 weeks ago GetIcsCommand.php 6 months ago GetIcsCommandHandler.php 4 years ago GetTimeSlotsCommand.php 1 year ago GetTimeSlotsCommandHandler.php 1 month ago ReassignBookingCommand.php 1 year ago ReassignBookingCommandHandler.php 3 months ago RejectBookingRemotelyCommand.php 1 year ago RejectBookingRemotelyCommandHandler.php 4 months ago SuccessfulBookingCommand.php 1 year ago SuccessfulBookingCommandHandler.php 1 year ago UpdateAppointmentCommand.php 1 year ago UpdateAppointmentCommandHandler.php 3 months ago UpdateAppointmentNoteCommand.php 3 months ago UpdateAppointmentNoteCommandHandler.php 3 months ago UpdateAppointmentStatusCommand.php 1 year ago UpdateAppointmentStatusCommandHandler.php 2 months ago UpdateAppointmentTimeCommand.php 1 year ago UpdateAppointmentTimeCommandHandler.php 1 month ago UpdateBookingStatusCommand.php 1 year ago UpdateBookingStatusCommandHandler.php 5 months ago
AddAppointmentCommandHandler.php
421 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 ($existingAppointment && !empty($appointmentData['internalNotes'])) {
171 if (
172 $existingAppointment->getInternalNotes() &&
173 $existingAppointment->getInternalNotes()->getValue()
174 ) {
175 $appointment->setInternalNotes(
176 new Description(
177 $existingAppointment->getInternalNotes()->getValue() .
178 PHP_EOL .
179 PHP_EOL .
180 $appointmentData['internalNotes']
181 )
182 );
183 } else {
184 $appointment->setInternalNotes(
185 new Description(
186 $appointmentData['internalNotes']
187 )
188 );
189 }
190 }
191
192 try {
193 $appointmentAS->addOrEditAppointment(
194 $appointment,
195 $existingAppointment,
196 $service,
197 $appointmentData,
198 $paymentData
199 );
200 } catch (CustomerBookedException $e) {
201 $appointmentRepo->rollback();
202
203 $result->setResult(CommandResult::RESULT_ERROR);
204 $result->setMessage($e->getMessage());
205 $result->setData(
206 [
207 'customerAlreadyBooked' => true
208 ]
209 );
210
211 return $result;
212 } catch (BookingUnavailableException $e) {
213 $appointmentRepo->rollback();
214
215 $result->setResult(CommandResult::RESULT_ERROR);
216 $result->setMessage($e->getMessage());
217 $result->setData(
218 [
219 'timeSlotUnavailable' => true
220 ]
221 );
222
223 return $result;
224 }
225
226 foreach ($appointmentData['bookings'] as $bookingData) {
227 $paymentData['customerPaymentParentId'][(int)$bookingData['customerId']] = null;
228 $paymentData['customerPaymentInvoiceNumber'][(int)$bookingData['customerId']] = null;
229 }
230
231 /** @var CustomerBooking $booking */
232 foreach ($appointment->getBookings()->getItems() as $booking) {
233 if (
234 $booking->getCustomerId() &&
235 $booking->getCustomerId()->getValue() &&
236 $booking->getPayments() &&
237 $booking->getPayments()->keyExists(0)
238 ) {
239 /** @var Payment $payment */
240 $payment = $booking->getPayments()->getItem(0);
241
242 if (array_key_exists($booking->getCustomerId()->getValue(), $paymentData['customerPaymentParentId'])) {
243 $paymentData['customerPaymentParentId'][$booking->getCustomerId()->getValue()]
244 = $payment->getId()->getValue();
245 }
246
247 if (array_key_exists($booking->getCustomerId()->getValue(), $paymentData['customerPaymentInvoiceNumber'])) {
248 $paymentData['customerPaymentInvoiceNumber'][$booking->getCustomerId()->getValue()]
249 = $payment->getInvoiceNumber() ? $payment->getInvoiceNumber()->getValue() : null;
250 }
251 }
252 }
253
254 if ($existingAppointment !== null) {
255 $existingAppointmentId = $existingAppointment->getId()->getValue();
256
257 $ignoredData[$existingAppointmentId] = [
258 'status' => $existingAppointment->getStatus()->getValue(),
259 'bookingsIds' => [],
260 ];
261
262 /** @var CustomerBooking $booking */
263 foreach ($existingAppointment->getBookings()->getItems() as $booking) {
264 $ignoredData[$existingAppointmentId]['bookingsIds'][$booking->getId()->getValue()] = true;
265 }
266 }
267
268 $error = false;
269
270 $recurringAppointments = [];
271
272 foreach ($command->getField('recurring') as $recurringData) {
273 $recurringAppointmentData = array_merge(
274 $appointmentData,
275 [
276 'bookingStart' => $recurringData['bookingStart'],
277 'locationId' => $recurringData['locationId'],
278 'parentId' => $appointment->getId()->getValue()
279 ]
280 );
281
282 $appointmentAS->convertTime($recurringAppointmentData);
283
284 /** @var Appointment $existingRecurringAppointment */
285 $existingRecurringAppointment = $appointmentAS->getAlreadyBookedAppointment(
286 $recurringAppointmentData,
287 false,
288 $service
289 );
290
291 /** @var Appointment $recurringAppointment */
292 $recurringAppointment = $appointmentAS->build(
293 $existingRecurringAppointment ? $existingRecurringAppointment->toArray() : $recurringAppointmentData,
294 $service
295 );
296
297 if ($existingRecurringAppointment && $recurringAppointmentData['internalNotes']) {
298 if (
299 $existingRecurringAppointment->getInternalNotes() &&
300 $existingRecurringAppointment->getInternalNotes()->getValue()
301 ) {
302 $recurringAppointment->setInternalNotes(
303 new Description(
304 $existingRecurringAppointment->getInternalNotes()->getValue() .
305 PHP_EOL .
306 PHP_EOL .
307 $recurringAppointmentData['internalNotes']
308 )
309 );
310 } else {
311 $recurringAppointment->setInternalNotes(
312 new Description(
313 $recurringAppointmentData['internalNotes']
314 )
315 );
316 }
317 }
318
319 try {
320 $appointmentAS->addOrEditAppointment(
321 $recurringAppointment,
322 $existingRecurringAppointment,
323 $service,
324 $recurringAppointmentData,
325 $paymentData
326 );
327 } catch (CustomerBookedException $e) {
328 $appointmentRepo->rollback();
329
330 $result->setResult(CommandResult::RESULT_ERROR);
331 $result->setMessage($e->getMessage());
332 $result->setData(
333 [
334 'customerAlreadyBooked' => true
335 ]
336 );
337
338 $error = true;
339 } catch (BookingUnavailableException $e) {
340 $appointmentRepo->rollback();
341
342 $result->setResult(CommandResult::RESULT_ERROR);
343 $result->setMessage($e->getMessage());
344 $result->setData(
345 [
346 'timeSlotUnavailable' => true
347 ]
348 );
349
350 $error = true;
351 }
352
353 if ($error) {
354 $appointmentAS->delete($appointment, $ignoredData);
355
356 if (
357 $appointment->getId() &&
358 $appointment->getId()->getValue() &&
359 !empty($ignoredData[$appointment->getId()->getValue()])
360 ) {
361 $appointmentRepo->updateFieldById(
362 $appointment->getId()->getValue(),
363 $ignoredData[$appointment->getId()->getValue()]['status'],
364 'status'
365 );
366 }
367
368 foreach ($recurringAppointments as $savedRecurringAppointment) {
369 $appointmentAS->delete(
370 $appointmentAS->build($savedRecurringAppointment[Entities::APPOINTMENT], $service),
371 $ignoredData
372 );
373
374 if (!empty($ignoredData[$savedRecurringAppointment[Entities::APPOINTMENT]['id']])) {
375 $appointmentRepo->updateFieldById(
376 $savedRecurringAppointment[Entities::APPOINTMENT]['id'],
377 $ignoredData[$savedRecurringAppointment[Entities::APPOINTMENT]['id']]['status'],
378 'status'
379 );
380 }
381 }
382
383 return $result;
384 }
385
386 if ($existingRecurringAppointment !== null) {
387 $existingAppointmentId = $existingRecurringAppointment->getId()->getValue();
388
389 $ignoredData[$existingAppointmentId] = [
390 'status' => $existingRecurringAppointment->getStatus()->getValue(),
391 'bookingsIds' => [],
392 ];
393
394 /** @var CustomerBooking $booking */
395 foreach ($existingRecurringAppointment->getBookings()->getItems() as $booking) {
396 $ignoredData[$existingAppointmentId]['bookingsIds'][$booking->getId()->getValue()] = true;
397 }
398 }
399
400 $recurringAppointments[] = [
401 Entities::APPOINTMENT => $recurringAppointment->toArray()
402 ];
403 }
404
405 $result->setResult(CommandResult::RESULT_SUCCESS);
406 $result->setMessage('Successfully added new appointment');
407 $result->setData(
408 [
409 Entities::APPOINTMENT => $appointment->toArray(),
410 'recurring' => $recurringAppointments
411 ]
412 );
413
414 $appointmentRepo->commit();
415
416 do_action('amelia_after_appointment_added', $appointment ? $appointment->toArray() : null, $service ? $service->toArray() : null, $paymentData);
417
418 return $result;
419 }
420 }
421