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;
/**
* 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`).
* When a participant's data is not mutable (mutable=false), personal data fields should be
* hidden and displayed as static text.
* Uses Travel::participantDataMutable (defaults to true) which is populated from the
* MOEGLICHEAENDERUNGEN API endpoint. When BPN marks participant data as not changeable
* for a booking, all core personal data fields are rendered as static text.
*
* This condition is combined with FirstParticipantReadOnlyCondition via OR in edit mode.
* 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.
* Exception: internal agency bookings always allow editing regardless of this flag.
*/
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 int $participantIndex The index of the participant being evaluated
* @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
{
@@ -55,13 +34,9 @@ class PersonalDataMutabilityCondition implements FieldConditionInterface
return false;
}
$participant = $bookingDto->getParticipant($participantIndex);
if (null === $participant) {
return false;
}
// Hide personal data fields if BPN indicates participant is not mutable
return false === $participant->mutable;
// Use the booking-level teilnehmerdaten flag from MOEGLICHEAENDERUNGEN.
// Defaults to true (editable) when the endpoint is unavailable.
return false === $bookingDto->travel->participantDataMutable;
}
/**
+9 -12
View File
@@ -65,23 +65,20 @@ class EditFieldStateProvider extends AbstractFieldStateProvider
$personalDataMutabilityCondition
);
// Render all personal data fields as 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
$personalDataFields = [
'firstName',
'lastName',
'dateOfBirth',
'gender',
'nationality',
'email',
'mobile',
];
foreach ($personalDataFields as $field) {
// Core identity fields: static text if first participant in non-internal agency OR BPN indicates not mutable
foreach (['firstName', 'lastName', 'dateOfBirth', 'gender', 'nationality'] as $field) {
$this->fieldStateConditions[$field] = [
'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
$this->fieldStateConditions['address'] = [
'static_text' => $personalDataHiddenCondition,