653 lines
23 KiB
PHP
653 lines
23 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Service;
|
|
|
|
use App\BusProNet\Constants;
|
|
use App\BusProNet\Model\Room;
|
|
use App\BusProNet\Model\Service;
|
|
use App\BusProNet\Model\Travel;
|
|
use App\BusProNet\Service\BookingStatusRuleRegistry;
|
|
use App\BusProNet\XmlLoader\AgencyLoader;
|
|
use App\Exception\NoRoomsAvailableException;
|
|
use App\Form\Model\BookingDto;
|
|
use App\Form\Model\ParticipantDto;
|
|
use App\Form\Model\RoomSelectionDto;
|
|
use App\Form\Service\ServiceAgeEvaluator;
|
|
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
|
use Symfony\Component\HttpFoundation\Request;
|
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
|
|
|
class BookingConfigurator
|
|
{
|
|
public function __construct(
|
|
private readonly BookingSessionManager $bookingSessionService,
|
|
private readonly TravelDataProvider $travelDataService,
|
|
private readonly ParticipantEligibilityChecker $participantEligibilityService,
|
|
private readonly BookingStatusRuleRegistry $bookingStatusRuleRegistry,
|
|
private readonly AgencyLoader $agencyLoader,
|
|
#[Autowire(param: 'default_booking_status')]
|
|
private readonly string $defaultBookingStatus,
|
|
) {
|
|
}
|
|
|
|
/**
|
|
* Creates a fresh booking session with the provided travel parameters.
|
|
*
|
|
* This method initializes a new BookingDto with empty room selections
|
|
* and saves it to the session. It's designed to be called from the clean
|
|
* booking entry point without requiring UID parameters.
|
|
*
|
|
* Handles three booking status types:
|
|
* - 'Frei': Regular booking with availability checks
|
|
* - 'Option': Create-flow override from specific rules
|
|
* - 'Anfrage': Inquiry booking, allows booking even with 0 availability
|
|
*/
|
|
public function startFreshBooking(Request $request, int $dateId, int $hotelId, ?int $agencyId = null): BookingDto
|
|
{
|
|
$travelData = $this->travelDataService->getTravelData($dateId, $hotelId);
|
|
if (null === $travelData) {
|
|
throw new NotFoundHttpException(sprintf('Travel data not found for date ID %d and hotel ID %d', $dateId, $hotelId));
|
|
}
|
|
|
|
// Fetch and patch availability data (includes allowedBookingStatus from API)
|
|
// Force refresh ensures fresh data at booking start, then populates cache for subsequent loads
|
|
$availabilities = $this->travelDataService->getAvailabilityData($dateId, cached: true, forceRefresh: true);
|
|
if (null !== $availabilities) {
|
|
$this->travelDataService->patchAvailabilities($travelData, $availabilities);
|
|
}
|
|
|
|
// Get bookable rooms (Frei or Anfrage with available > 0)
|
|
$availableRooms = $travelData->getAvailableRooms();
|
|
|
|
// No bookable rooms means booking is not possible
|
|
if ([] === $availableRooms) {
|
|
throw new NoRoomsAvailableException($dateId, $hotelId);
|
|
}
|
|
|
|
// Determine initial booking status based on room availability
|
|
// This is for early UI decisions (e.g., voucher visibility), final verdict is in step 3
|
|
$bookingStatus = $this->determineInitialBookingStatus($travelData);
|
|
|
|
// Create room selections with zero quantities (user will set these in step 1)
|
|
$roomSelections = array_map(
|
|
fn (Room $room) => $this->createRoomSelection($room, []),
|
|
$availableRooms
|
|
);
|
|
|
|
$bookingCreateDto = new BookingDto($travelData, $hotelId);
|
|
$bookingCreateDto->roomSelections = $roomSelections;
|
|
$bookingCreateDto->currentStep = 1;
|
|
$bookingCreateDto->agencyId = $agencyId;
|
|
$bookingCreateDto->agencyCode = null !== $agencyId
|
|
? $this->agencyLoader->loadById($agencyId)?->code
|
|
: null;
|
|
$bookingCreateDto->bookingStatus = $bookingStatus;
|
|
$this->applyCreateBookingStatusRules($bookingCreateDto);
|
|
|
|
$this->bookingSessionService->saveBookingDto($request, $bookingCreateDto, BookingDto::MODE_CREATE);
|
|
|
|
return $bookingCreateDto;
|
|
}
|
|
|
|
/**
|
|
* Creates a room selection DTO from room data and quantities.
|
|
*
|
|
* Converts a Room model into a RoomSelectionDto with the specified quantity
|
|
* selection. Used during booking initialization to create selectable room options.
|
|
*
|
|
* @param Room $room The room model to convert
|
|
* @param array<int|string, int> $roomsIdsAndQuantities Array of room ID to quantity mappings
|
|
*
|
|
* @return RoomSelectionDto The room selection DTO
|
|
*/
|
|
private function createRoomSelection(Room $room, array $roomsIdsAndQuantities): RoomSelectionDto
|
|
{
|
|
$selection = new RoomSelectionDto();
|
|
$selection->id = $room->id;
|
|
$selection->label = $room->label;
|
|
$selection->price = $room->price;
|
|
$selection->status = $room->status;
|
|
$selection->maxQuantity = $room->available;
|
|
$selection->capacity = $room->minPax ?? 1;
|
|
$selection->quantity = $roomsIdsAndQuantities[$room->id] ?? 0;
|
|
|
|
return $selection;
|
|
}
|
|
|
|
/**
|
|
* Pre-selects default services for all participants.
|
|
*
|
|
* Mandatory and auto-book rules are handled in dedicated methods:
|
|
* mandatory first, auto-book second.
|
|
*/
|
|
public function preselectDefaultServices(BookingDto $bookingDto): void
|
|
{
|
|
$additionalServices = $bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_ADDITIONAL);
|
|
$mandatoryAdditionalServices = array_filter(
|
|
$additionalServices,
|
|
static fn (Service $service): bool => true === $service->mandatory
|
|
);
|
|
$autoBookAdditionalServices = array_filter(
|
|
$additionalServices,
|
|
// Services that are both mandatory and auto-book belong to mandatory bucket only.
|
|
static fn (Service $service): bool => true === $service->autoBook && false === $service->mandatory
|
|
);
|
|
|
|
$skiPassServices = $bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_SKI_PASS, true);
|
|
$mandatorySkiPassServices = array_filter(
|
|
$skiPassServices,
|
|
static fn (Service $service): bool => true === $service->mandatory
|
|
);
|
|
$autoBookSkiPassServices = array_filter(
|
|
$skiPassServices,
|
|
// Services that are both mandatory and auto-book belong to mandatory bucket only.
|
|
static fn (Service $service): bool => true === $service->autoBook && false === $service->mandatory
|
|
);
|
|
|
|
$boardServices = $bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_BOARD, true);
|
|
$mandatoryBoardServices = array_filter(
|
|
$boardServices,
|
|
static fn (Service $service): bool => true === $service->mandatory
|
|
);
|
|
$autoBookBoardServices = array_filter(
|
|
$boardServices,
|
|
// Services that are both mandatory and auto-book belong to mandatory bucket only.
|
|
static fn (Service $service): bool => true === $service->autoBook && false === $service->mandatory
|
|
);
|
|
|
|
$rentalServices = $bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_RENTALS, true);
|
|
$mandatoryRentalServices = array_filter(
|
|
$rentalServices,
|
|
static fn (Service $service): bool => true === $service->mandatory
|
|
);
|
|
$autoBookRentalServices = array_filter(
|
|
$rentalServices,
|
|
// Services that are both mandatory and auto-book belong to mandatory bucket only.
|
|
static fn (Service $service): bool => true === $service->autoBook && false === $service->mandatory
|
|
);
|
|
|
|
$ageEvaluator = new ServiceAgeEvaluator();
|
|
|
|
foreach ($bookingDto->participants as $participantIndex => $participant) {
|
|
if (false === $this->canPreselectServicesForParticipant($bookingDto, $participantIndex, $participant)) {
|
|
continue;
|
|
}
|
|
|
|
$this->preselectMandatoryAdditionalServices(
|
|
$participant,
|
|
$mandatoryAdditionalServices,
|
|
$bookingDto,
|
|
$participantIndex,
|
|
$ageEvaluator
|
|
);
|
|
$this->preselectAutoBookAdditionalServices(
|
|
$participant,
|
|
$autoBookAdditionalServices,
|
|
$bookingDto,
|
|
$participantIndex,
|
|
$ageEvaluator
|
|
);
|
|
$this->preselectMandatorySkiPass(
|
|
$participant,
|
|
$mandatorySkiPassServices,
|
|
$bookingDto,
|
|
$participantIndex,
|
|
$ageEvaluator
|
|
);
|
|
$this->preselectAutoBookSkiPass(
|
|
$participant,
|
|
$autoBookSkiPassServices,
|
|
$bookingDto,
|
|
$participantIndex,
|
|
$ageEvaluator
|
|
);
|
|
$this->preselectMandatoryBoardServices(
|
|
$participant,
|
|
$mandatoryBoardServices,
|
|
$bookingDto,
|
|
$participantIndex,
|
|
$ageEvaluator
|
|
);
|
|
$this->preselectAutoBookBoardServices(
|
|
$participant,
|
|
$autoBookBoardServices,
|
|
$bookingDto,
|
|
$participantIndex,
|
|
$ageEvaluator
|
|
);
|
|
$this->preselectMandatoryRentals(
|
|
$participant,
|
|
$mandatoryRentalServices,
|
|
$bookingDto,
|
|
$participantIndex,
|
|
$ageEvaluator
|
|
);
|
|
$this->preselectAutoBookRentals(
|
|
$participant,
|
|
$autoBookRentalServices,
|
|
$bookingDto,
|
|
$participantIndex,
|
|
$ageEvaluator
|
|
);
|
|
}
|
|
}
|
|
|
|
private function canPreselectServicesForParticipant(
|
|
BookingDto $bookingDto,
|
|
int $participantIndex,
|
|
ParticipantDto $participant,
|
|
): bool {
|
|
if (null === $participant->dateOfBirth) {
|
|
return false;
|
|
}
|
|
|
|
$age = $participant->getAge($bookingDto->travel->dateFrom);
|
|
if (null !== $age && $age <= Constants::BABY_MAX_AGE) {
|
|
return false;
|
|
}
|
|
|
|
return $this->participantEligibilityService->isParticipantEligible($bookingDto, $participantIndex);
|
|
}
|
|
|
|
/** @param array<int, Service> $mandatoryAdditionalServices */
|
|
private function preselectMandatoryAdditionalServices(
|
|
ParticipantDto $participant,
|
|
array $mandatoryAdditionalServices,
|
|
BookingDto $bookingDto,
|
|
int $participantIndex,
|
|
ServiceAgeEvaluator $ageEvaluator,
|
|
): void {
|
|
$eligibleServices = $this->getEligibleServicesForParticipant(
|
|
$mandatoryAdditionalServices,
|
|
$bookingDto,
|
|
$participantIndex,
|
|
$ageEvaluator
|
|
);
|
|
|
|
$this->appendAdditionalServices($participant, $eligibleServices, false);
|
|
}
|
|
|
|
/** @param array<int, Service> $autoBookAdditionalServices */
|
|
private function preselectAutoBookAdditionalServices(
|
|
ParticipantDto $participant,
|
|
array $autoBookAdditionalServices,
|
|
BookingDto $bookingDto,
|
|
int $participantIndex,
|
|
ServiceAgeEvaluator $ageEvaluator,
|
|
): void {
|
|
$eligibleServices = $this->getEligibleServicesForParticipant(
|
|
$autoBookAdditionalServices,
|
|
$bookingDto,
|
|
$participantIndex,
|
|
$ageEvaluator
|
|
);
|
|
|
|
$this->appendAdditionalServices($participant, $eligibleServices, true);
|
|
}
|
|
|
|
/** @param array<int, Service> $mandatorySkiPassServices */
|
|
private function preselectMandatorySkiPass(
|
|
ParticipantDto $participant,
|
|
array $mandatorySkiPassServices,
|
|
BookingDto $bookingDto,
|
|
int $participantIndex,
|
|
ServiceAgeEvaluator $ageEvaluator,
|
|
): void {
|
|
if (null !== $participant->skiPass) {
|
|
return;
|
|
}
|
|
|
|
$eligibleServices = $this->getEligibleServicesForParticipant(
|
|
$mandatorySkiPassServices,
|
|
$bookingDto,
|
|
$participantIndex,
|
|
$ageEvaluator
|
|
);
|
|
|
|
foreach ($eligibleServices as $service) {
|
|
$participant->skiPass = $service;
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
/** @param array<int, Service> $autoBookSkiPassServices */
|
|
private function preselectAutoBookSkiPass(
|
|
ParticipantDto $participant,
|
|
array $autoBookSkiPassServices,
|
|
BookingDto $bookingDto,
|
|
int $participantIndex,
|
|
ServiceAgeEvaluator $ageEvaluator,
|
|
): void {
|
|
if (null !== $participant->skiPass) {
|
|
return;
|
|
}
|
|
|
|
$eligibleServices = $this->getEligibleServicesForParticipant(
|
|
$autoBookSkiPassServices,
|
|
$bookingDto,
|
|
$participantIndex,
|
|
$ageEvaluator
|
|
);
|
|
|
|
foreach ($eligibleServices as $service) {
|
|
if (null !== $service->id
|
|
&& true === in_array($service->id, $participant->autoBookOptOutSkiPassIds, true)) {
|
|
continue;
|
|
}
|
|
|
|
$participant->skiPass = $service;
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
/** @param array<int, Service> $mandatoryBoardServices */
|
|
private function preselectMandatoryBoardServices(
|
|
ParticipantDto $participant,
|
|
array $mandatoryBoardServices,
|
|
BookingDto $bookingDto,
|
|
int $participantIndex,
|
|
ServiceAgeEvaluator $ageEvaluator,
|
|
): void {
|
|
$eligibleServices = $this->getEligibleServicesForParticipant(
|
|
$mandatoryBoardServices,
|
|
$bookingDto,
|
|
$participantIndex,
|
|
$ageEvaluator
|
|
);
|
|
|
|
$this->appendBoardServices($participant, $eligibleServices, false);
|
|
}
|
|
|
|
/** @param array<int, Service> $autoBookBoardServices */
|
|
private function preselectAutoBookBoardServices(
|
|
ParticipantDto $participant,
|
|
array $autoBookBoardServices,
|
|
BookingDto $bookingDto,
|
|
int $participantIndex,
|
|
ServiceAgeEvaluator $ageEvaluator,
|
|
): void {
|
|
$eligibleServices = $this->getEligibleServicesForParticipant(
|
|
$autoBookBoardServices,
|
|
$bookingDto,
|
|
$participantIndex,
|
|
$ageEvaluator
|
|
);
|
|
|
|
$this->appendBoardServices($participant, $eligibleServices, true);
|
|
}
|
|
|
|
/** @param array<int, Service> $mandatoryRentalServices */
|
|
private function preselectMandatoryRentals(
|
|
ParticipantDto $participant,
|
|
array $mandatoryRentalServices,
|
|
BookingDto $bookingDto,
|
|
int $participantIndex,
|
|
ServiceAgeEvaluator $ageEvaluator,
|
|
): void {
|
|
if (null === $participant->skiPass) {
|
|
return;
|
|
}
|
|
|
|
$eligibleServices = $this->getEligibleServicesForParticipant(
|
|
$mandatoryRentalServices,
|
|
$bookingDto,
|
|
$participantIndex,
|
|
$ageEvaluator
|
|
);
|
|
|
|
$matchingDurationServices = $this->getRentalsMatchingSkiPassDuration($eligibleServices, $participant);
|
|
|
|
$this->appendRentalServices($participant, $matchingDurationServices, false);
|
|
}
|
|
|
|
/** @param array<int, Service> $autoBookRentalServices */
|
|
private function preselectAutoBookRentals(
|
|
ParticipantDto $participant,
|
|
array $autoBookRentalServices,
|
|
BookingDto $bookingDto,
|
|
int $participantIndex,
|
|
ServiceAgeEvaluator $ageEvaluator,
|
|
): void {
|
|
if (null === $participant->skiPass) {
|
|
return;
|
|
}
|
|
|
|
$eligibleServices = $this->getEligibleServicesForParticipant(
|
|
$autoBookRentalServices,
|
|
$bookingDto,
|
|
$participantIndex,
|
|
$ageEvaluator
|
|
);
|
|
|
|
$matchingDurationServices = $this->getRentalsMatchingSkiPassDuration($eligibleServices, $participant);
|
|
|
|
$this->appendRentalServices($participant, $matchingDurationServices, true);
|
|
}
|
|
|
|
/**
|
|
* @param Service[] $services
|
|
*
|
|
* @return Service[]
|
|
*/
|
|
private function getEligibleServicesForParticipant(
|
|
array $services,
|
|
BookingDto $bookingDto,
|
|
int $participantIndex,
|
|
ServiceAgeEvaluator $ageEvaluator,
|
|
): array {
|
|
return array_filter(
|
|
$services,
|
|
fn (Service $service): bool => $this->isServiceAvailableForParticipant(
|
|
$service,
|
|
$bookingDto,
|
|
$participantIndex,
|
|
$ageEvaluator
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @param Service[] $services
|
|
*/
|
|
private function appendAdditionalServices(ParticipantDto $participant, array $services, bool $respectOptOut): void
|
|
{
|
|
$currentSelections = $participant->additionalServices;
|
|
$currentServiceIds = array_map(static fn (Service $service): ?int => $service->id, $currentSelections);
|
|
|
|
foreach ($services as $service) {
|
|
if (null === $service->id || true === in_array($service->id, $currentServiceIds, true)) {
|
|
continue;
|
|
}
|
|
|
|
if (true === $respectOptOut
|
|
&& true === in_array($service->id, $participant->autoBookOptOutServiceIds, true)) {
|
|
continue;
|
|
}
|
|
|
|
$currentSelections[] = $service;
|
|
}
|
|
|
|
$participant->additionalServices = $currentSelections;
|
|
}
|
|
|
|
/**
|
|
* @param Service[] $services
|
|
*/
|
|
private function appendBoardServices(ParticipantDto $participant, array $services, bool $respectOptOut): void
|
|
{
|
|
$currentSelections = $participant->board;
|
|
$currentServiceIds = array_map(static fn (Service $service): ?int => $service->id, $currentSelections);
|
|
|
|
foreach ($services as $service) {
|
|
if (null === $service->id || true === in_array($service->id, $currentServiceIds, true)) {
|
|
continue;
|
|
}
|
|
|
|
if (true === $respectOptOut
|
|
&& true === in_array($service->id, $participant->autoBookOptOutBoardIds, true)) {
|
|
continue;
|
|
}
|
|
|
|
$currentSelections[] = $service;
|
|
}
|
|
|
|
$participant->board = $currentSelections;
|
|
}
|
|
|
|
/**
|
|
* @param Service[] $services
|
|
*/
|
|
private function appendRentalServices(ParticipantDto $participant, array $services, bool $respectOptOut): void
|
|
{
|
|
$currentSelections = $participant->rentals;
|
|
$currentServiceIds = array_map(static fn (Service $service): ?int => $service->id, $currentSelections);
|
|
|
|
foreach ($services as $service) {
|
|
if (null === $service->id || true === in_array($service->id, $currentServiceIds, true)) {
|
|
continue;
|
|
}
|
|
|
|
if (true === $respectOptOut
|
|
&& true === in_array($service->id, $participant->autoBookOptOutRentalIds, true)) {
|
|
continue;
|
|
}
|
|
|
|
$currentSelections[] = $service;
|
|
}
|
|
|
|
$participant->rentals = $currentSelections;
|
|
}
|
|
|
|
/**
|
|
* @param Service[] $rentals
|
|
*
|
|
* @return Service[]
|
|
*/
|
|
private function getRentalsMatchingSkiPassDuration(array $rentals, ParticipantDto $participant): array
|
|
{
|
|
$selectedSkiPass = $participant->skiPass;
|
|
if (null === $selectedSkiPass || null === $selectedSkiPass->dateFrom || null === $selectedSkiPass->dateTo) {
|
|
return [];
|
|
}
|
|
|
|
return array_filter($rentals, static function (Service $rental) use ($selectedSkiPass): bool {
|
|
if (null === $rental->dateFrom || null === $rental->dateTo) {
|
|
return false;
|
|
}
|
|
|
|
return $rental->dateFrom == $selectedSkiPass->dateFrom
|
|
&& $rental->dateTo == $selectedSkiPass->dateTo;
|
|
});
|
|
}
|
|
|
|
private function isServiceAvailableForParticipant(
|
|
Service $service,
|
|
BookingDto $bookingDto,
|
|
int $participantIndex,
|
|
ServiceAgeEvaluator $ageEvaluator,
|
|
): bool {
|
|
if (false === $ageEvaluator->canEvaluate($service)) {
|
|
return true;
|
|
}
|
|
|
|
return $ageEvaluator->isServiceAvailableForParticipant($service, $bookingDto, $participantIndex);
|
|
}
|
|
|
|
/**
|
|
* Determines the initial booking status based on travel configuration and API restrictions.
|
|
*
|
|
* This method implements a multi-stage check to determine the appropriate booking status:
|
|
* 1. Checks API restrictions via buchungstatusmoeglich attribute
|
|
* 2. Checks if only inquiry rooms are available (no Frei rooms with available > 0)
|
|
*
|
|
* When API provides allowed status restrictions, the method respects them by selecting
|
|
* the best available status in order of preference: configured default → 'F' → 'O' → 'A'.
|
|
*
|
|
* The default status is configured via DEFAULT_BOOKING_STATUS env variable.
|
|
* Use 'O' (Option) during beta for agency confirmation, 'F' (Final) for production.
|
|
*
|
|
* @param Travel $travelData The travel data to evaluate
|
|
*
|
|
* @return string The appropriate booking status code ('F', 'O', or 'A')
|
|
*/
|
|
private function determineInitialBookingStatus(Travel $travelData): string
|
|
{
|
|
// Check 1: Only inquiry rooms available (all rooms with available > 0 have status 'Anfrage')
|
|
// This takes precedence as it's a business rule independent of API restrictions
|
|
if ($travelData->requiresInquiryBooking()) {
|
|
return Constants::BOOKING_STATUS_INQUIRY;
|
|
}
|
|
|
|
// Check 2: If API provided allowed status restrictions, respect them
|
|
if ([] !== $travelData->allowedBookingStatus) {
|
|
// Prefer configured default status if allowed
|
|
if ($travelData->isBookingStatusAllowed($this->defaultBookingStatus)) {
|
|
return $this->defaultBookingStatus;
|
|
}
|
|
|
|
// Fall back to allowed statuses in order of preference: F → O(option) → A
|
|
if ($travelData->isBookingStatusAllowed(Constants::BOOKING_STATUS_FREE)) {
|
|
return Constants::BOOKING_STATUS_FREE;
|
|
}
|
|
|
|
if ($travelData->isBookingStatusAllowed(Constants::BOOKING_STATUS_OPTION)) {
|
|
return Constants::BOOKING_STATUS_OPTION;
|
|
}
|
|
|
|
if ($travelData->isBookingStatusAllowed(Constants::BOOKING_STATUS_INQUIRY)) {
|
|
return Constants::BOOKING_STATUS_INQUIRY;
|
|
}
|
|
}
|
|
|
|
return $this->defaultBookingStatus;
|
|
}
|
|
|
|
/**
|
|
* Updates booking status based on selected room requirements.
|
|
*
|
|
* Checks if any selected room has inquiry-only status. If so, forces
|
|
* the entire booking to inquiry mode. This override happens after room
|
|
* selection in Step 1 and respects the business rule: if ANY room requires
|
|
* inquiry, the whole booking becomes an inquiry.
|
|
*
|
|
* @param BookingDto $bookingDto The booking DTO to update
|
|
*/
|
|
public function updateBookingStatusFromRoomSelection(BookingDto $bookingDto): void
|
|
{
|
|
// Skip if already inquiry - no need to check
|
|
if ('A' === $bookingDto->bookingStatus) {
|
|
return;
|
|
}
|
|
|
|
// Check selected rooms for inquiry-only status
|
|
foreach ($bookingDto->getSelectedRooms() as $roomSelection) {
|
|
$room = $bookingDto->travel->getRoomById($roomSelection->id);
|
|
if ($room
|
|
&& Constants::STATUS_ON_REQUEST === $room->status
|
|
&& $room->available > 0) {
|
|
$bookingDto->bookingStatus = 'A';
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Applies booking-level status rules in create flow.
|
|
*
|
|
* Inquiry bookings always win and are never overridden.
|
|
*/
|
|
public function applyCreateBookingStatusRules(BookingDto $bookingDto): void
|
|
{
|
|
if (Constants::BOOKING_STATUS_INQUIRY === $bookingDto->bookingStatus) {
|
|
return;
|
|
}
|
|
|
|
$bookingDto->bookingStatus = $this->bookingStatusRuleRegistry->evaluateStatus($bookingDto);
|
|
}
|
|
}
|