> Array of room pricing data with labels, quantities, and totals */ public function calculateRoomPricing( BookingDto $bookingDto, string $pricingMode = self::PRICING_MODE_ASSIGNMENT, ): array { // In edit mode, use room data from the booking entity if (BookingDto::MODE_EDIT === $bookingDto->getMode() && null !== $bookingDto->booking) { return $this->calculateRoomPricingFromBooking($bookingDto); } // In create mode, use room selections from the form return $this->calculateRoomPricingFromSelections($bookingDto, $pricingMode); } /** * Calculates total price for all rooms. */ public function calculateRoomTotal( BookingDto $bookingDto, string $pricingMode = self::PRICING_MODE_ASSIGNMENT, ): float { $roomPricing = $this->calculateRoomPricing($bookingDto, $pricingMode); return array_sum(array_column($roomPricing, 'totalPrice')); } /** * Retrieves a room by ID from the booking's travel data. */ public function getRoomById(BookingDto $bookingDto, ?int $roomId): ?Room { if (null === $roomId) { return null; } foreach ($bookingDto->travel->rooms as $room) { if ($room->id === $roomId) { return $room; } } return null; } /** * Calculates room pricing from form selections (create mode). * * @param BookingDto $bookingDto The booking data containing room selections * * @return array> Array of room pricing data */ private function calculateRoomPricingFromSelections(BookingDto $bookingDto, string $pricingMode): array { $roomPricing = []; $selectedRooms = $bookingDto->getSelectedRooms(); if (true === empty($selectedRooms)) { return $roomPricing; } $assignmentCounts = $bookingDto->getRoomAssignmentCounts(); foreach ($selectedRooms as $roomSelection) { $room = $this->getRoomById($bookingDto, $roomSelection->id); if (null === $room || null === $room->price) { continue; } // Step 1 displays intended room pricing based on selected quantity and // minimum room occupancy (minPax). Subsequent steps calculate based on // actual participant assignments. $participantCount = self::PRICING_MODE_SELECTION === $pricingMode ? (($room->minPax ?? 1) * $roomSelection->quantity) : ($assignmentCounts[$room->id] ?? 0) ; $totalPrice = $participantCount * $room->price; $roomPricing[] = [ 'roomId' => $room->id, 'label' => $room->label, 'quantity' => $roomSelection->quantity, 'participantCount' => $participantCount, 'unitPrice' => $room->price, 'totalPrice' => $totalPrice, ]; } return $roomPricing; } /** * Calculates room pricing from booking entity data (edit mode). * * In edit mode, room prices come from the booking entity's individualPrice arrays. * Each participant has their room price stored in the room's individualPrice array. * * @param BookingDto $bookingDto The booking data with booking entity * * @return array> Array of room pricing data with labels, quantities, and totals */ private function calculateRoomPricingFromBooking(BookingDto $bookingDto): array { $roomPricing = []; $roomGroups = []; // Group participants by room and sum their individual prices foreach ($bookingDto->booking->rooms as $room) { if (false === isset($roomGroups[$room->id])) { $roomGroups[$room->id] = [ 'room' => $room, 'participantCount' => 0, 'totalPrice' => 0.0, ]; } // Sum individual prices for all participants in this room foreach ($room->mapping as $participantIndex) { $individualPrice = $room->individualPrice[$participantIndex] ?? 0.0; $roomGroups[$room->id]['totalPrice'] += $individualPrice; ++$roomGroups[$room->id]['participantCount']; } } // Build pricing array foreach ($roomGroups as $data) { $room = $data['room']; $participantCount = $data['participantCount']; $totalPrice = $data['totalPrice']; // Calculate average unit price (price per person) $unitPrice = $participantCount > 0 ? $totalPrice / $participantCount : 0.0; $roomPricing[] = [ 'roomId' => $room->id, 'label' => $room->label, // Rooms, not occupants: room assignments cannot change in edit mode 'quantity' => $room->totalCount, 'participantCount' => $participantCount, 'unitPrice' => $unitPrice, 'totalPrice' => $totalPrice, ]; } return $roomPricing; } }