<?php
/**
* Created by Elements.at New Media Solutions GmbH
*
*/
namespace App\Controller\Shop\Json;
use App\Controller\AbstractController;
use App\Service\Shop\JsonDataService;
use App\Service\Shop\ProductService;
use App\Service\Shop\ShopService;
use App\Service\Shop\SmartPricerService;
use App\Service\SiteConfigService;
use App\Twig\LinkGeneratorExtension;
use Carbon\Carbon;
use Elements\Bundle\RecurringDatesTypeBundle\Templating\RecurringDatesHelper;
use Pimcore\Model\DataObject\ShopTicketCatalog;
use Pimcore\Model\DataObject\TicketConsumerCategory;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* @Route("/{_locale}/shop/pricecalculator")
*/
class PriceCalculatorJsonController extends AbstractController
{
/**
* @Route("/basic-info", name="json_priceCalculator_basic_info", methods={"GET"})
*
* @param Request $request
* @param ProductService $productService
* @param TranslatorInterface $translator
*
* @return Response
*/
public function basicInfoJson(Request $request, ProductService $productService, TranslatorInterface $translator): Response
{
$catalogs = new ShopTicketCatalog\Listing();
$catalogs->addConditionParam('hideInListing IS NULL OR hideInListing = ""');
$data = $productService->getAvailableCategoryInterests($catalogs);
// interests
$interests = [
'title' => $translator->trans('shop.pricecalculator.basicinfos.interests'),
'type' => 'radio',
'data' => [],
];
foreach ($data['interests'] as $interest) {
$interests['data'][] = [
'id' => strval($interest->getId()),
'label' => $interest->getName() ?? '',
'categories' => array_map('strval', $data['categoriesPerInterest'][$interest->getId()]),
];
}
// categories
$categories = [
'title' => $translator->trans('shop.pricecalculator.basicinfos.categories'),
'type' => 'checkbox',
'data' => [],
];
foreach ($data['categories'] as $category) {
$categories['data'][] = [
'id' => strval($category->getId()),
'label' => $category->getName() ?? '',
];
}
// price groups
$priceGroups = [
'title' => $translator->trans('shop.pricecalculator.basicinfos.pricegroups'),
'type' => 'checkbox',
'data' => [],
];
$consumerCategories = new TicketConsumerCategory\Listing();
$consumerCategories->setOrderKey('order');
$consumerCategories->setOrder('desc');
foreach ($consumerCategories as $consumerCategory) {
if (!$consumerCategory->hasChildren()) {
continue;
}
$priceGroups['data'][] = [
'id' => strval($consumerCategory->getId()),
'label' => $consumerCategory->getName() ?? '',
'labelPlural' => $consumerCategory->getName() ?? '',
];
}
$json = [
'success' => true,
'interests' => $interests,
'categories' => $categories,
'priceGroups' => $priceGroups,
];
return $this->json($json);
}
/**
* @Route("/calendar", name="json_priceCalculator_calendar", methods={"GET"})
*
* @param Request $request
* @param ShopService $shopHelper
* @param SmartPricerService $smartPricerService
* @param SiteConfigService $siteConfigService
* @param ProductService $productService
* @param RecurringDatesHelper $recurringDatesHelper
*
* @return Response
*/
public function calendarJson(
Request $request,
ShopService $shopHelper,
SmartPricerService $smartPricerService,
SiteConfigService $siteConfigService,
ProductService $productService,
RecurringDatesHelper $recurringDatesHelper): Response
{
$interestId = $shopHelper->extractIdsFromString($request->get('selectedInterestIDs'), true);
$categoryIds = $shopHelper->extractIdsFromString($request->get('selectedCategoryIDs'));
$priceGroupIds = $shopHelper->extractIdsFromString($request->get('selectedPriceGroupIDs'));
$dateRange = $shopHelper->getDatesForPriceCalculator($request);
$startDate = $dateRange['startDate'];
$endDate = $dateRange['endDate'];
$date = $startDate->copy();
$seasonDates = $shopHelper->modifySeasonDates($siteConfigService->getSiteConfig()->getPriceCalculatorSeasons());
// preparation for demand pressure
$pressures = [];
foreach ($smartPricerService->getDemandPressureEntries($startDate->copy(), $endDate->copy()) as $pressureEntry) {
$pressures[$pressureEntry['pointInTime']] = $pressureEntry['score'];
}
$isFirstLoad = !($interestId && $categoryIds && $priceGroupIds);
$selectableValidities = [];
if (!$isFirstLoad) {
$catalogs = new ShopTicketCatalog\Listing();
$catalogs->addConditionParam('hideInListing IS NULL OR hideInListing = ""');
$catalogs = $productService->getFilteredCatalogs($catalogs, $interestId, $categoryIds, $priceGroupIds);
$catalogs = $catalogs->load();
/** @var \App\Model\Shop\Ticket\ShopTicketCatalog $catalog */
foreach ($catalogs as $catalog) {
$selectableValidities = array_merge($selectableValidities, $catalog->getValidityDaysNumeric());
}
$selectableValidities = array_unique($selectableValidities);
sort($selectableValidities);
/** @var \App\Model\Shop\Ticket\ShopTicketCatalog[] $catalogs */
[$recurringDates, $useNextDayForAll, $minSelectableDates, $maxSelectableDates, $minSelectableDays, $maxSelectableDays] =
$productService->getPriceCalculatorData($catalogs);
$lowestFromDate = $shopHelper->getMinValidityDate($recurringDates);
$minDate = $lowestFromDate->gt(Carbon::today())
? $lowestFromDate->copy()
: ($useNextDayForAll && Carbon::now()->hour > 15 ? Carbon::tomorrow() : Carbon::today());
$maxDate = $shopHelper->getMaxValidityDate($recurringDates) ?: $endDate->copy();
} else {
$minDate = Carbon::now()->hour > 15 ? Carbon::tomorrow() : Carbon::today();
$maxDate = $endDate->copy();
}
$json = [
'success' => true,
'calendarConfiguration' => [
'minDate' => $minDate->toDateTimeLocalString(),
'maxDate' => $maxDate->toDateTimeLocalString(),
'minSelectableDays' => $isFirstLoad ? 1 : $minSelectableDays,
'maxSelectableDays' => $isFirstLoad ? 30 : $maxSelectableDays,
'selectableValidities' => $selectableValidities,
'minSelectableDates' => $isFirstLoad ? 1 : $minSelectableDates,
'maxSelectableDates' => $isFirstLoad ? 2 : $maxSelectableDates,
],
'calendarDates' => $shopHelper->buildCalendarData($date, $endDate, $minDate, $seasonDates, $pressures),
];
return $this->json($json);
}
/**
* @Route("/price-groups", name="json_priceCalculator_price_groups", methods={"GET"})
*
* @param Request $request
* @param ProductService $productService
* @param TranslatorInterface $translator
* @param ShopService $shopHelper
*
* @return Response
*/
public function priceGroupsJson(
Request $request,
ProductService $productService,
TranslatorInterface $translator,
ShopService $shopHelper): Response
{
$interestId = $shopHelper->extractIdsFromString($request->get('selectedInterestIDs'), true);
$categoryIds = $shopHelper->extractIdsFromString($request->get('selectedCategoryIDs'));
$catalogs = new ShopTicketCatalog\Listing();
$catalogs->addConditionParam('hideInListing IS NULL OR hideInListing = ""');
$data = $productService->getFilteredPriceGroups($catalogs, $interestId, $categoryIds);
$priceGroups = [
'title' => $translator->trans('shop.pricecalculator.basicinfos.pricegroups'),
'type' => 'checkbox',
'data' => [],
];
/** @var TicketConsumerCategory $priceGroup */
foreach ($data as $priceGroup) {
$priceGroups['data'][] = [
'id' => strval($priceGroup->getId()),
'label' => $priceGroup->getName() ?? '',
'labelPlural' => $priceGroup->getName() ?? '',
];
}
return $this->json([
'success' => true,
'priceGroups' => $priceGroups,
]);
}
/**
* @Route("/tickets", name="json_priceCalculator_tickets", methods={"GET"})
*
* @param Request $request
*
* @return Response
*/
public function ticketsJson(
Request $request,
ShopService $shopHelper,
ProductService $productService,
JsonDataService $jsonDataService,
LinkGeneratorExtension $linkGenerator
): Response {
$interestId = $shopHelper->extractIdsFromString($request->get('selectedInterestIDs'), true);
$categoryIds = $shopHelper->extractIdsFromString($request->get('selectedCategoryIDs'));
$priceGroupIds = $shopHelper->extractIdsFromString($request->get('selectedPriceGroupIDs'));
$startDate = $request->get('startDate') ? Carbon::parse($request->get('startDate')) : null;
$endDate = $request->get('endDate') ? Carbon::parse($request->get('endDate')) : $startDate->copy();
$catalogs = new ShopTicketCatalog\Listing();
$catalogs->addConditionParam('hideInListing IS NULL OR hideInListing = ""');
$catalogs->setOrderKey('sort');
$catalogs->setOrder('desc');
$catalogs = $productService->getFilteredCatalogs($catalogs, $interestId, $categoryIds, $priceGroupIds);
$catalogs = $catalogs->load();
$data = [];
/** @var \App\Model\Shop\Ticket\ShopTicketCatalog $catalog */
foreach ($catalogs as $catalog) {
if (!$catalog->isAvailableInDateRange($startDate, $endDate)) {
continue;
}
// for normal tickets without upgrades
$allowedConsumerIds = $shopHelper->getCorrectAllowedConsumerIds($catalog, $priceGroupIds);
$availability = $catalog->getAvailabilityForDateRangeWithPriceGroup($allowedConsumerIds, $startDate, $endDate, true);
if (!$availability->hasAvailability() || $catalog->getIgnoreTicketsInPriceCalculator()) {
// $finalPriceGroups = array_map(fn ($id) => TicketConsumerCategory::getById($id), $priceGroupIds);
$catalog = $catalog->getBaseCatalog();
$data[] = [
'catalogTitle' => $catalog->getName(),
'tickets' => [
[
'ticketTitle' => $catalog->getName(),
'startDate' => $startDate->toDateTimeLocalString(),
'endDate' => $endDate->toDateTimeLocalString(),
'ticketId' => strval($catalog->getId()),
'isAnnualPass' => $catalog->getIsAnnualCatalog() ?? false,
'isNotBookable' => true, // important for showing the link to the detail page
'pathToDetailPage' => $linkGenerator->getDetailLink($catalog),
'data' => [],
],
],
];
continue;
}
$tickets = []; // all tickets per catalog
foreach ($availability->getTicketAvailability() as $ticket) {
$tickets[] = $jsonDataService->getTicketData($catalog, $ticket, $startDate, $endDate); // normal ticket without upgrades
if ($catalog->getUpgrades()) {
$tickets = array_merge(
$tickets,
$jsonDataService->getTicketUpgradeData($catalog, $startDate, $endDate, $ticket, $priceGroupIds)
);
}
}
$data[] = [
'catalogTitle' => $catalog->getName(),
'tickets' => $tickets,
];
}
$json = [
'success' => true,
'data' => $data,
];
return $this->json($json);
}
}