feat: split booking between participants and applicant

addresses #869f2q1vu
This commit is contained in:
fromme committed 2026-10-19 09:18:22 +02:00
1 parent 2d49212b08
commit 1ff293f41f
44 files changed
+2024 -316

No files matched your search

@@ -172,6 +172,59 @@ class BookingNewsletterOptInTest extends TestCase
);
}
public function testApplicantIsTheSeparateRecordWhenTheyDoNotTravel(): void
{
$bookingDto = $this->createBookingDto([['[email protected]', 12]]);
$bookingDto->applicantTravels = false;
$applicant = new ParticipantDto();
$applicant->firstName = 'Probe';
$applicant->lastName = 'Elternteil';
$applicant->email = '[email protected]';
$bookingDto->applicant = $applicant;
$service = $this->createService($this->createStub(NewsletterManager::class));
$this->assertSame('[email protected]', $service->resolveApplicantEmail($bookingDto, null));
$this->assertSame($applicant, $service->resolveApplicantParticipant($bookingDto));
$this->assertSame('Probe Elternteil', $service->resolveRequestedByName($bookingDto));
}
public function testAdultAtIndexZeroIsOfferedACompanionOptInOnASplitBooking(): void
{
$bookingDto = $this->createBookingDto([['[email protected]', 25]]);
$bookingDto->applicantTravels = false;
$applicant = new ParticipantDto();
$applicant->firstName = 'Probe';
$applicant->lastName = 'Elternteil';
$applicant->email = '[email protected]';
$bookingDto->applicant = $applicant;
$service = $this->createService($this->createStub(NewsletterManager::class));
$companions = $service->resolveCompanions($bookingDto, '[email protected]');
$this->assertCount(
1,
$companions,
'participant[0] is an ordinary companion once the applicant stays home'
);
$this->assertSame('[email protected]', $companions[0]->email);
}
public function testChildCarryingTheApplicantAddressIsNotOfferedACompanionOptIn(): void
{
$bookingDto = $this->createBookingDto([
['[email protected]', 40],
['[email protected]', 12],
]);
$service = $this->createService($this->createStub(NewsletterManager::class));
$companions = $service->resolveCompanions($bookingDto, '[email protected]');
$this->assertSame([], $companions);
}
private function createService(NewsletterManager $newsletterManager): BookingNewsletterOptIn
{
return new BookingNewsletterOptIn($newsletterManager, new NullLogger());
+27 -1
View File
@@ -300,7 +300,33 @@ class ParticipantDataPrefillerTest extends TestCase
$this->assertSame('[email protected]', $participant->email);
$this->assertSame('2006-01-15', $participant->dateOfBirth?->format('Y-m-d'));
$this->assertSame('Musterstr. 123', $participant->address?->street);
$this->assertSame('DE', $participant->address?->country);
$this->assertSame(
'D',
$participant->address?->country,
"BusPro's country tokens are not ISO codes: 'DE' matches no choice and leaves the select empty"
);
CarbonImmutable::setTestNow();
}
public function testFillDummyApplicantSetsACompleteAdult(): void
{
CarbonImmutable::setTestNow(CarbonImmutable::create(2026, 1, 15, 14, 30));
$applicant = new ParticipantDto();
$this->service()->fillDummyApplicant($applicant);
$this->assertSame('Probeelternteil', $applicant->firstName);
$this->assertSame('Elternteil 14:30', $applicant->lastName);
$this->assertSame('[email protected]', $applicant->email);
$this->assertSame('0171/222222', $applicant->mobile);
$this->assertSame('Probeweg 7', $applicant->address?->street);
// The applicant block requires these, unlike a participant.
$this->assertSame('W', $applicant->gender);
$this->assertSame('D', $applicant->nationality);
$this->assertSame('D', $applicant->address?->country);
$this->assertGreaterThanOrEqual(18, $applicant->getAge());
CarbonImmutable::setTestNow();
}
+47 -1
View File
@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace App\Tests\Service;
use App\BusProNet\Model\Booking;
use App\BusProNet\Model\Insurance;
use App\BusProNet\Model\Travel;
use App\Exception\ParticipantNotFoundException;
use App\Form\Model\BookingDto;
@@ -80,8 +81,53 @@ class ParticipantFormSupportTest extends TestCase
}
/**
* array<string, int>|null $bodyDimensionRanges
* array<string, int>|null $bodyDimensionRanges.
*/
public function testBlankTravellerKeepsTheRoomAssignmentAndDropsTheRest(): void
{
$previous = new ParticipantDto();
$previous->index = 0;
$previous->assignedRoomId = 4711;
$previous->firstName = 'Elternteil';
$previous->email = '[email protected]';
$previous->dateOfBirth = new \DateTimeImmutable('1981-03-16');
$traveller = $this->createService()->createBlankTravellerFrom($previous);
$this->assertSame(0, $traveller->index);
$this->assertSame(4711, $traveller->assignedRoomId);
$this->assertNull($traveller->firstName);
$this->assertNull($traveller->email);
$this->assertNull(
$traveller->dateOfBirth,
'The services were derived from an age that no longer applies to this slot'
);
}
public function testClearFamilyInsuranceRemovesOnlyFamilyPolicies(): void
{
$bookingDto = $this->createBookingDto();
$familyInsurance = new Insurance();
$familyInsurance->familyInsurance = true;
$bookingDto->participants[0]->insurance = $familyInsurance;
$bookingDto->participants[0]->bulkInsuranceBooking = true;
$ordinaryInsurance = new Insurance();
$ordinaryInsurance->familyInsurance = false;
$bookingDto->participants[1]->insurance = $ordinaryInsurance;
$this->createService()->clearFamilyInsurance($bookingDto);
$this->assertNull($bookingDto->participants[0]->insurance);
$this->assertFalse($bookingDto->participants[0]->bulkInsuranceBooking);
$this->assertSame(
$ordinaryInsurance,
$bookingDto->participants[1]->insurance,
'Only the family policy goes; an ordinary one is still valid on a split booking'
);
}
private function createService(?array $bodyDimensionRanges = null): ParticipantFormSupport
{
$bodyDimensionRanges ??= [