feat: offer non-travelling applicant choice only on selected travels

This commit is contained in:
fromme committed 2026-10-19 09:18:22 +02:00
1 parent 5b75938c73
commit b958d1a371
9 files changed
+320 -26

No files matched your search

@@ -5,10 +5,13 @@ declare(strict_types=1);
namespace App\Tests\Controller\Booking\Create;
use App\BusProNet\Constants;
use App\BusProNet\Model\CrmSelection;
use App\BusProNet\Model\CrmSelectionGroup;
use App\BusProNet\Model\Room;
use App\BusProNet\Model\Travel;
use App\Controller\Booking\Create\Step2Controller;
use App\Form\Model\BookingDto;
use App\Form\Model\ParticipantDto;
use App\Form\Model\RoomSelectionDto;
use App\Model\RoomSelectionAdjustment;
use App\Service\BookingConfigurator;
@@ -181,6 +184,63 @@ class Step2ControllerTest extends TestCase
$this->assertCount(6, $bookingDto->participants, 'Two rooms for three people each yield six participants');
}
public function testEndsASplitTheTravelDateDoesNotOffer(): void
{
$bookingDto = $this->createSplitBookingDto($this->createTravel([$this->createRoom(1409, 'Einzelzimmer', minPax: 1)]));
$applicant = $bookingDto->applicant;
$controller = $this->createControllerForFullRun($bookingDto);
$controller->index(Request::create('/bookings/create/participants', 'GET'));
$this->assertTrue($bookingDto->applicantTravels);
$this->assertNull($bookingDto->applicant);
$this->assertSame($applicant, $bookingDto->participants[0]);
}
public function testKeepsASplitTheTravelDateOffers(): void
{
$travel = $this->createTravel([$this->createRoom(1409, 'Einzelzimmer', minPax: 1)]);
$selection = new CrmSelection();
$selection->id = 1488;
$group = new CrmSelectionGroup();
$group->id = 10;
$group->selections = [$selection];
$travel->selectionGroups = [10 => $group];
$bookingDto = $this->createSplitBookingDto($travel);
$applicant = $bookingDto->applicant;
$controller = $this->createControllerForFullRun($bookingDto);
$controller->index(Request::create('/bookings/create/participants', 'GET'));
$this->assertFalse($bookingDto->applicantTravels);
$this->assertSame($applicant, $bookingDto->applicant);
$this->assertNotSame($applicant, $bookingDto->participants[0]);
}
private function createSplitBookingDto(Travel $travel): BookingDto
{
$bookingDto = $this->createBookingDto($travel);
$bookingDto->roomSelections = [
1409 => $this->createRoomSelection(1409, 'Einzelzimmer', quantity: 1, capacity: 1),
];
$bookingDto->applicantTravels = false;
$bookingDto->applicant = new ParticipantDto();
return $bookingDto;
}
private function createControllerForFullRun(BookingDto $bookingDto): TestableStep2Controller
{
$bookingService = $this->createStub(BookingConfigurator::class);
$bookingService->method('reconcileRoomSelections')->willReturn([]);
$bookingSessionService = $this->createStub(BookingSessionManager::class);
$bookingSessionService->method('getOrCreateBookingCreateDto')->willReturn($bookingDto);
return $this->createController($bookingService, $bookingSessionService, $this->createStub(LoggerInterface::class));
}
private function createController(
BookingConfigurator $bookingService,
BookingSessionManager $bookingSessionService,
@@ -0,0 +1,127 @@
<?php
declare(strict_types=1);
namespace App\Tests\Controller\Booking\Create;
use App\BusProNet\Model\Travel;
use App\Controller\Booking\Create\Step2ParticipantController;
use App\Form\Model\BookingDto;
use App\Form\Model\ParticipantDto;
use App\Service\ApplicantInsuranceCascade;
use App\Service\BookingConfigurator;
use App\Service\BookingCreateContextFactory;
use App\Service\BookingSessionManager;
use App\Service\ParticipantDataPrefiller;
use App\Service\ParticipantFormSupport;
use App\Service\TravelDataProvider;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
class Step2ParticipantControllerTest extends TestCase
{
public function testToggleChangesNothingWhereTheTravelDateDoesNotOfferTheChoice(): void
{
$request = Request::create('/bookings/create/applicant-toggle', 'POST');
$bookingDto = $this->createBookingDto();
$bookingSessionService = $this->createMock(BookingSessionManager::class);
$bookingSessionService->method('getBookingDto')->willReturn($bookingDto);
$bookingSessionService->expects($this->never())->method('saveBookingDto');
$controller = $this->createController($bookingSessionService);
$response = $controller->toggleApplicantTravels($request);
$this->assertInstanceOf(RedirectResponse::class, $response);
$this->assertSame('/app_booking_create_step_2', $response->getTargetUrl());
$this->assertSame(0, $controller->createdForms, 'The submitted choice is never bound');
$this->assertTrue($bookingDto->applicantTravels);
}
public function testApplicantFormIsNotServedWhereTheTravelDateDoesNotOfferTheChoice(): void
{
$request = Request::create('/bookings/create/applicant', 'GET');
$bookingDto = $this->createBookingDto();
$bookingDto->applicantTravels = false;
$bookingDto->applicant = new ParticipantDto();
$bookingSessionService = $this->createMock(BookingSessionManager::class);
$bookingSessionService->method('getBookingDto')->willReturn($bookingDto);
$bookingSessionService->expects($this->never())->method('saveBookingDto');
$controller = $this->createController($bookingSessionService);
$response = $controller->editApplicant($request);
$this->assertInstanceOf(RedirectResponse::class, $response);
$this->assertSame('/app_booking_create_step_2', $response->getTargetUrl());
$this->assertSame(0, $controller->createdForms);
}
private function createBookingDto(): BookingDto
{
$travel = new Travel();
$travel->id = 4711;
$participant = new ParticipantDto();
$participant->index = 0;
$bookingDto = new BookingDto($travel, 1);
$bookingDto->participants = [$participant];
return $bookingDto;
}
private function createController(BookingSessionManager $bookingSessionService): TestableStep2ParticipantController
{
return new TestableStep2ParticipantController(
$this->createStub(BookingConfigurator::class),
$bookingSessionService,
$this->createStub(BookingCreateContextFactory::class),
$this->createStub(TravelDataProvider::class),
$this->createStub(ParticipantDataPrefiller::class),
$this->createStub(ParticipantFormSupport::class),
$this->createStub(ApplicantInsuranceCascade::class),
);
}
}
final class TestableStep2ParticipantController extends Step2ParticipantController
{
public int $createdForms = 0;
/**
* @return FormInterface<mixed>
*/
protected function createForm(string $type, mixed $data = null, array $options = []): FormInterface
{
++$this->createdForms;
throw new \LogicException('No form is expected to be built.');
}
/**
* @param array<string, mixed> $parameters
*/
protected function generateUrl(string $route, array $parameters = [], int $referenceType = UrlGeneratorInterface::ABSOLUTE_PATH): string
{
return '/'.$route;
}
protected function redirect(string $url, int $status = 302): RedirectResponse
{
return new RedirectResponse($url, $status);
}
/**
* @param array<string, mixed> $parameters
*/
protected function redirectToRoute(string $route, array $parameters = [], int $status = 302): RedirectResponse
{
return new RedirectResponse('/'.$route, $status);
}
}