fix: preserve selected services from booking even when unavailable
When editing a booking, services that were previously booked but are no
longer available in the travel catalog were being dropped. This caused
API error 650 ("Anzahl Leistung stimmt nicht mit Teilnehmerzuordnung
überein") because the service participant counts no longer matched.
The fix ensures that in edit mode, booked services are merged with
travel data services in both:
- Form rendering (ParticipantFieldOptionsProvider): so checkboxes appear
- Handler validation (AbstractParticipantFieldHandler): so selections
are accepted
This allows users to keep their existing service selections or
deliberately replace them with other available options. Create mode
remains unchanged.
This commit is contained in:
@@ -127,7 +127,7 @@ class PersonalDataSynchronizer
|
||||
* Ensures mandatory fields have sensible defaults before submission to the
|
||||
* BPN API. Currently handles nationality which defaults to 'D' (German).
|
||||
*
|
||||
* @param \App\BusProNet\Model\PersonalData $participant The participant to fill defaults for
|
||||
* @param PersonalData $participant The participant to fill defaults for
|
||||
*/
|
||||
private function fillMissingParticipantFields(PersonalData $participant): void
|
||||
{
|
||||
|
||||
@@ -91,7 +91,7 @@ class PersonalData
|
||||
];
|
||||
|
||||
if (true === $includeDateOfBirth) {
|
||||
$dob = $this->dateOfBirth ?? new \DateTimeImmutable(self::DEFAULT_AGE_YEARS . ' years ago');
|
||||
$dob = $this->dateOfBirth ?? new \DateTimeImmutable(self::DEFAULT_AGE_YEARS.' years ago');
|
||||
$payload['geburtsdatum'] = $dob->format('d.m.Y');
|
||||
}
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ class BookingEditDraftCrudController extends AbstractCrudController
|
||||
try {
|
||||
return $this->exportService->createExportResponse($draft);
|
||||
} catch (\RuntimeException $e) {
|
||||
$this->addFlash('danger', 'Export fehlgeschlagen: ' . $e->getMessage());
|
||||
$this->addFlash('danger', 'Export fehlgeschlagen: '.$e->getMessage());
|
||||
|
||||
$url = $this->adminUrlGenerator
|
||||
->setController(self::class)
|
||||
@@ -94,7 +94,7 @@ class BookingEditDraftCrudController extends AbstractCrudController
|
||||
AssociationField::new('user', 'Kundenaccount')->formatValue(fn (User $user) => $user->getEmail()),
|
||||
DateTimeField::new('createdAt', 'erstellt am'),
|
||||
DateTimeField::new('updatedAt', 'aktualisiert am'),
|
||||
JsonDataField::new('formData', 'Daten')->onlyOnDetail()
|
||||
JsonDataField::new('formData', 'Daten')->onlyOnDetail(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ class DashboardController extends AbstractDashboardController
|
||||
{
|
||||
return parent::configureUserMenu($user)
|
||||
->addMenuItems([
|
||||
MenuItem::linkToRoute('MyE&P', 'fa fa-user', 'app_account')
|
||||
MenuItem::linkToRoute('MyE&P', 'fa fa-user', 'app_account'),
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,8 +8,6 @@ use EasyCorp\Bundle\EasyAdminBundle\Config\Actions;
|
||||
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
|
||||
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
|
||||
use EasyCorp\Bundle\EasyAdminBundle\Field\DateTimeField;
|
||||
use EasyCorp\Bundle\EasyAdminBundle\Field\IdField;
|
||||
use EasyCorp\Bundle\EasyAdminBundle\Field\TextEditorField;
|
||||
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
|
||||
|
||||
class UserCrudController extends AbstractCrudController
|
||||
|
||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Form\Service\Abstract;
|
||||
|
||||
use App\BusProNet\Model\Booking;
|
||||
use App\BusProNet\Model\Service;
|
||||
use App\Form\Model\BookingDto;
|
||||
use App\Form\Service\Contract\ParticipantFieldHandlerInterface;
|
||||
@@ -83,7 +84,7 @@ abstract class AbstractParticipantFieldHandler implements ParticipantFieldHandle
|
||||
*/
|
||||
protected function isEditMode(BookingDto $bookingDto): bool
|
||||
{
|
||||
return BookingDto::MODE_EDIT === $bookingDto->mode;
|
||||
return BookingDto::MODE_EDIT === $bookingDto->getMode();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,7 +96,7 @@ abstract class AbstractParticipantFieldHandler implements ParticipantFieldHandle
|
||||
*/
|
||||
protected function isCreateMode(BookingDto $bookingDto): bool
|
||||
{
|
||||
return BookingDto::MODE_CREATE === $bookingDto->mode;
|
||||
return BookingDto::MODE_CREATE === $bookingDto->getMode();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -269,4 +270,65 @@ abstract class AbstractParticipantFieldHandler implements ParticipantFieldHandle
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves available services from travel data, merged with booked services in edit mode.
|
||||
*
|
||||
* In edit mode, services that were previously booked for the participant are included
|
||||
* even if they're no longer available in travel data. This prevents booked services
|
||||
* from being dropped during form validation when the travel catalog has changed.
|
||||
*
|
||||
* @param BookingDto $bookingDto The booking DTO containing travel and booking data
|
||||
* @param int $participantIndex The participant index to retrieve booked services for
|
||||
* @param mixed $serviceGroup The service group(s) to filter by (e.g., TOKEN_RENTALS)
|
||||
* @param bool $filterByTravelDateRange Whether to filter travel services by date range
|
||||
*
|
||||
* @return Service[] Array of available services keyed by service ID
|
||||
*/
|
||||
protected function getAvailableServicesWithBooked(
|
||||
BookingDto $bookingDto,
|
||||
int $participantIndex,
|
||||
mixed $serviceGroup,
|
||||
bool $filterByTravelDateRange = false,
|
||||
): array {
|
||||
$availableServices = $bookingDto->travel->getAdditionalServicesBySubTypes($serviceGroup, $filterByTravelDateRange);
|
||||
|
||||
if ($this->isEditMode($bookingDto) && null !== $bookingDto->booking) {
|
||||
$availableServices = $this->mergeBookedServices(
|
||||
$availableServices,
|
||||
$bookingDto->booking,
|
||||
$participantIndex,
|
||||
$serviceGroup
|
||||
);
|
||||
}
|
||||
|
||||
return $availableServices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges booked services into the available services array.
|
||||
*
|
||||
* @param Service[] $availableServices The services available from travel data
|
||||
* @param Booking $booking The booking containing previously booked services
|
||||
* @param int $participantIndex The participant index to retrieve booked services for
|
||||
* @param mixed $serviceGroup The service group(s) to filter by
|
||||
*
|
||||
* @return Service[] Merged array of services keyed by service ID
|
||||
*/
|
||||
private function mergeBookedServices(
|
||||
array $availableServices,
|
||||
Booking $booking,
|
||||
int $participantIndex,
|
||||
mixed $serviceGroup,
|
||||
): array {
|
||||
$bookedServices = $booking->getAdditionalServicesForParticipantByGroup($participantIndex, $serviceGroup);
|
||||
|
||||
foreach ($bookedServices as $bookedService) {
|
||||
if (false === isset($availableServices[$bookedService->id])) {
|
||||
$availableServices[$bookedService->id] = $bookedService;
|
||||
}
|
||||
}
|
||||
|
||||
return $availableServices;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,8 +99,12 @@ class ParticipantAdditionalServicesFieldHandler extends AbstractParticipantField
|
||||
// Extract current service selections from submitted data
|
||||
$selectedServices = $this->getFieldValue($submittedData, $this->getFieldName()) ?? [];
|
||||
|
||||
// Get available additional services from travel data
|
||||
$availableServices = $bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_ADDITIONAL);
|
||||
// Get available additional services from travel data (includes booked services in edit mode)
|
||||
$availableServices = $this->getAvailableServicesWithBooked(
|
||||
$bookingDto,
|
||||
$participantIndex,
|
||||
Constants::TOKEN_ADDITIONAL
|
||||
);
|
||||
|
||||
// Filter selections to keep only age-appropriate services
|
||||
$validSelections = $this->filterValidServiceSelections(
|
||||
|
||||
@@ -58,7 +58,13 @@ class ParticipantBoardFieldHandler extends AbstractParticipantFieldHandler
|
||||
}
|
||||
|
||||
$selectedBoard = $this->getFieldValue($submittedData, $this->getFieldName()) ?? [];
|
||||
$availableBoard = $bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_BOARD);
|
||||
|
||||
// Get available board options from travel data (includes booked options in edit mode)
|
||||
$availableBoard = $this->getAvailableServicesWithBooked(
|
||||
$bookingDto,
|
||||
$participantIndex,
|
||||
Constants::TOKEN_BOARD
|
||||
);
|
||||
|
||||
$validSelections = $this->filterValidServiceSelections(
|
||||
$selectedBoard,
|
||||
|
||||
@@ -92,8 +92,12 @@ class ParticipantCoursesFieldHandler extends AbstractParticipantFieldHandler
|
||||
// Extract current course selections from submitted data
|
||||
$selectedCourses = $this->getFieldValue($submittedData, $this->getFieldName()) ?? [];
|
||||
|
||||
// Get available courses from travel data
|
||||
$availableCourses = $bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_COURSES);
|
||||
// Get available courses from travel data (includes booked courses in edit mode)
|
||||
$availableCourses = $this->getAvailableServicesWithBooked(
|
||||
$bookingDto,
|
||||
$participantIndex,
|
||||
Constants::TOKEN_COURSES
|
||||
);
|
||||
|
||||
// Filter selections to keep only age-appropriate courses
|
||||
$validSelections = $this->filterValidServiceSelections(
|
||||
|
||||
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
||||
namespace App\Form\Service;
|
||||
|
||||
use App\BusProNet\Constants;
|
||||
use App\BusProNet\Model\Booking;
|
||||
use App\BusProNet\Model\Insurance;
|
||||
use App\BusProNet\Model\Pickup;
|
||||
use App\BusProNet\Model\Room;
|
||||
@@ -122,7 +123,7 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
|
||||
// Returns empty array when no courses available
|
||||
$this->fieldOptionProviders['courses'] = function (BookingDto $bookingDto, int $participantIndex, array $options = []): array {
|
||||
$choices = $this->filterServicesByAgeConstraints(
|
||||
$bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_COURSES),
|
||||
$this->getServicesWithBooked($bookingDto, $participantIndex, Constants::TOKEN_COURSES),
|
||||
$bookingDto,
|
||||
$participantIndex
|
||||
);
|
||||
@@ -166,7 +167,7 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
|
||||
// Returns empty array when no additional services available
|
||||
$this->fieldOptionProviders['additionalServices'] = function (BookingDto $bookingDto, int $participantIndex, array $options = []): array {
|
||||
$choices = $this->filterServicesByAgeConstraints(
|
||||
$bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_ADDITIONAL),
|
||||
$this->getServicesWithBooked($bookingDto, $participantIndex, Constants::TOKEN_ADDITIONAL),
|
||||
$bookingDto,
|
||||
$participantIndex
|
||||
);
|
||||
@@ -217,7 +218,7 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
|
||||
// Returns empty array when no board options available
|
||||
$this->fieldOptionProviders['board'] = function (BookingDto $bookingDto, int $participantIndex, array $options = []): array {
|
||||
$choices = $this->filterServicesByAgeConstraints(
|
||||
$bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_BOARD),
|
||||
$this->getServicesWithBooked($bookingDto, $participantIndex, Constants::TOKEN_BOARD),
|
||||
$bookingDto,
|
||||
$participantIndex
|
||||
);
|
||||
@@ -261,7 +262,7 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
|
||||
// Returns empty array when no dietary options available
|
||||
$this->fieldOptionProviders['veg'] = function (BookingDto $bookingDto, int $participantIndex, array $options = []): array {
|
||||
$choices = $this->filterServicesByAgeConstraints(
|
||||
$bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_VEG, true),
|
||||
$this->getServicesWithBooked($bookingDto, $participantIndex, Constants::TOKEN_VEG, true),
|
||||
$bookingDto,
|
||||
$participantIndex
|
||||
);
|
||||
@@ -316,7 +317,7 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
|
||||
$this->fieldOptionProviders['rentals'] = function (BookingDto $bookingDto, int $participantIndex, array $options = []): array {
|
||||
$choices = $this->filterServicesByAgeConstraints(
|
||||
$this->filterRentalsBySkiPassDuration(
|
||||
$bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_RENTALS, true),
|
||||
$this->getServicesWithBooked($bookingDto, $participantIndex, Constants::TOKEN_RENTALS, true),
|
||||
$bookingDto,
|
||||
$participantIndex
|
||||
),
|
||||
@@ -386,7 +387,7 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
|
||||
// Returns empty array when no skipass options available
|
||||
$this->fieldOptionProviders['skiPass'] = function (BookingDto $bookingDto, int $participantIndex, array $options = []): array {
|
||||
$choices = $this->filterSkiPassChoices(
|
||||
$bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_SKI_PASS, true),
|
||||
$this->getServicesWithBooked($bookingDto, $participantIndex, Constants::TOKEN_SKI_PASS, true),
|
||||
$bookingDto,
|
||||
$participantIndex
|
||||
);
|
||||
@@ -557,7 +558,7 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
|
||||
// Simple checkbox since there's only ever one parking type
|
||||
// Returns empty array when no parking services exist to prevent field from rendering
|
||||
$this->fieldOptionProviders['parking'] = function (BookingDto $bookingDto, int $participantIndex, array $options = []): array {
|
||||
$parkingServices = $bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_PARKING);
|
||||
$parkingServices = $this->getServicesWithBooked($bookingDto, $participantIndex, Constants::TOKEN_PARKING);
|
||||
if (true === empty($parkingServices)) {
|
||||
return [];
|
||||
}
|
||||
@@ -1255,4 +1256,65 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
|
||||
// Fallback: return all services if we don't have the expected discount/regular pair
|
||||
return [...$otherServices, ...$pkwServices];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves available services from travel data, merged with booked services in edit mode.
|
||||
*
|
||||
* In edit mode, services that were previously booked for the participant are included
|
||||
* even if they're no longer available in travel data. This ensures form checkboxes
|
||||
* appear for booked services, allowing users to keep or deselect them.
|
||||
*
|
||||
* @param BookingDto $bookingDto The booking DTO containing travel and booking data
|
||||
* @param int $participantIndex The participant index to retrieve booked services for
|
||||
* @param mixed $serviceGroup The service group(s) to filter by (e.g., TOKEN_RENTALS)
|
||||
* @param bool $filterByTravelDateRange Whether to filter travel services by date range
|
||||
*
|
||||
* @return Service[] Array of available services keyed by service ID
|
||||
*/
|
||||
private function getServicesWithBooked(
|
||||
BookingDto $bookingDto,
|
||||
int $participantIndex,
|
||||
mixed $serviceGroup,
|
||||
bool $filterByTravelDateRange = false,
|
||||
): array {
|
||||
$availableServices = $bookingDto->travel->getAdditionalServicesBySubTypes($serviceGroup, $filterByTravelDateRange);
|
||||
|
||||
if (BookingDto::MODE_EDIT === $bookingDto->getMode() && null !== $bookingDto->booking) {
|
||||
$availableServices = $this->mergeBookedServices(
|
||||
$availableServices,
|
||||
$bookingDto->booking,
|
||||
$participantIndex,
|
||||
$serviceGroup
|
||||
);
|
||||
}
|
||||
|
||||
return $availableServices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges booked services into the available services array.
|
||||
*
|
||||
* @param Service[] $availableServices The services available from travel data
|
||||
* @param Booking $booking The booking containing previously booked services
|
||||
* @param int $participantIndex The participant index to retrieve booked services for
|
||||
* @param mixed $serviceGroup The service group(s) to filter by
|
||||
*
|
||||
* @return Service[] Merged array of services keyed by service ID
|
||||
*/
|
||||
private function mergeBookedServices(
|
||||
array $availableServices,
|
||||
Booking $booking,
|
||||
int $participantIndex,
|
||||
mixed $serviceGroup,
|
||||
): array {
|
||||
$bookedServices = $booking->getAdditionalServicesForParticipantByGroup($participantIndex, $serviceGroup);
|
||||
|
||||
foreach ($bookedServices as $bookedService) {
|
||||
if (false === isset($availableServices[$bookedService->id])) {
|
||||
$availableServices[$bookedService->id] = $bookedService;
|
||||
}
|
||||
}
|
||||
|
||||
return $availableServices;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ class ParticipantParkingFieldHandler extends AbstractParticipantFieldHandler
|
||||
|
||||
// Store parking service object for pricing calculation
|
||||
if (true === $isParkingSelected) {
|
||||
$participant->parkingService = $this->findParkingService($bookingDto);
|
||||
$participant->parkingService = $this->findParkingService($bookingDto, $participantIndex);
|
||||
} else {
|
||||
$participant->parkingService = null;
|
||||
}
|
||||
@@ -113,12 +113,18 @@ class ParticipantParkingFieldHandler extends AbstractParticipantFieldHandler
|
||||
* Returns null if no parking services are available.
|
||||
*
|
||||
* @param BookingDto $bookingDto The booking DTO containing travel data
|
||||
* @param int $participantIndex The participant index for booked services lookup
|
||||
*
|
||||
* @return Service|null The parking service object, or null if not found
|
||||
*/
|
||||
private function findParkingService(BookingDto $bookingDto): ?Service
|
||||
private function findParkingService(BookingDto $bookingDto, int $participantIndex): ?Service
|
||||
{
|
||||
$parkingServices = $bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_PARKING);
|
||||
// Get available parking services (includes booked parking in edit mode)
|
||||
$parkingServices = $this->getAvailableServicesWithBooked(
|
||||
$bookingDto,
|
||||
$participantIndex,
|
||||
Constants::TOKEN_PARKING
|
||||
);
|
||||
|
||||
if (empty($parkingServices)) {
|
||||
return null;
|
||||
|
||||
@@ -107,7 +107,7 @@ class ParticipantRentalInsuranceFieldHandler extends AbstractParticipantFieldHan
|
||||
|
||||
// Store service object based on checkbox state for pricing calculations
|
||||
if (true === $isRentalInsuranceSelected) {
|
||||
$participant->rentalInsurance = $this->findRentalInsuranceService($bookingDto);
|
||||
$participant->rentalInsurance = $this->findRentalInsuranceService($bookingDto, $participantIndex);
|
||||
} else {
|
||||
$participant->rentalInsurance = null;
|
||||
}
|
||||
@@ -120,12 +120,19 @@ class ParticipantRentalInsuranceFieldHandler extends AbstractParticipantFieldHan
|
||||
* Returns null if no rental insurance services are available.
|
||||
*
|
||||
* @param BookingDto $bookingDto The booking DTO containing travel data
|
||||
* @param int $participantIndex The participant index for booked services lookup
|
||||
*
|
||||
* @return Service|null The rental insurance service object, or null if not found
|
||||
*/
|
||||
private function findRentalInsuranceService(BookingDto $bookingDto): ?Service
|
||||
private function findRentalInsuranceService(BookingDto $bookingDto, int $participantIndex): ?Service
|
||||
{
|
||||
$rentalInsuranceServices = $bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_RENTAL_INSURANCE, true);
|
||||
// Get available rental insurance services (includes booked insurance in edit mode)
|
||||
$rentalInsuranceServices = $this->getAvailableServicesWithBooked(
|
||||
$bookingDto,
|
||||
$participantIndex,
|
||||
Constants::TOKEN_RENTAL_INSURANCE,
|
||||
true
|
||||
);
|
||||
|
||||
if (empty($rentalInsuranceServices)) {
|
||||
return null;
|
||||
|
||||
@@ -83,7 +83,14 @@ class ParticipantRentalsFieldHandler extends AbstractParticipantFieldHandler
|
||||
}
|
||||
|
||||
$selectedRentals = $this->getFieldValue($submittedData, $this->getFieldName()) ?? [];
|
||||
$availableRentals = $bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_RENTALS, true);
|
||||
|
||||
// Get available rentals from travel data (includes booked rentals in edit mode)
|
||||
$availableRentals = $this->getAvailableServicesWithBooked(
|
||||
$bookingDto,
|
||||
$participantIndex,
|
||||
Constants::TOKEN_RENTALS,
|
||||
true
|
||||
);
|
||||
|
||||
// Filter rentals by skipass duration to ensure only matching rentals are available
|
||||
$durationFilteredRentals = $this->filterRentalsBySkiPassDuration($availableRentals, $participant);
|
||||
|
||||
@@ -94,8 +94,13 @@ class ParticipantSkiPassFieldHandler extends AbstractParticipantFieldHandler
|
||||
// Extract current skipass selection from submitted data
|
||||
$selectedSkiPass = $this->getFieldValue($submittedData, $this->getFieldName());
|
||||
|
||||
// Get all skipasses from travel data (with date filtering)
|
||||
$availableSkipasses = $bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_SKI_PASS, true);
|
||||
// Get all skipasses from travel data (includes booked skipasses in edit mode)
|
||||
$availableSkipasses = $this->getAvailableServicesWithBooked(
|
||||
$bookingDto,
|
||||
$participantIndex,
|
||||
Constants::TOKEN_SKI_PASS,
|
||||
true
|
||||
);
|
||||
|
||||
// For single selection, validate the selected skipass and convert ID to Service object
|
||||
$validSelection = null;
|
||||
|
||||
@@ -84,7 +84,13 @@ class ParticipantVegFieldHandler extends AbstractParticipantFieldHandler
|
||||
|
||||
$selectedVeg = $this->getFieldValue($submittedData, $this->getFieldName());
|
||||
|
||||
$availableVegOptions = $bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_VEG, true);
|
||||
// Get available veg options from travel data (includes booked options in edit mode)
|
||||
$availableVegOptions = $this->getAvailableServicesWithBooked(
|
||||
$bookingDto,
|
||||
$participantIndex,
|
||||
Constants::TOKEN_VEG,
|
||||
true
|
||||
);
|
||||
|
||||
$validSelection = null;
|
||||
if (null !== $selectedVeg) {
|
||||
|
||||
@@ -178,7 +178,7 @@ class BookingExportService
|
||||
],
|
||||
];
|
||||
$lastColumn = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex(count(self::COLUMN_HEADERS));
|
||||
$sheet->getStyle('A1:' . $lastColumn . '1')->applyFromArray($headerStyle);
|
||||
$sheet->getStyle('A1:'.$lastColumn.'1')->applyFromArray($headerStyle);
|
||||
|
||||
// Write participant data
|
||||
$formData = $draft->getFormData();
|
||||
@@ -206,7 +206,7 @@ class BookingExportService
|
||||
\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $sheet,
|
||||
int $row,
|
||||
array $participant,
|
||||
array $lookups
|
||||
array $lookups,
|
||||
): void {
|
||||
$personal = $participant['personalData'] ?? [];
|
||||
$address = $participant['address'] ?? [];
|
||||
|
||||
Reference in New Issue
Block a user