fix: do not copy applicant address into participant for agency bookings
This commit is contained in:
@@ -8,6 +8,7 @@ use App\BusProNet\Constants;
|
|||||||
use App\BusProNet\Model\Booking;
|
use App\BusProNet\Model\Booking;
|
||||||
use App\BusProNet\Model\Travel;
|
use App\BusProNet\Model\Travel;
|
||||||
use App\BusProNet\Utility\DirectionMapper;
|
use App\BusProNet\Utility\DirectionMapper;
|
||||||
|
use App\BusProNet\XmlLoader\AgencyLoader;
|
||||||
use App\Form\Model\BankAccountDto;
|
use App\Form\Model\BankAccountDto;
|
||||||
use App\Form\Model\BookingDto;
|
use App\Form\Model\BookingDto;
|
||||||
use App\Form\Model\ParticipantDto;
|
use App\Form\Model\ParticipantDto;
|
||||||
@@ -42,11 +43,12 @@ class BookingDataProcessor
|
|||||||
*
|
*
|
||||||
* IMPORTANT: Address handling for edit mode
|
* IMPORTANT: Address handling for edit mode
|
||||||
* - ParticipantDto::fromPersonalData() clones address objects to prevent shared references
|
* - ParticipantDto::fromPersonalData() clones address objects to prevent shared references
|
||||||
* - First participant's address is NOT auto-populated from applicant
|
* - For normal bookings, participant[0]'s missing address/dimensions are filled from the
|
||||||
* - Template uses placeholders to show applicant's address as hints
|
* applicant (same person in normal bookings, but BPN may omit fields in <teilnehmer>)
|
||||||
* - This prevents address data from being inadvertently modified during form binding
|
* - For internal agency bookings, this copy is skipped: the applicant is a customer, not
|
||||||
|
* the first participant, so copying applicant data into participant[0] would be incorrect
|
||||||
*/
|
*/
|
||||||
public function createBookingDtoFromBooking(Booking $booking, Travel $travel): BookingDto
|
public function createBookingDtoFromBooking(Booking $booking, Travel $travel, bool $isInternalAgencyBooking = false): BookingDto
|
||||||
{
|
{
|
||||||
$dto = new BookingDto($travel, $booking->hotelId);
|
$dto = new BookingDto($travel, $booking->hotelId);
|
||||||
|
|
||||||
@@ -68,11 +70,12 @@ class BookingDataProcessor
|
|||||||
$participantData = ParticipantDto::fromPersonalData($participant);
|
$participantData = ParticipantDto::fromPersonalData($participant);
|
||||||
$participantData->index = $index;
|
$participantData->index = $index;
|
||||||
|
|
||||||
// First participant (applicant): copy data from applicant if participant data is empty
|
// For normal bookings, applicant === participant[0]: copy address and body dimensions
|
||||||
// BPN API may return full data only in <anmelder> but minimal/empty data in <teilnehmer id="1">
|
// from applicant when BPN returns full data only in <anmelder> and minimal data in
|
||||||
if (0 === $index) {
|
// <teilnehmer id="1">. Skipped for internal agency bookings where the applicant is
|
||||||
|
// a customer (a different entity from the first traveler).
|
||||||
|
if (0 === $index && false === $isInternalAgencyBooking) {
|
||||||
// Copy address if first participant has no street (indicating empty/incomplete address)
|
// Copy address if first participant has no street (indicating empty/incomplete address)
|
||||||
// This allows applicant and first participant to be different people with different addresses
|
|
||||||
$isEmpty = null === $participantData->address
|
$isEmpty = null === $participantData->address
|
||||||
|| null === $participantData->address->street
|
|| null === $participantData->address->street
|
||||||
|| '' === trim($participantData->address->street);
|
|| '' === trim($participantData->address->street);
|
||||||
|
|||||||
@@ -138,13 +138,21 @@ class BookingEditDataLoader
|
|||||||
$this->travelDataService->patchAvailabilities($travelData, $availabilities);
|
$this->travelDataService->patchAvailabilities($travelData, $availabilities);
|
||||||
$this->travelDataService->patchMutability($travelData, $mutableData);
|
$this->travelDataService->patchMutability($travelData, $mutableData);
|
||||||
|
|
||||||
$formData = $this->bookingDataProcessor->createBookingDtoFromBooking($bookingData, $travelData);
|
// Resolve agency code before building the DTO so the internal-agency flag can be
|
||||||
|
// passed to createBookingDtoFromBooking, preventing applicant data from being
|
||||||
// Set agency code for internal agency detection (used by field state conditions)
|
// copied into participant[0] for agency bookings where they are different people.
|
||||||
$formData->agencyCode = null !== $bookingData->agencyId
|
$agencyCode = null !== $bookingData->agencyId
|
||||||
? $this->agencyLoader->loadById($bookingData->agencyId)?->code
|
? $this->agencyLoader->loadById($bookingData->agencyId)?->code
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
|
$formData = $this->bookingDataProcessor->createBookingDtoFromBooking(
|
||||||
|
$bookingData,
|
||||||
|
$travelData,
|
||||||
|
AgencyLoader::INTERNAL_AGENCY_CODE === $agencyCode,
|
||||||
|
);
|
||||||
|
|
||||||
|
$formData->agencyCode = $agencyCode;
|
||||||
|
|
||||||
// Set original fingerprint BEFORE applying draft, so dirty detection
|
// Set original fingerprint BEFORE applying draft, so dirty detection
|
||||||
// compares against the original API data (not the draft-modified data)
|
// compares against the original API data (not the draft-modified data)
|
||||||
$formData->originalFingerprint = $this->fingerprintService->generateFingerprint($formData, true);
|
$formData->originalFingerprint = $this->fingerprintService->generateFingerprint($formData, true);
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class BookingEditSubmitGuard
|
|||||||
*/
|
*/
|
||||||
public function reconcileImmutableCategories(BookingDto $workingDto, Booking $freshBooking): bool
|
public function reconcileImmutableCategories(BookingDto $workingDto, Booking $freshBooking): bool
|
||||||
{
|
{
|
||||||
$baselineDto = $this->bookingDataProcessor->createBookingDtoFromBooking($freshBooking, $workingDto->travel);
|
$baselineDto = $this->bookingDataProcessor->createBookingDtoFromBooking($freshBooking, $workingDto->travel, $workingDto->isInternalAgencyBooking());
|
||||||
// Booking-level D-4 cutoff used as submit-time safety net for rentals.
|
// Booking-level D-4 cutoff used as submit-time safety net for rentals.
|
||||||
$serviceCutoffReachedCondition = new TravelStartCutoffReachedCondition(
|
$serviceCutoffReachedCondition = new TravelStartCutoffReachedCondition(
|
||||||
TravelStartCutoffReachedCondition::DEFAULT_DAYS_BEFORE_START
|
TravelStartCutoffReachedCondition::DEFAULT_DAYS_BEFORE_START
|
||||||
|
|||||||
Reference in New Issue
Block a user