feat: show room prices in room assignment form field

This commit is contained in:
Björn Fromme
2026-03-16 12:00:55 +01:00
parent 5b75a165ce
commit e1bfe9b93c
22 changed files with 193 additions and 92 deletions
@@ -17,6 +17,7 @@ use App\Form\Service\Condition\FieldValueCondition;
use App\Form\Service\Condition\PersonalDataMutabilityCondition;
use App\Form\Service\Condition\PickupsMutabilityCondition;
use App\Form\Service\Condition\RentalSelectionCondition;
use App\Form\Service\Condition\RoomSelectionCondition;
use App\Form\Service\Condition\ServiceSubTypeCondition;
use App\Form\Service\Condition\SkiPassSelectionCondition;
use App\Form\Service\Condition\TransportationServicesMutabilityCondition;
@@ -104,6 +105,12 @@ class EditFieldStateProvider extends AbstractFieldStateProvider
'static_text' => new BookingModeCondition(BookingDto::MODE_EDIT),
];
// Show remarks room field only when room with code 'mbz' (single bed) is selected
$sharedRoomCondition = new RoomSelectionCondition(['mbz']);
$this->fieldStateConditions['remarksRoom'] = [
'hidden' => CompositeCondition::not($sharedRoomCondition),
];
// Conditional visibility for service fields (same as create flow)
$rentalCondition = new RentalSelectionCondition();
$skiPassCondition = new SkiPassSelectionCondition();
@@ -110,7 +110,7 @@ class ParticipantAssignedRoomFieldHandler extends AbstractParticipantFieldHandle
// Get the room selection details
$roomSelection = null;
foreach ($bookingDto->roomSelections as $selection) {
if ($selection->roomId === $roomId) {
if ($selection->id === $roomId) {
$roomSelection = $selection;
break;
}
@@ -164,7 +164,7 @@ class ParticipantAssignedRoomFieldHandler extends AbstractParticipantFieldHandle
// Calculate how many need to be unassigned
$roomSelection = null;
foreach ($bookingDto->roomSelections as $selection) {
if ($selection->roomId === $roomId) {
if ($selection->id === $roomId) {
$roomSelection = $selection;
break;
}
@@ -229,8 +229,8 @@ class ParticipantAssignedRoomFieldHandler extends AbstractParticipantFieldHandle
private function getRoomLabelById(int $roomId, BookingDto $bookingDto): string
{
foreach ($bookingDto->roomSelections as $selection) {
if ($selection->roomId === $roomId) {
return $selection->roomLabel;
if ($selection->id === $roomId) {
return $selection->label;
}
}
@@ -73,15 +73,14 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
if (BookingDto::MODE_CREATE === $bookingDto->getMode()) {
// Create context: use selected rooms from step 1, filtered by participant age
$filteredRooms = $this->filterRoomsByParticipantAge(
$choices = $this->filterRoomsByParticipantAge(
$bookingDto->getSelectedRooms(),
$bookingDto,
$participantIndex
);
$choices = $this->buildRoomChoicesFromSelections($filteredRooms);
} elseif (BookingDto::MODE_EDIT === $bookingDto->getMode()) {
// Edit context: use already-booked rooms from booking
$choices = $this->buildRoomChoicesFromBookedRooms($bookingDto->booking->rooms);
// Edit context: convert booked rooms to RoomSelectionDto for consistent handling
$choices = $this->convertBookedRoomsToSelectionDtos($bookingDto->booking->rooms);
}
$singleChoice = 1 === count($choices);
@@ -93,6 +92,8 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
// No placeholder when only one room available - the only option is pre-selected
'placeholder' => $singleChoice ? false : 'Nicht zugeordnet',
'choices' => $choices,
'choice_value' => fn (RoomSelectionDto|int|null $room) => $room instanceof RoomSelectionDto ? $room->id : $room,
'choice_label' => fn (?RoomSelectionDto $room) => $room?->label,
];
};
@@ -511,7 +512,7 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
$availableRooms = $bookingDto->travel->getAvailableRooms();
return array_filter($roomSelections, function (RoomSelectionDto $roomSelection) use ($availableRooms, $age) {
$room = $availableRooms[$roomSelection->roomId] ?? null;
$room = $availableRooms[$roomSelection->id] ?? null;
// Exclude rooms not found in travel data to avoid validation issues
if (null === $room) {
@@ -529,37 +530,28 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
}
/**
* Builds room choices array from RoomSelectionDto objects.
* Converts booked Room objects to RoomSelectionDto for consistent form handling.
*
* @param RoomSelectionDto[] $roomSelections Room selections from step 1
*
* @return array<string, int> Choices array with label => id
*/
private function buildRoomChoicesFromSelections(array $roomSelections): array
{
$choices = [];
foreach ($roomSelections as $roomSelection) {
$choices[$roomSelection->roomLabel] = $roomSelection->roomId;
}
return $choices;
}
/**
* Builds room choices array from booked Room objects.
* In edit mode, we need to convert Room entities to RoomSelectionDto objects
* so the form can use the same choice_value and choice_label configuration
* as create mode, enabling consistent price display in the template.
*
* @param Room[] $bookedRooms Rooms from existing booking
*
* @return array<string, int> Choices array with label => id
* @return RoomSelectionDto[] Array of room selection DTOs
*/
private function buildRoomChoicesFromBookedRooms(array $bookedRooms): array
private function convertBookedRoomsToSelectionDtos(array $bookedRooms): array
{
$choices = [];
$selections = [];
foreach ($bookedRooms as $room) {
$choices[$room->label] = $room->id;
$selection = new RoomSelectionDto();
$selection->id = $room->id;
$selection->label = $room->label;
$selection->price = $room->price;
$selections[] = $selection;
}
return $choices;
return $selections;
}
/**