fix: always fill-in empty participants names when submitting to api

This commit is contained in:
Björn Fromme
2026-03-16 12:03:00 +01:00
parent 20162cceef
commit 3644b935fd
2 changed files with 137 additions and 13 deletions
@@ -33,7 +33,7 @@ class PersonalDataSynchronizer
*
* @param array<ParticipantDto> $participants The participants array from the form
* @param Booking $bookingData The booking data object to update
* @param bool $isInternalAgencyBooking Whether to fill default names for canceled participants
* @param bool $isInternalAgencyBooking Whether to fill default names for participants with empty names
*/
public function updateParticipantPersonalData(
array $participants,
@@ -48,20 +48,18 @@ class PersonalDataSynchronizer
$bookingData->participants[$participant->index]->firstName = $participant->firstName;
$bookingData->participants[$participant->index]->name = $participant->lastName;
// For internal agency bookings, canceled participants with empty names get default values
// since they are read-only in the UI and cannot be fixed by applicants
// For internal agency bookings, participants with empty names get default values.
// Agencies pre-book slots with placeholder data (e.g. applicant surname, empty first name),
// and the BPN API rejects updates with empty name fields.
if ($isInternalAgencyBooking) {
$status = $bookingData->participantsStatus[$participant->index] ?? null;
if ('S' === $status) {
$defaultName = sprintf('Teilnehmer:in %d', $participant->index + 1);
$personalData = $bookingData->participants[$participant->index];
$defaultName = sprintf('Teilnehmer:in %d', $participant->index + 1);
$personalData = $bookingData->participants[$participant->index];
if (null === $personalData->firstName || '' === $personalData->firstName) {
$personalData->firstName = $defaultName;
}
if (null === $personalData->name || '' === $personalData->name) {
$personalData->name = $defaultName;
}
if (null === $personalData->firstName || '' === $personalData->firstName) {
$personalData->firstName = $defaultName;
}
if (null === $personalData->name || '' === $personalData->name) {
$personalData->name = $defaultName;
}
}
@@ -564,6 +564,132 @@ class BookingDataProcessorTest extends TestCase
$this->assertEquals('', $canceledParticipant->name);
}
public function testConfirmedParticipantEmptyNamesFilledForAgencyBooking(): void
{
$formData = $this->createFormDataWithConfirmedParticipantEmptyNames();
$this->processor->createUpdateRequestPayload($formData);
// Confirmed participant (index 1) with empty names should have default names filled
$participant = $formData->booking->participants[1];
$this->assertEquals('Teilnehmer:in 2', $participant->firstName);
$this->assertEquals('Teilnehmer:in 2', $participant->name);
// Active participant (index 0) should retain original names from form
$activeParticipant = $formData->booking->participants[0];
$this->assertEquals('Participant0', $activeParticipant->firstName);
$this->assertEquals('LastName', $activeParticipant->name);
}
public function testConfirmedParticipantPartialEmptyNameFilledForAgencyBooking(): void
{
$formData = $this->createFormDataWithConfirmedParticipantPartialEmptyName();
$this->processor->createUpdateRequestPayload($formData);
// Participant with lastName but empty firstName should get default firstName only
$participant = $formData->booking->participants[1];
$this->assertEquals('Teilnehmer:in 2', $participant->firstName);
$this->assertEquals('Schnekenburger', $participant->name);
}
private function createFormDataWithConfirmedParticipantEmptyNames(): BookingDto
{
$bookingDto = new BookingDto($this->createMockTravel(), 1);
$bookingDto->booking = $this->createMockBookingWithEmptyNameParticipant('F', '', '');
$bookingDto->agencyCode = '0004';
$bookingDto->participants = [
$this->createMockParticipantDto(0, 'F'),
$this->createMockParticipantDtoWithEmptyNames(1, 'F'),
];
return $bookingDto;
}
private function createFormDataWithConfirmedParticipantPartialEmptyName(): BookingDto
{
$bookingDto = new BookingDto($this->createMockTravel(), 1);
$bookingDto->booking = $this->createMockBookingWithEmptyNameParticipant('F', '', 'Schnekenburger');
$bookingDto->agencyCode = '0004';
$bookingDto->participants = [
$this->createMockParticipantDto(0, 'F'),
$this->createMockParticipantDtoWithPartialName(1, 'F', '', 'Schnekenburger'),
];
return $bookingDto;
}
private function createMockBookingWithEmptyNameParticipant(
string $status,
string $firstName,
string $lastName,
): Booking {
$booking = new Booking();
$booking->id = 123;
$booking->status = 'ACTIVE';
$booking->agencyId = 999;
$booking->dateId = 1;
$booking->hotelId = 1;
$booking->paymentId = '1';
$booking->paymentLabel = 'Credit Card';
$booking->paymentType = 'CC';
$booking->additionalServices = [];
$booking->transportationServices = [];
$booking->pickups = [];
$booking->dropOffs = [];
$emptyNameParticipant = new PersonalData();
$emptyNameParticipant->firstName = $firstName;
$emptyNameParticipant->name = $lastName;
$emptyNameParticipant->dateOfBirth = new \DateTimeImmutable('1990-01-01');
$emptyNameParticipant->gender = 'M';
$emptyNameParticipant->nationality = 'DE';
$emptyNameParticipant->address = new Address();
$emptyNameParticipant->communication = new Communication();
$booking->participants = [
$this->createMockPersonalData('Participant0'),
$emptyNameParticipant,
];
$booking->participantsStatus = ['F', $status];
$booking->applicant = $this->createMockPersonalData('Applicant');
$booking->bankAccount = null;
$booking->rooms = [];
return $booking;
}
private function createMockParticipantDtoWithPartialName(
int $index,
string $status,
string $firstName,
string $lastName,
): ParticipantDto {
$participant = new ParticipantDto();
$participant->index = $index;
$participant->status = $status;
$participant->firstName = $firstName;
$participant->lastName = $lastName;
$participant->dateOfBirth = new \DateTimeImmutable('1990-01-01');
$participant->gender = 'M';
$participant->nationality = 'DE';
$participant->height = '175';
$participant->weight = '70';
$participant->shoeSize = '40';
$participant->email = null;
$participant->mobile = null;
$participant->courses = [];
$participant->additionalServices = [];
$participant->skiPass = null;
$participant->board = [];
$participant->rentals = [];
$participant->transportationOutbound = $this->createMockService(1);
$participant->transportationInbound = $this->createMockService(2);
$participant->pickup = null;
return $participant;
}
private function createFormDataWithCanceledParticipantEmptyNames(): BookingDto
{
$bookingDto = new BookingDto($this->createMockTravel(), 1);