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