Files
myep/src/Service/BookingPriceCalculatorService.php
T

219 lines
7.9 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Service;
use App\Form\Model\BookingDto;
/**
* Facade for booking pricing calculations.
*
* Provides comprehensive pricing calculations for the booking system by
* coordinating specialized calculators for rooms, services, and participants.
* Returns structured pricing data for display in forms and summaries.
*/
class BookingPriceCalculatorService
{
public function __construct(
private readonly RoomPricingCalculator $roomPricingCalculator,
private readonly ServicePricingCalculator $servicePricingCalculator,
private readonly ParticipantPricingCalculator $participantPricingCalculator,
) {
}
/**
* Calculates comprehensive pricing breakdown for a booking.
*
* @param BookingDto $bookingDto The booking data to calculate pricing for
*
* @return array{rooms: array, services: array, grandTotal: float} Complete pricing breakdown
*/
public function getPricingBreakdown(BookingDto $bookingDto): array
{
$roomPricing = $this->roomPricingCalculator->calculateRoomPricing($bookingDto);
$servicePricing = $this->servicePricingCalculator->calculateServicePricing($bookingDto);
$grandTotal = $this->calculateGrandTotal($bookingDto);
$result = [
'rooms' => $roomPricing,
'services' => $servicePricing,
'grandTotal' => $grandTotal,
];
// Add surcharges if in edit mode with booking data
if (null !== $bookingDto->booking && [] !== $bookingDto->booking->surcharges) {
$surchargePricing = $this->calculateSurchargePricing($bookingDto->booking);
if ([] !== $surchargePricing) {
$result['surcharges'] = $surchargePricing;
// Add surcharge total to grand total
$surchargeTotal = array_sum(array_column($surchargePricing, 'totalPrice'));
$result['grandTotal'] += $surchargeTotal;
}
}
return $result;
}
/**
* Calculates pricing for all selected rooms.
*
* @param BookingDto $bookingDto The booking data containing room selections
*
* @return array Array of room pricing data with labels, quantities, and totals
*/
public function calculateRoomPricing(BookingDto $bookingDto): array
{
return $this->roomPricingCalculator->calculateRoomPricing($bookingDto);
}
/**
* Calculates pricing for all selected services across all participants, grouped by subtype.
*
* Only includes services from eligible participants (those with available skipasses for their age).
*
* @param BookingDto $bookingDto The booking data containing participants and their service selections
*
* @return array Array of service groups with each group containing services of the same subtype
*/
public function calculateServicePricing(BookingDto $bookingDto): array
{
return $this->servicePricingCalculator->calculateServicePricing($bookingDto);
}
/**
* Calculates the grand total for the entire booking.
*
* @param BookingDto $bookingDto The booking data to calculate total for
*
* @return float The grand total price
*/
public function calculateGrandTotal(BookingDto $bookingDto): float
{
$roomTotal = $this->roomPricingCalculator->calculateRoomTotal($bookingDto);
$serviceTotal = $this->servicePricingCalculator->calculateServiceTotal($bookingDto);
return $roomTotal + $serviceTotal;
}
/**
* Calculates total price for all rooms.
*/
public function calculateRoomTotal(BookingDto $bookingDto): float
{
return $this->roomPricingCalculator->calculateRoomTotal($bookingDto);
}
/**
* Calculates total price for all services.
*/
public function calculateServiceTotal(BookingDto $bookingDto): float
{
return $this->servicePricingCalculator->calculateServiceTotal($bookingDto);
}
/**
* Calculates surcharge pricing grouped by label (edit mode only).
*
* Returns surcharges in a format similar to services for display in summary.
* Groups surcharges by label and counts participant assignments.
*
* @param \App\BusProNet\Model\Booking $bookingData The booking entity with surcharge information
*
* @return array Array of surcharge data with labels, counts, and totals
*/
public function calculateSurchargePricing(\App\BusProNet\Model\Booking $bookingData): array
{
$surchargePricing = [];
foreach ($bookingData->surcharges as $surcharge) {
$surchargePricing[] = [
'label' => $surcharge->label ?? 'unbekannt',
'participantCount' => count($surcharge->mapping),
'totalPrice' => $surcharge->totalPrice ?? 0.0,
];
}
return $surchargePricing;
}
/**
* Formats a price value for display with proper German formatting.
*
* @param float $price The price to format
*
* @return string Formatted price string (e.g., "123,45")
*/
public function formatPrice(float $price): string
{
return number_format($price, 2, ',', '.');
}
/**
* Formats a price with Euro symbol for display.
*
* @param float $price The price to format
*
* @return string Formatted price string with Euro symbol (e.g., "€123,45")
*/
public function formatPriceWithSymbol(float $price): string
{
return '€'.$this->formatPrice($price);
}
/**
* Calculates the total price for an individual participant.
*
* This method calculates the complete price breakdown for a single participant,
* including their room allocation (full room price) and all selected services.
*
* @param BookingDto $bookingDto The booking data containing all participants
* @param int $participantIndex The index of the participant to calculate for
*
* @return float The total price for the specified participant
*/
public function calculateIndividualParticipantPrice(BookingDto $bookingDto, int $participantIndex): float
{
return $this->participantPricingCalculator->calculateIndividualParticipantPrice($bookingDto, $participantIndex);
}
/**
* Calculates individual prices for all participants in a booking.
*
* @param BookingDto $bookingDto The booking data containing all participants
*
* @return array Array indexed by participant index containing individual prices
*/
public function calculateAllParticipantIndividualPrices(BookingDto $bookingDto): array
{
return $this->participantPricingCalculator->calculateAllParticipantIndividualPrices($bookingDto);
}
/**
* Calculates the total price for an individual participant excluding insurance.
*
* This method is used for insurance eligibility filtering to avoid circular dependency
* where insurance selection affects travel price which affects insurance eligibility.
*
* Only includes services where versicherungsberechnung='J' in the XML. Services with
* versicherungsberechnung='N' (like CO2 compensation) are excluded from the calculation
* as per BPN API requirements for insurance tier determination.
*
* @param BookingDto $bookingDto The booking data containing all participants
* @param int $participantIndex The index of the participant to calculate for
*
* @return float The total price for the specified participant excluding insurance and non-calculated services
*/
public function calculateIndividualParticipantPriceExcludingInsurance(
BookingDto $bookingDto,
int $participantIndex,
): float {
return $this->participantPricingCalculator->calculateIndividualParticipantPriceExcludingInsurance(
$bookingDto,
$participantIndex
);
}
}