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