<?php
/**
* Elements DeMI
*
* This source file is available under the elements DeMI license version 1
*
* @copyright Copyright (c) elements.at New Media Solutions GmbH (https://www.elements.at/)
* @license elements DeMI Lizenz Version 1 (https://www.elements.at/de/demi-lizenz)
*/
namespace Elements\Bundle\DemiFrontendBundle\Controller;
use Carbon\Carbon;
use Carbon\Traits\Creator;
use Elements\Bundle\CmsToolsBundle\Tool\Helper\ElementsCustomDateFormat;
use Elements\Bundle\DemiFrontendBundle\Event\DemiDirectInquiryEvent;
use Elements\Bundle\DemiFrontendBundle\Service\AdditionalService;
use Elements\Bundle\DemiFrontendBundle\Service\CartItemInfo;
use Elements\Demi\Frontend\Service\Configuration;
use Elements\Bundle\DemiFrontendBundle\Service\ConnectedEntryProvider;
use Elements\Bundle\DemiFrontendBundle\Service\EcommerceHelper;
use Elements\Bundle\DemiFrontendBundle\Service\PaginatorHelper;
use Elements\Bundle\DemiFrontendBundle\Service\Payment;
use Elements\Demi\AdditionalService\Search\Listing;
use Elements\Demi\AdditionalService\Search\Parameter;
use Elements\Demi\AdditionalService\Search\Parameter\Line;
use Elements\Demi\Deskline\AdditionalService\Search\Adapter;
use Elements\Demi\Deskline\Config;
use Elements\Demi\Deskline\Constant\AddressInterface;
use Elements\Demi\Deskline\Constant\DescriptionInterface;
use Elements\Demi\Deskline\Constant\FacilityGroupTypeInterface;
use Elements\Demi\Deskline\Service\Search\CancellationInformation;
use Elements\Demi\Info\CartItemInfoHolder;
use Elements\Demi\Model\AdditionalProduct;
use Elements\Demi\Model\AdditionalServiceProvider;
use ErrorException;
use Exception;
use InvalidArgumentException;
use Pimcore\Bundle\EcommerceFrameworkBundle\Factory;
use Pimcore\Bundle\EcommerceFrameworkBundle\Tracking\TrackingManager;
use Pimcore\Db;
use Pimcore\Model\DataObject;
use Pimcore\Model\DataObject\AbstractObject;
use Pimcore\Model\DataObject\DemiAdditionalService;
use Pimcore\Model\DataObject\DemiFilterObject;
use Pimcore\Model\Document;
use Pimcore\Model\Document\Editable\Areablock;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\GoneHttpException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Validator\Constraints\Email;
use Symfony\Component\Validator\Validator\ValidatorInterface;
class AdditionalServiceController extends AbstractDemiController
{
public function __construct(protected EcommerceHelper $ecommerceHelper,
protected CartItemInfo $cartItemInfoService,
protected Payment $paymentHelper,
protected array $enabledFeatures,
protected ConnectedEntryProvider $connectedEntryProvider,
protected Listing $additionalServiceListingLive,
protected Listing $additionalServiceListingLocal,
protected TrackingManager $trackingManager,
protected AdditionalService $additionalServiceService,
Configuration $config,
protected PaginatorHelper $paginatorHelper,
protected Adapter $adapter,
ElementsCustomDateFormat $elementsCustomDateFormat,
ContainerInterface $container,
protected SavingRequestController $savingRequestController,
protected ?ValidatorInterface $emailValidator = null)
{
$this->setElementsCustomDateFormat($elementsCustomDateFormat);
$this->setConfiguration($config);
$this->setContainer($container);
if ($emailValidator === null) {
$this->emailValidator = $this->container->get('validator.email');
}
}
public function overviewAction(Request $request) : Response
{
if (!$this->enabledFeatures['additionalServices']) {
throw new Exception('AdditionalServices are not enabled!');
}
$editablePrefix = $this->findEditablePrefix($this->document);
$providerId = DataObject\DemiAdditionalServiceProvider::classId();
$productId = DataObject\DemiAdditionalProduct::classId();
$items = new DemiAdditionalService\Listing();
$serviceId = $items->getClassId();
$lang = $request->getLocale();
$dateBegin = htmlentities($request->get('from'));
if (empty($dateBegin)) {
$dateBegin = new Carbon();
$dateBegin->startOfDay();
} else {
$dateBegin = $this->elementsCustomDateFormat->stringToCarbon($dateBegin);
}
$dateEnd = htmlentities($request->get('to'));
if (empty($dateEnd)) {
$dateEnd = $dateBegin->copy()->addYear();
} else {
$dateEnd = $this->elementsCustomDateFormat->stringToCarbon($dateEnd);
}
$text = $request->get('keyword');
if (!empty($text)) {
$items->addConditionParam(Db::get()->quoteIdentifier('name') . ' LIKE ' . Db::get()->quote('%' . $text . '%'));
$viewParams["text"] = htmlentities(nl2br($text));
}
$selectedHolidayTheme = $request->get('category');
$predefinedHolidayThemes = $this->document->getEditable($editablePrefix . 'holidayThemes')->getData();
if (!empty($selectedHolidayTheme)) {
$obj = AbstractObject::getById($selectedHolidayTheme);
if ($obj instanceof DataObject\DemiFilterObject) {
foreach ($obj->getFilterElements() as $theme) {
$themeids[] = $theme->getId();
}
} else {
$themeids[] = $selectedHolidayTheme;
}
$items->addConditionParam("object_localized_{$serviceId}_{$lang}.o_id in (select o_parentId from object_$productId where object_$productId.o_id in (select src_id from object_relations_$productId where dest_id in (". implode(',', $themeids) . ") and fieldname = 'holidaythemes'))");
} elseif (!empty($predefinedHolidayThemes)) {
$themeids = [];
foreach ($predefinedHolidayThemes as $holidayTheme) {
$obj = AbstractObject::getById($holidayTheme);
if ($obj instanceof DataObject\DemiFilterObject) {
foreach ($obj->getFilterElements() as $item) {
$themeids[] = $item->getId();
}
} else {
$themeids[] = $holidayTheme->getId();
}
}
$items->addConditionParam("object_localized_{$serviceId}_{$lang}.o_id in (select o_parentId from object_$productId where object_$productId.o_id in (select src_id from object_relations_$productId where dest_id in (". implode(',', $themeids).") and fieldname = 'holidaythemes'))");
}
$selectedRegion = $request->get('region');
$predefinedRegions = $this->document->getEditable($editablePrefix.'regions')->getData();
if (!empty($selectedRegion)) {
$townids = [];
$districtIds = [];
$region = AbstractObject::getById($selectedRegion);
if ($region instanceof DemiFilterObject) {
foreach ($region->getFilterElements() as $filterElement) {
if ($filterElement instanceof DataObject\DemiRegion) {
foreach ($filterElement->getChildren() as $town) {
$townids[] = $town->getId();
}
} elseif ($filterElement instanceof DataObject\DemiTown) {
$townids[] = $filterElement->getId();
} elseif ($filterElement instanceof DataObject\DemiDistrict) {
$districtIds[] = $filterElement->getId();
}
}
} elseif ($region instanceof DataObject\DemiRegion) {
foreach ($region->getChildren() as $town) {
$townids[] = $town->getId();
}
} elseif ($region instanceof DataObject\DemiTown) {
$townids[] = $region->getId();
} elseif ($region instanceof DataObject\DemiDistrict) {
$districtIds[] = $region->getId();
}
} elseif (!empty($predefinedRegions)) {
foreach ($predefinedRegions as $predRegion) {
if (!$predRegion instanceof AbstractObject) {
$region = AbstractObject::getById($predRegion);
} else {
$region = $predRegion;
}
if ($region instanceof DemiFilterObject) {
foreach ($region->getFilterElements() as $filterElement) {
if ($filterElement instanceof DataObject\DemiRegion) {
foreach ($filterElement->getChildren() as $town) {
$townids[] = $town->getId();
}
} elseif ($filterElement instanceof DataObject\DemiTown) {
$townids[] = $filterElement->getId();
} elseif ($filterElement instanceof DataObject\DemiDistrict) {
$districtIds[] = $filterElement->getId();
}
}
} elseif ($region instanceof DataObject\DemiRegion) {
foreach ($region->getChildren() as $town) {
$townids[] = $town->getId();
}
} elseif ($region instanceof DataObject\DemiTown) {
$townids[] = $region->getId();
} elseif ($region instanceof DataObject\DemiDistrict) {
$districtIds[] = $region->getId();
}
}
}
$selectedServiceTypes = $request->get('serviceType');
$serviceTypeIds = [];
$predefinedServiceTypes = $this->document->getEditable($editablePrefix. 'additionalServiceTypes')->getData();
if (!empty($selectedServiceTypes)) {
if (is_array($selectedServiceTypes)) {
foreach ($selectedServiceTypes as $selectedServiceType) {
$obj = DataObject\DemiAdditionalServiceType::getById($selectedServiceType);
if ($obj instanceof DataObject\DemiAdditionalServiceType) {
$serviceTypeIds[] = $selectedServiceType;
}
}
} else {
$obj = DataObject\DemiAdditionalServiceType::getById($selectedServiceTypes);
if ($obj instanceof DataObject\DemiAdditionalServiceType) {
$serviceTypeIds[] = $selectedServiceTypes;
}
}
$items->addConditionParam("object_localized_{$serviceId}_{$lang}.o_id in (select src_id from object_relations_$serviceId where dest_id in (" . implode(',', $serviceTypeIds) . '))');
} elseif (!empty($predefinedServiceTypes)) {
foreach ($predefinedServiceTypes as $serviceType) {
$allServiceTypes[] = $serviceType->getId();
}
$items->addConditionParam("object_localized_{$items->getClassId()}_{$lang}.o_id in (select src_id from object_relations_$serviceId where dest_id in (" . implode(',', $allServiceTypes) . '))');
}
if (!empty($townids)) {
$items->addConditionParam("o_parentId in (select o_id from object_$providerId where town__id in (" . implode(',', $townids) . ') AND o_published = 1)');
} elseif (!empty($districtIds)) {
$items->addConditionParam("o_parentId in (select o_id from object_$providerId where district__id in (" . implode(',', $districtIds) . ') AND o_published = 1)');
} else {
$items->addConditionParam("o_parentId in (select o_id from object_$providerId where o_published = 1)");
}
$items->addConditionParam('needAcco is null or needAcco = 0');
$items->addConditionParam("object_localized_{$serviceId}_{$lang}.o_id in (select o_parentid from object_$productId where packageOnly is null or packageOnly = 0)");
$items->addConditionParam("object_localized_{$serviceId}_{$lang}.o_id in (select o_id from object_collection_demiDate_$serviceId where (object_collection_demiDate_$serviceId.to > {$dateBegin->getTimestamp()} and object_collection_demiDate_$serviceId.from < {$dateEnd->getTimestamp()}))");
$items = $this->additionalServiceService->sortListingPerDefault($items, $serviceId, $lang);
$items = $this->additionalServiceService->modifyListingForOverview($items);
$perPage = $this->document->getEditable($editablePrefix.'perPage')->getData() ?: 12;
$paginator = $this->paginatorHelper->getPaginator($items, $perPage, $request->get('page', 1), 5);
$viewParams['paginator'] = $paginator;
$viewParams['isAjax'] = $request->isXmlHttpRequest();
$viewParams['additionalServiceNoResultText'] = $this->configuration->getAdditionalServiceNoResultText();
$viewParams['currencySymbol'] = $this->paymentHelper->getCurrency();
if ($request->isXmlHttpRequest() && ($request->headers->get('format') === 'json')) {
$response = [
'status' => 'success',
'html' => $this->renderTemplate('@ElementsDemiFrontend/AdditionalService/list-result.html.twig', $viewParams)->getContent()
];
return $this->json($response);
}
return $this->renderTemplate('@ElementsDemiFrontend/AdditionalService/list-result.html.twig', $viewParams);
}
public function detailAction(Request $request, int $id, UserInterface $user = null): ?Response
{
if (!$this->enabledFeatures['additionalServices']) {
throw new ErrorException('AdditionalServices are not enabled!');
}
$today = new Carbon();
$productId = DataObject\DemiAdditionalProduct::classId();
$providerId = DataObject\DemiAdditionalServiceProvider::classId();
$object = DataObject::getById($request->get('id'));
if (!$object instanceof DemiAdditionalService) {
throw new GoneHttpException("The requested Object doesn't exist (anymore)");
}
if (!$object->isPublished()) {
return $this->forward(self::class. '::unavailableAction', [
'request' => $request
]);
}
if (empty($object->getAdditionalProducts())) {
throw new GoneHttpException('The requested Object does not offer any services!');
}
$serviceProvider = $object->getParent() instanceof AdditionalServiceProvider ? $object->getParent() : null;
if (!$serviceProvider instanceof AdditionalServiceProvider || !$serviceProvider->isPublished()) {
throw new GoneHttpException("The requested Object doesn't have a published Serviceprovider!");
}
$viewParams['user'] = $user;
if ($request->get('enquire')) {
$success = $this->sendEnquire($request, $object, $user);
if ($success) {
$this->addResponseHeader('X-Robots-Tag', 'noindex,nofollow');
$response = [
'status' => 'success',
'html' => $this->renderTemplate('@ElementsDemiFrontend/AdditionalService/enquiry-success.html.twig', [])->getContent()
];
return $this->json($response);
} else {
throw new \Elements\Demi\Deskline\Exception('can not sent enquiry - dsi saving request was not successful');
}
}
if ($object->getDates()) {
$endDate = null;
foreach ($object->getDates()->getItems() as $item) {
if ($endDate === null) {
$endDate = $item->getTo();
} elseif ($endDate->lt($item->getTo())) {
$endDate = $item->getTo();
}
}
if ($endDate !== null) {
$endDate = $endDate->endOfDay()->toRfc850String();
$this->addResponseHeader('X-Robots-Tag', 'unavailable_after: ' . $endDate);
}
}
$onlyHolidaythemes = new DemiAdditionalService\Listing();
$serviceId = $onlyHolidaythemes->getClassId();
$themeids = [];
foreach ($object->getAdditionalProducts() as $product) {
foreach ($product->getHolidayThemes() as $holidayTheme) {
$themeId = $holidayTheme->getId();
if (in_array($themeId, $themeids, true)) {
continue;
}
$themeids[] = $themeId;
}
}
$onlyHolidaythemes->addConditionParam("o_id in (select o_parentId from object_$productId where holidayThemes like '%".implode(',', $themeids)."%')");
$onlyHolidaythemes->addConditionParam('needAcco is null or needAcco = 0');
$onlyHolidaythemes->addConditionParam("o_id in (select o_id from object_collection_demiDate_$serviceId where object_collection_demiDate_$serviceId.from > {$today->getTimestamp()} or object_collection_demiDate_$serviceId.to > {$today->getTimestamp()})");
$onlyHolidaythemes->addConditionParam('o_id != '. $object->getId());
$onlyHolidaythemes->addConditionParam("o_parentId in (select o_id from object_$providerId where o_published = 1 )");
$onlyHolidaythemes->addConditionParam("o_id in (select o_parentid from object_$productId where packageOnly is null or packageOnly = 0)");
$onlyHolidaythemes->setOrderKey('order');
$onlyHolidaythemes = $this->additionalServiceService->modifyListingForOverview($onlyHolidaythemes);
$onlyHolidaythemes->setLimit(4);
$relatedItems = $onlyHolidaythemes->load();
if (count($relatedItems) < 4) {
$townid = $serviceProvider->getTown() ? $serviceProvider->getTown()->getId() : null;
$relatedServices = new DemiAdditionalService\Listing();
$relatedServices->addConditionParam('needAcco is null or needAcco = 0');
$relatedServices->addConditionParam("o_id in (select o_id from object_collection_demiDate_$serviceId where object_collection_demiDate_$serviceId.from > {$today->getTimestamp()} or object_collection_demiDate_$serviceId.to > {$today->getTimestamp()})");
$relatedServices->addConditionParam('o_id != '. $object->getId());
if ($townid) {
$relatedServices->addConditionParam("o_parentId in (select o_id from object_$providerId where town__id in ($townid) and o_published = 1 )");
} else {
$relatedServices->addConditionParam("o_parentId in (select o_id from object_$providerId where o_published = 1 )");
}
if ($onlyHolidaythemes->count() > 0) {
$alreadyLoadedIds = [];
foreach ($relatedItems as $onlyHolidaytheme) {
$alreadyLoadedIds[] = $onlyHolidaytheme->getId();
}
$relatedServices->addConditionParam('o_id not in (' . implode(', ', $alreadyLoadedIds). ')');
}
$relatedServices->addConditionParam("o_id in (select o_parentid from object_$productId where packageOnly is null or packageOnly = 0)");
$relatedServices->setOrderKey('order');
$relatedServices = $this->additionalServiceService->modifyListingForOverview($relatedServices);
$relatedServices->setLimit(4 - count($relatedItems));
$relatedItems = array_merge($relatedItems, $relatedServices->load());
}
$objectAddress = $serviceProvider->getAddress([AddressInterface::ADDRESS_OBJECT]);
if ($objectAddress &&
($this->configuration->getAdditionalServiceShowAddressObjectName()
|| $this->configuration->getAdditionalServiceShowAddressObjectAddress()
|| $this->configuration->getAdditionalServiceShowAddressObjectEmail()
|| $this->configuration->getAdditionalServiceShowAddressObjectPhone()
|| $this->configuration->getAdditionalServiceShowAddressObjectWebsite())
) {
$viewParams["addressObject"] = $objectAddress;
}
$ownerAddress = $serviceProvider->getAddress([AddressInterface::ADDRESS_OWNER]);
if ($ownerAddress &&
($this->configuration->getAdditionalServiceShowAddressOwnerName()
|| $this->configuration->getAdditionalServiceShowAddressOwnerAddress()
|| $this->configuration->getAdditionalServiceShowAddressOwnerEmail()
|| $this->configuration->getAdditionalServiceShowAddressOwnerPhone()
|| $this->configuration->getAdditionalServiceShowAddressOwnerWebsite())
) {
$viewParams["addressOwner"] = $ownerAddress;
}
// Facilities
$facilities = $object->getFacilities();
$sortedHealthMeasures = [];
if ($facilities !== null) {
foreach ($facilities as $item) {
$facility = $item->getFacility();
if ($facility) {
$facGroup = $facility->getFacilityGroup();
if ($facGroup && $facGroup->getFacilityGroupType() == FacilityGroupTypeInterface::FACILITY_GROUP_TYPE_HEALTH) {
if (!isset($sortedHealthMeasures[$facGroup->getId()])) {
$data = [
'name' => $facGroup->getName(),
'keyname' => $facGroup->getDemiIconClass(),
'facilities' => []
];
$sortedHealthMeasures[$facGroup->getId()] = $data;
}
$facName = $facility->getName();
$sortedHealthMeasures[$facGroup->getId()]['facilities'][] = $facName;
}
}
}
}
$viewParams["sortedHealthMeasures"] = $sortedHealthMeasures;
$viewParams["connectedEntries"] = $this->connectedEntryProvider->getConnectedEntriesForAdditional($object, $request);
$viewParams["offeritem"] = $object;
$viewParams["loadAdditionalServiceJs"] = true;
$viewParams["relatedItems"] = $relatedItems;
return $this->renderTemplate('@ElementsDemiFrontend/AdditionalService/detail.html.twig', $viewParams);
}
public static function sortAdditionalServiceProducts(AdditionalProduct $a, AdditionalProduct $b): int
{
return (int) $a->getOrder() - (int) $b->getOrder();
}
public function productsAction(Request $request): Response
{
$serviceId = $request->get('id');
$additionalService = AbstractObject::getById((int) $serviceId);
/*
$dateFrom = $request->get('from') ? $this->elementsCustomDateFormat->stringToCarbon($request->get('from')) : new Carbon();
$dateTo = $request->get('to') ? $this->elementsCustomDateFormat->stringToCarbon($request->get('to')) : new Carbon();
*/
if($request->get('date')){
$date = $this->elementsCustomDateFormat->stringToCarbon($request->get('date'));
} else if($request->get('earliestServiceDate')){
$date = $this->elementsCustomDateFormat->stringToCarbon($request->get('earliestServiceDate'));
} else {
$date = new Carbon();
}
$date = $request->get('date') ? $this->elementsCustomDateFormat->stringToCarbon($request->get('date')) : new Carbon();
$dateFrom=$date;
$dateTo= clone $dateFrom;
if($additionalService !== null){
$first = true;
foreach($additionalService->getDates() as $availableDate){
if($availableDate->getTo()->gt($date) && $date->lt($availableDate->getFrom())){
//set date to first possibly available date
if($first || $availableDate->getFrom()->lt($dateFrom)){
$dateFrom = $availableDate->getFrom();
}
}
if ($availableDate->getTo()->gt($dateTo)) {
$dateTo = $availableDate->getTo();
}
$first = false;
}
}
if(empty($request->get('date'))){
//no date given, use now + 1 year
$dateTo->addYear();
}
$period = $dateFrom->diffInDays($dateTo) + 1;
if ($period > 999) {
$period = 365;
$dateTo = $dateFrom->clone()->addYear();
}
$viewParams = [];
$products = [];
$allCalendarProducts = [];
if ($additionalService !== null) {
if ($additionalService && $additionalService->getParent() && $additionalService->getParent() instanceof AdditionalServiceProvider) {
Config::setClientKeyOverrideFromObject($additionalService->getParent());
}
$productsAdditionalService = $additionalService->getAdditionalProducts();
usort($productsAdditionalService, [__CLASS__, 'sortAdditionalServiceProducts']);
$additionalServicesList = $this->additionalServiceListingLive;
$additionalServicesList->setAdapter($this->adapter);
foreach ($productsAdditionalService as $product) {
$paramLines = new Line();
$today = new Carbon();
$aYearLater = (clone $today)->addYear();
$paramLines->setDateFrom($today);
$paramLines->setDateTo($aYearLater);
$paramLines->setBookOnly(false);
$period = $today->diffInDays($aYearLater) + 1;
$paramLines->setPeriod($period);
$paramLines->setProductId($product->getId());
$params = new Parameter();
$params->setSearchLines([$paramLines]);
$params->setPage(1);
$params->setPerPage(100);
$additionalServicesList->setParameter($params);
$allCalendarProducts += $additionalServicesList->getItems(0, 100);
$additionalServicesList->flushObjects();
}
$availableDates = [];
$customDateFormat = new ElementsCustomDateFormat();
$firstAvailableDate = null;
foreach($allCalendarProducts as $productId => $product){
foreach($product->getPrices() as $price){
if($price->getAvailability() > 0){
$availableDates[$price->getStartDay()->getTimestamp()]=$customDateFormat->dateToString($price->getStartDay());
if($firstAvailableDate === null || $price->getStartDay()->getTimestamp() < $firstAvailableDate->getTimestamp()){
$firstAvailableDate = clone $price->getStartDay();
}
}
}
}
ksort($availableDates);
$availableDates = array_unique($availableDates);
$firstAvailableDate = count($availableDates)>0 ? $customDateFormat->stringToCarbon(reset($availableDates)) : null;
// some sanity checks
if ($dateTo->lt($firstAvailableDate)) {
$dateTo = $firstAvailableDate;
}
if ($date->lt($firstAvailableDate)) {
$date = $firstAvailableDate;
}
// get products after the from and to sanity checks
foreach ($productsAdditionalService as $product) {
$paramLines = new Line();
$paramLines->setDateFrom($dateFrom);
$paramLines->setDateTo($dateTo);
$paramLines->setPeriod($period);
$paramLines->setProductId($product->getId());
$paramLines->setBookOnly(false);
$params = new Parameter();
$params->setBookOnly(false);
$params->setSearchLines([$paramLines]);
$params->setPage(1);
$params->setPerPage(100);
$additionalServicesList->setParameter($params);
$products += $additionalServicesList->getItems(0, 100);
$additionalServicesList->flushObjects();
}
$viewParams["products"] = $products;
$viewParams["from"] = $firstAvailableDate ?: $dateFrom;
$viewParams["to"] = $dateTo;
$viewParams["date"] = $request->get('date') ? $date : $firstAvailableDate;
$viewParams["service"] = $additionalService;
//if ($request->headers->get('format') === 'json') {
$viewParams["isNew"] = true;
$viewParams["isAdditionalService"] = true;
$viewParams["styleModifier"] = 'package-group--additionalservice';
$viewParams["availableDates"] = array_values($availableDates);
$response = [
'status' => 'success',
'html' => $this->renderTemplate('@ElementsDemiFrontend/AdditionalService/products.html.twig', $viewParams)->getContent()
];
return $this->json($response);
//}
}
return $this->renderTemplate('@ElementsDemiFrontend/AdditionalService/products.html.twig', $viewParams);
}
public function productsAjaxAction(Request $request): ?JsonResponse
{
$reqProd = $request->get('products');
$prodid = key($reqProd);
$dateFrom = $request->get('from') ? $this->elementsCustomDateFormat->stringToCarbon($request->get('from')) : new Carbon();
$dateTo = $request->get('to') ? $this->elementsCustomDateFormat->stringToCarbon($request->get('to')) : new Carbon();
$serviceId = $request->get('id');
$dateDiff = $dateFrom->diff($dateTo);
$period = (int) $dateDiff->format('%R%a days') + 1;
$products = [];
if ($serviceId && AbstractObject::getById((int) $serviceId)) {
$additionalService = AbstractObject::getById((int) $serviceId);
if ($additionalService && $additionalService->getParent() && $additionalService->getParent() instanceof AdditionalServiceProvider) {
Config::setClientKeyOverrideFromObject($additionalService->getParent());
}
$productsAdditionalService = $additionalService->getAdditionalProducts();
usort($productsAdditionalService, [__CLASS__, 'sortAdditionalServiceProducts']);
$additionalServicesList = $this->additionalServiceListingLive;
$additionalServicesList->setAdapter($this->adapter);
foreach ($productsAdditionalService as $product) {
if ($product->getId() !== $prodid) {
continue;
}
$paramLines = new Line();
$paramLines->setDateFrom($dateFrom);
$paramLines->setDateTo($dateTo);
$paramLines->setPeriod($period);
$paramLines->setProductId($product->getId());
$paramLines->setBookOnly(false);
$params = new Parameter();
$params->setBookOnly(false);
$params->setSearchLines([$paramLines]);
$params->setPage(1);
$params->setPerPage(100);
$additionalServicesList->setParameter($params);
$products += $additionalServicesList->getItems(0, 100);
}
$viewParams["startdate"] = $reqProd[$prodid]['date'];
$viewParams["products"] = $products;
$viewParams["from"] = $dateFrom;
$viewParams["to"] = $dateTo;
$viewParams["service"] = $additionalService;
if ($request->headers->get('format') === 'json') {
$response = [
'success' => true,
'content' => $this->renderTemplate('@ElementsDemiFrontend/AdditionalService/productsAjax.html.twig', $viewParams)->getContent()
];
return $this->json($response);
}
}
return null;
}
public function addAdditionalItemAction(Request $request): Response
{
$items = [];
Factory::getInstance()->getEnvironment()->removeCustomItem('demi_cartName');
$productId = $request->get('offerId');
$product = AbstractObject::getById($productId);
$count = $request->get('count');
$cart = $this->ecommerceHelper->getCart();
if ($product instanceof AdditionalProduct) {
$cartItemInfo = $this->cartItemInfoService->fillAdditionalServiceProductFromRequest(new CartItemInfoHolder(), $request);
$cartItemInfo->setAdditionalInfo(['relatedProduct' => $request->get('relatedProduct'), 'ignoreInCartTemplate' => true]);
$cancelationService = new CancellationInformation();
$cancelationInfo = $cancelationService->getCancellationInformation($product->getParent()->getParent(),
$product,
$product->getParent()->getParent()->getDbCode(),
Config::getInstance()->getSalesChannel(),
$cartItemInfo->getDateFrom(),
$cartItemInfo->getDateTo(),
$cartItemInfo->getAdultAmount(),
$cartItemInfo->getChildrenAges(),
$cartItemInfo->getDurationValue());
$cartItemInfo->setCancellationInformation($cancelationInfo);
$this->ecommerceHelper->addProductToCart($count, $product, $cartItemInfo, $cart);
$this->trackingManager->trackCartProductActionAdd($cart, $product, $count);
$items[] = ['persons' => $count, 'product' => $product, 'price' => $this->paymentHelper->getPriceObject($cartItemInfo->getPrice()), 'count' => $count];
} else {
foreach ($request->get('products') as $productId => $productData) {
$selectedDay = $productData['days'];
$selectedDay = explode(';', $selectedDay);
$price = $selectedDay[2];
$duration = $selectedDay[0];
$request->request->set('additionalInformation', $productData);
if (!$productData['count'] || !$productData['date'] || !$price) {
throw new InvalidArgumentException('some parameters are missing. cannot add product to cart');
}
$request->request->set('count', $productData['count']);
$request->request->set('offerId', $productId);
$request->request->set('date', $productData['date']);
$request->request->set('price', $price);
$request->request->set('totalPrice', $price);
$request->request->set('settlerCode', $productData['settlerCode']);
$request->request->set('durationType', $productData['durationType']);
$request->request->set('durationValue', $duration);
$cartItemInfo = $this->cartItemInfoService->fillAdditionalServiceProductFromRequest(new CartItemInfoHolder(), $request);
$cartItemInfo->setAdditionalInfo(['relatedProduct' => $request->get('relatedProduct')]);
$additionalInfo = $productData;
unset($additionalInfo['date'], $additionalInfo['count'], $additionalInfo['settlerCode'],
$additionalInfo['price'], $additionalInfo['totalPrice'], $additionalInfo['durationValue'],
$additionalInfo['durationType'], $additionalInfo['days']);
$count = $request->get('count');
if (!empty($additionalInfo)) {
//process if any arrays be here
foreach ($additionalInfo as $key => $info) {
foreach ($info as $k => $v) {
if (is_array($v)) {
$additionalInfo[$key][$k] = implode('<br>', $v);
}
}
}
$cartItemInfo->setAdditionalInfo($additionalInfo);
$persons = max(array_keys($additionalInfo));
if ($persons <= 0) {
$persons = $count;
}
$cartItemInfo->setAdultAmount($persons);
}
$cancelationService = new CancellationInformation();
$cancelationInfo = $cancelationService->getCancellationInformation($product->getParent()->getParent(),
$product,
$product->getParent()->getParent()->getDbCode(),
Config::getInstance()->getSalesChannel(),
$cartItemInfo->getDateFrom(),
$cartItemInfo->getDateTo(),
$cartItemInfo->getAdultAmount(),
$cartItemInfo->getChildrenAges(),
$cartItemInfo->getDurationValue());
$cartItemInfo->setCancellationInformation($cancelationInfo);
$this->ecommerceHelper->addProductToCart($count, $product, $cartItemInfo, $cart);
$items[] = ['persons' => $persons, 'product' => $product, 'price' => $this->paymentHelper->getPriceObject($cartItemInfo->getPrice()), 'count' => $count];
}
}
$response = [
'status' => 'success',
'html' => $this->renderTemplate('@ElementsDemiFrontend/AdditionalService/package-add-cart.html.twig', [
'totalCount' => $cart->getItemAmount(),
'cartItems' => $items
])->getContent()
];
return $this->json($response);
}
public function productDetailAction(Request $request): Response
{
$productId = $request->get('id');
$price = $request->get('price');
$viewParams["showPrice"] = true;
$product = AdditionalProduct::getById($productId);
$additionalService = $product->getParent();
if ($additionalService && $additionalService->getParent() && $additionalService->getParent() instanceof AdditionalServiceProvider) {
Config::setClientKeyOverrideFromObject($additionalService->getParent());
}
if($request->get('date')){
$dateFrom = $this->elementsCustomDateFormat->stringToCarbon($request->get('date'));
$dateTo = clone $dateFrom;
} else {
//legacy?
$dateFrom = $request->get('from') ? $this->elementsCustomDateFormat->stringToCarbon($request->get('from')) : new Carbon();
$dateTo = $request->get('to') ? $this->elementsCustomDateFormat->stringToCarbon($request->get('to')) : (new Carbon())->addMonth();
}
$period = $dateFrom->diffInDays($dateTo) + 1;
$paramLines = new Line();
$paramLines->setDateFrom($dateFrom);
$paramLines->setDateTo($dateTo);
$paramLines->setPeriod($period);
$paramLines->setProductId($product->getId());
$paramLines->setBookOnly(false);
$params = new Parameter();
$params->setBookOnly(false);
$params->setSearchLines([$paramLines]);
$params->setPage(1);
$params->setPerPage(100);
$this->additionalServiceListingLocal->setParameter($params);
$this->additionalServiceListingLocal->load();
$paramLines->setUnits(1);
$params->setSearchLines([$paramLines]);
$this->additionalServiceListingLive->setParameter($params);
$this->additionalServiceListingLive->load();
$result = $this->additionalServiceListingLive->getItems(1, 100);
$bookable = false;
if($result) {
foreach ($result as $item) {
$prices = $item->getPrices();
if (reset($prices)->getBookable()) {
$bookable = true;
break;
}
}
}
$viewParams["id"] = $productId;
$viewParams["price"] = $price;
$viewParams["arrivalDate"] = $dateFrom;
$viewParams["departureDate"] = $dateTo;
foreach ($product->getAdditionalService()->getDescriptions() as $description) {
$descriptionTypes[] = $description->getDescriptionType();
if ($description->getDescriptionType() !== DescriptionInterface::DESCRIPTION_SERVICE_DESCRIPTION) {
$tosc5texts[$description->getDescriptionType()] = $description;
}
}
$viewParams["productText"] = $product->getDescription();
$viewParams["tosc5texts"] = $tosc5texts ?? [];
$viewParams["text"] = $product->getAdditionalService()->getDescription();
$viewParams["title"] = $product->getName();
$viewParams["additionalServiceItem"] = $this->additionalServiceListingLive;
$viewParams["additionalServiceItems"] = $this->additionalServiceListingLocal;
$viewParams["isPackage"] = !empty($request->get('packages'));
$viewParams["searchParam"] = $params;
$viewParams["maxSelect"] = 20;
if(!$bookable){
return $this->renderTemplate('@ElementsDemiFrontend/AdditionalService/includes/offerDetailEnquiry.desktop.html.twig', $viewParams);
} else {
return $this->renderTemplate('@ElementsDemiFrontend/AdditionalService/includes/offerDetailContent.desktop.html.twig', $viewParams);
}
}
protected function findEditablePrefix(Document $document): string
{
if ($document->getEditables() !== null) {
$areaBlock = current(array_filter($document->getEditables(), static function ($editable) {
return $editable instanceof Areablock;
}));
if ($areaBlock !== false && !empty($areaBlock->getIndices())) {
$correctIndex = array_filter($areaBlock->getIndices(), static function ($index) {
return $index['type'] === 'demi-additionalservice-list';
});
return $areaBlock->getName() . ':' . current($correctIndex)['key'] . '.';
}
}
// Fallback for overriden documents
if ($document->getContentMasterDocument() !== null) {
return $this->findEditablePrefix($document->getContentMasterDocument());
}
return '';
}
private function sendEnquire(Request $request, \Elements\Demi\Model\AdditionalService $additionalService, UserInterface $user = null): bool
{
if ($this->configuration->getDisableEnquiry()) {
return false; // Just return since detailEnquireAction is called from detailAction
}
// date
$fromDate = $this->elementsCustomDateFormat->stringToCarbon($request->get('date'));
$request->query->set('from', ElementsCustomDateFormat::toString($fromDate));
$request->query->set('to', ElementsCustomDateFormat::toString($fromDate));
if (!empty($this->configuration->getPrivacyPolicyEnquiry())) {
$ppAccepted = (bool)$request->get('pp');
} else {
$ppAccepted = true;
}
$request->query->set('accoIds', [$additionalService->getParent()->getId()]);
$request->query->set('pp', $ppAccepted);
$request->query->set('price', null);
$request->query->set('u0', $request->get('count') ?? 1 );
$productIds = $request->get('productId');
$time = $request->get('time') ? $this->elementsCustomDateFormat->stringToCarbon($request->get('time')) : '';
if($time instanceof Carbon){
$time = $time->format('H:i');
}
$products=[['id'=>$productIds, 'units' =>$request->get('count'), 'time' => $time]];
$request->query->set('comment', $this->getCommentForDSIEnquiry($request, $products));
if($additionalService->getParent()->getTown()){
$request->query->set('towns', [$additionalService->getParent()->getTown()->getId()]);
}
$mailSent = $this->savingRequestController->serviceProviderRequestAction($request, $user);
return $mailSent;
}
/**
* @param Request $request
* @param $package
* @param $products
* @param $nights
*
* @return mixed|string
*/
private function getCommentForDSIEnquiry(Request $request, array $products): mixed
{
$comment = $request->get('comment');
foreach ($products as $productInfo) {
$product = \Elements\Demi\AbstractObject::getById($productInfo['id']);
$units = $productInfo['units'];
$time = isset($productInfo['time']) ? $productInfo['time'] : '';
if ($product) {
$prodStr = '';
if ($units) {
$prodStr .= $units . 'x ';
}
$prodStr .= $product->getName();
$comment .= " ". $prodStr;
if(!empty($time)){
$comment .= " ".$time;
}
}
}
if ($request->get('tel')) {
$comment .= ', Tel.: '.$request->get('tel');
}
return $comment;
}
}