fix: streamlined discount display in all breakdowns
This commit is contained in:
@@ -17,17 +17,60 @@ class AccommodationBookingBreakdownCalculator
|
||||
|
||||
/**
|
||||
* Returns the authoritative stored snapshot, falling back to current prices only for
|
||||
* bookings created before snapshot persistence was introduced.
|
||||
* bookings created before snapshot persistence was introduced, enriched with the
|
||||
* discount rows and the discounted total for rendering.
|
||||
*
|
||||
* @return array<string, mixed>|null null when no accommodation or dates are set
|
||||
*/
|
||||
public function compute(AccommodationBooking $booking): ?array
|
||||
{
|
||||
if (null !== $booking->getPriceBreakdown()) {
|
||||
return $booking->getPriceBreakdown();
|
||||
$breakdown = $booking->getPriceBreakdown() ?? $this->computeCurrent($booking);
|
||||
|
||||
return null !== $breakdown ? $this->withDiscounts($booking, $breakdown) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the discount rows and the price the customer actually pays. Derived on every read
|
||||
* and never persisted — refreshPriceSnapshot() stores the raw breakdown from
|
||||
* computeCurrent() — so the stored total and this one come out of the same code and
|
||||
* cannot drift apart.
|
||||
*
|
||||
* @param array<string, mixed> $breakdown
|
||||
*
|
||||
* @return array<string, mixed> the breakdown plus `discounts` and `discountedTotal`
|
||||
*/
|
||||
public function withDiscounts(AccommodationBooking $booking, array $breakdown): array
|
||||
{
|
||||
$buckets = [
|
||||
['Unterkunft', $booking->getAccommodationDiscount(), (int) ($breakdown['basePrice'] ?? 0) + (int) ($breakdown['additionalPersonsPrice'] ?? 0)],
|
||||
['Verpflegung', $booking->getBoardServiceDiscount(), (int) ($breakdown['boardPrice'] ?? 0)],
|
||||
['Zusatzleistungen', $booking->getAdditionalServicesDiscount(), (int) ($breakdown['servicesPrice'] ?? 0)],
|
||||
];
|
||||
|
||||
$discounts = [];
|
||||
$discountSum = 0;
|
||||
|
||||
foreach ($buckets as [$label, $percent, $base]) {
|
||||
if (null === $percent) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$amount = self::discountAmount($base, $percent);
|
||||
$discountSum += $amount;
|
||||
$discounts[] = ['label' => $label, 'percent' => $percent, 'amount' => $amount];
|
||||
}
|
||||
|
||||
return $this->computeCurrent($booking);
|
||||
$breakdown['discounts'] = $discounts;
|
||||
// Deliberately not $booking->getTotalPrice(): refreshPriceSnapshot() calls this while
|
||||
// computing the new total, where the stored one is still the outdated value.
|
||||
$breakdown['discountedTotal'] = (int) ($breakdown['total'] ?? 0) - $discountSum;
|
||||
|
||||
return $breakdown;
|
||||
}
|
||||
|
||||
private static function discountAmount(int $base, ?int $percent): int
|
||||
{
|
||||
return null !== $percent ? (int) round($base * $percent / 100) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -356,28 +356,16 @@ class AccommodationBookingService
|
||||
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());
|
||||
|
||||
// The raw breakdown is what gets frozen; the discounted total comes from the same
|
||||
// calculator the templates read, so the stored number always matches what is shown.
|
||||
$booking->setPriceSnapshot(
|
||||
$breakdown,
|
||||
$total,
|
||||
$this->breakdownCalculator->withDiscounts($booking, $breakdown)['discountedTotal'],
|
||||
(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
|
||||
{
|
||||
$this->sendBookingEmail(
|
||||
|
||||
Reference in New Issue
Block a user