vendor/thelia/core/lib/Thelia/Action/Order.php line 433

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Thelia package.
  4.  * http://www.thelia.net
  5.  *
  6.  * (c) OpenStudio <info@thelia.net>
  7.  *
  8.  * For the full copyright and license information, please view the LICENSE
  9.  * file that was distributed with this source code.
  10.  */
  11. namespace Thelia\Action;
  12. use Propel\Runtime\Propel;
  13. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  14. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  15. use Symfony\Component\HttpFoundation\RequestStack;
  16. use Thelia\Core\Event\Order\GetStockUpdateOperationOnOrderStatusChangeEvent;
  17. use Thelia\Core\Event\Order\OrderAddressEvent;
  18. use Thelia\Core\Event\Order\OrderEvent;
  19. use Thelia\Core\Event\Order\OrderManualEvent;
  20. use Thelia\Core\Event\Order\OrderPaymentEvent;
  21. use Thelia\Core\Event\Product\VirtualProductOrderHandleEvent;
  22. use Thelia\Core\Event\TheliaEvents;
  23. use Thelia\Core\HttpFoundation\Request;
  24. use Thelia\Core\Security\SecurityContext;
  25. use Thelia\Core\Security\User\UserInterface;
  26. use Thelia\Exception\TheliaProcessException;
  27. use Thelia\Log\Tlog;
  28. use Thelia\Mailer\MailerFactory;
  29. use Thelia\Model\AddressQuery;
  30. use Thelia\Model\Cart as CartModel;
  31. use Thelia\Model\ConfigQuery;
  32. use Thelia\Model\Currency as CurrencyModel;
  33. use Thelia\Model\Lang as LangModel;
  34. use Thelia\Model\Map\OrderTableMap;
  35. use Thelia\Model\ModuleQuery;
  36. use Thelia\Model\Order as ModelOrder;
  37. use Thelia\Model\Order as OrderModel;
  38. use Thelia\Model\OrderAddress;
  39. use Thelia\Model\OrderAddressQuery;
  40. use Thelia\Model\OrderProduct;
  41. use Thelia\Model\OrderProductAttributeCombination;
  42. use Thelia\Model\OrderProductTax;
  43. use Thelia\Model\OrderStatusQuery;
  44. use Thelia\Model\OrderVersionQuery;
  45. use Thelia\Model\ProductI18n;
  46. use Thelia\Model\ProductSaleElements;
  47. use Thelia\Model\ProductSaleElementsQuery;
  48. use Thelia\Model\TaxRuleI18n;
  49. use Thelia\Tools\I18n;
  50. /**
  51.  * Class Order.
  52.  *
  53.  * @author Etienne Roudeix <eroudeix@openstudio.fr>
  54.  * @author Franck Allimant <thelia@cqfdev.fr>
  55.  */
  56. class Order extends BaseAction implements EventSubscriberInterface
  57. {
  58.     /** @var RequestStack */
  59.     protected $requestStack;
  60.     /** @var MailerFactory */
  61.     protected $mailer;
  62.     /** @var SecurityContext */
  63.     protected $securityContext;
  64.     public function __construct(RequestStack $requestStackMailerFactory $mailerSecurityContext $securityContext)
  65.     {
  66.         $this->requestStack $requestStack;
  67.         $this->mailer $mailer;
  68.         $this->securityContext $securityContext;
  69.     }
  70.     public function setDeliveryAddress(OrderEvent $event): void
  71.     {
  72.         $order $event->getOrder();
  73.         $order->setChoosenDeliveryAddress($event->getDeliveryAddress());
  74.         $event->setOrder($order);
  75.     }
  76.     public function setDeliveryModule(OrderEvent $event): void
  77.     {
  78.         $order $event->getOrder();
  79.         $deliveryModuleId $event->getDeliveryModule();
  80.         $order->setDeliveryModuleId($deliveryModuleId);
  81.         // Reset postage cost if the delivery module had been removed
  82.         if ($deliveryModuleId <= 0) {
  83.             $order->setPostage(0);
  84.             $order->setPostageTax(0);
  85.             $order->setPostageTaxRuleTitle(null);
  86.         }
  87.         $event->setOrder($order);
  88.     }
  89.     public function setPostage(OrderEvent $event): void
  90.     {
  91.         $order $event->getOrder();
  92.         $order->setPostage($event->getPostage());
  93.         $order->setPostageTax($event->getPostageTax());
  94.         $order->setPostageTaxRuleTitle($event->getPostageTaxRuleTitle());
  95.         $event->setOrder($order);
  96.     }
  97.     public function setInvoiceAddress(OrderEvent $event): void
  98.     {
  99.         $order $event->getOrder();
  100.         $order->setChoosenInvoiceAddress($event->getInvoiceAddress());
  101.         $event->setOrder($order);
  102.     }
  103.     public function setPaymentModule(OrderEvent $event): void
  104.     {
  105.         $order $event->getOrder();
  106.         $order->setPaymentModuleId($event->getPaymentModule());
  107.         $event->setOrder($order);
  108.     }
  109.     /**
  110.      * @param bool $unusedArgument           deprecated argument. Will be removed in 2.5
  111.      * @param bool $useOrderDefinedAddresses if true, the delivery and invoice OrderAddresses will be used instead of creating new OrderAdresses using Order::getChoosenXXXAddress()
  112.      *
  113.      * @return ModelOrder
  114.      *
  115.      * @throws \Exception
  116.      * @throws \Propel\Runtime\Exception\PropelException
  117.      */
  118.     protected function createOrder(
  119.         EventDispatcherInterface $dispatcher,
  120.         ModelOrder $sessionOrder,
  121.         CurrencyModel $currency,
  122.         LangModel $lang,
  123.         CartModel $cart,
  124.         UserInterface $customer,
  125.         $unusedArgument null,
  126.         $useOrderDefinedAddresses false
  127.     ) {
  128.         $con Propel::getConnection(
  129.             OrderTableMap::DATABASE_NAME
  130.         );
  131.         $con->beginTransaction();
  132.         $placedOrder $sessionOrder->copy();
  133.         // Be sure to create a brand new order, as copy raises the modified flag for all fields
  134.         // and will also copy order reference and id.
  135.         $placedOrder->setId(null)->setRef(null)->setNew(true);
  136.         // Dates should be marked as not updated so that Propel will update them.
  137.         $placedOrder->resetModified(OrderTableMap::COL_CREATED_AT);
  138.         $placedOrder->resetModified(OrderTableMap::COL_UPDATED_AT);
  139.         $placedOrder->resetModified(OrderTableMap::COL_VERSION_CREATED_AT);
  140.         $cartItems $cart->getCartItems();
  141.         /* fulfill order */
  142.         $placedOrder->setCustomerId($customer->getId());
  143.         $placedOrder->setCurrencyId($currency->getId());
  144.         $placedOrder->setCurrencyRate($currency->getRate());
  145.         $placedOrder->setLangId($lang->getId());
  146.         if ($useOrderDefinedAddresses) {
  147.             $taxCountry =
  148.                 OrderAddressQuery::create()
  149.                     ->findPk($placedOrder->getDeliveryOrderAddressId())
  150.                     ->getCountry()
  151.             ;
  152.         } else {
  153.             $deliveryAddress AddressQuery::create()->findPk($sessionOrder->getChoosenDeliveryAddress());
  154.             $invoiceAddress AddressQuery::create()->findPk($sessionOrder->getChoosenInvoiceAddress());
  155.             /* hard save the delivery and invoice addresses */
  156.             $deliveryOrderAddress = new OrderAddress();
  157.             $deliveryOrderAddress
  158.                 ->setCustomerTitleId($deliveryAddress->getTitleId())
  159.                 ->setCompany($deliveryAddress->getCompany())
  160.                 ->setFirstname($deliveryAddress->getFirstname())
  161.                 ->setLastname($deliveryAddress->getLastname())
  162.                 ->setAddress1($deliveryAddress->getAddress1())
  163.                 ->setAddress2($deliveryAddress->getAddress2())
  164.                 ->setAddress3($deliveryAddress->getAddress3())
  165.                 ->setZipcode($deliveryAddress->getZipcode())
  166.                 ->setCity($deliveryAddress->getCity())
  167.                 ->setPhone($deliveryAddress->getPhone())
  168.                 ->setCellphone($deliveryAddress->getCellphone())
  169.                 ->setCountryId($deliveryAddress->getCountryId())
  170.                 ->setStateId($deliveryAddress->getStateId())
  171.                 ->save($con);
  172.             $invoiceOrderAddress = new OrderAddress();
  173.             $invoiceOrderAddress
  174.                 ->setCustomerTitleId($invoiceAddress->getTitleId())
  175.                 ->setCompany($invoiceAddress->getCompany())
  176.                 ->setFirstname($invoiceAddress->getFirstname())
  177.                 ->setLastname($invoiceAddress->getLastname())
  178.                 ->setAddress1($invoiceAddress->getAddress1())
  179.                 ->setAddress2($invoiceAddress->getAddress2())
  180.                 ->setAddress3($invoiceAddress->getAddress3())
  181.                 ->setZipcode($invoiceAddress->getZipcode())
  182.                 ->setCity($invoiceAddress->getCity())
  183.                 ->setPhone($invoiceAddress->getPhone())
  184.                 ->setCellphone($invoiceAddress->getCellphone())
  185.                 ->setCountryId($invoiceAddress->getCountryId())
  186.                 ->setStateId($deliveryAddress->getStateId())
  187.                 ->save($con);
  188.             $placedOrder->setDeliveryOrderAddressId($deliveryOrderAddress->getId());
  189.             $placedOrder->setInvoiceOrderAddressId($invoiceOrderAddress->getId());
  190.             $taxCountry $deliveryAddress->getCountry();
  191.         }
  192.         $placedOrder->setStatusId(
  193.             OrderStatusQuery::getNotPaidStatus()->getId()
  194.         );
  195.         $placedOrder->setCartId($cart->getId());
  196.         /* memorize discount */
  197.         $placedOrder->setDiscount(
  198.             $cart->getDiscount()
  199.         );
  200.         $placedOrder->save($con);
  201.         $manageStock $placedOrder->isStockManagedOnOrderCreation($dispatcher);
  202.         /* fulfill order_products and decrease stock */
  203.         foreach ($cartItems as $cartItem) {
  204.             $product $cartItem->getProduct();
  205.             /* get translation */
  206.             /** @var ProductI18n $productI18n */
  207.             $productI18n I18n::forceI18nRetrieving($lang->getLocale(), 'Product'$product->getId());
  208.             $pse $cartItem->getProductSaleElements();
  209.             // get the virtual document path
  210.             $virtualDocumentEvent = new VirtualProductOrderHandleEvent($placedOrder$pse->getId());
  211.             // essentially used for virtual product. modules that handles virtual product can
  212.             // allow the use of stock even for virtual products
  213.             $useStock true;
  214.             $virtual 0;
  215.             // if the product is virtual, dispatch an event to collect information
  216.             if ($product->getVirtual() === 1) {
  217.                 $dispatcher->dispatch($virtualDocumentEventTheliaEvents::VIRTUAL_PRODUCT_ORDER_HANDLE);
  218.                 $useStock $virtualDocumentEvent->isUseStock();
  219.                 $virtual $virtualDocumentEvent->isVirtual() ? 0;
  220.             }
  221.             /* check still in stock */
  222.             if ($cartItem->getQuantity() > $pse->getQuantity()
  223.                 && true === ConfigQuery::checkAvailableStock()
  224.                 && $useStock) {
  225.                 throw new TheliaProcessException('Not enough stock'TheliaProcessException::CART_ITEM_NOT_ENOUGH_STOCK$cartItem);
  226.             }
  227.             if ($useStock && $manageStock) {
  228.                 /* decrease stock for non virtual product */
  229.                 $allowNegativeStock = (int) (ConfigQuery::read('allow_negative_stock'0));
  230.                 $newStock $pse->getQuantity() - $cartItem->getQuantity();
  231.                 //Forbid negative stock
  232.                 if ($newStock && === $allowNegativeStock) {
  233.                     $newStock 0;
  234.                 }
  235.                 $pse->setQuantity(
  236.                     $newStock
  237.                 );
  238.                 $pse->save($con);
  239.             }
  240.             /* get tax */
  241.             /** @var TaxRuleI18n $taxRuleI18n */
  242.             $taxRuleI18n I18n::forceI18nRetrieving($lang->getLocale(), 'TaxRule'$product->getTaxRuleId());
  243.             $taxDetail $product->getTaxRule()->getTaxDetail(
  244.                 $product,
  245.                 $taxCountry,
  246.                 $cartItem->getPrice(),
  247.                 $cartItem->getPromoPrice(),
  248.                 $lang->getLocale()
  249.             );
  250.             $orderProduct = new OrderProduct();
  251.             $orderProduct
  252.                 ->setOrderId($placedOrder->getId())
  253.                 ->setProductRef($product->getRef())
  254.                 ->setProductSaleElementsRef($pse->getRef())
  255.                 ->setProductSaleElementsId($pse->getId())
  256.                 ->setTitle($productI18n->getTitle())
  257.                 ->setChapo($productI18n->getChapo())
  258.                 ->setDescription($productI18n->getDescription())
  259.                 ->setPostscriptum($productI18n->getPostscriptum())
  260.                 ->setVirtual($virtual)
  261.                 ->setVirtualDocument($virtualDocumentEvent->getPath())
  262.                 ->setQuantity($cartItem->getQuantity())
  263.                 ->setPrice($cartItem->getPrice())
  264.                 ->setPromoPrice($cartItem->getPromoPrice())
  265.                 ->setWasNew($pse->getNewness())
  266.                 ->setWasInPromo($cartItem->getPromo())
  267.                 ->setWeight($pse->getWeight())
  268.                 ->setTaxRuleTitle($taxRuleI18n->getTitle())
  269.                 ->setTaxRuleDescription($taxRuleI18n->getDescription())
  270.                 ->setEanCode($pse->getEanCode())
  271.                 ->setCartItemId($cartItem->getId())
  272.                 ->save($con)
  273.             ;
  274.             /* fulfill order_product_tax */
  275.             /** @var OrderProductTax $tax */
  276.             foreach ($taxDetail as $tax) {
  277.                 $tax->setOrderProductId($orderProduct->getId());
  278.                 $tax->save($con);
  279.             }
  280.             /* fulfill order_attribute_combination and decrease stock */
  281.             foreach ($pse->getAttributeCombinations() as $attributeCombination) {
  282.                 /** @var \Thelia\Model\Attribute $attribute */
  283.                 $attribute I18n::forceI18nRetrieving($lang->getLocale(), 'Attribute'$attributeCombination->getAttributeId());
  284.                 /** @var \Thelia\Model\AttributeAv $attributeAv */
  285.                 $attributeAv I18n::forceI18nRetrieving($lang->getLocale(), 'AttributeAv'$attributeCombination->getAttributeAvId());
  286.                 $orderAttributeCombination = new OrderProductAttributeCombination();
  287.                 $orderAttributeCombination
  288.                     ->setOrderProductId($orderProduct->getId())
  289.                     ->setAttributeTitle($attribute->getTitle())
  290.                     ->setAttributeChapo($attribute->getChapo())
  291.                     ->setAttributeDescription($attribute->getDescription())
  292.                     ->setAttributePostscriptum($attribute->getPostscriptum())
  293.                     ->setAttributeAvTitle($attributeAv->getTitle())
  294.                     ->setAttributeAvChapo($attributeAv->getChapo())
  295.                     ->setAttributeAvDescription($attributeAv->getDescription())
  296.                     ->setAttributeAvPostscriptum($attributeAv->getPostscriptum())
  297.                     ->save($con);
  298.             }
  299.         }
  300.         $con->commit();
  301.         return $placedOrder;
  302.     }
  303.     /**
  304.      * Create an order outside of the front-office context, e.g. manually from the back-office.
  305.      *
  306.      * @param $eventName
  307.      *
  308.      * @throws \Exception
  309.      * @throws \Propel\Runtime\Exception\PropelException
  310.      */
  311.     public function createManual(OrderManualEvent $event$eventNameEventDispatcherInterface $dispatcher): void
  312.     {
  313.         $event->setPlacedOrder(
  314.             $this->createOrder(
  315.                 $dispatcher,
  316.                 $event->getOrder(),
  317.                 $event->getCurrency(),
  318.                 $event->getLang(),
  319.                 $event->getCart(),
  320.                 $event->getCustomer(),
  321.                 null,
  322.                 $event->getUseOrderDefinedAddresses()
  323.             )
  324.         );
  325.         $event->setOrder(new OrderModel());
  326.     }
  327.     /**
  328.      * @throws \Thelia\Exception\TheliaProcessException
  329.      *
  330.      * @param $eventName
  331.      *
  332.      * @throws \Exception
  333.      * @throws \Propel\Runtime\Exception\PropelException
  334.      */
  335.     public function create(OrderEvent $event$eventNameEventDispatcherInterface $dispatcher): void
  336.     {
  337.         $session $this->getSession();
  338.         $order $event->getOrder();
  339.         $paymentModule ModuleQuery::create()->findPk($order->getPaymentModuleId());
  340.         $placedOrder $this->createOrder(
  341.             $dispatcher,
  342.             $event->getOrder(),
  343.             $session->getCurrency(),
  344.             $session->getLang(),
  345.             $session->getSessionCart($dispatcher),
  346.             $this->securityContext->getCustomerUser()
  347.         );
  348.         $dispatcher->dispatch(new OrderEvent($placedOrder), TheliaEvents::ORDER_BEFORE_PAYMENT);
  349.         /* but memorize placed order */
  350.         $event->setOrder(new OrderModel());
  351.         $event->setPlacedOrder($placedOrder);
  352.         /* call pay method */
  353.         $payEvent = new OrderPaymentEvent($placedOrder);
  354.         $dispatcher->dispatch($payEventTheliaEvents::MODULE_PAY);
  355.         if ($payEvent->hasResponse()) {
  356.             $event->setResponse($payEvent->getResponse());
  357.         }
  358.     }
  359.     /**
  360.      * @param $eventName
  361.      */
  362.     public function orderBeforePayment(OrderEvent $event$eventNameEventDispatcherInterface $dispatcher): void
  363.     {
  364.         $dispatcher->dispatch(clone $eventTheliaEvents::ORDER_SEND_CONFIRMATION_EMAIL);
  365.         $dispatcher->dispatch(clone $eventTheliaEvents::ORDER_SEND_NOTIFICATION_EMAIL);
  366.     }
  367.     /**
  368.      * Clear the cart and the order in the customer session once the order is placed,
  369.      * and the payment performed.
  370.      *
  371.      * @param $eventName
  372.      */
  373.     public function orderCartClear(/* @noinspection PhpUnusedParameterInspection */ OrderEvent $event$eventNameEventDispatcherInterface $dispatcher): void
  374.     {
  375.         // Empty cart and clear current order
  376.         $session $this->getSession();
  377.         $session->clearSessionCart($dispatcher);
  378.         $session->setOrder(new OrderModel());
  379.     }
  380.     /**
  381.      * @throws \Exception if the message cannot be loaded
  382.      */
  383.     public function sendConfirmationEmail(OrderEvent $event): void
  384.     {
  385.         $this->mailer->sendEmailToCustomer(
  386.             'order_confirmation',
  387.             $event->getOrder()->getCustomer(),
  388.             [
  389.                 'order_id' => $event->getOrder()->getId(),
  390.                 'order_ref' => $event->getOrder()->getRef(),
  391.             ]
  392.         );
  393.     }
  394.     /**
  395.      * @throws \Exception if the message cannot be loaded
  396.      */
  397.     public function sendNotificationEmail(OrderEvent $event): void
  398.     {
  399.         $this->mailer->sendEmailToShopManagers(
  400.             'order_notification',
  401.             [
  402.                 'order_id' => $event->getOrder()->getId(),
  403.                 'order_ref' => $event->getOrder()->getRef(),
  404.             ]
  405.         );
  406.     }
  407.     /**
  408.      * @param $eventName
  409.      *
  410.      * @throws \Exception
  411.      * @throws \Propel\Runtime\Exception\PropelException
  412.      */
  413.     public function updateStatus(OrderEvent $event$eventNameEventDispatcherInterface $dispatcher): void
  414.     {
  415.         $order $event->getOrder();
  416.         $newStatus $event->getStatus();
  417.         $con Propel::getConnection(OrderTableMap::DATABASE_NAME);
  418.         // Prevent partial stock update on status change.
  419.         $con->beginTransaction();
  420.         try {
  421.             $this->updateQuantity($order$newStatus$dispatcher);
  422.             $order->setStatusId($newStatus)->save();
  423.             $event->setOrder($order);
  424.             $con->commit();
  425.         } catch (\Exception $ex) {
  426.             $con->rollBack();
  427.             throw $ex;
  428.         }
  429.     }
  430.     /**
  431.      * Check if a stock update is required on order products for a given order status change, and compute if
  432.      * the stock should be decreased or increased.
  433.      *
  434.      * @param $eventName
  435.      *
  436.      * @throws \Propel\Runtime\Exception\PropelException
  437.      */
  438.     public function getStockUpdateOnOrderStatusChange(GetStockUpdateOperationOnOrderStatusChangeEvent $event$eventNameEventDispatcherInterface $dispatcher): void
  439.     {
  440.         // The order
  441.         $order $event->getOrder();
  442.         // The new order status
  443.         $newStatus $event->getNewOrderStatus();
  444.         if ($newStatus->getId() !== $order->getStatusId()) {
  445.             // We have to change the stock in the following cases :
  446.             // 1) The order is currently paid, and will become unpaid (get products back in stock unconditionnaly)
  447.             // 2) The order is currently unpaid, and will become paid (remove products from stock, except if was done at order creation $manageStockOnCreation == false)
  448.             // 3) The order is currently NOT PAID, and will become canceled or the like (get products back in stock if it was done at order creation $manageStockOnCreation == true)
  449.             // We consider the ManageStockOnCreation flag only if the order status as not yet changed.
  450.             // Count distinct order statuses (e.g. NOT_PAID to something else) in the order version table.
  451.             if (OrderVersionQuery::create()->groupByStatusId()->filterById($order->getId())->count() > 1) {
  452.                 // A status change occured. Ignore $manageStockOnCreation
  453.                 $manageStockOnCreation false;
  454.             } else {
  455.                 // A status has not yet occured. Consider the ManageStockOnCreation flag
  456.                 $manageStockOnCreation $order->isStockManagedOnOrderCreation($dispatcher);
  457.             }
  458.             if (($order->isPaid(false) && $newStatus->isNotPaid(false)) // Case 1
  459.                 ||
  460.                 ($order->isNotPaid(true) && $newStatus->isNotPaid(false) && $manageStockOnCreation === true// Case 3
  461.             ) {
  462.                 $event->setOperation($event::INCREASE_STOCK);
  463.             }
  464.             if ($order->isNotPaid(false// Case 2
  465.                 &&
  466.                 $newStatus->isPaid(false)
  467.                 &&
  468.                 $manageStockOnCreation === false) {
  469.                 $event->setOperation($event::DECREASE_STOCK);
  470.             }
  471.             Tlog::getInstance()->addInfo(
  472.                 'Checking stock operation for status change of order : '.$order->getRef()
  473.                 .', version: '.$order->getVersion()
  474.                 .', manageStockOnCreation: '.($manageStockOnCreation 1)
  475.                 .', paid:'.($order->isPaid(false) ? 0)
  476.                 .', is not paid:'.($order->isNotPaid(false) ? 0)
  477.                 .', new status paid:'.($newStatus->isPaid(false) ? 0)
  478.                 .', new status is not paid:'.($newStatus->isNotPaid(false) ? 0)
  479.                 .' = operation: '.$event->getOperation()
  480.             );
  481.         }
  482.     }
  483.     /**
  484.      * Update order products stock after an order status change.
  485.      *
  486.      * @param int $newStatus the new status ID
  487.      *
  488.      * @throws \Exception
  489.      * @throws \Propel\Runtime\Exception\PropelException
  490.      */
  491.     protected function updateQuantity(ModelOrder $order$newStatusEventDispatcherInterface $dispatcher): void
  492.     {
  493.         if ($newStatus !== $order->getStatusId()) {
  494.             if (null !== $newStatusModel OrderStatusQuery::create()->findPk($newStatus)) {
  495.                 $operationEvent = new GetStockUpdateOperationOnOrderStatusChangeEvent($order$newStatusModel);
  496.                 $dispatcher->dispatch(
  497.                     $operationEvent,
  498.                     TheliaEvents::ORDER_GET_STOCK_UPDATE_OPERATION_ON_ORDER_STATUS_CHANGE
  499.                 );
  500.                 if ($operationEvent->getOperation() !== $operationEvent::DO_NOTHING) {
  501.                     $orderProductList $order->getOrderProducts();
  502.                     /** @var OrderProduct $orderProduct */
  503.                     foreach ($orderProductList as $orderProduct) {
  504.                         $productSaleElementsId $orderProduct->getProductSaleElementsId();
  505.                         /** @var ProductSaleElements $productSaleElements */
  506.                         if (null !== $productSaleElements ProductSaleElementsQuery::create()->findPk($productSaleElementsId)) {
  507.                             $offset 0;
  508.                             if ($operationEvent->getOperation() == $operationEvent::INCREASE_STOCK) {
  509.                                 $offset $orderProduct->getQuantity();
  510.                             } elseif ($operationEvent->getOperation() == $operationEvent::DECREASE_STOCK) {
  511.                                 /* Check if we have enough stock */
  512.                                 if ($orderProduct->getQuantity() > $productSaleElements->getQuantity() && true === ConfigQuery::checkAvailableStock()) {
  513.                                     throw new TheliaProcessException($productSaleElements->getRef().' : Not enough stock 2');
  514.                                 }
  515.                                 $offset = -$orderProduct->getQuantity();
  516.                             }
  517.                             Tlog::getInstance()->addError('Product stock: '.$productSaleElements->getQuantity().' -> '.($productSaleElements->getQuantity() + $offset));
  518.                             $productSaleElements
  519.                                 ->setQuantity($productSaleElements->getQuantity() + $offset)
  520.                                 ->save();
  521.                         }
  522.                     }
  523.                 }
  524.             }
  525.         }
  526.     }
  527.     /**
  528.      * @throws \Propel\Runtime\Exception\PropelException
  529.      */
  530.     public function updateDeliveryRef(OrderEvent $event): void
  531.     {
  532.         $order $event->getOrder();
  533.         $order->setDeliveryRef($event->getDeliveryRef())->save();
  534.         $event->setOrder($order);
  535.     }
  536.     /**
  537.      * @throws \Propel\Runtime\Exception\PropelException
  538.      */
  539.     public function updateTransactionRef(OrderEvent $event): void
  540.     {
  541.         $order $event->getOrder();
  542.         $order->setTransactionRef($event->getTransactionRef())->save();
  543.         $event->setOrder($order);
  544.     }
  545.     /**
  546.      * @throws \Propel\Runtime\Exception\PropelException
  547.      */
  548.     public function updateAddress(OrderAddressEvent $event): void
  549.     {
  550.         $orderAddress $event->getOrderAddress();
  551.         $orderAddress
  552.             ->setCustomerTitleId($event->getTitle())
  553.             ->setCompany($event->getCompany())
  554.             ->setFirstname($event->getFirstname())
  555.             ->setLastname($event->getLastname())
  556.             ->setAddress1($event->getAddress1())
  557.             ->setAddress2($event->getAddress2())
  558.             ->setAddress3($event->getAddress3())
  559.             ->setZipcode($event->getZipcode())
  560.             ->setCity($event->getCity())
  561.             ->setCountryId($event->getCountry())
  562.             ->setStateId($event->getState())
  563.             ->setPhone($event->getPhone())
  564.             ->setCellphone($event->getCellphone())
  565.             ->save()
  566.         ;
  567.         $event->setOrderAddress($orderAddress);
  568.     }
  569.     /**
  570.      * {@inheritdoc}
  571.      */
  572.     public static function getSubscribedEvents()
  573.     {
  574.         return [
  575.             TheliaEvents::ORDER_SET_DELIVERY_ADDRESS => ['setDeliveryAddress'128],
  576.             TheliaEvents::ORDER_SET_DELIVERY_MODULE => ['setDeliveryModule'128],
  577.             TheliaEvents::ORDER_SET_POSTAGE => ['setPostage'128],
  578.             TheliaEvents::ORDER_SET_INVOICE_ADDRESS => ['setInvoiceAddress'128],
  579.             TheliaEvents::ORDER_SET_PAYMENT_MODULE => ['setPaymentModule'128],
  580.             TheliaEvents::ORDER_PAY => ['create'128],
  581.             TheliaEvents::ORDER_CART_CLEAR => ['orderCartClear'128],
  582.             TheliaEvents::ORDER_BEFORE_PAYMENT => ['orderBeforePayment'128],
  583.             TheliaEvents::ORDER_SEND_CONFIRMATION_EMAIL => ['sendConfirmationEmail'128],
  584.             TheliaEvents::ORDER_SEND_NOTIFICATION_EMAIL => ['sendNotificationEmail'128],
  585.             TheliaEvents::ORDER_UPDATE_STATUS => ['updateStatus'128],
  586.             TheliaEvents::ORDER_UPDATE_DELIVERY_REF => ['updateDeliveryRef'128],
  587.             TheliaEvents::ORDER_UPDATE_TRANSACTION_REF => ['updateTransactionRef'128],
  588.             TheliaEvents::ORDER_UPDATE_ADDRESS => ['updateAddress'128],
  589.             TheliaEvents::ORDER_CREATE_MANUAL => ['createManual'128],
  590.             TheliaEvents::ORDER_GET_STOCK_UPDATE_OPERATION_ON_ORDER_STATUS_CHANGE => ['getStockUpdateOnOrderStatusChange'128],
  591.         ];
  592.     }
  593.     /**
  594.      * Returns the session from the current request.
  595.      *
  596.      * @return \Thelia\Core\HttpFoundation\Session\Session
  597.      */
  598.     protected function getSession()
  599.     {
  600.         /** @var Request $request */
  601.         $request $this->requestStack->getCurrentRequest();
  602.         return $request->getSession();
  603.     }
  604. }