createMock(ServiceAvailabilityCalculator::class); $insuranceService = $this->createMock(InsuranceService::class); $priceCalculatorService = $this->createMock(BookingPriceCalculatorService::class); $translator = $this->createMock(TranslatorInterface::class); $this->provider = new ParticipantFieldOptionsProvider( $serviceAvailabilityCalculator, $insuranceService, $priceCalculatorService, $translator ); } public function testMandatoryServiceSelectedHasReadonlyAndTooltip(): void { $mandatoryService = $this->createMandatoryService(1, 'Ortstaxe'); $travel = $this->createTravelWithAdditionalServices([$mandatoryService]); $bookingDto = new BookingDto($travel, 1); $participant = new ParticipantDto(); $participant->index = 0; $participant->dateOfBirth = $travel->dateFrom->modify('-25 years'); $participant->additionalServices = [$mandatoryService]; $bookingDto->participants[0] = $participant; $options = $this->provider->getFieldOptions('additionalServices', $bookingDto, 0); $choiceAttr = $options['choice_attr']; $attributes = $choiceAttr($mandatoryService); $this->assertTrue($attributes['readonly']); $this->assertSame('Diese Leistung ist nicht abwählbar', $attributes['data-tooltip']); $this->assertArrayNotHasKey('checked', $attributes); } public function testMandatoryServiceNotSelectedHasNoReadonlyOrChecked(): void { $mandatoryService = $this->createMandatoryService(1, 'Ortstaxe'); $travel = $this->createTravelWithAdditionalServices([$mandatoryService]); $bookingDto = new BookingDto($travel, 1); $participant = new ParticipantDto(); $participant->index = 0; $participant->dateOfBirth = $travel->dateFrom->modify('-25 years'); $participant->additionalServices = []; $bookingDto->participants[0] = $participant; $options = $this->provider->getFieldOptions('additionalServices', $bookingDto, 0); $choiceAttr = $options['choice_attr']; $attributes = $choiceAttr($mandatoryService); $this->assertArrayNotHasKey('readonly', $attributes); $this->assertArrayNotHasKey('checked', $attributes); $this->assertArrayNotHasKey('data-tooltip', $attributes); } public function testNonMandatoryServiceUnaffected(): void { $nonMandatoryService = new Service(); $nonMandatoryService->id = 2; $nonMandatoryService->label = 'Keycard-Pfand'; $nonMandatoryService->subType = Constants::TOKEN_ADDITIONAL; $nonMandatoryService->available = 10; $nonMandatoryService->price = 10.0; $nonMandatoryService->mandatory = false; $nonMandatoryService->autoBook = true; $travel = $this->createTravelWithAdditionalServices([$nonMandatoryService]); $bookingDto = new BookingDto($travel, 1); $participant = new ParticipantDto(); $participant->index = 0; $participant->dateOfBirth = $travel->dateFrom->modify('-25 years'); $participant->additionalServices = [$nonMandatoryService]; $bookingDto->participants[0] = $participant; $options = $this->provider->getFieldOptions('additionalServices', $bookingDto, 0); $choiceAttr = $options['choice_attr']; $attributes = $choiceAttr($nonMandatoryService); $this->assertArrayNotHasKey('readonly', $attributes); $this->assertArrayNotHasKey('checked', $attributes); } public function testNullParticipantReturnsEmptyOptions(): void { $mandatoryService = $this->createMandatoryService(1, 'Ortstaxe'); $travel = $this->createTravelWithAdditionalServices([$mandatoryService]); $bookingDto = new BookingDto($travel, 1); // Do not set participant — age filtering cannot determine choices, returns empty $options = $this->provider->getFieldOptions('additionalServices', $bookingDto, 0); $this->assertEmpty($options); } private function createMandatoryService(int $id, string $label): Service { $service = new Service(); $service->id = $id; $service->label = $label; $service->subType = Constants::TOKEN_ADDITIONAL; $service->available = 10; $service->price = 5.0; $service->mandatory = true; return $service; } private function createTravelWithAdditionalServices(array $services): Travel { $travel = new Travel(); $travel->dateFrom = new \DateTimeImmutable('+30 days'); $travel->dateTo = new \DateTimeImmutable('+37 days'); $indexed = []; foreach ($services as $service) { $indexed[$service->id] = $service; } $travel->additionalServices = $indexed; return $travel; } }