wip: group inquiries and booking
This commit is contained in:
1 parent
18a890e50e
commit
e7bfb19ac9
71 files changed
+2731
-512
No files matched your search
@@ -22,6 +22,8 @@ use Psr\Log\LoggerInterface;
|
||||
|
||||
class AccommodationBookingService
|
||||
{
|
||||
private const int PRICING_VERSION = 1;
|
||||
|
||||
public function __construct(
|
||||
private readonly AccommodationRepository $accommodationRepo,
|
||||
private readonly AccommodationPriceRepository $priceRepo,
|
||||
@@ -99,9 +101,12 @@ class AccommodationBookingService
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches hotel name, image, and address from the CMS for display in the sidebar.
|
||||
* Fetches hotel details from the CMS for display in the booking flow — name, images,
|
||||
* address, descriptive text blocks, amenity icons, and the surrounding region's info
|
||||
* (name, coordinates, webcam, ski area text, stats, images).
|
||||
*
|
||||
* @return array<string, mixed>|null null on CMS error or missing code
|
||||
* @return array<string, mixed>|null null on CMS error or missing code, see
|
||||
* {@see CmsDataProvider::getHotelDetails()} for the shape
|
||||
*/
|
||||
public function loadHotelCmsData(Accommodation $accommodation): ?array
|
||||
{
|
||||
@@ -187,7 +192,7 @@ class AccommodationBookingService
|
||||
|
||||
$candidates = array_values(array_filter(
|
||||
$prices,
|
||||
fn(AccommodationPrice $p) => $p->getDateFrom() <= $firstDay && $p->getDateTo() >= $firstDay,
|
||||
fn (AccommodationPrice $p) => $p->getDateFrom() <= $firstDay && $p->getDateTo() >= $firstDay,
|
||||
));
|
||||
|
||||
$winner = $this->priceTimelineBuilder->resolveWinner($candidates);
|
||||
@@ -224,14 +229,14 @@ class AccommodationBookingService
|
||||
* Board and additional services are stored as frozen snapshots — independent of
|
||||
* the catalog entities so that future catalog edits do not affect existing bookings.
|
||||
*
|
||||
* @param AccommodationPrice[] $prices
|
||||
* @param AccommodationPrice[] $prices
|
||||
* @param array{additionalServices: AdditionalService[], boardServices: mixed[]} $services
|
||||
*/
|
||||
public function persist(
|
||||
AccommodationBookingDto $dto,
|
||||
Accommodation $accommodation,
|
||||
array $prices,
|
||||
array $services,
|
||||
Accommodation $accommodation,
|
||||
array $prices,
|
||||
array $services,
|
||||
): AccommodationBooking {
|
||||
$booking = new AccommodationBooking();
|
||||
$booking->setAccommodation($accommodation);
|
||||
@@ -281,20 +286,72 @@ class AccommodationBookingService
|
||||
$booking->setCity($dto->city);
|
||||
$booking->setRemarks($dto->remarks);
|
||||
|
||||
$this->refreshPriceSnapshot($booking);
|
||||
|
||||
$this->entityManager->persist($booking);
|
||||
$this->entityManager->flush();
|
||||
|
||||
return $booking;
|
||||
}
|
||||
|
||||
/** @param array<string, mixed> $priceBreakdown */
|
||||
public function sendNotificationEmail(AccommodationBooking $booking, array $priceBreakdown = []): void
|
||||
/**
|
||||
* Persists the booking and sends the notification/confirmation emails in one go.
|
||||
*
|
||||
* @param AccommodationPrice[] $prices
|
||||
* @param array{additionalServices: AdditionalService[], boardServices: mixed[]} $services
|
||||
*/
|
||||
public function finalizeBooking(
|
||||
AccommodationBookingDto $dto,
|
||||
Accommodation $accommodation,
|
||||
array $prices,
|
||||
array $services,
|
||||
): AccommodationBooking {
|
||||
$booking = $this->persist($dto, $accommodation, $prices, $services);
|
||||
$this->issueAccessLinkForDirectBooking($booking);
|
||||
$this->sendNotificationEmail($booking);
|
||||
$this->sendCustomerConfirmationEmail($booking);
|
||||
|
||||
return $booking;
|
||||
}
|
||||
|
||||
public function refreshPriceSnapshot(AccommodationBooking $booking): void
|
||||
{
|
||||
$breakdown = $this->breakdownCalculator->computeCurrent($booking);
|
||||
if (null === $breakdown) {
|
||||
$booking->clearPriceSnapshot();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$accommodationBase = (int) ($breakdown['basePrice'] ?? 0) + (int) ($breakdown['additionalPersonsPrice'] ?? 0);
|
||||
$boardBase = (int) ($breakdown['boardPrice'] ?? 0);
|
||||
$servicesBase = (int) ($breakdown['servicesPrice'] ?? 0);
|
||||
|
||||
$total = (int) ($breakdown['total'] ?? 0)
|
||||
- $this->discountAmount($accommodationBase, $booking->getAccommodationDiscount())
|
||||
- $this->discountAmount($boardBase, $booking->getBoardServiceDiscount())
|
||||
- $this->discountAmount($servicesBase, $booking->getAdditionalServicesDiscount());
|
||||
|
||||
$booking->setPriceSnapshot(
|
||||
$breakdown,
|
||||
$total,
|
||||
(string) ($breakdown['currency'] ?? $booking->getAccommodation()?->getCurrency() ?? 'EUR'),
|
||||
self::PRICING_VERSION,
|
||||
);
|
||||
}
|
||||
|
||||
private function discountAmount(int $base, ?int $percent): int
|
||||
{
|
||||
return null !== $percent ? (int) round($base * $percent / 100) : 0;
|
||||
}
|
||||
|
||||
public function sendNotificationEmail(AccommodationBooking $booking): void
|
||||
{
|
||||
try {
|
||||
$this->mailer->createAndSendEmail(
|
||||
[
|
||||
'booking' => $booking,
|
||||
'priceBreakdown' => $priceBreakdown,
|
||||
'priceBreakdown' => $this->breakdownCalculator->compute($booking) ?? [],
|
||||
'accessLink' => $this->accessLinkOrNull($booking),
|
||||
],
|
||||
[
|
||||
@@ -362,15 +419,14 @@ class AccommodationBookingService
|
||||
}
|
||||
|
||||
/**
|
||||
* Explicit admin action: (re)issues the access link — invalidating any previously issued
|
||||
* link for this booking — and sends the customer confirmation email, now including it.
|
||||
* Explicit admin action: (re)issues the access link, invalidating any previously issued
|
||||
* link for this booking. No email side effect — sending is a separate, explicit admin
|
||||
* action via sendCustomerConfirmationEmail().
|
||||
*/
|
||||
public function regenerateAccessLinkAndNotifyCustomer(AccommodationBooking $booking): void
|
||||
public function regenerateAccessLink(AccommodationBooking $booking): void
|
||||
{
|
||||
$booking->setAccessLinkIssuedAt(new \DateTimeImmutable());
|
||||
$this->entityManager->flush();
|
||||
|
||||
$this->sendCustomerConfirmationEmail($booking);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -421,7 +477,7 @@ class AccommodationBookingService
|
||||
$prices = $this->priceRepo->findByHotelCodeAndDateRange($hotelCode, $dateFrom, $dateTo);
|
||||
$candidates = array_values(array_filter(
|
||||
$prices,
|
||||
fn(AccommodationPrice $price): bool => $price->getDateFrom() <= $dateFrom && $price->getDateTo() >= $dateFrom,
|
||||
fn (AccommodationPrice $price): bool => $price->getDateFrom() <= $dateFrom && $price->getDateTo() >= $dateFrom,
|
||||
));
|
||||
|
||||
return $this->priceTimelineBuilder->resolveWinner($candidates)?->getIncludedPax() ?? 1;
|
||||
|
||||
Reference in new issue
Block a user