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