chore: fix phpstan errors
This commit is contained in:
@@ -7,6 +7,7 @@ use App\BusProNet\Exception\ApiClientException;
|
|||||||
use App\BusProNet\Exception\ImmediateConnectionCloseException;
|
use App\BusProNet\Exception\ImmediateConnectionCloseException;
|
||||||
use App\BusProNet\Exception\ResponseParserException;
|
use App\BusProNet\Exception\ResponseParserException;
|
||||||
use App\BusProNet\Exception\TimeoutException;
|
use App\BusProNet\Exception\TimeoutException;
|
||||||
|
use App\BusProNet\Model\Agency;
|
||||||
use App\BusProNet\Model\BaseData;
|
use App\BusProNet\Model\BaseData;
|
||||||
use App\BusProNet\Model\Booking;
|
use App\BusProNet\Model\Booking;
|
||||||
use App\BusProNet\Model\BookingResponse;
|
use App\BusProNet\Model\BookingResponse;
|
||||||
@@ -49,11 +50,13 @@ class ApiClient
|
|||||||
public const TYPE_PURCHASE_VOUCHER = 'GUTSCHEINPRUEFUNGEINLOESUNG';
|
public const TYPE_PURCHASE_VOUCHER = 'GUTSCHEINPRUEFUNGEINLOESUNG';
|
||||||
public const TYPE_PROMO_VOUCHER = 'AKTIONSGUTSCHEIN';
|
public const TYPE_PROMO_VOUCHER = 'AKTIONSGUTSCHEIN';
|
||||||
|
|
||||||
|
/** @var array<string, mixed> */
|
||||||
private array $config;
|
private array $config;
|
||||||
private float $operationStartTime;
|
private float $operationStartTime;
|
||||||
private int $selectedPort;
|
private int $selectedPort;
|
||||||
private int $requestCounter = 0;
|
private int $requestCounter = 0;
|
||||||
|
|
||||||
|
/** @param array<string, mixed> $options */
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly SerializerInterface $serializer,
|
private readonly SerializerInterface $serializer,
|
||||||
private readonly ApiResponseParser $responseParser,
|
private readonly ApiResponseParser $responseParser,
|
||||||
@@ -613,6 +616,10 @@ class ApiClient
|
|||||||
/**
|
/**
|
||||||
* @throws ApiClientException
|
* @throws ApiClientException
|
||||||
*/
|
*/
|
||||||
|
/**
|
||||||
|
* @param array<string, mixed> $data
|
||||||
|
* @param array<string, mixed> $additionalArgs
|
||||||
|
*/
|
||||||
private function sendRequest(string $type, array $data, array $additionalArgs = [], bool $debug = false): mixed
|
private function sendRequest(string $type, array $data, array $additionalArgs = [], bool $debug = false): mixed
|
||||||
{
|
{
|
||||||
return $this->executeWithRetry(fn () => $this->doSendRequest($type, $data, $additionalArgs, $debug), $type);
|
return $this->executeWithRetry(fn () => $this->doSendRequest($type, $data, $additionalArgs, $debug), $type);
|
||||||
@@ -621,6 +628,7 @@ class ApiClient
|
|||||||
/**
|
/**
|
||||||
* @throws ApiClientException
|
* @throws ApiClientException
|
||||||
*/
|
*/
|
||||||
|
/** @param array<string, mixed> $data */
|
||||||
private function sendRequestRaw(array $data): string
|
private function sendRequestRaw(array $data): string
|
||||||
{
|
{
|
||||||
return $this->executeWithRetry(fn () => $this->doSendRequestRaw($data));
|
return $this->executeWithRetry(fn () => $this->doSendRequestRaw($data));
|
||||||
@@ -676,6 +684,10 @@ class ApiClient
|
|||||||
* @throws ApiClientException
|
* @throws ApiClientException
|
||||||
* @throws ImmediateConnectionCloseException
|
* @throws ImmediateConnectionCloseException
|
||||||
*/
|
*/
|
||||||
|
/**
|
||||||
|
* @param array<string, mixed> $data
|
||||||
|
* @param array<string, mixed> $additionalArgs
|
||||||
|
*/
|
||||||
private function doSendRequest(string $type, array $data, array $additionalArgs = [], bool $debug = false): mixed
|
private function doSendRequest(string $type, array $data, array $additionalArgs = [], bool $debug = false): mixed
|
||||||
{
|
{
|
||||||
$requestId = $this->getRequestId();
|
$requestId = $this->getRequestId();
|
||||||
@@ -733,6 +745,8 @@ class ApiClient
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param array<string, mixed> $data
|
||||||
|
*
|
||||||
* @throws ApiClientException
|
* @throws ApiClientException
|
||||||
* @throws ImmediateConnectionCloseException
|
* @throws ImmediateConnectionCloseException
|
||||||
*/
|
*/
|
||||||
@@ -794,6 +808,8 @@ class ApiClient
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @return resource
|
||||||
|
*
|
||||||
* @throws ApiClientException
|
* @throws ApiClientException
|
||||||
* @throws TimeoutException
|
* @throws TimeoutException
|
||||||
*/
|
*/
|
||||||
@@ -857,6 +873,8 @@ class ApiClient
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param resource $socket
|
||||||
|
*
|
||||||
* @throws TimeoutException
|
* @throws TimeoutException
|
||||||
*/
|
*/
|
||||||
private function send($socket, string $data): void
|
private function send($socket, string $data): void
|
||||||
@@ -875,6 +893,8 @@ class ApiClient
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param resource $socket
|
||||||
|
*
|
||||||
* @throws TimeoutException
|
* @throws TimeoutException
|
||||||
* @throws ImmediateConnectionCloseException
|
* @throws ImmediateConnectionCloseException
|
||||||
*/
|
*/
|
||||||
@@ -937,11 +957,17 @@ class ApiClient
|
|||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param resource $socket */
|
||||||
private function disconnect($socket): void
|
private function disconnect($socket): void
|
||||||
{
|
{
|
||||||
@fclose($socket);
|
@fclose($socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<string, mixed> $options
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
private function resolveOptions(array $options): array
|
private function resolveOptions(array $options): array
|
||||||
{
|
{
|
||||||
$optionsResolver = new OptionsResolver();
|
$optionsResolver = new OptionsResolver();
|
||||||
|
|||||||
@@ -73,14 +73,12 @@ class BookingDataProcessor
|
|||||||
if (0 === $index) {
|
if (0 === $index) {
|
||||||
// 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
|
// This allows applicant and first participant to be different people with different addresses
|
||||||
if (null !== $booking->applicant->address) {
|
$isEmpty = null === $participantData->address
|
||||||
$isEmpty = null === $participantData->address
|
|| null === $participantData->address->street
|
||||||
|| null === $participantData->address->street
|
|| '' === trim($participantData->address->street);
|
||||||
|| '' === trim($participantData->address->street);
|
|
||||||
|
|
||||||
if ($isEmpty) {
|
if ($isEmpty) {
|
||||||
$participantData->address = clone $booking->applicant->address;
|
$participantData->address = clone $booking->applicant->address;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy body dimensions from applicant if not present in participant
|
// Copy body dimensions from applicant if not present in participant
|
||||||
@@ -284,7 +282,7 @@ class BookingDataProcessor
|
|||||||
*
|
*
|
||||||
* @param BookingDto|null $formData The booking edit form data containing updated participant and service selections
|
* @param BookingDto|null $formData The booking edit form data containing updated participant and service selections
|
||||||
*
|
*
|
||||||
* @return array The structured payload array ready for BusProNet API submission
|
* @return array<string, mixed> The structured payload array ready for BusProNet API submission
|
||||||
*/
|
*/
|
||||||
public function createUpdateRequestPayload(?BookingDto $formData): array
|
public function createUpdateRequestPayload(?BookingDto $formData): array
|
||||||
{
|
{
|
||||||
@@ -345,7 +343,7 @@ class BookingDataProcessor
|
|||||||
* @param BookingDto $bookingDto The booking creation form data
|
* @param BookingDto $bookingDto The booking creation form data
|
||||||
* @param string $bookingType Either 'Anfrage' (inquiry) or 'Buchung' (final booking)
|
* @param string $bookingType Either 'Anfrage' (inquiry) or 'Buchung' (final booking)
|
||||||
*
|
*
|
||||||
* @return array The structured payload array for BusProNet API submission
|
* @return array<string, mixed> The structured payload array for BusProNet API submission
|
||||||
*/
|
*/
|
||||||
public function createBookingRequestPayload(BookingDto $bookingDto, string $bookingType): array
|
public function createBookingRequestPayload(BookingDto $bookingDto, string $bookingType): array
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ namespace App\BusProNet\DataProcessor;
|
|||||||
use App\BusProNet\Constants;
|
use App\BusProNet\Constants;
|
||||||
use App\BusProNet\Model\Booking;
|
use App\BusProNet\Model\Booking;
|
||||||
use App\Form\Model\BookingDto;
|
use App\Form\Model\BookingDto;
|
||||||
|
use App\Form\Model\ParticipantDto;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds API payload structures for BusProNet booking requests.
|
* Builds API payload structures for BusProNet booking requests.
|
||||||
@@ -30,7 +31,7 @@ class BookingPayloadBuilder
|
|||||||
*
|
*
|
||||||
* @param Booking $bookingData The booking data object
|
* @param Booking $bookingData The booking data object
|
||||||
*
|
*
|
||||||
* @return array The base payload structure
|
* @return array<string, mixed> The base payload structure
|
||||||
*/
|
*/
|
||||||
public function buildBasePayload(Booking $bookingData): array
|
public function buildBasePayload(Booking $bookingData): array
|
||||||
{
|
{
|
||||||
@@ -66,8 +67,8 @@ class BookingPayloadBuilder
|
|||||||
*
|
*
|
||||||
* Bank account information is required for direct debit payments.
|
* Bank account information is required for direct debit payments.
|
||||||
*
|
*
|
||||||
* @param array $payload The payload array to modify
|
* @param array<string, mixed> $payload The payload array to modify
|
||||||
* @param Booking $bookingData The booking data object
|
* @param Booking $bookingData The booking data object
|
||||||
*/
|
*/
|
||||||
public function addBankAccountToPayload(array &$payload, Booking $bookingData): void
|
public function addBankAccountToPayload(array &$payload, Booking $bookingData): void
|
||||||
{
|
{
|
||||||
@@ -86,9 +87,9 @@ class BookingPayloadBuilder
|
|||||||
*
|
*
|
||||||
* Includes status, personal data, and wishes (room remarks, license plate) for each participant.
|
* Includes status, personal data, and wishes (room remarks, license plate) for each participant.
|
||||||
*
|
*
|
||||||
* @param array $payload The payload array to modify
|
* @param array<string, mixed> $payload The payload array to modify
|
||||||
* @param Booking $bookingData The booking data object
|
* @param Booking $bookingData The booking data object
|
||||||
* @param array $participantDtos The participant DTOs from the form (for wishes data)
|
* @param array<int, ParticipantDto> $participantDtos The participant DTOs from the form (for wishes data)
|
||||||
*/
|
*/
|
||||||
public function buildParticipantPayload(array &$payload, Booking $bookingData, array $participantDtos): void
|
public function buildParticipantPayload(array &$payload, Booking $bookingData, array $participantDtos): void
|
||||||
{
|
{
|
||||||
@@ -141,8 +142,8 @@ class BookingPayloadBuilder
|
|||||||
* Includes additional services, transportation services, and accommodation details
|
* Includes additional services, transportation services, and accommodation details
|
||||||
* with participant mappings and quantities.
|
* with participant mappings and quantities.
|
||||||
*
|
*
|
||||||
* @param array $payload The payload array to modify
|
* @param array<string, mixed> $payload The payload array to modify
|
||||||
* @param Booking $bookingData The booking data object
|
* @param Booking $bookingData The booking data object
|
||||||
*/
|
*/
|
||||||
public function buildServicesPayload(array &$payload, Booking $bookingData): void
|
public function buildServicesPayload(array &$payload, Booking $bookingData): void
|
||||||
{
|
{
|
||||||
@@ -198,8 +199,8 @@ class BookingPayloadBuilder
|
|||||||
*
|
*
|
||||||
* Only included in payload if there are actual pickup assignments for bus transportation.
|
* Only included in payload if there are actual pickup assignments for bus transportation.
|
||||||
*
|
*
|
||||||
* @param array $payload The payload array to modify
|
* @param array<string, mixed> $payload The payload array to modify
|
||||||
* @param Booking $bookingData The booking data object
|
* @param Booking $bookingData The booking data object
|
||||||
*/
|
*/
|
||||||
public function buildPickupPayload(array &$payload, Booking $bookingData): void
|
public function buildPickupPayload(array &$payload, Booking $bookingData): void
|
||||||
{
|
{
|
||||||
@@ -223,8 +224,8 @@ class BookingPayloadBuilder
|
|||||||
*
|
*
|
||||||
* Only included in payload if there are actual drop-off assignments for bus transportation.
|
* Only included in payload if there are actual drop-off assignments for bus transportation.
|
||||||
*
|
*
|
||||||
* @param array $payload The payload array to modify
|
* @param array<string, mixed> $payload The payload array to modify
|
||||||
* @param Booking $bookingData The booking data object
|
* @param Booking $bookingData The booking data object
|
||||||
*/
|
*/
|
||||||
public function buildDropOffPayload(array &$payload, Booking $bookingData): void
|
public function buildDropOffPayload(array &$payload, Booking $bookingData): void
|
||||||
{
|
{
|
||||||
@@ -249,7 +250,7 @@ class BookingPayloadBuilder
|
|||||||
* @param BookingDto $bookingDto The booking creation form data
|
* @param BookingDto $bookingDto The booking creation form data
|
||||||
* @param string $bookingType Either 'Anfrage' (inquiry) or 'Buchung' (final booking)
|
* @param string $bookingType Either 'Anfrage' (inquiry) or 'Buchung' (final booking)
|
||||||
*
|
*
|
||||||
* @return array The structured payload array for BusProNet API submission
|
* @return array<string, mixed> The structured payload array for BusProNet API submission
|
||||||
*/
|
*/
|
||||||
public function buildCreatePayload(BookingDto $bookingDto, string $bookingType): array
|
public function buildCreatePayload(BookingDto $bookingDto, string $bookingType): array
|
||||||
{
|
{
|
||||||
@@ -439,11 +440,11 @@ class BookingPayloadBuilder
|
|||||||
* Generic helper method that converts service ID => participant IDs mappings
|
* Generic helper method that converts service ID => participant IDs mappings
|
||||||
* into XML payload structure.
|
* into XML payload structure.
|
||||||
*
|
*
|
||||||
* @param array $payload The payload array to modify
|
* @param array<string, mixed> $payload The payload array to modify
|
||||||
* @param string $sectionKey The section key (e.g., 'beförderungen', 'versicherungen')
|
* @param string $sectionKey The section key (e.g., 'beförderungen', 'versicherungen')
|
||||||
* @param string $itemKey The item key (e.g., 'beförderung', 'versicherung')
|
* @param string $itemKey The item key (e.g., 'beförderung', 'versicherung')
|
||||||
* @param string $idAttributeName The ID attribute name (e.g., '@idleistung', '@idversicherung')
|
* @param string $idAttributeName The ID attribute name (e.g., '@idleistung', '@idversicherung')
|
||||||
* @param array $serviceMap Map of service ID to participant IDs
|
* @param array<int|string, int[]> $serviceMap Map of service ID to participant IDs
|
||||||
*/
|
*/
|
||||||
public function addServicesFromMap(
|
public function addServicesFromMap(
|
||||||
array &$payload,
|
array &$payload,
|
||||||
@@ -475,9 +476,9 @@ class BookingPayloadBuilder
|
|||||||
* - abreise (departure date)
|
* - abreise (departure date)
|
||||||
* - anzahl (number of rooms of this type booked)
|
* - anzahl (number of rooms of this type booked)
|
||||||
*
|
*
|
||||||
* @param array $payload The payload array to modify
|
* @param array<string, mixed> $payload The payload array to modify
|
||||||
* @param array $roomMap Map of room ID to participant IDs
|
* @param array<int|string, int[]> $roomMap Map of room ID to participant IDs
|
||||||
* @param BookingDto $bookingDto The booking data for accessing room details and quantities
|
* @param BookingDto $bookingDto The booking data for accessing room details and quantities
|
||||||
*/
|
*/
|
||||||
public function addRoomMappingsToPayload(array &$payload, array $roomMap, BookingDto $bookingDto): void
|
public function addRoomMappingsToPayload(array &$payload, array $roomMap, BookingDto $bookingDto): void
|
||||||
{
|
{
|
||||||
@@ -520,8 +521,8 @@ class BookingPayloadBuilder
|
|||||||
/**
|
/**
|
||||||
* Adds purchase vouchers to the payload.
|
* Adds purchase vouchers to the payload.
|
||||||
*
|
*
|
||||||
* @param array $payload The payload array to modify
|
* @param array<string, mixed> $payload The payload array to modify
|
||||||
* @param BookingDto $bookingDto The booking data
|
* @param BookingDto $bookingDto The booking data
|
||||||
*/
|
*/
|
||||||
public function addPurchaseVouchersToPayload(array &$payload, BookingDto $bookingDto): void
|
public function addPurchaseVouchersToPayload(array &$payload, BookingDto $bookingDto): void
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ namespace App\BusProNet\DataProcessor;
|
|||||||
|
|
||||||
use App\BusProNet\Model\Address;
|
use App\BusProNet\Model\Address;
|
||||||
use App\BusProNet\Model\Booking;
|
use App\BusProNet\Model\Booking;
|
||||||
use App\BusProNet\Model\Communication;
|
|
||||||
use App\BusProNet\Model\PersonalData;
|
use App\BusProNet\Model\PersonalData;
|
||||||
use App\Form\Model\ParticipantDto;
|
use App\Form\Model\ParticipantDto;
|
||||||
|
|
||||||
@@ -86,9 +85,6 @@ class PersonalDataSynchronizer
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($participant->email || $participant->mobile) {
|
if ($participant->email || $participant->mobile) {
|
||||||
if (null === $bookingData->participants[$participant->index]->communication) {
|
|
||||||
$bookingData->participants[$participant->index]->communication = new Communication();
|
|
||||||
}
|
|
||||||
$bookingData->participants[$participant->index]->communication->email = $participant->email;
|
$bookingData->participants[$participant->index]->communication->email = $participant->email;
|
||||||
$bookingData->participants[$participant->index]->communication->mobile = $participant->mobile;
|
$bookingData->participants[$participant->index]->communication->mobile = $participant->mobile;
|
||||||
}
|
}
|
||||||
@@ -127,10 +123,6 @@ class PersonalDataSynchronizer
|
|||||||
$applicant->dateOfBirth = new \DateTimeImmutable('-20 years');
|
$applicant->dateOfBirth = new \DateTimeImmutable('-20 years');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null === $applicant->communication) {
|
|
||||||
$applicant->communication = new Communication();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (null === $applicant->communication->mobile || '' === $applicant->communication->mobile) {
|
if (null === $applicant->communication->mobile || '' === $applicant->communication->mobile) {
|
||||||
$applicant->communication->mobile = '12345';
|
$applicant->communication->mobile = '12345';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class ServiceMappingCollector
|
|||||||
*
|
*
|
||||||
* Groups participants by their assigned room ID.
|
* Groups participants by their assigned room ID.
|
||||||
*
|
*
|
||||||
* @return array<string, array<int>> Map of room ID to participant IDs
|
* @return array<int, list<int>> Map of room ID to participant IDs
|
||||||
*/
|
*/
|
||||||
public function collectRoomMappings(BookingDto $bookingDto): array
|
public function collectRoomMappings(BookingDto $bookingDto): array
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ class CountryDataProvider
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return array<string, Country> */
|
||||||
public function getAll(): array
|
public function getAll(): array
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
|||||||
use Symfony\Component\OptionsResolver\Options;
|
use Symfony\Component\OptionsResolver\Options;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
/** @extends AbstractType<string> */
|
||||||
class CountryType extends AbstractType
|
class CountryType extends AbstractType
|
||||||
{
|
{
|
||||||
public function __construct(private readonly CountryDataProvider $countries)
|
public function __construct(private readonly CountryDataProvider $countries)
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ namespace App\BusProNet\Model;
|
|||||||
*/
|
*/
|
||||||
class AgeConstraintResult
|
class AgeConstraintResult
|
||||||
{
|
{
|
||||||
|
/** @param array<string, mixed> $metadata */
|
||||||
public function __construct(
|
public function __construct(
|
||||||
public readonly string $type,
|
public readonly string $type,
|
||||||
public readonly ?int $ageFrom = null,
|
public readonly ?int $ageFrom = null,
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ namespace App\BusProNet\Model;
|
|||||||
*/
|
*/
|
||||||
class BaseData
|
class BaseData
|
||||||
{
|
{
|
||||||
|
/** @param array<array-key, mixed> $items */
|
||||||
public function __construct(private readonly array $items)
|
public function __construct(private readonly array $items)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -19,7 +20,7 @@ class BaseData
|
|||||||
/**
|
/**
|
||||||
* Retrieves all items in the base data collection.
|
* Retrieves all items in the base data collection.
|
||||||
*
|
*
|
||||||
* @return array The complete items array
|
* @return array<array-key, mixed> The complete items array
|
||||||
*/
|
*/
|
||||||
public function getItems(): array
|
public function getItems(): array
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -220,7 +220,7 @@ class Booking
|
|||||||
public function getInsuranceForParticipant(int $participantIndex): ?Insurance
|
public function getInsuranceForParticipant(int $participantIndex): ?Insurance
|
||||||
{
|
{
|
||||||
foreach ($this->insurances as $insurance) {
|
foreach ($this->insurances as $insurance) {
|
||||||
if (in_array($participantIndex, $insurance->mapping ?? [], true)) {
|
if (in_array($participantIndex, $insurance->mapping, true)) {
|
||||||
return $insurance;
|
return $insurance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class CrmSelectionGroup
|
|||||||
* Maps BusPro IDs of CRM selection groups representing
|
* Maps BusPro IDs of CRM selection groups representing
|
||||||
* included services.
|
* included services.
|
||||||
*
|
*
|
||||||
* @var array<string, string>
|
* @var array<int, string>
|
||||||
*/
|
*/
|
||||||
public static array $includedServicesMapping = [
|
public static array $includedServicesMapping = [
|
||||||
7 => 'Skipass',
|
7 => 'Skipass',
|
||||||
|
|||||||
@@ -1,115 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace App\BusProNet\Model;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents error codes and messages for the BusProNet API.
|
|
||||||
*
|
|
||||||
* This class provides a static mapping of error codes to their corresponding
|
|
||||||
* German error messages for consistent error handling across the application.
|
|
||||||
* Error codes range from 100-999 and cover various API scenarios.
|
|
||||||
*/
|
|
||||||
class Error
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var array<int, string>
|
|
||||||
*/
|
|
||||||
private static array $errors = [
|
|
||||||
100 => 'Anfrageknoten fehlt',
|
|
||||||
101 => 'Satzknoten fehlt in Anfrageknoten',
|
|
||||||
102 => 'Ungültiger Satztyp [#1#]',
|
|
||||||
103 => 'User fehlt',
|
|
||||||
104 => 'User fehlerhaft',
|
|
||||||
105 => 'Key fehlt',
|
|
||||||
106 => 'Key fehlerhaft',
|
|
||||||
200 => 'Keine Einträge vorhanden',
|
|
||||||
201 => 'Keine Partner zur Auswahl gefunden',
|
|
||||||
202 => 'Keinen Partner mit der ID [#1#] gefunden',
|
|
||||||
203 => 'Ungültiger Termin',
|
|
||||||
300 => 'IDReise fehlt',
|
|
||||||
301 => 'Reise nicht gefunden',
|
|
||||||
302 => 'IDLeistung (Hin & Rück) fehlt',
|
|
||||||
303 => 'IDLeistung passt nicht zu IDReise',
|
|
||||||
304 => 'Es konnte nicht für alle Teilnehmer ein Sitzplatz ermittelt werden',
|
|
||||||
305 => 'Anzahl Personen fehlt',
|
|
||||||
306 => 'Leistungen mit ID #1# nicht gefunden',
|
|
||||||
307 => 'Leistungen mit ID #1# passen nicht zur Reise mit ID #2#',
|
|
||||||
308 => 'Keine Zahlungsarten gefunden',
|
|
||||||
400 => 'IDPartner fehlt',
|
|
||||||
401 => 'Partner nicht gefunden',
|
|
||||||
402 => 'Bis-Termin fehlt',
|
|
||||||
403 => 'Keine Unterbringungsleistungen gefunden',
|
|
||||||
500 => 'Art fehlt',
|
|
||||||
501 => 'Reise- und Buchungszeitraum fehlen',
|
|
||||||
502 => 'Keine Kunden gefunden',
|
|
||||||
600 => 'Keine Gutscheine gefunden',
|
|
||||||
601 => 'Gutschein-IDs fehlen',
|
|
||||||
602 => 'Gutscheine mit ID #1# nicht gefunden',
|
|
||||||
610 => 'Buchungsart fehlt',
|
|
||||||
611 => 'Buchungsart falsch',
|
|
||||||
612 => 'Gutscheinart fehlt',
|
|
||||||
613 => 'Gutscheinart falsch',
|
|
||||||
614 => 'Gutscheinstamm-ID fehlt',
|
|
||||||
615 => 'Gutschein (Stamm) mit ID #1# nicht gefunden',
|
|
||||||
616 => 'Kapazität beim Gutschein #1# nicht ausreichend',
|
|
||||||
617 => 'Rechnungsempfänger fehlt',
|
|
||||||
618 => 'Zahlungsart fehlt',
|
|
||||||
619 => 'Agentur-ID fehlt',
|
|
||||||
620 => 'Agentur mit ID #1# nicht gefunden',
|
|
||||||
650 => '#1#',
|
|
||||||
700 => 'Keine Agenturen gefunden',
|
|
||||||
701 => 'Agentur mit ID #1# nicht gefunden',
|
|
||||||
800 => 'Produkt-ID fehlt',
|
|
||||||
801 => 'Produkt mit ID #1# nicht gefunden',
|
|
||||||
805 => 'Es wurden keine Produkte gefunden',
|
|
||||||
810 => 'Stammdaten (#1#) nicht gefunden',
|
|
||||||
900 => 'Buchungsart fehlt',
|
|
||||||
901 => 'Buchungsart falsch',
|
|
||||||
902 => 'Status fehlt',
|
|
||||||
903 => 'Status falsch',
|
|
||||||
904 => 'Agentur-ID fehlt',
|
|
||||||
905 => 'Agentur mit ID #1# nicht gefunden',
|
|
||||||
906 => 'Reise-ID fehlt',
|
|
||||||
907 => 'Reise mit ID #1# nicht gefunden',
|
|
||||||
908 => 'Reise mit ID #1# ist storniert',
|
|
||||||
909 => 'Beförderungen fehlen',
|
|
||||||
910 => 'Leistung mit ID #1# gehört nicht zur Reise',
|
|
||||||
911 => 'Leistung mit ID #1# gehört nicht zum Produkt',
|
|
||||||
912 => 'Beförderungsleistung für die #1# fehlt',
|
|
||||||
913 => 'Unterbringungen fehlen',
|
|
||||||
914 => 'Partner-ID fehlt',
|
|
||||||
915 => 'Partner mit ID #1# nicht gefunden',
|
|
||||||
916 => 'Ferienziel-Unterbringungen fehlen',
|
|
||||||
917 => 'Ferienziel: Zimmer-IDZ fehlt',
|
|
||||||
918 => 'Ferienziel: Kategorie fehlt',
|
|
||||||
919 => 'Ferienziel: Verpflegungs-ID fehlt',
|
|
||||||
920 => 'Ferienziel: Anreise fehlt',
|
|
||||||
921 => 'Ferienziel: Anreise passt nicht zur Beförderungsleistung (Hinfahrt)',
|
|
||||||
922 => 'Ferienziel: Abreise fehlt',
|
|
||||||
923 => 'Ferienziel: Abreise passt nicht zur Beförderungsleistung (Rückfahrt)',
|
|
||||||
924 => 'Ferienziel: Keine Preise zu den Daten gefunden',
|
|
||||||
925 => 'Ferienziel: Preis zu den Daten nicht gefunden',
|
|
||||||
930 => 'Zustiege fehlen',
|
|
||||||
931 => 'Zustieg mit ID #1# nicht gefunden',
|
|
||||||
932 => 'Zustieg mit ID #1# bei Leistung #2# nicht freigegeben',
|
|
||||||
933 => 'Sitzplan mit ID #1# bei Leistung #2# nicht freigegeben',
|
|
||||||
935 => 'Versicherung mit ID #1# nicht gefunden',
|
|
||||||
940 => 'Zahlungsart fehlt',
|
|
||||||
941 => 'Zahlungsart-ID fehlt',
|
|
||||||
942 => 'Zahlungsart mit ID #1# nicht gültig',
|
|
||||||
950 => 'Anmelder fehlt',
|
|
||||||
951 => 'Teilnehmerliste fehlt',
|
|
||||||
952 => 'Teilnehmer-ID fehlt',
|
|
||||||
960 => 'Preisfehler: Struct #1# / Obj #2#',
|
|
||||||
961 => 'Buchung konnte nicht gespeichert werden',
|
|
||||||
980 => 'Reise ist fürs Internet gesperrt',
|
|
||||||
981 => 'Reise ist nicht mehr buchbar (#1#)',
|
|
||||||
982 => 'Optionsbuchungen nicht zugelassen',
|
|
||||||
983 => 'Anfragebuchung nicht zugelassen',
|
|
||||||
984 => 'Leistung mit ID #1# nicht fürs Internet buchbar',
|
|
||||||
985 => 'Zustieg mit ID #1# nicht fürs Internet buchbar',
|
|
||||||
999 => 'Systemfehler: #1#',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
@@ -56,7 +56,9 @@ class PersonalData
|
|||||||
#[Assert\Valid(groups: ['personal_data'])]
|
#[Assert\Valid(groups: ['personal_data'])]
|
||||||
public Communication $communication;
|
public Communication $communication;
|
||||||
|
|
||||||
|
/** @var list<string> */
|
||||||
public array $roles = [];
|
public array $roles = [];
|
||||||
|
/** @var list<string> */
|
||||||
public array $hotelCodes = [];
|
public array $hotelCodes = [];
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ class Pickup
|
|||||||
#[Groups(['api:single', 'snapshot'])]
|
#[Groups(['api:single', 'snapshot'])]
|
||||||
public ?float $priceInbound = null;
|
public ?float $priceInbound = null;
|
||||||
|
|
||||||
|
/** @var list<int> */
|
||||||
#[Groups(['api:booking'])]
|
#[Groups(['api:booking'])]
|
||||||
public array $mapping = [];
|
public array $mapping = [];
|
||||||
|
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ class Room
|
|||||||
#[Groups(['booking'])]
|
#[Groups(['booking'])]
|
||||||
public ?string $board = null;
|
public ?string $board = null;
|
||||||
|
|
||||||
|
/** @var list<int> */
|
||||||
#[Groups(['booking'])]
|
#[Groups(['booking'])]
|
||||||
public array $mapping = [];
|
public array $mapping = [];
|
||||||
|
|
||||||
@@ -73,6 +74,7 @@ class Room
|
|||||||
#[Groups(['booking'])]
|
#[Groups(['booking'])]
|
||||||
public ?float $totalPrice = null;
|
public ?float $totalPrice = null;
|
||||||
|
|
||||||
|
/** @var array<int, float|null> */
|
||||||
#[Groups(['booking'])]
|
#[Groups(['booking'])]
|
||||||
public array $individualPrice = [];
|
public array $individualPrice = [];
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ class Service
|
|||||||
#[Groups(['booking'])]
|
#[Groups(['booking'])]
|
||||||
public ?int $totalCount = null;
|
public ?int $totalCount = null;
|
||||||
|
|
||||||
|
/** @var list<int> */
|
||||||
#[Groups(['api:single', 'snapshot'])]
|
#[Groups(['api:single', 'snapshot'])]
|
||||||
public array $mapping = [];
|
public array $mapping = [];
|
||||||
|
|
||||||
@@ -64,6 +65,7 @@ class Service
|
|||||||
#[Groups(['api:single', 'snapshot'])]
|
#[Groups(['api:single', 'snapshot'])]
|
||||||
public ?float $totalPrice = null;
|
public ?float $totalPrice = null;
|
||||||
|
|
||||||
|
/** @var array<int, float|null> */
|
||||||
#[Groups(['api:single', 'snapshot'])]
|
#[Groups(['api:single', 'snapshot'])]
|
||||||
public array $individualPrice = [];
|
public array $individualPrice = [];
|
||||||
|
|
||||||
@@ -91,6 +93,7 @@ class Service
|
|||||||
#[Groups(['api:single', 'api:list', 'snapshot'])]
|
#[Groups(['api:single', 'api:list', 'snapshot'])]
|
||||||
public ?string $ageConstraintType = null;
|
public ?string $ageConstraintType = null;
|
||||||
|
|
||||||
|
/** @var array<string, mixed>|null */
|
||||||
#[Groups(['api:single'])]
|
#[Groups(['api:single'])]
|
||||||
public ?array $ageConstraintMetadata = null;
|
public ?array $ageConstraintMetadata = null;
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,9 @@ namespace App\BusProNet\Model;
|
|||||||
class Surcharge
|
class Surcharge
|
||||||
{
|
{
|
||||||
public ?string $label = null;
|
public ?string $label = null;
|
||||||
|
/** @var list<int> */
|
||||||
public array $mapping = [];
|
public array $mapping = [];
|
||||||
public ?float $totalPrice = null;
|
public ?float $totalPrice = null;
|
||||||
|
/** @var array<int, float|null> */
|
||||||
public array $individualPrice = [];
|
public array $individualPrice = [];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ class Travel
|
|||||||
* Maps selection group IDs to their corresponding services based on
|
* Maps selection group IDs to their corresponding services based on
|
||||||
* the predefined included services mapping.
|
* the predefined included services mapping.
|
||||||
*
|
*
|
||||||
* @return array<int, Service> The included services from selection groups
|
* @return array<int, CrmSelectionGroup> The included services from selection groups
|
||||||
*/
|
*/
|
||||||
public function getIncludedServices(): array
|
public function getIncludedServices(): array
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ class ChaperonServiceStatusRule implements BookingStatusRuleInterface
|
|||||||
|
|
||||||
foreach ($arrayServices as $services) {
|
foreach ($arrayServices as $services) {
|
||||||
foreach ($services as $service) {
|
foreach ($services as $service) {
|
||||||
if ($service instanceof Service && true === $this->containsSearchTerm($service->label)) {
|
if (true === $this->containsSearchTerm($service->label)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,9 +28,9 @@ trait SortByPriceTrait
|
|||||||
* collections in the application. Items are sorted from lowest to highest price,
|
* collections in the application. Items are sorted from lowest to highest price,
|
||||||
* with null prices being treated as zero (appearing first).
|
* with null prices being treated as zero (appearing first).
|
||||||
*
|
*
|
||||||
* @param array $items Array of objects with a price property to sort
|
* @param array<array-key, object> $items Array of objects with a price property to sort
|
||||||
*
|
*
|
||||||
* @return array The sorted array of objects (ascending by price)
|
* @return array<array-key, object> The sorted array of objects (ascending by price)
|
||||||
*/
|
*/
|
||||||
protected function sortByPrice(array $items): array
|
protected function sortByPrice(array $items): array
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use Carbon\Exceptions\InvalidFormatException;
|
|||||||
|
|
||||||
trait TypeConversionTrait
|
trait TypeConversionTrait
|
||||||
{
|
{
|
||||||
|
/** @return list<string> */
|
||||||
protected function stringToArray(?string $string, string $separator = ','): array
|
protected function stringToArray(?string $string, string $separator = ','): array
|
||||||
{
|
{
|
||||||
if (true === empty($string)) {
|
if (true === empty($string)) {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ use Symfony\Contracts\Cache\ItemInterface;
|
|||||||
|
|
||||||
class HotelLoader extends AbstractLoader
|
class HotelLoader extends AbstractLoader
|
||||||
{
|
{
|
||||||
|
/** @return array<int, Hotel> */
|
||||||
public function loadAll(?string $filename = 'hotel.xml'): array
|
public function loadAll(?string $filename = 'hotel.xml'): array
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ class InsuranceLoader extends AbstractLoader
|
|||||||
parent::__construct($cache, $xmlExport);
|
parent::__construct($cache, $xmlExport);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return array<string|int, Insurance> */
|
||||||
public function loadAll(?string $filename = 'versicherungen.xml'): array
|
public function loadAll(?string $filename = 'versicherungen.xml'): array
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ use Symfony\Contracts\Cache\ItemInterface;
|
|||||||
|
|
||||||
class PickupLoader extends AbstractLoader
|
class PickupLoader extends AbstractLoader
|
||||||
{
|
{
|
||||||
|
/** @return array<int|string, Pickup> */
|
||||||
public function loadAll(?string $filename = 'zustiege.xml'): array
|
public function loadAll(?string $filename = 'zustiege.xml'): array
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
@@ -65,6 +66,11 @@ class PickupLoader extends AbstractLoader
|
|||||||
$travel->dropOffs = $this->patchAndOrderDropOffs($travel->dropOffs, $travel->pickups);
|
$travel->dropOffs = $this->patchAndOrderDropOffs($travel->dropOffs, $travel->pickups);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<int, Pickup> $pickups
|
||||||
|
*
|
||||||
|
* @return array<int, Pickup>
|
||||||
|
*/
|
||||||
private function patchAndSortPickups(array $pickups): array
|
private function patchAndSortPickups(array $pickups): array
|
||||||
{
|
{
|
||||||
$this->enrichPickupDetails($pickups);
|
$this->enrichPickupDetails($pickups);
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ class TravelLoader extends AbstractLoader
|
|||||||
* including ID, code, label, dates, and associated hotels. The mapping is
|
* including ID, code, label, dates, and associated hotels. The mapping is
|
||||||
* cached for 3 hours to improve performance.
|
* cached for 3 hours to improve performance.
|
||||||
*
|
*
|
||||||
* @return array<int, array> Mapping of travel IDs to their metadata and file paths
|
* @return array<int, array<string, mixed>> Mapping of travel IDs to their metadata and file paths
|
||||||
*/
|
*/
|
||||||
public function generateFilesMap(): array
|
public function generateFilesMap(): array
|
||||||
{
|
{
|
||||||
@@ -74,7 +74,7 @@ class TravelLoader extends AbstractLoader
|
|||||||
$travelDataNodes = $crawler->filterXPath('//reisen/reise/termin');
|
$travelDataNodes = $crawler->filterXPath('//reisen/reise/termin');
|
||||||
|
|
||||||
$travelDataNodes->each(function (Crawler $node) use (&$mapping, $hotels, $file) {
|
$travelDataNodes->each(function (Crawler $node) use (&$mapping, $hotels, $file) {
|
||||||
$travelId = $node->attr('idbuspro');
|
$travelId = (int) $node->attr('idbuspro');
|
||||||
|
|
||||||
$mapping[$travelId] = [
|
$mapping[$travelId] = [
|
||||||
'id' => $travelId,
|
'id' => $travelId,
|
||||||
@@ -173,6 +173,7 @@ class TravelLoader extends AbstractLoader
|
|||||||
*
|
*
|
||||||
* @throws TravelNotFoundException When travel ID is not found
|
* @throws TravelNotFoundException When travel ID is not found
|
||||||
* @throws HotelNotInTravelException When hotel ID exists but not for this travel
|
* @throws HotelNotInTravelException When hotel ID exists but not for this travel
|
||||||
|
* @throws \RuntimeException When cached mapping generation fails unexpectedly
|
||||||
*/
|
*/
|
||||||
public function loadById(int $dateId, ?int $hotelId = null, ?string $filename = null): Travel
|
public function loadById(int $dateId, ?int $hotelId = null, ?string $filename = null): Travel
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ abstract class AbstractParser
|
|||||||
return 0 < $node->count() && $this->stringToBool($node->text());
|
return 0 < $node->count() && $this->stringToBool($node->text());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return list<string> */
|
||||||
protected function getArrayValue(Crawler $node, string $separator = ','): array
|
protected function getArrayValue(Crawler $node, string $separator = ','): array
|
||||||
{
|
{
|
||||||
if (0 === $node->count()) {
|
if (0 === $node->count()) {
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ class AgeConstraintParserRegistry
|
|||||||
return $this->mergeConstraintResults($results, $constraintData);
|
return $this->mergeConstraintResults($results, $constraintData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param list<AgeConstraintResult> $results */
|
||||||
private function mergeConstraintResults(array $results, string $rawData): AgeConstraintResult
|
private function mergeConstraintResults(array $results, string $rawData): AgeConstraintResult
|
||||||
{
|
{
|
||||||
if (empty($results)) {
|
if (empty($results)) {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ class ApiResponseParser extends AbstractParser
|
|||||||
/**
|
/**
|
||||||
* @throws ResponseParserException
|
* @throws ResponseParserException
|
||||||
*/
|
*/
|
||||||
|
/** @param array<string, mixed> $additionalArgs */
|
||||||
public function parseXmlString(string $type, string $xml, array $additionalArgs = []): mixed
|
public function parseXmlString(string $type, string $xml, array $additionalArgs = []): mixed
|
||||||
{
|
{
|
||||||
$crawler = new Crawler($xml);
|
$crawler = new Crawler($xml);
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ use Symfony\Component\DomCrawler\Crawler;
|
|||||||
*/
|
*/
|
||||||
class BookingInsurancesParser extends AbstractParser
|
class BookingInsurancesParser extends AbstractParser
|
||||||
{
|
{
|
||||||
|
/** @return array<string, Insurance> */
|
||||||
public function parse(Crawler $result): array
|
public function parse(Crawler $result): array
|
||||||
{
|
{
|
||||||
$insurances = [];
|
$insurances = [];
|
||||||
|
|||||||
@@ -112,6 +112,7 @@ class BookingParser extends AbstractParser
|
|||||||
return $booking;
|
return $booking;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return array<int, PersonalData> */
|
||||||
private function parseParticipants(Crawler $node): array
|
private function parseParticipants(Crawler $node): array
|
||||||
{
|
{
|
||||||
$participants = [];
|
$participants = [];
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ class CrmAttributesResponseParser
|
|||||||
|
|
||||||
$result
|
$result
|
||||||
->filterXPath('//selektionsmerkmale/selektionsgruppe')
|
->filterXPath('//selektionsmerkmale/selektionsgruppe')
|
||||||
->each(function (Crawler $node) use (&$groups, &$roles, &$hotelCode) {
|
->each(function (Crawler $node) use (&$groups, &$roles) {
|
||||||
$group = new CrmSelectionGroup();
|
$group = new CrmSelectionGroup();
|
||||||
$group->id = (int) $node->attr('id');
|
$group->id = (int) $node->attr('id');
|
||||||
$group->label = $node->attr('bezeichnung');
|
$group->label = $node->attr('bezeichnung');
|
||||||
@@ -47,14 +47,14 @@ class CrmAttributesResponseParser
|
|||||||
$roles[] = 'ROLE_HOUSE_MANAGER';
|
$roles[] = 'ROLE_HOUSE_MANAGER';
|
||||||
$hotelCodes[] = $matches[1];
|
$hotelCodes[] = $matches[1];
|
||||||
}
|
}
|
||||||
if (static::BPN_CRM_ID_ADMIN === $attribute->id && true === $attribute->selected) {
|
if (self::BPN_CRM_ID_ADMIN === $attribute->id && true === $attribute->selected) {
|
||||||
$roles[] = 'ROLE_ADMIN';
|
$roles[] = 'ROLE_ADMIN';
|
||||||
$roles[] = 'ROLE_HOUSE_MANAGER';
|
$roles[] = 'ROLE_HOUSE_MANAGER';
|
||||||
}
|
}
|
||||||
if (static::BPN_CRM_ID_MANAGER === $attribute->id && true === $attribute->selected) {
|
if (self::BPN_CRM_ID_MANAGER === $attribute->id && true === $attribute->selected) {
|
||||||
$roles[] = 'ROLE_MANAGER';
|
$roles[] = 'ROLE_MANAGER';
|
||||||
}
|
}
|
||||||
if (static::BPN_CRM_ID_TEAMER === $attribute->id && true === $attribute->selected) {
|
if (self::BPN_CRM_ID_TEAMER === $attribute->id && true === $attribute->selected) {
|
||||||
$roles[] = 'ROLE_TEAMER';
|
$roles[] = 'ROLE_TEAMER';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,7 +90,7 @@ class CrmAttributesResponseParser
|
|||||||
;
|
;
|
||||||
|
|
||||||
if (true === in_array('ROLE_ADMIN', $roles, true)) {
|
if (true === in_array('ROLE_ADMIN', $roles, true)) {
|
||||||
$hotelCodes[] = static::BPN_DEFAULT_HOTEL_CODE;
|
$hotelCodes[] = self::BPN_DEFAULT_HOTEL_CODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
$response = new CrmAttributes();
|
$response = new CrmAttributes();
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ class DocumentsParser
|
|||||||
return base64_decode($pdfData);
|
return base64_decode($pdfData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return array{string, string} */
|
||||||
private function getFileInfo(Crawler $node): array
|
private function getFileInfo(Crawler $node): array
|
||||||
{
|
{
|
||||||
$pdfData = $this->decode($node->filterXPath('.//pdf'));
|
$pdfData = $this->decode($node->filterXPath('.//pdf'));
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ class InsuranceParser extends AbstractParser
|
|||||||
|
|
||||||
// Parse all individual insurances for reference lookup
|
// Parse all individual insurances for reference lookup
|
||||||
$insurance = $this->parseInsuranceNode($node, false);
|
$insurance = $this->parseInsuranceNode($node, false);
|
||||||
if (null !== $insurance && null !== $insurance->id) {
|
if (null !== $insurance->id) {
|
||||||
// Set complementary flag from XML attribute
|
// Set complementary flag from XML attribute
|
||||||
$insurance->complementary = $isComplementary;
|
$insurance->complementary = $isComplementary;
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ class InsuranceParser extends AbstractParser
|
|||||||
$xmlContent->filterXPath('//versicherungspakete/versicherungspaket')
|
$xmlContent->filterXPath('//versicherungspakete/versicherungspaket')
|
||||||
->each(function (Crawler $node) use (&$insurances, $individualInsurances) {
|
->each(function (Crawler $node) use (&$insurances, $individualInsurances) {
|
||||||
$insurance = $this->parseInsuranceNode($node, true, $individualInsurances);
|
$insurance = $this->parseInsuranceNode($node, true, $individualInsurances);
|
||||||
if (null !== $insurance && null !== $insurance->id) {
|
if (null !== $insurance->id) {
|
||||||
// Parse contained insurance IDs
|
// Parse contained insurance IDs
|
||||||
$insurance->containedInsuranceIds = $this->parseContainedInsuranceIds($node);
|
$insurance->containedInsuranceIds = $this->parseContainedInsuranceIds($node);
|
||||||
|
|
||||||
@@ -75,8 +75,8 @@ class InsuranceParser extends AbstractParser
|
|||||||
/**
|
/**
|
||||||
* Determines if a package contains any family insurances.
|
* Determines if a package contains any family insurances.
|
||||||
*
|
*
|
||||||
* @param Crawler $packageNode The package XML node
|
* @param Crawler $packageNode The package XML node
|
||||||
* @param array<int, Insurance> $individualInsurances Parsed individual insurances for reference
|
* @param array<string, Insurance> $individualInsurances Parsed individual insurances for reference
|
||||||
*
|
*
|
||||||
* @return bool True if any contained insurance is a family insurance
|
* @return bool True if any contained insurance is a family insurance
|
||||||
*/
|
*/
|
||||||
@@ -96,13 +96,13 @@ class InsuranceParser extends AbstractParser
|
|||||||
/**
|
/**
|
||||||
* Parses a single insurance or package node.
|
* Parses a single insurance or package node.
|
||||||
*
|
*
|
||||||
* @param Crawler $node The XML node to parse
|
* @param Crawler $node The XML node to parse
|
||||||
* @param bool $isPackage Whether this is a package node
|
* @param bool $isPackage Whether this is a package node
|
||||||
* @param array<int, Insurance> $individualInsurances Individual insurances for package family detection
|
* @param array<string, Insurance> $individualInsurances Individual insurances for package family detection
|
||||||
*
|
*
|
||||||
* @return Insurance|null The parsed insurance object
|
* @return Insurance The parsed insurance object
|
||||||
*/
|
*/
|
||||||
private function parseInsuranceNode(Crawler $node, bool $isPackage, array $individualInsurances = []): ?Insurance
|
private function parseInsuranceNode(Crawler $node, bool $isPackage, array $individualInsurances = []): Insurance
|
||||||
{
|
{
|
||||||
$insurance = new Insurance();
|
$insurance = new Insurance();
|
||||||
$insurance->package = $isPackage;
|
$insurance->package = $isPackage;
|
||||||
@@ -159,7 +159,7 @@ class InsuranceParser extends AbstractParser
|
|||||||
*
|
*
|
||||||
* @param Crawler $xmlContent The XML content to scan
|
* @param Crawler $xmlContent The XML content to scan
|
||||||
*
|
*
|
||||||
* @return array<int> Array of referenced insurance IDs
|
* @return list<string> Array of referenced insurance IDs
|
||||||
*/
|
*/
|
||||||
private function collectReferencedInsuranceIds(Crawler $xmlContent): array
|
private function collectReferencedInsuranceIds(Crawler $xmlContent): array
|
||||||
{
|
{
|
||||||
@@ -180,7 +180,7 @@ class InsuranceParser extends AbstractParser
|
|||||||
*
|
*
|
||||||
* @param Crawler $node The package XML node
|
* @param Crawler $node The package XML node
|
||||||
*
|
*
|
||||||
* @return array<int> Array of contained insurance IDs (always int, as they reference individual insurances)
|
* @return list<string> Array of contained insurance IDs
|
||||||
*/
|
*/
|
||||||
private function parseContainedInsuranceIds(Crawler $node): array
|
private function parseContainedInsuranceIds(Crawler $node): array
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use Symfony\Component\DomCrawler\Crawler;
|
|||||||
|
|
||||||
class PickupsParser extends AbstractParser
|
class PickupsParser extends AbstractParser
|
||||||
{
|
{
|
||||||
|
/** @return array<int, Pickup> */
|
||||||
public function parse(Crawler $result): array
|
public function parse(Crawler $result): array
|
||||||
{
|
{
|
||||||
$pickups = [];
|
$pickups = [];
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use Symfony\Component\DomCrawler\Crawler;
|
|||||||
|
|
||||||
class RoomsParser extends AbstractParser
|
class RoomsParser extends AbstractParser
|
||||||
{
|
{
|
||||||
|
/** @return array<int, Room> */
|
||||||
public function parse(Crawler $result): array
|
public function parse(Crawler $result): array
|
||||||
{
|
{
|
||||||
$rooms = [];
|
$rooms = [];
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use Symfony\Component\DomCrawler\Crawler;
|
|||||||
|
|
||||||
class ServicesParser extends AbstractParser
|
class ServicesParser extends AbstractParser
|
||||||
{
|
{
|
||||||
|
/** @return array<int, Service> */
|
||||||
public function parse(Crawler $result, string $category, string $source): array
|
public function parse(Crawler $result, string $category, string $source): array
|
||||||
{
|
{
|
||||||
$services = [];
|
$services = [];
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use Symfony\Component\DomCrawler\Crawler;
|
|||||||
|
|
||||||
class SurchargesParser extends AbstractParser
|
class SurchargesParser extends AbstractParser
|
||||||
{
|
{
|
||||||
|
/** @return list<Surcharge> */
|
||||||
public function parse(Crawler $result): array
|
public function parse(Crawler $result): array
|
||||||
{
|
{
|
||||||
$surcharges = [];
|
$surcharges = [];
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator;
|
|||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\Routing\Attribute\Route;
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
|
|
||||||
|
/** @extends AbstractCrudController<BookingEditDraft> */
|
||||||
class BookingEditDraftCrudController extends AbstractCrudController
|
class BookingEditDraftCrudController extends AbstractCrudController
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ use League\Flysystem\FilesystemException;
|
|||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
|
/** @extends AbstractCrudController<LogEntry> */
|
||||||
class LogEntryCrudController extends AbstractCrudController
|
class LogEntryCrudController extends AbstractCrudController
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
|
|||||||
use EasyCorp\Bundle\EasyAdminBundle\Field\DateTimeField;
|
use EasyCorp\Bundle\EasyAdminBundle\Field\DateTimeField;
|
||||||
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
|
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
|
||||||
|
|
||||||
|
/** @extends AbstractCrudController<User> */
|
||||||
class UserCrudController extends AbstractCrudController
|
class UserCrudController extends AbstractCrudController
|
||||||
{
|
{
|
||||||
public static function getEntityFqcn(): string
|
public static function getEntityFqcn(): string
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use League\Flysystem\FilesystemException;
|
|||||||
use League\Flysystem\FilesystemOperator;
|
use League\Flysystem\FilesystemOperator;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\Exception\JsonException;
|
||||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
@@ -73,7 +74,7 @@ class PickupController extends AbstractController
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$payload = $request->toArray();
|
$payload = $request->toArray();
|
||||||
} catch (\JsonException $e) {
|
} catch (JsonException $e) {
|
||||||
$this->logger->error('Failed to update pickups planning data', [
|
$this->logger->error('Failed to update pickups planning data', [
|
||||||
'message' => $e->getMessage(),
|
'message' => $e->getMessage(),
|
||||||
'payload' => (string) $request->getContent(),
|
'payload' => (string) $request->getContent(),
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ class TravelController extends AbstractController
|
|||||||
name: 'api_travel_single_code',
|
name: 'api_travel_single_code',
|
||||||
defaults: ['hotelCode' => null],
|
defaults: ['hotelCode' => null],
|
||||||
)]
|
)]
|
||||||
public function byCode(Request $request, $dateCode, ?string $hotelCode = null): JsonResponse
|
public function byCode(Request $request, string $dateCode, ?string $hotelCode = null): JsonResponse
|
||||||
{
|
{
|
||||||
// sanitize date code by removing potential dividers
|
// sanitize date code by removing potential dividers
|
||||||
$dateCode = (new DateCodeUtility())->sanitize($dateCode);
|
$dateCode = (new DateCodeUtility())->sanitize($dateCode);
|
||||||
|
|||||||
@@ -66,6 +66,11 @@ class UserinfoController extends AbstractController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param list<string> $scopes
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
private function getClaims(PersonalData $data, array $scopes): array
|
private function getClaims(PersonalData $data, array $scopes): array
|
||||||
{
|
{
|
||||||
// get all available claims
|
// get all available claims
|
||||||
|
|||||||
@@ -132,6 +132,7 @@ class Step2Controller extends AbstractController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param array<int, \App\Form\Model\RoomSelectionDto> $roomSelections */
|
||||||
private function calculateParticipantsCount(array $roomSelections, Travel $travelData): int
|
private function calculateParticipantsCount(array $roomSelections, Travel $travelData): int
|
||||||
{
|
{
|
||||||
$participantsCount = 0;
|
$participantsCount = 0;
|
||||||
|
|||||||
@@ -124,6 +124,7 @@ class Step2ParticipantController extends AbstractController
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param FormInterface<mixed> $form */
|
||||||
private function renderParticipantForm(
|
private function renderParticipantForm(
|
||||||
FormInterface $form,
|
FormInterface $form,
|
||||||
int $index,
|
int $index,
|
||||||
@@ -157,6 +158,7 @@ class Step2ParticipantController extends AbstractController
|
|||||||
return $bookingDto;
|
return $bookingDto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return FormInterface<mixed> */
|
||||||
private function createParticipantForm(BookingDto $bookingDto, int $index): FormInterface
|
private function createParticipantForm(BookingDto $bookingDto, int $index): FormInterface
|
||||||
{
|
{
|
||||||
$wrapper = $this->participantFormSupportService->createParticipantEditDto($bookingDto, $index);
|
$wrapper = $this->participantFormSupportService->createParticipantEditDto($bookingDto, $index);
|
||||||
|
|||||||
@@ -220,6 +220,7 @@ class Step3Controller extends AbstractController
|
|||||||
/**
|
/**
|
||||||
* Renders the step 3 form with standard template variables.
|
* Renders the step 3 form with standard template variables.
|
||||||
*/
|
*/
|
||||||
|
/** @param FormInterface<mixed> $form */
|
||||||
private function renderStepForm(BookingDto $bookingCreateDto, FormInterface $form): Response
|
private function renderStepForm(BookingDto $bookingCreateDto, FormInterface $form): Response
|
||||||
{
|
{
|
||||||
$context = $this->createContextFactory->create(
|
$context = $this->createContextFactory->create(
|
||||||
|
|||||||
@@ -177,6 +177,9 @@ class Step4Controller extends AbstractController
|
|||||||
/**
|
/**
|
||||||
* Renders the step 4 form with standard template variables.
|
* Renders the step 4 form with standard template variables.
|
||||||
*/
|
*/
|
||||||
|
/**
|
||||||
|
* @param FormInterface<mixed> $form
|
||||||
|
*/
|
||||||
private function renderStepForm(
|
private function renderStepForm(
|
||||||
BookingDto $bookingCreateDto,
|
BookingDto $bookingCreateDto,
|
||||||
FormInterface $form,
|
FormInterface $form,
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use App\Service\BookingSessionManager;
|
|||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\HttpFoundation\Session\FlashBagAwareSessionInterface;
|
||||||
use Symfony\Component\Routing\Attribute\Route;
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -23,11 +24,17 @@ class SuccessController extends AbstractController
|
|||||||
#[Route('/bookings/create/success', name: 'app_booking_create_success')]
|
#[Route('/bookings/create/success', name: 'app_booking_create_success')]
|
||||||
public function success(Request $request): Response
|
public function success(Request $request): Response
|
||||||
{
|
{
|
||||||
$flashBag = $request->getSession()->getFlashBag();
|
$returnUrl = $this->bookingSessionService->getReturnUrl($request);
|
||||||
|
$session = $request->getSession();
|
||||||
|
|
||||||
|
if (!$session instanceof FlashBagAwareSessionInterface) {
|
||||||
|
return $this->redirect($returnUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
$flashBag = $session->getFlashBag();
|
||||||
$bookingNumber = $flashBag->get('booking_number')[0] ?? null;
|
$bookingNumber = $flashBag->get('booking_number')[0] ?? null;
|
||||||
$bookingTotal = $flashBag->get('booking_total')[0] ?? null;
|
$bookingTotal = $flashBag->get('booking_total')[0] ?? null;
|
||||||
$travelName = $flashBag->get('booking_travel_name')[0] ?? null;
|
$travelName = $flashBag->get('booking_travel_name')[0] ?? null;
|
||||||
$returnUrl = $this->bookingSessionService->getReturnUrl($request);
|
|
||||||
|
|
||||||
// Redirect to return URL if no booking number (direct access or refresh)
|
// Redirect to return URL if no booking number (direct access or refresh)
|
||||||
if (null === $bookingNumber) {
|
if (null === $bookingNumber) {
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ class DownloadController extends AbstractController
|
|||||||
$type = match ($fileType) {
|
$type = match ($fileType) {
|
||||||
'documents' => 'Dokumentdruck',
|
'documents' => 'Dokumentdruck',
|
||||||
'invoice' => 'Vorgangdruck',
|
'invoice' => 'Vorgangdruck',
|
||||||
|
default => throw new \InvalidArgumentException(sprintf('Unknown file type: %s', $fileType)),
|
||||||
};
|
};
|
||||||
|
|
||||||
$this->logger->info('Initiated document download', [
|
$this->logger->info('Initiated document download', [
|
||||||
|
|||||||
@@ -52,6 +52,9 @@ trait BookingCreateTrait
|
|||||||
/**
|
/**
|
||||||
* Handles API errors by logging and adding a flash message.
|
* Handles API errors by logging and adding a flash message.
|
||||||
*/
|
*/
|
||||||
|
/**
|
||||||
|
* @param array<string, mixed> $context
|
||||||
|
*/
|
||||||
private function handleApiError(
|
private function handleApiError(
|
||||||
LoggerInterface $logger,
|
LoggerInterface $logger,
|
||||||
string $logMessage,
|
string $logMessage,
|
||||||
|
|||||||
@@ -5,9 +5,7 @@ declare(strict_types=1);
|
|||||||
namespace App\Controller\Booking\Traits;
|
namespace App\Controller\Booking\Traits;
|
||||||
|
|
||||||
use App\Exception\BookingSessionNotFoundException;
|
use App\Exception\BookingSessionNotFoundException;
|
||||||
use App\Exception\HotelNotFoundException;
|
|
||||||
use App\Exception\HotelNotInTravelException;
|
use App\Exception\HotelNotInTravelException;
|
||||||
use App\Exception\NoRoomsAvailableException;
|
|
||||||
use App\Exception\TravelNotFoundException;
|
use App\Exception\TravelNotFoundException;
|
||||||
use App\Form\Model\BookingDto;
|
use App\Form\Model\BookingDto;
|
||||||
use App\Service\BookingSessionManager;
|
use App\Service\BookingSessionManager;
|
||||||
@@ -33,25 +31,9 @@ trait BookingExceptionHandlerTrait
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
return $bookingSessionService->getOrCreateBookingCreateDto($request);
|
return $bookingSessionService->getOrCreateBookingCreateDto($request);
|
||||||
} catch (BookingSessionNotFoundException $e) {
|
} catch (BookingSessionNotFoundException|TravelNotFoundException|HotelNotInTravelException $e) {
|
||||||
$this->addFlash('error', 'Deine Buchungssitzung ist abgelaufen. Bitte starte eine neue Buchung.');
|
$this->addFlash('error', 'Deine Buchungssitzung ist abgelaufen. Bitte starte eine neue Buchung.');
|
||||||
|
|
||||||
return $this->redirectToRoute('app_booking_create_error');
|
|
||||||
} catch (TravelNotFoundException $e) {
|
|
||||||
$this->addFlash('error', 'Die angeforderte Reise wurde nicht gefunden.');
|
|
||||||
|
|
||||||
return $this->redirectToRoute('app_booking_create_error');
|
|
||||||
} catch (HotelNotFoundException $e) {
|
|
||||||
$this->addFlash('error', 'Das angeforderte Hotel wurde nicht gefunden.');
|
|
||||||
|
|
||||||
return $this->redirectToRoute('app_booking_create_error');
|
|
||||||
} catch (HotelNotInTravelException $e) {
|
|
||||||
$this->addFlash('error', 'Das Hotel ist für diese Reise nicht verfügbar.');
|
|
||||||
|
|
||||||
return $this->redirectToRoute('app_booking_create_error');
|
|
||||||
} catch (NoRoomsAvailableException $e) {
|
|
||||||
$this->addFlash('error', 'Für diese Reise sind aktuell keine Zimmer verfügbar.');
|
|
||||||
|
|
||||||
return $this->redirectToRoute('app_booking_create_error');
|
return $this->redirectToRoute('app_booking_create_error');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -66,7 +48,7 @@ trait BookingExceptionHandlerTrait
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
return $bookingSessionService->getOrCreateBookingCreateDto($request);
|
return $bookingSessionService->getOrCreateBookingCreateDto($request);
|
||||||
} catch (BookingSessionNotFoundException|TravelNotFoundException|HotelNotFoundException|HotelNotInTravelException|NoRoomsAvailableException $e) {
|
} catch (BookingSessionNotFoundException|TravelNotFoundException|HotelNotInTravelException $e) {
|
||||||
return new Response('', 400);
|
return new Response('', 400);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ use Symfony\Component\Form\Extension\Core\Type\TextType;
|
|||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
/** @extends AbstractType<Address> */
|
||||||
class AddressType extends AbstractType
|
class AddressType extends AbstractType
|
||||||
{
|
{
|
||||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ use Symfony\Component\Form\Extension\Core\Type\TextType;
|
|||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
/** @extends AbstractType<BankAccountDto> */
|
||||||
class BankAccountType extends AbstractType
|
class BankAccountType extends AbstractType
|
||||||
{
|
{
|
||||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
|||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
/** @extends AbstractType<ParticipantDto> */
|
||||||
class BodyDimensionsType extends AbstractType
|
class BodyDimensionsType extends AbstractType
|
||||||
{
|
{
|
||||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use Symfony\Component\Form\Extension\Core\Type\CollectionType;
|
|||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
/** @extends AbstractType<BookingDto> */
|
||||||
class BookingCreateStep1Type extends AbstractType
|
class BookingCreateStep1Type extends AbstractType
|
||||||
{
|
{
|
||||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
|
|||||||
* in separate forms. This form validates the complete BookingDto before proceeding
|
* in separate forms. This form validates the complete BookingDto before proceeding
|
||||||
* to Step 3, ensuring all participants have valid and complete data.
|
* to Step 3, ensuring all participants have valid and complete data.
|
||||||
*/
|
*/
|
||||||
|
/** @extends AbstractType<BookingDto> */
|
||||||
class BookingCreateStep2Type extends AbstractType
|
class BookingCreateStep2Type extends AbstractType
|
||||||
{
|
{
|
||||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||||
|
|||||||
@@ -12,8 +12,10 @@ use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
|||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
use Symfony\Component\Form\FormEvent;
|
use Symfony\Component\Form\FormEvent;
|
||||||
use Symfony\Component\Form\FormEvents;
|
use Symfony\Component\Form\FormEvents;
|
||||||
|
use Symfony\Component\Form\FormInterface;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
/** @extends AbstractType<BookingDto> */
|
||||||
class BookingCreateStep3Type extends AbstractType
|
class BookingCreateStep3Type extends AbstractType
|
||||||
{
|
{
|
||||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||||
@@ -76,7 +78,8 @@ class BookingCreateStep3Type extends AbstractType
|
|||||||
/**
|
/**
|
||||||
* Adds the bank account field to the form.
|
* Adds the bank account field to the form.
|
||||||
*/
|
*/
|
||||||
private function addBankAccountField($form): void
|
/** @param FormInterface<mixed> $form */
|
||||||
|
private function addBankAccountField(FormInterface $form): void
|
||||||
{
|
{
|
||||||
$form->add('bankAccount', BankAccountType::class, [
|
$form->add('bankAccount', BankAccountType::class, [
|
||||||
'label' => false,
|
'label' => false,
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ use Symfony\Component\Form\FormBuilderInterface;
|
|||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
use Symfony\Component\Validator\Constraints as Assert;
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
|
||||||
|
/** @extends AbstractType<BookingDto> */
|
||||||
class BookingCreateStep4Type extends AbstractType
|
class BookingCreateStep4Type extends AbstractType
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
|
|||||||
* This form validates the complete BookingDto before allowing updates,
|
* This form validates the complete BookingDto before allowing updates,
|
||||||
* ensuring all participants have valid and complete data.
|
* ensuring all participants have valid and complete data.
|
||||||
*/
|
*/
|
||||||
|
/** @extends AbstractType<BookingDto> */
|
||||||
class BookingEditType extends AbstractType
|
class BookingEditType extends AbstractType
|
||||||
{
|
{
|
||||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ use Symfony\Component\Form\FormEvents;
|
|||||||
use Symfony\Component\Form\FormInterface;
|
use Symfony\Component\Form\FormInterface;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
/** @extends AbstractType<ParticipantEditDto> */
|
||||||
class BookingParticipantType extends AbstractType
|
class BookingParticipantType extends AbstractType
|
||||||
{
|
{
|
||||||
private FieldStateProviderInterface $fieldStateProvider;
|
private FieldStateProviderInterface $fieldStateProvider;
|
||||||
@@ -80,10 +81,6 @@ class BookingParticipantType extends AbstractType
|
|||||||
/** @var ParticipantEditDto $data */
|
/** @var ParticipantEditDto $data */
|
||||||
$data = $form->getData();
|
$data = $form->getData();
|
||||||
|
|
||||||
if (null === $data || null === $data->participant) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process all field handlers for this participant and sync submitted data
|
// Process all field handlers for this participant and sync submitted data
|
||||||
$syncedData = $this->fieldHandlerRegistry->processFieldsForParticipantAndSync(
|
$syncedData = $this->fieldHandlerRegistry->processFieldsForParticipantAndSync(
|
||||||
$submittedData,
|
$submittedData,
|
||||||
@@ -110,11 +107,7 @@ class BookingParticipantType extends AbstractType
|
|||||||
$form = $event->getForm();
|
$form = $event->getForm();
|
||||||
|
|
||||||
// Use bookingContext from wrapper DTO or fallback to passed option
|
// Use bookingContext from wrapper DTO or fallback to passed option
|
||||||
$bookingDto = $data->bookingContext ?? $bookingContext ?? $this->fieldStateProvider->getBookingDtoFromForm($form);
|
$bookingDto = $data->bookingContext;
|
||||||
|
|
||||||
if (null === $bookingDto) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add base fields with states applied
|
// Add base fields with states applied
|
||||||
$this->addBaseFields($form, $bookingDto, $data->participant->index);
|
$this->addBaseFields($form, $bookingDto, $data->participant->index);
|
||||||
@@ -134,16 +127,8 @@ class BookingParticipantType extends AbstractType
|
|||||||
/** @var ParticipantEditDto $data */
|
/** @var ParticipantEditDto $data */
|
||||||
$data = $form->getData();
|
$data = $form->getData();
|
||||||
|
|
||||||
if (null === $data || null === $data->participant) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use bookingContext from wrapper DTO or fallback to passed option
|
// Use bookingContext from wrapper DTO or fallback to passed option
|
||||||
$bookingDto = $data->bookingContext ?? $bookingContext ?? $this->fieldStateProvider->getBookingDtoFromForm($form);
|
$bookingDto = $data->bookingContext;
|
||||||
|
|
||||||
if (null === $bookingDto) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rebuild all fields with updated states based on submitted data
|
// Rebuild all fields with updated states based on submitted data
|
||||||
$this->rebuildFieldsWithStates($form, $bookingDto, $data->participant->index, $submittedData);
|
$this->rebuildFieldsWithStates($form, $bookingDto, $data->participant->index, $submittedData);
|
||||||
@@ -154,6 +139,7 @@ class BookingParticipantType extends AbstractType
|
|||||||
/**
|
/**
|
||||||
* Adds base fields to the form with field states applied.
|
* Adds base fields to the form with field states applied.
|
||||||
*/
|
*/
|
||||||
|
/** @param FormInterface<mixed> $form */
|
||||||
private function addBaseFields(FormInterface $form, BookingDto $bookingDto, int $participantIndex): void
|
private function addBaseFields(FormInterface $form, BookingDto $bookingDto, int $participantIndex): void
|
||||||
{
|
{
|
||||||
// Get field states for base fields
|
// Get field states for base fields
|
||||||
@@ -280,6 +266,10 @@ class BookingParticipantType extends AbstractType
|
|||||||
* @param int $participantIndex The participant index
|
* @param int $participantIndex The participant index
|
||||||
* @param array<string, mixed> $submittedData Submitted form data for state calculation
|
* @param array<string, mixed> $submittedData Submitted form data for state calculation
|
||||||
*/
|
*/
|
||||||
|
/**
|
||||||
|
* @param FormInterface<mixed> $form
|
||||||
|
* @param array<string, mixed> $submittedData
|
||||||
|
*/
|
||||||
private function removeExcludedFields(FormInterface $form, BookingDto $bookingDto, int $participantIndex, array &$submittedData = []): void
|
private function removeExcludedFields(FormInterface $form, BookingDto $bookingDto, int $participantIndex, array &$submittedData = []): void
|
||||||
{
|
{
|
||||||
foreach (ParticipantDto::DYNAMIC_FIELDS as $fieldName) {
|
foreach (ParticipantDto::DYNAMIC_FIELDS as $fieldName) {
|
||||||
@@ -296,6 +286,10 @@ class BookingParticipantType extends AbstractType
|
|||||||
/**
|
/**
|
||||||
* Rebuilds all fields with updated states based on submitted data.
|
* Rebuilds all fields with updated states based on submitted data.
|
||||||
*/
|
*/
|
||||||
|
/**
|
||||||
|
* @param FormInterface<mixed> $form
|
||||||
|
* @param array<string, mixed> $submittedData
|
||||||
|
*/
|
||||||
private function rebuildFieldsWithStates(FormInterface $form, BookingDto $bookingDto, int $participantIndex, array &$submittedData): void
|
private function rebuildFieldsWithStates(FormInterface $form, BookingDto $bookingDto, int $participantIndex, array &$submittedData): void
|
||||||
{
|
{
|
||||||
// First, remove fields that should be excluded entirely
|
// First, remove fields that should be excluded entirely
|
||||||
@@ -326,6 +320,7 @@ class BookingParticipantType extends AbstractType
|
|||||||
/**
|
/**
|
||||||
* Adds all configured dynamic fields to the form with state conditions applied.
|
* Adds all configured dynamic fields to the form with state conditions applied.
|
||||||
*/
|
*/
|
||||||
|
/** @param FormInterface<mixed> $form */
|
||||||
private function addDynamicFields(FormInterface $form, BookingDto $bookingDto, int $participantIndex): void
|
private function addDynamicFields(FormInterface $form, BookingDto $bookingDto, int $participantIndex): void
|
||||||
{
|
{
|
||||||
$dynamicFields = [
|
$dynamicFields = [
|
||||||
|
|||||||
@@ -16,12 +16,12 @@ use Symfony\Component\Form\Exception\TransformationFailedException;
|
|||||||
* the full object (including price) via choiceData while the form binds
|
* the full object (including price) via choiceData while the form binds
|
||||||
* the scalar ID to the participant's assignedRoomId property.
|
* the scalar ID to the participant's assignedRoomId property.
|
||||||
*
|
*
|
||||||
* @implements DataTransformerInterface<int|null, RoomSelectionDto|null>
|
* @implements DataTransformerInterface<mixed, mixed>
|
||||||
*/
|
*/
|
||||||
class RoomSelectionToIdTransformer implements DataTransformerInterface
|
class RoomSelectionToIdTransformer implements DataTransformerInterface
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @param RoomSelectionDto[] $roomSelections Available room selections for reverse lookup
|
* @param array<RoomSelectionDto> $roomSelections Available room selections for reverse lookup
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly array $roomSelections,
|
private readonly array $roomSelections,
|
||||||
@@ -29,11 +29,8 @@ class RoomSelectionToIdTransformer implements DataTransformerInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transforms an integer room ID to a RoomSelectionDto for form display.
|
* Converts the persisted room id from the model into the matching
|
||||||
*
|
* RoomSelectionDto so the form can render labels and pricing details.
|
||||||
* @param int|null $value The room ID from the model
|
|
||||||
*
|
|
||||||
* @return RoomSelectionDto|null The matching RoomSelectionDto or null
|
|
||||||
*/
|
*/
|
||||||
public function transform(mixed $value): ?RoomSelectionDto
|
public function transform(mixed $value): ?RoomSelectionDto
|
||||||
{
|
{
|
||||||
@@ -51,29 +48,28 @@ class RoomSelectionToIdTransformer implements DataTransformerInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transforms a RoomSelectionDto back to an integer room ID for the model.
|
* Converts the submitted choice value back into the model's integer room id.
|
||||||
*
|
*
|
||||||
* @param RoomSelectionDto|null $value The selected RoomSelectionDto from the form
|
* ChoiceType submits the selected room id as a scalar, so this method accepts
|
||||||
*
|
* an empty value, an int, or a digit-only string and rejects everything else.
|
||||||
* @return int|null The room ID or null
|
|
||||||
*
|
|
||||||
* @throws TransformationFailedException If an unexpected value type is received
|
|
||||||
*/
|
*/
|
||||||
public function reverseTransform(mixed $value): ?int
|
public function reverseTransform(mixed $value): ?int
|
||||||
{
|
{
|
||||||
if (null === $value) {
|
if (null === $value || '' === $value) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($value instanceof RoomSelectionDto) {
|
if (is_int($value)) {
|
||||||
return $value->id;
|
return $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle case where form submits scalar ID directly
|
if (is_string($value) && ctype_digit($value)) {
|
||||||
if (is_int($value) || is_string($value)) {
|
|
||||||
return (int) $value;
|
return (int) $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new TransformationFailedException(sprintf('Expected RoomSelectionDto, int, or null, got %s', get_debug_type($value)));
|
throw new TransformationFailedException(sprintf(
|
||||||
|
'Invalid room id value: %s',
|
||||||
|
get_debug_type($value)
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,9 +34,9 @@ class BankAccountDto
|
|||||||
#[Assert\IsTrue(message: 'Bitte akzeptiere das SEPA-Mandat.')]
|
#[Assert\IsTrue(message: 'Bitte akzeptiere das SEPA-Mandat.')]
|
||||||
public bool $sepaMandateAccepted = false;
|
public bool $sepaMandateAccepted = false;
|
||||||
|
|
||||||
public static function fromBankAccount(BankAccount $bankAccount): static
|
public static function fromBankAccount(BankAccount $bankAccount): self
|
||||||
{
|
{
|
||||||
$instance = new static();
|
$instance = new self();
|
||||||
$instance->iban = $bankAccount->iban;
|
$instance->iban = $bankAccount->iban;
|
||||||
$instance->accountHolder = $bankAccount->holder;
|
$instance->accountHolder = $bankAccount->holder;
|
||||||
$instance->bankName = $bankAccount->bankName;
|
$instance->bankName = $bankAccount->bankName;
|
||||||
|
|||||||
@@ -153,6 +153,7 @@ class BookingDto
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return array<int, ParticipantDto> */
|
||||||
public function getParticipants(): array
|
public function getParticipants(): array
|
||||||
{
|
{
|
||||||
return $this->participants;
|
return $this->participants;
|
||||||
|
|||||||
@@ -88,19 +88,27 @@ class ParticipantDto
|
|||||||
)]
|
)]
|
||||||
public ?string $remarksRoom = null;
|
public ?string $remarksRoom = null;
|
||||||
|
|
||||||
|
/** @var list<Service> */
|
||||||
public array $courses = [];
|
public array $courses = [];
|
||||||
|
/** @var list<Service> */
|
||||||
public array $additionalServices = [];
|
public array $additionalServices = [];
|
||||||
|
/** @var list<int> */
|
||||||
public array $autoBookOptOutServiceIds = [];
|
public array $autoBookOptOutServiceIds = [];
|
||||||
|
/** @var list<int> */
|
||||||
public array $autoBookOptOutSkiPassIds = [];
|
public array $autoBookOptOutSkiPassIds = [];
|
||||||
|
/** @var list<int> */
|
||||||
public array $autoBookOptOutBoardIds = [];
|
public array $autoBookOptOutBoardIds = [];
|
||||||
|
/** @var list<int> */
|
||||||
public array $autoBookOptOutRentalIds = [];
|
public array $autoBookOptOutRentalIds = [];
|
||||||
|
|
||||||
// Note: Ski pass validation is conditional - see ParticipantEditDto::validateSkiPassRequired()
|
// Note: Ski pass validation is conditional - see ParticipantEditDto::validateSkiPassRequired()
|
||||||
// Babies (0-2 years) are exempt from ski pass requirement
|
// Babies (0-2 years) are exempt from ski pass requirement
|
||||||
public ?Service $skiPass = null;
|
public ?Service $skiPass = null;
|
||||||
|
|
||||||
|
/** @var list<Service> */
|
||||||
public array $board = [];
|
public array $board = [];
|
||||||
public ?Service $veg = null;
|
public ?Service $veg = null;
|
||||||
|
/** @var list<Service> */
|
||||||
public array $rentals = [];
|
public array $rentals = [];
|
||||||
public ?Service $rentalInsurance = null;
|
public ?Service $rentalInsurance = null;
|
||||||
|
|
||||||
@@ -190,9 +198,9 @@ class ParticipantDto
|
|||||||
$this->address = new Address();
|
$this->address = new Address();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function fromPersonalData(PersonalData $personalData): static
|
public static function fromPersonalData(PersonalData $personalData): self
|
||||||
{
|
{
|
||||||
$instance = new static();
|
$instance = new self();
|
||||||
|
|
||||||
$instance->status = $personalData->status;
|
$instance->status = $personalData->status;
|
||||||
$instance->addressId = $personalData->addressId;
|
$instance->addressId = $personalData->addressId;
|
||||||
@@ -203,15 +211,15 @@ class ParticipantDto
|
|||||||
$instance->title = $personalData->title;
|
$instance->title = $personalData->title;
|
||||||
$instance->gender = $personalData->gender;
|
$instance->gender = $personalData->gender;
|
||||||
$instance->nationality = $personalData->nationality ?: 'D';
|
$instance->nationality = $personalData->nationality ?: 'D';
|
||||||
$instance->email = $personalData->communication?->email;
|
$instance->email = $personalData->communication->email;
|
||||||
$instance->mobile = $personalData->communication?->mobile;
|
$instance->mobile = $personalData->communication->mobile;
|
||||||
$instance->dateOfBirth = $personalData->dateOfBirth;
|
$instance->dateOfBirth = $personalData->dateOfBirth;
|
||||||
$instance->height = $personalData->height;
|
$instance->height = $personalData->height;
|
||||||
$instance->weight = $personalData->weight;
|
$instance->weight = $personalData->weight;
|
||||||
$instance->shoeSize = $personalData->shoeSize;
|
$instance->shoeSize = $personalData->shoeSize;
|
||||||
|
|
||||||
// Clone address to prevent shared object references that could cause mutations
|
// Clone address to prevent shared object references that could cause mutations
|
||||||
$instance->address = null !== $personalData->address ? clone $personalData->address : null;
|
$instance->address = clone $personalData->address;
|
||||||
|
|
||||||
$instance->remarksRoom = $personalData->remarksRoom;
|
$instance->remarksRoom = $personalData->remarksRoom;
|
||||||
$instance->licensePlate = $personalData->licensePlate;
|
$instance->licensePlate = $personalData->licensePlate;
|
||||||
@@ -292,7 +300,7 @@ class ParticipantDto
|
|||||||
*/
|
*/
|
||||||
public function getInsurancePrice(): float
|
public function getInsurancePrice(): float
|
||||||
{
|
{
|
||||||
return $this->insurance?->price ?? 0.0;
|
return $this->insurance->price ?? 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ use Symfony\Component\Form\FormEvent;
|
|||||||
use Symfony\Component\Form\FormEvents;
|
use Symfony\Component\Form\FormEvents;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
/** @extends AbstractType<BookingDto> */
|
||||||
class PaymentType extends AbstractType
|
class PaymentType extends AbstractType
|
||||||
{
|
{
|
||||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ use Symfony\Component\Form\Extension\Core\Type\EmailType;
|
|||||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
|
||||||
|
/** @extends AbstractType<mixed> */
|
||||||
class PersonalDataType extends AbstractType
|
class PersonalDataType extends AbstractType
|
||||||
{
|
{
|
||||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ use Symfony\Component\Form\Extension\Core\Type\TextType;
|
|||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
/** @extends AbstractType<RegistrationDto> */
|
||||||
class RegistrationType extends AbstractType
|
class RegistrationType extends AbstractType
|
||||||
{
|
{
|
||||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
|
|||||||
* RoomSelectionDto objects (for template access to price data) and integer IDs
|
* RoomSelectionDto objects (for template access to price data) and integer IDs
|
||||||
* (for the participant's assignedRoomId property).
|
* (for the participant's assignedRoomId property).
|
||||||
*/
|
*/
|
||||||
|
/** @extends AbstractType<mixed> */
|
||||||
class RoomAssignmentType extends AbstractType
|
class RoomAssignmentType extends AbstractType
|
||||||
{
|
{
|
||||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ use Symfony\Component\Form\FormInterface;
|
|||||||
use Symfony\Component\Form\FormView;
|
use Symfony\Component\Form\FormView;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
/** @extends AbstractType<RoomSelectionDto> */
|
||||||
class RoomSelectType extends AbstractType
|
class RoomSelectType extends AbstractType
|
||||||
{
|
{
|
||||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||||
|
|||||||
@@ -36,10 +36,10 @@ abstract class AbstractFieldOptionsProvider implements FieldOptionsProviderInter
|
|||||||
* used when building the form field. These options are merged with any
|
* used when building the form field. These options are merged with any
|
||||||
* static options defined in the form type.
|
* static options defined in the form type.
|
||||||
*
|
*
|
||||||
* @param string $fieldName The name of the field to configure
|
* @param string $fieldName The name of the field to configure
|
||||||
* @param BookingDto $bookingDto The current booking data for context (create or edit)
|
* @param BookingDto $bookingDto The current booking data for context (create or edit)
|
||||||
* @param int $participantIndex The index of the participant being configured
|
* @param int $participantIndex The index of the participant being configured
|
||||||
* @param array $options Additional options to customize field behavior
|
* @param array<string, mixed> $options Additional options to customize field behavior
|
||||||
*
|
*
|
||||||
* @return array<string, mixed> Symfony form field options, or empty array if field not supported
|
* @return array<string, mixed> Symfony form field options, or empty array if field not supported
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ class BulkInsuranceBookingCondition implements FieldConditionInterface
|
|||||||
/**
|
/**
|
||||||
* Gets the bulk insurance booking flag value from form data or participant DTO.
|
* Gets the bulk insurance booking flag value from form data or participant DTO.
|
||||||
*/
|
*/
|
||||||
|
/** @param array<string, mixed> $formData */
|
||||||
private function getBulkInsuranceBookingValue(array $formData, object $applicant): bool
|
private function getBulkInsuranceBookingValue(array $formData, object $applicant): bool
|
||||||
{
|
{
|
||||||
// First check form data (for fresh submissions)
|
// First check form data (for fresh submissions)
|
||||||
|
|||||||
@@ -168,6 +168,7 @@ class CompositeCondition implements FieldConditionInterface
|
|||||||
* Returns false as soon as any condition evaluates to false,
|
* Returns false as soon as any condition evaluates to false,
|
||||||
* avoiding unnecessary evaluation of remaining conditions.
|
* avoiding unnecessary evaluation of remaining conditions.
|
||||||
*/
|
*/
|
||||||
|
/** @param array<string, mixed> $formData */
|
||||||
private function evaluateAnd(BookingDto $bookingDto, int $participantIndex, array $formData): bool
|
private function evaluateAnd(BookingDto $bookingDto, int $participantIndex, array $formData): bool
|
||||||
{
|
{
|
||||||
foreach ($this->conditions as $condition) {
|
foreach ($this->conditions as $condition) {
|
||||||
@@ -185,6 +186,7 @@ class CompositeCondition implements FieldConditionInterface
|
|||||||
* Returns true as soon as any condition evaluates to true,
|
* Returns true as soon as any condition evaluates to true,
|
||||||
* avoiding unnecessary evaluation of remaining conditions.
|
* avoiding unnecessary evaluation of remaining conditions.
|
||||||
*/
|
*/
|
||||||
|
/** @param array<string, mixed> $formData */
|
||||||
private function evaluateOr(BookingDto $bookingDto, int $participantIndex, array $formData): bool
|
private function evaluateOr(BookingDto $bookingDto, int $participantIndex, array $formData): bool
|
||||||
{
|
{
|
||||||
foreach ($this->conditions as $condition) {
|
foreach ($this->conditions as $condition) {
|
||||||
@@ -199,6 +201,7 @@ class CompositeCondition implements FieldConditionInterface
|
|||||||
/**
|
/**
|
||||||
* Evaluates NOT logic by inverting the result of the single condition.
|
* Evaluates NOT logic by inverting the result of the single condition.
|
||||||
*/
|
*/
|
||||||
|
/** @param array<string, mixed> $formData */
|
||||||
private function evaluateNot(BookingDto $bookingDto, int $participantIndex, array $formData): bool
|
private function evaluateNot(BookingDto $bookingDto, int $participantIndex, array $formData): bool
|
||||||
{
|
{
|
||||||
return !$this->conditions[0]->evaluate($bookingDto, $participantIndex, $formData);
|
return !$this->conditions[0]->evaluate($bookingDto, $participantIndex, $formData);
|
||||||
@@ -219,6 +222,7 @@ class CompositeCondition implements FieldConditionInterface
|
|||||||
/**
|
/**
|
||||||
* Validates condition count based on operator requirements.
|
* Validates condition count based on operator requirements.
|
||||||
*/
|
*/
|
||||||
|
/** @param list<mixed> $conditions */
|
||||||
private function validateConditionCount(string $operator, array $conditions): void
|
private function validateConditionCount(string $operator, array $conditions): void
|
||||||
{
|
{
|
||||||
$conditionCount = count($conditions);
|
$conditionCount = count($conditions);
|
||||||
|
|||||||
@@ -175,6 +175,7 @@ class FieldValueCondition implements FieldConditionInterface
|
|||||||
/**
|
/**
|
||||||
* Retrieves field value from form data or participant data.
|
* Retrieves field value from form data or participant data.
|
||||||
*/
|
*/
|
||||||
|
/** @param array<string, mixed> $formData */
|
||||||
private function getFieldValue(array $formData, int $participantIndex, BookingDto $bookingDto): mixed
|
private function getFieldValue(array $formData, int $participantIndex, BookingDto $bookingDto): mixed
|
||||||
{
|
{
|
||||||
// First check participant-specific form data
|
// First check participant-specific form data
|
||||||
@@ -212,6 +213,7 @@ class FieldValueCondition implements FieldConditionInterface
|
|||||||
/**
|
/**
|
||||||
* Checks if field value is in array of expected values.
|
* Checks if field value is in array of expected values.
|
||||||
*/
|
*/
|
||||||
|
/** @param list<mixed> $expectedValues */
|
||||||
private function compareIn(mixed $fieldValue, array $expectedValues): bool
|
private function compareIn(mixed $fieldValue, array $expectedValues): bool
|
||||||
{
|
{
|
||||||
foreach ($expectedValues as $expectedValue) {
|
foreach ($expectedValues as $expectedValue) {
|
||||||
|
|||||||
@@ -28,10 +28,6 @@ class RentalInsuranceAvailableCondition implements FieldConditionInterface
|
|||||||
*/
|
*/
|
||||||
public function evaluate(BookingDto $bookingDto, int $participantIndex, array $formData): bool
|
public function evaluate(BookingDto $bookingDto, int $participantIndex, array $formData): bool
|
||||||
{
|
{
|
||||||
if (null === $bookingDto->travel) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$services = $bookingDto->travel->getAdditionalServicesBySubTypes(
|
$services = $bookingDto->travel->getAdditionalServicesBySubTypes(
|
||||||
Constants::TOKEN_RENTAL_INSURANCE,
|
Constants::TOKEN_RENTAL_INSURANCE,
|
||||||
true
|
true
|
||||||
|
|||||||
@@ -49,12 +49,7 @@ class RentalSelectionCondition implements FieldConditionInterface
|
|||||||
if (null !== $participant) {
|
if (null !== $participant) {
|
||||||
$rentals = $participant->rentals;
|
$rentals = $participant->rentals;
|
||||||
if (false === empty($rentals)) {
|
if (false === empty($rentals)) {
|
||||||
// Check if any rental services are actually selected
|
return true;
|
||||||
foreach ($rentals as $rental) {
|
|
||||||
if ($rental instanceof Service) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ use App\Form\Service\Contract\FieldConditionInterface;
|
|||||||
*/
|
*/
|
||||||
class RoomSelectionCondition implements FieldConditionInterface
|
class RoomSelectionCondition implements FieldConditionInterface
|
||||||
{
|
{
|
||||||
private const MATCH_MODE_EXACT = 'exact';
|
|
||||||
private const MATCH_MODE_PREFIX = 'prefix';
|
private const MATCH_MODE_PREFIX = 'prefix';
|
||||||
|
|
||||||
|
/** @var list<string> */
|
||||||
private array $requiredRoomCodes;
|
private array $requiredRoomCodes;
|
||||||
private string $matchMode;
|
private string $matchMode;
|
||||||
|
|
||||||
|
|||||||
@@ -161,6 +161,7 @@ class ServiceSubTypeCondition implements FieldConditionInterface
|
|||||||
/**
|
/**
|
||||||
* Retrieves service from form data or participant data.
|
* Retrieves service from form data or participant data.
|
||||||
*/
|
*/
|
||||||
|
/** @param array<string, mixed> $formData */
|
||||||
private function getService(array $formData, int $participantIndex, BookingDto $bookingDto): ?Service
|
private function getService(array $formData, int $participantIndex, BookingDto $bookingDto): ?Service
|
||||||
{
|
{
|
||||||
// First check participant-specific form data
|
// First check participant-specific form data
|
||||||
@@ -185,6 +186,7 @@ class ServiceSubTypeCondition implements FieldConditionInterface
|
|||||||
/**
|
/**
|
||||||
* Checks if sub-type is in the expected array.
|
* Checks if sub-type is in the expected array.
|
||||||
*/
|
*/
|
||||||
|
/** @param string|list<string> $expectedSubTypes */
|
||||||
private function isSubTypeIn(string $actualSubType, string|array $expectedSubTypes): bool
|
private function isSubTypeIn(string $actualSubType, string|array $expectedSubTypes): bool
|
||||||
{
|
{
|
||||||
if (is_string($expectedSubTypes)) {
|
if (is_string($expectedSubTypes)) {
|
||||||
@@ -214,6 +216,7 @@ class ServiceSubTypeCondition implements FieldConditionInterface
|
|||||||
/**
|
/**
|
||||||
* Validates expected sub-type based on operator requirements.
|
* Validates expected sub-type based on operator requirements.
|
||||||
*/
|
*/
|
||||||
|
/** @param string|list<string> $expectedSubType */
|
||||||
private function validateExpectedSubType(string $operator, string|array $expectedSubType): void
|
private function validateExpectedSubType(string $operator, string|array $expectedSubType): void
|
||||||
{
|
{
|
||||||
if (in_array($operator, [self::OPERATOR_IN, self::OPERATOR_NOT_IN], true) && !is_array($expectedSubType)) {
|
if (in_array($operator, [self::OPERATOR_IN, self::OPERATOR_NOT_IN], true) && !is_array($expectedSubType)) {
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Form\Service\Condition;
|
namespace App\Form\Service\Condition;
|
||||||
|
|
||||||
use App\BusProNet\Model\Service;
|
|
||||||
use App\Form\Model\BookingDto;
|
use App\Form\Model\BookingDto;
|
||||||
use App\Form\Service\Contract\FieldConditionInterface;
|
use App\Form\Service\Contract\FieldConditionInterface;
|
||||||
|
|
||||||
@@ -39,7 +38,7 @@ class SkiPassSelectionCondition implements FieldConditionInterface
|
|||||||
// First check submitted form data for skipass selection
|
// First check submitted form data for skipass selection
|
||||||
if (isset($formData['participants'][$participantIndex]['skiPass'])) {
|
if (isset($formData['participants'][$participantIndex]['skiPass'])) {
|
||||||
$selectedSkiPass = $formData['participants'][$participantIndex]['skiPass'];
|
$selectedSkiPass = $formData['participants'][$participantIndex]['skiPass'];
|
||||||
if (null !== $selectedSkiPass && '' !== $selectedSkiPass) {
|
if ('' !== $selectedSkiPass) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -47,10 +46,7 @@ class SkiPassSelectionCondition implements FieldConditionInterface
|
|||||||
// Then check participant DTO data for existing skipass selection
|
// Then check participant DTO data for existing skipass selection
|
||||||
$participant = $bookingDto->getParticipant($participantIndex);
|
$participant = $bookingDto->getParticipant($participantIndex);
|
||||||
if (null !== $participant && null !== $participant->skiPass) {
|
if (null !== $participant && null !== $participant->skiPass) {
|
||||||
// Check if skipass is actually a Service object
|
return true;
|
||||||
if ($participant->skiPass instanceof Service) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -41,10 +41,10 @@ interface FieldOptionsProviderInterface
|
|||||||
* used when building the form field. These options are merged with any
|
* used when building the form field. These options are merged with any
|
||||||
* static options defined in the form type.
|
* static options defined in the form type.
|
||||||
*
|
*
|
||||||
* @param string $fieldName The name of the field to configure
|
* @param string $fieldName The name of the field to configure
|
||||||
* @param BookingDto $bookingDto The current booking data for context (create or edit)
|
* @param BookingDto $bookingDto The current booking data for context (create or edit)
|
||||||
* @param int $participantIndex The index of the participant being configured
|
* @param int $participantIndex The index of the participant being configured
|
||||||
* @param array $options Additional options to customize field behavior
|
* @param array<string, mixed> $options Additional options to customize field behavior
|
||||||
*
|
*
|
||||||
* @return array<string, mixed> Symfony form field options, or empty array if field not supported
|
* @return array<string, mixed> Symfony form field options, or empty array if field not supported
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
|||||||
namespace App\Form\Service\Contract;
|
namespace App\Form\Service\Contract;
|
||||||
|
|
||||||
use App\Form\Model\BookingDto;
|
use App\Form\Model\BookingDto;
|
||||||
|
use Symfony\Component\Form\FormInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for providing dynamic field state based on conditions.
|
* Interface for providing dynamic field state based on conditions.
|
||||||
@@ -30,6 +31,15 @@ use App\Form\Model\BookingDto;
|
|||||||
*/
|
*/
|
||||||
interface FieldStateProviderInterface
|
interface FieldStateProviderInterface
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Gets the BookingDto from the root of the form tree.
|
||||||
|
*
|
||||||
|
* @param FormInterface<mixed> $form The form to start traversing from
|
||||||
|
*
|
||||||
|
* @return BookingDto|null The booking DTO or null if not found
|
||||||
|
*/
|
||||||
|
public function getBookingDtoFromForm(FormInterface $form): ?BookingDto;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines whether a field should be included in the form at all.
|
* Determines whether a field should be included in the form at all.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -131,6 +131,10 @@ class ParticipantAdditionalServicesFieldHandler extends AbstractParticipantField
|
|||||||
$participant->additionalServices = $validSelections;
|
$participant->additionalServices = $validSelections;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<int, Service> $availableServices
|
||||||
|
* @param list<Service> $validSelections
|
||||||
|
*/
|
||||||
private function updateAutoBookOptOutServices(
|
private function updateAutoBookOptOutServices(
|
||||||
ParticipantDto $participant,
|
ParticipantDto $participant,
|
||||||
array $availableServices,
|
array $availableServices,
|
||||||
@@ -140,10 +144,6 @@ class ParticipantAdditionalServicesFieldHandler extends AbstractParticipantField
|
|||||||
): void {
|
): void {
|
||||||
$currentlySelectedAutoBookIds = [];
|
$currentlySelectedAutoBookIds = [];
|
||||||
foreach ($participant->additionalServices as $selectedService) {
|
foreach ($participant->additionalServices as $selectedService) {
|
||||||
if (false === $selectedService instanceof Service) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (null === $selectedService->id || true === $selectedService->mandatory || false === $selectedService->autoBook) {
|
if (null === $selectedService->id || true === $selectedService->mandatory || false === $selectedService->autoBook) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -186,12 +186,12 @@ class ParticipantAdditionalServicesFieldHandler extends AbstractParticipantField
|
|||||||
* and the participant's age constraints. Services that are no longer available
|
* and the participant's age constraints. Services that are no longer available
|
||||||
* or appropriate for the participant's age are filtered out.
|
* or appropriate for the participant's age are filtered out.
|
||||||
*
|
*
|
||||||
* @param array $selectedServices List of currently selected services
|
* @param list<mixed> $selectedServices List of currently selected services
|
||||||
* @param array $availableServices List of all available additional services
|
* @param array<int, Service> $availableServices List of all available additional services
|
||||||
* @param BookingDto $bookingDto The booking DTO for context
|
* @param BookingDto $bookingDto The booking DTO for context
|
||||||
* @param int $participantIndex The participant index for age evaluation
|
* @param int $participantIndex The participant index for age evaluation
|
||||||
*
|
*
|
||||||
* @return array Filtered array of valid service selections
|
* @return list<Service> Filtered array of valid service selections
|
||||||
*/
|
*/
|
||||||
private function filterValidServiceSelections(
|
private function filterValidServiceSelections(
|
||||||
array $selectedServices,
|
array $selectedServices,
|
||||||
@@ -220,10 +220,10 @@ class ParticipantAdditionalServicesFieldHandler extends AbstractParticipantField
|
|||||||
* This method checks if a selected service exists in the available services
|
* This method checks if a selected service exists in the available services
|
||||||
* and meets the age constraints for the current participant.
|
* and meets the age constraints for the current participant.
|
||||||
*
|
*
|
||||||
* @param mixed $selectedService The selected service to validate
|
* @param mixed $selectedService The selected service to validate
|
||||||
* @param array $availableServices Array of available services
|
* @param array<int, Service> $availableServices Array of available services
|
||||||
* @param BookingDto $bookingDto The booking DTO for context
|
* @param BookingDto $bookingDto The booking DTO for context
|
||||||
* @param int $participantIndex The participant index for age evaluation
|
* @param int $participantIndex The participant index for age evaluation
|
||||||
*
|
*
|
||||||
* @return bool True if the service is valid for the participant, false otherwise
|
* @return bool True if the service is valid for the participant, false otherwise
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -89,6 +89,10 @@ class ParticipantBoardFieldHandler extends AbstractParticipantFieldHandler
|
|||||||
$participant->board = $validSelections;
|
$participant->board = $validSelections;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<int, Service> $availableBoard
|
||||||
|
* @param list<Service> $validSelections
|
||||||
|
*/
|
||||||
private function updateAutoBookOptOutBoard(
|
private function updateAutoBookOptOutBoard(
|
||||||
ParticipantDto $participant,
|
ParticipantDto $participant,
|
||||||
array $availableBoard,
|
array $availableBoard,
|
||||||
@@ -98,10 +102,6 @@ class ParticipantBoardFieldHandler extends AbstractParticipantFieldHandler
|
|||||||
): void {
|
): void {
|
||||||
$currentlySelectedAutoBookIds = [];
|
$currentlySelectedAutoBookIds = [];
|
||||||
foreach ($participant->board as $selectedService) {
|
foreach ($participant->board as $selectedService) {
|
||||||
if (false === $selectedService instanceof Service) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (null === $selectedService->id || true === $selectedService->mandatory || false === $selectedService->autoBook) {
|
if (null === $selectedService->id || true === $selectedService->mandatory || false === $selectedService->autoBook) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -135,6 +135,12 @@ class ParticipantBoardFieldHandler extends AbstractParticipantFieldHandler
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param list<mixed> $selectedServices
|
||||||
|
* @param array<int, Service> $availableServices
|
||||||
|
*
|
||||||
|
* @return list<Service>
|
||||||
|
*/
|
||||||
private function filterValidServiceSelections(
|
private function filterValidServiceSelections(
|
||||||
array $selectedServices,
|
array $selectedServices,
|
||||||
array $availableServices,
|
array $availableServices,
|
||||||
@@ -156,6 +162,9 @@ class ParticipantBoardFieldHandler extends AbstractParticipantFieldHandler
|
|||||||
return $validSelections;
|
return $validSelections;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<int, Service> $availableServices
|
||||||
|
*/
|
||||||
private function isServiceValidForParticipant(
|
private function isServiceValidForParticipant(
|
||||||
mixed $selectedService,
|
mixed $selectedService,
|
||||||
array $availableServices,
|
array $availableServices,
|
||||||
|
|||||||
@@ -114,12 +114,12 @@ class ParticipantCoursesFieldHandler extends AbstractParticipantFieldHandler
|
|||||||
/**
|
/**
|
||||||
* Filters course selections to keep only those valid for the participant's age.
|
* Filters course selections to keep only those valid for the participant's age.
|
||||||
*
|
*
|
||||||
* @param array $selectedServices List of currently selected courses
|
* @param list<mixed> $selectedServices List of currently selected courses
|
||||||
* @param array $availableServices List of all available courses
|
* @param array<int, Service> $availableServices List of all available courses
|
||||||
* @param BookingDto $bookingDto The booking DTO for context
|
* @param BookingDto $bookingDto The booking DTO for context
|
||||||
* @param int $participantIndex The participant index for age evaluation
|
* @param int $participantIndex The participant index for age evaluation
|
||||||
*
|
*
|
||||||
* @return array Filtered array of valid course selections
|
* @return list<Service> Filtered array of valid course selections
|
||||||
*/
|
*/
|
||||||
private function filterValidServiceSelections(
|
private function filterValidServiceSelections(
|
||||||
array $selectedServices,
|
array $selectedServices,
|
||||||
@@ -145,10 +145,10 @@ class ParticipantCoursesFieldHandler extends AbstractParticipantFieldHandler
|
|||||||
/**
|
/**
|
||||||
* Validates if a selected course is still valid for the participant.
|
* Validates if a selected course is still valid for the participant.
|
||||||
*
|
*
|
||||||
* @param mixed $selectedService The selected course to validate
|
* @param mixed $selectedService The selected course to validate
|
||||||
* @param array $availableServices Array of available courses
|
* @param array<int, Service> $availableServices Array of available courses
|
||||||
* @param BookingDto $bookingDto The booking DTO for context
|
* @param BookingDto $bookingDto The booking DTO for context
|
||||||
* @param int $participantIndex The participant index for age evaluation
|
* @param int $participantIndex The participant index for age evaluation
|
||||||
*
|
*
|
||||||
* @return bool True if the course is valid for the participant, false otherwise
|
* @return bool True if the course is valid for the participant, false otherwise
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -100,9 +100,9 @@ class ParticipantDateOfBirthFieldHandler extends AbstractParticipantFieldHandler
|
|||||||
if (true === is_array($value)) {
|
if (true === is_array($value)) {
|
||||||
// Check if all required fields are present and valid
|
// Check if all required fields are present and valid
|
||||||
if (false === isset($value['year'], $value['month'], $value['day'])
|
if (false === isset($value['year'], $value['month'], $value['day'])
|
||||||
|| '' === trim((string) ($value['year'] ?? ''))
|
|| '' === trim((string) $value['year'])
|
||||||
|| '' === trim((string) ($value['month'] ?? ''))
|
|| '' === trim((string) $value['month'])
|
||||||
|| '' === trim((string) ($value['day'] ?? ''))
|
|| '' === trim((string) $value['day'])
|
||||||
) {
|
) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -511,7 +511,7 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
|
|||||||
return [
|
return [
|
||||||
'label' => 'Hinfahrt',
|
'label' => 'Hinfahrt',
|
||||||
'choices' => $choices,
|
'choices' => $choices,
|
||||||
'choice_label' => fn (Service $service) => $service?->label,
|
'choice_label' => fn (Service $service) => $service->label,
|
||||||
'choice_value' => 'id',
|
'choice_value' => 'id',
|
||||||
'expanded' => true,
|
'expanded' => true,
|
||||||
'multiple' => false,
|
'multiple' => false,
|
||||||
@@ -551,7 +551,7 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
|
|||||||
return [
|
return [
|
||||||
'label' => 'Rückfahrt',
|
'label' => 'Rückfahrt',
|
||||||
'choices' => $choices,
|
'choices' => $choices,
|
||||||
'choice_label' => fn (Service $service) => $service?->label,
|
'choice_label' => fn (Service $service) => $service->label,
|
||||||
'choice_value' => 'id',
|
'choice_value' => 'id',
|
||||||
'expanded' => true,
|
'expanded' => true,
|
||||||
'multiple' => false,
|
'multiple' => false,
|
||||||
@@ -622,7 +622,7 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
|
|||||||
$hasOutboundBus = null !== $participant?->transportationOutbound
|
$hasOutboundBus = null !== $participant?->transportationOutbound
|
||||||
&& DirectionMapper::SUBTYPE_BUS_API === $participant->transportationOutbound->subType;
|
&& DirectionMapper::SUBTYPE_BUS_API === $participant->transportationOutbound->subType;
|
||||||
|
|
||||||
if ($hasOutboundBus && false === ($participant->differentDropOff ?? false)) {
|
if ($hasOutboundBus && false === $participant->differentDropOff) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -806,11 +806,11 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
|
|||||||
* as the participant's selected skipass. This ensures rental equipment
|
* as the participant's selected skipass. This ensures rental equipment
|
||||||
* is only available for the exact duration of the skipass.
|
* is only available for the exact duration of the skipass.
|
||||||
*
|
*
|
||||||
* @param array $rentals Array of rental Service objects to filter
|
* @param array<int, Service> $rentals Array of rental Service objects to filter
|
||||||
* @param BookingDto $bookingDto The booking DTO containing participant data
|
* @param BookingDto $bookingDto The booking DTO containing participant data
|
||||||
* @param int $participantIndex Index of the participant to evaluate
|
* @param int $participantIndex Index of the participant to evaluate
|
||||||
*
|
*
|
||||||
* @return array Filtered array of rentals matching skipass duration
|
* @return array<int, Service> Filtered array of rentals matching skipass duration
|
||||||
*/
|
*/
|
||||||
private function filterRentalsBySkiPassDuration(array $rentals, BookingDto $bookingDto, int $participantIndex): array
|
private function filterRentalsBySkiPassDuration(array $rentals, BookingDto $bookingDto, int $participantIndex): array
|
||||||
{
|
{
|
||||||
@@ -914,8 +914,8 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
|
|||||||
/**
|
/**
|
||||||
* Checks if a service array contains a service with the given ID.
|
* Checks if a service array contains a service with the given ID.
|
||||||
*
|
*
|
||||||
* @param array $services Array of Service objects
|
* @param array<int, Service> $services Array of Service objects
|
||||||
* @param int $serviceId Service ID to search for
|
* @param int $serviceId Service ID to search for
|
||||||
*
|
*
|
||||||
* @return bool True if the service is found in the array
|
* @return bool True if the service is found in the array
|
||||||
*/
|
*/
|
||||||
@@ -937,11 +937,11 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
|
|||||||
* If no age evaluator is configured or participant has no birth date,
|
* If no age evaluator is configured or participant has no birth date,
|
||||||
* returns empty array to be handled by field visibility conditions.
|
* returns empty array to be handled by field visibility conditions.
|
||||||
*
|
*
|
||||||
* @param array $services Array of Service objects to filter
|
* @param array<int, Service> $services Array of Service objects to filter
|
||||||
* @param BookingDto $bookingDto The booking DTO containing participant data
|
* @param BookingDto $bookingDto The booking DTO containing participant data
|
||||||
* @param int $participantIndex Index of the participant to evaluate
|
* @param int $participantIndex Index of the participant to evaluate
|
||||||
*
|
*
|
||||||
* @return array Filtered array of available services
|
* @return array<int, Service> Filtered array of available services
|
||||||
*/
|
*/
|
||||||
private function filterServicesByAgeConstraints(array $services, BookingDto $bookingDto, int $participantIndex): array
|
private function filterServicesByAgeConstraints(array $services, BookingDto $bookingDto, int $participantIndex): array
|
||||||
{
|
{
|
||||||
@@ -1112,6 +1112,7 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
|
|||||||
/**
|
/**
|
||||||
* Gets the rental insurance description for help text.
|
* Gets the rental insurance description for help text.
|
||||||
*/
|
*/
|
||||||
|
/** @param list<Service> $rentalInsuranceManagers */
|
||||||
private function getRentalInsuranceDescription(array $rentalInsuranceManagers): ?string
|
private function getRentalInsuranceDescription(array $rentalInsuranceManagers): ?string
|
||||||
{
|
{
|
||||||
if (empty($rentalInsuranceManagers)) {
|
if (empty($rentalInsuranceManagers)) {
|
||||||
@@ -1131,7 +1132,7 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
|
|||||||
* @param BookingDto $bookingDto The booking DTO containing travel and participant data
|
* @param BookingDto $bookingDto The booking DTO containing travel and participant data
|
||||||
* @param int $participantIndex The index of the participant to get eligible insurances for
|
* @param int $participantIndex The index of the participant to get eligible insurances for
|
||||||
*
|
*
|
||||||
* @return array Array of eligible insurance objects filtered by age, family status, and other constraints
|
* @return list<Insurance> Array of eligible insurance objects filtered by age, family status, and other constraints
|
||||||
*/
|
*/
|
||||||
private function getEligibleInsurances(BookingDto $bookingDto, int $participantIndex): array
|
private function getEligibleInsurances(BookingDto $bookingDto, int $participantIndex): array
|
||||||
{
|
{
|
||||||
@@ -1180,11 +1181,11 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider
|
|||||||
* got the discount to change their mind (e.g., select bus instead), making the discount available
|
* got the discount to change their mind (e.g., select bus instead), making the discount available
|
||||||
* for others in the same booking session.
|
* for others in the same booking session.
|
||||||
*
|
*
|
||||||
* @param array $services Transportation services from Travel model
|
* @param array<int, Service> $services Transportation services from Travel model
|
||||||
* @param BookingDto $bookingDto Current booking DTO with participant selections
|
* @param BookingDto $bookingDto Current booking DTO with participant selections
|
||||||
* @param int $participantIndex Current participant being processed
|
* @param int $participantIndex Current participant being processed
|
||||||
*
|
*
|
||||||
* @return array Filtered transportation choices with smart PKW option selection
|
* @return array<int, Service> Filtered transportation choices with smart PKW option selection
|
||||||
*/
|
*/
|
||||||
private function filterTransportationChoices(array $services, BookingDto $bookingDto, int $participantIndex): array
|
private function filterTransportationChoices(array $services, BookingDto $bookingDto, int $participantIndex): array
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -128,6 +128,10 @@ class ParticipantRentalsFieldHandler extends AbstractParticipantFieldHandler
|
|||||||
$participant->rentals = $validSelections;
|
$participant->rentals = $validSelections;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<int, Service> $availableRentals
|
||||||
|
* @param list<Service> $validSelections
|
||||||
|
*/
|
||||||
private function updateAutoBookOptOutRentals(
|
private function updateAutoBookOptOutRentals(
|
||||||
ParticipantDto $participant,
|
ParticipantDto $participant,
|
||||||
array $availableRentals,
|
array $availableRentals,
|
||||||
@@ -137,10 +141,6 @@ class ParticipantRentalsFieldHandler extends AbstractParticipantFieldHandler
|
|||||||
): void {
|
): void {
|
||||||
$currentlySelectedAutoBookIds = [];
|
$currentlySelectedAutoBookIds = [];
|
||||||
foreach ($participant->rentals as $selectedService) {
|
foreach ($participant->rentals as $selectedService) {
|
||||||
if (false === $selectedService instanceof Service) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (null === $selectedService->id || true === $selectedService->mandatory || false === $selectedService->autoBook) {
|
if (null === $selectedService->id || true === $selectedService->mandatory || false === $selectedService->autoBook) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -174,6 +174,12 @@ class ParticipantRentalsFieldHandler extends AbstractParticipantFieldHandler
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param list<mixed> $selectedServices
|
||||||
|
* @param array<int, Service> $availableServices
|
||||||
|
*
|
||||||
|
* @return list<Service>
|
||||||
|
*/
|
||||||
private function filterValidServiceSelections(
|
private function filterValidServiceSelections(
|
||||||
array $selectedServices,
|
array $selectedServices,
|
||||||
array $availableServices,
|
array $availableServices,
|
||||||
@@ -195,6 +201,9 @@ class ParticipantRentalsFieldHandler extends AbstractParticipantFieldHandler
|
|||||||
return $validSelections;
|
return $validSelections;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<int, Service> $availableServices
|
||||||
|
*/
|
||||||
private function isServiceValidForParticipant(
|
private function isServiceValidForParticipant(
|
||||||
mixed $selectedService,
|
mixed $selectedService,
|
||||||
array $availableServices,
|
array $availableServices,
|
||||||
@@ -222,12 +231,12 @@ class ParticipantRentalsFieldHandler extends AbstractParticipantFieldHandler
|
|||||||
* - rental.dateFrom === skipass.dateFrom
|
* - rental.dateFrom === skipass.dateFrom
|
||||||
* - rental.dateTo === skipass.dateTo
|
* - rental.dateTo === skipass.dateTo
|
||||||
*
|
*
|
||||||
* @param array $rentals All available rental services
|
* @param array<int, Service> $rentals All available rental services
|
||||||
* @param ParticipantDto $participant The participant with skipass selection
|
* @param ParticipantDto $participant The participant with skipass selection
|
||||||
*
|
*
|
||||||
* @return array Filtered rentals matching the skipass duration
|
* @return array<int, Service> Filtered rentals matching the skipass duration
|
||||||
*/
|
*/
|
||||||
private function filterRentalsBySkiPassDuration(array $rentals, $participant): array
|
private function filterRentalsBySkiPassDuration(array $rentals, ParticipantDto $participant): array
|
||||||
{
|
{
|
||||||
$selectedSkiPass = $participant->skiPass;
|
$selectedSkiPass = $participant->skiPass;
|
||||||
|
|
||||||
|
|||||||
@@ -129,6 +129,7 @@ class ParticipantSkiPassFieldHandler extends AbstractParticipantFieldHandler
|
|||||||
$participant->skiPass = $validSelection;
|
$participant->skiPass = $validSelection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param array<int, Service> $availableSkipasses */
|
||||||
private function getSelectedAutoBookSkiPassId(
|
private function getSelectedAutoBookSkiPassId(
|
||||||
ParticipantDto $participant,
|
ParticipantDto $participant,
|
||||||
array $availableSkipasses,
|
array $availableSkipasses,
|
||||||
@@ -184,10 +185,10 @@ class ParticipantSkiPassFieldHandler extends AbstractParticipantFieldHandler
|
|||||||
* This method checks both age constraints (via birth year ranges) and
|
* This method checks both age constraints (via birth year ranges) and
|
||||||
* date constraints (skipass dates must be within travel dates).
|
* date constraints (skipass dates must be within travel dates).
|
||||||
*
|
*
|
||||||
* @param mixed $selectedService The selected skipass to validate
|
* @param mixed $selectedService The selected skipass to validate
|
||||||
* @param array $availableServices Array of available skipasses
|
* @param array<int, Service> $availableServices Array of available skipasses
|
||||||
* @param BookingDto $bookingDto The booking DTO for context
|
* @param BookingDto $bookingDto The booking DTO for context
|
||||||
* @param int $participantIndex The participant index for age evaluation
|
* @param int $participantIndex The participant index for age evaluation
|
||||||
*
|
*
|
||||||
* @return bool True if the skipass is valid for the participant, false otherwise
|
* @return bool True if the skipass is valid for the participant, false otherwise
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -107,10 +107,10 @@ class ParticipantVegFieldHandler extends AbstractParticipantFieldHandler
|
|||||||
*
|
*
|
||||||
* This method checks age constraints if they exist for the service.
|
* This method checks age constraints if they exist for the service.
|
||||||
*
|
*
|
||||||
* @param mixed $selectedService The selected veg option to validate
|
* @param mixed $selectedService The selected veg option to validate
|
||||||
* @param array $availableServices Array of available veg options
|
* @param array<int, Service> $availableServices Array of available veg options
|
||||||
* @param BookingDto $bookingDto The booking DTO for context
|
* @param BookingDto $bookingDto The booking DTO for context
|
||||||
* @param int $participantIndex The participant index for age evaluation
|
* @param int $participantIndex The participant index for age evaluation
|
||||||
*
|
*
|
||||||
* @return bool True if the option is valid for the participant, false otherwise
|
* @return bool True if the option is valid for the participant, false otherwise
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ trait FormTraversalTrait
|
|||||||
* and extracts the BookingDto data. This is used as a fallback when
|
* and extracts the BookingDto data. This is used as a fallback when
|
||||||
* BookingDto is not passed explicitly via form options.
|
* BookingDto is not passed explicitly via form options.
|
||||||
*
|
*
|
||||||
* @param FormInterface $form The form to start traversing from
|
* @param FormInterface<mixed> $form The form to start traversing from
|
||||||
*
|
*
|
||||||
* @return BookingDto|null The booking DTO or null if not found
|
* @return BookingDto|null The booking DTO or null if not found
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use Symfony\Component\Form\FormInterface;
|
|||||||
use Symfony\Component\Form\FormView;
|
use Symfony\Component\Form\FormView;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
/** @extends AbstractType<mixed> */
|
||||||
class StepSelectChoiceType extends AbstractType
|
class StepSelectChoiceType extends AbstractType
|
||||||
{
|
{
|
||||||
public function getParent(): string
|
public function getParent(): string
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Service;
|
namespace App\Service;
|
||||||
|
|
||||||
|
use App\BusProNet\Model\Service;
|
||||||
use App\Form\Model\BookingDto;
|
use App\Form\Model\BookingDto;
|
||||||
use App\Form\Model\ParticipantDto;
|
use App\Form\Model\ParticipantDto;
|
||||||
|
|
||||||
@@ -36,7 +37,7 @@ class BookingChangeTracker
|
|||||||
*
|
*
|
||||||
* @param BookingDto $bookingDto The booking DTO to extract data from
|
* @param BookingDto $bookingDto The booking DTO to extract data from
|
||||||
*
|
*
|
||||||
* @return array Serializable array of all user-editable data
|
* @return array<string, mixed> Serializable array of all user-editable data
|
||||||
*/
|
*/
|
||||||
public function extractUserData(BookingDto $bookingDto): array
|
public function extractUserData(BookingDto $bookingDto): array
|
||||||
{
|
{
|
||||||
@@ -61,7 +62,7 @@ class BookingChangeTracker
|
|||||||
*
|
*
|
||||||
* @param ParticipantDto $participant The participant to extract data from
|
* @param ParticipantDto $participant The participant to extract data from
|
||||||
*
|
*
|
||||||
* @return array Serializable array of participant data
|
* @return array<string, mixed> Serializable array of participant data
|
||||||
*/
|
*/
|
||||||
private function extractParticipantData(ParticipantDto $participant): array
|
private function extractParticipantData(ParticipantDto $participant): array
|
||||||
{
|
{
|
||||||
@@ -120,9 +121,9 @@ class BookingChangeTracker
|
|||||||
* This ensures that associative arrays, indexed arrays, and different orders
|
* This ensures that associative arrays, indexed arrays, and different orders
|
||||||
* all produce the same fingerprint as long as the same services are present.
|
* all produce the same fingerprint as long as the same services are present.
|
||||||
*
|
*
|
||||||
* @param array $services Array of Service objects
|
* @param list<Service> $services Array of Service objects
|
||||||
*
|
*
|
||||||
* @return array Sorted array of service IDs
|
* @return list<int|null> Sorted array of service IDs
|
||||||
*/
|
*/
|
||||||
private function normalizeServiceArray(array $services): array
|
private function normalizeServiceArray(array $services): array
|
||||||
{
|
{
|
||||||
@@ -130,7 +131,7 @@ class BookingChangeTracker
|
|||||||
$ids = array_unique($ids);
|
$ids = array_unique($ids);
|
||||||
sort($ids);
|
sort($ids);
|
||||||
|
|
||||||
return array_values($ids);
|
return $ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -95,8 +95,8 @@ class BookingConfigurator
|
|||||||
* Converts a Room model into a RoomSelectionDto with the specified quantity
|
* Converts a Room model into a RoomSelectionDto with the specified quantity
|
||||||
* selection. Used during booking initialization to create selectable room options.
|
* selection. Used during booking initialization to create selectable room options.
|
||||||
*
|
*
|
||||||
* @param Room $room The room model to convert
|
* @param Room $room The room model to convert
|
||||||
* @param array $roomsIdsAndQuantities Array of room ID to quantity mappings
|
* @param array<int|string, int> $roomsIdsAndQuantities Array of room ID to quantity mappings
|
||||||
*
|
*
|
||||||
* @return RoomSelectionDto The room selection DTO
|
* @return RoomSelectionDto The room selection DTO
|
||||||
*/
|
*/
|
||||||
@@ -249,6 +249,7 @@ class BookingConfigurator
|
|||||||
return $this->participantEligibilityService->isParticipantEligible($bookingDto, $participantIndex);
|
return $this->participantEligibilityService->isParticipantEligible($bookingDto, $participantIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param array<int, Service> $mandatoryAdditionalServices */
|
||||||
private function preselectMandatoryAdditionalServices(
|
private function preselectMandatoryAdditionalServices(
|
||||||
ParticipantDto $participant,
|
ParticipantDto $participant,
|
||||||
array $mandatoryAdditionalServices,
|
array $mandatoryAdditionalServices,
|
||||||
@@ -266,6 +267,7 @@ class BookingConfigurator
|
|||||||
$this->appendAdditionalServices($participant, $eligibleServices, false);
|
$this->appendAdditionalServices($participant, $eligibleServices, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param array<int, Service> $autoBookAdditionalServices */
|
||||||
private function preselectAutoBookAdditionalServices(
|
private function preselectAutoBookAdditionalServices(
|
||||||
ParticipantDto $participant,
|
ParticipantDto $participant,
|
||||||
array $autoBookAdditionalServices,
|
array $autoBookAdditionalServices,
|
||||||
@@ -283,6 +285,7 @@ class BookingConfigurator
|
|||||||
$this->appendAdditionalServices($participant, $eligibleServices, true);
|
$this->appendAdditionalServices($participant, $eligibleServices, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param array<int, Service> $mandatorySkiPassServices */
|
||||||
private function preselectMandatorySkiPass(
|
private function preselectMandatorySkiPass(
|
||||||
ParticipantDto $participant,
|
ParticipantDto $participant,
|
||||||
array $mandatorySkiPassServices,
|
array $mandatorySkiPassServices,
|
||||||
@@ -308,6 +311,7 @@ class BookingConfigurator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param array<int, Service> $autoBookSkiPassServices */
|
||||||
private function preselectAutoBookSkiPass(
|
private function preselectAutoBookSkiPass(
|
||||||
ParticipantDto $participant,
|
ParticipantDto $participant,
|
||||||
array $autoBookSkiPassServices,
|
array $autoBookSkiPassServices,
|
||||||
@@ -338,6 +342,7 @@ class BookingConfigurator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param array<int, Service> $mandatoryBoardServices */
|
||||||
private function preselectMandatoryBoardServices(
|
private function preselectMandatoryBoardServices(
|
||||||
ParticipantDto $participant,
|
ParticipantDto $participant,
|
||||||
array $mandatoryBoardServices,
|
array $mandatoryBoardServices,
|
||||||
@@ -355,6 +360,7 @@ class BookingConfigurator
|
|||||||
$this->appendBoardServices($participant, $eligibleServices, false);
|
$this->appendBoardServices($participant, $eligibleServices, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param array<int, Service> $autoBookBoardServices */
|
||||||
private function preselectAutoBookBoardServices(
|
private function preselectAutoBookBoardServices(
|
||||||
ParticipantDto $participant,
|
ParticipantDto $participant,
|
||||||
array $autoBookBoardServices,
|
array $autoBookBoardServices,
|
||||||
@@ -372,6 +378,7 @@ class BookingConfigurator
|
|||||||
$this->appendBoardServices($participant, $eligibleServices, true);
|
$this->appendBoardServices($participant, $eligibleServices, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param array<int, Service> $mandatoryRentalServices */
|
||||||
private function preselectMandatoryRentals(
|
private function preselectMandatoryRentals(
|
||||||
ParticipantDto $participant,
|
ParticipantDto $participant,
|
||||||
array $mandatoryRentalServices,
|
array $mandatoryRentalServices,
|
||||||
@@ -395,6 +402,7 @@ class BookingConfigurator
|
|||||||
$this->appendRentalServices($participant, $matchingDurationServices, false);
|
$this->appendRentalServices($participant, $matchingDurationServices, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param array<int, Service> $autoBookRentalServices */
|
||||||
private function preselectAutoBookRentals(
|
private function preselectAutoBookRentals(
|
||||||
ParticipantDto $participant,
|
ParticipantDto $participant,
|
||||||
array $autoBookRentalServices,
|
array $autoBookRentalServices,
|
||||||
@@ -445,7 +453,7 @@ class BookingConfigurator
|
|||||||
*/
|
*/
|
||||||
private function appendAdditionalServices(ParticipantDto $participant, array $services, bool $respectOptOut): void
|
private function appendAdditionalServices(ParticipantDto $participant, array $services, bool $respectOptOut): void
|
||||||
{
|
{
|
||||||
$currentSelections = $participant->additionalServices ?? [];
|
$currentSelections = $participant->additionalServices;
|
||||||
$currentServiceIds = array_map(static fn (Service $service): ?int => $service->id, $currentSelections);
|
$currentServiceIds = array_map(static fn (Service $service): ?int => $service->id, $currentSelections);
|
||||||
|
|
||||||
foreach ($services as $service) {
|
foreach ($services as $service) {
|
||||||
@@ -469,7 +477,7 @@ class BookingConfigurator
|
|||||||
*/
|
*/
|
||||||
private function appendBoardServices(ParticipantDto $participant, array $services, bool $respectOptOut): void
|
private function appendBoardServices(ParticipantDto $participant, array $services, bool $respectOptOut): void
|
||||||
{
|
{
|
||||||
$currentSelections = $participant->board ?? [];
|
$currentSelections = $participant->board;
|
||||||
$currentServiceIds = array_map(static fn (Service $service): ?int => $service->id, $currentSelections);
|
$currentServiceIds = array_map(static fn (Service $service): ?int => $service->id, $currentSelections);
|
||||||
|
|
||||||
foreach ($services as $service) {
|
foreach ($services as $service) {
|
||||||
@@ -493,7 +501,7 @@ class BookingConfigurator
|
|||||||
*/
|
*/
|
||||||
private function appendRentalServices(ParticipantDto $participant, array $services, bool $respectOptOut): void
|
private function appendRentalServices(ParticipantDto $participant, array $services, bool $respectOptOut): void
|
||||||
{
|
{
|
||||||
$currentSelections = $participant->rentals ?? [];
|
$currentSelections = $participant->rentals;
|
||||||
$currentServiceIds = array_map(static fn (Service $service): ?int => $service->id, $currentSelections);
|
$currentServiceIds = array_map(static fn (Service $service): ?int => $service->id, $currentSelections);
|
||||||
|
|
||||||
foreach ($services as $service) {
|
foreach ($services as $service) {
|
||||||
|
|||||||
@@ -178,6 +178,7 @@ class BookingEditDraftManager
|
|||||||
/**
|
/**
|
||||||
* Applies bank account data from draft to BookingDto.
|
* Applies bank account data from draft to BookingDto.
|
||||||
*/
|
*/
|
||||||
|
/** @param array<string, mixed> $bankAccountData */
|
||||||
private function applyBankAccountData(BookingDto $dto, array $bankAccountData): void
|
private function applyBankAccountData(BookingDto $dto, array $bankAccountData): void
|
||||||
{
|
{
|
||||||
$iban = $bankAccountData['iban'] ?? null;
|
$iban = $bankAccountData['iban'] ?? null;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace App\Service;
|
namespace App\Service;
|
||||||
|
|
||||||
|
use App\BusProNet\Model\Service;
|
||||||
use App\BusProNet\Model\Travel;
|
use App\BusProNet\Model\Travel;
|
||||||
use App\Form\Model\BookingDto;
|
use App\Form\Model\BookingDto;
|
||||||
use App\Form\Model\ParticipantDto;
|
use App\Form\Model\ParticipantDto;
|
||||||
@@ -21,6 +22,7 @@ use App\Form\Model\ParticipantDto;
|
|||||||
*/
|
*/
|
||||||
class BookingEditDraftMerger
|
class BookingEditDraftMerger
|
||||||
{
|
{
|
||||||
|
/** @param array<string, mixed> $data */
|
||||||
public function apply(
|
public function apply(
|
||||||
BookingDto $bookingDto,
|
BookingDto $bookingDto,
|
||||||
int $participantIndex,
|
int $participantIndex,
|
||||||
@@ -79,6 +81,7 @@ class BookingEditDraftMerger
|
|||||||
return $participant->mutable;
|
return $participant->mutable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param array<string, mixed> $data */
|
||||||
private function applyPersonalData(ParticipantDto $participant, array $data): void
|
private function applyPersonalData(ParticipantDto $participant, array $data): void
|
||||||
{
|
{
|
||||||
if (true === array_key_exists('firstName', $data)) {
|
if (true === array_key_exists('firstName', $data)) {
|
||||||
@@ -104,6 +107,7 @@ class BookingEditDraftMerger
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param array<string, mixed> $data */
|
||||||
private function applyAddressData(ParticipantDto $participant, array $data): void
|
private function applyAddressData(ParticipantDto $participant, array $data): void
|
||||||
{
|
{
|
||||||
$hasAddressData = null !== ($data['street'] ?? null)
|
$hasAddressData = null !== ($data['street'] ?? null)
|
||||||
@@ -133,6 +137,7 @@ class BookingEditDraftMerger
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param array<string, mixed> $data */
|
||||||
private function applyBodyDimensions(ParticipantDto $participant, array $data): void
|
private function applyBodyDimensions(ParticipantDto $participant, array $data): void
|
||||||
{
|
{
|
||||||
if (true === array_key_exists('height', $data)) {
|
if (true === array_key_exists('height', $data)) {
|
||||||
@@ -146,6 +151,7 @@ class BookingEditDraftMerger
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param array<string, mixed> $data */
|
||||||
private function applyRoomAssignment(ParticipantDto $participant, array $data): void
|
private function applyRoomAssignment(ParticipantDto $participant, array $data): void
|
||||||
{
|
{
|
||||||
if (true === array_key_exists('assignedRoomId', $data)) {
|
if (true === array_key_exists('assignedRoomId', $data)) {
|
||||||
@@ -156,6 +162,7 @@ class BookingEditDraftMerger
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param array<string, mixed> $data */
|
||||||
private function applyVoucherCodes(ParticipantDto $participant, array $data): void
|
private function applyVoucherCodes(ParticipantDto $participant, array $data): void
|
||||||
{
|
{
|
||||||
if (true === array_key_exists('purchaseVoucherCode', $data)) {
|
if (true === array_key_exists('purchaseVoucherCode', $data)) {
|
||||||
@@ -177,6 +184,7 @@ class BookingEditDraftMerger
|
|||||||
* Multi-select fields (checkboxes) and booleans use overwrite strategy: draft values
|
* Multi-select fields (checkboxes) and booleans use overwrite strategy: draft values
|
||||||
* always replace API data, since users can intentionally clear these selections.
|
* always replace API data, since users can intentionally clear these selections.
|
||||||
*/
|
*/
|
||||||
|
/** @param array<string, mixed> $data */
|
||||||
private function applyServiceSelections(ParticipantDto $participant, array $data, Travel $travel): void
|
private function applyServiceSelections(ParticipantDto $participant, array $data, Travel $travel): void
|
||||||
{
|
{
|
||||||
// Additional services category — only apply draft data when services are mutable.
|
// Additional services category — only apply draft data when services are mutable.
|
||||||
@@ -296,11 +304,11 @@ class BookingEditDraftMerger
|
|||||||
* The mandatory flag must be looked up from travel data since booking data
|
* The mandatory flag must be looked up from travel data since booking data
|
||||||
* doesn't include the pflicht attribute.
|
* doesn't include the pflicht attribute.
|
||||||
*
|
*
|
||||||
* @param array $draftServices Services resolved from draft data
|
* @param list<Service> $draftServices Services resolved from draft data
|
||||||
* @param array $originalServices Services from fresh API data (booking assignments)
|
* @param list<Service> $originalServices Services from fresh API data (booking assignments)
|
||||||
* @param Travel $travel Travel data containing mandatory flag on services
|
* @param Travel $travel Travel data containing mandatory flag on services
|
||||||
*
|
*
|
||||||
* @return array Merged array with draft services plus any missing mandatory services
|
* @return list<Service> Merged array with draft services plus any missing mandatory services
|
||||||
*/
|
*/
|
||||||
private function preserveMandatoryServices(array $draftServices, array $originalServices, Travel $travel): array
|
private function preserveMandatoryServices(array $draftServices, array $originalServices, Travel $travel): array
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -171,6 +171,10 @@ class BookingEditSubmitGuard
|
|||||||
return $changed;
|
return $changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param list<Service> $left
|
||||||
|
* @param list<Service> $right
|
||||||
|
*/
|
||||||
private function areServiceListsEqual(array $left, array $right): bool
|
private function areServiceListsEqual(array $left, array $right): bool
|
||||||
{
|
{
|
||||||
return $this->normalizeServiceIds($left) === $this->normalizeServiceIds($right);
|
return $this->normalizeServiceIds($left) === $this->normalizeServiceIds($right);
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ use App\Form\Model\BookingDto;
|
|||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Session\FlashBagAwareSessionInterface;
|
||||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -119,7 +120,10 @@ class BookingEditSubmitter
|
|||||||
|
|
||||||
private function addFlash(Request $request, string $type, string $message): void
|
private function addFlash(Request $request, string $type, string $message): void
|
||||||
{
|
{
|
||||||
$request->getSession()->getFlashBag()->add($type, $message);
|
$session = $request->getSession();
|
||||||
|
if ($session instanceof FlashBagAwareSessionInterface) {
|
||||||
|
$session->getFlashBag()->add($type, $message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function redirectToEdit(int $bookingId): RedirectResponse
|
private function redirectToEdit(int $bookingId): RedirectResponse
|
||||||
|
|||||||
@@ -156,8 +156,8 @@ class BookingExporter
|
|||||||
/**
|
/**
|
||||||
* Creates the spreadsheet with participant data.
|
* Creates the spreadsheet with participant data.
|
||||||
*
|
*
|
||||||
* @param BookingEditDraft $draft The draft containing form data
|
* @param BookingEditDraft $draft The draft containing form data
|
||||||
* @param array $lookups The ID to label lookup arrays
|
* @param array<string, array<int, string>> $lookups The ID to label lookup arrays
|
||||||
*/
|
*/
|
||||||
private function createSpreadsheet(BookingEditDraft $draft, array $lookups): Spreadsheet
|
private function createSpreadsheet(BookingEditDraft $draft, array $lookups): Spreadsheet
|
||||||
{
|
{
|
||||||
@@ -203,6 +203,10 @@ class BookingExporter
|
|||||||
/**
|
/**
|
||||||
* Writes a single participant row to the spreadsheet.
|
* Writes a single participant row to the spreadsheet.
|
||||||
*/
|
*/
|
||||||
|
/**
|
||||||
|
* @param array<string, mixed> $participant
|
||||||
|
* @param array<string, array<int, string>> $lookups
|
||||||
|
*/
|
||||||
private function writeParticipantRow(
|
private function writeParticipantRow(
|
||||||
\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $sheet,
|
\PhpOffice\PhpSpreadsheet\Worksheet\Worksheet $sheet,
|
||||||
int $row,
|
int $row,
|
||||||
@@ -298,6 +302,7 @@ class BookingExporter
|
|||||||
/**
|
/**
|
||||||
* Resolves a single service ID to its label.
|
* Resolves a single service ID to its label.
|
||||||
*/
|
*/
|
||||||
|
/** @param array<int, string> $lookup */
|
||||||
private function resolveService(int|string|null $serviceId, array $lookup): string
|
private function resolveService(int|string|null $serviceId, array $lookup): string
|
||||||
{
|
{
|
||||||
if (null === $serviceId || '' === $serviceId) {
|
if (null === $serviceId || '' === $serviceId) {
|
||||||
@@ -312,6 +317,10 @@ class BookingExporter
|
|||||||
/**
|
/**
|
||||||
* Resolves an array of service IDs to labels, joined by pipe.
|
* Resolves an array of service IDs to labels, joined by pipe.
|
||||||
*/
|
*/
|
||||||
|
/**
|
||||||
|
* @param list<int|string|null> $serviceIds
|
||||||
|
* @param array<int, string> $lookup
|
||||||
|
*/
|
||||||
private function resolveServiceArray(array $serviceIds, array $lookup): string
|
private function resolveServiceArray(array $serviceIds, array $lookup): string
|
||||||
{
|
{
|
||||||
if (true === empty($serviceIds)) {
|
if (true === empty($serviceIds)) {
|
||||||
@@ -332,6 +341,7 @@ class BookingExporter
|
|||||||
/**
|
/**
|
||||||
* Resolves a room ID to its label.
|
* Resolves a room ID to its label.
|
||||||
*/
|
*/
|
||||||
|
/** @param array<int, string> $lookup */
|
||||||
private function resolveRoom(?int $roomId, array $lookup): string
|
private function resolveRoom(?int $roomId, array $lookup): string
|
||||||
{
|
{
|
||||||
if (null === $roomId) {
|
if (null === $roomId) {
|
||||||
@@ -344,6 +354,7 @@ class BookingExporter
|
|||||||
/**
|
/**
|
||||||
* Resolves a pickup ID to its label.
|
* Resolves a pickup ID to its label.
|
||||||
*/
|
*/
|
||||||
|
/** @param array<int, string> $lookup */
|
||||||
private function resolvePickup(?int $pickupId, array $lookup): string
|
private function resolvePickup(?int $pickupId, array $lookup): string
|
||||||
{
|
{
|
||||||
if (null === $pickupId) {
|
if (null === $pickupId) {
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ class BookingPriceMismatchAnalyzer
|
|||||||
{
|
{
|
||||||
$pricingBreakdown = $this->pricingAssembler->getPricingBreakdown($bookingCreateDto);
|
$pricingBreakdown = $this->pricingAssembler->getPricingBreakdown($bookingCreateDto);
|
||||||
|
|
||||||
$roomLines = $pricingBreakdown['rooms'] ?? [];
|
$roomLines = $pricingBreakdown['rooms'];
|
||||||
$serviceGroups = $pricingBreakdown['services'] ?? [];
|
$serviceGroups = $pricingBreakdown['services'];
|
||||||
|
|
||||||
$roomTotal = round(array_sum(array_column($roomLines, 'totalPrice')), 2);
|
$roomTotal = round(array_sum(array_column($roomLines, 'totalPrice')), 2);
|
||||||
$serviceTotal = round(array_sum(array_column($serviceGroups, 'groupTotal')), 2);
|
$serviceTotal = round(array_sum(array_column($serviceGroups, 'groupTotal')), 2);
|
||||||
@@ -70,14 +70,14 @@ class BookingPriceMismatchAnalyzer
|
|||||||
$apiTotal = round($response->totalPrice ?? 0.0, 2);
|
$apiTotal = round($response->totalPrice ?? 0.0, 2);
|
||||||
$apiServiceTotal = round($apiTotal - $apiRoomTotal, 2);
|
$apiServiceTotal = round($apiTotal - $apiRoomTotal, 2);
|
||||||
|
|
||||||
$deltaTotal = round(($pricingBreakdown['grandTotal'] ?? 0.0) - $apiTotal, 2);
|
$deltaTotal = round($pricingBreakdown['grandTotal'] - $apiTotal, 2);
|
||||||
$deltaRoom = round($roomTotal - $apiRoomTotal, 2);
|
$deltaRoom = round($roomTotal - $apiRoomTotal, 2);
|
||||||
$deltaService = round($serviceTotal - $apiServiceTotal, 2);
|
$deltaService = round($serviceTotal - $apiServiceTotal, 2);
|
||||||
$deltaInsurance = round($insuranceTotal - $apiInsuranceTotal, 2);
|
$deltaInsurance = round($insuranceTotal - $apiInsuranceTotal, 2);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'localBreakdown' => [
|
'localBreakdown' => [
|
||||||
'grandTotal' => round($pricingBreakdown['grandTotal'] ?? 0.0, 2),
|
'grandTotal' => round($pricingBreakdown['grandTotal'], 2),
|
||||||
'roomTotal' => $roomTotal,
|
'roomTotal' => $roomTotal,
|
||||||
'serviceTotal' => $serviceTotal,
|
'serviceTotal' => $serviceTotal,
|
||||||
'insuranceTotal' => $insuranceTotal,
|
'insuranceTotal' => $insuranceTotal,
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ class BookingPricingAssembler
|
|||||||
/**
|
/**
|
||||||
* Assembles a complete pricing breakdown for display or diagnostic use.
|
* Assembles a complete pricing breakdown for display or diagnostic use.
|
||||||
*
|
*
|
||||||
* @return array{rooms: array, services: array, grandTotal: float, surcharges?: array}
|
* @return array{rooms: array<int, array<string, mixed>>, services: array<int, array<string, mixed>>, grandTotal: float, surcharges?: array<int, array<string, mixed>>}
|
||||||
*/
|
*/
|
||||||
public function getPricingBreakdown(
|
public function getPricingBreakdown(
|
||||||
BookingDto $bookingDto,
|
BookingDto $bookingDto,
|
||||||
@@ -251,7 +251,8 @@ class BookingPricingAssembler
|
|||||||
|
|
||||||
foreach ($serviceAggregation as $serviceData) {
|
foreach ($serviceAggregation as $serviceData) {
|
||||||
$subType = $serviceData['subType'] ?? 'other';
|
$subType = $serviceData['subType'] ?? 'other';
|
||||||
if (null === $subType || '' === $subType) {
|
|
||||||
|
if ('' === $subType) {
|
||||||
$subType = 'other';
|
$subType = 'other';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -308,6 +309,7 @@ class BookingPricingAssembler
|
|||||||
return Constants::SERVICE_LABELS[$subType] ?? 'Sonstige Leistungen';
|
return Constants::SERVICE_LABELS[$subType] ?? 'Sonstige Leistungen';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param array<string, array<string, mixed>> $serviceAggregation */
|
||||||
private function aggregateParticipantServices(
|
private function aggregateParticipantServices(
|
||||||
ParticipantDto $participant,
|
ParticipantDto $participant,
|
||||||
array &$serviceAggregation,
|
array &$serviceAggregation,
|
||||||
@@ -338,16 +340,15 @@ class BookingPricingAssembler
|
|||||||
];
|
];
|
||||||
|
|
||||||
foreach ($multipleServiceArrays as $serviceArray) {
|
foreach ($multipleServiceArrays as $serviceArray) {
|
||||||
if (true === is_array($serviceArray)) {
|
foreach ($serviceArray as $service) {
|
||||||
foreach ($serviceArray as $service) {
|
if (null !== $service->price) {
|
||||||
if ($service instanceof Service && null !== $service->price) {
|
$this->addToServiceAggregation($serviceAggregation, $service);
|
||||||
$this->addToServiceAggregation($serviceAggregation, $service);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param array<string, array<string, mixed>> $serviceAggregation */
|
||||||
private function addToServiceAggregation(array &$serviceAggregation, Service $service, int $quantity = 1): void
|
private function addToServiceAggregation(array &$serviceAggregation, Service $service, int $quantity = 1): void
|
||||||
{
|
{
|
||||||
$serviceKey = $service->id.'_'.$service->label;
|
$serviceKey = $service->id.'_'.$service->label;
|
||||||
@@ -367,6 +368,7 @@ class BookingPricingAssembler
|
|||||||
$serviceAggregation[$serviceKey]['totalPrice'] += $service->price * $quantity;
|
$serviceAggregation[$serviceKey]['totalPrice'] += $service->price * $quantity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param array<string, array<string, mixed>> $serviceAggregation */
|
||||||
private function addInsuranceToServiceAggregation(array &$serviceAggregation, Insurance $insurance, int $quantity = 1): void
|
private function addInsuranceToServiceAggregation(array &$serviceAggregation, Insurance $insurance, int $quantity = 1): void
|
||||||
{
|
{
|
||||||
$serviceKey = $insurance->id.'_'.$insurance->label;
|
$serviceKey = $insurance->id.'_'.$insurance->label;
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ declare(strict_types=1);
|
|||||||
namespace App\Service;
|
namespace App\Service;
|
||||||
|
|
||||||
use App\Exception\BookingSessionNotFoundException;
|
use App\Exception\BookingSessionNotFoundException;
|
||||||
|
use App\Exception\HotelNotInTravelException;
|
||||||
|
use App\Exception\TravelNotFoundException;
|
||||||
use App\Form\Model\BookingDto;
|
use App\Form\Model\BookingDto;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
|
||||||
@@ -32,6 +34,8 @@ class BookingSessionManager
|
|||||||
* Retrieves the booking creation DTO from the session.
|
* Retrieves the booking creation DTO from the session.
|
||||||
*
|
*
|
||||||
* @throws BookingSessionNotFoundException
|
* @throws BookingSessionNotFoundException
|
||||||
|
* @throws TravelNotFoundException
|
||||||
|
* @throws HotelNotInTravelException
|
||||||
*/
|
*/
|
||||||
public function getOrCreateBookingCreateDto(Request $request): BookingDto
|
public function getOrCreateBookingCreateDto(Request $request): BookingDto
|
||||||
{
|
{
|
||||||
@@ -46,6 +50,8 @@ class BookingSessionManager
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets or creates the baseline room selection snapshot for change detection.
|
* Gets or creates the baseline room selection snapshot for change detection.
|
||||||
|
*
|
||||||
|
* @return array<int, array{int, int}>
|
||||||
*/
|
*/
|
||||||
public function getOrCreateBaselineSnapshot(Request $request, BookingDto $bookingCreateDto): array
|
public function getOrCreateBaselineSnapshot(Request $request, BookingDto $bookingCreateDto): array
|
||||||
{
|
{
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user