PluginProbe ʕ •ᴥ•ʔ
Booking for Appointments and Events Calendar – Amelia / 2.4.8
Booking for Appointments and Events Calendar – Amelia v2.4.8
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 / Services / Reservation / EventReservationService.php
ameliabooking / src / Application / Services / Reservation Last commit date
AbstractReservationService.php 1 week ago AppointmentReservationService.php 1 week ago EventReservationService.php 1 week ago ReservationService.php 2 years ago
EventReservationService.php
1418 lines
1 <?php
2
3 namespace AmeliaBooking\Application\Services\Reservation;
4
5 use AmeliaBooking\Application\Commands\CommandResult;
6 use AmeliaBooking\Application\Common\Exceptions\AccessDeniedException;
7 use AmeliaBooking\Application\Services\Booking\EventApplicationService;
8 use AmeliaBooking\Application\Services\Coupon\CouponApplicationService;
9 use AmeliaBooking\Application\Services\Deposit\AbstractDepositApplicationService;
10 use AmeliaBooking\Application\Services\QrCode\QrCodeApplicationService;
11 use AmeliaBooking\Application\Services\Tax\TaxApplicationService;
12 use AmeliaBooking\Domain\Collection\Collection;
13 use AmeliaBooking\Domain\Common\Exceptions\BookingCancellationException;
14 use AmeliaBooking\Domain\Common\Exceptions\BookingsLimitReachedException;
15 use AmeliaBooking\Domain\Common\Exceptions\BookingUnavailableException;
16 use AmeliaBooking\Domain\Common\Exceptions\CouponExpiredException;
17 use AmeliaBooking\Domain\Common\Exceptions\CouponInvalidException;
18 use AmeliaBooking\Domain\Common\Exceptions\CouponUnknownException;
19 use AmeliaBooking\Domain\Common\Exceptions\CustomerBookedException;
20 use AmeliaBooking\Domain\Common\Exceptions\InvalidArgumentException;
21 use AmeliaBooking\Domain\Entity\Bookable\AbstractBookable;
22 use AmeliaBooking\Domain\Entity\Booking\Appointment\CustomerBooking;
23 use AmeliaBooking\Domain\Entity\Booking\Appointment\CustomerBookingExtra;
24 use AmeliaBooking\Domain\Entity\Booking\Event\CustomerBookingEventPeriod;
25 use AmeliaBooking\Domain\Entity\Booking\Event\CustomerBookingEventTicket;
26 use AmeliaBooking\Domain\Entity\Booking\Event\Event;
27 use AmeliaBooking\Domain\Entity\Booking\Event\EventPeriod;
28 use AmeliaBooking\Domain\Entity\Booking\Event\EventTicket;
29 use AmeliaBooking\Domain\Entity\Booking\Reservation;
30 use AmeliaBooking\Domain\Entity\Coupon\Coupon;
31 use AmeliaBooking\Domain\Entity\Entities;
32 use AmeliaBooking\Domain\Entity\Location\Location;
33 use AmeliaBooking\Domain\Entity\Payment\Payment;
34 use AmeliaBooking\Domain\Entity\Tax\Tax;
35 use AmeliaBooking\Domain\Entity\User\AbstractUser;
36 use AmeliaBooking\Domain\Entity\User\Provider;
37 use AmeliaBooking\Domain\Factory\Booking\Appointment\CustomerBookingFactory;
38 use AmeliaBooking\Domain\Factory\Booking\Event\CustomerBookingEventPeriodFactory;
39 use AmeliaBooking\Domain\Factory\Booking\Event\CustomerBookingEventTicketFactory;
40 use AmeliaBooking\Domain\Factory\Booking\Event\EventFactory;
41 use AmeliaBooking\Domain\Services\DateTime\DateTimeService;
42 use AmeliaBooking\Domain\Services\Reservation\ReservationServiceInterface;
43 use AmeliaBooking\Domain\Services\Settings\SettingsService;
44 use AmeliaBooking\Domain\ValueObjects\BooleanValueObject;
45 use AmeliaBooking\Domain\ValueObjects\Number\Float\Price;
46 use AmeliaBooking\Domain\ValueObjects\Number\Integer\Id;
47 use AmeliaBooking\Domain\ValueObjects\Number\Integer\IntegerValue;
48 use AmeliaBooking\Domain\ValueObjects\String\BookingStatus;
49 use AmeliaBooking\Domain\ValueObjects\String\PaymentType;
50 use AmeliaBooking\Domain\ValueObjects\String\Token;
51 use AmeliaBooking\Domain\ValueObjects\Json;
52 use AmeliaBooking\Infrastructure\Common\Exceptions\QueryExecutionException;
53 use AmeliaBooking\Infrastructure\Repository\Booking\Appointment\CustomerBookingExtraRepository;
54 use AmeliaBooking\Infrastructure\Repository\Booking\Appointment\CustomerBookingRepository;
55 use AmeliaBooking\Infrastructure\Repository\Booking\Event\CustomerBookingEventPeriodRepository;
56 use AmeliaBooking\Infrastructure\Repository\Booking\Event\CustomerBookingEventTicketRepository;
57 use AmeliaBooking\Infrastructure\Repository\Booking\Event\EventRepository;
58 use AmeliaBooking\Infrastructure\Repository\Location\LocationRepository;
59 use AmeliaBooking\Infrastructure\Repository\User\CustomerRepository;
60 use AmeliaBooking\Infrastructure\WP\Translations\FrontendStrings;
61 use DateTime;
62 use Exception;
63
64 /**
65 * Class EventReservationService
66 *
67 * @package AmeliaBooking\Application\Services\Reservation
68 */
69 class EventReservationService extends AbstractReservationService
70 {
71 /**
72 * @return string
73 */
74 public function getType()
75 {
76 return Entities::EVENT;
77 }
78
79 /**
80 * @param array $eventData
81 * @param Reservation $reservation
82 * @param bool $save
83 *
84 * @return void
85 *
86 * @throws CouponExpiredException
87 * @throws CouponInvalidException
88 * @throws CouponUnknownException
89 * @throws BookingUnavailableException
90 * @throws InvalidArgumentException
91 * @throws QueryExecutionException
92 * @throws Exception
93 */
94 public function book($eventData, $reservation, $save)
95 {
96 /** @var LocationRepository $locationRepository */
97 $locationRepository = $this->container->get('domain.locations.repository');
98
99 /** @var EventApplicationService $eventApplicationService */
100 $eventApplicationService = $this->container->get('application.booking.event.service');
101
102 /** @var CouponApplicationService $couponAS */
103 $couponAS = $this->container->get('application.coupon.service');
104
105 /** @var AbstractDepositApplicationService $depositAS */
106 $depositAS = $this->container->get('application.deposit.service');
107
108 $this->manageTaxes($eventData);
109
110 /** @var Coupon $coupon */
111 $coupon = !empty($eventData['couponCode']) ? $couponAS->processCoupon(
112 $eventData['couponCode'],
113 [$eventData['eventId']],
114 Entities::EVENT,
115 $eventData['bookings'][0]['customerId'],
116 $reservation->hasCouponValidation()->getValue()
117 ) : null;
118
119 if ($coupon) {
120 $eventData['bookings'][0]['coupon'] = $coupon->toArray();
121
122 $eventData['bookings'][0]['couponId'] = $coupon->getId()->getValue();
123 }
124
125 /** @var Event $event */
126 $event = $eventApplicationService->getEventById(
127 $eventData['eventId'],
128 [
129 'fetchEventsPeriods' => true,
130 'fetchEventsTickets' => true,
131 'fetchApprovedBookings' => true,
132 'fetchBookings' => true,
133 'fetchBookingsTickets' => true,
134 'fetchEventsProviders' => true,
135 ]
136 );
137
138 if ($event->getCustomPricing()->getValue()) {
139 $event->setCustomTickets($eventApplicationService->getTicketsPriceByDateRange($event->getCustomTickets()));
140 }
141
142 $bookingArray = array_merge(
143 $eventData['bookings'][0],
144 empty($eventData['bookings'][0]['status']) ?
145 ['status' => BookingStatus::APPROVED] : ['status' => $eventData['bookings'][0]['status']]
146 );
147
148 $bookingArray = apply_filters('amelia_before_event_booking_saved_filter', $bookingArray, $event ? $event->toArray() : null);
149
150 do_action('amelia_before_event_booking_saved', $bookingArray, $event ? $event->toArray() : null);
151
152 $booking = CustomerBookingFactory::create($bookingArray);
153
154 if ($event->getCustomPricing()->getValue()) {
155 $booking->setPersons(new IntegerValue(0));
156 }
157
158 $bookingStatus = empty($eventData['bookings'][0]['status']) ? BookingStatus::APPROVED : $eventData['bookings'][0]['status'];
159
160 if (!empty($eventData['payment']['gateway'])) {
161 $isDeferredPayment = $this->isDeferredPaymentGateway($eventData['payment']);
162
163 $bookingStatus = $isDeferredPayment ?
164 BookingStatus::PENDING : (empty($eventData['bookings'][0]['status']) ? BookingStatus::APPROVED : $eventData['bookings'][0]['status']);
165
166 // see AppointmentReservationService - the order status is WooCommerce-only and server-derived
167 if (
168 $eventData['payment']['gateway'] === PaymentType::WC &&
169 !empty($eventData['payment']['orderStatus'])
170 ) {
171 $bookingStatus = $this->getWcStatus(
172 Entities::EVENT,
173 $eventData['payment']['orderStatus'],
174 'booking',
175 false
176 ) ?: $bookingStatus;
177 }
178 }
179
180 $booking->setStatus(new BookingStatus($bookingStatus));
181
182 $personsCount = 0;
183
184 /** @var CustomerBooking $customerBooking */
185 foreach ($event->getBookings()->getItems() as $customerBooking) {
186 if ($customerBooking->getStatus()->getValue() === BookingStatus::APPROVED) {
187 $personsCount += $customerBooking->getPersons()->getValue();
188 }
189 if (
190 $customerBooking->getStatus()->getValue() !== BookingStatus::CANCELED &&
191 !$event->getBookMultipleTimes()->getValue() &&
192 $booking->getCustomerId() &&
193 $booking->getCustomerId()->getValue() === $customerBooking->getCustomerId()->getValue()
194 ) {
195 throw new CustomerBookedException(
196 FrontendStrings::getCommonStrings()['customer_already_booked_ev']
197 );
198 }
199 }
200
201 /** @var SettingsService $settingsDS */
202 $settingsDS = $this->container->get('domain.settings.service');
203
204 $limitPerCustomerEvents = $settingsDS->getSetting('roles', 'limitPerCustomerEvent');
205
206 if (
207 !empty($limitPerCustomerEvents) &&
208 $limitPerCustomerEvents['enabled'] &&
209 empty($eventData['isBackendOrCabinet'])
210 ) {
211 /** @var EventRepository $eventRepository */
212 $eventRepository = $this->container->get('domain.booking.event.repository');
213
214 $count = $eventRepository->getRelevantBookingsCount(
215 $event,
216 $booking->toArray(),
217 $limitPerCustomerEvents
218 );
219
220 if ($count >= $limitPerCustomerEvents['numberOfApp']) {
221 throw new BookingsLimitReachedException(
222 FrontendStrings::getCommonStrings()['bookings_limit_reached']
223 );
224 }
225 }
226
227 /** @var AbstractUser $currentUser */
228 $currentUser = $this->container->get('logged.in.user');
229
230 $isCustomer = (!$currentUser || ($currentUser->getType() === AbstractUser::USER_ROLE_CUSTOMER));
231
232 if (
233 $reservation->hasAvailabilityValidation()->getValue() &&
234 $isCustomer &&
235 !$this->isBookable($event, $booking, DateTimeService::getNowDateTimeObject())
236 ) {
237 throw new BookingUnavailableException(
238 FrontendStrings::getCommonStrings()['time_slot_unavailable']
239 );
240 }
241
242
243 $booking->setAggregatedPrice(new BooleanValueObject($event->getAggregatedPrice() ? $event->getAggregatedPrice()->getValue() : true));
244
245 $paymentAmount = $this->getPaymentAmount($booking, $event)['price'];
246
247 $applyDeposit =
248 !empty($eventData['bookings'][0]['deposit']) && $eventData['payment']['gateway'] !== PaymentType::ON_SITE;
249
250 if ($applyDeposit) {
251 $personsCount = $booking->getPersons()->getValue();
252
253 if ($booking->getTicketsBooking() && $event->getCustomPricing()->getValue()) {
254 $personsCount = 0;
255
256 /** @var CustomerBookingEventTicket $bookingToEventTicket */
257 foreach ($booking->getTicketsBooking()->getItems() as $bookingToEventTicket) {
258 $personsCount += ($bookingToEventTicket->getPersons() ?
259 $bookingToEventTicket->getPersons()->getValue() : 0);
260 }
261 }
262
263 $paymentDeposit = $depositAS->calculateDepositAmount(
264 $paymentAmount,
265 $event,
266 $personsCount
267 );
268
269 $eventData['payment']['deposit'] = $paymentAmount !== $paymentDeposit;
270
271 $paymentAmount = $paymentDeposit;
272 }
273
274 if ($save) {
275 /** @var CustomerBookingRepository $bookingRepository */
276 $bookingRepository = $this->container->get('domain.booking.customerBooking.repository');
277
278 /** @var CustomerBookingExtraRepository $bookingExtraRepository */
279 $bookingExtraRepository = $this->container->get('domain.booking.customerBookingExtra.repository');
280
281 /** @var CustomerBookingEventPeriodRepository $bookingEventPeriodRepository */
282 $bookingEventPeriodRepository =
283 $this->container->get('domain.booking.customerBookingEventPeriod.repository');
284
285 /** @var CustomerBookingEventTicketRepository $bookingEventTicketRepository */
286 $bookingEventTicketRepository = $this->container->get('domain.booking.customerBookingEventTicket.repository');
287
288 $booking->setPrice(new Price($event->getPrice()->getValue()));
289 $booking->setToken(new Token());
290
291 if ($booking->getTicketsBooking() && $event->getCustomPricing()->getValue()) {
292 $ticketSumPrice = 0;
293
294 /** @var CustomerBookingEventTicket $bookingToEventTicket */
295 foreach ($booking->getTicketsBooking()->getItems() as $bookingToEventTicket) {
296 /** @var EventTicket $ticket */
297 $ticket = $event->getCustomTickets()->getItem(
298 $bookingToEventTicket->getEventTicketId()->getValue()
299 );
300
301 $ticketPrice = $ticket->getDateRangePrice() ?
302 $ticket->getDateRangePrice()->getValue() : $ticket->getPrice()->getValue();
303
304 $ticketSumPrice += $bookingToEventTicket->getPersons() ?
305 ($booking->getAggregatedPrice()->getValue() ? $bookingToEventTicket->getPersons()->getValue() : 1)
306 * $ticketPrice : 0;
307 }
308
309 $booking->setPrice(new Price($ticketSumPrice));
310 }
311
312 $booking->setActionsCompleted(new BooleanValueObject(!empty($eventData['payment']['isBackendBooking'])));
313
314 $bookingId = $bookingRepository->add($booking);
315
316 /** @var CustomerBookingExtra $bookingExtra */
317 foreach ($booking->getExtras()->getItems() as $bookingExtra) {
318 $bookingExtra->setCustomerBookingId(new Id($bookingId));
319 $bookingExtraId = $bookingExtraRepository->add($bookingExtra);
320 $bookingExtra->setId(new Id($bookingExtraId));
321 }
322
323 $booking->setId(new Id($bookingId));
324
325 // The reservation is only handed the persisted entities at the end of this method, but the
326 // payment row is written just below - hand it the booking as soon as the booking row exists,
327 // so a throwable raised while saving can still be rolled back in processRequest instead of
328 // leaving a committed booking behind. Both are reassigned unchanged further down.
329 if ($booking->getCustomer()) {
330 $reservation->setCustomer($booking->getCustomer());
331 }
332
333 $reservation->setBooking($booking);
334 $reservation->setReservation($event);
335
336 // BEGIN QR Codes generation for event booking
337 if ($settingsDS->isFeatureEnabled('eTickets')) {
338 /** @var QrCodeApplicationService $qrCodeApplicationService */
339 $qrCodeApplicationService = $this->container->get('application.qrcode.service');
340
341 $qrCodes = $qrCodeApplicationService->createQrCodeEventData($event, $booking);
342
343
344 if (!empty($qrCodes)) {
345 $booking->setQrCodes(new Json(json_encode($qrCodes)));
346 $bookingRepository->update($bookingId, $booking);
347 }
348 }
349 // END QR Codes generation
350
351 /** @var Payment $payment */
352 $payment = $this->addPayment(
353 $booking->getId()->getValue(),
354 null,
355 $eventData['payment'],
356 $paymentAmount,
357 $event->getPeriods()->getItem(0)->getPeriodStart()->getValue(),
358 Entities::EVENT
359 );
360
361 /** @var Collection $payments */
362 $payments = new Collection();
363
364 $payments->addItem($payment);
365
366 $booking->setPayments($payments);
367
368 /** @var EventPeriod $eventPeriod */
369 foreach ($event->getPeriods()->getItems() as $eventPeriod) {
370 /** @var CustomerBookingEventPeriod $bookingEventPeriod */
371 $bookingEventPeriod = CustomerBookingEventPeriodFactory::create(
372 [
373 'eventPeriodId' => $eventPeriod->getId()->getValue(),
374 'customerBookingId' => $bookingId
375 ]
376 );
377
378 $bookingEventPeriodRepository->add($bookingEventPeriod);
379 }
380
381 /** @var CustomerBookingEventTicket $eventTicket */
382 foreach ($booking->getTicketsBooking()->getItems() as $eventTicket) {
383 if ($eventTicket->getPersons()) {
384 /** @var EventTicket $ticket */
385 $ticket = $event->getCustomTickets()->getItem($eventTicket->getEventTicketId()->getValue());
386
387 $ticketPrice = $ticket->getDateRangePrice() ?
388 $ticket->getDateRangePrice()->getValue() : $ticket->getPrice()->getValue();
389
390 /** @var CustomerBookingEventTicket $bookingEventTicket */
391 $bookingEventTicket = CustomerBookingEventTicketFactory::create(
392 [
393 'eventTicketId' => $eventTicket->getEventTicketId()->getValue(),
394 'customerBookingId' => $bookingId,
395 'persons' => $eventTicket->getPersons()->getValue(),
396 'price' => $ticketPrice,
397 ]
398 );
399
400 $bookingEventTicketRepository->add($bookingEventTicket);
401 }
402 }
403
404 $event->getBookings()->addItem($booking, $booking->getId()->getValue());
405
406 do_action('amelia_after_event_booking_saved', $booking ? $booking->toArray() : null, $event ? $event->toArray() : null);
407 }
408
409 if ($event->getLocationId()) {
410 /** @var Location $location */
411 $location = $locationRepository->getById($event->getLocationId()->getValue());
412
413 $event->setLocation($location);
414 }
415
416 $reservation->setApplyDeposit(new BooleanValueObject($applyDeposit));
417 if ($booking->getCustomer()) {
418 $reservation->setCustomer($booking->getCustomer());
419 }
420
421 /** @var Collection $bookings */
422 $bookings = new Collection();
423
424 $bookings->addItem($booking);
425
426 $event->setBookings($bookings);
427
428 $reservation->setBookable($event);
429 $reservation->setBooking($booking);
430 $reservation->setReservation($event);
431 $reservation->setRecurring(new Collection());
432 $reservation->setPackageReservations(new Collection());
433 $reservation->setIsStatusChanged(new BooleanValueObject(false));
434 }
435
436 /**
437 * @param CustomerBooking $booking
438 * @param string $requestedStatus
439 * @param bool $inspectCancellationTime
440 *
441 * @return array
442 *
443 * @throws InvalidArgumentException
444 * @throws QueryExecutionException
445 * @throws BookingCancellationException
446 */
447 public function updateStatus($booking, $requestedStatus, $inspectCancellationTime = true)
448 {
449 /** @var CustomerBookingRepository $bookingRepository */
450 $bookingRepository = $this->container->get('domain.booking.customerBooking.repository');
451 /** @var SettingsService $settingsDS */
452 $settingsDS = $this->container->get('domain.settings.service');
453
454 /** @var Event $event */
455 $event = $this->getReservationByBookingId($booking->getId()->getValue());
456
457 if ($requestedStatus === BookingStatus::CANCELED && $inspectCancellationTime) {
458 $minimumCancelTimeInSeconds = $settingsDS
459 ->getEntitySettings($event->getSettings())
460 ->getGeneralSettings()
461 ->getMinimumTimeRequirementPriorToCanceling();
462
463 $this->inspectMinimumCancellationTime(
464 $event->getPeriods()->getItem(0)->getPeriodStart()->getValue(),
465 $minimumCancelTimeInSeconds
466 );
467 }
468
469 $booking->setStatus(new BookingStatus($requestedStatus));
470
471 $bookingRepository->update($booking->getId()->getValue(), $booking);
472
473 return [
474 Entities::EVENT => $event->toArray(),
475 'appointmentStatusChanged' => false,
476 Entities::BOOKING => $booking->toArray()
477 ];
478 }
479
480 /**
481 * @param Event $reservation
482 * @param CustomerBooking $booking
483 * @param AbstractBookable $bookable
484 *
485 * @return array
486 */
487 public function getBookingPeriods($reservation, $booking, $bookable)
488 {
489 $dates = [];
490
491 /** @var EventPeriod $period */
492 foreach ($reservation->getPeriods()->getItems() as $period) {
493 $dates[] = [
494 'start' => DateTimeService::getCustomDateTimeInUtc(
495 $period->getPeriodStart()->getValue()->format('Y-m-d H:i:s')
496 ),
497 'end' => DateTimeService::getCustomDateTimeInUtc(
498 $period->getPeriodEnd()->getValue()->format('Y-m-d H:i:s')
499 )
500 ];
501 }
502
503 return $dates;
504 }
505
506 /**
507 * @param array $data
508 *
509 * @return AbstractBookable
510 *
511 * @throws QueryExecutionException
512 * @throws InvalidArgumentException
513 */
514 public function getBookableEntity($data)
515 {
516 /** @var EventRepository $eventRepository */
517 $eventRepository = $this->container->get('domain.booking.event.repository');
518
519 return $eventRepository->getById($data['eventId']);
520 }
521
522 /**
523 * @param Event $bookable
524 *
525 * @return boolean
526 */
527 public function isAggregatedPrice($bookable)
528 {
529 return $bookable->getAggregatedPrice()->getValue();
530 }
531
532 /**
533 * @param BooleanValueObject $bookableAggregatedPrice
534 * @param BooleanValueObject $extraAggregatedPrice
535 *
536 * @return boolean
537 */
538 public function isExtraAggregatedPrice($extraAggregatedPrice, $bookableAggregatedPrice)
539 {
540 return true;
541 }
542
543 /**
544 * @param Reservation $reservation
545 * @param string $paymentGateway
546 * @param array $requestData
547 *
548 * @return array
549 *
550 * @throws InvalidArgumentException
551 */
552 public function getWooCommerceData($reservation, $paymentGateway, $requestData)
553 {
554 /** @var Event $event */
555 $event = $reservation->getBookable();
556
557 /** @var AbstractUser $customer */
558 $customer = $reservation->getCustomer();
559
560 /** @var CustomerBooking $booking */
561 $booking = $reservation->getBooking();
562
563 $dateTimeValues = [];
564
565 /** @var EventPeriod $period */
566 foreach ($event->getPeriods()->getItems() as $period) {
567 $dateTimeValues[] = [
568 'start' => $period->getPeriodStart()->getValue()->format('Y-m-d H:i'),
569 'end' => $period->getPeriodEnd()->getValue()->format('Y-m-d H:i')
570 ];
571 }
572
573 $info = [
574 'type' => Entities::EVENT,
575 'eventId' => $event->getId()->getValue(),
576 'name' => $event->getName()->getValue(),
577 'couponId' => $booking->getCoupon() ? $booking->getCoupon()->getId()->getValue() : '',
578 'couponCode' => $booking->getCoupon() ? $booking->getCoupon()->getCode()->getValue() : '',
579 'dateTimeValues' => $dateTimeValues,
580 'bookings' => [
581 [
582 'customerId' => $customer->getId() ? $customer->getId()->getValue() : null,
583 'customer' => [
584 'email' => $customer->getEmail()->getValue(),
585 'externalId' => $customer->getExternalId() ? $customer->getExternalId()->getValue() : null,
586 'firstName' => $customer->getFirstName()->getValue(),
587 'id' => $customer->getId() ? $customer->getId()->getValue() : null,
588 'lastName' => $customer->getLastName()->getValue(),
589 'phone' => $customer->getPhone()->getValue(),
590 'countryPhoneIso' => $customer->getCountryPhoneIso() ?
591 $customer->getCountryPhoneIso()->getValue() : null,
592 'customFields' => $customer->getCustomFields() ?
593 json_decode($customer->getCustomFields()->getValue(), true) : null,
594 'subscribeToMailchimp' => $this->isMailchimpSubscriptionRequested($requestData),
595 ],
596 'info' => $booking->getInfo()->getValue(),
597 'persons' => $booking->getPersons()->getValue(),
598 'extras' => [],
599 'utcOffset' => $booking->getUtcOffset() ? $booking->getUtcOffset()->getValue() : null,
600 'customFields' => $booking->getCustomFields() ?
601 json_decode($booking->getCustomFields()->getValue(), true) : null,
602 'deposit' => $reservation->getApplyDeposit()->getValue(),
603 'ticketsData' => $requestData['bookings'][0]['ticketsData'],
604 ]
605 ],
606 'payment' => [
607 'gateway' => $paymentGateway
608 ],
609 'locale' => $reservation->getLocale()->getValue(),
610 'timeZone' => $reservation->getTimeZone()->getValue(),
611 'recurring' => [],
612 'package' => [],
613 'ivy' => !empty($requestData['ivy']) ? $requestData['ivy'] : null,
614 ];
615
616 foreach ($booking->getExtras()->keys() as $extraKey) {
617 /** @var CustomerBookingExtra $bookingExtra */
618 $bookingExtra = $booking->getExtras()->getItem($extraKey);
619
620 $info['bookings'][0]['extras'][] = [
621 'extraId' => $bookingExtra->getExtraId()->getValue(),
622 'quantity' => $bookingExtra->getQuantity()->getValue()
623 ];
624 }
625
626 return $info;
627 }
628
629
630 /**
631 * @param array $reservation
632 *
633 * @return array
634 *
635 * @throws InvalidArgumentException
636 */
637 public function getWooCommerceDataFromArray($reservation, $index)
638 {
639 /** @var array $event */
640 $event = $reservation['bookable'];
641
642 /** @var array $customer */
643 $customer = !empty($reservation['customer'])
644 ? $reservation['customer']
645 : (!empty($reservation['booking']['customer']) ? $reservation['booking']['customer'] : null);
646
647 /** @var array $booking */
648 $booking = $reservation['booking'];
649
650 if (!empty($booking['ticketsData'])) {
651 foreach ($booking['ticketsData'] as &$ticket) {
652 $customTicketIndex = array_search(
653 $ticket['eventTicketId'],
654 array_column($reservation['event']['customTickets'], 'id')
655 );
656 if ($customTicketIndex !== false) {
657 $ticket['name'] = $reservation['event']['customTickets'][$customTicketIndex]['name'];
658 }
659 }
660 }
661
662 $dateTimeValues = [];
663
664 $customerInfo = !empty($booking['info']) ? json_decode($booking['info'], true) : null;
665
666 foreach ($event['periods'] as $period) {
667 $dateTimeValues[] = [
668 'start' => $period['periodStart'],
669 'end' => $period['periodEnd']
670 ];
671 }
672
673 $info = [
674 'type' => Entities::EVENT,
675 'eventId' => $event['id'],
676 'name' => $event['name'],
677 'couponId' => $booking['coupon'] ? $booking['coupon']['id'] : '',
678 'couponCode' => $booking['coupon'] ? $booking['coupon']['code'] : '',
679 'dateTimeValues' => $dateTimeValues,
680 'bookings' => [
681 [
682 'customerId' => $customer['id'],
683 'customer' => [
684 'email' => $customer['email'],
685 'externalId' => $customer['externalId'],
686 'firstName' => $customer['firstName'],
687 'id' => $customer['id'],
688 'lastName' => $customer['lastName'],
689 'phone' => $customer['phone'],
690 'countryPhoneIso' => $customer['countryPhoneIso']
691 ],
692 'info' => $booking['info'],
693 'persons' => $booking['persons'],
694 'extras' => [],
695 'utcOffset' => $booking['utcOffset'],
696 'customFields' => $booking['customFields'] ?
697 json_decode($booking['customFields'], true) : null,
698 'deposit' => $booking['price'] > $booking['payments'][0]['amount'],
699 'ticketsData' => $booking['ticketsData'],
700 ]
701 ],
702 'payment' => [
703 'gateway' => $booking['payments'][0]['gateway']
704 ],
705 'locale' => $customerInfo ? $customerInfo['locale'] : null,
706 'timeZone' => $customerInfo ? $customerInfo['timeZone'] : null,
707 'recurring' => [],
708 'package' => [],
709 ];
710
711 foreach ($booking['extras'] as $extra) {
712 $info['bookings'][0]['extras'][] = [
713 'extraId' => $extra['id'],
714 'quantity' => $extra['quantity']
715 ];
716 }
717
718 return $info;
719 }
720
721 /**
722 * @param int $id
723 *
724 * @return Event
725 *
726 * @throws QueryExecutionException
727 * @throws InvalidArgumentException
728 */
729 public function getReservationByBookingId($id)
730 {
731 /** @var EventRepository $eventRepository */
732 $eventRepository = $this->container->get('domain.booking.event.repository');
733
734 /** @var Event $event */
735 $event = $eventRepository->getByBookingId(
736 $id,
737 [
738 'fetchEventsTickets' => true,
739 'fetchEventsTags' => true,
740 'fetchEventsProviders' => true,
741 'fetchEventsImages' => true,
742 ]
743 );
744
745 /** @var Collection $eventsBookings */
746 $eventsBookings = $eventRepository->getBookingsByCriteria(
747 [
748 'ids' => [$event->getId()->getValue()],
749 'fetchBookings' => true,
750 'fetchBookingsTickets' => true,
751 'fetchBookingsUsers' => true,
752 'fetchBookingsPayments' => true,
753 ]
754 );
755
756 if ($eventsBookings->keyExists($event->getId()->getValue())) {
757 $event->setBookings($eventsBookings->getItem($event->getId()->getValue()));
758 }
759
760 return $event;
761 }
762
763 /**
764 * @param Event $reservation
765 * @param CustomerBooking $newBooking
766 * @param DateTime $dateTime
767 *
768 * @return boolean
769 *
770 * @throws InvalidArgumentException
771 */
772 public function isBookable($reservation, $newBooking, $dateTime)
773 {
774 if ($reservation->getCustomPricing() && $reservation->getCustomPricing()->getValue() && !$reservation->getMaxCustomCapacity()) {
775 $availableTicketsSpots = [];
776
777 $reservedTicketsSpots = [];
778
779 /** @var EventTicket $ticket */
780 foreach ($reservation->getCustomTickets()->getItems() as $ticket) {
781 $availableTicketsSpots[$ticket->getId()->getValue()] = $ticket->getSpots()->getValue();
782
783 if (!$reservation->getBookings()->length()) {
784 $reservedTicketsSpots[$ticket->getId()->getValue()] = $ticket->getSold() ? $ticket->getSold()->getValue() : 0;
785 }
786 }
787
788 /** @var CustomerBooking $booking */
789 foreach ($reservation->getBookings()->getItems() as $booking) {
790 if ($booking->getStatus()->getValue() === BookingStatus::APPROVED) {
791 /** @var CustomerBookingEventTicket $bookingTicket */
792 foreach ($booking->getTicketsBooking()->getItems() as $bookingTicket) {
793 $eventTicketId = $bookingTicket->getEventTicketId()->getValue();
794
795 if (!array_key_exists($eventTicketId, $reservedTicketsSpots)) {
796 $reservedTicketsSpots[$eventTicketId] = 0;
797 }
798
799 $reservedTicketsSpots[$eventTicketId] += $bookingTicket->getPersons()->getValue();
800 }
801 }
802 }
803
804 if ($newBooking) {
805 /** @var CustomerBookingEventTicket $newBookingTicket */
806 foreach ($newBooking->getTicketsBooking()->getItems() as $newBookingTicket) {
807 $eventTicketId = $newBookingTicket->getEventTicketId()->getValue();
808
809 if (empty($reservedTicketsSpots[$eventTicketId])) {
810 $reservedTicketsSpots[$eventTicketId] = 0;
811 }
812
813 $reservedTicketsSpots[$eventTicketId] +=
814 $newBookingTicket->getPersons() ? $newBookingTicket->getPersons()->getValue() : 0;
815 }
816 }
817
818 $hasTicketCapacity = [];
819
820 foreach ($availableTicketsSpots as $eventTicketId => $availablePersons) {
821 $hasTicketCapacity[$eventTicketId] = !array_key_exists($eventTicketId, $reservedTicketsSpots) ||
822 (
823 $newBooking
824 ? $reservedTicketsSpots[$eventTicketId] <= $availablePersons
825 : $reservedTicketsSpots[$eventTicketId] < $availablePersons
826 );
827 }
828
829 $hasCapacity = false;
830
831 foreach ($hasTicketCapacity as $ticketId => $ticketCapacity) {
832 if ($newBooking) {
833 $hasCapacity = true;
834
835 /** @var EventTicket $ticket */
836 $ticket = $reservation->getCustomTickets()->getItem($ticketId);
837
838 /** @var CustomerBookingEventTicket $ticketBooking */
839 foreach ($newBooking->getTicketsBooking()->getItems() as $ticketBooking) {
840 if (
841 $ticketBooking->getEventTicketId()->getValue() === $ticketId &&
842 $ticketBooking->getPersons() &&
843 $ticketBooking->getPersons()->getValue() &&
844 (!$ticketCapacity || !$ticket->getEnabled()->getValue())
845 ) {
846 $hasCapacity = false;
847
848 break 2;
849 }
850 }
851 } else {
852 $hasCapacity = $hasCapacity || $ticketCapacity;
853 }
854 }
855 } elseif ($reservation->getMaxCustomCapacity()) {
856 $availableTicketsSpots = $reservation->getMaxCustomCapacity()->getValue();
857
858 $reservedTicketsSpots = 0;
859
860 if (!$reservation->getBookings()->length()) {
861 /** @var EventTicket $ticket */
862 foreach ($reservation->getCustomTickets()->getItems() as $ticket) {
863 $reservedTicketsSpots += $ticket->getSold() ? $ticket->getSold()->getValue() : 0;
864 }
865 }
866
867 /** @var CustomerBooking $booking */
868 foreach ($reservation->getBookings()->getItems() as $booking) {
869 if ($booking->getStatus()->getValue() === BookingStatus::APPROVED) {
870 /** @var CustomerBookingEventTicket $bookingTicket */
871 foreach ($booking->getTicketsBooking()->getItems() as $bookingTicket) {
872 $reservedTicketsSpots += $bookingTicket->getPersons()->getValue();
873 }
874 }
875 }
876
877 if ($newBooking) {
878 /** @var CustomerBookingEventTicket $newBookingTicket */
879 foreach ($newBooking->getTicketsBooking()->getItems() as $newBookingTicket) {
880 $reservedTicketsSpots += $newBookingTicket->getPersons() ? $newBookingTicket->getPersons()->getValue() : 0;
881 }
882 }
883
884 $hasCapacity = ($newBooking ? $reservedTicketsSpots <= $availableTicketsSpots : $reservedTicketsSpots < $availableTicketsSpots);
885 } else {
886 $persons = !$reservation->getBookings()->length() && $reservation->getSpotsSold()
887 ? $reservation->getSpotsSold()->getValue()
888 : 0;
889
890 /** @var CustomerBooking $booking */
891 foreach ($reservation->getBookings()->getItems() as $booking) {
892 if ($booking->getStatus()->getValue() === BookingStatus::APPROVED) {
893 $persons += $booking->getPersons()->getValue();
894 }
895 }
896
897 if ($newBooking) {
898 $hasCapacity = ($reservation->getMaxCapacity()->getValue() - $persons - $newBooking->getPersons()->getValue()) >= 0;
899 } else {
900 $hasCapacity = $reservation->getMaxCapacity()->getValue() - $persons > 0;
901 }
902 }
903
904 $bookingCloses = $reservation->getBookingCloses() ?
905 $reservation->getBookingCloses()->getValue() :
906 $reservation->getPeriods()->getItem(0)->getPeriodStart()->getValue();
907
908 $bookingOpens = $reservation->getBookingOpens() ?
909 $reservation->getBookingOpens()->getValue() :
910 $reservation->getCreated()->getValue();
911
912 $hasWaitingList = false;
913 $eventSettings = $reservation->getSettings() ? json_decode($reservation->getSettings()->getValue(), true) : null;
914
915 /** @var SettingsService $settingsDS */
916 $settingsDS = $this->container->get('domain.settings.service');
917
918 if (
919 $settingsDS->isFeatureEnabled('waitingList') && $eventSettings && !empty($eventSettings['waitingList']) &&
920 $eventSettings['waitingList']['enabled']
921 ) {
922 $waitingCustomers = 0;
923
924 if (!$reservation->getBookings()->length()) {
925 if ($reservation->getCustomPricing()->getValue()) {
926 /** @var EventTicket $ticket */
927 foreach ($reservation->getCustomTickets()->getItems() as $ticket) {
928 $waitingCustomers += $ticket->getWaiting() ? $ticket->getWaiting()->getValue() : 0;
929 }
930 } else {
931 $waitingCustomers += $reservation->getSpotsWaiting() ? $reservation->getSpotsWaiting()->getValue() : 0;
932 }
933 }
934
935 /** @var CustomerBooking $booking */
936 foreach ($reservation->getBookings()->getItems() as $booking) {
937 if ($booking->getStatus()->getValue() === BookingStatus::WAITING) {
938 if ($reservation->getCustomPricing()->getValue()) {
939 foreach ($booking->getTicketsBooking()->getItems() as $item) {
940 $waitingCustomers += $item->getPersons()->getValue();
941 }
942 } else {
943 $waitingCustomers += $booking->getPersons()->getValue();
944 }
945 }
946 }
947
948 if ($newBooking && $reservation->getCustomPricing() && $reservation->getCustomPricing()->getValue()) {
949 foreach ($newBooking->getTicketsBooking()->getItems() as $item) {
950 if (!$reservation->getMaxCustomCapacity()) {
951 $ticketData = $reservation->getCustomTickets()->getItem($item->getId()->getValue());
952
953 $waitingListSpots = $ticketData->getWaitingListSpots() ? $ticketData->getWaitingListSpots()->getValue() : 0;
954
955 $personsValue = $item->getPersons() ? $item->getPersons()->getValue() : 0;
956 $waitingValue = $ticketData->getWaiting() ? $ticketData->getWaiting()->getValue() : 0;
957
958 $hasWaitingList = $waitingListSpots >= ($personsValue + $waitingValue);
959 }
960 }
961
962 if ($reservation->getMaxCustomCapacity()) {
963 $hasWaitingList = $eventSettings['waitingList']['maxCapacity'] > $waitingCustomers;
964 }
965 } else {
966 $hasWaitingList = $eventSettings['waitingList']['maxCapacity'] > $waitingCustomers;
967 }
968
969 $eventSettings['waitingList']['peopleWaiting'] = $waitingCustomers;
970
971 $reservation->setSettings(new Json(json_encode($eventSettings)));
972 }
973
974 return $dateTime > $bookingOpens &&
975 $dateTime < $bookingCloses &&
976 ($hasCapacity || ($hasWaitingList && $newBooking && $newBooking->getStatus()->getValue() === BookingStatus::WAITING)) &&
977 in_array($reservation->getStatus()->getValue(), [BookingStatus::APPROVED, BookingStatus::PENDING], true);
978 }
979
980 /**
981 * @param CustomerBooking $booking
982 * @param Event $bookable
983 * @param bool $invoice
984 *
985 * @return array
986 *
987 * @throws InvalidArgumentException
988 */
989 public function getPaymentAmount($booking, $bookable, $invoice = false)
990 {
991 /** @var TaxApplicationService $taxApplicationService */
992 $taxApplicationService = $this->container->get('application.tax.service');
993
994 /** @var Tax $eventTax */
995 $eventTax = $this->getTax($booking->getTax());
996
997 $persons = $booking->getPersons()->getValue();
998
999 $unitPrice = (float)$bookable->getPrice()->getValue();
1000
1001 $price = $unitPrice * ($this->isAggregatedPrice($bookable) ? $persons : 1);
1002
1003 $taxAmount = 0;
1004
1005 $ticketsTax = [];
1006
1007 if (
1008 $booking->getTicketsBooking() &&
1009 $booking->getTicketsBooking()->length() &&
1010 $bookable->getCustomPricing() &&
1011 $bookable->getCustomPricing()->getValue()
1012 ) {
1013 /** @var EventApplicationService $eventApplicationService */
1014 $eventApplicationService = $this->container->get('application.booking.event.service');
1015
1016 $bookable->setCustomTickets(
1017 $eventApplicationService->getTicketsPriceByDateRange($bookable->getCustomTickets())
1018 );
1019
1020 $ticketSumPrice = 0;
1021
1022 /** @var CustomerBookingEventTicket $bookingToEventTicket */
1023 foreach ($booking->getTicketsBooking()->getItems() as $bookingToEventTicket) {
1024 /** @var EventTicket $ticket */
1025 $ticket = $bookable->getCustomTickets()->getItem($bookingToEventTicket->getEventTicketId()->getValue());
1026
1027 $ticketPrice = $ticket->getDateRangePrice() ?
1028 $ticket->getDateRangePrice()->getValue() : $ticket->getPrice()->getValue();
1029
1030 $ticketPersons = $bookingToEventTicket->getPersons() ?
1031 ($booking->getAggregatedPrice()->getValue() ? $bookingToEventTicket->getPersons()->getValue() : 1)
1032 : 0;
1033
1034 $ticketSubtotal = $ticketPersons * $ticketPrice;
1035
1036 $ticketSumPrice += $ticketSubtotal;
1037
1038 if ($bookingToEventTicket->getId()) {
1039 if ($eventTax && $eventTax->getExcluded()->getValue()) {
1040 $ticketsTax[$bookingToEventTicket->getId()->getValue()] = $this->getTaxAmount($eventTax, $ticketSubtotal);
1041 } elseif ($eventTax && !$eventTax->getExcluded()->getValue()) {
1042 $ticketsTax[$bookingToEventTicket->getId()->getValue()] =
1043 $this->getTaxAmount($eventTax, $taxApplicationService->getBasePrice($ticketSubtotal, $eventTax));
1044 } else {
1045 $ticketsTax[$bookingToEventTicket->getId()->getValue()] = 0;
1046 }
1047 }
1048 }
1049
1050 $price = $ticketSumPrice;
1051 }
1052
1053 if ($eventTax && !$eventTax->getExcluded()->getValue() && ($booking->getCoupon() || $invoice)) {
1054 $price = $taxApplicationService->getBasePrice($price, $eventTax);
1055 }
1056
1057 $priceWithoutCoupon = $price;
1058
1059 $subtotalPrice = round($price, 4);
1060
1061 $subtraction = 0;
1062
1063 $reductionAmount = [
1064 'deduction' => 0,
1065 'discount' => 0,
1066 ];
1067
1068 if ($booking->getCoupon()) {
1069 $reductionAmount['discount'] = $price / 100 * ($booking->getCoupon()->getDiscount()->getValue() ?: 0);
1070
1071 $reductionAmount['deduction'] = $booking->getCoupon()->getDeduction()->getValue();
1072
1073 $subtraction = $reductionAmount['discount'] + $reductionAmount['deduction'];
1074
1075 $price = max($price - $subtraction, 0);
1076 }
1077
1078 if ($eventTax && ($eventTax->getExcluded()->getValue() || $subtraction || $invoice)) {
1079 $taxAmount = $this->getTaxAmount($eventTax, $price);
1080 $price += $taxAmount;
1081 $priceWithoutCoupon += $taxAmount;
1082 }
1083
1084 $price = (float)max(round($price, 2), 0);
1085
1086 if (!$price) {
1087 foreach ($ticketsTax as $ticketId => $ticketTax) {
1088 $ticketsTax[$ticketId] = 0;
1089 }
1090 }
1091
1092 return [
1093 'price' => apply_filters('amelia_modify_payment_amount', $price, $booking),
1094 'discount' => $reductionAmount['discount'],
1095 'deduction' => $reductionAmount['deduction'],
1096 'total' => $priceWithoutCoupon,
1097 'unit_price' => $unitPrice,
1098 'qty' => $this->isAggregatedPrice($bookable) ? $persons : 1,
1099 'bookable' => $subtotalPrice,
1100 'subtotal' => $subtotalPrice,
1101 'tax' => $eventTax ? $this->getTaxAmount($eventTax, $subtotalPrice) : 0,
1102 'total_tax' => $taxAmount,
1103 'tax_rate' => $eventTax ? $this->getTaxRate($eventTax) : '',
1104 'tax_type' => $eventTax ? $eventTax->getType()->getValue() : '',
1105 'tax_excluded' => $eventTax ? $eventTax->getExcluded()->getValue() : false,
1106 'tickets_tax' => $ticketsTax,
1107 'full_discount' =>
1108 $this->getCouponDiscountAmount($booking->getCoupon(), $priceWithoutCoupon) +
1109 ($booking->getCoupon() && $booking->getCoupon()->getDeduction() ? (float)$booking->getCoupon()->getDeduction()->getValue() : 0)
1110 ];
1111 }
1112
1113 /**
1114 * @param Reservation $reservation
1115 *
1116 * @return float
1117 *
1118 * @throws InvalidArgumentException
1119 */
1120 public function getReservationPaymentAmount($reservation)
1121 {
1122 /** @var AbstractDepositApplicationService $depositAS */
1123 $depositAS = $this->container->get('application.deposit.service');
1124
1125 /** @var Event $bookable */
1126 $bookable = $reservation->getBookable();
1127
1128 $paymentAmount = $this->getPaymentAmount($reservation->getBooking(), $bookable)['price'];
1129
1130 if ($reservation->getApplyDeposit()->getValue()) {
1131 $personsCount = $reservation->getBooking()->getPersons()->getValue();
1132
1133 if ($reservation->getBooking()->getTicketsBooking() && $bookable->getCustomPricing()->getValue()) {
1134 $personsCount = 0;
1135
1136 /** @var CustomerBookingEventTicket $bookingToEventTicket */
1137 foreach ($reservation->getBooking()->getTicketsBooking()->getItems() as $bookingToEventTicket) {
1138 $personsCount += ($bookingToEventTicket->getPersons() ?
1139 $bookingToEventTicket->getPersons()->getValue() : 0);
1140 }
1141 }
1142
1143 $paymentAmount = $depositAS->calculateDepositAmount(
1144 $paymentAmount,
1145 $bookable,
1146 $personsCount
1147 );
1148 }
1149
1150 return $paymentAmount;
1151 }
1152
1153 /**
1154 * @param Reservation $reservation
1155 * @param bool $usePayment
1156 *
1157 * @return array
1158 *
1159 * @throws InvalidArgumentException
1160 */
1161 public function getProvidersPaymentAmount($reservation, $usePayment = true)
1162 {
1163 $amountData = [];
1164
1165 /** @var Payment $payment */
1166 $payment = $usePayment ? $reservation->getBooking()->getPayments()->getItem(0) : null;
1167
1168 /** @var Event $event */
1169 $event = $reservation->getBookable();
1170
1171 /** @var Provider $provider */
1172 foreach ($event->getProviders()->getItems() as $provider) {
1173 $amountData[$provider->getId()->getValue()][] = [
1174 'paymentId' => $payment ? $payment->getId()->getValue() : null,
1175 'amount' => $this->getReservationPaymentAmount($reservation),
1176 ];
1177 }
1178
1179 return $amountData;
1180 }
1181
1182 /**
1183 * @param Payment $payment
1184 * @param boolean $fromLink
1185 *
1186 * @return CommandResult
1187 * @throws InvalidArgumentException
1188 * @throws Exception
1189 */
1190 public function getReservationByPayment($payment, $fromLink = false)
1191 {
1192 $result = new CommandResult();
1193
1194 /** @var CustomerRepository $customerRepository */
1195 $customerRepository = $this->container->get('domain.users.customers.repository');
1196
1197 /** @var LocationRepository $locationRepository */
1198 $locationRepository = $this->container->get('domain.locations.repository');
1199
1200 /** @var ReservationServiceInterface $reservationService */
1201 $reservationService = $this->container->get('application.reservation.service')->get(Entities::EVENT);
1202
1203 /** @var Event $event */
1204 $event = $reservationService->getReservationByBookingId(
1205 $payment->getCustomerBookingId()->getValue()
1206 );
1207
1208 if ($event->getLocationId()) {
1209 /** @var Location $location */
1210 $location = $locationRepository->getById($event->getLocationId()->getValue());
1211
1212 $event->setLocation($location);
1213 }
1214
1215 /** @var CustomerBooking $booking */
1216 $booking = $event->getBookings()->getItem($payment->getCustomerBookingId()->getValue());
1217
1218 $booking->setChangedStatus(new BooleanValueObject(true));
1219
1220 $this->setToken($booking);
1221
1222 /** @var AbstractUser $customer */
1223 $customer = $customerRepository->getById($booking->getCustomerId()->getValue());
1224
1225 $result->setData(
1226 [
1227 'type' => Entities::EVENT,
1228 Entities::EVENT => $event->toArray(),
1229 Entities::BOOKING => $booking->toArray(),
1230 'appointmentStatusChanged' => false,
1231 'customer' => $customer->toArray(),
1232 'packageId' => 0,
1233 'recurring' => [],
1234 'utcTime' => $reservationService->getBookingPeriods(
1235 $event,
1236 $booking,
1237 $event
1238 ),
1239 'bookable' => $event->toArray(),
1240 'isRetry' => !$fromLink,
1241 'fromLink' => $fromLink,
1242 'paymentId' => $payment->getId()->getValue(),
1243 'packageCustomerId' => null,
1244 'payment' => [
1245 'id' => $payment->getId()->getValue(),
1246 'amount' => $payment->getAmount()->getValue(),
1247 'gateway' => $payment->getGateway()->getName()->getValue(),
1248 'gatewayTitle' => $payment->getGatewayTitle() ? $payment->getGatewayTitle()->getValue() : '',
1249 'invoiceNumber' => $payment->getInvoiceNumber() ? $payment->getInvoiceNumber()->getValue() : '',
1250 ],
1251 ]
1252 );
1253
1254 return $result;
1255 }
1256
1257 /**
1258 * @param int $bookingId
1259 *
1260 * @return CommandResult
1261 * @throws InvalidArgumentException
1262 * @throws Exception
1263 */
1264 public function getBookingResultByBookingId($bookingId)
1265 {
1266 $result = new CommandResult();
1267
1268 /** @var CustomerRepository $customerRepository */
1269 $customerRepository = $this->container->get('domain.users.customers.repository');
1270
1271 /** @var LocationRepository $locationRepository */
1272 $locationRepository = $this->container->get('domain.locations.repository');
1273
1274 /** @var ReservationServiceInterface $reservationService */
1275 $reservationService = $this->container->get('application.reservation.service')->get(Entities::EVENT);
1276
1277 /** @var Event $event */
1278 $event = $reservationService->getReservationByBookingId(
1279 $bookingId
1280 );
1281
1282 if ($event->getLocationId()) {
1283 /** @var Location $location */
1284 $location = $locationRepository->getById($event->getLocationId()->getValue());
1285
1286 $event->setLocation($location);
1287 }
1288
1289 /** @var CustomerBooking $booking */
1290 $booking = $event->getBookings()->getItem($bookingId);
1291
1292 $booking->setChangedStatus(new BooleanValueObject(true));
1293
1294 $this->setToken($booking);
1295
1296 /** @var AbstractUser $customer */
1297 $customer = $customerRepository->getById($booking->getCustomerId()->getValue());
1298
1299 $result->setData(
1300 [
1301 'type' => Entities::EVENT,
1302 Entities::EVENT => $event->toArray(),
1303 Entities::BOOKING => $booking->toArray(),
1304 'appointmentStatusChanged' => false,
1305 'customer' => $customer->toArray(),
1306 'packageId' => 0,
1307 'recurring' => [],
1308 'utcTime' => $reservationService->getBookingPeriods(
1309 $event,
1310 $booking,
1311 $event
1312 ),
1313 'isRetry' => true,
1314 'paymentId' => null,
1315 'packageCustomerId' => null,
1316 'payment' => null,
1317 ]
1318 );
1319
1320 return $result;
1321 }
1322
1323 /**
1324 * @param array $data
1325 *
1326 * @return void
1327 * @throws QueryExecutionException
1328 */
1329 public function manageTaxes(&$data)
1330 {
1331 /** @var TaxApplicationService $taxAS */
1332 $taxAS = $this->container->get('application.tax.service');
1333
1334 /** @var SettingsService $settingsService */
1335 $settingsService = $this->container->get('domain.settings.service');
1336
1337 if ($settingsService->isFeatureEnabled('tax')) {
1338 /** @var Collection $taxes */
1339 $taxes = $taxAS->getAll();
1340
1341 $data['bookings'][0]['tax'] = $taxAS->getTaxData(
1342 $data['eventId'],
1343 Entities::EVENT,
1344 $taxes
1345 );
1346 }
1347 }
1348
1349 /**
1350 * @param int $bookingId
1351 *
1352 * @return array
1353 *
1354 * @throws AccessDeniedException
1355 * @throws InvalidArgumentException
1356 * @throws QueryExecutionException
1357 */
1358 public function deleteBooking($bookingId)
1359 {
1360 /** @var CustomerBookingRepository $customerBookingRepository */
1361 $customerBookingRepository = $this->container->get('domain.booking.customerBooking.repository');
1362
1363 /** @var EventApplicationService $eventApplicationService */
1364 $eventApplicationService = $this->container->get('application.booking.event.service');
1365
1366 /** @var CustomerBooking $customerBooking */
1367 $customerBooking = $customerBookingRepository->getById((int)$bookingId);
1368
1369 if (!$customerBooking) {
1370 throw new \Exception('Booking not found');
1371 }
1372
1373 $customerBookingRepository->beginTransaction();
1374
1375 if (!$eventApplicationService->deleteEventBooking($customerBooking)) {
1376 $customerBookingRepository->rollback();
1377 throw new \Exception('Could not delete booking');
1378 }
1379
1380 $customerBookingRepository->commit();
1381
1382 return [];
1383 }
1384
1385 /**
1386 * @param array $data
1387 * @param bool $invoices
1388 *
1389 * @return array
1390 * @throws InvalidArgumentException
1391 */
1392 public function getPaymentSummary($data, $invoices)
1393 {
1394 /** @var Event $bookable */
1395 $bookable = EventFactory::create(
1396 [
1397 'price' => $data['bookedPrice'] * ($data['aggregatedPrice'] ? $data['persons'] : 1),
1398 'aggregatedPrice' => $data['aggregatedPrice'],
1399 'customPricing' => false,
1400 'customTickets' => [],
1401 ]
1402 );
1403
1404 /** @var CustomerBooking $booking */
1405 $booking = CustomerBookingFactory::create(
1406 [
1407 'persons' => 1,
1408 'aggregatedPrice' => $data['aggregatedPrice'],
1409 'ticketsData' => null,
1410 'coupon' => $data['coupon'],
1411 'tax' => $data['bookedTax'],
1412 ]
1413 );
1414
1415 return $this->getCommonPaymentSummary($booking, $bookable, $data, $invoices);
1416 }
1417 }
1418