Below is a differential between the unpatched vulnerable code and the patched update, for reference.
--- a/ameliabooking/ameliabooking.php
+++ b/ameliabooking/ameliabooking.php
@@ -3,7 +3,7 @@
Plugin Name: Amelia
Plugin URI: https://wpamelia.com/
Description: Amelia is a simple yet powerful automated booking specialist, working 24/7 to make sure your customers can make appointments and events even while you sleep!
-Version: 2.1.2
+Version: 2.1.3
Author: Melograno Ventures
Author URI: https://melograno.io/
Text Domain: ameliabooking
@@ -35,6 +35,8 @@
use AmeliaBookingInfrastructureWPUserRolesUserRoles;
use AmeliaBookingInfrastructureWPWPMenuSubmenu;
use AmeliaBookingInfrastructureWPWPMenuSubmenuPageHandler;
+use AmeliaBookingInfrastructureWPCompatibilityLiteSpeedCacheCompatibility;
+use AmeliaBookingInfrastructureWPWPMenuAdminBarMenu;
use Exception;
use SlimApp;
use AmeliaBookingInfrastructureLicence;
@@ -109,7 +111,7 @@
// Const for Amelia version
if (!defined('AMELIA_VERSION')) {
- define('AMELIA_VERSION', '2.1.2');
+ define('AMELIA_VERSION', '2.1.3');
}
// Const for site URL
@@ -214,6 +216,9 @@
{
$settingsService = new SettingsService(new SettingsStorage());
+ // Initialize LiteSpeed Cache compatibility
+ LiteSpeedCacheCompatibility::init();
+
self::weglotConflict($settingsService, true);
load_plugin_textdomain(AMELIA_DOMAIN, false, plugin_basename(__DIR__) . '/languages/' . AMELIA_LOCALE . '/');
@@ -257,6 +262,14 @@
$ameliaRole = UserRoles::getUserAmeliaRole(wp_get_current_user());
+ // Register Gutenberg blocks for rendering on frontend (works for all users, logged in or not)
+ AmeliaStepBookingGutenbergBlock::init();
+ AmeliaCatalogBookingGutenbergBlock::init();
+ AmeliaBookingGutenbergBlock::init();
+ AmeliaCatalogGutenbergBlock::init();
+ AmeliaEventsGutenbergBlock::init();
+ AmeliaEventsListBookingGutenbergBlock::init();
+
// Init menu if user is logged in with amelia role
if (in_array($ameliaRole, ['admin', 'manager', 'provider', 'customer'])) {
if ($ameliaRole === 'admin') {
@@ -266,15 +279,6 @@
// Add TinyMCE button for shortcode generator
ButtonService::renderButton();
- // Add Gutenberg Block for shortcode generator
- AmeliaStepBookingGutenbergBlock::init();
- AmeliaCatalogBookingGutenbergBlock::init();
- AmeliaBookingGutenbergBlock::init();
- AmeliaCatalogGutenbergBlock::init();
- AmeliaEventsGutenbergBlock::init();
- AmeliaEventsListBookingGutenbergBlock::init();
-
-
add_filter('block_categories_all', array('AmeliaBookingPlugin', 'addAmeliaBlockCategory'), 10, 2);
add_filter('learn-press/frontend-default-scripts', array('AmeliaBookingPlugin', 'learnPressConflict'));
}
@@ -415,6 +419,16 @@
$wpMenu->addOptionsPages();
}
+ public static function initAdminBar()
+ {
+ $settingsService = new SettingsService(new SettingsStorage());
+
+ add_action('admin_bar_menu', function ($wpAdminBar) use ($settingsService) {
+ $adminBarMenu = new AdminBarMenu($settingsService);
+ $adminBarMenu->addAdminBarMenu($wpAdminBar);
+ }, 100);
+ }
+
public static function adminInit()
{
$settingsService = new SettingsService(new SettingsStorage());
@@ -667,6 +681,9 @@
/** Init the plugin */
add_action('plugins_loaded', array('AmeliaBookingPlugin', 'init'));
+add_action('init', array('AmeliaBookingInfrastructureWPWPMenuAdminBarMenu', 'enqueueScripts'));
+add_action('init', array('AmeliaBookingPlugin', 'initAdminBar'));
+
add_action('admin_init', array('AmeliaBookingPlugin', 'adminInit'));
add_action('admin_menu', array('AmeliaBookingPlugin', 'initMenu'));
--- a/ameliabooking/src/Application/Commands/Bookable/Category/GetCategoryDeleteEffectCommandHandler.php
+++ b/ameliabooking/src/Application/Commands/Bookable/Category/GetCategoryDeleteEffectCommandHandler.php
@@ -10,9 +10,9 @@
use AmeliaBookingApplicationCommandsCommandResult;
use AmeliaBookingApplicationCommandsCommandHandler;
use AmeliaBookingInfrastructureCommonExceptionsQueryExecutionException;
+use AmeliaBookingInfrastructureRepositoryBookableServicePackageRepository;
use AmeliaBookingInfrastructureRepositoryBookableServiceServiceRepository;
use AmeliaBookingDomainCollectionCollection;
-use InteropContainerExceptionContainerException;
use SlimExceptionContainerValueNotFoundException;
/**
@@ -29,7 +29,6 @@
* @throws ContainerValueNotFoundException
* @throws AccessDeniedException
* @throws QueryExecutionException
- * @throws ContainerException
* @throws InvalidArgumentException
*/
public function handle(GetCategoryDeleteEffectCommand $command)
@@ -46,6 +45,9 @@
/** @var ServiceRepository $serviceRepository */
$serviceRepository = $this->getContainer()->get('domain.bookable.service.repository');
+ /** @var PackageRepository $packageRepository */
+ $packageRepository = $this->container->get('domain.bookable.package.repository');
+
/** @var Collection $services */
$services = $serviceRepository->getByCriteria(['categories' => [$command->getArg('id')]]);
@@ -73,11 +75,18 @@
}
}
+ /** @var Collection $packages */
+ $packages = $services->length() ? $packageRepository->getByCriteria(['services' => $services->keys()]) : new Collection();
+
+ if ($packages->length()) {
+ $messageKey = 'red_category_failed_to_be_deleted';
+ }
+
$result->setResult(CommandResult::RESULT_SUCCESS);
$result->setMessage('Successfully retrieved message.');
$result->setData(
[
- 'valid' => !($categoryServiceIds && ($appointmentsCount['futureAppointments'] || $appointmentsCount['packageAppointments'])),
+ 'valid' => !($categoryServiceIds && ($appointmentsCount['futureAppointments'] || $appointmentsCount['packageAppointments'])),
'messageKey' => $messageKey,
'messageData' => $messageData,
]
--- a/ameliabooking/src/Application/Commands/Bookable/Service/DeleteServiceCommandHandler.php
+++ b/ameliabooking/src/Application/Commands/Bookable/Service/DeleteServiceCommandHandler.php
@@ -11,12 +11,13 @@
use AmeliaBookingApplicationCommandsCommandResult;
use AmeliaBookingApplicationCommonExceptionsAccessDeniedException;
use AmeliaBookingApplicationServicesBookableBookableApplicationService;
+use AmeliaBookingDomainCollectionCollection;
use AmeliaBookingDomainCommonExceptionsInvalidArgumentException;
use AmeliaBookingDomainEntityBookableServiceService;
use AmeliaBookingDomainEntityEntities;
use AmeliaBookingInfrastructureCommonExceptionsQueryExecutionException;
+use AmeliaBookingInfrastructureRepositoryBookableServicePackageRepository;
use AmeliaBookingInfrastructureRepositoryBookableServiceServiceRepository;
-use InteropContainerExceptionContainerException;
use SlimExceptionContainerValueNotFoundException;
/**
@@ -34,7 +35,6 @@
* @throws InvalidArgumentException
* @throws QueryExecutionException
* @throws AccessDeniedException
- * @throws ContainerException
*/
public function handle(DeleteServiceCommand $command)
{
@@ -51,15 +51,21 @@
$appointmentsCount = $bookableApplicationService->getAppointmentsCountForServices([$command->getArg('id')]);
- /** @var ServiceRepository $serviceRepository */
- $serviceRepository = $this->container->get('domain.bookable.service.repository');
+ if ($appointmentsCount['futureAppointments']) {
+ $result->setResult(CommandResult::RESULT_CONFLICT);
+ $result->setMessage('Could not delete service.');
+ $result->setData([]);
- /** @var Service $service */
- $service = $serviceRepository->getByCriteria(
- ['services' => [$command->getArg('id')]]
- )->getItem($command->getArg('id'));
+ return $result;
+ }
- if ($appointmentsCount['futureAppointments']) {
+ /** @var PackageRepository $packageRepository */
+ $packageRepository = $this->container->get('domain.bookable.package.repository');
+
+ /** @var Collection $packages */
+ $packages = $packageRepository->getByCriteria(['services' => [$command->getArg('id')]]);
+
+ if ($packages->length()) {
$result->setResult(CommandResult::RESULT_CONFLICT);
$result->setMessage('Could not delete service.');
$result->setData([]);
@@ -67,6 +73,14 @@
return $result;
}
+ /** @var ServiceRepository $serviceRepository */
+ $serviceRepository = $this->container->get('domain.bookable.service.repository');
+
+ /** @var Service $service */
+ $service = $serviceRepository->getByCriteria(
+ ['services' => [$command->getArg('id')]]
+ )->getItem($command->getArg('id'));
+
$serviceRepository->beginTransaction();
do_action('amelia_before_service_deleted', $service->toArray());
--- a/ameliabooking/src/Application/Commands/Bookable/Service/GetServiceDeleteEffectCommandHandler.php
+++ b/ameliabooking/src/Application/Commands/Bookable/Service/GetServiceDeleteEffectCommandHandler.php
@@ -4,12 +4,13 @@
use AmeliaBookingApplicationCommonExceptionsAccessDeniedException;
use AmeliaBookingApplicationServicesBookableBookableApplicationService;
+use AmeliaBookingDomainCollectionCollection;
use AmeliaBookingDomainCommonExceptionsInvalidArgumentException;
use AmeliaBookingDomainEntityEntities;
use AmeliaBookingApplicationCommandsCommandResult;
use AmeliaBookingApplicationCommandsCommandHandler;
use AmeliaBookingInfrastructureCommonExceptionsQueryExecutionException;
-use InteropContainerExceptionContainerException;
+use AmeliaBookingInfrastructureRepositoryBookableServicePackageRepository;
use SlimExceptionContainerValueNotFoundException;
/**
@@ -26,7 +27,6 @@
* @throws ContainerValueNotFoundException
* @throws AccessDeniedException
* @throws QueryExecutionException
- * @throws ContainerException
* @throws InvalidArgumentException
*/
public function handle(GetServiceDeleteEffectCommand $command)
@@ -37,6 +37,9 @@
$result = new CommandResult();
+ /** @var PackageRepository $packageRepository */
+ $packageRepository = $this->container->get('domain.bookable.package.repository');
+
/** @var BookableApplicationService $bookableAS */
$bookableAS = $this->getContainer()->get('application.bookable.service');
@@ -55,11 +58,18 @@
$messageData = ['count' => $appointmentsCount['pastAppointments']];
}
+ /** @var Collection $packages */
+ $packages = $packageRepository->getByCriteria(['services' => [$command->getArg('id')]]);
+
+ if ($packages->length()) {
+ $messageKey = 'red_service_failed_to_be_deleted';
+ }
+
$result->setResult(CommandResult::RESULT_SUCCESS);
$result->setMessage('Successfully retrieved message.');
$result->setData(
[
- 'valid' => $appointmentsCount['futureAppointments'] ? false : true,
+ 'valid' => !$appointmentsCount['futureAppointments'] && !$packages->length(),
'messageKey' => $messageKey,
'messageData' => $messageData,
]
--- a/ameliabooking/src/Application/Commands/Booking/Appointment/AddAppointmentCommandHandler.php
+++ b/ameliabooking/src/Application/Commands/Booking/Appointment/AddAppointmentCommandHandler.php
@@ -151,6 +151,10 @@
$service
);
+ if (!empty($appointmentData['createPaymentLinks'])) {
+ $appointment->setCreatePaymentLinks(true);
+ }
+
if ($existingAppointment && !empty($appointmentData['internalNotes'])) {
if (
$existingAppointment->getInternalNotes() &&
--- a/ameliabooking/src/Application/Commands/Booking/Appointment/GetAppointmentBookingsCommandHandler.php
+++ b/ameliabooking/src/Application/Commands/Booking/Appointment/GetAppointmentBookingsCommandHandler.php
@@ -227,6 +227,8 @@
),
'status' => $paymentAS->getFullStatus($booking->toArray(), 'appointment'),
],
+ 'created' => $booking->getCreated() ?
+ $booking->getCreated()->getValue()->format('Y-m-d') : null,
];
$isPackageAppointment = !empty($booking->getPackageCustomerService());
--- a/ameliabooking/src/Application/Commands/Booking/Appointment/ReassignBookingCommandHandler.php
+++ b/ameliabooking/src/Application/Commands/Booking/Appointment/ReassignBookingCommandHandler.php
@@ -616,6 +616,8 @@
$oldAppointment->getStatus()->getValue()
);
+ $newAppointment->setInternalNotes(new Description(''));
+
$newAppointmentId = $appointmentRepository->add($newAppointment);
$newAppointment->setId(new Id($newAppointmentId));
--- a/ameliabooking/src/Application/Commands/Booking/Appointment/UpdateAppointmentCommandHandler.php
+++ b/ameliabooking/src/Application/Commands/Booking/Appointment/UpdateAppointmentCommandHandler.php
@@ -13,7 +13,6 @@
use AmeliaBookingApplicationServicesPaymentPaymentApplicationService;
use AmeliaBookingApplicationServicesReservationAppointmentReservationService;
use AmeliaBookingApplicationServicesUserUserApplicationService;
-use AmeliaBookingApplicationServicesZoomAbstractZoomApplicationService;
use AmeliaBookingDomainCollectionCollection;
use AmeliaBookingDomainCommonExceptionsAuthorizationException;
use AmeliaBookingDomainCommonExceptionsInvalidArgumentException;
@@ -35,6 +34,7 @@
use AmeliaBookingInfrastructureCommonExceptionsQueryExecutionException;
use AmeliaBookingInfrastructureRepositoryBookingAppointmentAppointmentRepository;
use AmeliaBookingInfrastructureRepositoryBookingAppointmentCustomerBookingRepository;
+use AmeliaBookingInfrastructureRepositoryPaymentPaymentRepository;
use AmeliaBookingInfrastructureRepositoryUserProviderRepository;
use AmeliaBookingInfrastructureRepositoryUserUserRepository;
use AmeliaBookingInfrastructureWPTranslationsFrontendStrings;
@@ -87,8 +87,6 @@
$bookableAS = $this->container->get('application.bookable.service');
/** @var AbstractCustomFieldApplicationService $customFieldService */
$customFieldService = $this->container->get('application.customField.service');
- /** @var AbstractZoomApplicationService $zoomService */
- $zoomService = $this->container->get('application.zoom.service');
/** @var UserApplicationService $userAS */
$userAS = $this->getContainer()->get('application.user.service');
/** @var SettingsService $settingsDS */
@@ -428,6 +426,43 @@
$appointment->setChangedStatus(new BooleanValueObject(true));
}
+ /** @var PaymentRepository $paymentRepository */
+ $paymentRepository = $this->container->get('domain.payment.repository');
+
+ $bookingIds = [];
+
+ /** @var CustomerBooking $booking */
+ foreach ($appointment->getBookings()->getItems() as $booking) {
+ if ($booking->getId() && $booking->getId()->getValue()) {
+ $bookingIds[] = $booking->getId()->getValue();
+ }
+ }
+
+ if ($bookingIds) {
+ /** @var Collection $payments */
+ $payments = $paymentRepository->getByCriteria(['bookingIds' => $bookingIds]);
+
+ /** @var CustomerBooking $booking */
+ foreach ($appointment->getBookings()->getItems() as $booking) {
+ if ($booking->getId() && $booking->getId()->getValue() && !$booking->getPayments()->length()) {
+ $bookingPayments = new Collection();
+
+ foreach ($payments->getItems() as $payment) {
+ if (
+ $payment->getCustomerBookingId() &&
+ $payment->getCustomerBookingId()->getValue() === $booking->getId()->getValue()
+ ) {
+ $bookingPayments->addItem($payment, $payment->getId()->getValue());
+ }
+ }
+
+ if ($bookingPayments->length()) {
+ $booking->setPayments($bookingPayments);
+ }
+ }
+ }
+ }
+
$appointmentArray = $appointment->toArray();
$oldAppointmentArray = $oldAppointment->toArray();
--- a/ameliabooking/src/Application/Commands/Booking/Appointment/UpdateAppointmentTimeCommandHandler.php
+++ b/ameliabooking/src/Application/Commands/Booking/Appointment/UpdateAppointmentTimeCommandHandler.php
@@ -129,26 +129,28 @@
}
}
- $minimumRescheduleTimeInSeconds = $settingsDS
- ->getEntitySettings($service->getSettings())
- ->getGeneralSettings()
- ->getMinimumTimeRequirementPriorToRescheduling();
+ if ($userAS->isCustomer($user)) {
+ $minimumRescheduleTimeInSeconds = $settingsDS
+ ->getEntitySettings($service->getSettings())
+ ->getGeneralSettings()
+ ->getMinimumTimeRequirementPriorToRescheduling();
- try {
- $reservationService->inspectMinimumCancellationTime(
- $appointment->getBookingStart()->getValue(),
- $minimumRescheduleTimeInSeconds
- );
- } catch (BookingCancellationException $e) {
- $result->setResult(CommandResult::RESULT_ERROR);
- $result->setMessage('You are not allowed to update booking');
- $result->setData(
- [
- 'rescheduleBookingUnavailable' => true
- ]
- );
+ try {
+ $reservationService->inspectMinimumCancellationTime(
+ $appointment->getBookingStart()->getValue(),
+ $minimumRescheduleTimeInSeconds
+ );
+ } catch (BookingCancellationException $e) {
+ $result->setResult(CommandResult::RESULT_ERROR);
+ $result->setMessage('You are not allowed to update booking');
+ $result->setData(
+ [
+ 'rescheduleBookingUnavailable' => true
+ ]
+ );
- return $result;
+ return $result;
+ }
}
$bookingStart = $command->getField('bookingStart');
--- a/ameliabooking/src/Application/Commands/Booking/Event/GetEventBookingCommandHandler.php
+++ b/ameliabooking/src/Application/Commands/Booking/Event/GetEventBookingCommandHandler.php
@@ -197,6 +197,12 @@
'location' =>
$event->getCustomLocation() ?
['name' => $event->getCustomLocation()->getValue()] : ($event->getLocationId() ? $event->getLocation()->toArray() : null),
+ 'periods' => array_map(function ($period) {
+ return [
+ 'periodStart' => $period['periodStart'],
+ 'periodEnd' => $period['periodEnd']
+ ];
+ }, $event->getPeriods()->toArray()),
]
);
--- a/ameliabooking/src/Application/Commands/Booking/Event/GetEventBookingsCommandHandler.php
+++ b/ameliabooking/src/Application/Commands/Booking/Event/GetEventBookingsCommandHandler.php
@@ -6,9 +6,11 @@
use AmeliaBookingApplicationCommandsCommandResult;
use AmeliaBookingApplicationCommonExceptionsAccessDeniedException;
use AmeliaBookingApplicationServicesBookingEventApplicationService;
+use AmeliaBookingApplicationServicesCustomFieldAbstractCustomFieldApplicationService;
use AmeliaBookingApplicationServicesPaymentPaymentApplicationService;
use AmeliaBookingApplicationServicesUserProviderApplicationService;
use AmeliaBookingApplicationServicesUserUserApplicationService;
+use AmeliaBookingDomainCollectionCollection;
use AmeliaBookingDomainCommonExceptionsAuthorizationException;
use AmeliaBookingDomainCommonExceptionsInvalidArgumentException;
use AmeliaBookingDomainEntityBookingAppointmentCustomerBooking;
@@ -18,6 +20,7 @@
use AmeliaBookingDomainEntityEntities;
use AmeliaBookingDomainEntityUserAbstractUser;
use AmeliaBookingDomainEntityUserProvider;
+use AmeliaBookingDomainFactoryBookingAppointmentCustomerBookingFactory;
use AmeliaBookingDomainFactoryBookingEventEventFactory;
use AmeliaBookingDomainServicesDateTimeDateTimeService;
use AmeliaBookingDomainServicesSettingsSettingsService;
@@ -25,6 +28,7 @@
use AmeliaBookingDomainValueObjectsStringBookingStatus;
use AmeliaBookingInfrastructureCommonExceptionsQueryExecutionException;
use AmeliaBookingInfrastructureRepositoryBookingAppointmentCustomerBookingRepository;
+use AmeliaBookingInfrastructureRepositoryCustomFieldCustomFieldRepository;
use Exception;
/**
@@ -58,8 +62,12 @@
$eventApplicationService = $this->container->get('application.booking.event.service');
/** @var CustomerBookingRepository $bookingRepository */
$bookingRepository = $this->container->get('domain.booking.customerBooking.repository');
+ /** @var CustomFieldRepository $customFieldRepository */
+ $customFieldRepository = $this->container->get('domain.customField.repository');
/** @var ProviderApplicationService $providerAS */
$providerAS = $this->container->get('application.user.provider.service');
+ /** @var AbstractCustomFieldApplicationService $customFieldService */
+ $customFieldService = $this->container->get('application.customField.service');
$params = $command->getField('params');
@@ -217,6 +225,7 @@
$bookings = $bookingRepository->getEventBookingsByIds(
$bookingIds,
array_merge(
+ !empty($params['sort']) ? ['sort' => $params['sort']] : [],
!empty($params['dates']) ? ['dates' => $params['dates']] : [],
[
'fetchBookingsPayments' => true,
@@ -229,6 +238,9 @@
);
+ /** @var Collection $customFieldsCollection */
+ $customFieldsCollection = $customFieldRepository->getAll([], false);
+
$customersNoShowCountIds = [];
$noShowTagEnabled = $settingsDS->isFeatureEnabled('noShowTag');
@@ -236,6 +248,8 @@
$eventBookings = [];
foreach ($bookings as &$booking) {
+ $customFields = [];
+
ksort($booking['payments']);
if ($noShowTagEnabled) {
@@ -281,6 +295,7 @@
$wcTax = 0;
$wcDiscount = 0;
+ $paid = 0;
foreach ($booking['payments'] as $payment) {
$paymentAS->addWcFields($payment);
@@ -288,8 +303,16 @@
$wcTax += !empty($payment['wcItemTaxValue']) ? $payment['wcItemTaxValue'] : 0;
$wcDiscount += !empty($payment['wcItemCouponValue']) ? $payment['wcItemCouponValue'] : 0;
+
+ $paid = $paid + $payment['amount'];
}
+ $customFields = $customFieldService->reformatCustomField(
+ CustomerBookingFactory::create($booking),
+ $customFields,
+ $customFieldsCollection
+ );
+
$eventBooking = [
'id' => $booking['id'],
'bookedSpots' => $persons,
@@ -329,10 +352,13 @@
'payment' => [
'status' => $paymentAS->getFullStatus($booking, BookableType::EVENT),
'total' => $paymentAS->calculateAppointmentPrice($booking, BookableType::EVENT) + $wcTax - $wcDiscount,
+ 'paid' => $paid,
],
+ 'customFields' => $customFields,
'payments' => array_values($booking['payments']),
'qrCodes' => !empty($booking['qrCodes']) ? $booking['qrCodes'] : null,
'cancelable' => $eventApplicationService->isCancelable(EventFactory::create($booking['event']), $user),
+ 'created' => !empty($booking['created']) ? explode(' ', $booking['created'])[0] : null,
];
if ($isCabinetPage) {
--- a/ameliabooking/src/Application/Commands/Booking/Event/GetEventCommandHandler.php
+++ b/ameliabooking/src/Application/Commands/Booking/Event/GetEventCommandHandler.php
@@ -21,7 +21,6 @@
use AmeliaBookingDomainEntityBookingEventEventTicket;
use AmeliaBookingDomainEntityEntities;
use AmeliaBookingDomainEntityUserAbstractUser;
-use AmeliaBookingDomainEntityUserProvider;
use AmeliaBookingDomainValueObjectsNumberIntegerIntegerValue;
use AmeliaBookingDomainValueObjectsStringBookingStatus;
use AmeliaBookingInfrastructureCommonExceptionsQueryExecutionException;
@@ -90,6 +89,9 @@
/** @var CustomFieldRepository $customFieldRepository */
$customFieldRepository = $this->container->get('domain.customField.repository');
+ $fetchBookings =
+ empty($command->getFields()['params']['bookings']) ||
+ filter_var($command->getFields()['params']['bookings'], FILTER_VALIDATE_BOOLEAN);
/** @var Event $event */
$event = $eventApplicationService->getEventById(
@@ -100,13 +102,14 @@
'fetchEventsTags' => empty($command->getFields()['params']['drawer']),
'fetchEventsProviders' => empty($command->getFields()['params']['drawer']),
'fetchEventsImages' => true,
- 'fetchBookings' => true,
- 'fetchBookingsTickets' => true,
- 'fetchBookingsUsers' => true,
- 'fetchBookingsPayments' => true,
- 'fetchBookingsCoupons' => true,
+ 'fetchBookings' => $fetchBookings,
+ 'fetchBookingsTickets' => $fetchBookings,
+ 'fetchBookingsUsers' => $fetchBookings,
+ 'fetchBookingsPayments' => $fetchBookings,
+ 'fetchBookingsCoupons' => $fetchBookings,
'fetchEventsOrganizer' => true,
'fetchEventsLocation' => true,
+ 'fetchOccupancy' => !$fetchBookings,
]
);
@@ -173,6 +176,15 @@
$bookingsPrice = 0;
$paidPrice = 0;
+ $customersIds = [];
+
+ /** @var CustomerBooking $booking */
+ foreach ($event->getBookings()->getItems() as $booking) {
+ $customersIds[] = $booking->getCustomerId()->getValue();
+ }
+
+ $customersNoShowCount = $customersIds ? $bookingRepository->countByNoShowStatus($customersIds) : [];
+
/** @var CustomerBooking $booking */
foreach ($event->getBookings()->getItems() as $booking) {
$customFields = [];
@@ -211,11 +223,6 @@
}
$paidPrice += $bookingPaidPrice;
- $noShowCount = $bookingRepository->countByNoShowStatus([$booking->getCustomerId()->getValue()]);
- if ($noShowCount && !empty($noShowCount[$booking->getCustomerId()->getValue()])) {
- $noShowCount = $noShowCount[$booking->getCustomerId()->getValue()]['count'];
- }
-
$customFields = $customFieldService->reformatCustomField($booking, $customFields, $customFieldsCollection);
$eventBookings[] = [
@@ -225,7 +232,9 @@
'firstName' => $booking->getCustomer()->getFirstName()->getValue(),
'lastName' => $booking->getCustomer()->getLastName() ? $booking->getCustomer()->getLastName()->getValue() : null,
'email' => $booking->getCustomer()->getEmail() ? $booking->getCustomer()->getEmail()->getValue() : null,
- 'noShowCount' => $noShowCount,
+ 'noShowCount' => !empty($customersNoShowCount[$booking->getCustomerId()->getValue()])
+ ? $customersNoShowCount[$booking->getCustomerId()->getValue()]['count']
+ : [],
'note' => $booking->getCustomer()->getNote() ? $booking->getCustomer()->getNote()->getValue() : null,
],
'tickets' => $ticketsData,
@@ -286,6 +295,7 @@
'location' => $event->getCustomLocation() ?
['name' => $event->getCustomLocation()->getValue()] :
($event->getLocationId() ? $event->getLocation()->toArray() : null),
+ 'payment' => $eventRepository->getEventsPaymentsSummary((int)$command->getField('id')),
],
$eventInfo
);
--- a/ameliabooking/src/Application/Commands/Booking/Event/GetEventsCommandHandler.php
+++ b/ameliabooking/src/Application/Commands/Booking/Event/GetEventsCommandHandler.php
@@ -64,6 +64,10 @@
$isFrontEnd = isset($params['page']) && empty($params['group']);
+ $fetchBookings = !$isFrontEnd && (
+ !isset($params['bookings']) || filter_var($params['bookings'], FILTER_VALIDATE_BOOLEAN)
+ );
+
$isCalendarPage = $isFrontEnd && (int)$params['page'] === 0;
$isCabinetPage = $command->getPage() === 'cabinet';
@@ -122,11 +126,12 @@
'fetchEventsProviders' => true,
'fetchEventsOrganizer' => true,
'fetchEventsImages' => true,
- 'fetchBookings' => true,
- 'fetchBookingsTickets' => true,
- 'fetchBookingsCoupons' => $isCabinetPage,
- 'fetchBookingsPayments' => $isCabinetPage,
- 'fetchBookingsUsers' => $isCabinetPage,
+ 'fetchBookings' => $fetchBookings,
+ 'fetchBookingsTickets' => $fetchBookings,
+ 'fetchBookingsCoupons' => $fetchBookings && $isCabinetPage,
+ 'fetchBookingsPayments' => $fetchBookings && $isCabinetPage,
+ 'fetchBookingsUsers' => $fetchBookings && $isCabinetPage,
+ 'fetchOccupancy' => !$fetchBookings,
];
/** @var Collection $events */
--- a/ameliabooking/src/Application/Commands/Booking/Event/UpdateEventCommandHandler.php
+++ b/ameliabooking/src/Application/Commands/Booking/Event/UpdateEventCommandHandler.php
@@ -169,6 +169,21 @@
if ($oldEventPeriod->getLessonSpace()) {
$eventPeriod->setLessonSpace($oldEventPeriod->getLessonSpace());
}
+ if ($oldEventPeriod->getGoogleCalendarEventId()) {
+ $eventPeriod->setGoogleCalendarEventId($oldEventPeriod->getGoogleCalendarEventId());
+ }
+ if ($oldEventPeriod->getGoogleMeetUrl()) {
+ $eventPeriod->setGoogleMeetUrl($oldEventPeriod->getGoogleMeetUrl());
+ }
+ if ($oldEventPeriod->getOutlookCalendarEventId()) {
+ $eventPeriod->setOutlookCalendarEventId($oldEventPeriod->getOutlookCalendarEventId());
+ }
+ if ($oldEventPeriod->getMicrosoftTeamsUrl()) {
+ $eventPeriod->setMicrosoftTeamsUrl($oldEventPeriod->getMicrosoftTeamsUrl());
+ }
+ if ($oldEventPeriod->getAppleCalendarEventId()) {
+ $eventPeriod->setAppleCalendarEventId($oldEventPeriod->getAppleCalendarEventId());
+ }
}
}
}
--- a/ameliabooking/src/Application/Commands/Calendar/GetCalendarEventsCommandHandler.php
+++ b/ameliabooking/src/Application/Commands/Calendar/GetCalendarEventsCommandHandler.php
@@ -53,6 +53,10 @@
$timeZone = '';
if ($user->getType() === Entities::CUSTOMER) {
+ if (!$user->getId()) {
+ throw new AccessDeniedException('You are not allowed to read calendar events.');
+ }
+
$queryParams['customers'] = [$user->getId()->getValue()];
}
@@ -112,6 +116,7 @@
}
$result->setData(['events' => $filledDays]);
+
return $result;
}
--- a/ameliabooking/src/Application/Commands/Calendar/GetCalendarSlotsCommandHandler.php
+++ b/ameliabooking/src/Application/Commands/Calendar/GetCalendarSlotsCommandHandler.php
@@ -9,9 +9,11 @@
use AmeliaBookingApplicationCommandsCommandHandler;
use AmeliaBookingApplicationCommandsCommandResult;
+use AmeliaBookingDomainEntityEntities;
use AmeliaBookingDomainEntityScheduleDayOff;
use AmeliaBookingDomainEntityScheduleSpecialDay;
use AmeliaBookingDomainEntityScheduleWeekDay;
+use AmeliaBookingDomainEntityUserAbstractUser;
use AmeliaBookingDomainEntityUserProvider;
use AmeliaBookingDomainServicesDateTimeDateTimeService;
use AmeliaBookingDomainValueObjectsStringBookingStatus;
@@ -32,6 +34,9 @@
$providerRepository = $this->container->get('domain.users.providers.repository');
$locationRepository = $this->container->get('domain.locations.repository');
+ /** @var AbstractUser $user */
+ $user = $this->container->get('logged.in.user');
+
$queryParams = $command->getField('queryParams');
$allWorkDays = [];
$selectedService = $queryParams['service'] ?? null;
@@ -61,7 +66,7 @@
}
}
- if (empty($allWorkDays)) {
+ if (empty($allWorkDays) || $user->getType() === Entities::CUSTOMER) {
$this->fillEmptyWorkDays($allWorkDays, $queryParams);
}
--- a/ameliabooking/src/Application/Commands/Command.php
+++ b/ameliabooking/src/Application/Commands/Command.php
@@ -6,6 +6,7 @@
use AmeliaBookingApplicationCommandsBookingAppointmentDeleteBookingRemotelyCommand;
use AmeliaBookingApplicationCommandsBookingAppointmentSuccessfulBookingCommand;
use AmeliaBookingApplicationCommandsNotificationUpdateSMSNotificationHistoryCommand;
+use AmeliaBookingApplicationCommandsOutlookFetchAccessTokenWithAuthCodeOutlookCommand;
use AmeliaBookingApplicationCommandsPaymentCalculatePaymentAmountCommand;
use AmeliaBookingApplicationCommandsSquareDisconnectFromSquareAccountCommand;
use AmeliaBookingApplicationCommandsSquareSquareRefundWebhookCommand;
@@ -187,6 +188,7 @@
!($this instanceof SquareRefundWebhookCommand) &&
!($this instanceof DisconnectFromSquareAccountCommand) &&
!($this instanceof SuccessfulBookingCommand) &&
+ !($this instanceof FetchAccessTokenWithAuthCodeOutlookCommand) &&
!($this instanceof UpdateSMSNotificationHistoryCommand)
) {
$queryParams = $request->getQueryParams();
--- a/ameliabooking/src/Application/Commands/Entities/GetEntitiesCommandHandler.php
+++ b/ameliabooking/src/Application/Commands/Entities/GetEntitiesCommandHandler.php
@@ -432,12 +432,12 @@
}
/** Coupons */
+ // Deprecated for backend use; replaced by `/coupons` endpoint.
+ // Retained for public `/entities` route and API access.
if (
in_array(Entities::COUPONS, $params['types'], true) &&
$this->getContainer()->getPermissionsService()->currentUserCanRead(Entities::COUPONS)
) {
- $coupons = $couponAS->getAll();
-
/** @var CouponRepository $couponRepository */
$couponRepository = $this->container->get('domain.coupon.repository');
@@ -447,6 +447,11 @@
/** @var PackageRepository $packageRepository */
$packageRepository = $this->container->get('domain.bookable.package.repository');
+ $coupons = $couponRepository->getFiltered(
+ ['page' => 1],
+ 100
+ );
+
if ($coupons->length()) {
foreach ($couponRepository->getCouponsServicesIds($coupons->keys()) as $ids) {
/** @var Coupon $coupon */
--- a/ameliabooking/src/Application/Commands/Google/VerifyRecaptchaCommand.php
+++ b/ameliabooking/src/Application/Commands/Google/VerifyRecaptchaCommand.php
@@ -0,0 +1,14 @@
+<?php
+
+namespace AmeliaBookingApplicationCommandsGoogle;
+
+use AmeliaBookingApplicationCommandsCommand;
+
+/**
+ * Class VerifyRecaptchaCommand
+ *
+ * @package AmeliaBookingApplicationCommandsGoogle
+ */
+class VerifyRecaptchaCommand extends Command
+{
+}
--- a/ameliabooking/src/Application/Commands/Google/VerifyRecaptchaCommandHandler.php
+++ b/ameliabooking/src/Application/Commands/Google/VerifyRecaptchaCommandHandler.php
@@ -0,0 +1,53 @@
+<?php
+
+namespace AmeliaBookingApplicationCommandsGoogle;
+
+use AmeliaBookingApplicationCommandsCommandHandler;
+use AmeliaBookingApplicationCommandsCommandResult;
+use AmeliaBookingApplicationCommonExceptionsAccessDeniedException;
+use AmeliaBookingDomainEntityEntities;
+
+/**
+ * Class VerifyRecaptchaCommandHandler
+ *
+ * @package AmeliaBookingApplicationCommandsGoogle
+ */
+class VerifyRecaptchaCommandHandler extends CommandHandler
+{
+ /**
+ * @param VerifyRecaptchaCommand $command
+ *
+ * @return CommandResult
+ * @throws AccessDeniedException
+ */
+ public function handle(VerifyRecaptchaCommand $command)
+ {
+ $result = new CommandResult();
+
+ if (!$this->getContainer()->getPermissionsService()->currentUserCanWrite(Entities::SETTINGS)) {
+ throw new AccessDeniedException('You are not allowed to read settings.');
+ }
+
+ $fields = $command->getFields();
+ $secret = isset($fields['secret']) ? $fields['secret'] : '';
+ $token = isset($fields['token']) ? $fields['token'] : null;
+
+ /** @var AmeliaBookingInfrastructureServicesRecaptchaAbstractRecaptchaService $recaptchaService */
+ $recaptchaService = $this->getContainer()->get('infrastructure.recaptcha.service');
+
+ $verification = $recaptchaService->verifyWithSecret($secret, $token);
+
+ if ($verification['success']) {
+ $result->setResult(CommandResult::RESULT_SUCCESS);
+ $result->setMessage($verification['message']);
+ } else {
+ $result->setResult(CommandResult::RESULT_ERROR);
+ $result->setMessage($verification['message']);
+ if (isset($verification['error_codes'])) {
+ $result->setData(['error_codes' => $verification['error_codes']]);
+ }
+ }
+
+ return $result;
+ }
+}
--- a/ameliabooking/src/Application/Commands/Import/ImportCustomersCommandHandler.php
+++ b/ameliabooking/src/Application/Commands/Import/ImportCustomersCommandHandler.php
@@ -20,6 +20,7 @@
use AmeliaBookingDomainValueObjectsNumberIntegerId;
use AmeliaBookingInfrastructureCommonExceptionsQueryExecutionException;
use AmeliaBookingInfrastructureRepositoryUserUserRepository;
+use AmeliaBookingInfrastructureWPTranslationsBackendStrings;
use Exception;
use InteropContainerExceptionContainerException;
use SlimExceptionContainerValueNotFoundException;
@@ -114,6 +115,9 @@
$existingEmails = $userRepository->getAllEmailsByType('customer');
for ($i = 0; $i < $num; $i++) {
+ if ($data['firstName'][$i] === BackendStrings::get('first_name')) {
+ continue;
+ }
try {
$customerData = [
'firstName' => $data['firstName'][$i],
--- a/ameliabooking/src/Application/Commands/QrCode/ScanQrCodeCommandHandler.php
+++ b/ameliabooking/src/Application/Commands/QrCode/ScanQrCodeCommandHandler.php
@@ -8,7 +8,7 @@
use AmeliaBookingApplicationServicesUserUserApplicationService;
use AmeliaBookingDomainCommonExceptionsInvalidArgumentException;
use AmeliaBookingDomainEntityBookingAppointmentCustomerBooking;
-use AmeliaBookingDomainEntityUserAbstractUser;
+use AmeliaBookingDomainEntityBookingEventEvent;
use AmeliaBookingInfrastructureCommonExceptionsQueryExecutionException;
use AmeliaBookingInfrastructureRepositoryBookingAppointmentCustomerBookingRepository;
use AmeliaBookingDomainEntityEntities;
@@ -49,18 +49,22 @@
$userAS = $this->container->get('application.user.service');
if (!$command->getPermissionService()->currentUserCanWrite(Entities::BOOKINGS)) {
- $user = $userAS->getAuthenticatedUser($command->getToken(), false, 'providerCabinet');
+ $user = $this->container->get('logged.in.user');
- if ($user === null) {
- $result->setResult(CommandResult::RESULT_ERROR);
- $result->setMessage('Could not retrieve user');
- $result->setData(
- [
- 'reauthorize' => true
- ]
- );
+ if (!$user || $user->getId() === null) {
+ $user = $userAS->getAuthenticatedUser($command->getToken(), false, 'providerCabinet');
- return $result;
+ if ($user === null) {
+ $result->setResult(CommandResult::RESULT_ERROR);
+ $result->setMessage('Could not retrieve user');
+ $result->setData(
+ [
+ 'reauthorize' => true
+ ]
+ );
+
+ return $result;
+ }
}
}
@@ -114,9 +118,10 @@
/** @var EventRepository $eventRepository */
$eventRepository = $this->container->get('domain.booking.event.repository');
- $event = $eventRepository->getByBookingId($bookingId);
+ $eventId = $eventRepository->getByBookingId($bookingId)->getId()->getValue();
+ $event = $eventRepository->getById($eventId);
- if ($event && $event->getStatus()->getValue() === 'rejected') {
+ if (!$event || $event->getStatus()->getValue() === 'rejected') {
$result->setResult(CommandResult::RESULT_ERROR);
$result->setMessage('Event is canceled');
$result->setData([
@@ -127,6 +132,18 @@
return $result;
}
+ // Check if the scanned date is within the event's periods
+ if (!$this->isDateWithinEventPeriods($event, $scannedAt)) {
+ $result->setResult(CommandResult::RESULT_ERROR);
+ $result->setMessage('Ticket cannot be scanned for this date');
+ $result->setData([
+ 'messageType' => 'error',
+ 'message' => 'ticket_not_valid_for_date',
+ ]);
+
+ return $result;
+ }
+
$updated = false;
$type = 'ticket';
@@ -144,18 +161,7 @@
isset($qrCode['ticketManualCode']) &&
hash_equals($qrCode['ticketManualCode'], $ticketManualCode)
) {
- if (!array_key_exists($scannedAt, $qrCode['dates'])) {
- $result->setResult(CommandResult::RESULT_ERROR);
- $result->setMessage('Ticket cannot be scanned for this date');
- $result->setData([
- 'messageType' => 'error',
- 'message' => 'ticket_not_valid_for_date',
- ]);
-
- return $result;
- }
-
- if ($qrCode['dates'][$scannedAt] === true) {
+ if (isset($qrCode['dates'][$scannedAt]) && $qrCode['dates'][$scannedAt] === true) {
$result->setResult(CommandResult::RESULT_ERROR);
$result->setMessage('Ticket has already been scanned');
$result->setData([
@@ -182,18 +188,7 @@
isset($qrCode['ticketManualCode']) &&
hash_equals($qrCode['ticketManualCode'], $ticketManualCode)
) {
- if (!array_key_exists($scannedAt, $qrCode['dates'])) {
- $result->setResult(CommandResult::RESULT_ERROR);
- $result->setMessage('Ticket cannot be scanned for this date');
- $result->setData([
- 'messageType' => 'error',
- 'message' => 'ticket_not_valid_for_date',
- ]);
-
- return $result;
- }
-
- if ($qrCode['dates'][$scannedAt] === true) {
+ if (isset($qrCode['dates'][$scannedAt]) && $qrCode['dates'][$scannedAt] === true) {
$result->setResult(CommandResult::RESULT_ERROR);
$result->setMessage('Group ticket has already been scanned');
$result->setData([
@@ -212,7 +207,7 @@
// Check if any ticket is already scanned for this date
foreach ($qrCodes as $qrCodeItem) {
- if (array_key_exists($scannedAt, $qrCodeItem['dates']) && $qrCodeItem['dates'][$scannedAt] === true) {
+ if (isset($qrCodeItem['dates'][$scannedAt]) && $qrCodeItem['dates'][$scannedAt] === true) {
$ticketsControl++;
}
}
@@ -229,13 +224,11 @@
}
$ticketsControl = 0;
- // Mark all as scanned for this date
+ // Mark all tickets as scanned for this date
foreach ($qrCodes as &$qr) {
- if (array_key_exists($scannedAt, $qr['dates'])) {
- if ($qr['dates'][$scannedAt] === false) {
- $ticketsControl++;
- $qr['dates'][$scannedAt] = true;
- }
+ if (!isset($qr['dates'][$scannedAt]) || $qr['dates'][$scannedAt] === false) {
+ $ticketsControl++;
+ $qr['dates'][$scannedAt] = true;
}
}
}
@@ -270,4 +263,27 @@
return $result;
}
+
+ private function isDateWithinEventPeriods(Event $event, string $scannedAt): bool
+ {
+ if (!$event->getPeriods()) {
+ return false;
+ }
+
+ $scannedDateTime = DateTime::createFromFormat('Y-m-d', $scannedAt);
+ if (!$scannedDateTime) {
+ return false;
+ }
+
+ foreach ($event->getPeriods()->getItems() as $period) {
+ $periodStart = (clone $period->getPeriodStart()->getValue())->setTime(0, 0, 0);
+ $periodEnd = (clone $period->getPeriodEnd()->getValue())->setTime(23, 59, 59);
+
+ if ($scannedDateTime >= $periodStart && $scannedDateTime <= $periodEnd) {
+ return true;
+ }
+ }
+
+ return false;
+ }
}
--- a/ameliabooking/src/Application/Commands/Settings/UpdateSettingsCommandHandler.php
+++ b/ameliabooking/src/Application/Commands/Settings/UpdateSettingsCommandHandler.php
@@ -6,6 +6,7 @@
use AmeliaBookingApplicationCommandsCommandResult;
use AmeliaBookingApplicationCommonExceptionsAccessDeniedException;
use AmeliaBookingApplicationServicesLocationAbstractCurrentLocation;
+use AmeliaBookingApplicationServicesNotificationAbstractWhatsAppNotificationService;
use AmeliaBookingApplicationServicesStashStashApplicationService;
use AmeliaBookingDomainCollectionCollection;
use AmeliaBookingDomainCommonExceptionsForbiddenFileUploadException;
--- a/ameliabooking/src/Application/Commands/User/Customer/UpdateCustomerCommandHandler.php
+++ b/ameliabooking/src/Application/Commands/User/Customer/UpdateCustomerCommandHandler.php
@@ -123,6 +123,16 @@
/** @var Customer $newUser */
$newUser = UserFactory::create($newUserData);
+ $oldExternalId = $oldUser->getExternalId() ? $oldUser->getExternalId()->getValue() : null;
+ $newExternalId = $newUser->getExternalId() ? $newUser->getExternalId()->getValue() : null;
+
+ if ($oldExternalId !== $newExternalId && (!$currentUser || $currentUser->getType() !== AbstractUser::USER_ROLE_ADMIN)) {
+ $result->setResult(CommandResult::RESULT_ERROR);
+ $result->setMessage('Could not update user.');
+
+ return $result;
+ }
+
// If the phone is not set and the old phone is set, set the phone and country phone iso to null
if (empty($customerData['phone']) && $oldUser->getPhone() && $oldUser->getPhone()->getValue()) {
$newUser->setPhone(new Phone(null));
--- a/ameliabooking/src/Application/Commands/WhatsNew/GetWhatsNewCommandHandler.php
+++ b/ameliabooking/src/Application/Commands/WhatsNew/GetWhatsNewCommandHandler.php
@@ -90,8 +90,6 @@
$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
$curlError = curl_error($curl);
- curl_close($curl);
-
if ($response === false) {
throw new Exception('Failed to fetch posts from API: ' . $curlError);
}
--- a/ameliabooking/src/Application/Controller/Google/VerifyRecaptchaController.php
+++ b/ameliabooking/src/Application/Controller/Google/VerifyRecaptchaController.php
@@ -0,0 +1,45 @@
+<?php
+
+namespace AmeliaBookingApplicationControllerGoogle;
+
+use AmeliaBookingApplicationCommandsGoogleVerifyRecaptchaCommand;
+use AmeliaBookingApplicationControllerController;
+use SlimHttpRequest;
+
+/**
+ * Class VerifyRecaptchaController
+ *
+ * @package AmeliaBookingApplicationControllerGoogle
+ */
+class VerifyRecaptchaController extends Controller
+{
+ protected $allowedFields = [
+ 'ameliaNonce',
+ 'wpAmeliaNonce',
+ 'secret',
+ 'token'
+ ];
+
+ /**
+ * @param Request $request
+ * @param $args
+ *
+ * @return VerifyRecaptchaCommand
+ */
+ protected function instantiateCommand(Request $request, $args)
+ {
+ $command = new VerifyRecaptchaCommand($args);
+ $requestBody = $request->getParsedBody();
+
+ if (empty($requestBody)) {
+ $json = json_decode(file_get_contents('php://input'), true);
+ if (is_array($json)) {
+ $requestBody = $json;
+ }
+ }
+
+ $this->setCommandFields($command, $requestBody);
+
+ return $command;
+ }
+}
--- a/ameliabooking/src/Application/Services/Booking/EventApplicationService.php
+++ b/ameliabooking/src/Application/Services/Booking/EventApplicationService.php
@@ -1583,6 +1583,101 @@
!empty($criteria['sort']) ? $criteria['sort'] : null
);
+ if (!empty($criteria['fetchOccupancy'])) {
+ $spotsEventsIds = [];
+
+ $ticketsIds = [];
+
+ /** @var Event $event */
+ foreach ($events->getItems() as $event) {
+ if ($event->getCustomPricing() && $event->getCustomPricing()->getValue()) {
+ $ticketsIds[] = $event->getId()->getValue();
+ } else {
+ $spotsEventsIds[] = $event->getId()->getValue();
+ }
+ }
+
+ $spots = $spotsEventsIds ? $eventRepository->getEventsSpotsCount($spotsEventsIds) : [];
+
+ foreach ($spots as $eventId => $spotsData) {
+ if ($events->keyExists($eventId)) {
+ /** @var Event $event */
+ $event = $events->getItem($eventId);
+
+ $event->setSpotsSold(
+ new IntegerValue(
+ (!empty($spotsData[BookingStatus::APPROVED]) ? $spotsData[BookingStatus::APPROVED] : 0) +
+ (!empty($spotsData[BookingStatus::PENDING]) ? $spotsData[BookingStatus::PENDING] : 0)
+ )
+ );
+
+ $event->setSpotsWaiting(
+ new IntegerValue(
+ !empty($spotsData[BookingStatus::WAITING]) ? $spotsData[BookingStatus::WAITING] : 0
+ )
+ );
+ }
+ }
+
+ $tickets = $ticketsIds ? $eventRepository->getEventsTicketsCount($ticketsIds) : [];
+
+ foreach ($tickets as $eventId => $ticketsData) {
+ if ($events->keyExists($eventId)) {
+ /** @var Event $event */
+ $event = $events->getItem($eventId);
+
+ foreach ($ticketsData as $ticketId => $ticketData) {
+ if ($event->getCustomTickets()->keyExists($ticketId)) {
+ /** @var EventTicket $ticket */
+ $ticket = $event->getCustomTickets()->getItem($ticketId);
+
+ $ticket->setSold(
+ new IntegerValue(
+ (!empty($ticketData[BookingStatus::APPROVED]) ? $ticketData[BookingStatus::APPROVED] : 0) +
+ (!empty($ticketData[BookingStatus::PENDING]) ? $ticketData[BookingStatus::PENDING] : 0)
+ )
+ );
+
+ $ticket->setWaiting(
+ new IntegerValue(
+ !empty($ticketData[BookingStatus::WAITING]) ? $ticketData[BookingStatus::WAITING] : 0
+ )
+ );
+ }
+ }
+ }
+ }
+
+ $statuses = $spotsEventsIds || $ticketsIds
+ ? $eventRepository->getEventsBookingsStatusesCount(array_merge($spotsEventsIds, $ticketsIds))
+ : [];
+
+ foreach ($statuses as $eventId => $statusesData) {
+ if ($events->keyExists($eventId)) {
+ /** @var Event $event */
+ $event = $events->getItem($eventId);
+
+ $event->setBookingsApproved(
+ new IntegerValue(
+ (!empty($statusesData[BookingStatus::APPROVED]) ? $statusesData[BookingStatus::APPROVED] : 0)
+ )
+ );
+
+ $event->setBookingsPending(
+ new IntegerValue(
+ (!empty($statusesData[BookingStatus::PENDING]) ? $statusesData[BookingStatus::PENDING] : 0)
+ )
+ );
+
+ $event->setBookingsWaiting(
+ new IntegerValue(
+ (!empty($statusesData[BookingStatus::WAITING]) ? $statusesData[BookingStatus::WAITING] : 0)
+ )
+ );
+ }
+ }
+ }
+
/** @var Collection $eventsBookings */
$eventsBookings = $events->length() && !empty($criteria['fetchBookings']) ? $eventRepository->getBookingsByCriteria(
[
@@ -1677,6 +1772,8 @@
$criteria['fetchEventsOrganizer'] : false,
'fetchEventsLocation' => !empty($criteria['fetchEventsLocation']) ?
$criteria['fetchEventsLocation'] : false,
+ 'fetchOccupancy' => !empty($criteria['fetchOccupancy']) ?
+ $criteria['fetchOccupancy'] : false,
]
);
@@ -1747,8 +1844,9 @@
/**
* @param Event $event
- *
+ * @param bool $isFrontEnd
* @return array
+ * @throws InvalidArgumentException
*/
public function getEventInfo($event, $isFrontEnd = false)
{
@@ -1779,13 +1877,15 @@
$minimumReached = null;
if ($event->getCloseAfterMin() !== null && $event->getCloseAfterMinBookings() !== null) {
if ($event->getCloseAfterMinBookings()->getValue()) {
- $approvedBookings = array_filter(
- $event->getBookings()->toArray(),
- function ($value) {
- return $value['status'] === 'approved';
- }
- );
- $minimumReached = count($approvedBookings) >= $event->getCloseAfterMin()->getValue();
+ $approvedBookings = !$event->getBookings()->length() && $event->getBookingsApproved()
+ ? $event->getBookingsApproved()->getValue()
+ : count(array_filter(
+ $event->getBookings()->toArray(),
+ function ($value) {
+ return $value['status'] === 'approved';
+ }
+ ));
+ $minimumReached = $approvedBookings >= $event->getCloseAfterMin()->getValue();
} else {
$minimumReached = $persons['booked'] >= $event->getCloseAfterMin()->getValue();
}
@@ -1795,6 +1895,12 @@
$eventSettings = $event->getSettings() ? json_decode($event->getSettings()->getValue(), true) : null;
if ($eventSettings && !empty($eventSettings['waitingList']) && $eventSettings['waitingList']['enabled']) {
+ $peopleWaiting =
+ !$event->getBookings()->length() &&
+ $event->getBookingsWaiting() &&
+ $event->getBookingsWaiting()->getValue();
+
+ /** @var CustomerBooking $booking */
foreach ($event->getBookings()->getItems() as $booking) {
if ($booking->getStatus()->getValue() === BookingStatus::WAITING) {
$peopleWaiting = true;
@@ -1902,6 +2008,15 @@
$waiting = 0;
if ($event->getCustomPricing()->getValue()) {
+ if ($event->getBookings()->length()) {
+ /** @var EventTicket $ticket */
+ foreach ($event->getCustomTickets()->getItems() as $ticket) {
+ $ticket->setSold(new IntegerValue(0));
+
+ $ticket->setWaiting(new IntegerValue(0));
+ }
+ }
+
/** @var CustomerBooking $booking */
foreach ($event->getBookings()->getItems() as $booking) {
/** @var CustomerBookingEventTicket $bookedTicket */
@@ -1943,6 +2058,12 @@
$event->setMaxCapacity($event->getMaxCustomCapacity() ?: new IntegerValue($maxCapacity));
} else {
+ if (!$event->getBookings()->length()) {
+ $persons = $event->getSpotsSold() ? $event->getSpotsSold()->getValue() : 0;
+
+ $waiting = $event->getSpotsWaiting() ? $event->getSpotsWaiting()->getValue() : 0;
+ }
+
/** @var CustomerBooking $booking */
foreach ($event->getBookings()->getItems() as $booking) {
if ($booking->getStatus()->getValue() === BookingStatus::APPROVED || $booking->getStatus()->getValue() === BookingStatus::PENDING) {
--- a/ameliabooking/src/Application/Services/Location/CurrentLocation.php
+++ b/ameliabooking/src/Application/Services/Location/CurrentLocation.php
@@ -36,7 +36,6 @@
curl_setopt($curlHandle, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curlHandle, CURLOPT_USERAGENT, 'Amelia');
$result = json_decode(curl_exec($curlHandle));
- curl_close($curlHandle);
return !isset($result->country_code) ? '' : strtolower($result->country_code);
} catch (Exception $e) {
--- a/ameliabooking/src/Application/Services/Notif