calculator = new RoomPricingCalculator(); } public function testCalculateRoomPricingWithParticipantBasedCalculation(): void { $room = new Room(); $room->id = 1; $room->price = 100.0; $room->minPax = 2; $room->label = 'Double Room'; $travel = new Travel(); $travel->rooms = [$room]; $roomSelection = new RoomSelectionDto(); $roomSelection->id = 1; $roomSelection->quantity = 2; $bookingDto = new BookingDto($travel, 1); $bookingDto->roomSelections = [$roomSelection]; $bookingDto->participants = [ $this->participantInRoom(1), $this->participantInRoom(1), $this->participantInRoom(1), $this->participantInRoom(1), ]; $result = $this->calculator->calculateRoomPricing($bookingDto); // 4 assigned participants × €100 = €400 total $this->assertCount(1, $result); $this->assertEquals(1, $result[0]['roomId']); $this->assertEquals('Double Room', $result[0]['label']); $this->assertEquals(2, $result[0]['quantity']); $this->assertEquals(4, $result[0]['participantCount']); $this->assertEquals(100.0, $result[0]['unitPrice']); $this->assertEquals(400.0, $result[0]['totalPrice']); } public function testCalculateRoomPricingWithSingleRoomSelection(): void { $room = new Room(); $room->id = 2; $room->price = 150.0; $room->minPax = 3; $room->label = 'Triple Room'; $travel = new Travel(); $travel->rooms = [$room]; $roomSelection = new RoomSelectionDto(); $roomSelection->id = 2; $roomSelection->quantity = 1; $bookingDto = new BookingDto($travel, 1); $bookingDto->roomSelections = [$roomSelection]; $bookingDto->participants = [ $this->participantInRoom(2), $this->participantInRoom(2), ]; $result = $this->calculator->calculateRoomPricing($bookingDto); // 2 assigned participants × €150 = €300 total $this->assertCount(1, $result); $this->assertEquals(2, $result[0]['roomId']); $this->assertEquals('Triple Room', $result[0]['label']); $this->assertEquals(1, $result[0]['quantity']); $this->assertEquals(2, $result[0]['participantCount']); $this->assertEquals(150.0, $result[0]['unitPrice']); $this->assertEquals(300.0, $result[0]['totalPrice']); } public function testCalculateRoomPricingWithMultipleRoomTypes(): void { $singleRoom = new Room(); $singleRoom->id = 1; $singleRoom->price = 80.0; $singleRoom->minPax = 1; $singleRoom->label = 'Single Room'; $doubleRoom = new Room(); $doubleRoom->id = 2; $doubleRoom->price = 120.0; $doubleRoom->minPax = 2; $doubleRoom->label = 'Double Room'; $travel = new Travel(); $travel->rooms = [$singleRoom, $doubleRoom]; $singleRoomSelection = new RoomSelectionDto(); $singleRoomSelection->id = 1; $singleRoomSelection->quantity = 1; $doubleRoomSelection = new RoomSelectionDto(); $doubleRoomSelection->id = 2; $doubleRoomSelection->quantity = 2; $bookingDto = new BookingDto($travel, 1); $bookingDto->roomSelections = [$singleRoomSelection, $doubleRoomSelection]; $bookingDto->participants = [ $this->participantInRoom(1), $this->participantInRoom(2), $this->participantInRoom(2), $this->participantInRoom(2), ]; $result = $this->calculator->calculateRoomPricing($bookingDto); // Single: 1 participant × €80 = €80 // Double: 3 participants × €120 = €360 $this->assertCount(2, $result); $this->assertEquals(1, $result[0]['roomId']); $this->assertEquals(1, $result[0]['quantity']); $this->assertEquals(1, $result[0]['participantCount']); $this->assertEquals(80.0, $result[0]['unitPrice']); $this->assertEquals(80.0, $result[0]['totalPrice']); $this->assertEquals(2, $result[1]['roomId']); $this->assertEquals(2, $result[1]['quantity']); $this->assertEquals(3, $result[1]['participantCount']); $this->assertEquals(120.0, $result[1]['unitPrice']); $this->assertEquals(360.0, $result[1]['totalPrice']); } public function testCalculateRoomPricingSkipsRoomsWithNullPrice(): void { $room = new Room(); $room->id = 1; $room->price = null; $room->minPax = 2; $room->label = 'Free Room'; $travel = new Travel(); $travel->rooms = [$room]; $roomSelection = new RoomSelectionDto(); $roomSelection->id = 1; $roomSelection->quantity = 1; $bookingDto = new BookingDto($travel, 1); $bookingDto->roomSelections = [$roomSelection]; $result = $this->calculator->calculateRoomPricing($bookingDto); $this->assertEmpty($result); } public function testCalculateRoomPricingWithZeroQuantityRooms(): void { $room = new Room(); $room->id = 1; $room->price = 100.0; $room->minPax = 2; $room->label = 'Double Room'; $travel = new Travel(); $travel->rooms = [$room]; $roomSelection = new RoomSelectionDto(); $roomSelection->id = 1; $roomSelection->quantity = 0; $bookingDto = new BookingDto($travel, 1); $bookingDto->roomSelections = [$roomSelection]; $result = $this->calculator->calculateRoomPricing($bookingDto); $this->assertEmpty($result); } public function testCalculateRoomPricingShowsSelectedRoomWithZeroAssignments(): void { $room = new Room(); $room->id = 1; $room->price = 100.0; $room->label = 'Double Room'; $travel = new Travel(); $travel->rooms = [$room]; $roomSelection = new RoomSelectionDto(); $roomSelection->id = 1; $roomSelection->quantity = 1; $bookingDto = new BookingDto($travel, 1); $bookingDto->roomSelections = [$roomSelection]; $bookingDto->participants = []; $result = $this->calculator->calculateRoomPricing($bookingDto); $this->assertCount(1, $result); $this->assertEquals(1, $result[0]['roomId']); $this->assertEquals(1, $result[0]['quantity']); $this->assertEquals(0, $result[0]['participantCount']); $this->assertEquals(0.0, $result[0]['totalPrice']); } public function testCalculateRoomPricingUsesSelectionModeForStepOneSummary(): void { $room = new Room(); $room->id = 3; $room->price = 229.0; $room->minPax = 2; $room->label = 'Doppelzimmer Dusche/WC'; $travel = new Travel(); $travel->rooms = [$room]; $roomSelection = new RoomSelectionDto(); $roomSelection->id = 3; $roomSelection->quantity = 1; $bookingDto = new BookingDto($travel, 1); $bookingDto->roomSelections = [$roomSelection]; $bookingDto->participants = [ $this->participantInRoom(3), $this->participantInRoom(3), ]; $result = $this->calculator->calculateRoomPricing($bookingDto, RoomPricingCalculator::PRICING_MODE_SELECTION); $this->assertCount(1, $result); $this->assertEquals(2, $result[0]['participantCount']); $this->assertEquals(458.0, $result[0]['totalPrice']); } public function testCalculateRoomPricingFallsBackToOneParticipantWhenOccupancyIsUnknown(): void { $room = new Room(); $room->id = 4; $room->price = 419.0; $room->minPax = null; $room->label = 'Bett im Mehrbettzimmer'; $travel = new Travel(); $travel->rooms = [$room]; $roomSelection = new RoomSelectionDto(); $roomSelection->id = 4; $roomSelection->quantity = 2; $bookingDto = new BookingDto($travel, 1); $bookingDto->roomSelections = [$roomSelection]; $result = $this->calculator->calculateRoomPricing($bookingDto, RoomPricingCalculator::PRICING_MODE_SELECTION); $this->assertCount(1, $result); $this->assertEquals(2, $result[0]['participantCount']); $this->assertEquals(838.0, $result[0]['totalPrice']); } public function testCalculateRoomPricingInEditModeUsesStoredIndividualPrices(): void { $travel = new Travel(); $bookingDto = new BookingDto($travel, 2); $participantA = new ParticipantDto(); $participantA->assignedRoomId = 10; $participantB = new ParticipantDto(); $participantB->assignedRoomId = 10; $bookingDto->participants = [$participantA, $participantB]; $booking = new Booking(); $room = new Room(); $room->id = 10; $room->label = 'Stored Room'; $room->mapping = [0, 1]; $room->individualPrice = [0 => 200.0, 1 => 220.0]; $room->totalCount = 1; $booking->rooms = [$room]; $bookingDto->booking = $booking; $result = $this->calculator->calculateRoomPricing($bookingDto); $this->assertCount(1, $result); $this->assertEquals(10, $result[0]['roomId']); $this->assertEquals(2, $result[0]['participantCount']); $this->assertEquals(210.0, $result[0]['unitPrice']); $this->assertEquals(420.0, $result[0]['totalPrice']); $this->assertEquals(1, $result[0]['quantity']); } public function testCalculateRoomPricingInEditModeShowsBookedRoomCountNotOccupants(): void { // Booking 104407: 16 participants in one 6-bed room, one 4-bed room and three doubles. $bookingDto = new BookingDto(new Travel(), 16); $bookingDto->participants = []; foreach ([0, 1, 2, 3, 4, 5] as $index) { $bookingDto->participants[$index] = $this->participantInRoom(863); } foreach ([6, 7, 8, 9] as $index) { $bookingDto->participants[$index] = $this->participantInRoom(95); } foreach ([10, 11, 12, 13, 14, 15] as $index) { $bookingDto->participants[$index] = $this->participantInRoom(3); } $booking = new Booking(); $booking->rooms = [ 863 => $this->bookedRoom(863, 6, 1, [0, 1, 2, 3, 4, 5], 194.0), 95 => $this->bookedRoom(95, 4, 1, [6, 7, 8, 9], 204.0), 3 => $this->bookedRoom(3, 2, 3, [10, 11, 12, 13, 14, 15], 224.0), ]; $bookingDto->booking = $booking; $result = $this->calculator->calculateRoomPricing($bookingDto); $quantities = array_column($result, 'quantity', 'roomId'); $this->assertSame([863 => 1, 95 => 1, 3 => 3], $quantities); $this->assertEquals(1344.0, $result[2]['totalPrice']); } /** @param int[] $mapping */ private function bookedRoom(int $id, int $maxPax, int $totalCount, array $mapping, float $price): Room { $room = new Room(); $room->id = $id; $room->label = 'Room '.$id; $room->maxPax = $maxPax; $room->totalCount = $totalCount; $room->mapping = $mapping; $room->individualPrice = array_fill_keys($mapping, $price); return $room; } private function participantInRoom(int $roomId): ParticipantDto { $participant = new ParticipantDto(); $participant->assignedRoomId = $roomId; return $participant; } }