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

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