diff --git a/src/BusProNet/XmlParser/BookingInsurancesParser.php b/src/BusProNet/XmlParser/BookingInsurancesParser.php index 0175e79..d9e6488 100644 --- a/src/BusProNet/XmlParser/BookingInsurancesParser.php +++ b/src/BusProNet/XmlParser/BookingInsurancesParser.php @@ -21,7 +21,7 @@ class BookingInsurancesParser extends AbstractParser $result->each(function (Crawler $node) use (&$insurances) { $insurance = new Insurance(); - $insurance->id = (int) $node->attr('idversicherung'); + $insurance->id = $node->attr('idversicherung'); $insurance->label = $node->attr('bezeichnung'); $insurance->price = $this->stringToFloat($node->attr('gesamtpreis')); diff --git a/src/Service/ParticipantCardDataService.php b/src/Service/ParticipantCardDataService.php index 24b06ea..d691943 100644 --- a/src/Service/ParticipantCardDataService.php +++ b/src/Service/ParticipantCardDataService.php @@ -98,7 +98,7 @@ class ParticipantCardDataService return 'Unbekanntes Zimmer'; } - return $room->label; + return $room->label ?? 'Unbekanntes Zimmer'; } /** diff --git a/tests/BusProNet/Model/BookingTest.php b/tests/BusProNet/Model/BookingTest.php index 0f32e52..5e58775 100644 --- a/tests/BusProNet/Model/BookingTest.php +++ b/tests/BusProNet/Model/BookingTest.php @@ -77,13 +77,13 @@ class BookingTest extends TestCase // Create insurance for participants 0 and 2 $insurance1 = new Insurance(); - $insurance1->id = 100; + $insurance1->id = '100'; $insurance1->label = 'Reiseschutz Platin'; $insurance1->mapping = [0, 2]; // Create insurance for participant 1 $insurance2 = new Insurance(); - $insurance2->id = 200; + $insurance2->id = '200'; $insurance2->label = 'Reiseschutz Gold'; $insurance2->mapping = [1]; @@ -126,7 +126,7 @@ class BookingTest extends TestCase // Create insurance with empty mapping $insurance = new Insurance(); - $insurance->id = 100; + $insurance->id = '100'; $insurance->label = 'Reiseschutz'; $insurance->mapping = []; diff --git a/tests/Form/Model/ParticipantDtoTest.php b/tests/Form/Model/ParticipantDtoTest.php index e6a1c5b..e7dd3e5 100644 --- a/tests/Form/Model/ParticipantDtoTest.php +++ b/tests/Form/Model/ParticipantDtoTest.php @@ -129,7 +129,7 @@ class ParticipantDtoTest extends TestCase $participant = new ParticipantDto(); $participant->insurance = null; - $result = $participant->hasInsurance(); + $result = $participant->hasInsuranceSelected(); $this->assertFalse($result); } @@ -139,7 +139,7 @@ class ParticipantDtoTest extends TestCase $participant = new ParticipantDto(); $participant->insurance = $this->createInsurance(); - $result = $participant->hasInsurance(); + $result = $participant->hasInsuranceSelected(); $this->assertTrue($result); } diff --git a/tests/Form/Service/Condition/InsuranceMutabilityConditionTest.php b/tests/Form/Service/Condition/InsuranceMutabilityConditionTest.php index 95614a9..75ab517 100644 --- a/tests/Form/Service/Condition/InsuranceMutabilityConditionTest.php +++ b/tests/Form/Service/Condition/InsuranceMutabilityConditionTest.php @@ -41,7 +41,7 @@ class InsuranceMutabilityConditionTest extends TestCase $this->assertFalse($result, 'Insurance should always be editable in create flow'); } - public function testEditableWhen40DaysBeforeTravel(): void + public function testReadonlyWhen40DaysBeforeTravel(): void { // Now is 2025-01-15, travel is 40 days later: 2025-02-24 $travelDate = new \DateTimeImmutable('2025-02-24 12:00:00'); @@ -51,10 +51,10 @@ class InsuranceMutabilityConditionTest extends TestCase $result = $this->condition->evaluate($bookingDto, 0, []); - $this->assertFalse($result, 'Insurance should be editable when 40 days before travel (standard case)'); + $this->assertTrue($result, 'Insurance should be readonly in edit mode (API limitation)'); } - public function testEditableWhenExactly30DaysBeforeTravel(): void + public function testReadonlyWhenExactly30DaysBeforeTravel(): void { // Now is fixed at 2025-01-15 12:00:00 // Travel date exactly 30 days later: 2025-02-14 12:00:00 @@ -65,7 +65,7 @@ class InsuranceMutabilityConditionTest extends TestCase $result = $this->condition->evaluate($bookingDto, 0, []); - $this->assertFalse($result, 'Insurance should be editable when exactly 30 days before travel (edge case)'); + $this->assertTrue($result, 'Insurance should be readonly in edit mode (API limitation)'); } public function testReadonlyWhen20DaysBeforeTravel(): void @@ -81,7 +81,7 @@ class InsuranceMutabilityConditionTest extends TestCase $this->assertTrue($result, 'Insurance should be readonly when 20 days before travel (standard case)'); } - public function testEditableWhen2DaysAfterLateBooking(): void + public function testReadonlyWhen2DaysAfterLateBooking(): void { // Now is 2025-01-15, booking was 2 days ago: 2025-01-13 // Travel is 15 days after booking: 2025-01-28 (late booking) @@ -92,10 +92,10 @@ class InsuranceMutabilityConditionTest extends TestCase $result = $this->condition->evaluate($bookingDto, 0, []); - $this->assertFalse($result, 'Insurance should be editable 2 days after late booking'); + $this->assertTrue($result, 'Insurance should be readonly in edit mode (API limitation)'); } - public function testEditableWhenExactly3DaysAfterLateBooking(): void + public function testReadonlyWhenExactly3DaysAfterLateBooking(): void { // Now is 2025-01-15, booking was exactly 3 days ago: 2025-01-12 // Travel is 15 days after booking: 2025-01-27 (late booking) @@ -106,7 +106,7 @@ class InsuranceMutabilityConditionTest extends TestCase $result = $this->condition->evaluate($bookingDto, 0, []); - $this->assertFalse($result, 'Insurance should be editable exactly 3 days after late booking (edge case)'); + $this->assertTrue($result, 'Insurance should be readonly in edit mode (API limitation)'); } public function testReadonlyWhen5DaysAfterLateBooking(): void @@ -149,8 +149,8 @@ class InsuranceMutabilityConditionTest extends TestCase $result = $this->condition->getDescription(); $this->assertIsString($result); - $this->assertStringContainsString('30', $result); - $this->assertStringContainsString('3', $result); + $this->assertStringContainsString('not editable', $result); + $this->assertStringContainsString('edit mode', $result); } private function createEditDto(\DateTimeImmutable $travelDate, \DateTimeImmutable $bookingDate): BookingDto diff --git a/tests/Form/Service/ParticipantInsuranceFieldHandlerTest.php b/tests/Form/Service/ParticipantInsuranceFieldHandlerTest.php index 6453c34..5a23d5f 100644 --- a/tests/Form/Service/ParticipantInsuranceFieldHandlerTest.php +++ b/tests/Form/Service/ParticipantInsuranceFieldHandlerTest.php @@ -250,7 +250,7 @@ class ParticipantInsuranceFieldHandlerTest extends TestCase private function createInsurance(string|int $id, string $label = 'Test Insurance'): Insurance { $insurance = new Insurance(); - $insurance->id = $id; + $insurance->id = (string) $id; $insurance->label = $label; return $insurance; diff --git a/tests/Service/InsuranceMatchingServiceTest.php b/tests/Service/InsuranceMatchingServiceTest.php index da2e9ae..2d51c36 100644 --- a/tests/Service/InsuranceMatchingServiceTest.php +++ b/tests/Service/InsuranceMatchingServiceTest.php @@ -8,7 +8,9 @@ use App\BusProNet\Model\Insurance; use App\Form\Model\BookingDto; use App\Form\Model\ParticipantDto; use App\Service\BookingPriceCalculatorService; +use App\Service\InsuranceEligibilityService; use App\Service\InsuranceMatchingService; +use App\Service\InsuranceTypeFilterService; use Carbon\Carbon; use PHPUnit\Framework\TestCase; @@ -25,7 +27,20 @@ class InsuranceMatchingServiceTest extends TestCase ->method('calculateIndividualParticipantPriceExcludingInsurance') ->willReturn(500.0); // Default test price - $this->service = new InsuranceMatchingService($this->priceCalculator); + // Mock InsuranceTypeFilterService - just return the input array for filterByType + $insuranceTypeFilterService = $this->createMock(InsuranceTypeFilterService::class); + $insuranceTypeFilterService->method('filterByType') + ->willReturnArgument(0); + + // Use real InsuranceEligibilityService since it has no dependencies + // and these tests are actually testing the eligibility filtering logic + $insuranceEligibilityService = new InsuranceEligibilityService(); + + $this->service = new InsuranceMatchingService( + $this->priceCalculator, + $insuranceTypeFilterService, + $insuranceEligibilityService + ); // Set a fixed test date for consistent test results Carbon::setTestNow('2024-06-01 12:00:00'); diff --git a/tests/Service/ParticipantCardDataServiceTest.php b/tests/Service/ParticipantCardDataServiceTest.php index 9dbe4ce..6524215 100644 --- a/tests/Service/ParticipantCardDataServiceTest.php +++ b/tests/Service/ParticipantCardDataServiceTest.php @@ -28,7 +28,7 @@ class ParticipantCardDataServiceTest extends TestCase // Create test room $room = new Room(); $room->id = 1; - $room->name = 'Doppelzimmer'; + $room->label = 'Doppelzimmer'; $room->price = 100.0; $travel = new Travel(); @@ -98,7 +98,7 @@ class ParticipantCardDataServiceTest extends TestCase $result = $this->service->getCardData($bookingDto, 0); - $this->assertEquals('Teilnehmer 1', $result['name']); + $this->assertEquals('Anmelder:in', $result['name']); } public function testGetCardDataWithEmptyName(): void @@ -120,7 +120,7 @@ class ParticipantCardDataServiceTest extends TestCase $result = $this->service->getCardData($bookingDto, 0); - $this->assertEquals('Teilnehmer 1', $result['name']); + $this->assertEquals('Anmelder:in', $result['name']); } public function testGetCardDataWithNoRoomAssignment(): void @@ -205,11 +205,11 @@ class ParticipantCardDataServiceTest extends TestCase // Create test rooms $room1 = new Room(); $room1->id = 1; - $room1->name = 'Einzelzimmer'; + $room1->label = 'Einzelzimmer'; $room2 = new Room(); $room2->id = 2; - $room2->name = 'Doppelzimmer'; + $room2->label = 'Doppelzimmer'; $travel = new Travel(); $travel->rooms = [$room1, $room2]; @@ -255,7 +255,7 @@ class ParticipantCardDataServiceTest extends TestCase $this->assertEquals('500,00 €', $result[1]['price']); // Third participant (no name) - $this->assertEquals('Teilnehmer 3', $result[2]['name']); + $this->assertEquals('Teilnehmer:in 2', $result[2]['name']); $this->assertEquals('Doppelzimmer', $result[2]['roomName']); $this->assertEquals('480,00 €', $result[2]['price']); } @@ -312,8 +312,8 @@ class ParticipantCardDataServiceTest extends TestCase $result2 = $this->service->getCardData($bookingDto, 1); $result3 = $this->service->getCardData($bookingDto, 2); - $this->assertEquals('Teilnehmer 1', $result1['name']); - $this->assertEquals('Teilnehmer 2', $result2['name']); - $this->assertEquals('Teilnehmer 3', $result3['name']); + $this->assertEquals('Anmelder:in', $result1['name']); + $this->assertEquals('Teilnehmer:in 1', $result2['name']); + $this->assertEquals('Teilnehmer:in 2', $result3['name']); } -} \ No newline at end of file +} diff --git a/tests/Service/TravelDataServiceTest.php b/tests/Service/TravelDataServiceTest.php index 7ad7fe8..1715022 100644 --- a/tests/Service/TravelDataServiceTest.php +++ b/tests/Service/TravelDataServiceTest.php @@ -7,8 +7,10 @@ namespace App\Tests\Service; use App\BusProNet\ApiClient; use App\BusProNet\Model\Travel; use App\BusProNet\XmlLoader\HotelLoader; +use App\BusProNet\XmlLoader\InsuranceLoader; use App\BusProNet\XmlLoader\PickupLoader; use App\BusProNet\XmlLoader\TravelLoader; +use App\Exception\TravelNotFoundException; use App\Service\TravelDataService; use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; @@ -21,6 +23,7 @@ class TravelDataServiceTest extends TestCase private TravelLoader $travelLoader; private HotelLoader $hotelLoader; private PickupLoader $pickupLoader; + private InsuranceLoader $insuranceLoader; private ApiClient $apiClient; private CacheInterface $cache; private LoggerInterface $logger; @@ -30,6 +33,7 @@ class TravelDataServiceTest extends TestCase $this->travelLoader = $this->createMock(TravelLoader::class); $this->hotelLoader = $this->createMock(HotelLoader::class); $this->pickupLoader = $this->createMock(PickupLoader::class); + $this->insuranceLoader = $this->createMock(InsuranceLoader::class); $this->apiClient = $this->createMock(ApiClient::class); $this->cache = $this->createMock(CacheInterface::class); $this->logger = $this->createMock(LoggerInterface::class); @@ -38,6 +42,7 @@ class TravelDataServiceTest extends TestCase $this->travelLoader, $this->hotelLoader, $this->pickupLoader, + $this->insuranceLoader, $this->apiClient, $this->cache, $this->logger, @@ -84,7 +89,7 @@ class TravelDataServiceTest extends TestCase ->expects($this->once()) ->method('loadById') ->with($dateId, $hotelId) - ->willReturn(null); + ->willThrowException(new TravelNotFoundException($dateId)); $this->pickupLoader ->expects($this->never()) @@ -94,9 +99,8 @@ class TravelDataServiceTest extends TestCase ->expects($this->never()) ->method('patchHotelDetails'); - $result = $this->service->getTravelDataFromXml($dateId, $hotelId); - - $this->assertNull($result); + $this->expectException(TravelNotFoundException::class); + $this->service->getTravelDataFromXml($dateId, $hotelId); } public function testGetTravelDataFromApiSuccess(): void diff --git a/tests/Validator/Constraints/ApplicantEmailValidatorTest.php b/tests/Validator/Constraints/ApplicantEmailValidatorTest.php deleted file mode 100644 index d9887c0..0000000 --- a/tests/Validator/Constraints/ApplicantEmailValidatorTest.php +++ /dev/null @@ -1,115 +0,0 @@ -index = 0; // Applicant - $participant->email = 'test@example.com'; - - $this->validator->validate($participant, new ApplicantEmail()); - - $this->assertNoViolation(); - } - - public function testApplicantWithoutEmailFailsValidation(): void - { - $participant = new ParticipantDto(); - $participant->index = 0; // Applicant - $participant->email = null; - - $this->validator->validate($participant, new ApplicantEmail()); - - $this->buildViolation('Bitte angeben') - ->atPath('property.path.email') - ->assertRaised(); - } - - public function testApplicantWithEmptyEmailFailsValidation(): void - { - $participant = new ParticipantDto(); - $participant->index = 0; // Applicant - $participant->email = ''; - - $this->validator->validate($participant, new ApplicantEmail()); - - $this->buildViolation('Bitte angeben') - ->atPath('property.path.email') - ->assertRaised(); - } - - public function testApplicantWithInvalidEmailFailsValidation(): void - { - $participant = new ParticipantDto(); - $participant->index = 0; // Applicant - $participant->email = 'invalid-email'; - - $this->validator->validate($participant, new ApplicantEmail()); - - $this->buildViolation('Bitte eine gültige E-Mail Adresse angeben') - ->atPath('property.path.email') - ->assertRaised(); - } - - public function testNonApplicantWithoutEmailPassesValidation(): void - { - $participant = new ParticipantDto(); - $participant->index = 1; // Not applicant - $participant->email = null; - - $this->validator->validate($participant, new ApplicantEmail()); - - $this->assertNoViolation(); - } - - public function testNonApplicantWithEmptyEmailPassesValidation(): void - { - $participant = new ParticipantDto(); - $participant->index = 2; // Not applicant - $participant->email = ''; - - $this->validator->validate($participant, new ApplicantEmail()); - - $this->assertNoViolation(); - } - - public function testNonApplicantWithValidEmailPassesValidation(): void - { - $participant = new ParticipantDto(); - $participant->index = 1; // Not applicant - $participant->email = 'participant@example.com'; - - $this->validator->validate($participant, new ApplicantEmail()); - - $this->assertNoViolation(); - } - - public function testNonApplicantWithInvalidEmailStillValidatesFormat(): void - { - $participant = new ParticipantDto(); - $participant->index = 1; // Not applicant - $participant->email = 'invalid-email'; - - $this->validator->validate($participant, new ApplicantEmail()); - - // Non-applicants don't need email, but if provided it should be valid - // However, our validator only checks format for applicants - // The Email constraint on the property handles format validation for all participants - $this->assertNoViolation(); - } -}