src/Model/Shop/Ticket/ShopTicketCatalog.php line 33

Open in your IDE?
  1. <?php
  2. /**
  3.  * Created by Elements.at New Media Solutions GmbH
  4.  *
  5.  */
  6. namespace App\Model\Shop\Ticket;
  7. use App\Ecommerce\PriceSystem\Ticket\PriceSystem;
  8. use App\Model\Shop\TeaserInfoInterface;
  9. use App\Service\TicketShopFrameworkBundle\TicketFilter;
  10. use Carbon\Carbon;
  11. use Elements\Bundle\RecurringDatesTypeBundle\Templating\RecurringDatesHelper;
  12. use Elements\Bundle\SkidataTicketingSwebBundle\Model\Constant\ValidityUnit;
  13. use Elements\Bundle\TicketShopFrameworkBundle\Model\DataObject\TicketCatalog;
  14. use Elements\Bundle\TicketShopFrameworkBundle\Model\Shop\Ticketing\TicketCatalogAvailability;
  15. use Pimcore\Bundle\EcommerceFrameworkBundle\Model\ProductInterface;
  16. use Pimcore\Bundle\EcommerceFrameworkBundle\PriceSystem\PriceInfoInterface;
  17. use Pimcore\Bundle\EcommerceFrameworkBundle\PriceSystem\PriceInterface;
  18. use Pimcore\Log\ApplicationLogger;
  19. use Pimcore\Model\Asset\Image;
  20. /**
  21.  * Class TicketProduct
  22.  *
  23.  * @package App\Model\Shop\Ticketing
  24.  *
  25.  * @method TicketProduct[] getTicketProducts()
  26.  * @method TicketConsumerCategory[] getTicketConsumerCategories()
  27.  * @method null|TicketConsumerCategory getCalendarPriceConsumerCategory()
  28.  */
  29. class ShopTicketCatalog extends TicketCatalog implements TeaserInfoInterfaceProductInterface
  30. {
  31.     /**
  32.      * @return PriceInterface|null
  33.      */
  34.     public function getTeaserPrice(): ?PriceInterface
  35.     {
  36.         return $this->getPrice(nulltrue);
  37.     }
  38.     public function getStartDate(?Carbon $fromDate null): ?Carbon
  39.     {
  40.         if (!$fromDate) {
  41.             $firstValidityDate $this->getFirstValidDateRange(Carbon::now()->startOfDay());
  42.             $startDate $firstValidityDate['from'] ?? null;
  43.         } else {
  44.             $startDate $fromDate;
  45.         }
  46.         return $startDate;
  47.     }
  48.     public function getProduct(?Carbon $fromDate null): ?TicketProduct
  49.     {
  50.         $startDate $this->getStartDate($fromDate);
  51.         $products $this->getTicketProducts();
  52.         $consumer $this->getCalendarPriceConsumerCategory();
  53.         $refProduct null;
  54.         if ($products && $consumer && $startDate) {
  55.             // get ref product with the shortest duration, sorting in relations-field is important
  56.             $refProduct null;
  57.             foreach ($products as $ticketProduct) {
  58.                 if ($ticketProduct->getSkidataProduct()) {
  59.                     if ($refProduct == null || $ticketProduct->getValidityUnit() == ValidityUnit::DAY) {
  60.                         if (($refProduct && $refProduct->getValidityUnit() !== ValidityUnit::DAY) || $refProduct == null || $ticketProduct->getValidityValue() < $refProduct->getValidityValue()) {
  61.                             $refProduct $ticketProduct;
  62.                             if ($refProduct->getValidityValue() == && $refProduct->getValidityValue() == ValidityUnit::DAY) {
  63.                                 break;
  64.                             }
  65.                         }
  66.                     }
  67.                 }
  68.             }
  69.         }
  70.         return $refProduct;
  71.     }
  72.     public function getPriceInfoForProduct(TicketProduct $refProduct, ?Carbon $fromDate nullbool $ignoreSmartPricer false): ?PriceInfoInterface
  73.     {
  74.         $consumer $this->getCalendarPriceConsumerCategory();
  75.         $startDate $this->getStartDate($fromDate);
  76.         try {
  77.             /** @var PriceSystem $priceSystem */
  78.             $priceSystem $refProduct->getPriceSystemImplementation();
  79.             if ($ignoreSmartPricer) {
  80.                 $priceSystem->setIgnoreSmartPricer();
  81.             }
  82.             $priceInfo $priceSystem->getPriceInfo($refProduct1, [], $startDate,
  83.                 $consumernull$this);
  84.             return $priceInfo;
  85.         } catch (\Exception $e) {
  86.             //error ticket on this date is not available
  87.             ApplicationLogger::getInstance('ticketPrice')->debug($e->getMessage(), [
  88.                 'relatedObject' => $refProduct,
  89.             ]);
  90.         }
  91.         return null;
  92.     }
  93.     public function getPriceInfo(?Carbon $fromDate nullbool $ignoreSmartPricer false): ?PriceInfoInterface
  94.     {
  95.         $refProduct $this->getProduct($fromDate);
  96.         return $refProduct ?
  97.          $this->getPriceInfoForProduct($refProduct$fromDate$ignoreSmartPricer) : null;
  98.     }
  99.     public function getPrice(?Carbon $fromDate nullbool $ignoreSmartPricer false): ?PriceInterface
  100.     {
  101.         return $this->getPriceInfo($fromDate$ignoreSmartPricer)?->getPrice();
  102.     }
  103.     public function getPriceForDateRange(?Carbon $fromDate null, ?Carbon $toDate nullbool $useBasePrice false): ?PriceInterface
  104.     {
  105.         $availabilities $this->getAvailabilityForDateRange($fromDate$toDate);
  106.         return $this->getLowestPriceInfoForAvailability($availabilities$useBasePrice)?->getTotalPrice();
  107.     }
  108.     public function getAvailabilityForDateRange(
  109.         ?Carbon $fromDate null,
  110.         ?Carbon $toDate null,
  111.         bool $exactDuration true,
  112.         bool $ignorePrice false,
  113.         bool $includeInsurances false,
  114.         bool $ignoreIsBookable false
  115.     ): TicketCatalogAvailability {
  116.         $filter = new TicketFilter($fromDate$toDate);
  117.         $filter->setExactDuration($exactDuration);
  118.         $filter->setIgnorePrice($ignorePrice);
  119.         if ($calendarConsumer $this->getCalendarPriceConsumerCategory()) {
  120.             $filter->setConsumers([$calendarConsumer->getId()]);
  121.         }
  122.         $availabilities $filter->getTicketCatalogAvailability($this$includeInsurances$ignoreIsBookable);
  123.         return $availabilities;
  124.     }
  125.     /**
  126.      * @param Carbon|null $fromDate
  127.      * @param Carbon|null $toDate
  128.      * @param array<int> $allowedConsumerIds
  129.      * @param bool $ignoreIsBookable
  130.      *
  131.      * @return TicketCatalogAvailability
  132.      */
  133.     public function getAvailabilityForDateRangeWithPriceGroup(array $allowedConsumerIds, ?Carbon $fromDate null, ?Carbon $toDate nullbool $ignoreIsBookable false): TicketCatalogAvailability
  134.     {
  135.         $filter = new TicketFilter($fromDate$toDate);
  136.         $filter->setExactDuration(true);
  137.         $filter->setConsumers($allowedConsumerIds);
  138.         $availabilities $filter->getTicketCatalogAvailability($thisfalse$ignoreIsBookable);
  139.         return $availabilities;
  140.     }
  141.     /**
  142.      * Checks if it is available in a specific date range. If no end date is given, all future dates get checked
  143.      *
  144.      * @param ?Carbon $startDate
  145.      * @param ?Carbon $endDate
  146.      *
  147.      * @return bool
  148.      */
  149.     public function isAvailableInDateRange(?Carbon $startDate null, ?Carbon $endDate null): bool
  150.     {
  151.         $recurringDates = (new RecurringDatesHelper())->getCalculatedDates($this'getValidityDates');
  152.         $checkFuture false;
  153.         if (!$startDate) {
  154.             $startDate Carbon::now();
  155.             $checkFuture true;
  156.         }
  157.         if (!$endDate) {
  158.             $endDate $startDate->copy();
  159.         }
  160.         foreach ($recurringDates as $recurringDate) {
  161.             if ($checkFuture && $recurringDate['fromDate']->isFuture()) {
  162.                 return true;
  163.             } elseif ($recurringDate['fromDate']->lte($startDate) && $recurringDate['toDate']->gte($endDate)) {
  164.                 return true;
  165.             }
  166.         }
  167.         return false;
  168.     }
  169.     public function getLowestPriceInfoForAvailability(TicketCatalogAvailability $availabilitiesbool $useBasePrice falsebool $includeIgnoredTickets false): ?PriceInfoInterface
  170.     {
  171.         $priceInfo null;
  172.         if ($availabilities->hasAvailability()) {
  173.             foreach ($availabilities->getTicketAvailability() as $ticketAvailability) {
  174.                 $product $ticketAvailability->getTicketProduct();
  175.                 //get first, because we already restricted to our adult consumer
  176.                 $consumerAvailability $ticketAvailability->getConsumerAvailabilities()[0];
  177.                 if ($priceInfo == null || ((!$product->getIgnoreForFromPrice() || $includeIgnoredTickets) &&
  178.                     $priceInfo->getTotalPrice()->getGrossAmount()->asNumeric() > $consumerAvailability->getPriceInfo()->getTotalPrice()->getGrossAmount()->asNumeric())
  179.                 ) {
  180.                     $priceInfo $consumerAvailability->getPriceInfo();
  181.                 }
  182.             }
  183.         }
  184.         if ($useBasePrice && $priceInfo) {
  185.             $price $priceInfo->getOriginalPriceInfo();
  186.         } else {
  187.             $price $priceInfo;
  188.         }
  189.         return $price;
  190.     }
  191.     public function getTeaserTopTitle(): ?string
  192.     {
  193.         if ($category $this->getProductCategory()) {
  194.             return $category->getName();
  195.         }
  196.         return '';
  197.     }
  198.     public function getDescriptionForTeaser(): ?string
  199.     {
  200.         return $this->getTeaserDescription() ?: $this->getShortDescription();
  201.     }
  202.     public function getTeaserImage(): ?Image
  203.     {
  204.         return $this->getMainImage();
  205.     }
  206.     /** @return array<mixed> */
  207.     public function getTeaserValidity(): array
  208.     {
  209.         return $this->getFirstValidDateRange(Carbon::now());
  210.     }
  211.     public function getFirstValidValidityDate(Carbon $date): ?Carbon
  212.     {
  213.         $validityDate null;
  214.         $firstValidityDateRange $this->getFirstValidDateRange($date);
  215.         if (isset($firstValidityDateRange['from'])) {
  216.             /** @var Carbon $fromDateValidity */
  217.             $fromDateValidity $firstValidityDateRange['from'];
  218.             $validityDate $fromDateValidity->lt($date) ? $date $fromDateValidity;
  219.         }
  220.         return $validityDate;
  221.     }
  222.     /**
  223.      * @param Carbon $date
  224.      *
  225.      * @return  array<mixed>
  226.      */
  227.     public function getFirstValidDateRange(Carbon $date): array
  228.     {
  229.         if ($validDates $this->getValidityDates()) {
  230.             if ($definitions $validDates->getDefinitionArray()) {
  231.                 foreach ($definitions as $definition) {
  232.                     if (isset($definition['values']['fromDate'])) {
  233.                         $fromDate Carbon::parse($definition['values']['fromDate']);
  234.                         $toDate Carbon::parse($definition['values']['toDate']);
  235.                         if ($definition['type'] == 'RecurringDate'
  236.                             && ($date->between($fromDate$toDate) || $fromDate->gte($date))
  237.                         ) {
  238.                             return [
  239.                                 'from' => $fromDate,
  240.                                 'to' => $toDate,
  241.                             ];
  242.                         }
  243.                     }
  244.                 }
  245.             }
  246.         }
  247.         return [];
  248.     }
  249.     /**
  250.      * returns all valid date ranges now and in the future, if no dateformat is given, dats are returned as timestamp
  251.      *
  252.      * @param Carbon $date
  253.      *
  254.      * @return  array<mixed>
  255.      */
  256.     public function getAllValidDateRanges(?Carbon $date nullstring $dateFormat null): array
  257.     {
  258.         $validRanges=[];
  259.         if(!$date) {
  260.             $date Carbon::now()->startOfDay();
  261.         }
  262.         if ($validDates $this->getValidityDates()) {
  263.             if ($definitions $validDates->getDefinitionArray()) {
  264.                 foreach ($definitions as $definition) {
  265.                     $fromDate Carbon::parse($definition['values']['fromDate']);
  266.                     $toDate Carbon::parse($definition['values']['toDate']);
  267.                     if ($definition['type'] == 'RecurringDate'
  268.                         && ($date->between($fromDate$toDate) || $fromDate->gte($date))
  269.                     ) {
  270.                         $validRanges[]= [
  271.                             'from' => $dateFormat $fromDate->format($dateFormat) : $fromDate->getTimestamp(),
  272.                             'to' => $dateFormat $toDate->format($dateFormat) : $toDate->getTimestamp(),
  273.                         ];
  274.                     }
  275.                 }
  276.             }
  277.         }
  278.         return $validRanges;
  279.     }
  280.     /**
  281.      * @return array<mixed>
  282.      */
  283.     public function getValidityDaysNumeric(): array
  284.     {
  285.         $validityDays = [];
  286.         $products $this->getTicketProducts();
  287.         foreach ($products as $product) {
  288.             $validityDays[] = $product->getValidity();
  289.             //add for flex-tickets e.g. 2in4 days
  290.             if ($validTicketDays $product->getValidDays()) {
  291.                 $validityDays[] = $validTicketDays;
  292.             }
  293.         }
  294.         $validityDays array_unique($validityDays);
  295.         sort($validityDays);
  296.         return $validityDays;
  297.     }
  298.     public function getCurrentDateRangeStartDate(): ?Carbon
  299.     {
  300.         $range $this->getFirstValidDateRange(Carbon::now()->startOfDay());
  301.         if (isset($range['from'])) {
  302.             return $range['from']->startOfDay();
  303.         }
  304.         return null;
  305.     }
  306.     public function getCurrentDateRangeEndDate(): ?Carbon
  307.     {
  308.         $range $this->getFirstValidDateRange(Carbon::now()->startOfDay());
  309.         if (isset($range['to'])) {
  310.             return $range['to']->startOfDay();
  311.         }
  312.         return null;
  313.     }
  314.     //for dummy template
  315.     public function getDescriptionExpand(): bool
  316.     {
  317.         return true;
  318.     }
  319.     public function getMaxSelectableDates(): int
  320.     {
  321.         $selectableDates 1;
  322.         if ($this->getTicketProducts()) {
  323.             foreach ($this->getTicketProducts() as $ticketProduct) {
  324.                 if (!$ticketProduct->isSingleRide() && $ticketProduct->getValidityValue() > 1) {
  325.                     $selectableDates 2;
  326.                     break;
  327.                 }
  328.             }
  329.         }
  330.         return $selectableDates;
  331.     }
  332.     public function getMinSelectableDates(): int
  333.     {
  334.         $selectableDates 2;
  335.         if ($this->getTicketProducts()) {
  336.             foreach ($this->getTicketProducts() as $ticketProduct) {
  337.                 if ($ticketProduct->isSingleRide() || $ticketProduct->getValidityValue() < 2) {
  338.                     $selectableDates 1;
  339.                     break;
  340.                 }
  341.             }
  342.         }
  343.         return $selectableDates;
  344.     }
  345.     public function getMinValidityValue(): int
  346.     {
  347.         $minValidityValue null;
  348.         if ($this->getTicketProducts()) {
  349.             foreach ($this->getTicketProducts() as $ticketProduct) {
  350.                 if ($minValidityValue === null) {
  351.                     $minValidityValue $ticketProduct->getValidityValue();
  352.                 } elseif ($ticketProduct->getValidityValue() < $minValidityValue) {
  353.                     $minValidityValue $ticketProduct->getValidityValue();
  354.                 }
  355.             }
  356.         }
  357.         return $minValidityValue;
  358.     }
  359.     public function hasBookableTicketProducts(): bool
  360.     {
  361.         if ($this->getTicketProducts()) {
  362.             foreach ($this->getTicketProducts() as $ticketProduct) {
  363.                 if ($ticketProduct->isBookable()) {
  364.                     return true// return true if at least one TicketProduct is bookable !
  365.                 }
  366.             }
  367.         }
  368.         return false;
  369.     }
  370.     /**
  371.      * @return bool
  372.      */
  373.     public function isBookable(): bool
  374.     {
  375.         $isPublished $this->isPublished();
  376.         $hasActiveProducts count($this->getActiveProducts()) > 0;
  377.         $isBookable = !$this->getIsNotBookable();
  378.         $hasBookableTicketProducts $this->hasBookableTicketProducts();
  379.         $hasCurrentOrFutureDateRanges $this->hasCurrentOrFutureDateRanges();
  380.         return $hasActiveProducts && $isBookable && $isPublished && $hasBookableTicketProducts && $hasCurrentOrFutureDateRanges;
  381.     }
  382.     public function hasCurrentOrFutureDateRanges(): bool
  383.     {
  384.         $datesHelper \Pimcore::getContainer()->get(RecurringDatesHelper::class);
  385.         return !empty($datesHelper->getCalculatedDates($this'getValidityDates'));
  386.     }
  387.     //for tracking
  388.     public function getOSName(): ?string
  389.     {
  390.         return $this->getName();
  391.     }
  392.     //for tracking
  393.     public function getOSProductNumber(): ?string
  394.     {
  395.         return null;
  396.     }
  397.     public function getMinDuration(): int
  398.     {
  399.         $products $this->getTicketProducts();
  400.         if (!$this->maxDuration && !$this->minDuration) {
  401.             $maxDuration = -1;
  402.             $minDuration 1000;
  403.             foreach ($products as $product) {
  404.                 $minValidityDuration $product->getValidDays() ?: $product->getValidity();
  405.                 $maxValidityDuration $product->getValidity();
  406.                 if (!$minValidityDuration) {
  407.                     continue;  // skip products where validity can not be calculated
  408.                 }
  409.                 if ($maxValidityDuration $maxDuration) {
  410.                     $maxDuration $maxValidityDuration;
  411.                 }
  412.                 if ($minValidityDuration $minDuration) {
  413.                     $minDuration $minValidityDuration;
  414.                 }
  415.             }
  416.             $this->minDuration intval($minDuration);
  417.             $this->maxDuration intval($maxDuration);
  418.         }
  419.         return $this->minDuration;
  420.     }
  421.     // for b2b
  422.     public function getBaseCatalog(): self
  423.     {
  424.         $id \Pimcore\Db::getConnection()->fetchOne("
  425.             SELECT src_id AS id
  426.             FROM object_relations_{$this->getClassId()}
  427.             WHERE dest_id = {$this->getId()} and fieldname = 'upgrades'
  428.         ");
  429.         if (!empty($id)) {
  430.             return ShopTicketCatalog::getById($id);
  431.         }
  432.         return $this;
  433.     }
  434. }