parser = new BookingResponseParser(); } public function testParseBookingResponseWithPurchaseVoucher(): void { $xmlContent = ' möglich 321530 755,00 '; $crawler = new Crawler($xmlContent); $response = $this->parser->parse($crawler->filter('ergebnis')); self::assertTrue($response->isInquiryValid()); self::assertEquals(321530, $response->bookingNumber); self::assertEquals(755.0, $response->totalPrice); // Verify purchase voucher is parsed self::assertNotNull($response->paymentTerms); self::assertCount(1, $response->paymentTerms->appliedPurchaseVouchers); self::assertEquals('G1263', $response->paymentTerms->appliedPurchaseVouchers[0]['nummer']); self::assertEquals(100.0, $response->paymentTerms->appliedPurchaseVouchers[0]['betrag']); self::assertEquals(100.0, $response->paymentTerms->getPurchaseVoucherDiscount()); self::assertEquals(655.0, $response->paymentTerms->finalPaymentAmount); } public function testParseBookingResponseWithPromotionalVoucher(): void { $xmlContent = ' möglich 321530 615,20 '; $crawler = new Crawler($xmlContent); $response = $this->parser->parse($crawler->filter('ergebnis')); self::assertTrue($response->isInquiryValid()); self::assertEquals(615.2, $response->totalPrice); // Verify price items include promotional voucher self::assertCount(2, $response->priceItems); $voucherItem = $response->priceItems[1]; self::assertEquals('AKTION', $voucherItem->type); self::assertEquals('TESTERINO1', $voucherItem->label); self::assertEquals(-100.0, $voucherItem->totalPrice); // Verify voucher discount extraction $voucherDiscounts = $response->getVoucherDiscountsFromPrices(); self::assertCount(1, $voucherDiscounts); self::assertEquals(100.0, $response->getVoucherDiscountFromPrices()); self::assertEquals(100.0, $response->getTotalVoucherDiscount()); } public function testParseBookingResponseWithGoodwillVoucher(): void { $xmlContent = ' möglich 321530 0,00 '; $crawler = new Crawler($xmlContent); $response = $this->parser->parse($crawler->filter('ergebnis')); self::assertTrue($response->isInquiryValid()); self::assertEquals(0.0, $response->totalPrice); // Verify goodwill voucher is parsed $voucherDiscounts = $response->getVoucherDiscountsFromPrices(); self::assertCount(1, $voucherDiscounts); $goodwillVoucher = array_values($voucherDiscounts)[0]; self::assertEquals('KULANZGUTSCHEIN', $goodwillVoucher->type); self::assertEquals('Kulanzgutschein K1904', $goodwillVoucher->label); self::assertEquals(-679.0, $goodwillVoucher->totalPrice); self::assertEquals(679.0, $response->getVoucherDiscountFromPrices()); self::assertEquals(679.0, $response->getTotalVoucherDiscount()); } public function testParseBookingResponseWithMultipleVouchers(): void { $xmlContent = ' möglich 321530 499,00 '; $crawler = new Crawler($xmlContent); $response = $this->parser->parse($crawler->filter('ergebnis')); // Verify all voucher types are parsed self::assertEquals(80.0, $response->getVoucherDiscountFromPrices()); // 50 + 30 self::assertEquals(100.0, $response->getPurchaseVoucherDiscount()); self::assertEquals(180.0, $response->getTotalVoucherDiscount()); // 50 + 30 + 100 // Verify price item vouchers $voucherDiscounts = $response->getVoucherDiscountsFromPrices(); self::assertCount(2, $voucherDiscounts); } public function testParseBookingResponseWithNoVouchers(): void { $xmlContent = ' möglich 321530 679,00 '; $crawler = new Crawler($xmlContent); $response = $this->parser->parse($crawler->filter('ergebnis')); self::assertTrue($response->isInquiryValid()); self::assertEquals(679.0, $response->totalPrice); // Verify no voucher discounts self::assertCount(0, $response->getVoucherDiscountsFromPrices()); self::assertEquals(0.0, $response->getVoucherDiscountFromPrices()); self::assertEquals(0.0, $response->getPurchaseVoucherDiscount()); self::assertEquals(0.0, $response->getTotalVoucherDiscount()); } public function testParseBookingResponseWithMultiplePurchaseVouchers(): void { $xmlContent = ' möglich 321530 679,00 '; $crawler = new Crawler($xmlContent); $response = $this->parser->parse($crawler->filter('ergebnis')); // Verify multiple purchase vouchers are parsed self::assertNotNull($response->paymentTerms); self::assertCount(2, $response->paymentTerms->appliedPurchaseVouchers); self::assertEquals(125.0, $response->paymentTerms->getPurchaseVoucherDiscount()); // 50 + 75 self::assertEquals(125.0, $response->getTotalVoucherDiscount()); } public function testParseBookingResponseWithGruppenrabatt(): void { $xmlContent = ' möglich 321530 3972,00 '; $crawler = new Crawler($xmlContent); $response = $this->parser->parse($crawler->filter('ergebnis')); self::assertTrue($response->isInquiryValid()); self::assertEquals(3972.0, $response->totalPrice); // Verify Gruppenrabatt is NOT counted as voucher discount self::assertCount(0, $response->getVoucherDiscountsFromPrices()); self::assertEquals(0.0, $response->getVoucherDiscountFromPrices()); // Verify Gruppenrabatt IS counted as API-applied discount $apiAppliedDiscounts = $response->getApiAppliedDiscounts(); self::assertCount(1, $apiAppliedDiscounts); $gruppenrabatt = array_values($apiAppliedDiscounts)[0]; self::assertEquals('ERM', $gruppenrabatt->type); self::assertEquals('GRU', $gruppenrabatt->subType); self::assertEquals('Gruppenrabatt', $gruppenrabatt->label); self::assertEquals(-90.0, $gruppenrabatt->totalPrice); self::assertEquals(90.0, $response->getApiAppliedDiscountTotal()); } public function testParseBookingResponseWithGruppenrabattAndVouchers(): void { $xmlContent = ' möglich 321530 430,00 '; $crawler = new Crawler($xmlContent); $response = $this->parser->parse($crawler->filter('ergebnis')); // Voucher discount should only include AKTION self::assertEquals(20.0, $response->getVoucherDiscountFromPrices()); // API-applied discount should only include ERM (Gruppenrabatt) self::assertEquals(50.0, $response->getApiAppliedDiscountTotal()); // Verify they are separate and don't overlap $voucherDiscounts = $response->getVoucherDiscountsFromPrices(); $apiDiscounts = $response->getApiAppliedDiscounts(); self::assertCount(1, $voucherDiscounts); self::assertCount(1, $apiDiscounts); self::assertEquals('AKTION', array_values($voucherDiscounts)[0]->type); self::assertEquals('ERM', array_values($apiDiscounts)[0]->type); } public function testParseBookingResponseWithNoApiAppliedDiscounts(): void { $xmlContent = ' möglich 321530 679,00 '; $crawler = new Crawler($xmlContent); $response = $this->parser->parse($crawler->filter('ergebnis')); // Verify no API-applied discounts self::assertCount(0, $response->getApiAppliedDiscounts()); self::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')); self::assertTrue($response->isInquiryValid()); self::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 self::assertCount(0, $response->getApiAppliedDiscounts()); self::assertEquals(0.0, $response->getApiAppliedDiscountTotal()); // Verify no voucher discounts either self::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(); self::assertCount(1, $apiAppliedDiscounts); $gruppenrabatt = array_values($apiAppliedDiscounts)[0]; self::assertEquals('ERM', $gruppenrabatt->type); self::assertEquals(-100.0, $gruppenrabatt->totalPrice); // Total API-applied discount should only include Gruppenrabatt (100), not transportation (300) self::assertEquals(100.0, $response->getApiAppliedDiscountTotal()); } }