createStub(TranslatorInterface::class); $translator->method('trans')->willReturnArgument(0); $this->provider = new ParticipantFieldOptionsProvider( new ServiceAvailabilityCalculator(), $this->createStub(InsuranceManager::class), $this->createStub(BookingPriceCalculator::class), new ServiceLabelFormatter(), $translator ); } public function testSoldOutSkiPassIsNotRendered(): void { $bookingDto = $this->createBookingDto([ $this->createSkiPass(id: 1, available: null), $this->createSkiPass(id: 2, available: 0), ]); $this->assertSame([1], $this->getSkiPassChoiceIds($bookingDto)); } public function testSkiPassOnBookingStopIsNotRendered(): void { $bookingDto = $this->createBookingDto([ $this->createSkiPass(id: 1, available: null), $this->createSkiPass(id: 2, available: 20, status: Constants::STATUS_BLOCKED), ]); $this->assertSame([1], $this->getSkiPassChoiceIds($bookingDto)); } public function testSkiPassClaimedByOtherParticipantIsNotRendered(): void { $limitedSkiPass = $this->createSkiPass(id: 2, available: 1); $bookingDto = $this->createBookingDto([ $this->createSkiPass(id: 1, available: null), $limitedSkiPass, ]); $otherParticipant = new ParticipantDto(); $otherParticipant->index = 1; $otherParticipant->dateOfBirth = new \DateTimeImmutable('1990-01-01'); $otherParticipant->skiPass = $limitedSkiPass; $bookingDto->participants[1] = $otherParticipant; $this->assertSame([1], $this->getSkiPassChoiceIds($bookingDto)); } public function testSelectedSkiPassStaysRenderedWhenItSoldOut(): void { $soldOutSkiPass = $this->createSkiPass(id: 2, available: 0); $bookingDto = $this->createBookingDto([ $this->createSkiPass(id: 1, available: null), $soldOutSkiPass, ]); $bookingDto->participants[0]->skiPass = $soldOutSkiPass; $this->assertSame([1, 2], $this->getSkiPassChoiceIds($bookingDto)); } public function testBookedSkiPassStaysRenderedAfterSwitchingToAnotherPassInEditMode(): void { $blockedSkiPass = $this->createSkiPass(id: 2, available: null, status: Constants::STATUS_BLOCKED); $bookableSkiPass = $this->createSkiPass(id: 1, available: null); $bookingDto = $this->createBookingDto([$bookableSkiPass, $blockedSkiPass]); $bookedSkiPass = clone $blockedSkiPass; $bookedSkiPass->mapping = [0]; $booking = new Booking(); $booking->additionalServices = [2 => $bookedSkiPass]; $bookingDto->booking = $booking; // The participant already moved away from the booked pass - it still has to be offered // so the switch stays reversible $bookingDto->participants[0]->skiPass = $bookableSkiPass; $this->assertSame(BookingDto::MODE_EDIT, $bookingDto->getMode()); $this->assertSame([1, 2], $this->getSkiPassChoiceIds($bookingDto)); } public function testRenderedSkiPassesCarryNoSoldOutTooltip(): void { $soldOutSkiPass = $this->createSkiPass(id: 2, available: 0); $bookingDto = $this->createBookingDto([ $this->createSkiPass(id: 1, available: null), $soldOutSkiPass, ]); $bookingDto->participants[0]->skiPass = $soldOutSkiPass; $options = $this->provider->getFieldOptions('skiPass', $bookingDto, 0); $choiceAttr = $options['choice_attr']; foreach ($options['choices'] as $choice) { $attributes = $choiceAttr($choice); $this->assertArrayNotHasKey('readonly', $attributes); $this->assertArrayNotHasKey('data-tooltip', $attributes); } } public function testTravelWithoutSkiPassesRendersNoField(): void { $bookingDto = $this->createBookingDto([]); $this->assertSame( [], $this->provider->getFieldOptions('skiPass', $bookingDto, 0), 'The field has to be absent entirely, not rendered with an empty choice list' ); } /** @return int[] */ private function getSkiPassChoiceIds(BookingDto $bookingDto): array { $options = $this->provider->getFieldOptions('skiPass', $bookingDto, 0); if (true === empty($options)) { return []; } $choiceIds = array_map(static fn (Service $service): ?int => $service->id, $options['choices']); sort($choiceIds); return $choiceIds; } /** @param Service[] $skiPasses */ private function createBookingDto(array $skiPasses): BookingDto { $travel = new Travel(); $travel->dateFrom = new \DateTimeImmutable('2027-01-09'); $travel->dateTo = new \DateTimeImmutable('2027-01-16'); foreach ($skiPasses as $skiPass) { $travel->additionalServices[$skiPass->id] = $skiPass; } $bookingDto = new BookingDto($travel, 1); $participant = new ParticipantDto(); $participant->index = 0; $participant->dateOfBirth = new \DateTimeImmutable('1990-01-01'); $bookingDto->participants[0] = $participant; return $bookingDto; } private function createSkiPass(int $id, ?int $available, string $status = Constants::STATUS_AVAILABLE): Service { $service = new Service(); $service->id = $id; $service->label = sprintf('Skipass %d', $id); $service->subType = Constants::TOKEN_SKI_PASS; $service->price = (float) $id; $service->available = $available; $service->status = $status; return $service; } }