diff --git a/src/BusProNet/Model/BookingResponse.php b/src/BusProNet/Model/BookingResponse.php index 70afd5f..b1f0da2 100644 --- a/src/BusProNet/Model/BookingResponse.php +++ b/src/BusProNet/Model/BookingResponse.php @@ -111,8 +111,12 @@ class BookingResponse * - ERM/GRU: Gruppenrabatt (group discount for large bookings) * - Other ERM subtypes: Various automatic discounts * - * These discounts appear as negative price items and must be accounted for when - * comparing the API total price against the locally calculated price. + * These discounts appear as negative price items with type "ERM" and must be + * accounted for when comparing the API total price against the locally calculated price. + * + * Important: Only ERM type discounts are considered API-applied. Other negative price + * items (like BEF transportation discounts) are already handled by the local price + * calculator and should not be subtracted again. * * Note: Voucher discounts (AKTION, KULANZGUTSCHEIN) are handled separately via * getVoucherDiscountFromPrices() as they are user-initiated, not automatic. @@ -123,8 +127,7 @@ class BookingResponse { return array_filter( $this->priceItems, - fn (PriceItem $item) => $item->totalPrice < 0 - && false === \in_array($item->type, ['AKTION', 'KULANZGUTSCHEIN'], true) + fn (PriceItem $item) => $item->totalPrice < 0 && 'ERM' === $item->type ); } diff --git a/tests/BusProNet/XmlParser/BookingResponseParserTest.php b/tests/BusProNet/XmlParser/BookingResponseParserTest.php index 6000add..90b186f 100644 --- a/tests/BusProNet/XmlParser/BookingResponseParserTest.php +++ b/tests/BusProNet/XmlParser/BookingResponseParserTest.php @@ -312,4 +312,73 @@ class BookingResponseParserTest extends TestCase $this->assertCount(0, $response->getApiAppliedDiscounts()); $this->assertEquals(0.0, $response->getApiAppliedDiscountTotal()); } + + public function testParseBookingResponseWithTransportationDiscountNotCountedAsApiApplied(): void + { + $xmlContent = ' + + + möglich + 321530 + + + + + + + + 1682,00 + + + +'; + + $crawler = new Crawler($xmlContent); + $response = $this->parser->parse($crawler->filter('ergebnis')); + + $this->assertTrue($response->isInquiryValid()); + $this->assertEquals(1682.0, $response->totalPrice); + + // Transportation discount (BEF with negative price) should NOT be counted as API-applied discount + // because it's already handled by the local price calculator + $this->assertCount(0, $response->getApiAppliedDiscounts()); + $this->assertEquals(0.0, $response->getApiAppliedDiscountTotal()); + + // Verify no voucher discounts either + $this->assertEquals(0.0, $response->getVoucherDiscountFromPrices()); + } + + public function testParseBookingResponseWithBothTransportationAndGruppenrabatt(): void + { + $xmlContent = ' + + + möglich + 321530 + + + + + + 1600,00 + + + +'; + + $crawler = new Crawler($xmlContent); + $response = $this->parser->parse($crawler->filter('ergebnis')); + + // Only ERM (Gruppenrabatt) should be counted as API-applied discount + // BEF transportation discount should NOT be counted + $apiAppliedDiscounts = $response->getApiAppliedDiscounts(); + $this->assertCount(1, $apiAppliedDiscounts); + + $gruppenrabatt = array_values($apiAppliedDiscounts)[0]; + $this->assertEquals('ERM', $gruppenrabatt->type); + $this->assertEquals(-100.0, $gruppenrabatt->totalPrice); + + // Total API-applied discount should only include Gruppenrabatt (100), not transportation (300) + $this->assertEquals(100.0, $response->getApiAppliedDiscountTotal()); + } }