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