From 45d05786da5b05f0669c95ac9adff8c08d630599 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Fromme?= Date: Thu, 19 Mar 2026 15:45:23 +0100 Subject: [PATCH] fix: correctly calculate room pricing based on participant assignment --- src/Service/RoomPricingCalculator.php | 9 ++- .../BookingPriceCalculatorServiceTest.php | 75 ++++++++++++++++--- 2 files changed, 68 insertions(+), 16 deletions(-) diff --git a/src/Service/RoomPricingCalculator.php b/src/Service/RoomPricingCalculator.php index 69bb19d..a027bfd 100644 --- a/src/Service/RoomPricingCalculator.php +++ b/src/Service/RoomPricingCalculator.php @@ -77,16 +77,17 @@ class RoomPricingCalculator return $roomPricing; } + $assignmentCounts = $bookingDto->getRoomAssignmentCounts(); + foreach ($selectedRooms as $roomSelection) { $room = $this->getRoomById($bookingDto, $roomSelection->id); if (null === $room || null === $room->price) { continue; } - // Pricing in create flow is based on selected room quantity from step 1. - // Do not derive billable units from minPax, which represents capacity constraints. - $participantCount = $roomSelection->quantity; - $totalPrice = $roomSelection->quantity * $room->price; + // Pricing in create flow is based on actual participant assignments per room. + $participantCount = $assignmentCounts[$room->id] ?? 0; + $totalPrice = $participantCount * $room->price; $roomPricing[] = [ 'roomId' => $room->id, diff --git a/tests/Service/BookingPriceCalculatorServiceTest.php b/tests/Service/BookingPriceCalculatorServiceTest.php index 102eb35..988204c 100644 --- a/tests/Service/BookingPriceCalculatorServiceTest.php +++ b/tests/Service/BookingPriceCalculatorServiceTest.php @@ -68,18 +68,24 @@ class BookingPriceCalculatorServiceTest extends TestCase $bookingDto = new BookingDto($travel, 1); $bookingDto->roomSelections = [$roomSelection]; + $bookingDto->participants = [ + $this->createParticipantWithAssignedRoom(1), + $this->createParticipantWithAssignedRoom(1), + $this->createParticipantWithAssignedRoom(1), + $this->createParticipantWithAssignedRoom(1), + ]; // Test the calculation $result = $this->service->calculateRoomPricing($bookingDto); - // Expected: 2 rooms × €100 = €200 total + // Expected: 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']); // 2 rooms - $this->assertEquals(2, $result[0]['participantCount']); // billed units follow selected room count - $this->assertEquals(100.0, $result[0]['unitPrice']); // €100 per room - $this->assertEquals(200.0, $result[0]['totalPrice']); // €200 total + $this->assertEquals(4, $result[0]['participantCount']); // billed units follow assigned participants + $this->assertEquals(100.0, $result[0]['unitPrice']); // €100 per participant + $this->assertEquals(400.0, $result[0]['totalPrice']); // €400 total } public function testCalculateRoomPricingWithSingleRoomSelection(): void @@ -100,18 +106,22 @@ class BookingPriceCalculatorServiceTest extends TestCase $bookingDto = new BookingDto($travel, 1); $bookingDto->roomSelections = [$roomSelection]; + $bookingDto->participants = [ + $this->createParticipantWithAssignedRoom(2), + $this->createParticipantWithAssignedRoom(2), + ]; // Test the calculation $result = $this->service->calculateRoomPricing($bookingDto); - // Expected: 1 room × €150 = €150 total + // Expected: 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']); // 1 room - $this->assertEquals(1, $result[0]['participantCount']); // billed units follow selected room count - $this->assertEquals(150.0, $result[0]['unitPrice']); // €150 per room - $this->assertEquals(150.0, $result[0]['totalPrice']); // €150 total + $this->assertEquals(2, $result[0]['participantCount']); // billed units follow assigned participants + $this->assertEquals(150.0, $result[0]['unitPrice']); // €150 per participant + $this->assertEquals(300.0, $result[0]['totalPrice']); // €300 total } public function testCalculateRoomPricingWithMultipleRoomTypes(): void @@ -142,13 +152,19 @@ class BookingPriceCalculatorServiceTest extends TestCase $bookingDto = new BookingDto($travel, 1); $bookingDto->roomSelections = [$singleRoomSelection, $doubleRoomSelection]; + $bookingDto->participants = [ + $this->createParticipantWithAssignedRoom(1), + $this->createParticipantWithAssignedRoom(2), + $this->createParticipantWithAssignedRoom(2), + $this->createParticipantWithAssignedRoom(2), + ]; // Test the calculation $result = $this->service->calculateRoomPricing($bookingDto); // Expected: - // - Single: 1 room × €80 = €80 - // - Double: 2 rooms × €120 = €240 + // - Single: 1 assigned participant × €80 = €80 + // - Double: 3 assigned participants × €120 = €360 $this->assertCount(2, $result); // Single room result @@ -163,9 +179,9 @@ class BookingPriceCalculatorServiceTest extends TestCase $doubleResult = $result[1]; $this->assertEquals(2, $doubleResult['roomId']); $this->assertEquals(2, $doubleResult['quantity']); - $this->assertEquals(2, $doubleResult['participantCount']); + $this->assertEquals(3, $doubleResult['participantCount']); $this->assertEquals(120.0, $doubleResult['unitPrice']); - $this->assertEquals(240.0, $doubleResult['totalPrice']); + $this->assertEquals(360.0, $doubleResult['totalPrice']); } public function testCalculateRoomPricingSkipsRoomsWithNullPrice(): void @@ -216,6 +232,33 @@ class BookingPriceCalculatorServiceTest extends TestCase $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 = []; // nothing assigned yet + + $result = $this->service->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 testCalculateRoomPricingInEditModeUsesStoredIndividualPrices(): void { $travel = new Travel(); @@ -645,4 +688,12 @@ class BookingPriceCalculatorServiceTest extends TestCase return null; } + + private function createParticipantWithAssignedRoom(int $roomId): ParticipantDto + { + $participant = new ParticipantDto(); + $participant->assignedRoomId = $roomId; + + return $participant; + } }