feat: move prepopulation guards into participant service
This commit is contained in:
@@ -19,6 +19,8 @@ The codebase is already in a better place than it was at the start of the refact
|
|||||||
|
|
||||||
- `BookingService` no longer owns session lifecycle, baseline snapshot handling, return URL management, or room grouping. That work now lives in `BookingSessionService` and `BookingRoomSelectionService`, which keeps the booking orchestration boundary narrower.
|
- `BookingService` no longer owns session lifecycle, baseline snapshot handling, return URL management, or room grouping. That work now lives in `BookingSessionService` and `BookingRoomSelectionService`, which keeps the booking orchestration boundary narrower.
|
||||||
- `BookingService` still covers hydration, booking bootstrap, service preselection, and booking status rules.
|
- `BookingService` still covers hydration, booking bootstrap, service preselection, and booking status rules.
|
||||||
|
- `BookingParticipantCountService` now handles only participant count shaping.
|
||||||
|
- `ParticipantPrepopulationService` now owns applicant prefill plus the create-mode dummy-data shortcut.
|
||||||
- `BookingPriceCalculatorService` is focused on pricing, but it still sits close to display-oriented behavior in adjacent code paths.
|
- `BookingPriceCalculatorService` is focused on pricing, but it still sits close to display-oriented behavior in adjacent code paths.
|
||||||
- `TravelDataService` remains broad and is likely the next larger boundary after booking orchestration is reduced.
|
- `TravelDataService` remains broad and is likely the next larger boundary after booking orchestration is reduced.
|
||||||
|
|
||||||
@@ -104,7 +106,7 @@ Likely directions, only if justified later:
|
|||||||
|------|--------|-------|
|
|------|--------|-------|
|
||||||
| Participant card DTO cleanup | Done | Card data now uses typed DTOs instead of nested array payloads |
|
| Participant card DTO cleanup | Done | Card data now uses typed DTOs instead of nested array payloads |
|
||||||
| Room label formatting cleanup | Done | Pricing labels now have a dedicated presentation helper |
|
| Room label formatting cleanup | Done | Pricing labels now have a dedicated presentation helper |
|
||||||
| Booking service split | In progress | Session lifecycle, baseline snapshot, return URL handling, room grouping, and participant count shaping moved out of `BookingService` |
|
| Booking service split | In progress | Session lifecycle, baseline snapshot, return URL handling, room grouping, and participant count shaping moved out of `BookingService`; dummy prefill moved into `ParticipantPrepopulationService` |
|
||||||
| Pricing service review | Pending | Keep focused on calculation, not rendering |
|
| Pricing service review | Pending | Keep focused on calculation, not rendering |
|
||||||
| Travel data service review | Pending | Broad boundary, likely later pass |
|
| Travel data service review | Pending | Broad boundary, likely later pass |
|
||||||
| Participant field registry review | Deferred | Real orchestration boundary, intentionally left alone for now |
|
| Participant field registry review | Deferred | Real orchestration boundary, intentionally left alone for now |
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Controller\Booking\Create;
|
namespace App\Controller\Booking\Create;
|
||||||
|
|
||||||
|
use App\Entity\User;
|
||||||
use App\Controller\Booking\Traits\BookingCreateTrait;
|
use App\Controller\Booking\Traits\BookingCreateTrait;
|
||||||
use App\Controller\Booking\Traits\BookingExceptionHandlerTrait;
|
use App\Controller\Booking\Traits\BookingExceptionHandlerTrait;
|
||||||
use App\Form\BookingCreateStep2Type;
|
use App\Form\BookingCreateStep2Type;
|
||||||
@@ -65,12 +66,18 @@ class Step2Controller extends AbstractController
|
|||||||
// Enrich with fresh availability data
|
// Enrich with fresh availability data
|
||||||
$this->travelDataService->enrichWithFreshAvailabilities($bookingCreateDto->travel);
|
$this->travelDataService->enrichWithFreshAvailabilities($bookingCreateDto->travel);
|
||||||
|
|
||||||
// Ensure correct number of participants with prepopulation callback
|
// Ensure correct number of participants first, then prepopulate the applicant if needed.
|
||||||
$this->participantCountService->ensureCorrectNumberOfParticipants(
|
$this->participantCountService->ensureCorrectNumberOfParticipants($bookingCreateDto);
|
||||||
$bookingCreateDto,
|
|
||||||
$this->getUser(),
|
$user = $this->getUser();
|
||||||
fn ($user, $participant) => $this->prepopulationService->prepopulateApplicantFromUser($user, $participant)
|
if ($user instanceof User
|
||||||
);
|
&& isset($bookingCreateDto->participants[0])
|
||||||
|
&& $this->prepopulationService->shouldPrepopulateApplicant($bookingCreateDto->participants[0])) {
|
||||||
|
$bookingCreateDto->participants[0] = $this->prepopulationService->prepopulateApplicantFromUser(
|
||||||
|
$user,
|
||||||
|
$bookingCreateDto->participants[0]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Validate room assignments against current selection (handles back-navigation from step 2 to step 1)
|
// Validate room assignments against current selection (handles back-navigation from step 2 to step 1)
|
||||||
$this->roomAssignmentService->validateAndResetInvalidAssignments($bookingCreateDto);
|
$this->roomAssignmentService->validateAndResetInvalidAssignments($bookingCreateDto);
|
||||||
|
|||||||
@@ -6,12 +6,12 @@ namespace App\Controller\Booking\Create;
|
|||||||
|
|
||||||
use App\Form\BookingParticipantType;
|
use App\Form\BookingParticipantType;
|
||||||
use App\Form\Model\BookingDto;
|
use App\Form\Model\BookingDto;
|
||||||
use App\Form\Service\DummyDataFillService;
|
|
||||||
use App\Htmx\HxTrait;
|
use App\Htmx\HxTrait;
|
||||||
use App\Service\BookingService;
|
use App\Service\BookingService;
|
||||||
use App\Service\BookingSessionService;
|
use App\Service\BookingSessionService;
|
||||||
use App\Service\BookingSummaryDataService;
|
use App\Service\BookingSummaryDataService;
|
||||||
use App\Service\ParticipantFormSupportService;
|
use App\Service\ParticipantFormSupportService;
|
||||||
|
use App\Service\ParticipantPrepopulationService;
|
||||||
use App\Service\TravelDataService;
|
use App\Service\TravelDataService;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\Form\FormInterface;
|
use Symfony\Component\Form\FormInterface;
|
||||||
@@ -31,7 +31,7 @@ class Step2ParticipantController extends AbstractController
|
|||||||
private readonly BookingSessionService $bookingSessionService,
|
private readonly BookingSessionService $bookingSessionService,
|
||||||
private readonly BookingSummaryDataService $summaryDataService,
|
private readonly BookingSummaryDataService $summaryDataService,
|
||||||
private readonly TravelDataService $travelDataService,
|
private readonly TravelDataService $travelDataService,
|
||||||
private readonly DummyDataFillService $dummyDataFillService,
|
private readonly ParticipantPrepopulationService $prepopulationService,
|
||||||
private readonly ParticipantFormSupportService $participantFormSupportService,
|
private readonly ParticipantFormSupportService $participantFormSupportService,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
@@ -62,11 +62,11 @@ class Step2ParticipantController extends AbstractController
|
|||||||
$isSubmitted = $form->isSubmitted();
|
$isSubmitted = $form->isSubmitted();
|
||||||
|
|
||||||
$isDummyDataFill = $this
|
$isDummyDataFill = $this
|
||||||
->dummyDataFillService
|
->prepopulationService
|
||||||
->isTokenMatch($bookingDto->participants[$index], $bookingDto->getMode())
|
->isDummyDataFillRequested($bookingDto->participants[$index], $bookingDto->getMode())
|
||||||
;
|
;
|
||||||
if (true === $isSubmitted && true === $isDummyDataFill) {
|
if (true === $isSubmitted && true === $isDummyDataFill) {
|
||||||
$this->dummyDataFillService->fill($bookingDto->participants[$index], $index);
|
$this->prepopulationService->fillDummyParticipant($bookingDto->participants[$index], $index);
|
||||||
|
|
||||||
$this->bookingService->preselectDefaultServices($bookingDto);
|
$this->bookingService->preselectDefaultServices($bookingDto);
|
||||||
$this->bookingService->applyCreateBookingStatusRules($bookingDto);
|
$this->bookingService->applyCreateBookingStatusRules($bookingDto);
|
||||||
|
|||||||
@@ -1,71 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Form\Service;
|
|
||||||
|
|
||||||
use App\BusProNet\Model\Address;
|
|
||||||
use App\Form\Model\BookingDto;
|
|
||||||
use App\Form\Model\ParticipantDto;
|
|
||||||
use Carbon\CarbonImmutable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fills participant forms with generated dummy data for testing and demo workflows.
|
|
||||||
*
|
|
||||||
* When a special token is entered in the lastName field during booking creation,
|
|
||||||
* this service detects it and fills contact data fields with generated values
|
|
||||||
* based on the participant number and current time. Only active in create mode.
|
|
||||||
*/
|
|
||||||
class DummyDataFillService
|
|
||||||
{
|
|
||||||
public const TOKEN = '#KUN#';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the participant's lastName matches the fill token.
|
|
||||||
*
|
|
||||||
* Only matches in create mode to prevent accidental triggering during
|
|
||||||
* editing of existing bookings.
|
|
||||||
*
|
|
||||||
* @param ParticipantDto $participant The participant to check
|
|
||||||
* @param string $mode The booking mode (create or edit)
|
|
||||||
*
|
|
||||||
* @return bool True if the token matches and mode is create
|
|
||||||
*/
|
|
||||||
public function isTokenMatch(ParticipantDto $participant, string $mode): bool
|
|
||||||
{
|
|
||||||
if (BookingDto::MODE_CREATE !== $mode) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return self::TOKEN === $participant->lastName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fills the participant DTO with generated dummy personal data.
|
|
||||||
*
|
|
||||||
* Generates firstName, lastName, email, mobile, date of birth and address
|
|
||||||
* values based on the participant number (1-based). The lastName includes
|
|
||||||
* the current time for easy identification of test bookings.
|
|
||||||
*
|
|
||||||
* @param ParticipantDto $participant The participant DTO to fill
|
|
||||||
* @param int $participantIndex The zero-based participant index
|
|
||||||
*/
|
|
||||||
public function fill(ParticipantDto $participant, int $participantIndex): void
|
|
||||||
{
|
|
||||||
$participantNumber = $participantIndex + 1;
|
|
||||||
$now = CarbonImmutable::now();
|
|
||||||
|
|
||||||
$participant->firstName = sprintf('Vorname %d', $participantNumber);
|
|
||||||
$participant->lastName = sprintf('Muster %d %s', $participantNumber, $now->format('H:i'));
|
|
||||||
$participant->mobile = '0171/111111';
|
|
||||||
$participant->email = sprintf('teilnehmer.in%[email protected]', $participantNumber);
|
|
||||||
$participant->dateOfBirth = $now->subYears(20)->toImmutable();
|
|
||||||
|
|
||||||
$address = new Address();
|
|
||||||
$address->street = 'Musterstr. 123';
|
|
||||||
$address->postCode = '99999';
|
|
||||||
$address->city = 'MusterOrt';
|
|
||||||
$address->country = 'Deutschland';
|
|
||||||
$participant->address = $address;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,7 +7,6 @@ namespace App\Service;
|
|||||||
use App\BusProNet\Model\Travel;
|
use App\BusProNet\Model\Travel;
|
||||||
use App\Form\Model\BookingDto;
|
use App\Form\Model\BookingDto;
|
||||||
use App\Form\Model\ParticipantDto;
|
use App\Form\Model\ParticipantDto;
|
||||||
use Symfony\Component\Security\Core\User\UserInterface;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keeps participant-count shaping separate from booking orchestration.
|
* Keeps participant-count shaping separate from booking orchestration.
|
||||||
@@ -17,13 +16,9 @@ class BookingParticipantCountService
|
|||||||
/**
|
/**
|
||||||
* Ensures the booking DTO has the expected number of participant objects.
|
* Ensures the booking DTO has the expected number of participant objects.
|
||||||
*
|
*
|
||||||
* @param callable|null $prepopulateCallback fn(UserInterface, ParticipantDto): ParticipantDto
|
|
||||||
*/
|
*/
|
||||||
public function ensureCorrectNumberOfParticipants(
|
public function ensureCorrectNumberOfParticipants(BookingDto $bookingDto): void
|
||||||
BookingDto $bookingDto,
|
{
|
||||||
?UserInterface $user = null,
|
|
||||||
?callable $prepopulateCallback = null,
|
|
||||||
): void {
|
|
||||||
$participantsCount = $this->calculateParticipantsCount($bookingDto->roomSelections, $bookingDto->travel);
|
$participantsCount = $this->calculateParticipantsCount($bookingDto->roomSelections, $bookingDto->travel);
|
||||||
|
|
||||||
$existingParticipants = $bookingDto->participants;
|
$existingParticipants = $bookingDto->participants;
|
||||||
@@ -33,11 +28,6 @@ class BookingParticipantCountService
|
|||||||
$participant = $existingParticipants[$i] ?? new ParticipantDto();
|
$participant = $existingParticipants[$i] ?? new ParticipantDto();
|
||||||
$participant->index = $i;
|
$participant->index = $i;
|
||||||
|
|
||||||
// Prepopulate applicant from authenticated user (index 0 only)
|
|
||||||
if (0 === $i && null !== $user && null !== $prepopulateCallback && $this->shouldPrepopulate($participant)) {
|
|
||||||
$participant = $prepopulateCallback($user, $participant);
|
|
||||||
}
|
|
||||||
|
|
||||||
$bookingDto->participants[$i] = $participant;
|
$bookingDto->participants[$i] = $participant;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -63,12 +53,4 @@ class BookingParticipantCountService
|
|||||||
|
|
||||||
return $participantsCount;
|
return $participantsCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Only prepopulate if the participant is fresh.
|
|
||||||
*/
|
|
||||||
private function shouldPrepopulate(ParticipantDto $participant): bool
|
|
||||||
{
|
|
||||||
return null === $participant->firstName || '' === $participant->firstName;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,13 @@ declare(strict_types=1);
|
|||||||
namespace App\Service;
|
namespace App\Service;
|
||||||
|
|
||||||
use App\BusProNet\ApiClient;
|
use App\BusProNet\ApiClient;
|
||||||
|
use App\BusProNet\Model\Address;
|
||||||
use App\BusProNet\Model\Notification;
|
use App\BusProNet\Model\Notification;
|
||||||
use App\Entity\User;
|
use App\Entity\User;
|
||||||
|
use App\Form\Model\BookingDto;
|
||||||
use App\Form\Model\ParticipantDto;
|
use App\Form\Model\ParticipantDto;
|
||||||
use App\Security\Crypt;
|
use App\Security\Crypt;
|
||||||
|
use Carbon\CarbonImmutable;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -20,6 +23,8 @@ use Psr\Log\LoggerInterface;
|
|||||||
*/
|
*/
|
||||||
class ParticipantPrepopulationService
|
class ParticipantPrepopulationService
|
||||||
{
|
{
|
||||||
|
public const TOKEN = '#KUN#';
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly ApiClient $apiClient,
|
private readonly ApiClient $apiClient,
|
||||||
private readonly Crypt $crypt,
|
private readonly Crypt $crypt,
|
||||||
@@ -94,4 +99,50 @@ class ParticipantPrepopulationService
|
|||||||
return $applicant;
|
return $applicant;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether the applicant should be prepopulated.
|
||||||
|
*
|
||||||
|
* Only prepopulates if the participant is fresh.
|
||||||
|
*/
|
||||||
|
public function shouldPrepopulateApplicant(ParticipantDto $applicant): bool
|
||||||
|
{
|
||||||
|
return null === $applicant->firstName || '' === $applicant->firstName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the participant's last name triggers dummy data fill.
|
||||||
|
*
|
||||||
|
* Only matches in create mode to avoid accidental triggering during edits.
|
||||||
|
*/
|
||||||
|
public function isDummyDataFillRequested(ParticipantDto $participant, string $mode): bool
|
||||||
|
{
|
||||||
|
if (BookingDto::MODE_CREATE !== $mode) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::TOKEN === $participant->lastName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fills the participant DTO with generated dummy personal data.
|
||||||
|
*/
|
||||||
|
public function fillDummyParticipant(ParticipantDto $participant, int $participantIndex): void
|
||||||
|
{
|
||||||
|
$participantNumber = $participantIndex + 1;
|
||||||
|
$now = CarbonImmutable::now();
|
||||||
|
|
||||||
|
$participant->firstName = sprintf('Vorname %d', $participantNumber);
|
||||||
|
$participant->lastName = sprintf('Muster %d %s', $participantNumber, $now->format('H:i'));
|
||||||
|
$participant->mobile = '0171/111111';
|
||||||
|
$participant->email = sprintf('teilnehmer.in%[email protected]', $participantNumber);
|
||||||
|
$participant->dateOfBirth = $now->subYears(20)->toImmutable();
|
||||||
|
|
||||||
|
$address = new Address();
|
||||||
|
$address->street = 'Musterstr. 123';
|
||||||
|
$address->postCode = '99999';
|
||||||
|
$address->city = 'MusterOrt';
|
||||||
|
$address->country = 'Deutschland';
|
||||||
|
$participant->address = $address;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,160 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\Tests\Form\Service;
|
|
||||||
|
|
||||||
use App\Form\Model\BookingDto;
|
|
||||||
use App\Form\Model\ParticipantDto;
|
|
||||||
use App\Form\Service\DummyDataFillService;
|
|
||||||
use Carbon\CarbonImmutable;
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
|
|
||||||
class DummyDataFillServiceTest extends TestCase
|
|
||||||
{
|
|
||||||
private DummyDataFillService $service;
|
|
||||||
|
|
||||||
protected function setUp(): void
|
|
||||||
{
|
|
||||||
$this->service = new DummyDataFillService();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testTokenMatchInCreateMode(): void
|
|
||||||
{
|
|
||||||
$participant = new ParticipantDto();
|
|
||||||
$participant->lastName = DummyDataFillService::TOKEN;
|
|
||||||
|
|
||||||
$this->assertTrue($this->service->isTokenMatch($participant, BookingDto::MODE_CREATE));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testTokenMatchReturnsFalseInEditMode(): void
|
|
||||||
{
|
|
||||||
$participant = new ParticipantDto();
|
|
||||||
$participant->lastName = DummyDataFillService::TOKEN;
|
|
||||||
|
|
||||||
$this->assertFalse($this->service->isTokenMatch($participant, BookingDto::MODE_EDIT));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testNonMatchingLastNameReturnsFalse(): void
|
|
||||||
{
|
|
||||||
$participant = new ParticipantDto();
|
|
||||||
$participant->lastName = 'Schmidt';
|
|
||||||
|
|
||||||
$this->assertFalse($this->service->isTokenMatch($participant, BookingDto::MODE_CREATE));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testNullLastNameReturnsFalse(): void
|
|
||||||
{
|
|
||||||
$participant = new ParticipantDto();
|
|
||||||
$participant->lastName = null;
|
|
||||||
|
|
||||||
$this->assertFalse($this->service->isTokenMatch($participant, BookingDto::MODE_CREATE));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testFillSetsFirstNameWithParticipantNumber(): void
|
|
||||||
{
|
|
||||||
$participant = new ParticipantDto();
|
|
||||||
|
|
||||||
$this->service->fill($participant, 0);
|
|
||||||
|
|
||||||
$this->assertSame('Vorname 1', $participant->firstName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testFillSetsLastNameWithParticipantNumberAndTime(): void
|
|
||||||
{
|
|
||||||
CarbonImmutable::setTestNow(CarbonImmutable::create(2026, 1, 15, 14, 30));
|
|
||||||
|
|
||||||
$participant = new ParticipantDto();
|
|
||||||
|
|
||||||
$this->service->fill($participant, 0);
|
|
||||||
|
|
||||||
$this->assertSame('Muster 1 14:30', $participant->lastName);
|
|
||||||
|
|
||||||
CarbonImmutable::setTestNow();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testFillSetsMobilePhone(): void
|
|
||||||
{
|
|
||||||
$participant = new ParticipantDto();
|
|
||||||
|
|
||||||
$this->service->fill($participant, 0);
|
|
||||||
|
|
||||||
$this->assertSame('0171/111111', $participant->mobile);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testFillSetsEmailWithParticipantNumber(): void
|
|
||||||
{
|
|
||||||
$participant = new ParticipantDto();
|
|
||||||
|
|
||||||
$this->service->fill($participant, 0);
|
|
||||||
|
|
||||||
$this->assertSame('[email protected]', $participant->email);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testFillUsesOneBasedParticipantNumber(): void
|
|
||||||
{
|
|
||||||
CarbonImmutable::setTestNow(CarbonImmutable::create(2026, 1, 15, 9, 5));
|
|
||||||
|
|
||||||
$participant0 = new ParticipantDto();
|
|
||||||
$participant1 = new ParticipantDto();
|
|
||||||
$participant4 = new ParticipantDto();
|
|
||||||
|
|
||||||
$this->service->fill($participant0, 0);
|
|
||||||
$this->service->fill($participant1, 1);
|
|
||||||
$this->service->fill($participant4, 4);
|
|
||||||
|
|
||||||
$this->assertSame('Vorname 1', $participant0->firstName);
|
|
||||||
$this->assertSame('Muster 1 09:05', $participant0->lastName);
|
|
||||||
$this->assertSame('[email protected]', $participant0->email);
|
|
||||||
|
|
||||||
$this->assertSame('Vorname 2', $participant1->firstName);
|
|
||||||
$this->assertSame('Muster 2 09:05', $participant1->lastName);
|
|
||||||
$this->assertSame('[email protected]', $participant1->email);
|
|
||||||
|
|
||||||
$this->assertSame('Vorname 5', $participant4->firstName);
|
|
||||||
$this->assertSame('Muster 5 09:05', $participant4->lastName);
|
|
||||||
$this->assertSame('[email protected]', $participant4->email);
|
|
||||||
|
|
||||||
CarbonImmutable::setTestNow();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testFillSetsDateOfBirthToTwentyYearsAgo(): void
|
|
||||||
{
|
|
||||||
CarbonImmutable::setTestNow(CarbonImmutable::create(2026, 3, 10, 12, 0));
|
|
||||||
|
|
||||||
$participant = new ParticipantDto();
|
|
||||||
|
|
||||||
$this->service->fill($participant, 0);
|
|
||||||
|
|
||||||
$this->assertInstanceOf(\DateTimeImmutable::class, $participant->dateOfBirth);
|
|
||||||
$this->assertSame('2006-03-10', $participant->dateOfBirth->format('Y-m-d'));
|
|
||||||
|
|
||||||
CarbonImmutable::setTestNow();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testFillSetsAddress(): void
|
|
||||||
{
|
|
||||||
$participant = new ParticipantDto();
|
|
||||||
|
|
||||||
$this->service->fill($participant, 0);
|
|
||||||
|
|
||||||
$this->assertNotNull($participant->address);
|
|
||||||
$this->assertSame('Musterstr. 123', $participant->address->street);
|
|
||||||
$this->assertSame('99999', $participant->address->postCode);
|
|
||||||
$this->assertSame('MusterOrt', $participant->address->city);
|
|
||||||
$this->assertSame('Deutschland', $participant->address->country);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testFillSetsAddressForAllParticipants(): void
|
|
||||||
{
|
|
||||||
$participant0 = new ParticipantDto();
|
|
||||||
$participant3 = new ParticipantDto();
|
|
||||||
|
|
||||||
$this->service->fill($participant0, 0);
|
|
||||||
$this->service->fill($participant3, 3);
|
|
||||||
|
|
||||||
$this->assertNotNull($participant0->address);
|
|
||||||
$this->assertNotNull($participant3->address);
|
|
||||||
$this->assertSame('Musterstr. 123', $participant3->address->street);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -12,7 +12,6 @@ use App\Form\Model\ParticipantDto;
|
|||||||
use App\Form\Model\RoomSelectionDto;
|
use App\Form\Model\RoomSelectionDto;
|
||||||
use App\Service\BookingParticipantCountService;
|
use App\Service\BookingParticipantCountService;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use Symfony\Component\Security\Core\User\UserInterface;
|
|
||||||
|
|
||||||
class BookingParticipantCountServiceTest extends TestCase
|
class BookingParticipantCountServiceTest extends TestCase
|
||||||
{
|
{
|
||||||
@@ -44,31 +43,6 @@ class BookingParticipantCountServiceTest extends TestCase
|
|||||||
$this->assertSame(7, $bookingDto->participants[7]->index);
|
$this->assertSame(7, $bookingDto->participants[7]->index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testEnsureCorrectNumberOfParticipantsPrepopulatesFreshApplicant(): void
|
|
||||||
{
|
|
||||||
$travel = $this->createTravel([1 => 2]);
|
|
||||||
$bookingDto = new BookingDto($travel, 123);
|
|
||||||
$bookingDto->roomSelections = [$this->createRoomSelection(1, 1)];
|
|
||||||
$bookingDto->participants = [new ParticipantDto()];
|
|
||||||
|
|
||||||
$user = $this->createMock(UserInterface::class);
|
|
||||||
$callbackCalled = false;
|
|
||||||
|
|
||||||
$this->service->ensureCorrectNumberOfParticipants(
|
|
||||||
$bookingDto,
|
|
||||||
$user,
|
|
||||||
function (UserInterface $userArg, ParticipantDto $participant) use (&$callbackCalled): ParticipantDto {
|
|
||||||
$callbackCalled = true;
|
|
||||||
$participant->firstName = 'Alex';
|
|
||||||
|
|
||||||
return $participant;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->assertTrue($callbackCalled);
|
|
||||||
$this->assertSame('Alex', $bookingDto->participants[0]->firstName);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function createTravel(array $roomCapacities): Travel
|
private function createTravel(array $roomCapacities): Travel
|
||||||
{
|
{
|
||||||
$travel = new Travel();
|
$travel = new Travel();
|
||||||
|
|||||||
@@ -10,9 +10,11 @@ use App\BusProNet\Model\Communication;
|
|||||||
use App\BusProNet\Model\Notification;
|
use App\BusProNet\Model\Notification;
|
||||||
use App\BusProNet\Model\PersonalData;
|
use App\BusProNet\Model\PersonalData;
|
||||||
use App\Entity\User;
|
use App\Entity\User;
|
||||||
|
use App\Form\Model\BookingDto;
|
||||||
use App\Form\Model\ParticipantDto;
|
use App\Form\Model\ParticipantDto;
|
||||||
use App\Security\Crypt;
|
use App\Security\Crypt;
|
||||||
use App\Service\ParticipantPrepopulationService;
|
use App\Service\ParticipantPrepopulationService;
|
||||||
|
use Carbon\CarbonImmutable;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
@@ -240,6 +242,44 @@ class ParticipantPrepopulationServiceTest extends TestCase
|
|||||||
$this->assertTrue($result->bulkInsuranceBooking);
|
$this->assertTrue($result->bulkInsuranceBooking);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testShouldPrepopulateApplicantOnlyWhenFresh(): void
|
||||||
|
{
|
||||||
|
$fresh = new ParticipantDto();
|
||||||
|
$fresh->firstName = '';
|
||||||
|
|
||||||
|
$filled = new ParticipantDto();
|
||||||
|
$filled->firstName = 'Already set';
|
||||||
|
|
||||||
|
$this->assertTrue($this->service->shouldPrepopulateApplicant($fresh));
|
||||||
|
$this->assertFalse($this->service->shouldPrepopulateApplicant($filled));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDummyTokenMatchesOnlyInCreateMode(): void
|
||||||
|
{
|
||||||
|
$participant = new ParticipantDto();
|
||||||
|
$participant->lastName = ParticipantPrepopulationService::TOKEN;
|
||||||
|
|
||||||
|
$this->assertTrue($this->service->isDummyDataFillRequested($participant, BookingDto::MODE_CREATE));
|
||||||
|
$this->assertFalse($this->service->isDummyDataFillRequested($participant, BookingDto::MODE_EDIT));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFillDummyParticipantSetsGeneratedData(): void
|
||||||
|
{
|
||||||
|
CarbonImmutable::setTestNow(CarbonImmutable::create(2026, 1, 15, 14, 30));
|
||||||
|
|
||||||
|
$participant = new ParticipantDto();
|
||||||
|
$this->service->fillDummyParticipant($participant, 0);
|
||||||
|
|
||||||
|
$this->assertSame('Vorname 1', $participant->firstName);
|
||||||
|
$this->assertSame('Muster 1 14:30', $participant->lastName);
|
||||||
|
$this->assertSame('0171/111111', $participant->mobile);
|
||||||
|
$this->assertSame('[email protected]', $participant->email);
|
||||||
|
$this->assertSame('2006-01-15', $participant->dateOfBirth?->format('Y-m-d'));
|
||||||
|
$this->assertSame('Musterstr. 123', $participant->address?->street);
|
||||||
|
|
||||||
|
CarbonImmutable::setTestNow();
|
||||||
|
}
|
||||||
|
|
||||||
private function createUser(string $email, string $encryptedPassword): User
|
private function createUser(string $email, string $encryptedPassword): User
|
||||||
{
|
{
|
||||||
$user = new User($email);
|
$user = new User($email);
|
||||||
|
|||||||
Reference in New Issue
Block a user