feat: replace *Service suffix with role-based class names
This commit is contained in:
@@ -0,0 +1,644 @@
|
||||
<?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\Service\ServiceAgeEvaluator;
|
||||
use App\Form\Model\RoomSelectionDto;
|
||||
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
class BookingConfigurator
|
||||
{
|
||||
public function __construct(
|
||||
private readonly BookingSessionStore $bookingSessionService,
|
||||
private readonly TravelDataProvider $travelDataService,
|
||||
private readonly ParticipantEligibilityChecker $participantEligibilityService,
|
||||
private readonly BookingStatusRuleRegistry $bookingStatusRuleRegistry,
|
||||
private readonly AgencyLoader $agencyLoader,
|
||||
#[Autowire('%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
|
||||
* - '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->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 $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;
|
||||
$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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 → A
|
||||
if ($travelData->isBookingStatusAllowed(Constants::BOOKING_STATUS_FREE)) {
|
||||
return Constants::BOOKING_STATUS_FREE;
|
||||
}
|
||||
|
||||
if ($travelData->isBookingStatusAllowed(Constants::BOOKING_STATUS_OPEN)) {
|
||||
return Constants::BOOKING_STATUS_OPEN;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user