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 / UpdateAppointmentCommandHandler.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
UpdateAppointmentCommandHandler.php
458 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 }
198 }
199
200 $appointment->setBookingEnd(
201 new DateTimeValue(
202 DateTimeService::getCustomDateTimeObject(
203 $appointment->getBookingStart()->getValue()->format('Y-m-d H:i:s')
204 )->modify('+' . $appointmentAS->getAppointmentLengthTime($appointment, $service) . ' second')
205 )
206 );
207
208 $userConnectionChanges = $appointmentAS->getUserConnectionChanges(
209 $appointment->getProviderId()->getValue(),
210 $oldAppointment->getProviderId()->getValue()
211 );
212
213 if ($oldAppointment->getZoomMeeting()) {
214 $appointment->setZoomMeeting($oldAppointment->getZoomMeeting());
215 }
216
217 if (
218 $bookingAS->isBookingApprovedOrPending($appointment->getStatus()->getValue()) &&
219 $bookingAS->isBookingCanceledOrRejectedOrNoShow($oldAppointment->getStatus()->getValue()) &&
220 !$appointmentAS->canBeBooked($appointment, false, null, null)
221 ) {
222 $result->setResult(CommandResult::RESULT_ERROR);
223 $result->setMessage(FrontendStrings::getCommonStrings()['time_slot_unavailable']);
224 $result->setData(
225 [
226 'timeSlotUnavailable' => true
227 ]
228 );
229
230 return $result;
231 }
232
233 $appointment->setGoogleCalendarEventId($oldAppointment->getGoogleCalendarEventId());
234 $appointment->setGoogleMeetUrl($oldAppointment->getGoogleMeetUrl());
235 $appointment->setOutlookCalendarEventId($oldAppointment->getOutlookCalendarEventId());
236 $appointment->setMicrosoftTeamsUrl($oldAppointment->getMicrosoftTeamsUrl());
237 $appointment->setAppleCalendarEventId($oldAppointment->getAppleCalendarEventId());
238
239 $appointmentRepo->beginTransaction();
240
241 /** @var Collection $removedBookings */
242 $removedBookings = new Collection();
243
244 foreach ($removedBookingsData as $removedBookingData) {
245 $removedBookings->addItem(CustomerBookingFactory::create($removedBookingData), $removedBookingData['id']);
246 }
247
248 $paymentData = [];
249
250 $bookingAdded = $bookingAS->isBookingAdded($appointment->getBookings());
251
252 /** @var CustomerBooking $oldBooking */
253 foreach ($oldAppointment->getBookings()->getItems() as $oldBooking) {
254 if (
255 $appointment->getServiceId()->getValue() !== $oldAppointment->getServiceId()->getValue() &&
256 !$appointmentAS->processPackageAppointmentBooking(
257 $oldBooking,
258 $removedBookings,
259 $appointment->getServiceId()->getValue(),
260 $paymentData
261 )
262 ) {
263 $result->setResult(CommandResult::RESULT_ERROR);
264 $result->setMessage(FrontendStrings::getCommonStrings()['package_booking_unavailable']);
265 $result->setData(
266 [
267 'packageBookingUnavailable' => true
268 ]
269 );
270
271 return $result;
272 }
273 }
274
275 $paymentData = !empty($command->getField('payment')) ? array_merge($command->getField('payment'), ['isBackendBooking' => true]) :
276 ['amount' => 0, 'gateway' => 'onSite', 'isBackendBooking' => true];
277
278 try {
279 $appointmentAS->update(
280 $oldAppointment,
281 $appointment,
282 $removedBookings,
283 $service,
284 $paymentData
285 );
286 } catch (QueryExecutionException $e) {
287 $appointmentRepo->rollback();
288 throw $e;
289 }
290
291 do_action(
292 'amelia_after_appointment_updated',
293 $appointment ? $appointment->toArray() : null,
294 $oldAppointment ? $oldAppointment->toArray() : null,
295 $removedBookings ? $removedBookings->toArray() : null,
296 $service ? $service->toArray() : null,
297 $paymentData
298 );
299
300
301 $appointmentStatusChanged = $appointmentAS->isAppointmentStatusChanged($appointment, $oldAppointment);
302
303 $appRescheduled = $appointmentAS->isAppointmentRescheduled($appointment, $oldAppointment);
304
305 if ($appRescheduled) {
306 if (!$appointmentAS->canBeBooked($appointment, false, null, null)) {
307 $result->setResult(CommandResult::RESULT_ERROR);
308 $result->setMessage(FrontendStrings::getCommonStrings()['package_booking_unavailable']);
309 $result->setData(
310 [
311 'timeSlotUnavailable' => true
312 ]
313 );
314
315 return $result;
316 }
317
318 $appointment->setRescheduled(new BooleanValueObject(true));
319
320 foreach ($appointment->getBookings()->getItems() as $booking) {
321 $bookingStartInUtc = DateTimeService::getCustomDateTimeObjectInUtc(
322 $appointment->getBookingStart()->getValue()->format('Y-m-d H:i:s')
323 )->format('Y-m-d H:i:s');
324
325 $paymentAS->updateBookingPaymentDate(
326 $booking,
327 $bookingStartInUtc
328 );
329
330 if ($appointmentAS->isPeriodCustomPricing($service)) {
331 /** @var UserRepository $userRepository */
332 $userRepository = $this->getContainer()->get('domain.users.repository');
333
334 /** @var CustomerBookingRepository $bookingRepository */
335 $bookingRepository = $this->container->get('domain.booking.customerBooking.repository');
336
337 /** @var Provider $provider */
338 $provider = $userRepository->getById($appointment->getProviderId()->getValue());
339
340 $price = $appointmentAS->getBookingPriceForService(
341 $service,
342 null,
343 $provider,
344 $appointment->getBookingStart()->getValue()->format('Y-m-d H:i:s')
345 );
346
347 $booking->setPrice(new Price($price));
348
349 $bookingRepository->updatePrice($booking->getId()->getValue(), $booking);
350 }
351 }
352
353 $bookingAS->bookingRescheduled(
354 $oldAppointment->getId()->getValue(),
355 Entities::APPOINTMENT,
356 null,
357 Entities::CUSTOMER
358 );
359
360 $bookingAS->bookingRescheduled(
361 $oldAppointment->getId()->getValue(),
362 Entities::APPOINTMENT,
363 $oldAppointment->getProviderId()->getValue(),
364 Entities::PROVIDER
365 );
366 }
367
368 $appointmentRepo->commit();
369
370 if ($appointmentStatusChanged) {
371 $appointmentStatus = $appointment->getStatus()->getValue();
372
373 /** @var CustomerBooking $booking */
374 foreach ($appointment->getBookings()->getItems() as $booking) {
375 if (
376 $booking->getStatus()->getValue() === BookingStatus::APPROVED &&
377 ($appointmentStatus === BookingStatus::PENDING || $appointmentStatus === BookingStatus::APPROVED)
378 ) {
379 $booking->setChangedStatus(new BooleanValueObject(true));
380 }
381 }
382
383 $appointment->setChangedStatus(new BooleanValueObject(true));
384 }
385
386 /** @var PaymentRepository $paymentRepository */
387 $paymentRepository = $this->container->get('domain.payment.repository');
388
389 $bookingIds = [];
390
391 /** @var CustomerBooking $booking */
392 foreach ($appointment->getBookings()->getItems() as $booking) {
393 if ($booking->getId() && $booking->getId()->getValue()) {
394 $bookingIds[] = $booking->getId()->getValue();
395 }
396 }
397
398 if ($bookingIds) {
399 /** @var Collection $payments */
400 $payments = $paymentRepository->getByCriteria(['bookingIds' => $bookingIds]);
401
402 /** @var CustomerBooking $booking */
403 foreach ($appointment->getBookings()->getItems() as $booking) {
404 if ($booking->getId() && $booking->getId()->getValue() && !$booking->getPayments()->length()) {
405 $bookingPayments = new Collection();
406
407 foreach ($payments->getItems() as $payment) {
408 if (
409 $payment->getCustomerBookingId() &&
410 $payment->getCustomerBookingId()->getValue() === $booking->getId()->getValue()
411 ) {
412 $bookingPayments->addItem($payment, $payment->getId()->getValue());
413 }
414 }
415
416 if ($bookingPayments->length()) {
417 $booking->setPayments($bookingPayments);
418 }
419 }
420 }
421 }
422
423 $appointmentArray = $appointment->toArray();
424
425 $oldAppointmentArray = $oldAppointment->toArray();
426
427 $bookingsWithChangedStatus = $bookingAS->getBookingsWithChangedStatus($appointmentArray, $oldAppointmentArray);
428
429 /** @var CustomerBooking $booking */
430 foreach ($appointment->getBookings()->getItems() as $booking) {
431 $reservationService->updateWooCommerceOrder($booking, $appointment);
432 }
433
434 $result->setResult(CommandResult::RESULT_SUCCESS);
435 $result->setMessage('Successfully updated appointment');
436 $result->setData(
437 [
438 Entities::APPOINTMENT => $appointmentArray,
439 'appointmentStatusChanged' => $appointmentStatusChanged,
440 'oldAppointmentStatus' => $oldAppointment->getStatus()->getValue(),
441 'appointmentRescheduled' => $appRescheduled,
442 'bookingsWithChangedStatus' => $bookingsWithChangedStatus,
443 'appointmentEmployeeChanged' => $userConnectionChanges['appointmentEmployeeChanged'],
444 'appointmentZoomUserChanged' => $userConnectionChanges['appointmentZoomUserChanged'],
445 'bookingAdded' => $bookingAdded,
446 'appointmentZoomUsersLicenced' => $userConnectionChanges['appointmentZoomUsersLicenced']
447 ]
448 );
449
450 $customFieldService->deleteUploadedFilesForDeletedBookings(
451 $appointment->getBookings(),
452 $oldAppointment->getBookings()
453 );
454
455 return $result;
456 }
457 }
458