PluginProbe ʕ •ᴥ•ʔ
Booking for Appointments and Events Calendar – Amelia / 2.4.9
Booking for Appointments and Events Calendar – Amelia v2.4.9
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 / UpdateAppointmentCommandHandler.php
ameliabooking / src / Application / Commands / Booking / Appointment Last commit date
AddAppointmentCommand.php 1 year ago AddAppointmentCommandHandler.php 3 weeks ago AddBookingCommand.php 1 year ago AddBookingCommandHandler.php 1 week ago ApproveBookingRemotelyCommand.php 1 year ago ApproveBookingRemotelyCommandHandler.php 4 months ago CancelBookingCommand.php 1 year ago CancelBookingCommandHandler.php 3 weeks 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 1 year ago DeleteBookingRemotelyCommand.php 1 year ago DeleteBookingRemotelyCommandHandler.php 1 week ago GetAppointmentBookingsCommand.php 8 months ago GetAppointmentBookingsCommandHandler.php 3 weeks ago GetAppointmentCommand.php 7 years ago GetAppointmentCommandHandler.php 3 weeks ago GetAppointmentsCommand.php 1 year ago GetAppointmentsCommandHandler.php 3 weeks ago GetIcsCommand.php 8 months ago GetIcsCommandHandler.php 4 years ago GetTimeSlotsCommand.php 1 year ago GetTimeSlotsCommandHandler.php 1 week ago ReassignBookingCommand.php 1 year ago ReassignBookingCommandHandler.php 3 weeks ago RejectBookingRemotelyCommand.php 1 year ago RejectBookingRemotelyCommandHandler.php 6 months ago SuccessfulBookingCommand.php 1 year ago SuccessfulBookingCommandHandler.php 1 week ago UpdateAppointmentCommand.php 1 year ago UpdateAppointmentCommandHandler.php 1 week ago UpdateAppointmentNoteCommand.php 4 months ago UpdateAppointmentNoteCommandHandler.php 3 weeks ago UpdateAppointmentStatusCommand.php 1 year ago UpdateAppointmentStatusCommandHandler.php 1 week ago UpdateAppointmentTimeCommand.php 1 year ago UpdateAppointmentTimeCommandHandler.php 3 weeks ago UpdateBookingStatusCommand.php 1 year ago UpdateBookingStatusCommandHandler.php 7 months ago
UpdateAppointmentCommandHandler.php
460 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\Booking\BookingApplicationService;
11 use AmeliaBooking\Application\Services\CustomField\AbstractCustomFieldApplicationService;
12 use AmeliaBooking\Application\Services\Entity\EntityApplicationService;
13 use AmeliaBooking\Application\Services\Payment\PaymentApplicationService;
14 use AmeliaBooking\Application\Services\Reservation\AppointmentReservationService;
15 use AmeliaBooking\Application\Services\User\UserApplicationService;
16 use AmeliaBooking\Domain\Collection\Collection;
17 use AmeliaBooking\Domain\Common\Exceptions\InvalidArgumentException;
18 use AmeliaBooking\Domain\Entity\Bookable\Service\Service;
19 use AmeliaBooking\Domain\Entity\Booking\Appointment\Appointment;
20 use AmeliaBooking\Domain\Entity\Booking\Appointment\CustomerBooking;
21 use AmeliaBooking\Domain\Entity\Entities;
22 use AmeliaBooking\Domain\Entity\User\AbstractUser;
23 use AmeliaBooking\Domain\Entity\User\Provider;
24 use AmeliaBooking\Domain\Factory\Booking\Appointment\CustomerBookingFactory;
25 use AmeliaBooking\Domain\Services\DateTime\DateTimeService;
26 use AmeliaBooking\Domain\Services\Settings\SettingsService;
27 use AmeliaBooking\Domain\ValueObjects\BooleanValueObject;
28 use AmeliaBooking\Domain\ValueObjects\DateTime\DateTimeValue;
29 use AmeliaBooking\Domain\ValueObjects\Number\Float\Price;
30 use AmeliaBooking\Domain\ValueObjects\Number\Integer\IntegerValue;
31 use AmeliaBooking\Domain\ValueObjects\String\BookingStatus;
32 use AmeliaBooking\Infrastructure\Common\Exceptions\NotFoundException;
33 use AmeliaBooking\Infrastructure\Common\Exceptions\QueryExecutionException;
34 use AmeliaBooking\Infrastructure\Repository\Booking\Appointment\AppointmentRepository;
35 use AmeliaBooking\Infrastructure\Repository\Booking\Appointment\CustomerBookingRepository;
36 use AmeliaBooking\Infrastructure\Repository\Payment\PaymentRepository;
37 use AmeliaBooking\Infrastructure\Repository\User\ProviderRepository;
38 use AmeliaBooking\Infrastructure\Repository\User\UserRepository;
39 use AmeliaBooking\Infrastructure\WP\Translations\FrontendStrings;
40 use Exception;
41
42 /**
43 * Class UpdateAppointmentCommandHandler
44 *
45 * @package AmeliaBooking\Application\Commands\Booking\Appointment
46 */
47 class UpdateAppointmentCommandHandler extends CommandHandler
48 {
49 /**
50 * @var array
51 */
52 public $mandatoryFields = [
53 'bookings',
54 'bookingStart',
55 'notifyParticipants',
56 'serviceId',
57 'providerId',
58 'id'
59 ];
60
61 /**
62 * @param UpdateAppointmentCommand $command
63 *
64 * @return CommandResult
65 * @throws AccessDeniedException
66 * @throws InvalidArgumentException
67 * @throws QueryExecutionException
68 * @throws NotFoundException
69 * @throws Exception
70 */
71 public function handle(UpdateAppointmentCommand $command)
72 {
73 /** @var AbstractUser $user */
74 $user = $command->authorize();
75
76 $result = new CommandResult();
77
78 /** @var AppointmentRepository $appointmentRepo */
79 $appointmentRepo = $this->container->get('domain.booking.appointment.repository');
80 /** @var AppointmentApplicationService $appointmentAS */
81 $appointmentAS = $this->container->get('application.booking.appointment.service');
82 /** @var BookingApplicationService $bookingAS */
83 $bookingAS = $this->container->get('application.booking.booking.service');
84 /** @var BookableApplicationService $bookableAS */
85 $bookableAS = $this->container->get('application.bookable.service');
86 /** @var AbstractCustomFieldApplicationService $customFieldService */
87 $customFieldService = $this->container->get('application.customField.service');
88 /** @var UserApplicationService $userAS */
89 $userAS = $this->getContainer()->get('application.user.service');
90 /** @var SettingsService $settingsDS */
91 $settingsDS = $this->container->get('domain.settings.service');
92 /** @var ProviderRepository $providerRepository */
93 $providerRepository = $this->container->get('domain.users.providers.repository');
94 /** @var PaymentApplicationService $paymentAS */
95 $paymentAS = $this->container->get('application.payment.service');
96 /** @var AppointmentReservationService $reservationService */
97 $reservationService = $this->container->get('application.reservation.service')->get(Entities::APPOINTMENT);
98
99 if ($userAS->isCustomer($user)) {
100 throw new AccessDeniedException('You are not allowed to update appointment');
101 }
102
103 if ($userAS->isProvider($user) && !$settingsDS->getSetting('roles', 'allowWriteAppointments')) {
104 throw new AccessDeniedException('You are not allowed to update appointment');
105 }
106
107 $this->checkMandatoryFields($command);
108
109 $appointmentData = $command->getFields();
110
111 /** @var EntityApplicationService $entityService */
112 $entityService = $this->container->get('application.entity.service');
113
114 $entityService->removeMissingEntityForAppointment($appointmentData);
115
116 /** @var Service $service */
117 $service = $bookableAS->getAppointmentService(
118 $command->getFields()['serviceId'],
119 $command->getFields()['providerId']
120 );
121
122 $appointmentAS->convertTime($appointmentData);
123
124 $reservationService->manageTaxes($appointmentData);
125
126 $removedBookingsData = $command->getField('removedBookings');
127
128 // added check for API call when removedBookings not sent
129 $removedBookingsData = empty($removedBookingsData) ? [] : $removedBookingsData;
130
131 $appointment = apply_filters('amelia_before_appointment_updated_filter', $appointmentData, $removedBookingsData, $service ? $service->toArray() : null);
132
133 do_action('amelia_before_appointment_updated', $appointment, $removedBookingsData, $service ? $service->toArray() : null);
134
135 /** @var Appointment $appointment */
136 $appointment = $appointmentAS->build($appointmentData, $service);
137
138 /** @var ProviderRepository $providerRepository */
139 $providerRepository = $this->container->get('domain.users.providers.repository');
140
141 /** @var Provider $provider */
142 $provider = $providerRepository->getById($appointmentData['providerId']);
143
144 $appointment->setProvider($provider);
145
146 /** @var Appointment $oldAppointment */
147 $oldAppointment = $appointmentRepo->getById($appointment->getId()->getValue());
148
149 if ($userAS->isProvider($user) && $user->getId()->getValue() !== $oldAppointment->getProviderId()->getValue()) {
150 throw new AccessDeniedException('You are not allowed to update appointment');
151 }
152
153 $appointment->setInitialBookingStart(
154 new DateTimeValue(clone $oldAppointment->getBookingStart()->getValue())
155 );
156
157 $appointment->setInitialBookingEnd(
158 new DateTimeValue(clone $oldAppointment->getBookingEnd()->getValue())
159 );
160
161 /** @var CustomerBooking $newBooking */
162 foreach ($appointment->getBookings()->getItems() as $newBooking) {
163 /** @var CustomerBooking $oldBooking */
164 foreach ($oldAppointment->getBookings()->getItems() as $oldBooking) {
165 if (
166 $newBooking->getId() &&
167 $newBooking->getId()->getValue() === $oldBooking->getId()->getValue()
168 ) {
169 if ($oldBooking->getUtcOffset()) {
170 $bookingStartClone = clone $appointment->getBookingStart()->getValue();
171 if ($oldBooking->getInfo() && json_decode($oldBooking->getInfo()->getValue(), true)) {
172 $info = json_decode($oldBooking->getInfo()->getValue(), true);
173 if (!empty($info['timeZone'])) {
174 $bookingStartClone->setTimezone(new \DateTimeZone($info['timeZone']));
175 }
176 }
177 $newBooking->setUtcOffset(new IntegerValue($bookingStartClone->getOffset() / 60));
178 }
179
180 if ($oldBooking->getCreated()) {
181 $newBooking->setCreated($oldBooking->getCreated());
182 }
183
184 if ($oldBooking->getInfo()) {
185 $newBooking->setInfo($oldBooking->getInfo());
186 }
187
188 if ($oldBooking->getStatus()->getValue() === $newBooking->getStatus()->getValue()) {
189 $newBooking->setUpdated(
190 new BooleanValueObject(
191 $appointmentAS->appointmentDetailsChanged($appointment, $oldAppointment) ||
192 $appointmentAS->bookingDetailsChanged($newBooking, $oldBooking)
193 )
194 );
195 }
196
197 $newBooking->setAggregatedPrice($oldBooking->getAggregatedPrice());
198 }
199 }
200 }
201
202 $appointment->setBookingEnd(
203 new DateTimeValue(
204 DateTimeService::getCustomDateTimeObject(
205 $appointment->getBookingStart()->getValue()->format('Y-m-d H:i:s')
206 )->modify('+' . $appointmentAS->getAppointmentLengthTime($appointment, $service) . ' second')
207 )
208 );
209
210 $userConnectionChanges = $appointmentAS->getUserConnectionChanges(
211 $appointment->getProviderId()->getValue(),
212 $oldAppointment->getProviderId()->getValue()
213 );
214
215 if ($oldAppointment->getZoomMeeting()) {
216 $appointment->setZoomMeeting($oldAppointment->getZoomMeeting());
217 }
218
219 if (
220 $bookingAS->isBookingApprovedOrPending($appointment->getStatus()->getValue()) &&
221 $bookingAS->isBookingCanceledOrRejectedOrNoShow($oldAppointment->getStatus()->getValue()) &&
222 !$appointmentAS->canBeBooked($appointment, false, null, null)
223 ) {
224 $result->setResult(CommandResult::RESULT_ERROR);
225 $result->setMessage(FrontendStrings::getCommonStrings()['time_slot_unavailable']);
226 $result->setData(
227 [
228 'timeSlotUnavailable' => true
229 ]
230 );
231
232 return $result;
233 }
234
235 $appointment->setGoogleCalendarEventId($oldAppointment->getGoogleCalendarEventId());
236 $appointment->setGoogleMeetUrl($oldAppointment->getGoogleMeetUrl());
237 $appointment->setOutlookCalendarEventId($oldAppointment->getOutlookCalendarEventId());
238 $appointment->setMicrosoftTeamsUrl($oldAppointment->getMicrosoftTeamsUrl());
239 $appointment->setAppleCalendarEventId($oldAppointment->getAppleCalendarEventId());
240
241 $appointmentRepo->beginTransaction();
242
243 /** @var Collection $removedBookings */
244 $removedBookings = new Collection();
245
246 foreach ($removedBookingsData as $removedBookingData) {
247 $removedBookings->addItem(CustomerBookingFactory::create($removedBookingData), $removedBookingData['id']);
248 }
249
250 $paymentData = [];
251
252 $bookingAdded = $bookingAS->isBookingAdded($appointment->getBookings());
253
254 /** @var CustomerBooking $oldBooking */
255 foreach ($oldAppointment->getBookings()->getItems() as $oldBooking) {
256 if (
257 $appointment->getServiceId()->getValue() !== $oldAppointment->getServiceId()->getValue() &&
258 !$appointmentAS->processPackageAppointmentBooking(
259 $oldBooking,
260 $removedBookings,
261 $appointment->getServiceId()->getValue(),
262 $paymentData
263 )
264 ) {
265 $result->setResult(CommandResult::RESULT_ERROR);
266 $result->setMessage(FrontendStrings::getCommonStrings()['package_booking_unavailable']);
267 $result->setData(
268 [
269 'packageBookingUnavailable' => true
270 ]
271 );
272
273 return $result;
274 }
275 }
276
277 $paymentData = !empty($command->getField('payment')) ? array_merge($command->getField('payment'), ['isBackendBooking' => true]) :
278 ['amount' => 0, 'gateway' => 'onSite', 'isBackendBooking' => true];
279
280 try {
281 $appointmentAS->update(
282 $oldAppointment,
283 $appointment,
284 $removedBookings,
285 $service,
286 $paymentData
287 );
288 } catch (QueryExecutionException $e) {
289 $appointmentRepo->rollback();
290 throw $e;
291 }
292
293 do_action(
294 'amelia_after_appointment_updated',
295 $appointment ? $appointment->toArray() : null,
296 $oldAppointment ? $oldAppointment->toArray() : null,
297 $removedBookings ? $removedBookings->toArray() : null,
298 $service ? $service->toArray() : null,
299 $paymentData
300 );
301
302
303 $appointmentStatusChanged = $appointmentAS->isAppointmentStatusChanged($appointment, $oldAppointment);
304
305 $appRescheduled = $appointmentAS->isAppointmentRescheduled($appointment, $oldAppointment);
306
307 if ($appRescheduled) {
308 if (!$appointmentAS->canBeBooked($appointment, false, null, null)) {
309 $result->setResult(CommandResult::RESULT_ERROR);
310 $result->setMessage(FrontendStrings::getCommonStrings()['package_booking_unavailable']);
311 $result->setData(
312 [
313 'timeSlotUnavailable' => true
314 ]
315 );
316
317 return $result;
318 }
319
320 $appointment->setRescheduled(new BooleanValueObject(true));
321
322 foreach ($appointment->getBookings()->getItems() as $booking) {
323 $bookingStartInUtc = DateTimeService::getCustomDateTimeObjectInUtc(
324 $appointment->getBookingStart()->getValue()->format('Y-m-d H:i:s')
325 )->format('Y-m-d H:i:s');
326
327 $paymentAS->updateBookingPaymentDate(
328 $booking,
329 $bookingStartInUtc
330 );
331
332 if ($appointmentAS->isPeriodCustomPricing($service)) {
333 /** @var UserRepository $userRepository */
334 $userRepository = $this->getContainer()->get('domain.users.repository');
335
336 /** @var CustomerBookingRepository $bookingRepository */
337 $bookingRepository = $this->container->get('domain.booking.customerBooking.repository');
338
339 /** @var Provider $provider */
340 $provider = $userRepository->getById($appointment->getProviderId()->getValue());
341
342 $price = $appointmentAS->getBookingPriceForService(
343 $service,
344 null,
345 $provider,
346 $appointment->getBookingStart()->getValue()->format('Y-m-d H:i:s')
347 );
348
349 $booking->setPrice(new Price($price));
350
351 $bookingRepository->updatePrice($booking->getId()->getValue(), $booking);
352 }
353 }
354
355 $bookingAS->bookingRescheduled(
356 $oldAppointment->getId()->getValue(),
357 Entities::APPOINTMENT,
358 null,
359 Entities::CUSTOMER
360 );
361
362 $bookingAS->bookingRescheduled(
363 $oldAppointment->getId()->getValue(),
364 Entities::APPOINTMENT,
365 $oldAppointment->getProviderId()->getValue(),
366 Entities::PROVIDER
367 );
368 }
369
370 $appointmentRepo->commit();
371
372 if ($appointmentStatusChanged) {
373 $appointmentStatus = $appointment->getStatus()->getValue();
374
375 /** @var CustomerBooking $booking */
376 foreach ($appointment->getBookings()->getItems() as $booking) {
377 if (
378 $booking->getStatus()->getValue() === BookingStatus::APPROVED &&
379 ($appointmentStatus === BookingStatus::PENDING || $appointmentStatus === BookingStatus::APPROVED)
380 ) {
381 $booking->setChangedStatus(new BooleanValueObject(true));
382 }
383 }
384
385 $appointment->setChangedStatus(new BooleanValueObject(true));
386 }
387
388 /** @var PaymentRepository $paymentRepository */
389 $paymentRepository = $this->container->get('domain.payment.repository');
390
391 $bookingIds = [];
392
393 /** @var CustomerBooking $booking */
394 foreach ($appointment->getBookings()->getItems() as $booking) {
395 if ($booking->getId() && $booking->getId()->getValue()) {
396 $bookingIds[] = $booking->getId()->getValue();
397 }
398 }
399
400 if ($bookingIds) {
401 /** @var Collection $payments */
402 $payments = $paymentRepository->getByCriteria(['bookingIds' => $bookingIds]);
403
404 /** @var CustomerBooking $booking */
405 foreach ($appointment->getBookings()->getItems() as $booking) {
406 if ($booking->getId() && $booking->getId()->getValue() && !$booking->getPayments()->length()) {
407 $bookingPayments = new Collection();
408
409 foreach ($payments->getItems() as $payment) {
410 if (
411 $payment->getCustomerBookingId() &&
412 $payment->getCustomerBookingId()->getValue() === $booking->getId()->getValue()
413 ) {
414 $bookingPayments->addItem($payment, $payment->getId()->getValue());
415 }
416 }
417
418 if ($bookingPayments->length()) {
419 $booking->setPayments($bookingPayments);
420 }
421 }
422 }
423 }
424
425 $appointmentArray = $appointment->toArray();
426
427 $oldAppointmentArray = $oldAppointment->toArray();
428
429 $bookingsWithChangedStatus = $bookingAS->getBookingsWithChangedStatus($appointmentArray, $oldAppointmentArray);
430
431 /** @var CustomerBooking $booking */
432 foreach ($appointment->getBookings()->getItems() as $booking) {
433 $reservationService->updateWooCommerceOrder($booking, $appointment);
434 }
435
436 $result->setResult(CommandResult::RESULT_SUCCESS);
437 $result->setMessage('Successfully updated appointment');
438 $result->setData(
439 [
440 Entities::APPOINTMENT => $appointmentArray,
441 'appointmentStatusChanged' => $appointmentStatusChanged,
442 'oldAppointmentStatus' => $oldAppointment->getStatus()->getValue(),
443 'appointmentRescheduled' => $appRescheduled,
444 'bookingsWithChangedStatus' => $bookingsWithChangedStatus,
445 'appointmentEmployeeChanged' => $userConnectionChanges['appointmentEmployeeChanged'],
446 'appointmentZoomUserChanged' => $userConnectionChanges['appointmentZoomUserChanged'],
447 'bookingAdded' => $bookingAdded,
448 'appointmentZoomUsersLicenced' => $userConnectionChanges['appointmentZoomUsersLicenced']
449 ]
450 );
451
452 $customFieldService->deleteUploadedFilesForDeletedBookings(
453 $appointment->getBookings(),
454 $oldAppointment->getBookings()
455 );
456
457 return $result;
458 }
459 }
460