fix: make personal data editable in bookings as permitted by bpn

This commit is contained in:
Björn Fromme
2026-06-23 15:24:10 +02:00
parent 287ec30cf7
commit 145f7de781
2 changed files with 19 additions and 47 deletions
@@ -8,44 +8,23 @@ use App\Form\Model\BookingDto;
use App\Form\Service\Contract\FieldConditionInterface; use App\Form\Service\Contract\FieldConditionInterface;
/** /**
* Condition that determines if personal data fields should be hidden based on BPN mutability flag. * Condition that determines if personal data fields should be hidden based on the
* booking-level MOEGLICHEAENDERUNGEN/teilnehmerdaten flag.
* *
* This condition respects the BPN API's per-participant mutability flag (`aenderungmoeglich`). * Uses Travel::participantDataMutable (defaults to true) which is populated from the
* When a participant's data is not mutable (mutable=false), personal data fields should be * MOEGLICHEAENDERUNGEN API endpoint. When BPN marks participant data as not changeable
* hidden and displayed as static text. * for a booking, all core personal data fields are rendered as static text.
* *
* This condition is combined with FirstParticipantReadOnlyCondition via OR in edit mode. * Exception: internal agency bookings always allow editing regardless of this flag.
* FirstParticipantReadOnlyCondition handles agency-based read-only logic for first participant,
* while this condition applies BPN mutability rules to all participants.
*
* Exception: For internal agency bookings (agency code 0004), the BPN mutability flag
* is ignored for all participants. Agency staff need full control over participant data
* regardless of BPN's mutability restrictions.
*
* In edit mode, BPN determines mutability based on business rules (e.g., payment status,
* booking state, etc.). We must respect this flag to prevent users from attempting to
* modify data that BPN will reject.
*
* When this condition is satisfied (returns true), the template renders fields as
* static text via the `field_or_static` macro instead of form inputs.
*/ */
class PersonalDataMutabilityCondition implements FieldConditionInterface class PersonalDataMutabilityCondition implements FieldConditionInterface
{ {
/** /**
* Evaluates if personal data fields should be hidden (not editable).
*
* Returns true when the participant's mutable flag is false, indicating
* that BPN does not allow modifications to this participant's data.
* When true, personal data fields should be hidden and displayed as static text.
*
* Exception: For internal agency bookings, always returns false to allow
* editing all participants regardless of BPN's mutability flag.
*
* @param BookingDto $bookingDto The current booking data * @param BookingDto $bookingDto The current booking data
* @param int $participantIndex The index of the participant being evaluated * @param int $participantIndex The index of the participant being evaluated
* @param array<string, mixed> $formData Current form data (unused) * @param array<string, mixed> $formData Current form data (unused)
* *
* @return bool True if fields should be hidden (participant data not mutable) * @return bool True if fields should be shown as static text (BPN disallows changes)
*/ */
public function evaluate(BookingDto $bookingDto, int $participantIndex, array $formData): bool public function evaluate(BookingDto $bookingDto, int $participantIndex, array $formData): bool
{ {
@@ -55,13 +34,9 @@ class PersonalDataMutabilityCondition implements FieldConditionInterface
return false; return false;
} }
$participant = $bookingDto->getParticipant($participantIndex); // Use the booking-level teilnehmerdaten flag from MOEGLICHEAENDERUNGEN.
if (null === $participant) { // Defaults to true (editable) when the endpoint is unavailable.
return false; return false === $bookingDto->travel->participantDataMutable;
}
// Hide personal data fields if BPN indicates participant is not mutable
return false === $participant->mutable;
} }
/** /**
+9 -12
View File
@@ -65,23 +65,20 @@ class EditFieldStateProvider extends AbstractFieldStateProvider
$personalDataMutabilityCondition $personalDataMutabilityCondition
); );
// Render all personal data fields as static text if first participant in non-internal agency OR BPN indicates not mutable // Core identity fields: static text if first participant in non-internal agency OR BPN indicates not mutable
// Using 'static_text' state (not 'hidden') so template renders values as static text foreach (['firstName', 'lastName', 'dateOfBirth', 'gender', 'nationality'] as $field) {
$personalDataFields = [
'firstName',
'lastName',
'dateOfBirth',
'gender',
'nationality',
'email',
'mobile',
];
foreach ($personalDataFields as $field) {
$this->fieldStateConditions[$field] = [ $this->fieldStateConditions[$field] = [
'static_text' => $personalDataHiddenCondition, 'static_text' => $personalDataHiddenCondition,
]; ];
} }
// Contact fields: only the applicant (index 0) is read-only — participants can always update email/phone
foreach (['email', 'mobile'] as $field) {
$this->fieldStateConditions[$field] = [
'static_text' => $firstParticipantReadOnlyCondition,
];
}
// Address fields - render as static text if first participant in non-internal agency OR participant not mutable // Address fields - render as static text if first participant in non-internal agency OR participant not mutable
$this->fieldStateConditions['address'] = [ $this->fieldStateConditions['address'] = [
'static_text' => $personalDataHiddenCondition, 'static_text' => $personalDataHiddenCondition,