feat: split summary DTOs into typed sub-objects

This commit is contained in:
Björn Fromme
2026-04-12 11:23:19 +02:00
parent 69705052b3
commit aa997826f8
18 changed files with 224 additions and 113 deletions
+4 -4
View File
@@ -6,6 +6,8 @@ namespace App\Service;
use App\Form\Model\BookingCreateContext;
use App\Form\Model\BookingDto;
use App\Form\Model\BookingSummaryDto;
use App\Form\Model\RoomGroupsDto;
/**
* Prepares the shared view model for booking create.
@@ -60,15 +62,13 @@ class BookingCreateContextFactory
}
/**
* @return array{summaryData: \App\Form\Model\BookingSummaryDto, groupedRooms: array{by_pax: array<int, \App\BusProNet\Model\Room>, by_room: array<int, \App\BusProNet\Model\Room>}}
* @return array{summaryData: BookingSummaryDto, groupedRooms: RoomGroupsDto}
*/
private function buildBaseContext(BookingDto $bookingDto, string $pricingMode): array
{
return [
'summaryData' => $this->summaryDataService->getSummaryData($bookingDto, $pricingMode),
'groupedRooms' => $this->roomSelectionService->groupRoomsBySelectionType(
$bookingDto->travel->getAvailableRooms()
),
'groupedRooms' => $this->roomSelectionService->groupRoomsBySelectionType($bookingDto->travel->getAvailableRooms()),
];
}
}
+5 -2
View File
@@ -8,6 +8,7 @@ use App\BusProNet\Model\Booking;
use App\Form\Model\BookingDto;
use App\Form\Model\BookingEditContext;
use App\Form\Model\BookingSummaryDto;
use App\Form\Model\BookingMutabilityDto;
/**
* Prepares the shared booking edit flow context.
@@ -37,7 +38,9 @@ class BookingEditContextFactory
return new BookingEditContext(
bookingDto: $bookingDto,
bookingData: $bookingData,
mutableData: $bookingData ? $this->travelDataService->getMutabilityData($bookingData->dateId) : null,
mutableData: BookingMutabilityDto::fromBaseData(
$bookingData ? $this->travelDataService->getMutabilityData($bookingData->dateId) : null
),
summaryData: $this->createSummaryData($bookingDto),
);
}
@@ -52,7 +55,7 @@ class BookingEditContextFactory
return new BookingEditContext(
bookingDto: $bookingDto,
bookingData: $bookingData,
mutableData: $this->travelDataService->getMutabilityData($bookingData->dateId),
mutableData: BookingMutabilityDto::fromBaseData($this->travelDataService->getMutabilityData($bookingData->dateId)),
summaryData: $this->createSummaryData($bookingDto),
cardsData: $this->participantCardDataService->getAllCardsDataWithValidation($bookingDto),
isDirty: $isDirty,
+6 -4
View File
@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace App\Service;
use App\BusProNet\Model\Room;
use App\Form\Model\RoomGroupsDto;
/**
* Groups room data for booking steps.
@@ -13,10 +14,8 @@ class BookingRoomSelectionService
{
/**
* @param array<int, Room> $rooms
*
* @return array{by_pax: array<int, Room>, by_room: array<int, Room>}
*/
public function groupRoomsBySelectionType(array $rooms): array
public function groupRoomsBySelectionType(array $rooms): RoomGroupsDto
{
$groups = [
Room::SELECTION_TYPE_BY_PAX => [],
@@ -35,6 +34,9 @@ class BookingRoomSelectionService
uasort($groups[Room::SELECTION_TYPE_BY_PAX], static fn (Room $a, Room $b): int => $a->maxPax <=> $b->maxPax);
uasort($groups[Room::SELECTION_TYPE_BY_ROOM], static fn (Room $a, Room $b): int => $a->maxPax <=> $b->maxPax);
return $groups;
return new RoomGroupsDto(
byPax: $groups[Room::SELECTION_TYPE_BY_PAX],
byRoom: $groups[Room::SELECTION_TYPE_BY_ROOM],
);
}
}
+23 -22
View File
@@ -7,8 +7,11 @@ namespace App\Service;
use App\BusProNet\DataProvider\CountryDataProvider;
use App\BusProNet\Model\Hotel;
use App\BusProNet\XmlLoader\HotelLoader;
use App\Form\Model\AcceptedVouchersDto;
use App\Form\Model\BookingDto;
use App\Form\Model\BookingSummaryDto;
use App\Form\Model\BookingSummaryPricingDto;
use App\Form\Model\BookingSummaryVoucherDto;
use Psr\Log\LoggerInterface;
use Symfony\Contracts\Cache\CacheInterface;
use Symfony\Contracts\Cache\ItemInterface;
@@ -53,18 +56,6 @@ class BookingSummaryDataService
}
}
// Group selected rooms with counts (for display)
$groupedSelectedRooms = [];
foreach ($roomCounts as $roomId => $count) {
$room = $bookingDto->travel->getRoomById($roomId);
if (null !== $room) {
$groupedSelectedRooms[] = [
'room' => $room,
'count' => $count,
];
}
}
// Get detailed pricing breakdown
$pricingData = $this->priceCalculator->getPricingBreakdown($bookingDto, $roomPricingMode);
@@ -74,17 +65,29 @@ class BookingSummaryDataService
// Calculate participant count from room capacity (source of truth)
$participantCount = $this->calculateParticipantCountFromRooms($bookingDto);
$acceptedVouchers = $bookingDto->getAcceptedVouchers($participantPrices);
// Calculate payable amount after voucher deductions
$payableAmount = $this->calculatePayableAmount($bookingDto, $pricingData['grandTotal'], $participantPrices);
$payableAmount = $this->calculatePayableAmount($pricingData['grandTotal'], $acceptedVouchers);
$pricing = new BookingSummaryPricingDto(
rooms: $pricingData['rooms'],
services: $pricingData['services'],
surcharges: $pricingData['surcharges'] ?? null,
assignmentCounts: $roomCounts,
grandTotal: $pricingData['grandTotal'],
);
$vouchers = new BookingSummaryVoucherDto(
acceptedVouchers: $acceptedVouchers,
payableAmount: $payableAmount,
);
return new BookingSummaryDto(
selectedRooms: $selectedRooms,
participantCount: $participantCount,
totalPrice: $pricingData['grandTotal'],
payableAmount: $payableAmount,
groupedSelectedRooms: $groupedSelectedRooms,
assignmentCounts: $roomCounts,
pricingData: $pricingData,
pricing: $pricing,
vouchers: $vouchers,
cmsData: $cmsData,
);
}
@@ -92,12 +95,10 @@ class BookingSummaryDataService
/**
* Calculates the payable amount after voucher deductions.
*
* @param array<int, float> $participantPrices Prices per participant for percentage voucher calculation
* @param AcceptedVouchersDto|null $acceptedVouchers Accepted vouchers for discount calculation
*/
private function calculatePayableAmount(BookingDto $bookingDto, float $grandTotal, array $participantPrices): float
private function calculatePayableAmount(float $grandTotal, ?AcceptedVouchersDto $acceptedVouchers): float
{
$acceptedVouchers = $bookingDto->getAcceptedVouchers($participantPrices);
if (null === $acceptedVouchers) {
return $grandTotal;
}