src/Controller/Shop/Json/TicketJsonController.php line 37

Open in your IDE?
  1. <?php
  2. /**
  3.  * Created by Elements.at New Media Solutions GmbH
  4.  *
  5.  */
  6. namespace App\Controller\Shop\Json;
  7. use App\Controller\AbstractController;
  8. use App\Model\DataObject\Customer;
  9. use App\Model\Shop\Ticket\ShopTicketCatalog;
  10. use App\Model\Shop\Ticket\TicketProduct;
  11. use App\Service\Shop\JsonDataService;
  12. use App\Service\Shop\PricingRulesService;
  13. use App\Service\Shop\ProductService;
  14. use App\Service\Shop\ShopService;
  15. use App\Service\Shop\SmartPricerService;
  16. use App\Service\TicketShopFrameworkBundle\TicketFilter;
  17. use Carbon\Carbon;
  18. use CustomerManagementFrameworkBundle\CustomerProvider\CustomerProviderInterface;
  19. use CustomerManagementFrameworkBundle\Security\Authentication\LoginManager;
  20. use Elements\Bundle\RecurringDatesTypeBundle\Templating\RecurringDatesHelper;
  21. use Elements\Bundle\TicketShopFrameworkBundle\Ecommerce\PricingManager\PriceInfo;
  22. use Elements\Bundle\TicketShopFrameworkBundle\Model\Constant\AcquisitionType;
  23. use Elements\Bundle\TicketShopFrameworkBundle\Model\DataObject\TicketConsumerCategory;
  24. use Pimcore\Security\Hasher\PasswordFieldHasher;
  25. use Symfony\Component\HttpFoundation\Request;
  26. use Symfony\Component\HttpFoundation\Response;
  27. use Symfony\Component\PasswordHasher\Hasher\PasswordHasherFactoryInterface;
  28. use Symfony\Component\Routing\Annotation\Route;
  29. use Symfony\Contracts\Translation\TranslatorInterface;
  30. /**
  31.  * @Route("/{_locale}/shop/ticket")
  32.  */
  33. class TicketJsonController extends AbstractController
  34. {
  35.     /**
  36.      * @Route("/calendar-dates", name="json_ticket_calendar_dates", methods={"GET"})
  37.      */
  38.     public function calendarDatesJson(
  39.         Request $request,
  40.         ShopService $shopHelper,
  41.         SmartPricerService $smartPricerService,
  42.         RecurringDatesHelper $recurringDatesHelper,
  43.         ProductService $productService
  44.     ): Response {
  45.         $json = [];
  46.         $id intval($request->get('ticketId'));
  47.         if (empty($id)) {
  48.             return $this->json($json);
  49.         }
  50.         if ($catalog ShopTicketCatalog::getById($id)) {
  51.             $recurringDates $recurringDatesHelper->getCalculatedDates($catalog'getValidityDates');
  52.             $isMobile $request->get('isMobile');
  53.             $today Carbon::today();
  54.             $validDates $catalog->getFirstValidDateRange($today);
  55.             //for timePressure
  56.             $useDemandPressure $catalog->getUseDemandPressure();
  57.             /** @var Carbon $minDate */
  58.             $minDate $validDates['from']->gt($today) ? $validDates['from'] : $today;
  59.             $maxDate $shopHelper->getMaxValidityDate($recurringDates);
  60.             $maxDate $maxDate ?: $validDates['to'];
  61.             if ($request->get('shownStartYear') && $request->get('shownStartMonth')) {
  62.                 $shownStartDate Carbon::create($request->get('shownStartYear'), $request->get('shownStartMonth'));
  63.             } else {
  64.                 $shownStartDate = clone $minDate;
  65.                 $shownStartDate->startOfMonth();
  66.             }
  67.             if ($request->get('shownEndYear') && $request->get('shownEndMonth')) {
  68.                 $shownEndDate Carbon::create($request->get('shownEndYear'), $request->get('shownEndMonth'));
  69.             } else {
  70.                 $shownEndDate = clone $minDate;
  71.                 if ($isMobile === 'false') {
  72.                     $shownEndDate->addMonthWithoutOverflow();
  73.                 }
  74.             }
  75.             //after 15pm
  76.             if ($catalog->getUseNextDay() && $minDate->equalTo($today) && Carbon::now()->hour 15) {
  77.                 $minDate->addDay();
  78.             }
  79.             $calendarData = [];
  80.             $seasonDates $shopHelper->getSeasonDates($catalog);
  81.             if ($useDemandPressure) {
  82.                 $pressureEntries $smartPricerService->getDemandPressureEntries($shownStartDate->copy(), $shownEndDate->copy()->endOfMonth());
  83.                 $pressures = [];
  84.                 foreach ($pressureEntries as $pressureEntry) {
  85.                     $pressures[$pressureEntry['pointInTime']] = $pressureEntry['score'];
  86.                 }
  87.             }
  88.             while ($shownStartDate->lessThanOrEqualTo($shownEndDate)) {
  89.                 $dates = [];
  90.                 $month $shownStartDate->month;
  91.                 $year $shownStartDate->year;
  92.                 $tmpDate = clone $shownStartDate;
  93.                 while ($shownStartDate->lessThanOrEqualTo($tmpDate->endOfMonth())) {
  94.                     $data = [
  95.                         'id' => $id,
  96.                         'date' => $shownStartDate->toDateTimeLocalString(),
  97.                         'season' => $shopHelper->getSeasonNameForDate($seasonDates$shownStartDate),
  98.                     ];
  99.                     foreach ($recurringDates as $dateInfo) {
  100.                         if (!$shownStartDate->betweenIncluded($dateInfo['fromDate'], $dateInfo['toDate'])) {
  101.                             $data['disabled'] = true;
  102.                         } else {
  103.                             $data['disabled'] = false;
  104.                             break;
  105.                         }
  106.                     }
  107.                     //no demand pressure for the past
  108.                     if ($useDemandPressure && $shownStartDate->greaterThanOrEqualTo($today)) {
  109.                         $data['priceTendency'] = $productService->getPriceTendency($shownStartDate$pressures);
  110.                     }
  111.                     $dates[] = $data;
  112.                     $shownStartDate->addDay();
  113.                 }
  114.                 $calendarData[] = [
  115.                     'month' => $month,
  116.                     'year' => $year,
  117.                     'dates' => $dates,
  118.                 ];
  119.             }
  120.             $json = [
  121.                 'success' => true,
  122.                 'calendarConfiguration' => [
  123.                     'minDate' => $minDate->toDateTimeLocalString(),
  124.                     'maxDate' => $maxDate->toDateTimeLocalString(),
  125.                     'minSelectableDays' => $catalog->getMinSelectableDays(),
  126.                     'maxSelectableDays' => $catalog->getMaxSelectableDays(),
  127.                     'selectableValidities' => $catalog->getValidityDaysNumeric(),
  128.                     'minSelectableDates' => $catalog->getMinSelectableDates(),
  129.                     'maxSelectableDates' => $catalog->getMaxSelectableDates(),
  130.                 ],
  131.                 'calendarDates' => $calendarData,
  132.             ];
  133.         }
  134.         if ($json) {
  135.             return $this->json($json);
  136.         } elseif (\Pimcore::inDebugMode()) {
  137.             return $this->redirect('/faker-api/skiticket-configs/dates.json');
  138.         } else {
  139.             return $this->json([]);
  140.         }
  141.     }
  142.     /**
  143.      * @Route("/price", name="json_ticket_price", methods={"GET"})
  144.      *
  145.      * @param Request $request
  146.      * @param ShopService $shopHelper
  147.      * @param PricingRulesService $pricingRulesService
  148.      * @param TranslatorInterface $translator
  149.      *
  150.      * @return Response
  151.      */
  152.     public function priceJson(
  153.         Request $request,
  154.         ShopService $shopHelper,
  155.         PricingRulesService $pricingRulesService,
  156.         TranslatorInterface $translator
  157.     ): Response {
  158.         $json = [];
  159.         $priceInfo null;
  160.         if ($catalog ShopTicketCatalog::getById(intval($request->get('ticketId')))) {
  161.             $wrongRange false;
  162.             if (($selectedStartDate $request->get('selectedDateStart')) && ($selectedEndDate $request->get('selectedDateEnd'))) {
  163.                 $startDate Carbon::parse($selectedStartDate);
  164.                 $endDate Carbon::parse($selectedEndDate);
  165.                 $ticketAvailability $catalog->getAvailabilityForDateRange($startDate$endDate);
  166.                 if ($ticketAvailability->hasAvailability()) {
  167.                     $priceInfo $catalog->getLowestPriceInfoForAvailability($ticketAvailability);
  168.                 } else {
  169.                     $wrongRange true;
  170.                 }
  171.             } elseif ($selectedStartDate $request->get('selectedDateStart')) {
  172.                 $startDate Carbon::parse($selectedStartDate);
  173.                 $product $catalog->getProduct($startDate);
  174.                 if ($product) {
  175.                     $priceInfo $catalog->getPriceInfoForProduct($product$startDate);
  176.                 } else {
  177.                     $wrongRange true;
  178.                 }
  179.             } else {
  180.                 //initial price when opening the calendar
  181.                 $startDate Carbon::now();
  182.                 $product $catalog->getProduct();
  183.                 if ($product) {
  184.                     $priceInfo $catalog->getPriceInfoForProduct($product$startDate);
  185.                 } else {
  186.                     $wrongRange true;
  187.                 }
  188.             }
  189.             $json = [
  190.                 'success' => true,
  191.                 'data' => [
  192.                     'hideServiceView' => $shopHelper->isServiceViewHidden($catalog$startDate$endDate ?? nulltrue),
  193.                     'pricePerAdult' => $priceInfo $priceInfo->getPrice()->getGrossAmount()->asNumeric() : 0,
  194.                     'noAvailableDates' => $wrongRange,
  195.                 ],
  196.             ];
  197.             if ($priceInfo instanceof PriceInfo) {
  198.                 $product $priceInfo->getOriginalPriceInfo()->getProduct();
  199.                 if ($product instanceof TicketProduct && $presalesExpiredMessage $pricingRulesService->getPresaleExpiredMessage($startDate,
  200.                     $product$priceInfo)) {
  201.                     $json['data']['presalesExpiredMessage'] = $translator->trans($presalesExpiredMessage);
  202.                 } else {
  203.                     $json['data']['presalesExpiredMessage'] = '';
  204.                 }
  205.             }
  206.         }
  207.         return $this->json($json);
  208.     }
  209.     /**
  210.      * @Route("/price_tendency", name="json_ticket_price_tendency", methods={"GET"})
  211.      *
  212.      * @param Request $request
  213.      * @param SmartPricerService $smartPricerService
  214.      * @param TranslatorInterface $translator
  215.      *
  216.      * @return Response
  217.      */
  218.     public function priceTendencyJson(
  219.         Request $request,
  220.         SmartPricerService $smartPricerService,
  221.         TranslatorInterface $translator
  222.     ): Response {
  223.         $json = [];
  224.         if ($catalog ShopTicketCatalog::getById(intval($request->get('ticketId')))) {
  225.             $data = [];
  226.             if ($catalog->getPriceType() !== 'dynamicPrice') {
  227.                 $data['hidePriceTendency'] = true;
  228.             }
  229.             if (!$catalog->getUseTimePressure()) {
  230.                 return $this->json([
  231.                     'success' => true,
  232.                     'data' => $data,
  233.                 ]);
  234.             }
  235.             if ($selectedDate $request->get('selectedDateStart')) {
  236.                 $startDate Carbon::parse($selectedDate);
  237.             } else {
  238.                 $startDate $catalog->getFirstValidValidityDate(Carbon::now());
  239.             }
  240.             $endDate $request->get('selectedDateEnd') == null null Carbon::parse($request->get('selectedDateEnd'));
  241.             $filter = new TicketFilter($startDate$endDate);
  242.             $filter->setExactDuration(true);
  243.             $filter->setIgnorePrice(true);
  244.             $priceTendencyScore null;
  245.             if ($calendarConsumer $catalog->getCalendarPriceConsumerCategory()) {
  246.                 /** @var TicketConsumerCategory $calendarConsumer */
  247.                 $filter->setConsumers([$calendarConsumer->getId()]);
  248.                 $availabilities $filter->getTicketCatalogAvailability($catalogfalse);
  249.                 $skidataProduct null;
  250.                 if ($availabilities->hasAvailability()) {
  251.                     foreach ($availabilities->getTicketAvailability() as $ticketAvailability) {
  252.                         $ticketProduct $ticketAvailability->getTicketProduct();
  253.                         if (!$ticketProduct->getIgnoreTimePressure()) {
  254.                             $skidataProduct $ticketProduct->getSkidataProduct();
  255.                             break;
  256.                         }
  257.                     }
  258.                 }
  259.                 if ($skidataProduct) {
  260.                     $consumer $calendarConsumer->getSkidataConsumerForSkidataProduct($skidataProduct);
  261.                     $priceTendencyScore $smartPricerService->getTimePressure($skidataProduct->getExternalId(), $consumer->getExternalId(), $startDate);
  262.                 }
  263.             }
  264.             $data = [];
  265.             if ($priceTendencyScore) {
  266.                 $allowedLevels = ['low''rather-low''normal'];
  267.                 $pressureText $smartPricerService->getPressureText($priceTendencyScore['textScore']);
  268.                 $pressureDescription $smartPricerService->getPriceAvailabilityText(1.01 $priceTendencyScore['score']);
  269.                 $data['priceTendency'] = $pressureText;
  270.                 $data['percentage'] = 100 - ($priceTendencyScore['score'] * 99.9);
  271.                 $data['percentageDescription'] = $translator->trans('pricing.' $pressureDescription);
  272.                 $data['percentageDescriptionInfo'] = '';
  273.                 $data['additionalPriceInfo'] = in_array($pressureText$allowedLevels) ? $translator->trans('price-tendency.price-info.' $pressureText) : '';
  274.             }
  275.             $json = [
  276.                 'success' => true,
  277.                 'data' => $data,
  278.             ];
  279.         }
  280.         return $this->json($json);
  281.     }
  282.     /**
  283.      * @Route("/pricing", name="json_ticket_pricing", methods={"GET"})
  284.      *
  285.      * @param Request $request
  286.      * @param ShopService $shopHelper
  287.      * @param JsonDataService $jsonDataService
  288.      *
  289.      * @return Response
  290.      */
  291.     public function pricingJson(Request $requestShopService $shopHelperJsonDataService $jsonDataService): Response
  292.     {
  293.         $json = [];
  294.         if ($catalog ShopTicketCatalog::getById(intval($request->get('ticketId')))) {
  295.             $startDate Carbon::parse($request->get('selectedDateStart'));
  296.             if ($selectedEndDate $request->get('selectedDateEnd')) {
  297.                 $endDate Carbon::parse($selectedEndDate);
  298.             } else {
  299.                 $endDate $startDate->copy();
  300.             }
  301.             $filter = new TicketFilter($startDate$endDate);
  302.             $filter->setExactDuration(true);
  303.             $filter->setUseTicketValidity(true);
  304.             $filter->setIgnorePrice(true);
  305.             $allowedConsumers = [];
  306.             foreach ($catalog->getTicketConsumerCategories() as $allowedConsumer) {
  307.                 $allowedConsumers[] = $allowedConsumer->getId();
  308.             }
  309.             if ($allowedConsumers) {
  310.                 $filter->setConsumers($allowedConsumers);
  311.             }
  312.             $catalogAvailability $filter->getTicketCatalogAvailability($catalogtrue);
  313.             $originalConsumerGroups $jsonDataService->getPriceGroupObjects($catalogAvailability);
  314.             if ($catalogAvailability->hasAvailability()) {
  315.                 $insuranceData $shopHelper->getInsurancesForProduct($catalogAvailability);
  316.                 $insurances $insuranceData['insurances'] ?? [];
  317.                 $jsonDataService->setStartDate($startDate);
  318.                 $jsonDataService->setEndDate($endDate);
  319.                 $priceConfigurations $jsonDataService->getPriceForCatalogAvailability($catalogAvailability$insurances$originalConsumerGroups$startDate$endDate);
  320.                 $json = [
  321.                     'success' => true,
  322.                     'isAgeGroup' => true,
  323.                     'priceGroups' => $jsonDataService->getPriceGroupJson($catalogAvailability),
  324.                     'priceConfigurations' => $priceConfigurations,
  325.                 ];
  326.                 // special info modal when adding a consumer that meets the condition of a hta consumer or the saturday child
  327.                 if ($specialPriceModal $jsonDataService->getSpecialPriceModals($catalogAvailability)) {
  328.                     $json['specialPriceModals'] = $specialPriceModal;
  329.                 }
  330.             }
  331.         }
  332.         return $this->json($json);
  333.     }
  334.     /**
  335.      * @Route("/services", name="json_services", methods={"GET"})
  336.      *
  337.      * @param Request $request
  338.      * @param TranslatorInterface $translator
  339.      * @param ShopService $shopHelper
  340.      *
  341.      * @return Response
  342.      */
  343.     public function servicesJson(Request $requestTranslatorInterface $translatorShopService $shopHelper): Response
  344.     {
  345.         $json = [];
  346.         if ($catalog ShopTicketCatalog::getById(intval($request->get('ticketId')))) {
  347.             $startDate Carbon::parse($request->get('selectedDateStart'));
  348.             if ($selectedEndDate $request->get('selectedDateEnd')) {
  349.                 $endDate Carbon::parse($selectedEndDate);
  350.             } else {
  351.                 $endDate $startDate->copy();
  352.             }
  353.             $filter = new TicketFilter($startDate$endDate);
  354.             $filter->setExactDuration(true);
  355.             $filter->setIgnorePrice(true);
  356.             $filter->setUseTicketValidity(true);
  357.             $allowedConsumers = [];
  358.             foreach ($catalog->getTicketConsumerCategories() as $allowedConsumer) {
  359.                 $allowedConsumers[] = $allowedConsumer->getId();
  360.             }
  361.             if ($allowedConsumers) {
  362.                 $filter->setConsumers($allowedConsumers);
  363.             }
  364.             $catalogAvailability $filter->getTicketCatalogAvailability($catalogtrue);
  365.             $options = [];
  366.             $insurances = [];
  367.             $upgrades = [];
  368.             $upgradeCatalog $catalog->getUpgrades();
  369.             if ($catalogAvailability->hasAvailability()) {
  370.                 $insuranceData $shopHelper->getInsurancesForProduct($catalogAvailability);
  371.                 $insuranceObjects $insuranceData['insurances'] ?? [];
  372.                 foreach ($catalogAvailability->getTicketAvailability() as $availability) {
  373.                     /** @var TicketProduct $ticketProduct */
  374.                     $ticketProduct $availability->getTicketProduct();
  375.                     $metaProduct $ticketProduct->getMetaProduct();
  376.                     $insuranceIds = [];
  377.                     $optionUpgrades = [];
  378.                     if ($insuranceObjects) {
  379.                         /** @var TicketProduct $insurance */
  380.                         foreach ($insuranceObjects[$ticketProduct->getId()] as $insurance) {
  381.                             $mappingObject $insuranceData['mappingObject'][$insurance->getId()];
  382.                             $insuranceIds[] = (string)$insurance->getId();
  383.                             $insurances[] = [
  384.                                 'id' => (string)$insurance->getId(),
  385.                                 'label' => (string)$mappingObject->getName(),
  386.                                 'labelSubText' => (string)$insurance->getTextDateSelectOverlay(),
  387.                                 'info' => (string)($mappingObject->getDescription() ?: $insurance->getDescription()),
  388.                             ];
  389.                         }
  390.                     }
  391.                     foreach ($catalog->getUpgrades() as $upgrade) {
  392.                         if (!str_contains($upgrade->getData()['name'], ',')) {
  393.                             /** @var ShopTicketCatalog $upgradeObject */
  394.                             $upgradeObject $upgrade->getObject();
  395.                             $upgradeFilter = new TicketFilter($startDate$endDate);
  396.                             $upgradeFilter->setExactDuration(true);
  397.                             $upgradeFilter->setIgnorePrice(true);
  398.                             $upgradeFilter->setUseTicketValidity(true);
  399.                             $upgradeCatalogAvailability $upgradeFilter->getTicketCatalogAvailability($upgradeObjecttrue);
  400.                             if ($upgradeCatalogAvailability->hasAvailability() && !$upgradeObject->getIsNotBookable()) {
  401.                                 //upgrade insurances
  402.                                 if ($upgradeInsuranceData $shopHelper->getInsurancesForProduct($upgradeCatalogAvailability)) {
  403.                                     if ($upgradeInsuranceObjects $upgradeInsuranceData['insurances'] ?? []) {
  404.                                         foreach ($upgradeCatalogAvailability->getTicketAvailability() as $upgradeTicketAvailability) {
  405.                                             $upgradeTicketProduct $upgradeTicketAvailability->getTicketProduct();
  406.                                             /** @var TicketProduct $insurance */
  407.                                             foreach ($upgradeInsuranceObjects[$upgradeTicketProduct->getId()] as $insurance) {
  408.                                                 $mappingObject $upgradeInsuranceData['mappingObject'][$insurance->getId()];
  409.                                                 $insuranceIds[] = (string)$insurance->getId();
  410.                                                 $insurances[] = [
  411.                                                     'id' => (string)$insurance->getId(),
  412.                                                     'label' => (string)$mappingObject->getName(),
  413.                                                     'labelSubText' => (string)$insurance->getTextDateSelectOverlay(),
  414.                                                     'info' => (string)($mappingObject->getDescription() ?: $insurance->getDescription()),
  415.                                                 ];
  416.                                             }
  417.                                         }
  418.                                     }
  419.                                 }
  420.                                 //special logic for flex passes where there is no shuttle
  421.                                 if ($metaProduct) {
  422.                                     if (array_intersect($metaProduct->getRelatedTo(), $upgradeObject->getTicketProducts())) {
  423.                                         $optionUpgrades[] = (string)$upgradeObject->getId();
  424.                                     }
  425.                                 } else {
  426.                                     $optionUpgrades[] = (string)$upgradeObject->getId();
  427.                                 }
  428.                             }
  429.                         }
  430.                     }
  431.                     if ($insuranceIds) {
  432.                         $insuranceIds array_values(array_unique($insuranceIds));
  433.                     }
  434.                     $options[] = [
  435.                         'id' => (string)$ticketProduct->getId(),
  436.                         'label' => (string)$ticketProduct->getName(),
  437.                         'labelSubText' => (string)$ticketProduct->getTextDateSelectOverlay(),
  438.                         'info' => (string)$ticketProduct->getDescription(),
  439.                         'upgrades' => $optionUpgrades,
  440.                         'insurances' => $insuranceIds,
  441.                     ];
  442.                 }
  443.             }
  444.             foreach ($upgradeCatalog as $upgrade) {
  445.                 if (!str_contains($upgrade->getData()['name'], ',')) {
  446.                     /** @var ShopTicketCatalog $upgradeObject */
  447.                     $upgradeObject $upgrade->getObject();
  448.                     $upgrades[] = [
  449.                         'id' => (string)$upgradeObject->getId(),
  450.                         'label' => (string)$upgradeObject->getName(),
  451.                         'labelSubText' => (string)$upgradeObject->getTextDateSelectOverlay(),
  452.                         'info' => (string)$upgradeObject->getInfoBubbleDescription(),
  453.                         'warning' => $upgrade->getData()['warning'] ? $translator->trans('shop.warning-catalog-' $upgrade->getData()['name']) : '',
  454.                     ];
  455.                 }
  456.             }
  457.             $noDuplicateInsurances array_values(array_intersect_key($insurancesarray_unique(array_map('serialize'$insurances))));
  458.             $json = [
  459.                 'success' => true,
  460.                 'serviceDescription' => $catalog->getServicesDescription() ?? '',
  461.                 'options' => $options,
  462.                 'upgrades' => $upgrades,
  463.                 'insurances' => $noDuplicateInsurances,
  464.             ];
  465.         }
  466.         return $this->json($json);
  467.     }
  468.     /**
  469.      * @Route("/login-data", name="json_login_data")
  470.      *
  471.      * @param Request $request
  472.      * @param LoginManager $loginManager
  473.      * @param CustomerProviderInterface $customerProvider
  474.      * @param PasswordHasherFactoryInterface $hasherFactory
  475.      * @param TranslatorInterface $translator
  476.      *
  477.      * @return Response
  478.      */
  479.     public function loginCalendarJson(
  480.         Request $request,
  481.         LoginManager $loginManager,
  482.         CustomerProviderInterface $customerProvider,
  483.         PasswordHasherFactoryInterface $hasherFactory,
  484.         TranslatorInterface $translator
  485.     ): Response {
  486.         //get user if logged in
  487.         $user $this->getUser();
  488.         $redirectData = [
  489.             'ticketId' => $request->get('ticketId'),
  490.             'option' => $request->get('option'),
  491.             'selectedDateStart' => $request->get('selectedDateStart'Carbon::today()->toDateTimeLocalString()),
  492.         ];
  493.         if (!$user instanceof Customer) {
  494.             $email $request->get('email');
  495.             $password $request->get('password');
  496.             if (!$email || !$password) {
  497.                 return $this->getErrorJson($translator->trans('error.login.no-user-or-password'));
  498.             }
  499.             /** @var Customer|null $user */
  500.             $user $customerProvider->getActiveCustomerByEmail($email);
  501.             if ($user) {
  502.                 /** @var PasswordFieldHasher $passwordHasher */
  503.                 $passwordHasher $hasherFactory->getPasswordHasher($user);
  504.                 //check if password is correct and log in user
  505.                 if ($passwordHasher->isPasswordValid(true$password)) {
  506.                     $loginManager->login($user$request);
  507.                     return $this->redirectToRoute('json_person_data'$redirectData);
  508.                 } else {
  509.                     return $this->getErrorJson($translator->trans('error.login.wrong-user-or-password'));
  510.                 }
  511.             } else {
  512.                 return $this->getErrorJson($translator->trans('error.login.wrong-user-or-password'));
  513.             }
  514.         }
  515.         return $this->redirectToRoute('json_person_data'$redirectData);
  516.     }
  517.     /**
  518.      * @Route("/person-data", name="json_person_data")
  519.      *
  520.      * @param Request $request
  521.      *
  522.      * @return Response
  523.      */
  524.     public function personDataJson(Request $request): Response
  525.     {
  526.         /** @var Customer $user */
  527.         $user $this->getUser();
  528.         $ticket TicketProduct::getById((int)$request->get('option'));
  529.         $validityDate Carbon::parse($request->get('selectedDateStart'Carbon::today()));
  530.         $consumerCategories $ticket->getConsumerCategories();
  531.         $persons = [];
  532.         $userAgeGroup null;
  533.         foreach ($consumerCategories as $consumerCategory) {
  534.             /** @phpstan-ignore-next-line */
  535.             if ($user->getBirthdate() && $user->getBirthdate()->between($validityDate->clone()->subYears($consumerCategory->getYearFrom()), $validityDate->clone()->subYears($consumerCategory->getYearTo() + 1)->addDay())) {
  536.                 $userAgeGroup $consumerCategory;
  537.                 break;
  538.             }
  539.         }
  540.         if ($userAgeGroup) {
  541.             $persons[] = [
  542.                 'id' => (string)$user->getId(),
  543.                 'name' => $user->getFullname(),
  544.                 'priceGroup' => (string)$userAgeGroup->getId(),
  545.             ];
  546.         }
  547.         foreach ($user->getContacts() as $contact) {
  548.             $ageGroup null;
  549.             $birthday $contact->getBirthday();
  550.             foreach ($consumerCategories as $consumerCategory) {
  551.                 /** @phpstan-ignore-next-line */
  552.                 if ($birthday && $birthday->between($validityDate->clone()->subYears($consumerCategory->getYearFrom()), $validityDate->clone()->subYears($consumerCategory->getYearTo() + 1)->addDay())) {
  553.                     $ageGroup $consumerCategory;
  554.                     break;
  555.                 }
  556.             }
  557.             if (!empty($ageGroup)) {
  558.                 $persons[] = [
  559.                     'id' => (string)$contact->getId(),
  560.                     'name' => $contact->getFullname(),
  561.                     'priceGroup' => (string)$ageGroup->getId(),
  562.                 ];
  563.             }
  564.         }
  565.         $json = [
  566.             'success' => true,
  567.             'errorMessage' => '',
  568.             'persons' => $persons,
  569.         ];
  570.         return $this->json($json);
  571.     }
  572.     /**
  573.      * @Route("/b2b-tickets", name="json_b2b_tickets")
  574.      *
  575.      * @param Request $request
  576.      * @param TranslatorInterface $translator
  577.      *
  578.      * @return Response
  579.      */
  580.     public function b2bTicketsJson(Request $requestTranslatorInterface $translator): Response
  581.     {
  582.         $catalog null;
  583.         $date $request->get('selectedDateStart');
  584.         if ($catalogId = (int)$request->get('ticketId')) {
  585.             $catalog ShopTicketCatalog::getById($catalogId);
  586.         }
  587.         if (empty($catalog) || empty($date)) {
  588.             return $this->json([
  589.                 'success' => true,
  590.                 'ticketTypes' => [],
  591.             ]);
  592.         }
  593.         $ticketTypes = [];
  594.         $date Carbon::create($date);
  595.         $map = [];
  596.         if ($dateRange $catalog->getFirstValidDateRange($date)) {
  597.             $availabilities $catalog->getAvailabilityForDateRange($date$dateRange['to'], falsetrue);
  598.             if ($availabilities->hasAvailability()) {
  599.                 foreach ($availabilities->getTicketAvailability() as $ticketAvailability) {
  600.                     $product $ticketAvailability->getTicketProduct();
  601.                     if (in_array($product->getValidity(), $map)) {
  602.                         continue;
  603.                     }
  604.                     $ticketTypes[] = [
  605.                         'value' => $product->getValidity(),
  606.                         'label' => $translator->trans('ticket.' $product->getValidity() . '-days'),
  607.                         'dayRange' => $product->getValidity(),
  608.                         'hasServices' => true,
  609.                     ];
  610.                     $map[] = $product->getValidity();
  611.                 }
  612.             }
  613.         }
  614.         $json = [
  615.             'success' => true,
  616.             'ticketTypes' => $ticketTypes,
  617.         ];
  618.         return $this->json($json);
  619.     }
  620.     /**
  621.      * @Route("/tour-operator-tickets", name="json_tourOperator_tickets")
  622.      *
  623.      * @param Request $request
  624.      * @param TranslatorInterface $translator
  625.      *
  626.      * @return Response
  627.      */
  628.     public function tourOperatorTicketsJson(Request $requestTranslatorInterface $translator): Response
  629.     {
  630.         $catalog null;
  631.         $date $request->get('selectedDateStart');
  632.         if ($catalogId = (int)$request->get('ticketId')) {
  633.             $catalog ShopTicketCatalog::getById($catalogId);
  634.         }
  635.         if (empty($catalog) || empty($date)) {
  636.             return $this->json([
  637.                 'success' => true,
  638.                 'ticketTypes' => [],
  639.             ]);
  640.         }
  641.         $ticketTypes = [];
  642.         $date Carbon::create($date);
  643.         $map = [];
  644.         if ($dateRange $catalog->getFirstValidDateRange($date)) {
  645.             $availabilities $catalog->getAvailabilityForDateRange($date$dateRange['to'], falsetrue);
  646.             if ($availabilities->hasAvailability()) {
  647.                 foreach ($availabilities->getTicketAvailability() as $ticketAvailability) {
  648.                     $product $ticketAvailability->getTicketProduct();
  649.                     if (in_array($product->getValidity(), $map)) {
  650.                         continue;
  651.                     }
  652.                     if (!is_array($product->getAllowedAcquisitionTypes())
  653.                         || !in_array(AcquisitionType::TICKETPICKUP$product->getAllowedAcquisitionTypes(), true)
  654.                     ) {
  655.                         continue;
  656.                     }
  657.                     $ticketTypes[] = [
  658.                         'value' => $product->getValidity(),
  659.                         'label' => $translator->trans('ticket.' $product->getValidity() . '-days'),
  660.                         'dayRange' => $product->getValidity(),
  661.                         'hasServices' => true,
  662.                     ];
  663.                     $map[] = $product->getValidity();
  664.                 }
  665.             }
  666.         }
  667.         $json = [
  668.             'success' => true,
  669.             'ticketTypes' => $ticketTypes,
  670.         ];
  671.         return $this->json($json);
  672.     }
  673.     /**
  674.      * @param string $message
  675.      *
  676.      * @return Response
  677.      */
  678.     private function getErrorJson(string $message): Response
  679.     {
  680.         return $this->json([
  681.             'success' => false,
  682.             'errorMessage' => $message,
  683.             'persons' => [],
  684.         ]);
  685.     }
  686. }