feat: fetch additional content from cms via api
This commit is contained in:
@@ -103,3 +103,4 @@ services:
|
|||||||
App\Service\CmsDataService:
|
App\Service\CmsDataService:
|
||||||
arguments:
|
arguments:
|
||||||
$httpClient: '@typo3.client'
|
$httpClient: '@typo3.client'
|
||||||
|
$apiKey: 'AbcAbc123'# dummy key, not yet implemented
|
||||||
|
|||||||
@@ -26,6 +26,9 @@ class Travel
|
|||||||
#[Groups(['api:list', 'api:single'])]
|
#[Groups(['api:list', 'api:single'])]
|
||||||
public ?string $code = null;
|
public ?string $code = null;
|
||||||
|
|
||||||
|
#[Groups(['api:list', 'api:single'])]
|
||||||
|
public ?string $productCode = null;
|
||||||
|
|
||||||
#[Groups(['api:list', 'api:single'])]
|
#[Groups(['api:list', 'api:single'])]
|
||||||
public ?string $label = null;
|
public ?string $label = null;
|
||||||
|
|
||||||
|
|||||||
@@ -54,6 +54,13 @@ class TravelParser extends AbstractParser
|
|||||||
$travel->dateFrom = $dateFrom;
|
$travel->dateFrom = $dateFrom;
|
||||||
$travel->dateTo = $dateTo;
|
$travel->dateTo = $dateTo;
|
||||||
$travel->code = $node->attr('code');
|
$travel->code = $node->attr('code');
|
||||||
|
|
||||||
|
// Parse product code from parent reise node using DOM
|
||||||
|
$domNode = $node->getNode(0);
|
||||||
|
if (null !== $domNode && null !== $domNode->parentNode) {
|
||||||
|
$travel->productCode = $domNode->parentNode->getAttribute('code');
|
||||||
|
}
|
||||||
|
|
||||||
$travel->type = $node->attr('reiseart');
|
$travel->type = $node->attr('reiseart');
|
||||||
$travel->status = $this->getStringOrNullValue($node->filterXPath('//status_hin'));
|
$travel->status = $this->getStringOrNullValue($node->filterXPath('//status_hin'));
|
||||||
$travel->priceFrom = $this->stringToFloat($this->getStringOrNullValue($node->filterXPath('//abpreis')));
|
$travel->priceFrom = $this->stringToFloat($this->getStringOrNullValue($node->filterXPath('//abpreis')));
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ use App\Controller\Booking\Traits\BookingExceptionHandlerTrait;
|
|||||||
use App\Form\BookingCreateStep1Type;
|
use App\Form\BookingCreateStep1Type;
|
||||||
use App\Htmx\HxTrait;
|
use App\Htmx\HxTrait;
|
||||||
use App\Service\BookingService;
|
use App\Service\BookingService;
|
||||||
|
use App\Service\BookingSummaryDataService;
|
||||||
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;
|
||||||
@@ -28,6 +29,7 @@ class Step1Controller extends AbstractController
|
|||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly BookingService $bookingService,
|
private readonly BookingService $bookingService,
|
||||||
|
private readonly BookingSummaryDataService $summaryDataService,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,8 +48,6 @@ class Step1Controller extends AbstractController
|
|||||||
// Get or create baseline snapshot for change detection
|
// Get or create baseline snapshot for change detection
|
||||||
$oldRoomSelectionSnapshot = $this->bookingService->getOrCreateBaselineSnapshot($request, $bookingCreateDto);
|
$oldRoomSelectionSnapshot = $this->bookingService->getOrCreateBaselineSnapshot($request, $bookingCreateDto);
|
||||||
|
|
||||||
$summary = $this->bookingService->getRoomSummaryAndParticipantCount($bookingCreateDto);
|
|
||||||
|
|
||||||
// Validate step access - allow step 1 or redirect to current step
|
// Validate step access - allow step 1 or redirect to current step
|
||||||
if ($redirect = $this->validateStepAccess($bookingCreateDto, 1)) {
|
if ($redirect = $this->validateStepAccess($bookingCreateDto, 1)) {
|
||||||
return $redirect;
|
return $redirect;
|
||||||
@@ -79,6 +79,9 @@ class Step1Controller extends AbstractController
|
|||||||
return $this->hxRedirect($request, $this->generateUrl('app_booking_create_step_2'));
|
return $this->hxRedirect($request, $this->generateUrl('app_booking_create_step_2'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get complete summary data (pricing, rooms, CMS data)
|
||||||
|
$summary = $this->summaryDataService->getSummaryData($bookingCreateDto);
|
||||||
|
|
||||||
$availableRooms = $bookingCreateDto->travel->getAvailableRooms();
|
$availableRooms = $bookingCreateDto->travel->getAvailableRooms();
|
||||||
$groupedRooms = $this->bookingService->groupRoomsBySelectionType($availableRooms);
|
$groupedRooms = $this->bookingService->groupRoomsBySelectionType($availableRooms);
|
||||||
$groupedSelectedRooms = $this->bookingService->groupRoomSelectionsByType($summary['selectedRooms'], $availableRooms);
|
$groupedSelectedRooms = $this->bookingService->groupRoomSelectionsByType($summary['selectedRooms'], $availableRooms);
|
||||||
@@ -87,7 +90,8 @@ class Step1Controller extends AbstractController
|
|||||||
'bookingCreateDto' => $bookingCreateDto,
|
'bookingCreateDto' => $bookingCreateDto,
|
||||||
'roomSummary' => $summary['selectedRooms'],
|
'roomSummary' => $summary['selectedRooms'],
|
||||||
'participantCount' => $summary['participantCount'],
|
'participantCount' => $summary['participantCount'],
|
||||||
'pricingData' => $summary['pricing'],
|
'pricingData' => $summary['pricingData'],
|
||||||
|
'cmsData' => $summary['cmsData'],
|
||||||
'form' => $form->createView(),
|
'form' => $form->createView(),
|
||||||
'groupedRooms' => $groupedRooms,
|
'groupedRooms' => $groupedRooms,
|
||||||
'groupedSelectedRooms' => $groupedSelectedRooms,
|
'groupedSelectedRooms' => $groupedSelectedRooms,
|
||||||
@@ -115,7 +119,8 @@ class Step1Controller extends AbstractController
|
|||||||
|
|
||||||
$this->bookingService->saveBookingCreateDto($request, $bookingCreateDto);
|
$this->bookingService->saveBookingCreateDto($request, $bookingCreateDto);
|
||||||
|
|
||||||
$summary = $this->bookingService->getRoomSummaryAndParticipantCount($bookingCreateDto);
|
// Get complete summary data (pricing, rooms, CMS data)
|
||||||
|
$summary = $this->summaryDataService->getSummaryData($bookingCreateDto);
|
||||||
$availableRooms = $bookingCreateDto->travel->getAvailableRooms();
|
$availableRooms = $bookingCreateDto->travel->getAvailableRooms();
|
||||||
$groupedRooms = $this->bookingService->groupRoomsBySelectionType($availableRooms);
|
$groupedRooms = $this->bookingService->groupRoomsBySelectionType($availableRooms);
|
||||||
$groupedSelectedRooms = $this->bookingService->groupRoomSelectionsByType($summary['selectedRooms'], $availableRooms);
|
$groupedSelectedRooms = $this->bookingService->groupRoomSelectionsByType($summary['selectedRooms'], $availableRooms);
|
||||||
@@ -129,7 +134,8 @@ class Step1Controller extends AbstractController
|
|||||||
'form' => $form->createView(),
|
'form' => $form->createView(),
|
||||||
'bookingCreateDto' => $bookingCreateDto,
|
'bookingCreateDto' => $bookingCreateDto,
|
||||||
'participantCount' => $summary['participantCount'],
|
'participantCount' => $summary['participantCount'],
|
||||||
'pricingData' => $summary['pricing'],
|
'pricingData' => $summary['pricingData'],
|
||||||
|
'cmsData' => $summary['cmsData'],
|
||||||
'groupedRooms' => $groupedRooms,
|
'groupedRooms' => $groupedRooms,
|
||||||
'groupedSelectedRooms' => $groupedSelectedRooms,
|
'groupedSelectedRooms' => $groupedSelectedRooms,
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ use App\Form\Model\BookingDto;
|
|||||||
use App\Form\Model\ParticipantDto;
|
use App\Form\Model\ParticipantDto;
|
||||||
use App\Form\Service\ParticipantFieldOptionsProvider;
|
use App\Form\Service\ParticipantFieldOptionsProvider;
|
||||||
use App\Htmx\HxTrait;
|
use App\Htmx\HxTrait;
|
||||||
use App\Service\BookingPriceCalculatorService;
|
|
||||||
use App\Service\BookingService;
|
use App\Service\BookingService;
|
||||||
|
use App\Service\BookingSummaryDataService;
|
||||||
use App\Service\ParticipantCardDataService;
|
use App\Service\ParticipantCardDataService;
|
||||||
use App\Service\ParticipantPrepopulationService;
|
use App\Service\ParticipantPrepopulationService;
|
||||||
use App\Service\RoomAssignmentService;
|
use App\Service\RoomAssignmentService;
|
||||||
@@ -38,7 +38,7 @@ class Step2Controller extends AbstractController
|
|||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly BookingService $bookingService,
|
private readonly BookingService $bookingService,
|
||||||
private readonly BookingPriceCalculatorService $priceCalculator,
|
private readonly BookingSummaryDataService $summaryDataService,
|
||||||
private readonly TravelDataService $travelDataService,
|
private readonly TravelDataService $travelDataService,
|
||||||
private readonly RoomAssignmentService $roomAssignmentService,
|
private readonly RoomAssignmentService $roomAssignmentService,
|
||||||
private readonly ParticipantCardDataService $participantCardService,
|
private readonly ParticipantCardDataService $participantCardService,
|
||||||
@@ -99,18 +99,16 @@ class Step2Controller extends AbstractController
|
|||||||
? $this->participantCardService->getAllCardsDataWithValidation($bookingCreateDto)
|
? $this->participantCardService->getAllCardsDataWithValidation($bookingCreateDto)
|
||||||
: $this->generateAllCardsData($bookingCreateDto);
|
: $this->generateAllCardsData($bookingCreateDto);
|
||||||
|
|
||||||
// Calculate summary data
|
// Get complete summary data (pricing, rooms, CMS data)
|
||||||
$summaryData = $this->calculateSummaryData($bookingCreateDto);
|
$summaryData = $this->summaryDataService->getSummaryData($bookingCreateDto);
|
||||||
|
|
||||||
// Get detailed pricing data for summary sidebar
|
|
||||||
$summary = $this->bookingService->getRoomSummaryAndParticipantCount($bookingCreateDto);
|
|
||||||
|
|
||||||
$templateData = [
|
$templateData = [
|
||||||
'form' => $form->createView(),
|
'form' => $form->createView(),
|
||||||
'bookingDto' => $bookingCreateDto,
|
'bookingDto' => $bookingCreateDto,
|
||||||
'cardsData' => $cardsData,
|
'cardsData' => $cardsData,
|
||||||
'summaryData' => $summaryData,
|
'summaryData' => $summaryData,
|
||||||
'pricingData' => $summary['pricing'],
|
'pricingData' => $summaryData['pricingData'],
|
||||||
|
'cmsData' => $summaryData['cmsData'],
|
||||||
];
|
];
|
||||||
|
|
||||||
// HTMX request: render blocks only
|
// HTMX request: render blocks only
|
||||||
@@ -160,18 +158,16 @@ class Step2Controller extends AbstractController
|
|||||||
return $this->hxRedirect($request, $this->generateUrl('app_booking_create_step_2'));
|
return $this->hxRedirect($request, $this->generateUrl('app_booking_create_step_2'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate summary data for sidebar
|
// Get complete summary data (pricing, rooms, CMS data)
|
||||||
$summaryData = $this->calculateSummaryData($bookingDto);
|
$summaryData = $this->summaryDataService->getSummaryData($bookingDto);
|
||||||
|
|
||||||
// Get detailed pricing data for summary sidebar
|
|
||||||
$summary = $this->bookingService->getRoomSummaryAndParticipantCount($bookingDto);
|
|
||||||
|
|
||||||
$templateData = [
|
$templateData = [
|
||||||
'form' => $form->createView(),
|
'form' => $form->createView(),
|
||||||
'participantIndex' => $index,
|
'participantIndex' => $index,
|
||||||
'bookingDto' => $bookingDto,
|
'bookingDto' => $bookingDto,
|
||||||
'summaryData' => $summaryData,
|
'summaryData' => $summaryData,
|
||||||
'pricingData' => $summary['pricing'],
|
'pricingData' => $summaryData['pricingData'],
|
||||||
|
'cmsData' => $summaryData['cmsData'],
|
||||||
'refreshRouteName' => 'app_booking_create_step_2_participant_refresh',
|
'refreshRouteName' => 'app_booking_create_step_2_participant_refresh',
|
||||||
'submitRouteName' => 'app_booking_create_step_2_participant',
|
'submitRouteName' => 'app_booking_create_step_2_participant',
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ use App\Controller\Booking\Traits\BookingExceptionHandlerTrait;
|
|||||||
use App\Form\BookingCreateStep3Type;
|
use App\Form\BookingCreateStep3Type;
|
||||||
use App\Form\Model\BookingDto;
|
use App\Form\Model\BookingDto;
|
||||||
use App\Htmx\HxTrait;
|
use App\Htmx\HxTrait;
|
||||||
use App\Service\BookingPriceCalculatorService;
|
|
||||||
use App\Service\BookingService;
|
use App\Service\BookingService;
|
||||||
|
use App\Service\BookingSummaryDataService;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\Form\FormInterface;
|
use Symfony\Component\Form\FormInterface;
|
||||||
@@ -32,8 +32,8 @@ class Step3Controller extends AbstractController
|
|||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly BookingService $bookingService,
|
private readonly BookingService $bookingService,
|
||||||
|
private readonly BookingSummaryDataService $summaryDataService,
|
||||||
private readonly ApiClient $apiClient,
|
private readonly ApiClient $apiClient,
|
||||||
private readonly BookingPriceCalculatorService $priceCalculator,
|
|
||||||
private readonly LoggerInterface $logger,
|
private readonly LoggerInterface $logger,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
@@ -172,10 +172,19 @@ class Step3Controller extends AbstractController
|
|||||||
*/
|
*/
|
||||||
private function renderStepForm(BookingDto $bookingCreateDto, FormInterface $form): Response
|
private function renderStepForm(BookingDto $bookingCreateDto, FormInterface $form): Response
|
||||||
{
|
{
|
||||||
|
// Get complete summary data (pricing, rooms, CMS data)
|
||||||
|
$summaryData = $this->summaryDataService->getSummaryData($bookingCreateDto);
|
||||||
|
$availableRooms = $bookingCreateDto->travel->getAvailableRooms();
|
||||||
|
$groupedSelectedRooms = $this->bookingService->groupRoomSelectionsByType($summaryData['selectedRooms'], $availableRooms);
|
||||||
|
|
||||||
return $this->render('booking/create/step_3.html.twig', [
|
return $this->render('booking/create/step_3.html.twig', [
|
||||||
'bookingCreateDto' => $bookingCreateDto,
|
'bookingCreateDto' => $bookingCreateDto,
|
||||||
'form' => $form->createView(),
|
'form' => $form->createView(),
|
||||||
...$this->getSummaryVariables($bookingCreateDto),
|
'participantCount' => $summaryData['participantCount'],
|
||||||
|
'pricingData' => $summaryData['pricingData'],
|
||||||
|
'cmsData' => $summaryData['cmsData'],
|
||||||
|
'assignmentCounts' => $summaryData['assignmentCounts'],
|
||||||
|
'groupedSelectedRooms' => $groupedSelectedRooms,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ use App\Form\Model\BookingDto;
|
|||||||
use App\Htmx\HxTrait;
|
use App\Htmx\HxTrait;
|
||||||
use App\Service\BookingPriceCalculatorService;
|
use App\Service\BookingPriceCalculatorService;
|
||||||
use App\Service\BookingService;
|
use App\Service\BookingService;
|
||||||
|
use App\Service\BookingSummaryDataService;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
use Symfony\Component\Form\FormInterface;
|
use Symfony\Component\Form\FormInterface;
|
||||||
@@ -32,6 +33,7 @@ class Step4Controller extends AbstractController
|
|||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private readonly BookingService $bookingService,
|
private readonly BookingService $bookingService,
|
||||||
|
private readonly BookingSummaryDataService $summaryDataService,
|
||||||
private readonly BookingPriceCalculatorService $priceCalculator,
|
private readonly BookingPriceCalculatorService $priceCalculator,
|
||||||
private readonly ApiClient $apiClient,
|
private readonly ApiClient $apiClient,
|
||||||
private readonly LoggerInterface $logger,
|
private readonly LoggerInterface $logger,
|
||||||
@@ -128,10 +130,19 @@ class Step4Controller extends AbstractController
|
|||||||
*/
|
*/
|
||||||
private function renderStepForm(BookingDto $bookingCreateDto, FormInterface $form): Response
|
private function renderStepForm(BookingDto $bookingCreateDto, FormInterface $form): Response
|
||||||
{
|
{
|
||||||
|
// Get complete summary data (pricing, rooms, CMS data)
|
||||||
|
$summaryData = $this->summaryDataService->getSummaryData($bookingCreateDto);
|
||||||
|
$availableRooms = $bookingCreateDto->travel->getAvailableRooms();
|
||||||
|
$groupedSelectedRooms = $this->bookingService->groupRoomSelectionsByType($summaryData['selectedRooms'], $availableRooms);
|
||||||
|
|
||||||
return $this->render('booking/create/step_4.html.twig', [
|
return $this->render('booking/create/step_4.html.twig', [
|
||||||
'bookingCreateDto' => $bookingCreateDto,
|
'bookingCreateDto' => $bookingCreateDto,
|
||||||
'form' => $form->createView(),
|
'form' => $form->createView(),
|
||||||
...$this->getSummaryVariables($bookingCreateDto),
|
'participantCount' => $summaryData['participantCount'],
|
||||||
|
'pricingData' => $summaryData['pricingData'],
|
||||||
|
'cmsData' => $summaryData['cmsData'],
|
||||||
|
'assignmentCounts' => $summaryData['assignmentCounts'],
|
||||||
|
'groupedSelectedRooms' => $groupedSelectedRooms,
|
||||||
'participantPrices' => $this->priceCalculator->calculateAllParticipantIndividualPrices($bookingCreateDto),
|
'participantPrices' => $this->priceCalculator->calculateAllParticipantIndividualPrices($bookingCreateDto),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ use App\Form\Service\ParticipantFieldHandlerRegistry;
|
|||||||
use App\Htmx\HxTrait;
|
use App\Htmx\HxTrait;
|
||||||
use App\Security\Crypt;
|
use App\Security\Crypt;
|
||||||
use App\Service\BookingFingerprintService;
|
use App\Service\BookingFingerprintService;
|
||||||
use App\Service\BookingPriceCalculatorService;
|
|
||||||
use App\Service\BookingService;
|
use App\Service\BookingService;
|
||||||
|
use App\Service\BookingSummaryDataService;
|
||||||
use App\Service\ParticipantCardDataService;
|
use App\Service\ParticipantCardDataService;
|
||||||
use App\Service\TravelDataService;
|
use App\Service\TravelDataService;
|
||||||
use Psr\Cache\InvalidArgumentException;
|
use Psr\Cache\InvalidArgumentException;
|
||||||
@@ -57,7 +57,7 @@ class IndexController extends AbstractController
|
|||||||
private readonly TravelDataService $travelDataService,
|
private readonly TravelDataService $travelDataService,
|
||||||
private readonly BookingService $bookingService,
|
private readonly BookingService $bookingService,
|
||||||
private readonly BookingFingerprintService $fingerprintService,
|
private readonly BookingFingerprintService $fingerprintService,
|
||||||
private readonly BookingPriceCalculatorService $priceCalculator,
|
private readonly BookingSummaryDataService $summaryDataService,
|
||||||
private readonly ParticipantCardDataService $participantCardService,
|
private readonly ParticipantCardDataService $participantCardService,
|
||||||
private readonly ParticipantFieldHandlerRegistry $fieldHandlerRegistry,
|
private readonly ParticipantFieldHandlerRegistry $fieldHandlerRegistry,
|
||||||
private readonly CacheInterface $cache,
|
private readonly CacheInterface $cache,
|
||||||
@@ -166,9 +166,8 @@ class IndexController extends AbstractController
|
|||||||
? $this->participantCardService->getAllCardsDataWithValidation($bookingDto)
|
? $this->participantCardService->getAllCardsDataWithValidation($bookingDto)
|
||||||
: $this->participantCardService->getAllCardsData($bookingDto);
|
: $this->participantCardService->getAllCardsData($bookingDto);
|
||||||
|
|
||||||
// Calculate summary data for sidebar
|
// Get complete summary data (pricing, rooms, CMS data)
|
||||||
$summary = $this->bookingService->getRoomSummaryAndParticipantCount($bookingDto);
|
$summaryData = $this->summaryDataService->getSummaryData($bookingDto);
|
||||||
$roomAssignmentCounts = $this->bookingService->getRoomAssignmentCounts($bookingDto);
|
|
||||||
|
|
||||||
// Group selected rooms for summary display
|
// Group selected rooms for summary display
|
||||||
$availableRooms = $bookingDto->travel->getAvailableRooms();
|
$availableRooms = $bookingDto->travel->getAvailableRooms();
|
||||||
@@ -184,9 +183,10 @@ class IndexController extends AbstractController
|
|||||||
'mutableData' => $mutableData,
|
'mutableData' => $mutableData,
|
||||||
'cardsData' => $cardsData,
|
'cardsData' => $cardsData,
|
||||||
'participantsCount' => count($bookingDto->participants),
|
'participantsCount' => count($bookingDto->participants),
|
||||||
'pricingData' => $summary['pricing'],
|
'pricingData' => $summaryData['pricingData'],
|
||||||
|
'cmsData' => $summaryData['cmsData'],
|
||||||
'groupedSelectedRooms' => $groupedSelectedRooms,
|
'groupedSelectedRooms' => $groupedSelectedRooms,
|
||||||
'assignmentCounts' => $roomAssignmentCounts,
|
'assignmentCounts' => $summaryData['assignmentCounts'],
|
||||||
'isDirty' => $this->fingerprintService->isDirty($bookingDto),
|
'isDirty' => $this->fingerprintService->isDirty($bookingDto),
|
||||||
'hasValidationErrors' => $form->isSubmitted() && false === $form->isValid(),
|
'hasValidationErrors' => $form->isSubmitted() && false === $form->isValid(),
|
||||||
];
|
];
|
||||||
@@ -275,9 +275,8 @@ class IndexController extends AbstractController
|
|||||||
return $this->hxRedirect($request, $this->generateUrl('app_booking_edit', ['id' => $id]));
|
return $this->hxRedirect($request, $this->generateUrl('app_booking_edit', ['id' => $id]));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate summary data using trait helper
|
// Get complete summary data (pricing, rooms, CMS data)
|
||||||
$summaryData = $this->calculateSummaryData($bookingDto);
|
$summaryData = $this->summaryDataService->getSummaryData($bookingDto);
|
||||||
$summary = $this->bookingService->getRoomSummaryAndParticipantCount($bookingDto);
|
|
||||||
|
|
||||||
// Fetch mutable data for form constraints
|
// Fetch mutable data for form constraints
|
||||||
$mutableData = $this->travelDataService->getMutabilityData($bookingData->dateId);
|
$mutableData = $this->travelDataService->getMutabilityData($bookingData->dateId);
|
||||||
@@ -289,7 +288,8 @@ class IndexController extends AbstractController
|
|||||||
'bookingData' => $bookingData,
|
'bookingData' => $bookingData,
|
||||||
'mutableData' => $mutableData,
|
'mutableData' => $mutableData,
|
||||||
'summaryData' => $summaryData,
|
'summaryData' => $summaryData,
|
||||||
'pricingData' => $summary['pricing'],
|
'pricingData' => $summaryData['pricingData'],
|
||||||
|
'cmsData' => $summaryData['cmsData'],
|
||||||
'refreshRouteName' => 'app_booking_edit_participant_refresh',
|
'refreshRouteName' => 'app_booking_edit_participant_refresh',
|
||||||
'refreshRouteParams' => ['id' => $id, 'index' => $index],
|
'refreshRouteParams' => ['id' => $id, 'index' => $index],
|
||||||
'submitRouteName' => 'app_booking_edit_participant',
|
'submitRouteName' => 'app_booking_edit_participant',
|
||||||
@@ -374,9 +374,8 @@ class IndexController extends AbstractController
|
|||||||
$participant->notifications = [];
|
$participant->notifications = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate summary data using trait helper
|
// Get complete summary data (pricing, rooms, CMS data)
|
||||||
$summaryData = $this->calculateSummaryData($bookingDto);
|
$summaryData = $this->summaryDataService->getSummaryData($bookingDto);
|
||||||
$summary = $this->bookingService->getRoomSummaryAndParticipantCount($bookingDto);
|
|
||||||
|
|
||||||
// Render form + sidebar using htmxOobResponse
|
// Render form + sidebar using htmxOobResponse
|
||||||
$response = $this->htmxOobResponse(
|
$response = $this->htmxOobResponse(
|
||||||
@@ -389,7 +388,8 @@ class IndexController extends AbstractController
|
|||||||
'bookingData' => $bookingData,
|
'bookingData' => $bookingData,
|
||||||
'mutableData' => $mutableData,
|
'mutableData' => $mutableData,
|
||||||
'summaryData' => $summaryData,
|
'summaryData' => $summaryData,
|
||||||
'pricingData' => $summary['pricing'],
|
'pricingData' => $summaryData['pricingData'],
|
||||||
|
'cmsData' => $summaryData['cmsData'],
|
||||||
'refreshRouteName' => 'app_booking_edit_participant_refresh',
|
'refreshRouteName' => 'app_booking_edit_participant_refresh',
|
||||||
'refreshRouteParams' => ['id' => $id, 'index' => $index],
|
'refreshRouteParams' => ['id' => $id, 'index' => $index],
|
||||||
'submitRouteName' => 'app_booking_edit_participant',
|
'submitRouteName' => 'app_booking_edit_participant',
|
||||||
|
|||||||
@@ -76,52 +76,6 @@ trait ParticipantCardFlowTrait
|
|||||||
return $this->createForm(BookingParticipantType::class, $wrapper, $formOptions);
|
return $this->createForm(BookingParticipantType::class, $wrapper, $formOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculate summary data (pricing, room counts, etc.).
|
|
||||||
*
|
|
||||||
* @return array{
|
|
||||||
* participantsCount: int,
|
|
||||||
* totalPrice: string,
|
|
||||||
* groupedSelectedRooms: array,
|
|
||||||
* assignmentCounts: array
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
private function calculateSummaryData(BookingDto $bookingDto): array
|
|
||||||
{
|
|
||||||
// Calculate individual prices for all participants
|
|
||||||
$participantPrices = $this->priceCalculator->calculateAllParticipantIndividualPrices($bookingDto);
|
|
||||||
|
|
||||||
// Calculate total price
|
|
||||||
$totalPrice = array_sum($participantPrices);
|
|
||||||
|
|
||||||
// Get room assignment counts
|
|
||||||
$roomCounts = [];
|
|
||||||
foreach ($bookingDto->participants as $participant) {
|
|
||||||
if (null !== $participant->assignedRoomId) {
|
|
||||||
$roomCounts[$participant->assignedRoomId] = ($roomCounts[$participant->assignedRoomId] ?? 0) + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Group selected rooms with counts
|
|
||||||
$groupedSelectedRooms = [];
|
|
||||||
foreach ($roomCounts as $roomId => $count) {
|
|
||||||
$room = $bookingDto->travel->getRoomById($roomId);
|
|
||||||
if (null !== $room) {
|
|
||||||
$groupedSelectedRooms[] = [
|
|
||||||
'room' => $room,
|
|
||||||
'count' => $count,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
|
||||||
'participantsCount' => count($bookingDto->participants),
|
|
||||||
'totalPrice' => number_format($totalPrice, 2, ',', '.').' €',
|
|
||||||
'groupedSelectedRooms' => $groupedSelectedRooms,
|
|
||||||
'assignmentCounts' => $roomCounts,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process single participant form refresh.
|
* Process single participant form refresh.
|
||||||
*
|
*
|
||||||
@@ -155,11 +109,8 @@ trait ParticipantCardFlowTrait
|
|||||||
// Save updated booking data to session (after collecting & clearing notifications)
|
// Save updated booking data to session (after collecting & clearing notifications)
|
||||||
$this->bookingService->saveBookingDto($request, $bookingDto, $bookingDto->getMode());
|
$this->bookingService->saveBookingDto($request, $bookingDto, $bookingDto->getMode());
|
||||||
|
|
||||||
// Calculate summary data for sidebar
|
// Get complete summary data (pricing, rooms, CMS data)
|
||||||
$summaryData = $this->calculateSummaryData($bookingDto);
|
$summaryData = $this->summaryDataService->getSummaryData($bookingDto);
|
||||||
|
|
||||||
// Get detailed pricing data for summary sidebar
|
|
||||||
$summary = $this->bookingService->getRoomSummaryAndParticipantCount($bookingDto);
|
|
||||||
|
|
||||||
// Render form and sidebar with OOB swap using htmxOobResponse
|
// Render form and sidebar with OOB swap using htmxOobResponse
|
||||||
// This renders ONLY the specific blocks, not the entire template
|
// This renders ONLY the specific blocks, not the entire template
|
||||||
@@ -171,7 +122,8 @@ trait ParticipantCardFlowTrait
|
|||||||
'participantIndex' => $index,
|
'participantIndex' => $index,
|
||||||
'bookingDto' => $bookingDto,
|
'bookingDto' => $bookingDto,
|
||||||
'summaryData' => $summaryData,
|
'summaryData' => $summaryData,
|
||||||
'pricingData' => $summary['pricing'],
|
'pricingData' => $summaryData['pricingData'],
|
||||||
|
'cmsData' => $summaryData['cmsData'],
|
||||||
'refreshRouteName' => $refreshRouteName,
|
'refreshRouteName' => $refreshRouteName,
|
||||||
'submitRouteName' => $submitRouteName,
|
'submitRouteName' => $submitRouteName,
|
||||||
]
|
]
|
||||||
@@ -193,7 +145,7 @@ trait ParticipantCardFlowTrait
|
|||||||
* Controllers using this trait must have the following properties:
|
* Controllers using this trait must have the following properties:
|
||||||
* - BookingService $bookingService
|
* - BookingService $bookingService
|
||||||
* - ParticipantCardDataService $participantCardService
|
* - ParticipantCardDataService $participantCardService
|
||||||
* - BookingPriceCalculatorService $priceCalculator
|
* - BookingSummaryDataService $summaryDataService
|
||||||
*/
|
*/
|
||||||
abstract private function createForm(string $type, $data = null, array $options = []): FormInterface;
|
abstract private function createForm(string $type, $data = null, array $options = []): FormInterface;
|
||||||
|
|
||||||
|
|||||||
@@ -7,36 +7,18 @@ use Symfony\Contracts\HttpClient\HttpClientInterface;
|
|||||||
|
|
||||||
class CmsDataService
|
class CmsDataService
|
||||||
{
|
{
|
||||||
public const MODE_PRODUCT = 'product';
|
public function __construct(private readonly HttpClientInterface $httpClient, private readonly string $apiKey)
|
||||||
public const MODE_HOTEL = 'hotel';
|
|
||||||
|
|
||||||
public function __construct(private readonly HttpClientInterface $httpClient)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getProductDetails(string $code): array
|
public function getProductDetails(string $productCode, ?string $hotelCode = null): array
|
||||||
{
|
{
|
||||||
return $this->makeApiCall(static::MODE_PRODUCT, $code);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getHotelDetails(string $code): array
|
|
||||||
{
|
|
||||||
return $this->makeApiCall(static::MODE_HOTEL, $code);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function makeApiCall(string $mode, string $code): array
|
|
||||||
{
|
|
||||||
if (false === in_array($mode, [self::MODE_PRODUCT, self::MODE_HOTEL])) {
|
|
||||||
throw new \InvalidArgumentException('Invalid mode provided');
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$request = $this->httpClient->request('GET', '/', [
|
$request = $this->httpClient->request('GET', 'api/product', [
|
||||||
'query' => [
|
'query' => [
|
||||||
'type' => 1720,
|
'product' => $productCode,
|
||||||
'tx_epproducts_api[code]' => $code,
|
'hotel' => $hotelCode,
|
||||||
'tx_epproducts_api[action]' => $mode,
|
'key' => $this->apiKey,
|
||||||
'tx_epproducts_api[controller]' => 'Api',
|
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
} catch (ExceptionInterface $e) {
|
} catch (ExceptionInterface $e) {
|
||||||
|
|||||||
@@ -45,7 +45,16 @@
|
|||||||
|
|
||||||
{# Travel Information #}
|
{# Travel Information #}
|
||||||
<div class="mb-6 pb-4 border-b border-gray-200">
|
<div class="mb-6 pb-4 border-b border-gray-200">
|
||||||
<h4 class="font-semibold text-lg mb-3 text-gray-800">Reiseinformationen</h4>
|
{% if cmsData.hotel.images is defined %}
|
||||||
|
<img src="{{ cmsData.hotel.images.resized.l[0].url }}" alt="{{ cmsData.hotel.images.resized.s[0].alt }}" class="w-full rounded mb-4">
|
||||||
|
{% endif %}
|
||||||
|
{% if cmsData.hotel.address is defined %}
|
||||||
|
<address>
|
||||||
|
{{ cmsData.hotel.name }}
|
||||||
|
<br>
|
||||||
|
{{ cmsData.hotel.address | nl2br }}
|
||||||
|
</address>
|
||||||
|
{% endif %}
|
||||||
<div class="space-y-2 text-sm text-gray-600">
|
<div class="space-y-2 text-sm text-gray-600">
|
||||||
<div><span class="font-medium">Reise:</span> {{ bookingCreateDto.travel.label }}</div>
|
<div><span class="font-medium">Reise:</span> {{ bookingCreateDto.travel.label }}</div>
|
||||||
<div><span class="font-medium">Zeitraum:</span> {{ bookingCreateDto.travel.dateFrom|date('d.m.Y') }} - {{ bookingCreateDto.travel.dateTo|date('d.m.Y') }}</div>
|
<div><span class="font-medium">Zeitraum:</span> {{ bookingCreateDto.travel.dateFrom|date('d.m.Y') }} - {{ bookingCreateDto.travel.dateTo|date('d.m.Y') }}</div>
|
||||||
|
|||||||
@@ -69,6 +69,7 @@
|
|||||||
'bookingCreateDto': bookingCreateDto,
|
'bookingCreateDto': bookingCreateDto,
|
||||||
'participantCount': participantCount,
|
'participantCount': participantCount,
|
||||||
'pricingData': pricingData,
|
'pricingData': pricingData,
|
||||||
|
'cmsData': cmsData,
|
||||||
'groupedSelectedRooms': groupedSelectedRooms,
|
'groupedSelectedRooms': groupedSelectedRooms,
|
||||||
'assignmentCounts': []
|
'assignmentCounts': []
|
||||||
} %}
|
} %}
|
||||||
|
|||||||
@@ -64,10 +64,11 @@
|
|||||||
<div id="booking-summary"{% if htmx_oob_swap|default(false) %} hx-swap-oob="true"{% endif %}>
|
<div id="booking-summary"{% if htmx_oob_swap|default(false) %} hx-swap-oob="true"{% endif %}>
|
||||||
{% include 'booking/_summary.html.twig' with {
|
{% include 'booking/_summary.html.twig' with {
|
||||||
'bookingCreateDto': bookingDto,
|
'bookingCreateDto': bookingDto,
|
||||||
'participantCount': summaryData.participantsCount,
|
'participantCount': summaryData.participantCount,
|
||||||
'groupedSelectedRooms': summaryData.groupedSelectedRooms,
|
'groupedSelectedRooms': summaryData.groupedSelectedRooms,
|
||||||
'assignmentCounts': summaryData.assignmentCounts,
|
'assignmentCounts': summaryData.assignmentCounts,
|
||||||
'pricingData': pricingData
|
'pricingData': pricingData,
|
||||||
|
'cmsData': cmsData
|
||||||
} %}
|
} %}
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -14,10 +14,11 @@
|
|||||||
<div id="booking-summary">
|
<div id="booking-summary">
|
||||||
{% include 'booking/_summary.html.twig' with {
|
{% include 'booking/_summary.html.twig' with {
|
||||||
'bookingCreateDto': bookingDto,
|
'bookingCreateDto': bookingDto,
|
||||||
'participantCount': summaryData.participantsCount,
|
'participantCount': summaryData.participantCount,
|
||||||
'groupedSelectedRooms': summaryData.groupedSelectedRooms,
|
'groupedSelectedRooms': summaryData.groupedSelectedRooms,
|
||||||
'assignmentCounts': summaryData.assignmentCounts,
|
'assignmentCounts': summaryData.assignmentCounts,
|
||||||
'pricingData': pricingData
|
'pricingData': pricingData,
|
||||||
|
'cmsData': cmsData
|
||||||
} %}
|
} %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -59,7 +59,9 @@
|
|||||||
<div id="booking-summary">
|
<div id="booking-summary">
|
||||||
{% include 'booking/_summary.html.twig' with {
|
{% include 'booking/_summary.html.twig' with {
|
||||||
'bookingCreateDto': bookingCreateDto,
|
'bookingCreateDto': bookingCreateDto,
|
||||||
'participantCount': participantsCount,
|
'participantCount': participantCount,
|
||||||
|
'pricingData': pricingData,
|
||||||
|
'cmsData': cmsData,
|
||||||
'groupedSelectedRooms': groupedSelectedRooms,
|
'groupedSelectedRooms': groupedSelectedRooms,
|
||||||
'assignmentCounts': assignmentCounts
|
'assignmentCounts': assignmentCounts
|
||||||
} %}
|
} %}
|
||||||
|
|||||||
@@ -98,7 +98,7 @@
|
|||||||
|
|
||||||
{# Participants Summary #}
|
{# Participants Summary #}
|
||||||
<div class="mb-8 p-6 bg-gray-50 rounded-lg border border-gray-200">
|
<div class="mb-8 p-6 bg-gray-50 rounded-lg border border-gray-200">
|
||||||
<h3 class="text-xl font-semibold mb-4">Teilnehmer ({{ participantsCount }})</h3>
|
<h3 class="text-xl font-semibold mb-4">Teilnehmer ({{ participantCount }})</h3>
|
||||||
{% for participant in bookingCreateDto.participants %}
|
{% for participant in bookingCreateDto.participants %}
|
||||||
<div class="mb-6 pb-6 {% if not loop.last %}border-b border-gray-300{% endif %}">
|
<div class="mb-6 pb-6 {% if not loop.last %}border-b border-gray-300{% endif %}">
|
||||||
<div class="flex justify-between items-start mb-3">
|
<div class="flex justify-between items-start mb-3">
|
||||||
|
|||||||
@@ -102,6 +102,7 @@
|
|||||||
'bookingCreateDto': bookingDto,
|
'bookingCreateDto': bookingDto,
|
||||||
'participantCount': participantsCount,
|
'participantCount': participantsCount,
|
||||||
'pricingData': pricingData,
|
'pricingData': pricingData,
|
||||||
|
'cmsData': cmsData,
|
||||||
'groupedSelectedRooms': groupedSelectedRooms,
|
'groupedSelectedRooms': groupedSelectedRooms,
|
||||||
'assignmentCounts': assignmentCounts,
|
'assignmentCounts': assignmentCounts,
|
||||||
'mutableData': mutableData|default(null)
|
'mutableData': mutableData|default(null)
|
||||||
|
|||||||
@@ -14,10 +14,11 @@
|
|||||||
<div id="booking-summary">
|
<div id="booking-summary">
|
||||||
{% include 'booking/_summary.html.twig' with {
|
{% include 'booking/_summary.html.twig' with {
|
||||||
'bookingCreateDto': bookingDto,
|
'bookingCreateDto': bookingDto,
|
||||||
'participantCount': summaryData.participantsCount,
|
'participantCount': summaryData.participantCount,
|
||||||
'groupedSelectedRooms': summaryData.groupedSelectedRooms,
|
'groupedSelectedRooms': summaryData.groupedSelectedRooms,
|
||||||
'assignmentCounts': summaryData.assignmentCounts,
|
'assignmentCounts': summaryData.assignmentCounts,
|
||||||
'pricingData': pricingData
|
'pricingData': pricingData,
|
||||||
|
'cmsData': cmsData
|
||||||
} %}
|
} %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user