custom/plugins/ProcOrderSimulate/src/Subscriber/OrderSimulateSubscriber.php line 397

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace Proc\ProcOrderSimulate\Subscriber;
  4. use Proc\ProcFoundation\Helper\RequestHandler;
  5. use Proc\ProcFoundation\Helper\ErrorHandler;
  6. use Proc\ProcFoundation\Service\ProcFoundationService;
  7. use Proc\ProcOrderSimulate\Helper\BuildRequestHelper;
  8. use Shopware\Core\Checkout\Cart\Cart;
  9. use Shopware\Core\Checkout\Cart\CartBehavior;
  10. use Shopware\Core\Checkout\Cart\Event\CheckoutOrderPlacedEvent;
  11. use Shopware\Core\Checkout\Cart\Exception\MissingPriceDefinitionException;
  12. use Shopware\Core\Checkout\Cart\LineItem\LineItem;
  13. use Shopware\Core\Checkout\Cart\LineItem\LineItemCollection;
  14. use Shopware\Core\Checkout\Cart\Price\AbsolutePriceCalculator;
  15. use Shopware\Core\Checkout\Cart\Price\CurrencyPriceCalculator;
  16. use Shopware\Core\Checkout\Cart\Price\PercentagePriceCalculator;
  17. use Shopware\Core\Checkout\Cart\Price\Struct\AbsolutePriceDefinition;
  18. use Shopware\Core\Checkout\Cart\Price\Struct\CartPrice;
  19. use Shopware\Core\Checkout\Cart\Price\Struct\CurrencyPriceDefinition;
  20. use Shopware\Core\Checkout\Cart\Price\Struct\PercentagePriceDefinition;
  21. use Shopware\Core\Checkout\Cart\Price\Struct\ListPrice;
  22. use Shopware\Core\Checkout\Cart\Tax\Struct\CalculatedTax;
  23. use Shopware\Core\Checkout\Cart\Tax\Struct\CalculatedTaxCollection;
  24. use Shopware\Core\Checkout\Cart\Price\Struct\CalculatedPrice;
  25. use Shopware\Core\Checkout\Cart\Tax\Struct\TaxRuleCollection;
  26. use Shopware\Core\Checkout\Cart\Tax\Struct\TaxRule;
  27. use Shopware\Core\Checkout\Order\OrderEntity;
  28. use Shopware\Core\Content\MailTemplate\Service\Event\MailBeforeValidateEvent;
  29. use Shopware\Core\Content\Product\Cart\ProductCartProcessor;
  30. use Shopware\Core\Content\Product\DataAbstractionLayer\CheapestPrice\CalculatedCheapestPrice;
  31. use Shopware\Core\Content\Product\DataAbstractionLayer\CheapestPrice\CheapestPriceContainer;
  32. use Shopware\Core\Content\Product\ProductEntity;
  33. use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
  34. use Shopware\Core\Framework\DataAbstractionLayer\Exception\InconsistentCriteriaIdsException;
  35. use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
  36. use Shopware\Core\System\SalesChannel\Context\AbstractSalesChannelContextFactory;
  37. use Shopware\Core\System\SalesChannel\Context\SalesChannelContextFactory;
  38. use Shopware\Core\System\SalesChannel\Context\SalesChannelContextService;
  39. use Shopware\Core\System\SalesChannel\SalesChannelContext;
  40. use Shopware\Core\System\SystemConfig\SystemConfigService;
  41. use Shopware\Storefront\Page\Checkout\Cart\CheckoutCartPageLoadedEvent;
  42. use Shopware\Storefront\Page\Checkout\Confirm\CheckoutConfirmPageLoadedEvent;
  43. use Shopware\Storefront\Page\Checkout\Finish\CheckoutFinishPageLoadedEvent;
  44. use Shopware\Storefront\Page\Checkout\Offcanvas\OffcanvasCartPageLoadedEvent;
  45. use Shopware\Storefront\Page\PageLoadedEvent;
  46. use Shopware\Core\Checkout\Cart\Delivery\Struct\Delivery;
  47. use Shopware\Core\Checkout\Cart\Delivery\Struct\DeliveryCollection;
  48. use Shopware\Core\Framework\DataAbstractionLayer\EntityCollection;
  49. use Shopware\Core\Checkout\Cart\AbstractCartPersister;
  50. use Shopware\Storefront\Page\Product\ProductPageLoadedEvent;
  51. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  52. use Shopware\Core\Checkout\Order\Aggregate\OrderLineItem\OrderLineItemEntity;
  53. /**
  54.  * Class OrderSimulateSubscriber
  55.  *
  56.  * @package Proc\ProcOrderSimulate\Subscriber
  57.  */
  58. class OrderSimulateSubscriber implements EventSubscriberInterface
  59. {
  60.     private const PLUGINNAME 'ProcOderSimulate';
  61.     private const PATH '/iman/order-simulate';
  62.     public const EUR_THRESHOLD 250;
  63.     public const ZLOTY_THRESHOLD 1062;
  64.     /**
  65.      * @var RequestHandler
  66.      */
  67.     private $requestHandler;
  68.     /**
  69.      * @var ErrorHandler
  70.      */
  71.     private $errorHandler;
  72.     /**
  73.      * @var string
  74.      */
  75.     private $host,
  76.         $port,
  77.         $customerNumber;
  78.     private $error null;
  79.     /**
  80.      * @var ProcFoundationService
  81.      */
  82.     private $foundationService;
  83.     /**
  84.      * @var EntityRepositoryInterface
  85.      */
  86.     private $productRepository;
  87.     /**
  88.      * @var CheckoutCartPageLoadedEvent | CheckoutConfirmPageLoadedEvent | CheckoutFinishPageLoadedEvent | ProductPageLoadedEvent | CheckoutOrderPlacedEvent | MailBeforeValidateEvent
  89.      */
  90.     private $event;
  91.     /**
  92.      * @var array
  93.      */
  94.     private $result;
  95.     /**
  96.      * @var CalculatedTaxCollection
  97.      */
  98.     private $calculatedTaxCollection;
  99.     /**
  100.      * @var TaxRuleCollection
  101.      */
  102.     private $taxRuleCollection;
  103.     /**
  104.      * @var LineItemCollection
  105.      */
  106.     private $lineItems;
  107.     /**
  108.      * @var Cart
  109.      */
  110.     private $cart;
  111.     /**
  112.      * @var float
  113.      */
  114.     private $lineItemsCost;
  115.     private $baseObj;
  116.     /**
  117.      * @var array
  118.      */
  119.     private $taxValues = [];
  120.     /**
  121.      * @var AbstractCartPersister
  122.      */
  123.     private $persister;
  124.     /**
  125.      * @var EntityRepositoryInterface
  126.      */
  127.     private $orderRepository;
  128.     /**
  129.      * @var DeliveryCollection
  130.      */
  131.     private $delivery;
  132.     /** Used for promotions with a fixed values */
  133.     protected const ZRN2 "ZRN2";
  134.     /** Used for promotions with percentage */
  135.     protected const ZRN0 "ZRN0";
  136.     /**
  137.      * @return array
  138.      */
  139.     static function getSubscribedEvents(): array
  140.     {
  141.         return [
  142.             // ProductPageLoadedEvent::class => ['onProductPageLoaded', 1],
  143.             // CheckoutCartPageLoadedEvent::class => ['onCartPageLoaded', 1],
  144.             // CheckoutConfirmPageLoadedEvent::class => ['onCartPageLoaded', 1],
  145.             // OffcanvasCartPageLoadedEvent::class => ['onCartPageLoaded', 1],
  146.             // CheckoutFinishPageLoadedEvent::class => ['onFinishPageLoaded', 1],
  147.             CheckoutOrderPlacedEvent::class => ['onCheckoutOrderPlaced'1],
  148.             MailBeforeValidateEvent::class => ['mailBeforeSent'1]
  149.         ];
  150.     }
  151.     /**
  152.      * OrderSimulateSubscriber constructor.
  153.      *
  154.      * @param ProcFoundationService $foundationService
  155.      * @param RequestHandler $requestHandler
  156.      * @param ErrorHandler $errorHandler
  157.      * @param EntityRepositoryInterface $repositoryInterface
  158.      * @param AbstractCartPersister $persister
  159.      * @param SalesChannelContextFactory $salesChannelContextFactory
  160.      */
  161.     public function __construct(
  162.         ProcFoundationService $foundationService,
  163.         RequestHandler $requestHandler,
  164.         ErrorHandler $errorHandler,
  165.         EntityRepositoryInterface $repositoryInterface,
  166.         AbstractCartPersister $persister,
  167.         EntityRepositoryInterface $orderRepository,
  168.         AbstractSalesChannelContextFactory $salesChannelContextFactory,
  169.         private readonly PercentagePriceCalculator $percentageCalculator,
  170.         private readonly AbsolutePriceCalculator $absolutePriceCalculator,
  171.     ) {
  172.         $this->foundationService $foundationService;
  173.         $this->requestHandler $requestHandler;
  174.         $this->errorHandler $errorHandler;
  175.         $this->productRepository $repositoryInterface;
  176.         $this->persister $persister;
  177.         $this->orderRepository $orderRepository;
  178.         $this->salesChannelContextFactory $salesChannelContextFactory;
  179.     }
  180.     public function mailBeforeSent(MailBeforeValidateEvent $event)
  181.     {
  182.         $this->event $event;
  183.         $discount null;
  184.         $globalDiscountRate null;
  185.         $globalDiscountValue null;
  186.         $globalTotalAmount null;
  187.         $globalTotalNetAmount null;
  188.         $globalShippingAmount null;
  189.         if (array_key_exists('priceInformations'$this->event->getContext()->getExtensions())) {
  190.             $discount $this->event->getContext()->getExtensions()['priceInformations']['discountSum'];
  191.             $globalDiscountValue $this->event->getContext()->getExtensions()['priceInformations']['globalDiscountValue'];
  192.             $globalDiscountRate $this->event->getContext()->getExtensions()['priceInformations']['globalDiscountRate'];
  193.         }
  194.         if (array_key_exists('priceTotalInformations'$this->event->getContext()->getExtensions())) {
  195.             $globalTotalAmount $this->event->getContext()->getExtensions()['priceTotalInformations']['globalTotalAmount'];
  196.             $globalTotalNetAmount $this->event->getContext()->getExtensions()['priceTotalInformations']['globalTotalNetAmount'];
  197.             $globalShippingAmount $this->event->getContext()->getExtensions()['priceTotalInformations']['globalShippingAmount'];
  198.         }
  199.         $this->event->addTemplateData('discount'$discount);
  200.         $this->event->addTemplateData('globalDiscountValue'$globalDiscountValue);
  201.         $this->event->addTemplateData('globalDiscountRate'$globalDiscountRate);
  202.         $this->event->addTemplateData('globalTotalAmount'$globalTotalAmount);
  203.         $this->event->addTemplateData('globalTotalNetAmount'$globalTotalNetAmount);
  204.         $this->event->addTemplateData('globalShippingAmount'$globalShippingAmount);
  205.     }
  206.     /**
  207.      * @param PageLoadedEvent $event
  208.      * @throws \Exception
  209.      */
  210.     public function onProductPageLoaded(ProductPageLoadedEvent $event): void
  211.     {
  212.         $this->event $event;
  213.         /**
  214.          * Prüfung ob Benutzer angemeldet ist, sonst keine Live-Abfrage.
  215.          */
  216.         if (!($this->customerNumber $this->foundationService->checkLogin(
  217.             $this->event->getSalesChannelContext(),
  218.             self::PLUGINNAME
  219.         ))) {
  220.             return;
  221.         }
  222.         /**
  223.          * Configeinstellungen prüfen und setzen.
  224.          */
  225.         if (!$this->checkConfig()) {
  226.             return;
  227.         }
  228.         /**
  229.          * @var array $articles
  230.          */
  231.         $product $this->event->getPage()->getProduct();
  232.         $articles $this->articleData($product);
  233.         $this->result $this->getArticleInfo($articles);
  234.         if (isset($this->result['shipping-costs']) && isset($this->result['shipping-costs']['free-shipping-threshold'])) {
  235.             $freeShippingThreshold = (int)$this->result['shipping-costs']['free-shipping-threshold'];
  236.         } else {
  237.             $freeShippingThreshold $this->calculateShippingThreshold();
  238.         }
  239.         $extension = [
  240.             'freeShippingThreshold' => $freeShippingThreshold,
  241.         ];
  242.         $this->event->getSalesChannelContext()->getShippingMethod()->addArrayExtension(
  243.             'deliveryInformations',
  244.             $extension
  245.         );
  246.         $this->error $this->errorHandler->error(
  247.             $this->errorHandler::UNKNOWN_REQUEST,
  248.             get_class($this),
  249.             'Result: ' print_r($this->resulttrue)
  250.         );
  251.         $this->errorHandler->writeErrorLog($this->error);
  252.     }
  253.     private function articleData($product): array
  254.     {
  255.         $articleData = [];
  256.         $customFields $product->getCustomFields();
  257.         $article['number'] = $product->getProductNumber();
  258.         $article['quantity'] = $product->getCalculatedPrice()->getQuantity();
  259.         $article['division'] = $customFields['custom_salesdata_division'];
  260.         $article['quantity-unit'] = $product->getPackUnit();
  261.         $article["position"] = 0;
  262.         $articleData[] = $article;
  263.         return $articleData;
  264.     }
  265.     public function onCartPageLoaded(PageLoadedEvent $event): void
  266.     {
  267.         $this->event $event;
  268.         /**
  269.          * Prüfung ob Benutzer angemeldet ist, sonst keine Live-Abfrage.
  270.          */
  271.         if (!($this->customerNumber $this->foundationService->checkLogin(
  272.             $this->event->getSalesChannelContext(),
  273.             self::PLUGINNAME
  274.         ))) {
  275.             return;
  276.         }
  277.         /**
  278.          * Configeinstellungen prüfen und setzen.
  279.          */
  280.         if (!$this->checkConfig()) {
  281.             return;
  282.         }
  283.         $this->cart $this->event->getPage()->getCart();
  284.         //dd($this->cart);
  285.         $this->lineItems $this->cart->getLineItems()->filterType(LineItem::PRODUCT_LINE_ITEM_TYPE);
  286.         /** @var LineItem $promotion */
  287.         $promotion $this->cart->getLineItems()->filterType(LineItem::PROMOTION_LINE_ITEM_TYPE)?->first();
  288.         if ($this->lineItems->count() < 1) {
  289.             return;
  290.         }
  291.         /** @var array $articles */
  292.         $articles $this->lineItemsToArticles();
  293.         $this->addDiscountToRequest($promotion$articles);
  294.         $this->result $this->getArticleInfo($articles);
  295.         $this->error $this->errorHandler->error(
  296.             $this->errorHandler::UNKNOWN_REQUEST,
  297.             get_class($this),
  298.             'Result: ' print_r($this->resulttrue)
  299.         );
  300.         $this->errorHandler->writeErrorLog($this->error);
  301.         if (array_key_exists('head'$this->result) && $this->result['head']['status'] == 'NOK') {
  302.             return;
  303.         }
  304.         $this->taxRuleCollection = new TaxRuleCollection();
  305.         $this->calculatedTaxCollection = new CalculatedTaxCollection();
  306.         $sum $this->lineItemsCost $this->calculateLineItems();
  307.         $this->setDiscount($sum);
  308.         // Set discount value from response after all other lineItems have their price set "$this->calculateLineItems()"
  309.         $this->calculateDiscount($promotion);
  310.         /**
  311.          * @var CalculatedTax $shippingCosts
  312.          */
  313.         $this->cart->setPrice($this->calculateNewCartPrice());
  314.         if (isset($this->result['shipping-costs']) && isset($this->result['shipping-costs']['free-shipping-threshold'])) {
  315.             //            $shippingCosts = $this->result['shipping-costs']['condition-value'];
  316.             $freeShippingThreshold = (int)$this->result['shipping-costs']['free-shipping-threshold'];
  317.         } else {
  318.             $freeShippingThreshold $this->calculateShippingThreshold();
  319.         }
  320.         $extension = [
  321.             'freeShippingThreshold' => $freeShippingThreshold,
  322.         ];
  323.         $this->event->getPage()->getCart()->getDeliveries()->addArrayExtension('deliveryInformations'$extension);
  324.         $this->event->getSalesChannelContext()->setPermissions([ProductCartProcessor::SKIP_PRODUCT_RECALCULATION]);
  325.         $this->cart->setBehavior(new CartBehavior([ProductCartProcessor::SKIP_PRODUCT_RECALCULATION]));
  326.         $this->persister->save($this->cart$this->event->getSalesChannelContext());
  327.     }
  328.     public function onCheckoutOrderPlaced(CheckoutOrderPlacedEvent $event)
  329.     {
  330.         $this->event $event;
  331.         $this->order $this->event->getOrder();
  332.         /**
  333.          * Configeinstellungen prüfen und setzen.
  334.          */
  335.         if (!$this->checkConfig()) {
  336.             return;
  337.         }
  338.         $this->lineItems $this->event->getOrder()->getLineItems()->filterByType(LineItem::PRODUCT_LINE_ITEM_TYPE);
  339.         /** @var LineItem $promotion */
  340.         $promotion $this->event->getOrder()->getLineItems()->filterByType(LineItem::PROMOTION_LINE_ITEM_TYPE)?->first();
  341.         if ($this->lineItems->count() < 1) {
  342.             return;
  343.         }
  344.         /**
  345.          * @var array $articles
  346.          */
  347.         $articles $this->lineItemsToArticles();
  348.         $this->addDiscountToRequest($promotion$articles);
  349.         $this->result $this->getArticleInfo($articles);
  350.         $this->error $this->errorHandler->error(
  351.             $this->errorHandler::UNKNOWN_REQUEST,
  352.             get_class($this),
  353.             'Result: ' print_r($this->resulttrue)
  354.         );
  355.         $this->errorHandler->writeErrorLog($this->error);
  356.         if (array_key_exists('head'$this->result) && $this->result['head']['status'] == 'NOK') {
  357.             return;
  358.         }
  359.         $this->taxRuleCollection = new TaxRuleCollection();
  360.         $this->calculatedTaxCollection = new CalculatedTaxCollection();
  361.         $sum $this->lineItemsCost $this->calculateLineItems();
  362.         $this->setDiscount($sum);
  363.         // Set discount value from response after all other lineItems have their price set "$this->calculateLineItems()"
  364.         $this->calculateDiscount($promotion);
  365.     }
  366.     /**
  367.      * @param CheckoutFinishPageLoadedEvent $event
  368.      * @throws InconsistentCriteriaIdsException
  369.      */
  370.     public function onFinishPageLoaded(CheckoutFinishPageLoadedEvent $event)
  371.     {
  372.         $this->event $event;
  373.         /**
  374.          * Prüfung ob Benutzer angemeldet ist, sonst keine Live-Abfrage.
  375.          */
  376.         if (!($this->customerNumber $this->foundationService->checkLogin(
  377.             $this->event->getSalesChannelContext(),
  378.             self::PLUGINNAME
  379.         ))) // $this->errorHandler->writeErrorLog(['foundationService']);
  380.         {
  381.             return;
  382.         }
  383.         /**
  384.          * Configeinstellungen prüfen und setzen.
  385.          */
  386.         if (!$this->checkConfig()) // $this->errorHandler->writeErrorLog(['checkConfig']);
  387.         {
  388.             return;
  389.         }
  390.         $this->lineItems $this->event->getPage()->getOrder()->getLineItems()->filterByType(LineItem::PRODUCT_LINE_ITEM_TYPE);
  391.         $promotion $this->event->getPage()->getOrder()->getLineItems()->filterByType(LineItem::PROMOTION_LINE_ITEM_TYPE)?->first();
  392.         /**
  393.          * @var array $articles
  394.          */
  395.         $articles $this->lineItemsToArticles();
  396.         $this->addDiscountToRequest($promotion$articles);
  397.         if ($articles === false) {
  398.             return;
  399.         }
  400.         $this->result $this->getArticleInfo($articles);
  401.         if ($this->result['head']['status'] == 'NOK') {
  402.             // $this->errorHandler->writeErrorLog(['status']);
  403.             return;
  404.         }
  405.         $freeShippingThreshold $this->calculateShippingThreshold();
  406.         $shippingCosts 0;
  407.         if (array_key_exists('free-shipping-threshold'$this->result['shipping-costs']))
  408.             $freeShippingThreshold = (int) $this->result['shipping-costs']['free-shipping-threshold'];
  409.         if (array_key_exists('pickup-only'$this->result['shipping-costs'])) {
  410.             $pickupOnly = (bool)$this->result['shipping-costs']['pickup-only'];
  411.         } else {
  412.             $pickupOnly false;
  413.         }
  414.         $this->taxRuleCollection = new TaxRuleCollection();
  415.         $this->calculatedTaxCollection = new CalculatedTaxCollection();
  416.         $sum $this->lineItemsCost $this->calculateLineItems();
  417.         $this->setDiscount($sum);
  418.         // Set discount value from response after all other lineItems have their price set "$this->calculateLineItems()"
  419.         $this->calculateDiscount($promotion);
  420.         /**
  421.          * @var OrderEntity $order
  422.          */
  423.         $order $this->event->getPage()->getOrder();
  424.         $order->setPrice($this->calculateNewCartPrice());
  425.         $netPrice $order->getPrice()->getPositionPrice();
  426.         if (array_key_exists('condition-value'$this->result['shipping-costs']) && ($netPrice $freeShippingThreshold)) {
  427.             $shippingCosts = (float) $this->result['shipping-costs']['condition-value'];
  428.         }
  429.         $this->saveOrder(
  430.             $order->getId(),
  431.             $order->getPrice(),
  432.             $pickupOnly,
  433.             $freeShippingThreshold,
  434.             $shippingCosts,
  435.             $this->result['shipping-costs']
  436.         );
  437.     }
  438.     /**
  439.      * @param string $orderId
  440.      * @param CartPrice $price
  441.      * @return void
  442.      */
  443.     private function saveOrder(string $orderIdCartPrice $price$pickupOnly$freeShippingThreshold$shippingCosts$tempConditionTree)
  444.     {
  445.         $tax = (float) $tempConditionTree['condition-value'];
  446.         $taxRate = (float) $tempConditionTree['condition-rate'];
  447.         $calTaxCollection = new CalculatedTaxCollection();
  448.         $taxRuleCollection = new TaxRuleCollection();
  449.         $calTaxCollection->add(new CalculatedTax($tax$taxRate$price->getTotalPrice()));
  450.         $taxRuleCollection->add(new TaxRule($taxRate));
  451.         foreach ($this->lineItems as $lineItem) {
  452.             $lineItems[] = [
  453.                 "id" => $lineItem->getId(),
  454.                 "identifier" => $lineItem->getIdentifier(),
  455.                 "totalPrice" => $lineItem->getPrice()->getTotalPrice(),
  456.                 "unitPrice" => $lineItem->getPrice()->getUnitPrice(),
  457.                 "label" => $lineItem->getLabel(),
  458.                 "price" => $lineItem->getPrice(),
  459.                 "quantity" => $lineItem->getQuantity(),
  460.             ];
  461.         }
  462.         $shippingCostsArray = [
  463.             'taxRules' => $taxRuleCollection,
  464.             'calculatedTaxes' => $calTaxCollection,
  465.             'quantity' => 1,
  466.             'totalPrice' => $shippingCosts,
  467.             'unitPrice' => $shippingCosts
  468.         ];
  469.         $orderData = [
  470.             'id' => $orderId,
  471.             'price' => $price,
  472.             'shippingCosts' => $shippingCostsArray,
  473.             'lineItems' => $lineItems,
  474.             'deliveries' => [
  475.                 [
  476.                     'id' => $this->delivery->getId(),
  477.                     'shippingCosts' => $shippingCostsArray,
  478.                     'shippingDateLatest' => $this->delivery->getShippingDateLatest(),
  479.                     'shippingDateEarliest' => $this->delivery->getShippingDateEarliest(),
  480.                     'shippingOrderAddressId' => $this->delivery->getShippingOrderAddressId(),
  481.                     'shippingMethodId' => $this->delivery->getShippingMethodId(),
  482.                     'trackingCodes' => $this->delivery->getTrackingCodes()
  483.                 ]
  484.             ],
  485.             'customFields' => [
  486.                 'custom_shippingCosts_pickupOnly' => (bool)$pickupOnly,
  487.                 'custom_shippingCosts_freeShippingThreshold' => (int)$freeShippingThreshold
  488.             ]
  489.         ];
  490.         $this->errorHandler->writeErrorLog($orderData);
  491.         $this->orderRepository->update([$orderData], $this->event->getContext());
  492.     }
  493.     /**
  494.      * @param array $articles
  495.      * @param int $shopInstance
  496.      * @param string $salesOrganization
  497.      * @param string $distributionChannel
  498.      * @param string $division
  499.      * @param string $currency
  500.      * @param string $language
  501.      * @return array
  502.      */
  503.     public function getArticleInfo(
  504.         array  $articles,
  505.         int    $shopInstance 1,
  506.         string $salesOrganization 'DE01',
  507.         string $distributionChannel '01',
  508.         string $division '00',
  509.         string $language 'DE'
  510.     ): array {
  511.         if (!$this->customerNumber && $this->order) {
  512.             $this->customerNumber $this->order->getOrderCustomer()->getCustomer()->getCustomFields()['custom_sap_number'];
  513.         }
  514.         $params = [
  515.             'shop-instance' => $shopInstance,
  516.             'language'      => $language,
  517.             'customer'      => $this->customerNumber,
  518.             'customer-we'   => $this->customerNumber,
  519.             'order-type'    => 'ZDSA',
  520.             'currency'      => $this->getCurrencyISO(),
  521.             'delivery-date' => date('Y-m-d'),
  522.         ];
  523.         $buildRequestHelper = new BuildRequestHelper($params$articles$this->errorHandler);
  524.         /**
  525.          * @var string $request
  526.          */
  527.         $request $this->requestHandler->buildRequest($buildRequestHelperself::PLUGINNAME);
  528.         if ($request !== '') {
  529.             /**
  530.              * @var string $result
  531.              */
  532.             $result $this->requestHandler->sendRequest($this->host$this->portself::PATH$request);
  533.         } else {
  534.             $this->error $this->errorHandler->error(
  535.                 $this->errorHandler::UNKNOWN_REQUEST,
  536.                 get_class($this),
  537.                 'Fehler im Aufbau des Request'
  538.             );
  539.             $this->errorHandler->writeErrorLog($this->error);
  540.             return [];
  541.         }
  542.         $this->error $this->errorHandler->error(
  543.             $this->errorHandler::UNKNOWN_REQUEST,
  544.             get_class($this),
  545.              $request
  546.         );
  547.         $this->error $this->errorHandler->error(
  548.             $this->errorHandler::UNKNOWN_REQUEST,
  549.             get_class($this),
  550.             $result
  551.         );
  552.         /**
  553.          * @var array $resultArray
  554.          */
  555.         return $this->requestHandler->parseResult($result);
  556.     }
  557.     /**
  558.      * @return bool
  559.      */
  560.     private function checkConfig(): bool
  561.     {
  562.         if ($this->foundationService->getConfigStatus()) {
  563.             $this->host $this->foundationService->getHost();
  564.             $this->port $this->foundationService->getPort();
  565.             return true;
  566.         }
  567.         $this->error $this->errorHandler->error(
  568.             $this->errorHandler::CONFIG_NOT_VALID,
  569.             get_class($this),
  570.             'Konnte die Konfiguration nicht ermitteln'
  571.         );
  572.         $this->errorHandler->writeErrorLog($this->error);
  573.         return false;
  574.     }
  575.     /**
  576.      * @return array
  577.      */
  578.     private function lineItemsToArticles(): array
  579.     {
  580.         /**
  581.          * @var array $articles
  582.          */
  583.         $articles = [];
  584.         /**
  585.          * @todo Die position-id noch richtig machen
  586.          */
  587.         $count 0;
  588.         /** @var LineItem $lineItem */
  589.         foreach ($this->lineItems as $lineItem) {
  590.             if ($lineItem->getType() === LineItem::PROMOTION_LINE_ITEM_TYPE) {
  591.                 continue;
  592.             }
  593.             $count++;
  594.             $product $this->getProduct($lineItem->getReferencedId());
  595.             $customFields $product->getCustomFields();
  596.             $article['position'] = $count;
  597.             $article['number'] = $product->getProductNumber();
  598.             $article['quantity'] = $lineItem->getPrice()->getQuantity();
  599.             $article['division'] = $customFields['custom_salesdata_division'];
  600.             $article['quantity-unit'] = $product->getPackUnit();
  601.             $articles[] = $article;
  602.         }
  603.         return $articles;
  604.     }
  605.     /**
  606.      * @param string $productID
  607.      * @return ProductEntity
  608.      */
  609.     public function getProduct(string $productID, array $associations null): ProductEntity
  610.     {
  611.         /**
  612.          * @var Criteria $criteria
  613.          */
  614.         $criteria = new Criteria([$productID]);
  615.         if ($associations !== null) {
  616.             foreach ($associations as $association) {
  617.                 $criteria->addAssociation($association);
  618.             }
  619.         }
  620.         /**
  621.          * @var EntityCollection $products
  622.          */
  623.         $products $this->productRepository->search(
  624.             $criteria,
  625.             \Shopware\Core\Framework\Context::createDefaultContext()
  626.         );
  627.         /**
  628.          * @var array $productList
  629.          */
  630.         $productList $products->getElements();
  631.         /**
  632.          * @var ProductEntity $product
  633.          */
  634.         $product $productList[$productID];
  635.         return $product;
  636.     }
  637.     function calculateLineItems(): float
  638.     {
  639.         // $this->result = Ergebnis des Requests
  640.         $count 0;
  641.         $sum 0.0;
  642.         /** @var LineItem $lineItem */
  643.         foreach ($this->lineItems as $lineItem) {
  644.             if ($lineItem->getType() === LineItem::PROMOTION_LINE_ITEM_TYPE) {
  645.                 continue;
  646.             }
  647.             if (array_key_exists(0$this->result['articles']['article'])) {
  648.                 $articleArray $this->result['articles']['article'][$count];
  649.             } else {
  650.                 $articleArray $this->result['articles']['article'];
  651.             }
  652.             $tempConditionTree null;
  653.             if (array_key_exists(0$articleArray['conditions']['condition'])) {
  654.                 if ($articleArray['conditions']['condition'][0]['condition-type'] === 'MWST') {
  655.                     $tempConditionTree $articleArray['conditions']['condition'][0];
  656.                 } else {
  657.                     $tempConditionTree $articleArray['conditions']['condition'][1];
  658.                 }
  659.             } else {
  660.                 $tempConditionTree $articleArray['conditions']['condition'];
  661.             }
  662.             $tax $price = (float)$tempConditionTree['condition-value'];
  663.             $taxRate = (float)$tempConditionTree['condition-rate'];
  664.             $calTaxCollection = new CalculatedTaxCollection();
  665.             $taxRuleCollection = new TaxRuleCollection();
  666.             $calTaxCollection->add(new CalculatedTax($tax$taxRate$price));
  667.             $taxRuleCollection->add(new TaxRule($taxRate));
  668.             if (!array_key_exists((string)$taxRate$this->taxValues)) {
  669.                 $this->taxValues[(string)$taxRate] = 0.0;
  670.             }
  671.             $this->taxValues[(string)$taxRate] += $price;
  672.             $this->taxRuleCollection->add(new TaxRule($taxRate));
  673.             $newCalculatedPrice = new CalculatedPrice(
  674.                 (float)$articleArray['net-position-value'],
  675.                 (float)$articleArray['net-position-sum'],
  676.                 $calTaxCollection,
  677.                 $taxRuleCollection,
  678.                 (int)$articleArray['quantity']
  679.             );
  680.             $sum += (float)$articleArray['net-position-sum'];
  681.             $lineItem->setPrice($newCalculatedPrice);
  682.             $count++;
  683.         }
  684.         return $sum;
  685.     }
  686.     function calculateNewTotals()
  687.     {
  688.         /**
  689.          * @var CalculatedPrice
  690.          */
  691.         $pickup false;
  692.         $addPrice 0;
  693.         if ($this->result['shipping-costs']) {
  694.             $addPrice = isset($this->result['shipping-costs']['condition-value']) ? (float)$this->result['shipping-costs']['condition-value'] : 0.0;
  695.             if (isset($this->result['shipping-costs']['free-shipping-threshold'])) {
  696.                 $freeShippingThreshold = (int)$this->result['shipping-costs']['free-shipping-threshold'];
  697.             } else {
  698.                 $freeShippingThreshold $this->calculateShippingThreshold();
  699.             }
  700.             if ($this->lineItemsCost >= $freeShippingThreshold || $pickup) {
  701.                 $addPrice 0.0;
  702.             }
  703.         }
  704.         /**
  705.          * @var CalculatedPrice
  706.          */
  707.         $newShippingPrice $this->getNewShippingPrice($addPrice);
  708.         $taxSum 0.0;
  709.         foreach ($this->taxValues as $key => $value) {
  710.             $this->calculatedTaxCollection->add(new CalculatedTax($value, (float) $key$value));
  711.             $taxSum += $value;
  712.         }
  713.         $globalTotalAmount $this->lineItemsCost $newShippingPrice->getTotalPrice() + $taxSum;
  714.         $globalTotalNetAmount $this->lineItemsCost $newShippingPrice->getTotalPrice();
  715.         $extension = array();
  716.         $extension['globalTotalAmount'] = (float)$globalTotalAmount;
  717.         $extension['globalTotalNetAmount'] = (float)$globalTotalNetAmount;
  718.         $extension['globalShippingAmount'] = (float)$addPrice;
  719.         $this->event->getContext()->addArrayExtension('priceTotalInformations'$extension);
  720.     }
  721.     function calculateNewCartPrice()
  722.     {
  723.         if ($this->event instanceof CheckoutFinishPageLoadedEvent) {
  724.             $this->baseObj $this->event->getPage()->getOrder();
  725.         } else {
  726.             $this->baseObj $this->event->getPage()->getCart();
  727.         }
  728.         /**
  729.          * @var CartPrice
  730.          */
  731.         $cartPrice $this->baseObj->getPrice();
  732.         /**
  733.          * @var DeliveryCollection
  734.          */
  735.         $deliveryCosts $this->baseObj->getDeliveries();
  736.         /**
  737.          * @var Delivery
  738.          */
  739.         $delivery $deliveryCosts->first();
  740.         /**
  741.          * @var CalculatedPrice
  742.          */
  743.         $customfields $this->event->getSalesChannelContext()->getCustomer()->getCustomFields();
  744.         $pickup key_exists('custom_sap_pickup'$customfields) ? $customfields['custom_sap_pickup'] : false;
  745.         if (isset($this->result['shipping-costs'])) {
  746.             $addPrice = isset($this->result['shipping-costs']['condition-value']) ? (float)$this->result['shipping-costs']['condition-value'] : 0.0;
  747.             if (isset($this->result['shipping-costs']['free-shipping-threshold'])) {
  748.                 $freeShippingThreshold = (int)$this->result['shipping-costs']['free-shipping-threshold'];
  749.             } else {
  750.                 $freeShippingThreshold $this->calculateShippingThreshold();
  751.             }
  752.             if ($this->lineItemsCost >= $freeShippingThreshold || $pickup) {
  753.                 $addPrice 0.0;
  754.             }
  755.         }
  756.         /**
  757.          * @var CalculatedPrice
  758.          */
  759.         $newShippingPrice $this->getNewShippingPrice($addPrice);
  760.         $delivery->setShippingCosts($newShippingPrice);
  761.         $this->delivery $delivery;
  762.         $taxSum 0.0;
  763.         foreach ($this->taxValues as $key => $value) {
  764.             $this->calculatedTaxCollection->add(new CalculatedTax($value, (float)$key$value));
  765.             $taxSum += $value;
  766.         }
  767.         $globalTotalAmount $this->lineItemsCost $newShippingPrice->getTotalPrice() + $taxSum;
  768.         $globalTotalNetAmount $this->lineItemsCost $newShippingPrice->getTotalPrice();
  769.         $newCartPrice = new CartPrice(
  770.             $globalTotalNetAmount,
  771.             $globalTotalAmount,
  772.             $this->lineItemsCost,
  773.             $this->calculatedTaxCollection,
  774.             $this->taxRuleCollection,
  775.             $cartPrice->getTaxStatus()
  776.         );
  777.         return $newCartPrice;
  778.     }
  779.     private function getNewShippingPrice(float $addPrice): CalculatedPrice
  780.     {
  781.         $unitPrice $totalPrice $addPrice;
  782.         return new CalculatedPrice($unitPrice$totalPrice, new CalculatedTaxCollection(), new TaxRuleCollection());
  783.     }
  784.     private function setDiscount($sum)
  785.     {
  786.         /**
  787.          * @var int $count
  788.          */
  789.         $count 0;
  790.         $discountSum 0;
  791.         $globalDiscountValueSum 0;
  792.         $globalDiscountRate 0;
  793.         $discountRate 0;
  794.         foreach ($this->lineItems as $lineItem) {
  795.             if (count($this->lineItems) > && array_key_exists($count$this->result['articles']['article'])) {
  796.                 $articleArray $this->result['articles']['article'][$count];
  797.             } else {
  798.                 $articleArray $this->result['articles']['article'];
  799.             }
  800.             if (array_key_exists('condition-type'$condition $articleArray['conditions']['condition'])) {
  801.                 if ($condition['condition-type'] == "ZRN1") {
  802.                     $discountValue $condition['condition-value'];
  803.                     $discountRate $condition['condition-rate'];
  804.                     $extension = [
  805.                         'discountValue' => (float) $discountValue,
  806.                         'discountRate' => round((float) $discountRate2)
  807.                     ];
  808.                     $lineItem->addArrayExtension('lineItemDiscount'$extension);
  809.                     $discountSum += $discountValue;
  810.                     $this->addCustomField($lineItem"discountLabel""Shop Gutschein ZRN1 wurde als Sondernachlaß berücksichtigt");
  811.                 } elseif ($condition['condition-type'] == "ZECO") {
  812.                     $globalDiscountValue $condition['condition-value'];
  813.                     $globalDiscountValueSum += $globalDiscountValue;
  814.                     $globalDiscountRate $condition['condition-rate'];
  815.                     $extension = [
  816.                         'globalDiscountValue' => (float) $globalDiscountValue,
  817.                         'globalDiscountRate' => round((float) $globalDiscountRate2)
  818.                     ];
  819.                     $lineItem->addArrayExtension('lineItemGlobalDiscount'$extension);
  820.                     $this->addCustomField($lineItem"discountLabel""Shop Gutschein ZECO wurde als Sondernachlaß berücksichtigt");
  821.                 }
  822.             } else {
  823.                 foreach ($articleArray['conditions']['condition'] as $condition) {
  824.                     if ($condition['condition-type'] == "ZRN1") {
  825.                         $discountValue $condition['condition-value'];
  826.                         $discountRate $condition['condition-rate'];
  827.                         $extension = [
  828.                             'discountValue' => (float) $discountValue,
  829.                             'discountRate' => round((float) $discountRate2)
  830.                         ];
  831.                         $lineItem->addArrayExtension('lineItemDiscount'$extension);
  832.                         $discountSum += $discountValue;
  833.                         $this->addCustomField($lineItem"discountLabel""Shop Gutschein ZECO wurde als Sondernachlaß berücksichtigt");
  834.                     }
  835.                     if ($condition['condition-type'] == "ZECO") {
  836.                         $globalDiscountValue $condition['condition-value'];
  837.                         $globalDiscountValueSum += $globalDiscountValue;
  838.                         $globalDiscountRate $condition['condition-rate'];
  839.                         $extension = [
  840.                             'globalDiscountValue' => (float) $globalDiscountValue,
  841.                             'globalDiscountRate' => round((float) $globalDiscountRate2)
  842.                         ];
  843.                         $lineItem->addArrayExtension('lineItemGlobalDiscount'$extension);
  844.                         $this->addCustomField($lineItem"discountLabel""Shop Gutschein ZECO wurde als Sondernachlaß berücksichtigt");
  845.                     }
  846.                 }
  847.             }
  848.             $count++;
  849.         }
  850.         $extension = [
  851.             'discountRate' =>  round((float) $discountRate2),
  852.             'discountSum'  => $discountSum,
  853.             'globalDiscountValue' => (float) $globalDiscountValueSum,
  854.             'globalDiscountRate' => round((float) $globalDiscountRate2),
  855.         ];
  856.         $this->event->getContext()->addArrayExtension('priceInformations'$extension);
  857.     }
  858.     /**
  859.      * fts - Retrieve currency iso code from saleschannel context
  860.      * @return string
  861.      */
  862.     private function getCurrencyISO(): string
  863.     {
  864.         return $this->getSalesChannelContext()?->getCurrency()->getIsoCode() ?? "EUR";
  865.     }
  866.     /**
  867.      * If the current currency is not EUR, then the default threshold (250€)
  868.      * will be converted to the appropriate currency using the currency factor.
  869.      * @return int
  870.      */
  871.     private function calculateShippingThreshold(): int
  872.     {
  873.         if ($this->getSalesChannelContext()->getCurrency()->getIsoCode() === "PLN") {
  874.             return self::ZLOTY_THRESHOLD;
  875.         } else {
  876.             return self::EUR_THRESHOLD;
  877.         }
  878.     }
  879.     private function getSalesChannelContext(): SalesChannelContext
  880.     {
  881.         if ($this->event instanceof CheckoutOrderPlacedEvent) {
  882.             return $this->salesChannelContextFactory->create(""$this->event->getSalesChannelId());
  883.         } else {
  884.             return $this->event->getSalesChannelContext();
  885.         }
  886.     }
  887.     /**
  888.      * @426 - Set discount value from response after all other lineItems have their price set "$this->calculateLineItems()"
  889.      * **lineItemsCost += discount value**
  890.      * @param OrderLineItemEntity|LineItem|null $promotion
  891.      * @return void
  892.      */
  893.     private function calculateDiscount(OrderLineItemEntity|LineItem|null $promotion): void
  894.     {
  895.         if ($promotion && isset($this->result["discounts"])) {
  896.             if ($this->event instanceof CheckoutOrderPlacedEvent) {
  897.                 $context $this->salesChannelContextFactory->create(""$this->event->getSalesChannelId());
  898.             } else {
  899.                 $context $this->event->getSalesChannelContext();
  900.             }
  901.             foreach ($this->result["discounts"] as $discount) {
  902.                 if (!isset($discount["code"]) || !isset($discount["value"])) {
  903.                     continue;
  904.                 }
  905.                 // Promotion with percentage, calculate
  906.                 if ($discount["code"] === self::ZRN0) {
  907.                     $value = -abs((float)$discount["value"]);
  908.                     // Set value that was calculated from SAP. Dont use shopware's price calculation
  909.                     $promotion->addArrayExtension("sap",["discountValue" => $value]);
  910.                     $calculated_price $this->percentageCalculator->calculate(
  911.                         (float)$value,
  912.                         $this->lineItems->getPrices(),
  913.                         $context
  914.                     );
  915.                 } elseif ($discount["code"] === self::ZRN2) {
  916.                     $value = -abs((float)$discount["value"]);
  917.                     // Set value that was calculated from SAP. Dont use shopware's price calculation
  918.                     $promotion->addArrayExtension("sap",["discountValue" => $value]);
  919.                     // Promotion with fixed value, calculate
  920.                     $calculated_price $this->absolutePriceCalculator->calculate(
  921.                         (float)$value,
  922.                         $this->lineItems->getPrices(),
  923.                         $context
  924.                     );
  925.                 }
  926.                 if ($calculated_price !== null) {
  927.                     $promotion->setPrice($calculated_price);
  928.                     // Subtract the discount from the current total
  929.                     $this->lineItemsCost += $promotion->getPrice()->getTotalPrice();
  930.                 }
  931.             }
  932.         }
  933.     }
  934.     /**
  935.      * @426 - Adds the promotion with it's corresponding code (ZRN0 | ZRN2) to the request array.
  936.      * @param LineItem|OrderLineItemEntity|null $promotion
  937.      * @param array $articles
  938.      * @return void
  939.      */
  940.     private function addDiscountToRequest(OrderLineItemEntity|LineItem|null $promotion, array &$articles): void
  941.     {
  942.         if ($promotion) {
  943.             $promotionType $promotion?->getPayload()["discountType"];
  944.             $code $promotionType === "percentage" self::ZRN0 self::ZRN2;
  945.             $articles["discounts"][] = ["code" => $code"value" => $promotion?->getPayload()["value"]];
  946.         }
  947.     }
  948.     private function addCustomField(LineItem|OrderLineItemEntity &$lineItemstring $keymixed $value): void
  949.     {
  950.         if($lineItem instanceof OrderLineItemEntity) {
  951.             $payload $lineItem->getPayload();
  952.             $payload["customFields"][$key] = $value;
  953.         } else {
  954.             $customFields $lineItem->getPayloadValue("customFields");
  955.             $customFields[$key] = $value;
  956.             $lineItem->setPayloadValue("customFields"$customFields);
  957.         }
  958.     }
  959. }