custom/plugins/AvencyShopwareCore/src/Core/Subscriber/CheckoutConfirmPageSubscriber.php line 78

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Avency\Shopware\Core\Core\Subscriber;
  3. use Avency\Shopware\Core\Core\Content\Event\AvencyNoCalculationByTypesEvent;
  4. use Avency\Shopware\Core\Core\Content\Product\Cart\MinimumOrderAmountError;
  5. use Avency\Shopware\Core\Core\Service\CalculationService;
  6. use Shopware\Core\Checkout\Cart\Cart;
  7. use Shopware\Core\Checkout\Cart\LineItem\LineItem;
  8. use Shopware\Core\Framework\Struct\ArrayStruct;
  9. use Shopware\Core\System\Currency\CurrencyFormatter;
  10. use Shopware\Core\System\SystemConfig\SystemConfigService;
  11. use Shopware\Storefront\Page\Checkout\Cart\CheckoutCartPageLoadedEvent;
  12. use Shopware\Storefront\Page\Checkout\Confirm\CheckoutConfirmPageLoadedEvent;
  13. use Shopware\Storefront\Page\Checkout\Offcanvas\OffcanvasCartPageLoadedEvent;
  14. use Shopware\Storefront\Page\PageLoadedEvent;
  15. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  16. use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
  17. class CheckoutConfirmPageSubscriber implements EventSubscriberInterface
  18. {
  19.     const MESSAGE_SIMPLE 'simple';
  20.     const MESSAGE_NO_VALUE 'no-value';
  21.     const MESSAGE_MISSING_SUM 'missing-sum';
  22.     const MESSAGES_TYPES = [
  23.         'simple' => self::MESSAGE_SIMPLE,
  24.         'noValue' => self::MESSAGE_NO_VALUE,
  25.         'missingSum' => self::MESSAGE_MISSING_SUM,
  26.     ];
  27.     /**
  28.      * @var SystemConfigService
  29.      */
  30.     protected $systemConfigService;
  31.     /**
  32.      * @var CurrencyFormatter
  33.      */
  34.     private $currencyFormatter;
  35.     /**
  36.      * @var EventDispatcherInterface
  37.      */
  38.     private $eventDispatcher;
  39.     /**
  40.      * @var CalculationService
  41.      */
  42.     private $calculationService;
  43.     public function __construct(
  44.         SystemConfigService $systemConfigService,
  45.         CurrencyFormatter $currencyFormatter,
  46.         CalculationService $calculationService,
  47.         EventDispatcherInterface $eventDispatcher
  48.     )
  49.     {
  50.         $this->systemConfigService $systemConfigService;
  51.         $this->currencyFormatter $currencyFormatter;
  52.         $this->eventDispatcher $eventDispatcher;
  53.         $this->calculationService $calculationService;
  54.     }
  55.     public static function getSubscribedEvents(): array
  56.     {
  57.         return [
  58.             CheckoutConfirmPageLoadedEvent::class => 'extendCheckoutConfirm',
  59.             CheckoutCartPageLoadedEvent::class => 'extendCheckoutCart',
  60.             OffcanvasCartPageLoadedEvent::class => 'extendCheckoutCart',
  61.         ];
  62.     }
  63.     /**
  64.      * @param PageLoadedEvent $event
  65.      */
  66.     public function extendCheckoutCart(PageLoadedEvent $event)
  67.     {
  68.         if (!$event instanceof CheckoutCartPageLoadedEvent && !$event instanceof OffcanvasCartPageLoadedEvent) {
  69.             return;
  70.         }
  71.         $config $this->systemConfigService->get('AvencyShopwareCore.config'$event->getSalesChannelContext()->getSalesChannelId());
  72.         if (!$config['avencyMinimumOrderShowInCart']) {
  73.             return;
  74.         }
  75.         $this->extendCheckout($event$config);
  76.     }
  77.     /**
  78.      * @param CheckoutConfirmPageLoadedEvent $event
  79.      */
  80.     public function extendCheckoutConfirm(CheckoutConfirmPageLoadedEvent $event)
  81.     {
  82.         $config $this->systemConfigService->get('AvencyShopwareCore.config'$event->getSalesChannelContext()->getSalesChannelId());
  83.         $this->extendCheckout($event$config);
  84.     }
  85.     /**
  86.      * @param PageLoadedEvent $event
  87.      * @param array $config
  88.      */
  89.     private function extendCheckout(PageLoadedEvent $event, array $config)
  90.     {
  91.         $cart $event->getPage()->getCart();
  92.         $calculatedPositionPrice $this->calculationService->getCalculatedPositionPrice($cart$event->getSalesChannelContext(), $config);
  93.         if (!$this->errorShouldBeSet($config$calculatedPositionPrice$cart$event)) {
  94.             return;
  95.         }
  96.         $messageType $this->getMessageType($config);
  97.         if ($messageType === self::MESSAGE_MISSING_SUM) {
  98.             $missingSum $config['avencyMinimumOrderAmount'] - $calculatedPositionPrice;
  99.         }
  100.         if ($event instanceof OffcanvasCartPageLoadedEvent) {
  101.             $cart->addExtension('avencyMinimumOrderAmount', new ArrayStruct([
  102.                 'messageType' => $messageType,
  103.                 'minimumOrderAmount' => $this->formatPrice($event$config['avencyMinimumOrderAmount']),
  104.                 'missingSum' => isset($missingSum) ? $this->formatPrice($event$missingSum) : null,
  105.             ]));
  106.         } else {
  107.             $cart->addErrors(new MinimumOrderAmountError(
  108.                 $messageType,
  109.                 [
  110.                     'minimumOrderAmount' => $this->formatPrice($event$config['avencyMinimumOrderAmount']),
  111.                     'missingSum' => isset($missingSum) ? $this->formatPrice($event$missingSum) : null,
  112.                 ]
  113.             ));
  114.         }
  115.     }
  116.     /**
  117.      * @param PageLoadedEvent $event
  118.      * @param float $price
  119.      * @return string
  120.      */
  121.     private function formatPrice(PageLoadedEvent $eventfloat $price): string
  122.     {
  123.         return str_replace(",000"""str_replace(".000"""$this->currencyFormatter->formatCurrencyByLanguage(
  124.             $price,
  125.             $event->getSalesChannelContext()->getCurrency()->getIsoCode(),
  126.             $event->getSalesChannelContext()->getSalesChannel()->getLanguageId(),
  127.             $event->getSalesChannelContext()->getContext()
  128.         )));
  129.     }
  130.     /**
  131.      * Validate if error has to be set (or message in ajax cart)
  132.      *
  133.      * @param array $config
  134.      * @param float $calculatedPositionPrice
  135.      * @param Cart $cart
  136.      * @param PageLoadedEvent $event
  137.      * @return bool
  138.      */
  139.     private function errorShouldBeSet(array $configfloat $calculatedPositionPriceCart $cartPageLoadedEvent $event): bool
  140.     {
  141.         $setError false;
  142.         if ($calculatedPositionPrice $config['avencyMinimumOrderAmount']) {
  143.             $setError true;
  144.         }
  145.         $evaluateTypes array_filter(array_map('trim'explode(','$config['avencyMinimumOrderNoCalculationTypes'] ?? '')));
  146.         $evaluateTypes = ($this->eventDispatcher->dispatch(new AvencyNoCalculationByTypesEvent($evaluateTypes$event->getSalesChannelContext())))->getTypes();
  147.         if (!empty($evaluateTypes) && $setError) {
  148.             $shouldMatchAtLeastOne $config['avencyMinimumOrderNoCalculationMatch'] ?? false;
  149.             if (!$shouldMatchAtLeastOne && !empty(array_intersect($evaluateTypes$cart->getLineItems()->getTypes()))) {
  150.                 // If at least one match is found, set no error
  151.                 $setError false;
  152.             }
  153.             if ($shouldMatchAtLeastOne) {
  154.                 $lineItems $cart->getLineItems()->filter(
  155.                     function (LineItem $lineItem) use ($evaluateTypes) {
  156.                         return !in_array($lineItem->getType(), $evaluateTypes);
  157.                     }
  158.                 );
  159.                 // If all line items matches the types, set no error
  160.                 $setError = !($lineItems->count() === 0);
  161.             }
  162.             return $setError;
  163.         }
  164.         if (isset($config['avencyMinimumOrderRuleId'])) {
  165.             /*
  166.              * Validate rule configuration only if
  167.              * 1. `$setError` is not relevant (minimum order value is validated by rule)
  168.              * 2. `$setError` has to be set to false (there is no minimum order quantity for some customers)
  169.              */
  170.             if (
  171.                 $config['avencyMinimumOrderExtendedAmount'] ||
  172.                 (!$config['avencyMinimumOrderExtendedAmount'] && $setError)
  173.             ) {
  174.                 return (\in_array($config['avencyMinimumOrderRuleId'], $event->getContext()->getRuleIds())) === $config['avencyMinimumOrderRuleValid'];
  175.             }
  176.         }
  177.         return $setError;
  178.     }
  179.     /**
  180.      * Get the message type for snippet
  181.      *
  182.      * @param array $config
  183.      * @return string
  184.      */
  185.     private function getMessageType(array $config): string
  186.     {
  187.         $messageType self::MESSAGES_TYPES[$config['avencyMinimumOrderMessage']] ?? self::MESSAGE_SIMPLE;
  188.         // If minimum order amount is validated by rule we can only set a simple message
  189.         if (isset($config['avencyMinimumOrderRuleId']) && $config['avencyMinimumOrderExtendedAmount']) {
  190.             $messageType self::MESSAGE_NO_VALUE;
  191.         }
  192.         return $messageType;
  193.     }
  194. }