feat: split booking between participants and applicant
addresses #869f2q1vu
This commit is contained in:
1 parent
2d49212b08
commit
1ff293f41f
44 files changed
+2024
-316
No files matched your search
@@ -155,6 +155,79 @@ class BookingDataProcessorTest extends TestCase
|
||||
$this->assertSame(194672, $dto->participants[0]->veg?->id);
|
||||
}
|
||||
|
||||
public function testApplicantAddressIsCopiedOntoFirstParticipantOnAnOrdinaryBooking(): void
|
||||
{
|
||||
$booking = $this->createMockBooking();
|
||||
$travel = $this->createMockTravel();
|
||||
|
||||
$booking->applicant->personId = 4711;
|
||||
$booking->participants[0]->personId = 4711;
|
||||
$booking->applicant->address = $this->createFilledAddress('Elternweg 7');
|
||||
$booking->participants[0]->address = new Address();
|
||||
$booking->participants[0]->height = null;
|
||||
|
||||
$dto = $this->processor->createBookingDtoFromBooking($booking, $travel);
|
||||
|
||||
$this->assertSame(
|
||||
'Elternweg 7',
|
||||
$dto->participants[0]->address?->street,
|
||||
'BPN returns the full record only in <anmelder>, so participant[0] is filled from it'
|
||||
);
|
||||
$this->assertSame('175', $dto->participants[0]->height);
|
||||
}
|
||||
|
||||
public function testApplicantAddressIsNotCopiedOntoFirstParticipantOnASplitBooking(): void
|
||||
{
|
||||
$booking = $this->createMockBooking();
|
||||
$travel = $this->createMockTravel();
|
||||
|
||||
// The applicant is a different person: a parent who booked for their child.
|
||||
$booking->applicant->personId = 4711;
|
||||
$booking->participants[0]->personId = 4712;
|
||||
$booking->applicant->address = $this->createFilledAddress('Elternweg 7');
|
||||
$booking->participants[0]->address = new Address();
|
||||
$booking->participants[0]->height = null;
|
||||
|
||||
$dto = $this->processor->createBookingDtoFromBooking($booking, $travel);
|
||||
|
||||
$this->assertNull(
|
||||
$dto->participants[0]->address?->street,
|
||||
"The parent's address must not be written onto the child at the next edit submit"
|
||||
);
|
||||
$this->assertNull(
|
||||
$dto->participants[0]->height,
|
||||
"The parent's body dimensions must not be written onto the child either"
|
||||
);
|
||||
}
|
||||
|
||||
public function testApplicantAddressIsCopiedWhenPersonIdsAreUnknown(): void
|
||||
{
|
||||
$booking = $this->createMockBooking();
|
||||
$travel = $this->createMockTravel();
|
||||
|
||||
$booking->applicant->address = $this->createFilledAddress('Elternweg 7');
|
||||
$booking->participants[0]->address = new Address();
|
||||
|
||||
$dto = $this->processor->createBookingDtoFromBooking($booking, $travel);
|
||||
|
||||
$this->assertSame(
|
||||
'Elternweg 7',
|
||||
$dto->participants[0]->address?->street,
|
||||
'Incomplete BPN data falls back to the established, stricter behaviour'
|
||||
);
|
||||
}
|
||||
|
||||
private function createFilledAddress(string $street): Address
|
||||
{
|
||||
$address = new Address();
|
||||
$address->street = $street;
|
||||
$address->postCode = '99999';
|
||||
$address->city = 'MusterOrt';
|
||||
$address->country = 'D';
|
||||
|
||||
return $address;
|
||||
}
|
||||
|
||||
public function testTransportationServicesProcessing(): void
|
||||
{
|
||||
$formData = $this->createFormDataWithTransportation();
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\BusProNet\DataProcessor;
|
||||
|
||||
use App\BusProNet\DataProcessor\BookingPayloadBuilder;
|
||||
use App\BusProNet\DataProcessor\ServiceMappingCollector;
|
||||
use App\BusProNet\Model\Address;
|
||||
use App\BusProNet\Model\Travel;
|
||||
use App\Form\Model\BookingDto;
|
||||
use App\Form\Model\ParticipantDto;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* Covers who the <anmelder> block is built from, and the participant email fallback.
|
||||
*/
|
||||
class BookingPayloadBuilderTest extends TestCase
|
||||
{
|
||||
private BookingPayloadBuilder $builder;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$mappingCollector = $this->createStub(ServiceMappingCollector::class);
|
||||
$mappingCollector->method('getPromoVoucherCodeForParticipant')->willReturn(null);
|
||||
|
||||
$this->builder = new BookingPayloadBuilder($mappingCollector);
|
||||
}
|
||||
|
||||
public function testAnmelderComesFromFirstParticipantWhenTheApplicantTravels(): void
|
||||
{
|
||||
$bookingDto = $this->createBookingDto();
|
||||
|
||||
$payload = $this->builder->buildCreatePayload($bookingDto, 'BUCHUNG');
|
||||
|
||||
$this->assertSame('Kind', $payload['anmelder']['vorname']);
|
||||
$this->assertSame('Kind', $payload['teilnehmerliste']['teilnehmer'][0]['vorname']);
|
||||
}
|
||||
|
||||
public function testAnmelderComesFromTheApplicantRecordWhenTheyDoNotTravel(): void
|
||||
{
|
||||
$bookingDto = $this->createBookingDto();
|
||||
$bookingDto->applicantTravels = false;
|
||||
$bookingDto->applicant = $this->createPerson('Elternteil', '[email protected]');
|
||||
|
||||
$payload = $this->builder->buildCreatePayload($bookingDto, 'BUCHUNG');
|
||||
|
||||
$this->assertSame('Elternteil', $payload['anmelder']['vorname']);
|
||||
$this->assertSame('[email protected]', $payload['anmelder']['kommunikation']['email']);
|
||||
$this->assertSame(
|
||||
'Kind',
|
||||
$payload['teilnehmerliste']['teilnehmer'][0]['vorname'],
|
||||
'participant[0] stays an ordinary traveller'
|
||||
);
|
||||
}
|
||||
|
||||
public function testAnmelderStillCarriesNoIdsOnCreate(): void
|
||||
{
|
||||
$bookingDto = $this->createBookingDto();
|
||||
$bookingDto->applicantTravels = false;
|
||||
$applicant = $this->createPerson('Elternteil', '[email protected]');
|
||||
$applicant->personId = 4711;
|
||||
$applicant->addressId = 1234;
|
||||
$bookingDto->applicant = $applicant;
|
||||
|
||||
$payload = $this->builder->buildCreatePayload($bookingDto, 'BUCHUNG');
|
||||
|
||||
$this->assertArrayNotHasKey('idadresseperson', $payload['anmelder']);
|
||||
$this->assertArrayNotHasKey('idadresse', $payload['anmelder']);
|
||||
}
|
||||
|
||||
public function testParticipantWithoutEmailInheritsTheApplicants(): void
|
||||
{
|
||||
$bookingDto = $this->createBookingDto();
|
||||
$bookingDto->applicantTravels = false;
|
||||
$bookingDto->applicant = $this->createPerson('Elternteil', '[email protected]');
|
||||
$bookingDto->participants[0]->email = null;
|
||||
|
||||
$payload = $this->builder->buildCreatePayload($bookingDto, 'BUCHUNG');
|
||||
|
||||
$this->assertSame(
|
||||
'[email protected]',
|
||||
$payload['teilnehmerliste']['teilnehmer'][0]['kommunikation']['email'],
|
||||
'BusPro rejects a participant without a Mail-Adresse with 650, but accepts a shared one'
|
||||
);
|
||||
}
|
||||
|
||||
public function testParticipantKeepsTheirOwnEmail(): void
|
||||
{
|
||||
$bookingDto = $this->createBookingDto();
|
||||
$bookingDto->applicantTravels = false;
|
||||
$bookingDto->applicant = $this->createPerson('Elternteil', '[email protected]');
|
||||
|
||||
$payload = $this->builder->buildCreatePayload($bookingDto, 'BUCHUNG');
|
||||
|
||||
$this->assertSame(
|
||||
'[email protected]',
|
||||
$payload['teilnehmerliste']['teilnehmer'][0]['kommunikation']['email']
|
||||
);
|
||||
}
|
||||
|
||||
public function testOrdinaryBookingPayloadIsUnchangedByTheApplicantSwitch(): void
|
||||
{
|
||||
$withApplicantTravelling = $this->builder->buildCreatePayload($this->createBookingDto(), 'BUCHUNG');
|
||||
|
||||
$bookingDto = $this->createBookingDto();
|
||||
$bookingDto->applicant = $this->createPerson('Elternteil', '[email protected]');
|
||||
|
||||
$this->assertSame(
|
||||
$withApplicantTravelling,
|
||||
$this->builder->buildCreatePayload($bookingDto, 'BUCHUNG'),
|
||||
'A stale applicant record must not leak into a booking where the applicant travels'
|
||||
);
|
||||
}
|
||||
|
||||
private function createBookingDto(): BookingDto
|
||||
{
|
||||
$travel = new Travel();
|
||||
$travel->id = 12500;
|
||||
$travel->hotelId = 223055;
|
||||
|
||||
$bookingDto = new BookingDto($travel, 223055);
|
||||
$bookingDto->agencyId = 77883;
|
||||
|
||||
$participant = $this->createPerson('Kind', '[email protected]');
|
||||
$participant->index = 0;
|
||||
$bookingDto->participants = [$participant];
|
||||
|
||||
return $bookingDto;
|
||||
}
|
||||
|
||||
private function createPerson(string $firstName, string $email): ParticipantDto
|
||||
{
|
||||
$person = new ParticipantDto();
|
||||
$person->firstName = $firstName;
|
||||
$person->lastName = 'Probe';
|
||||
$person->gender = 'W';
|
||||
$person->nationality = 'D';
|
||||
$person->dateOfBirth = new \DateTimeImmutable('2014-09-16');
|
||||
$person->email = $email;
|
||||
$person->mobile = '0171/222222';
|
||||
|
||||
$address = new Address();
|
||||
$address->street = 'Probeweg 7';
|
||||
$address->postCode = '99999';
|
||||
$address->city = 'MusterOrt';
|
||||
$address->country = 'D';
|
||||
$person->address = $address;
|
||||
|
||||
return $person;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Form;
|
||||
|
||||
use App\BusProNet\Model\Travel;
|
||||
use App\Form\BookingApplicantTravelsType;
|
||||
use App\Form\Model\BookingDto;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Form\Forms;
|
||||
|
||||
class BookingApplicantTravelsTypeTest extends TestCase
|
||||
{
|
||||
public function testBooleanChoicesRenderAsRadioValues(): void
|
||||
{
|
||||
$form = $this->createForm($this->createBookingDto());
|
||||
|
||||
$values = [];
|
||||
foreach ($form->get('applicantTravels')->createView()->vars['choices'] as $choice) {
|
||||
$values[] = $choice->value;
|
||||
}
|
||||
|
||||
// Symfony derives these from the booleans on its own, so the type needs no choice_value.
|
||||
// Pinned because the whole toggle silently stops working if that ever changes.
|
||||
$this->assertSame(['1', '0'], $values);
|
||||
}
|
||||
|
||||
public function testSubmittingTheSplitChoiceFlipsTheFlag(): void
|
||||
{
|
||||
$bookingDto = $this->createBookingDto();
|
||||
$form = $this->createForm($bookingDto);
|
||||
|
||||
$form->submit(['applicantTravels' => '0']);
|
||||
|
||||
$this->assertTrue($form->isSynchronized());
|
||||
$this->assertTrue($form->isValid());
|
||||
$this->assertFalse($bookingDto->applicantTravels);
|
||||
}
|
||||
|
||||
public function testSubmittingTheTravellingChoiceRestoresTheFlag(): void
|
||||
{
|
||||
$bookingDto = $this->createBookingDto();
|
||||
$bookingDto->applicantTravels = false;
|
||||
$form = $this->createForm($bookingDto);
|
||||
|
||||
$form->submit(['applicantTravels' => '1']);
|
||||
|
||||
$this->assertTrue($form->isValid());
|
||||
$this->assertTrue($bookingDto->applicantTravels);
|
||||
}
|
||||
|
||||
public function testCurrentChoiceIsPreselected(): void
|
||||
{
|
||||
$bookingDto = $this->createBookingDto();
|
||||
$bookingDto->applicantTravels = false;
|
||||
|
||||
$view = $this->createForm($bookingDto)->get('applicantTravels')->createView();
|
||||
|
||||
$this->assertSame('0', $view->vars['value']);
|
||||
}
|
||||
|
||||
public function testNoValidationRunsOnTheToggle(): void
|
||||
{
|
||||
$bookingDto = $this->createBookingDto();
|
||||
// Deliberately incomplete: flipping the radio must not report participant gaps.
|
||||
$bookingDto->participants = [];
|
||||
|
||||
$form = $this->createForm($bookingDto);
|
||||
$form->submit(['applicantTravels' => '0']);
|
||||
|
||||
$this->assertCount(0, $form->getErrors(true));
|
||||
}
|
||||
|
||||
private function createBookingDto(): BookingDto
|
||||
{
|
||||
$travel = new Travel();
|
||||
$travel->dateFrom = new \DateTimeImmutable('2026-06-01');
|
||||
|
||||
return new BookingDto($travel, 1);
|
||||
}
|
||||
|
||||
/** @return \Symfony\Component\Form\FormInterface<BookingDto> */
|
||||
private function createForm(BookingDto $bookingDto): \Symfony\Component\Form\FormInterface
|
||||
{
|
||||
return Forms::createFormFactory()->create(BookingApplicantTravelsType::class, $bookingDto);
|
||||
}
|
||||
}
|
||||
@@ -4,11 +4,15 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Form\Model;
|
||||
|
||||
use App\BusProNet\Model\Travel;
|
||||
use App\BusProNet\Model\Address;
|
||||
use App\BusProNet\Model\Booking;
|
||||
use App\BusProNet\Model\PersonalData;
|
||||
use App\BusProNet\Model\Travel;
|
||||
use App\BusProNet\XmlLoader\AgencyLoader;
|
||||
use App\Form\Model\BookingDto;
|
||||
use App\Form\Model\ParticipantDto;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Validator\Validation;
|
||||
|
||||
/**
|
||||
* Tests for BookingDto validation and business logic.
|
||||
@@ -128,4 +132,240 @@ class BookingDtoTest extends TestCase
|
||||
$this->assertSame('Test City', $restored->participants[0]->address->city);
|
||||
$this->assertSame('DE', $restored->participants[0]->address->country);
|
||||
}
|
||||
|
||||
public function testFirstParticipantIsTheApplicantByDefaultInCreateMode(): void
|
||||
{
|
||||
$dto = $this->createCreateModeDto();
|
||||
|
||||
$this->assertTrue($dto->isFirstParticipantApplicant());
|
||||
}
|
||||
|
||||
public function testFirstParticipantIsNotTheApplicantWhenTheApplicantDoesNotTravel(): void
|
||||
{
|
||||
$dto = $this->createCreateModeDto();
|
||||
$dto->applicantTravels = false;
|
||||
|
||||
$this->assertFalse($dto->isFirstParticipantApplicant());
|
||||
}
|
||||
|
||||
public function testInternalAgencyBookingNeverHasTheFirstParticipantAsApplicant(): void
|
||||
{
|
||||
$dto = $this->createCreateModeDto();
|
||||
$dto->agencyCode = AgencyLoader::INTERNAL_AGENCY_CODE;
|
||||
|
||||
$this->assertFalse(
|
||||
$dto->isFirstParticipantApplicant(),
|
||||
'Their applicant is a staff member who never travels'
|
||||
);
|
||||
}
|
||||
|
||||
public function testEditModeDerivesTheSplitFromPersonIds(): void
|
||||
{
|
||||
$dto = $this->createEditModeDto(applicantPersonId: 4711, firstParticipantPersonId: 4711);
|
||||
|
||||
$this->assertTrue($dto->isFirstParticipantApplicant());
|
||||
|
||||
$split = $this->createEditModeDto(applicantPersonId: 4711, firstParticipantPersonId: 4712);
|
||||
|
||||
$this->assertFalse($split->isFirstParticipantApplicant());
|
||||
}
|
||||
|
||||
public function testEditModeTreatsAnUnknownPersonIdAsTheSamePerson(): void
|
||||
{
|
||||
$dto = $this->createEditModeDto(applicantPersonId: 4711, firstParticipantPersonId: null);
|
||||
|
||||
$this->assertTrue(
|
||||
$dto->isFirstParticipantApplicant(),
|
||||
'Incomplete BPN data must fall back to the established, locked-down behaviour'
|
||||
);
|
||||
}
|
||||
|
||||
public function testFamilyBookingRequiresTheApplicantToTravel(): void
|
||||
{
|
||||
$dto = $this->createCreateModeDto();
|
||||
$dto->participants = [
|
||||
$this->createParticipantAged(40),
|
||||
$this->createParticipantAged(12),
|
||||
];
|
||||
|
||||
$this->assertTrue($dto->isFamilyBooking());
|
||||
|
||||
$dto->applicantTravels = false;
|
||||
|
||||
$this->assertFalse(
|
||||
$dto->isFamilyBooking(),
|
||||
'Family insurance is not offered when the applicant does not travel'
|
||||
);
|
||||
}
|
||||
|
||||
public function testAdultSiblingWithAChildIsNotAFamilyBookingOnceTheApplicantStaysHome(): void
|
||||
{
|
||||
$dto = $this->createCreateModeDto();
|
||||
$dto->applicantTravels = false;
|
||||
$dto->participants = [
|
||||
$this->createParticipantAged(18),
|
||||
$this->createParticipantAged(12),
|
||||
];
|
||||
|
||||
$this->assertFalse(
|
||||
$dto->isFamilyBooking(),
|
||||
'The age distribution alone would still qualify, which is why the flag is checked first'
|
||||
);
|
||||
}
|
||||
|
||||
public function testOldSessionsWithoutTheApplicantFieldsRestoreToTheDefaults(): void
|
||||
{
|
||||
$travel = new Travel();
|
||||
$travel->id = 42;
|
||||
$travel->dateFrom = new \DateTimeImmutable('2025-06-01');
|
||||
|
||||
$dto = new BookingDto($travel, 1);
|
||||
$data = $dto->__serialize();
|
||||
unset($data['applicantTravels'], $data['applicant']);
|
||||
|
||||
$restored = new BookingDto($travel, 1);
|
||||
$restored->__unserialize($data);
|
||||
|
||||
$this->assertTrue($restored->applicantTravels);
|
||||
$this->assertNull($restored->applicant);
|
||||
}
|
||||
|
||||
private function createCreateModeDto(): BookingDto
|
||||
{
|
||||
$travel = new Travel();
|
||||
$travel->dateFrom = new \DateTimeImmutable('2025-06-01');
|
||||
$travel->dateTo = new \DateTimeImmutable('2025-06-08');
|
||||
|
||||
$dto = new BookingDto($travel, 1);
|
||||
$dto->participants = [$this->createParticipantAged(40)];
|
||||
|
||||
return $dto;
|
||||
}
|
||||
|
||||
private function createEditModeDto(?int $applicantPersonId, ?int $firstParticipantPersonId): BookingDto
|
||||
{
|
||||
$dto = $this->createCreateModeDto();
|
||||
|
||||
$applicant = new PersonalData();
|
||||
$applicant->personId = $applicantPersonId;
|
||||
|
||||
$booking = new Booking();
|
||||
$booking->applicant = $applicant;
|
||||
$dto->booking = $booking;
|
||||
|
||||
$dto->participants[0]->personId = $firstParticipantPersonId;
|
||||
|
||||
return $dto;
|
||||
}
|
||||
|
||||
private function createParticipantAged(int $years): ParticipantDto
|
||||
{
|
||||
$participant = new ParticipantDto();
|
||||
$participant->dateOfBirth = (new \DateTimeImmutable('2025-06-01'))->modify(sprintf('-%d years', $years));
|
||||
|
||||
return $participant;
|
||||
}
|
||||
|
||||
public function testApplicantRulesDoNotLeakOntoTravellers(): void
|
||||
{
|
||||
$dto = $this->createCreateModeDto();
|
||||
$dto->applicantTravels = false;
|
||||
$dto->participants = [$this->createParticipantAged(15)];
|
||||
$dto->participants[0]->index = 0;
|
||||
|
||||
$applicant = new ParticipantDto();
|
||||
$applicant->firstName = 'Probe';
|
||||
$applicant->lastName = 'Elternteil';
|
||||
$applicant->gender = 'W';
|
||||
$applicant->nationality = 'D';
|
||||
$applicant->email = '[email protected]';
|
||||
$applicant->mobile = '0171/222222';
|
||||
$applicant->dateOfBirth = new \DateTimeImmutable('1981-03-16');
|
||||
$applicant->address = $this->createAddress();
|
||||
$dto->applicant = $applicant;
|
||||
|
||||
$validator = Validation::createValidatorBuilder()->enableAttributeMapping()->getValidator();
|
||||
$violations = $validator->validate($dto, null, ['booking_applicant']);
|
||||
|
||||
$paths = [];
|
||||
foreach ($violations as $violation) {
|
||||
$paths[] = $violation->getPropertyPath();
|
||||
}
|
||||
|
||||
$this->assertSame(
|
||||
[],
|
||||
$paths,
|
||||
'A 15-year-old traveller must not be held to the applicant rules through the group cascade'
|
||||
);
|
||||
}
|
||||
|
||||
public function testIncompleteApplicantIsReportedUnderTheApplicantPathOnlyOnce(): void
|
||||
{
|
||||
$dto = $this->createCreateModeDto();
|
||||
$dto->applicantTravels = false;
|
||||
$dto->participants[0]->index = 0;
|
||||
|
||||
$applicant = new ParticipantDto();
|
||||
$applicant->dateOfBirth = new \DateTimeImmutable('1981-03-16');
|
||||
$dto->applicant = $applicant;
|
||||
|
||||
$validator = Validation::createValidatorBuilder()->enableAttributeMapping()->getValidator();
|
||||
$violations = $validator->validate($dto, null, ['booking_applicant']);
|
||||
|
||||
$paths = [];
|
||||
foreach ($violations as $violation) {
|
||||
$paths[] = $violation->getPropertyPath();
|
||||
}
|
||||
|
||||
$this->assertContains('applicant.firstName', $paths);
|
||||
$this->assertContains(
|
||||
'applicant.address.street',
|
||||
$paths,
|
||||
'A fresh ParticipantDto carries an empty Address, so the gaps surface per subfield'
|
||||
);
|
||||
$this->assertSame(
|
||||
array_unique($paths),
|
||||
$paths,
|
||||
'Explicit delegation plus a cascade would report each gap twice'
|
||||
);
|
||||
}
|
||||
|
||||
public function testMinorApplicantIsRejected(): void
|
||||
{
|
||||
$dto = $this->createCreateModeDto();
|
||||
$dto->applicantTravels = false;
|
||||
$dto->participants[0]->index = 0;
|
||||
|
||||
$applicant = new ParticipantDto();
|
||||
$applicant->firstName = 'Probe';
|
||||
$applicant->lastName = 'Elternteil';
|
||||
$applicant->gender = 'W';
|
||||
$applicant->nationality = 'D';
|
||||
$applicant->email = '[email protected]';
|
||||
$applicant->mobile = '0171/222222';
|
||||
$applicant->dateOfBirth = (new \DateTimeImmutable('today'))->modify('-17 years');
|
||||
$applicant->address = $this->createAddress();
|
||||
$dto->applicant = $applicant;
|
||||
|
||||
$validator = Validation::createValidatorBuilder()->enableAttributeMapping()->getValidator();
|
||||
$violations = $validator->validate($dto, null, ['booking_applicant']);
|
||||
|
||||
$messages = [];
|
||||
foreach ($violations as $violation) {
|
||||
$messages[] = $violation->getMessage();
|
||||
}
|
||||
|
||||
$this->assertContains('Die anmeldende Person muss volljährig sein.', $messages);
|
||||
}
|
||||
|
||||
private function createAddress(): Address
|
||||
{
|
||||
$address = new Address();
|
||||
$address->street = 'Probeweg 7';
|
||||
$address->postCode = '99999';
|
||||
$address->city = 'MusterOrt';
|
||||
$address->country = 'D';
|
||||
|
||||
return $address;
|
||||
}
|
||||
}
|
||||
@@ -205,46 +205,34 @@ class ParticipantDtoTest extends TestCase
|
||||
return $insurance;
|
||||
}
|
||||
|
||||
public function testRequiresOwnEmailIsFalseForNonApplicantChild(): void
|
||||
public function testIsChildIsTrueBelowTheAgeThreshold(): void
|
||||
{
|
||||
$participant = new ParticipantDto();
|
||||
$participant->index = 1;
|
||||
$participant->dateOfBirth = new \DateTimeImmutable('2015-01-01');
|
||||
|
||||
$this->assertFalse($participant->requiresOwnEmail());
|
||||
$this->assertTrue($participant->isChild());
|
||||
}
|
||||
|
||||
public function testRequiresOwnEmailIsTrueForNonApplicantAdult(): void
|
||||
public function testIsChildIsFalseForAnAdult(): void
|
||||
{
|
||||
$participant = new ParticipantDto();
|
||||
$participant->index = 1;
|
||||
$participant->dateOfBirth = new \DateTimeImmutable('1990-01-01');
|
||||
|
||||
$this->assertTrue($participant->requiresOwnEmail());
|
||||
$this->assertFalse($participant->isChild());
|
||||
}
|
||||
|
||||
public function testRequiresOwnEmailIsTrueForTheApplicantEvenAsAChild(): void
|
||||
{
|
||||
$participant = new ParticipantDto();
|
||||
$participant->index = 0;
|
||||
$participant->dateOfBirth = new \DateTimeImmutable('2015-01-01');
|
||||
|
||||
$this->assertTrue(
|
||||
$participant->requiresOwnEmail(),
|
||||
'The applicant is the booking contact and always has to be reachable'
|
||||
);
|
||||
}
|
||||
|
||||
public function testRequiresOwnEmailTreatsUnknownAgeAsAdult(): void
|
||||
public function testIsChildTreatsUnknownAgeAsAdult(): void
|
||||
{
|
||||
$participant = new ParticipantDto();
|
||||
$participant->index = 1;
|
||||
$participant->dateOfBirth = null;
|
||||
|
||||
$this->assertTrue($participant->requiresOwnEmail());
|
||||
$this->assertFalse($participant->isChild(), 'An unknown date of birth counts as an adult');
|
||||
}
|
||||
|
||||
public function testRequiresOwnEmailBoundaryAtChildAgeThreshold(): void
|
||||
public function testIsChildBoundaryAtAgeThreshold(): void
|
||||
{
|
||||
$exactlyThreshold = new ParticipantDto();
|
||||
$exactlyThreshold->index = 1;
|
||||
@@ -257,7 +245,7 @@ class ParticipantDtoTest extends TestCase
|
||||
->modify(sprintf('-%d years', ParticipantDto::CHILD_AGE_THRESHOLD))
|
||||
->modify('+1 day');
|
||||
|
||||
$this->assertTrue($exactlyThreshold->requiresOwnEmail());
|
||||
$this->assertFalse($oneDayShort->requiresOwnEmail());
|
||||
$this->assertFalse($exactlyThreshold->isChild());
|
||||
$this->assertTrue($oneDayShort->isChild());
|
||||
}
|
||||
}
|
||||
@@ -877,7 +877,7 @@ class ParticipantEditDtoTest extends TestCase
|
||||
* available ski pass. Ski pass validation depends on the travel actually offering
|
||||
* passes, so a travel without them is a distinct fixture, not the default.
|
||||
*/
|
||||
public function testChildWithoutEmailPassesStrictValidation(): void
|
||||
public function testChildWithoutEmailFailsStrictValidation(): void
|
||||
{
|
||||
$bookingDto = $this->createBookingDtoWithParticipants([
|
||||
$this->createAdultParticipant('[email protected]'),
|
||||
@@ -886,10 +886,14 @@ class ParticipantEditDtoTest extends TestCase
|
||||
|
||||
$violations = $this->validateStrict($bookingDto, 1);
|
||||
|
||||
$this->assertSame([], $this->emailRequiredMessages($violations));
|
||||
$this->assertSame(
|
||||
['Bitte angeben'],
|
||||
$this->emailRequiredMessages($violations),
|
||||
'BusPro requires a Mail-Adresse for every participant, children included'
|
||||
);
|
||||
}
|
||||
|
||||
public function testChildWithNullEmailPassesStrictValidation(): void
|
||||
public function testChildWithNullEmailFailsStrictValidation(): void
|
||||
{
|
||||
$child = $this->createChildParticipant('');
|
||||
$child->email = null;
|
||||
@@ -901,7 +905,23 @@ class ParticipantEditDtoTest extends TestCase
|
||||
|
||||
$violations = $this->validateStrict($bookingDto, 1);
|
||||
|
||||
$this->assertSame([], $this->emailRequiredMessages($violations));
|
||||
$this->assertSame(['Bitte angeben'], $this->emailRequiredMessages($violations));
|
||||
}
|
||||
|
||||
public function testChildSharingTheApplicantsEmailPassesStrictValidation(): void
|
||||
{
|
||||
$bookingDto = $this->createBookingDtoWithParticipants([
|
||||
$this->createAdultParticipant('[email protected]'),
|
||||
$this->createChildParticipant('[email protected]'),
|
||||
]);
|
||||
|
||||
$violations = $this->validateStrict($bookingDto, 1);
|
||||
|
||||
$this->assertSame(
|
||||
[],
|
||||
$this->emailRequiredMessages($violations),
|
||||
'A child inherits the applicant address, which BusPro accepts'
|
||||
);
|
||||
}
|
||||
|
||||
public function testChildWithMalformedEmailStillFailsEmailFormatValidation(): void
|
||||
@@ -984,7 +1004,7 @@ class ParticipantEditDtoTest extends TestCase
|
||||
$this->assertSame(['Bitte angeben'], $this->emailRequiredMessages($violations));
|
||||
}
|
||||
|
||||
public function testDependentOneDayShortOfSixteenDoesNotRequireEmail(): void
|
||||
public function testDependentOneDayShortOfSixteenStillRequiresEmail(): void
|
||||
{
|
||||
$participant = $this->createAdultParticipant('');
|
||||
$participant->dateOfBirth = (new \DateTimeImmutable('today'))->modify('-16 years')->modify('+1 day');
|
||||
@@ -996,7 +1016,7 @@ class ParticipantEditDtoTest extends TestCase
|
||||
|
||||
$violations = $this->validateStrict($bookingDto, 1);
|
||||
|
||||
$this->assertSame([], $this->emailRequiredMessages($violations));
|
||||
$this->assertSame(['Bitte angeben'], $this->emailRequiredMessages($violations));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -74,57 +74,55 @@ class CreateFieldStateProviderTest extends TestCase
|
||||
);
|
||||
}
|
||||
|
||||
public function testEmailIsNotRequiredForNonApplicantChild(): void
|
||||
public function testEmailIsRequiredForEveryParticipantIncludingChildren(): void
|
||||
{
|
||||
$bookingDto = $this->createBookingDtoWithApplicantAndDependent(new \DateTimeImmutable('2015-01-01'));
|
||||
|
||||
$this->assertFalse(
|
||||
$this->provider->getFieldState('email', $bookingDto, 1)['required'],
|
||||
'A child travelling with an applicant does not need an email address of their own'
|
||||
$this->assertArrayNotHasKey(
|
||||
'required',
|
||||
$this->provider->getFieldState('email', $bookingDto, 1),
|
||||
'Requiredness is the form type base option now that it is unconditional'
|
||||
);
|
||||
}
|
||||
|
||||
public function testEmailIsRequiredForNonApplicantAdult(): void
|
||||
public function testMobileIsRequiredForTheApplicantOnly(): void
|
||||
{
|
||||
$bookingDto = $this->createBookingDtoWithApplicantAndDependent(new \DateTimeImmutable('1990-01-01'));
|
||||
|
||||
$this->assertTrue($this->provider->getFieldState('email', $bookingDto, 1)['required']);
|
||||
$this->assertTrue($this->provider->getFieldState('mobile', $bookingDto, 0)['required']);
|
||||
$this->assertFalse($this->provider->getFieldState('mobile', $bookingDto, 1)['required']);
|
||||
}
|
||||
|
||||
public function testEmailIsRequiredForTheApplicantEvenAsAChild(): void
|
||||
public function testMobileAndAddressAreNotRequiredOfParticipantZeroWhenTheApplicantDoesNotTravel(): void
|
||||
{
|
||||
$bookingDto = $this->createBookingDtoWithApplicantAndDependent(new \DateTimeImmutable('2015-01-01'));
|
||||
$bookingDto->participants[0]->dateOfBirth = new \DateTimeImmutable('2015-01-01');
|
||||
$bookingDto->applicantTravels = false;
|
||||
|
||||
$this->assertTrue(
|
||||
$this->provider->getFieldState('email', $bookingDto, 0)['required'],
|
||||
'The applicant is the booking contact and always has to be reachable'
|
||||
$this->assertFalse(
|
||||
$this->provider->getFieldState('mobile', $bookingDto, 0)['required'],
|
||||
'BusPro does not ask a telefonmobil of an ordinary participant'
|
||||
);
|
||||
$this->assertFalse(
|
||||
$this->provider->getFieldState('address', $bookingDto, 0)['required'],
|
||||
'BusPro accepts an empty anschrift for an ordinary participant'
|
||||
);
|
||||
}
|
||||
|
||||
public function testEmailIsRequiredWhenDateOfBirthIsUnknown(): void
|
||||
public function testParticipantZeroIsEditableWhenTheApplicantDoesNotTravel(): void
|
||||
{
|
||||
$bookingDto = $this->createBookingDtoWithApplicantAndDependent(new \DateTimeImmutable('2015-01-01'));
|
||||
$bookingDto->participants[1]->dateOfBirth = null;
|
||||
$bookingDto->participants[0]->personId = 4711;
|
||||
|
||||
$this->assertTrue(
|
||||
$this->provider->getFieldState('email', $bookingDto, 1)['required'],
|
||||
'An unknown age counts as an adult'
|
||||
$this->provider->shouldRenderAsStaticText('firstName', $bookingDto, 0),
|
||||
'A logged-in applicant who travels keeps their prefilled data locked'
|
||||
);
|
||||
}
|
||||
|
||||
public function testEmailRequirementFlipsWhenDateOfBirthChanges(): void
|
||||
{
|
||||
$bookingDto = $this->createBookingDtoWithApplicantAndDependent(new \DateTimeImmutable('2015-01-01'));
|
||||
$dependent = $bookingDto->participants[1];
|
||||
$bookingDto->applicantTravels = false;
|
||||
|
||||
$this->assertFalse($this->provider->getFieldState('email', $bookingDto, 1)['required']);
|
||||
|
||||
$dependent->dateOfBirth = new \DateTimeImmutable('1990-01-01');
|
||||
|
||||
$this->assertTrue(
|
||||
$this->provider->getFieldState('email', $bookingDto, 1)['required'],
|
||||
'Correcting a child date of birth to an adult one must reinstate the requirement'
|
||||
$this->assertFalse(
|
||||
$this->provider->shouldRenderAsStaticText('firstName', $bookingDto, 0),
|
||||
'Once the applicant does not travel, participant[0] is an ordinary traveller'
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,11 +31,14 @@ class EditFieldStateProviderTest extends TestCase
|
||||
$this->assertTrue($this->provider->getFieldState('email', $bookingDto, 1)['required']);
|
||||
}
|
||||
|
||||
public function testEmailIsNotRequiredForNonApplicantChild(): void
|
||||
public function testEmailIsRequiredForNonApplicantChild(): void
|
||||
{
|
||||
$bookingDto = $this->createBookingDto(new \DateTimeImmutable('2015-01-01'), false);
|
||||
|
||||
$this->assertFalse($this->provider->getFieldState('email', $bookingDto, 1)['required']);
|
||||
$this->assertTrue(
|
||||
$this->provider->getFieldState('email', $bookingDto, 1)['required'],
|
||||
'BusPro requires a Mail-Adresse for every participant, children included'
|
||||
);
|
||||
}
|
||||
|
||||
public function testEmailIsNotRequiredForInternalAgencyBookingsEvenForAdults(): void
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Form\Service;
|
||||
|
||||
use App\BusProNet\Model\Travel;
|
||||
use App\Form\Model\BookingDto;
|
||||
use App\Form\Model\ParticipantDto;
|
||||
use App\Form\Service\ParticipantDateOfBirthFieldHandler;
|
||||
use App\Form\Service\ParticipantEmailFieldHandler;
|
||||
use App\Form\Service\ParticipantFieldHandlerRegistry;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psr\Log\NullLogger;
|
||||
|
||||
class ParticipantEmailFieldHandlerTest extends TestCase
|
||||
{
|
||||
private ParticipantEmailFieldHandler $handler;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->handler = new ParticipantEmailFieldHandler();
|
||||
}
|
||||
|
||||
public function testChildWithoutEmailInheritsTheApplicants(): void
|
||||
{
|
||||
$bookingDto = $this->createBookingDto();
|
||||
|
||||
$this->handler->processField(['email' => ''], $bookingDto, 1);
|
||||
|
||||
$this->assertSame('[email protected]', $bookingDto->participants[1]->email);
|
||||
}
|
||||
|
||||
public function testChildKeepsAnEmailThatWasTypedIn(): void
|
||||
{
|
||||
$bookingDto = $this->createBookingDto();
|
||||
|
||||
$this->handler->processField(['email' => '[email protected]'], $bookingDto, 1);
|
||||
|
||||
$this->assertSame(
|
||||
'[email protected]',
|
||||
$bookingDto->participants[1]->email,
|
||||
'The pre-filled address stays overridable'
|
||||
);
|
||||
}
|
||||
|
||||
public function testAdultWithoutEmailDoesNotInherit(): void
|
||||
{
|
||||
$bookingDto = $this->createBookingDto();
|
||||
$bookingDto->participants[1]->dateOfBirth = new \DateTimeImmutable('1990-01-01');
|
||||
|
||||
$this->handler->processField(['email' => ''], $bookingDto, 1);
|
||||
|
||||
$this->assertNull(
|
||||
$bookingDto->participants[1]->email,
|
||||
'An adult supplies their own address; NotBlank reports the gap'
|
||||
);
|
||||
}
|
||||
|
||||
public function testApplicantDoesNotInheritFromThemselves(): void
|
||||
{
|
||||
$bookingDto = $this->createBookingDto();
|
||||
$bookingDto->participants[0]->dateOfBirth = new \DateTimeImmutable('2015-01-01');
|
||||
|
||||
$this->handler->processField(['email' => ''], $bookingDto, 0);
|
||||
|
||||
$this->assertNull($bookingDto->participants[0]->email);
|
||||
}
|
||||
|
||||
public function testChildAtIndexZeroInheritsWhenTheApplicantDoesNotTravel(): void
|
||||
{
|
||||
$bookingDto = $this->createBookingDto();
|
||||
$bookingDto->applicantTravels = false;
|
||||
$bookingDto->applicant = $this->createParticipant('[email protected]', '1981-03-16');
|
||||
$bookingDto->participants[0]->dateOfBirth = new \DateTimeImmutable('2015-01-01');
|
||||
|
||||
$this->handler->processField(['email' => ''], $bookingDto, 0);
|
||||
|
||||
$this->assertSame('[email protected]', $bookingDto->participants[0]->email);
|
||||
}
|
||||
|
||||
public function testHandlerRunsAfterDateOfBirth(): void
|
||||
{
|
||||
$this->assertSame(
|
||||
['dateOfBirth'],
|
||||
$this->handler->getDependencies(),
|
||||
'Whether someone counts as a child is only known once their DOB is processed'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The handler runs in PRE_SUBMIT and writes to the DTO, but the form then binds the submitted
|
||||
* data over it. Only fields the registry syncs back survive, so the pre-filled address has to
|
||||
* reappear in the returned data - otherwise the blank wins and the field renders empty.
|
||||
*/
|
||||
public function testPreFilledEmailIsSyncedBackIntoTheSubmittedData(): void
|
||||
{
|
||||
$bookingDto = $this->createBookingDto();
|
||||
$registry = new ParticipantFieldHandlerRegistry([
|
||||
new ParticipantDateOfBirthFieldHandler(new NullLogger()),
|
||||
new ParticipantEmailFieldHandler(),
|
||||
]);
|
||||
|
||||
$synced = $registry->processFieldsForParticipantAndSync(['email' => ''], $bookingDto, 1);
|
||||
|
||||
$this->assertSame('[email protected]', $bookingDto->participants[1]->email);
|
||||
$this->assertSame(
|
||||
'[email protected]',
|
||||
$synced['email'],
|
||||
'Without the sync the form binds the blank back over the pre-filled address'
|
||||
);
|
||||
}
|
||||
|
||||
private function createBookingDto(): BookingDto
|
||||
{
|
||||
$bookingDto = new BookingDto(new Travel(), 1);
|
||||
$bookingDto->participants = [
|
||||
$this->createParticipant('[email protected]', '1980-01-01'),
|
||||
$this->createParticipant('', '2015-01-01'),
|
||||
];
|
||||
$bookingDto->participants[0]->index = 0;
|
||||
$bookingDto->participants[1]->index = 1;
|
||||
$bookingDto->participants[1]->email = null;
|
||||
|
||||
return $bookingDto;
|
||||
}
|
||||
|
||||
private function createParticipant(string $email, string $dateOfBirth): ParticipantDto
|
||||
{
|
||||
$participant = new ParticipantDto();
|
||||
$participant->email = '' !== $email ? $email : null;
|
||||
$participant->dateOfBirth = new \DateTimeImmutable($dateOfBirth);
|
||||
|
||||
return $participant;
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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 ??= [
|
||||
|
||||
Reference in new issue
Block a user