custom/static-plugins/LDSCustom/src/Subscriber/ProductSubscriber.php line 82

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace LDSCustom\Subscriber;
  4. use Shopware\Core\Content\Product\ProductEvents;
  5. use Shopware\Storefront\Page\Product\ProductPageLoadedEvent;
  6. use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityLoadedEvent;
  7. use Shopware\Core\System\SalesChannel\Entity\SalesChannelEntityLoadedEvent;
  8. use Shopware\Core\Checkout\Cart\LineItem\LineItem;
  9. use Shopware\Core\Content\Product\Cart\ProductLineItemFactory;
  10. use Shopware\Core\Checkout\Cart\SalesChannel\CartService;
  11. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  12. use Shopware\Core\Checkout\Cart\Cart;
  13. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  14. use Shopware\Core\Framework\Struct\ArrayEntity;
  15. use Shopware\Core\Framework\Util\Random;
  16. use Shopware\Core\Checkout\Cart\CartBehavior;
  17. use Shopware\Core\Checkout\Cart\Delivery\Struct\DeliveryInformation;
  18. use Shopware\Core\Checkout\Cart\Delivery\Struct\DeliveryTime;
  19. use Shopware\Core\Checkout\Cart\LineItem\QuantityInformation;
  20. use Shopware\Core\Checkout\Cart\Price\Struct\CalculatedPrice;
  21. use Shopware\Core\Checkout\Cart\Price\Struct\QuantityPriceDefinition;
  22. use Shopware\Core\Defaults;
  23. use Shopware\Core\Checkout\Cart\Processor;
  24. use Shopware\Core\Checkout\Cart\CartDataCollectorInterface;
  25. use Shopware\Core\Checkout\Cart\CartProcessorInterface;
  26. use Shopware\Core\Checkout\Promotion\Cart\PromotionProcessor;
  27. use Shopware\Core\Checkout\Cart\Price\Struct\ReferencePriceDefinition;
  28. use Shopware\Core\Checkout\Cart\Price\AmountCalculator;
  29. use Shopware\Core\Checkout\Cart\CartRuleLoader;
  30. class ProductSubscriber implements EventSubscriberInterface
  31. {
  32.     private ProductLineItemFactory $factory;
  33.     /**
  34.      * @var CartDataCollectorInterface
  35.      */
  36.     private $promotionCollector;
  37.     /**
  38.      * @var CartProcessorInterface
  39.      */
  40.     private $promotionProcessor;
  41.     /**
  42.      * @var AmountCalculator
  43.      */
  44.     private $amountCalculator;
  45.     private CartRuleLoader $cartRuleLoader;
  46.     /**
  47.      * @var array|null
  48.      */
  49.     private $promotionsAuto;
  50.     public function __construct(
  51.         ProductLineItemFactory $factory,
  52.         CartDataCollectorInterface $promotionCollector,
  53.         CartProcessorInterface $promotionProcessor,
  54.         AmountCalculator $amountCalculator,
  55.         CartRuleLoader $cartRuleLoader
  56.     ) {
  57.         $this->factory $factory;
  58.         $this->promotionCollector $promotionCollector;
  59.         $this->promotionProcessor $promotionProcessor;
  60.         $this->amountCalculator $amountCalculator;
  61.         $this->cartRuleLoader $cartRuleLoader;
  62.     }
  63.     public static function getSubscribedEvents()
  64.     {
  65.         return [
  66.             ProductPageLoadedEvent::class => ['loaded', -50],
  67.         ];
  68.     }
  69.     public function loaded(ProductPageLoadedEvent $event): void
  70.     {
  71.         $salesChannelContext $event->getSalesChannelContext();
  72.         $page $event->getPage();
  73.         $product $page->getProduct();
  74.         $behavior = new CartBehavior($salesChannelContext->getPermissions());
  75.         $cart = new Cart($salesChannelContext->getSalesChannel()->getTypeId(), Random::getAlphanumericString(32));
  76.         $cart->add($this->CreateLineItem($product$behavior));
  77.         $amount $this->amountCalculator->calculate(
  78.             $cart->getLineItems()->getPrices(),
  79.             $cart->getDeliveries()->getShippingCosts(),
  80.             $salesChannelContext
  81.         );
  82.         $cart->setPrice($amount);
  83.         $this->promotionProcessor->process($cart->getData(), $cart$cart$salesChannelContext$behavior);
  84.         $this->promotionCollector->collect($cart->getData(), $cart$salesChannelContext$behavior);
  85.         $validated $this->cartRuleLoader->loadByCart($salesChannelContext$cart$behavior);
  86.         $cart $validated->getCart();
  87.         $salesChannelContext->addExtension('promotions'$cart);
  88.     }
  89.     private function CreateLineItem($product$behavior): LineItem
  90.     {
  91.         $lineItem $this->factory->create($product->getId(), ['quantity' => 1]);
  92.         $lineItem->setPrice($product->getCalculatedPrice());
  93.         $label trim($lineItem->getLabel() ?? '');
  94.         // set the label if its empty or the context does not have the permission to overwrite it
  95.         if ($label === '' || !$behavior->hasPermission(ProductCartProcessor::ALLOW_PRODUCT_LABEL_OVERWRITES)) {
  96.             $lineItem->setLabel($product->getTranslation('name'));
  97.         }
  98.         if ($product->getCover()) {
  99.             $lineItem->setCover($product->getCover()->getMedia());
  100.         }
  101.         /* DeliveryTime */
  102.         $deliveryTime null;
  103.         if ($product->getDeliveryTime() !== null) {
  104.             $deliveryTime DeliveryTime::createFromEntity($product->getDeliveryTime());
  105.         }
  106.         $lineItem->setDeliveryInformation(
  107.             new DeliveryInformation(
  108.                 (int) $product->getAvailableStock(),
  109.                 (float) $product->getWeight(),
  110.                 $product->getShippingFree() === true,
  111.                 $product->getRestockTime(),
  112.                 $deliveryTime,
  113.                 $product->getHeight(),
  114.                 $product->getWidth(),
  115.                 $product->getLength()
  116.             )
  117.         );
  118.         $lineItem->setPriceDefinition(
  119.             $this->getPriceDefinition($product$lineItem->getQuantity())
  120.         );
  121.         $quantityInformation = new QuantityInformation();
  122.         $quantityInformation->setMinPurchase(
  123.             $product->getMinPurchase() ?? 1
  124.         );
  125.         $quantityInformation->setMaxPurchase(
  126.             $product->getCalculatedMaxPurchase()
  127.         );
  128.         $quantityInformation->setPurchaseSteps(
  129.             $product->getPurchaseSteps() ?? 1
  130.         );
  131.         $lineItem->setQuantityInformation($quantityInformation);
  132.         $purchasePrices null;
  133.         $purchasePricesCollection $product->getPurchasePrices();
  134.         if ($purchasePricesCollection !== null) {
  135.             $purchasePrices $purchasePricesCollection->getCurrencyPrice(Defaults::CURRENCY);
  136.         }
  137.         $payload = [
  138.             'isCloseout' => $product->getIsCloseout(),
  139.             'customFields' => $product->getCustomFields(),
  140.             'createdAt' => $product->getCreatedAt()->format(Defaults::STORAGE_DATE_TIME_FORMAT),
  141.             'releaseDate' => $product->getReleaseDate() ? $product->getReleaseDate()->format(Defaults::STORAGE_DATE_TIME_FORMAT) : null,
  142.             'isNew' => $product->isNew(),
  143.             'markAsTopseller' => $product->getMarkAsTopseller(),
  144.             'purchasePrices' => $purchasePrices json_encode($purchasePrices) : null,
  145.             'productNumber' => $product->getProductNumber(),
  146.             'manufacturerId' => $product->getManufacturerId(),
  147.             'taxId' => $product->getTaxId(),
  148.             'tagIds' => $product->getTagIds(),
  149.             'categoryIds' => $product->getCategoryTree(),
  150.             'propertyIds' => $product->getPropertyIds(),
  151.             'optionIds' => $product->getOptionIds(),
  152.             'streamIds' => $product->getStreamIds(),
  153.             'parentId' => $product->getParentId(),
  154.             'stock' => $product->getStock(),
  155.         ];
  156.         $payload['options'] = $product->getVariation();
  157.         $lineItem->replacePayload($payload);
  158.         return $lineItem;
  159.     }
  160.     private function getPriceDefinition($productint $quantity): QuantityPriceDefinition
  161.     {
  162.         // we don't need to recalculate the product - it is already calculated when we get it from the listing
  163.         if ($product->getCalculatedPrices()->count() === 0) {
  164.             return $this->buildPriceDefinition($product->getCalculatedPrice(), $quantity);
  165.         }
  166.         // keep loop reference to $price variable to get last quantity price in case of "null"
  167.         $price $product->getCalculatedPrice();
  168.         foreach ($product->getCalculatedPrices() as $price) {
  169.             if ($quantity <= $price->getQuantity()) {
  170.                 break;
  171.             }
  172.         }
  173.         return $this->buildPriceDefinition($price$quantity);
  174.     }
  175.     private function buildPriceDefinition(CalculatedPrice $priceint $quantity): QuantityPriceDefinition
  176.     {
  177.         $definition = new QuantityPriceDefinition($price->getUnitPrice(), $price->getTaxRules(), $quantity);
  178.         if ($price->getListPrice() !== null) {
  179.             $definition->setListPrice($price->getListPrice()->getPrice());
  180.         }
  181.         if ($price->getReferencePrice() !== null) {
  182.             $definition->setReferencePriceDefinition(
  183.                 new ReferencePriceDefinition(
  184.                     $price->getReferencePrice()->getPurchaseUnit(),
  185.                     $price->getReferencePrice()->getReferenceUnit(),
  186.                     $price->getReferencePrice()->getUnitName()
  187.                 )
  188.             );
  189.         }
  190.         return $definition;
  191.     }
  192. }