custom/plugins/NeonPlatformUnitarticles/src/Subscribers/OnLineItemAdded.php line 61

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Neon\Unitarticles\Subscribers;
  3. use Neon\Unitarticles\Cart\Checkout\ProductUnitarticleInvalidError;
  4. use Neon\Unitarticles\Cart\Checkout\ProductUnitarticleStockReachedError;
  5. use Neon\Unitarticles\NeonPlatformUnitarticles;
  6. use Neon\Unitarticles\Services\PriceFactorService;
  7. use Neon\Unitarticles\Services\UnitarticlesLineItemValidator;
  8. use Shopware\Core\Checkout\Cart\Cart;
  9. use Shopware\Core\Checkout\Cart\Event\BeforeLineItemAddedEvent;
  10. use Shopware\Core\Checkout\Cart\LineItem\LineItem;
  11. use Shopware\Core\Content\Product\ProductEntity;
  12. use Shopware\Core\Content\Product\SalesChannel\SalesChannelProductEntity;
  13. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  14. use Shopware\Core\Framework\Uuid\Uuid;
  15. use Shopware\Core\System\SalesChannel\Entity\SalesChannelRepository;
  16. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  17. use Symfony\Component\HttpFoundation\RequestStack;
  18. class OnLineItemAdded implements EventSubscriberInterface
  19. {
  20.     /** @var RequestStack */
  21.     private $requestStack;
  22.     /** @var SalesChannelRepository */
  23.     private $productRepository;
  24.     /** @var PriceFactorService */
  25.     private $priceFactorService;
  26.     /** @var UnitarticlesLineItemValidator */
  27.     private $unitarticlesLineItemValidator;
  28.     public function __construct($requestStack$productRepository$priceFactorService$unitarticlesLineItemValidator)
  29.     {
  30.         $this->requestStack $requestStack;
  31.         $this->productRepository $productRepository;
  32.         $this->priceFactorService $priceFactorService;
  33.         $this->unitarticlesLineItemValidator $unitarticlesLineItemValidator;
  34.     }
  35.     /**
  36.      * @inheritDoc
  37.      */
  38.     public static function getSubscribedEvents()
  39.     {
  40.         return [
  41.             BeforeLineItemAddedEvent::class => 'onLineItemAdded'
  42.         ];
  43.     }
  44.     /**
  45.      * @param BeforeLineItemAddedEvent $event
  46.      * @throws \Shopware\Core\Checkout\Cart\Exception\InvalidPayloadException
  47.      * @throws \Shopware\Core\Checkout\Cart\Exception\InvalidQuantityException
  48.      * @throws \Shopware\Core\Checkout\Cart\Exception\LineItemNotStackableException
  49.      * @throws \Shopware\Core\Checkout\Cart\Exception\MixedLineItemTypeException
  50.      * @throws \Shopware\Core\Framework\DataAbstractionLayer\Exception\InconsistentCriteriaIdsException
  51.      */
  52.     public function onLineItemAdded(BeforeLineItemAddedEvent $event): void
  53.     {
  54.         $lineItem $event->getLineItem();
  55.         $isExistingProductAfterLogin $event->getLineItem()->getPayloadValue(NeonPlatformUnitarticles::PAYLOAD_KEY) != null;
  56.         if (!$isExistingProductAfterLogin && $lineItem->getType() === LineItem::PRODUCT_LINE_ITEM_TYPE) {
  57.             $product $this->getProduct($event$lineItem);
  58.             $lineItemParam $this->requestStack->getCurrentRequest()->request->get('lineItems');
  59.             if ($lineItemParam == null) {
  60.                 $lineItemParam $this->getDefaultUnit($product$lineItem);
  61.                 if ($this->isQuantityHidden($product)) {
  62.                     $lineItemParam $this->updateLineItem($lineItemParam$lineItem$product);
  63.                 }
  64.             }
  65.             if ($this->isProductUnitarticle($product) && $lineItemParam != null) {
  66.                 if ($this->isMergeUserValues($product)) {
  67.                     foreach ($event->getCart()->getLineItems() as $cartLineItem) {
  68.                         if (array_key_exists($lineItem->getId(), $lineItemParam) &&
  69.                             $cartLineItem->getReferencedId() == $lineItemParam[$lineItem->getId()]['referencedId']) {
  70.                             $payload $cartLineItem->getPayloadValue(NeonPlatformUnitarticles::PAYLOAD_KEY);
  71.                             if ($payload) {
  72.                                 foreach ($lineItemParam[$lineItem->getId()]['neonUnitarticleUnitValue'] as $key => $userValue) {
  73.                                     $formattedUserValue floatval(str_replace(',''.'$userValue));
  74.                                     $payload['dimensions'][$key 1]['unitvalue'] = $payload['dimensions'][$key 1]['unitvalue'] + $formattedUserValue;
  75.                                 }
  76.                                 $cartLineItem->setQuantity(1);
  77.                                 $cartLineItem->setPayloadValue(NeonPlatformUnitarticles::PAYLOAD_KEY$payload);
  78.                             }
  79.                         }
  80.                     }
  81.                 }
  82.                 $unitValues = [];
  83.                 if (array_key_exists($lineItem->getId(), $lineItemParam)) {
  84.                     foreach ($lineItemParam[$lineItem->getId()][NeonPlatformUnitarticles::PARAM_UNITVALUE] as $dimensionNumber => $value) {
  85.                         $descriptionKey substr(NeonPlatformUnitarticles::CUSTOMFIELD_DESCRIPTION0strlen(NeonPlatformUnitarticles::CUSTOMFIELD_DESCRIPTION) - 1) . $dimensionNumber;
  86.                         $unitlabelKey substr(NeonPlatformUnitarticles::CUSTOMFIELD_UNITLABEL0strlen(NeonPlatformUnitarticles::CUSTOMFIELD_UNITLABEL) - 1) . $dimensionNumber;
  87.                         $floatval floatval(str_replace(",""."$value ''));
  88.                         $unitValues[] = [
  89.                             'dimension' => $dimensionNumber,
  90.                             'unitvalue' => $floatval,
  91.                             'description' => $product->getCustomFields()[$descriptionKey],
  92.                             'unitlabel' => $product->getCustomFields()[$unitlabelKey]
  93.                         ];
  94.                     }
  95.                     $isValid $this->unitarticlesLineItemValidator->isValid($unitValues$product);
  96.                     $isUnitArticleStockReached false;
  97.                     if (!$isValid) {
  98.                         $this->setProductUnitarticleInvalidError($event->getCart(), $product);
  99.                         $isUnitArticleStockReached true;
  100.                     }
  101.                     if ($isValid && $this->isQuantityHidden($product)) {
  102.                         $totalQuantity $this->getQuantityOfSameProducts($event->getCart(), $product);
  103.                         if ($totalQuantity $product->getCalculatedMaxPurchase()) {
  104.                             $isUnitArticleStockReached true;
  105.                             $this->setProductUnitarticleStockReachedError($event->getCart(), $product->getCustomFields()[$unitlabelKey],
  106.                                 $product->getCustomFields()[$descriptionKey], $product->getCalculatedMaxPurchase(), $product);
  107.                         }
  108.                     }
  109.                     if (!$isUnitArticleStockReached && $isValid) {
  110.                         $lineItem->setPayloadValue(NeonPlatformUnitarticles::PAYLOAD_KEY,
  111.                             [
  112.                                 NeonPlatformUnitarticles::PAYLOAD_KEY_DIMENSION => $unitValues,
  113.                                 'isQuantityHidden' => $this->isQuantityHidden($product),
  114.                                 'isMergeUserValues' => $this->isMergeUserValues($product),
  115.                                 'basePrice' => $this->getBasePrice($product),
  116.                                 'basePriceUnitValue' => $product->getCustomFields()[NeonPlatformUnitarticles::CUSTOMFIELD_BASEPRICEVALUE],
  117.                                 'surcharges' => $this->getSurcharges($product)]
  118.                         );
  119.                     } else {
  120.                         $event->getCart()->remove($lineItem->getId());
  121.                     }
  122.                 }
  123.             }
  124.         }
  125.     }
  126.     private function setProductUnitarticleInvalidError(Cart $toCalculateProductEntity $product)
  127.     {
  128.         $toCalculate->addErrors(
  129.             new ProductUnitarticleInvalidError(
  130.                 $product->getId(),
  131.                 (string)$product->getTranslation('name'))
  132.         );
  133.     }
  134.     private function setProductUnitarticleStockReachedError(Cart $cartstring $unitLabelstring $descriptionint $quantityProductEntity $product): void
  135.     {
  136.         $cart->addErrors(
  137.             new ProductUnitarticleStockReachedError(
  138.                 $product->getId(),
  139.                 (string)$product->getTranslation('name'),
  140.                 $quantity $this->priceFactorService->calculateWithCustomFields($product->getCustomFields()),
  141.                 $unitLabel,
  142.                 $description)
  143.         );
  144.     }
  145.     private function getQuantityOfSameProducts(Cart $cartProductEntity $referenceProduct)
  146.     {
  147.         $quantity 0;
  148.         foreach ($cart->getLineItems() as $lineItem) {
  149.             if ($referenceProduct->getId() == $lineItem->getReferencedId()) {
  150.                 $quantity += $lineItem->getQuantity();
  151.             }
  152.         }
  153.         return $quantity;
  154.     }
  155.     private function getSurcharges($product)
  156.     {
  157.         $surcharges = [];
  158.         if ($this->getSurcharge1($product)) {
  159.             $surcharges[] = $this->getSurcharge1($product);
  160.         }
  161.         if ($this->getSurcharge2($product)) {
  162.             $surcharges[] = $this->getSurcharge2($product);
  163.         }
  164.         return $surcharges;
  165.     }
  166.     private function getSurcharge1($product)
  167.     {
  168.         $value floatval($this->getProductCustomField($productNeonPlatformUnitarticles::CUSTOMFIELD_SURCHARGE1VALUE));
  169.         $label $this->getProductCustomField($productNeonPlatformUnitarticles::CUSTOMFIELD_SURCHARGE1LABEL);
  170.         return $value !== null
  171.             ? [
  172.                 'value' => $value,
  173.                 'label' => $label
  174.             ]
  175.             : null;
  176.     }
  177.     private function getSurcharge2($product)
  178.     {
  179.         $value floatval($this->getProductCustomField($productNeonPlatformUnitarticles::CUSTOMFIELD_SURCHARGE2VALUE));
  180.         $label $this->getProductCustomField($productNeonPlatformUnitarticles::CUSTOMFIELD_SURCHARGE2LABEL);
  181.         return $value !== null
  182.             ? [
  183.                 'value' => $value,
  184.                 'label' => $label
  185.             ]
  186.             : null;
  187.     }
  188.     /**
  189.      * @param ProductEntity $product
  190.      * @return bool
  191.      */
  192.     private function isProductUnitarticle($product): bool
  193.     {
  194.         return isset($product->getCustomFields()[NeonPlatformUnitarticles::CUSTOMFIELD_ISUNITARTICLE]) && $product->getCustomFields()[NeonPlatformUnitarticles::CUSTOMFIELD_ISUNITARTICLE];
  195.     }
  196.     /**
  197.      * @param BeforeLineItemAddedEvent $event
  198.      * @param LineItem $lineItem
  199.      * @throws \Shopware\Core\Framework\DataAbstractionLayer\Exception\InconsistentCriteriaIdsException
  200.      */
  201.     private function getProduct(BeforeLineItemAddedEvent $eventLineItem $lineItem): SalesChannelProductEntity
  202.     {
  203.         $productCollection $this->productRepository->search(new Criteria([
  204.             $lineItem->getReferencedId()
  205.         ]), $event->getSalesChannelContext());
  206.         if ($productCollection->count() === 1) {
  207.             $product $productCollection->first();
  208.         }
  209.         return $product;
  210.     }
  211.     /**
  212.      * @param ProductEntity $product
  213.      * @return bool
  214.      */
  215.     private function isQuantityHidden(SalesChannelProductEntity $product): bool
  216.     {
  217.         return array_key_exists(NeonPlatformUnitarticles::CUSTOMFIELD_HIDEQUANTITYSELECTION$product->getCustomFields()) && $product->getCustomFields()[NeonPlatformUnitarticles::CUSTOMFIELD_HIDEQUANTITYSELECTION];
  218.     }
  219.     /**
  220.      * @param ProductEntity $product
  221.      * @return bool
  222.      */
  223.     private function isMergeUserValues(SalesChannelProductEntity $product): bool
  224.     {
  225.         return array_key_exists(NeonPlatformUnitarticles::CUSTOMFIELD_MERGEUSERVALUES$product->getCustomFields()) && $product->getCustomFields()[NeonPlatformUnitarticles::CUSTOMFIELD_MERGEUSERVALUES];
  226.     }
  227.     private function getProductCustomField(SalesChannelProductEntity $productstring $key)
  228.     {
  229.         return array_key_exists($key$product->getCustomFields())
  230.             ? $product->getCustomFields()[$key]
  231.             : null;
  232.     }
  233.     private function getDefaultUnit($product$lineItem): array
  234.     {
  235.         $params = [
  236.             $lineItem->getId() => [
  237.                 NeonPlatformUnitarticles::PARAM_UNITVALUE => [
  238.                     => $this->getProductCustomField($productNeonPlatformUnitarticles::CUSTOMFIELD_DEFAULTVALUE)
  239.                 ]
  240.             ]
  241.         ];
  242.         if ($this->getProductCustomField($productNeonPlatformUnitarticles::CUSTOMFIELD_HASDIMENSION2) != null) {
  243.             $params[$lineItem->getId()][NeonPlatformUnitarticles::PARAM_UNITVALUE][2] = $product->getCustomFields()[NeonPlatformUnitarticles::CUSTOMFIELD_DEFAULTVALUE2];
  244.         }
  245.         return $params;
  246.     }
  247.     /**
  248.      * @param array $lineItemParam
  249.      * @param LineItem $lineItem
  250.      * @param ProductEntity $product
  251.      * @return array
  252.      */
  253.     private function updateLineItem(array $lineItemParamLineItem $lineItemProductEntity $product): array
  254.     {
  255.         //set new ID as we don't stack the line items which have active stock updates
  256.         $newId Uuid::randomHex();
  257.         $lineItemParam[$newId] = $lineItemParam[$lineItem->getId()];
  258.         $factor $this->priceFactorService->calculateWithCustomFields($product->getCustomFields());
  259.         $newQuantity intval(floatval($lineItemParam[$newId][NeonPlatformUnitarticles::PARAM_UNITVALUE]) * $factor);
  260.         $lineItem->setId($newId);
  261.         $lineItem->setQuantity($newQuantity);
  262.         return $lineItemParam;
  263.     }
  264.     private function getBasePrice(SalesChannelProductEntity $product)
  265.     {
  266.         $unitSign $this->getUnitSign($product);
  267.         return [
  268.             'sign' => $unitSign,
  269.             'price' => $product->getCalculatedPrice()->getUnitPrice() * $this->priceFactorService->calculateWithCustomFields($product->getCustomFields())
  270.         ];
  271.     }
  272.     private function getUnitSign(SalesChannelProductEntity $product)
  273.     {
  274.         $unitSign '';
  275.         if ($product->getCalculatedPrice()->getReferencePrice() &&
  276.             $product->getCalculatedPrice()->getReferencePrice()->getReferenceUnit()) {
  277.             if ($product->getCalculatedPrice()->getReferencePrice()->getReferenceUnit() != 1) {
  278.                 $unitSign $product->getCalculatedPrice()->getReferencePrice()->getReferenceUnit();
  279.             }
  280.             $unitSign .= $product->getCalculatedPrice()->getReferencePrice()->getUnitName();
  281.         } elseif ($product->getReferenceUnit() == && $product->getPurchaseUnit() == 1) {
  282.             $unitSign $product->getUnit()->getName();
  283.         } else {
  284.             if ($this->getProductCustomField($productNeonPlatformUnitarticles::CUSTOMFIELD_BASEPRICEVALUE) != 1) {
  285.                 $unitSign $this->getProductCustomField($productNeonPlatformUnitarticles::CUSTOMFIELD_BASEPRICEVALUE);
  286.             }
  287.             if ($this->getProductCustomField($productNeonPlatformUnitarticles::CUSTOMFIELD_BASEPRICEVALUELABEL)) {
  288.                 $unitSign .= $this->getProductCustomField($productNeonPlatformUnitarticles::CUSTOMFIELD_BASEPRICEVALUELABEL);
  289.             } else {
  290.                 $unitSign .= $this->getProductCustomField($productNeonPlatformUnitarticles::CUSTOMFIELD_UNITLABEL);
  291.             }
  292.         }
  293.         return $unitSign;
  294.     }
  295. }