merger = new BookingEditDraftMerger(new ServiceAvailabilityCalculator()); } public function testDraftDropsSkiPassThatIsNowOnRequest(): void { $skiPass = $this->createSkiPass(60, 'Skipass 6 Tage', Constants::STATUS_ON_REQUEST); $travel = $this->createTravel([60 => $skiPass]); $participant = new ParticipantDto(); $participant->mutable = true; $dropped = $this->apply($travel, $participant, ['skiPass' => 60], new Booking()); $this->assertNull($participant->skiPass); $this->assertSame(['Skipass 6 Tage'], $dropped); } public function testDraftRestoresSkiPassThatIsStillFree(): void { $skiPass = $this->createSkiPass(60, 'Skipass 6 Tage'); $travel = $this->createTravel([60 => $skiPass]); $participant = new ParticipantDto(); $participant->mutable = true; $dropped = $this->apply($travel, $participant, ['skiPass' => 60], new Booking()); $this->assertSame(60, $participant->skiPass?->id); $this->assertSame([], $dropped); } public function testDraftRestoresOnRequestSkiPassTheParticipantAlreadyHolds(): void { $skiPass = $this->createSkiPass(60, 'Skipass 6 Tage', Constants::STATUS_ON_REQUEST); $travel = $this->createTravel([60 => $skiPass]); $held = clone $skiPass; $held->mapping = [1]; $booking = new Booking(); $booking->additionalServices = [60 => $held]; $participant = new ParticipantDto(); $participant->mutable = true; $dropped = $this->apply($travel, $participant, ['skiPass' => 60], $booking); $this->assertSame(60, $participant->skiPass?->id); $this->assertSame([], $dropped); } public function testDraftDropsOnlyTheUnbookableEntryOfAMultiSelectField(): void { $bookable = $this->createCourse(70, 'Snowboardkurs'); $onRequest = $this->createCourse(71, 'Skikurs', Constants::STATUS_ON_REQUEST); $travel = $this->createTravel([70 => $bookable, 71 => $onRequest]); $participant = new ParticipantDto(); $participant->mutable = true; $dropped = $this->apply($travel, $participant, ['courses' => [70, 71]], new Booking()); $this->assertSame([70], array_map(static fn (Service $s) => $s->id, $participant->courses)); $this->assertSame(['Skikurs'], $dropped); } /** * @param array $services * * @return list */ private function apply(Travel $travel, ParticipantDto $participant, array $services, Booking $booking): array { $dto = new BookingDto($travel, 1); $dto->participants = [1 => $participant]; // A non-null booking is what puts the DTO into edit mode $dto->booking = $booking; return $this->merger->apply($dto, 1, $participant, ['services' => $services], $travel); } /** @param array $additionalServices */ private function createTravel(array $additionalServices): Travel { $travel = new Travel(); $travel->additionalServices = $additionalServices; $travel->additionalServicesMutable = true; return $travel; } private function createSkiPass(int $id, string $label, string $status = Constants::STATUS_AVAILABLE): Service { return $this->createService($id, $label, Constants::TOKEN_SKI_PASS, $status); } private function createCourse(int $id, string $label, string $status = Constants::STATUS_AVAILABLE): Service { return $this->createService($id, $label, Constants::TOKEN_COURSES, $status); } private function createService(int $id, string $label, string $subType, string $status): Service { $service = new Service(); $service->id = $id; $service->label = $label; $service->subType = $subType; $service->status = $status; $service->category = Constants::CATEGORY_ADDITIONAL; return $service; } }