1<?php 2/** 3 * Copyright since 2007 PrestaShop SA and Contributors 4 * PrestaShop is an International Registered Trademark & Property of PrestaShop SA 5 * 6 * NOTICE OF LICENSE 7 * 8 * This source file is subject to the Open Software License (OSL 3.0) 9 * that is bundled with this package in the file LICENSE.md. 10 * It is also available through the world-wide-web at this URL: 11 * https://opensource.org/licenses/OSL-3.0 12 * If you did not receive a copy of the license and are unable to 13 * obtain it through the world-wide-web, please send an email 14 * to license@prestashop.com so we can send you a copy immediately. 15 * 16 * DISCLAIMER 17 * 18 * Do not edit or add to this file if you wish to upgrade PrestaShop to newer 19 * versions in the future. If you wish to customize PrestaShop for your 20 * needs please refer to https://devdocs.prestashop.com/ for more information. 21 * 22 * @author PrestaShop SA and Contributors <contact@prestashop.com> 23 * @copyright Since 2007 PrestaShop SA and Contributors 24 * @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) 25 */ 26 27namespace PrestaShop\PrestaShop\Adapter\Order\CommandHandler; 28 29use Address; 30use Cart; 31use Order; 32use OrderDetail; 33use OrderInvoice; 34use PrestaShop\PrestaShop\Adapter\Cart\Comparator\CartProductsComparator; 35use PrestaShop\PrestaShop\Adapter\Cart\Comparator\CartProductUpdate; 36use PrestaShop\PrestaShop\Adapter\ContextStateManager; 37use PrestaShop\PrestaShop\Adapter\Order\OrderAmountUpdater; 38use PrestaShop\PrestaShop\Adapter\Order\OrderDetailUpdater; 39use PrestaShop\PrestaShop\Adapter\Order\OrderProductQuantityUpdater; 40use PrestaShop\PrestaShop\Core\Domain\Order\Command\ChangeOrderDeliveryAddressCommand; 41use PrestaShop\PrestaShop\Core\Domain\Order\CommandHandler\ChangeOrderDeliveryAddressHandlerInterface; 42use PrestaShop\PrestaShop\Core\Domain\Order\Exception\OrderException; 43use Validate; 44 45/** 46 * @internal 47 */ 48final class ChangeOrderDeliveryAddressHandler extends AbstractOrderCommandHandler implements ChangeOrderDeliveryAddressHandlerInterface 49{ 50 /** 51 * @var OrderAmountUpdater 52 */ 53 private $orderAmountUpdater; 54 55 /** 56 * @var OrderDetailUpdater 57 */ 58 private $orderDetailTaxUpdater; 59 60 /** 61 * @var ContextStateManager 62 */ 63 private $contextStateManager; 64 65 /** 66 * @var OrderProductQuantityUpdater 67 */ 68 private $orderProductQuantityUpdater; 69 70 /** 71 * @param OrderAmountUpdater $orderAmountUpdater 72 * @param OrderDetailUpdater $orderDetailTaxUpdater 73 * @param ContextStateManager $contextStateManager 74 * @param OrderProductQuantityUpdater $orderProductQuantityUpdater 75 */ 76 public function __construct( 77 OrderAmountUpdater $orderAmountUpdater, 78 OrderDetailUpdater $orderDetailTaxUpdater, 79 ContextStateManager $contextStateManager, 80 OrderProductQuantityUpdater $orderProductQuantityUpdater 81 ) { 82 $this->orderAmountUpdater = $orderAmountUpdater; 83 $this->orderDetailTaxUpdater = $orderDetailTaxUpdater; 84 $this->contextStateManager = $contextStateManager; 85 $this->orderProductQuantityUpdater = $orderProductQuantityUpdater; 86 } 87 88 /** 89 * {@inheritdoc} 90 */ 91 public function handle(ChangeOrderDeliveryAddressCommand $command) 92 { 93 $order = $this->getOrder($command->getOrderId()); 94 $address = new Address($command->getNewDeliveryAddressId()->getValue()); 95 96 $cart = Cart::getCartByOrderId($order->id); 97 98 if (!Validate::isLoadedObject($address)) { 99 throw new OrderException('New delivery address is not valid'); 100 } 101 102 $this->setCartContext($this->contextStateManager, $cart); 103 104 try { 105 $comparator = new CartProductsComparator($cart); 106 107 $cart->updateDeliveryAddressId((int) $cart->id_address_delivery, (int) $address->id); 108 $cart->setDeliveryOption([ 109 (int) $cart->id_address_delivery => $this->formatLegacyDeliveryOptionFromCarrierId($order->id_carrier), 110 ]); 111 $cart->update(); 112 113 // gift could have been added/deleted when changing delivery address 114 $this->synchronizeOrderWithCart($order, $cart, $comparator); 115 116 $order->id_address_delivery = $address->id; 117 $this->orderDetailTaxUpdater->updateOrderDetailsTaxes($order); 118 $this->orderAmountUpdater->update($order, $cart); 119 } finally { 120 $this->contextStateManager->restorePreviousContext(); 121 } 122 } 123 124 /** 125 * @param Order $order 126 * @param Cart $cart 127 * @param CartProductsComparator $productsComparator 128 */ 129 private function synchronizeOrderWithCart( 130 Order $order, 131 Cart $cart, 132 CartProductsComparator $productsComparator 133 ): void { 134 $modified = $productsComparator->getModifiedProducts(); 135 foreach ($modified as $productUpdate) { 136 $orderDetail = $this->getOrderDetail($productUpdate, $order, $cart); 137 if (null === $orderDetail) { 138 continue; 139 } 140 $quantity = $productUpdate->isCreated() 141 ? $productUpdate->getDeltaQuantity() 142 : $orderDetail->product_quantity + $productUpdate->getDeltaQuantity(); 143 $orderInvoice = $orderDetail->id_order_invoice != 0 ? new OrderInvoice($orderDetail->id_order_invoice) : null; 144 145 $this->orderProductQuantityUpdater->update( 146 $order, 147 $orderDetail, 148 $quantity, 149 $orderInvoice, 150 false 151 ); 152 } 153 } 154 155 /** 156 * @param CartProductUpdate $productUpdate 157 * @param Order $order 158 * @param Cart $cart 159 * 160 * @return OrderDetail|null 161 */ 162 private function getOrderDetail(CartProductUpdate $productUpdate, Order $order, Cart $cart): ?OrderDetail 163 { 164 $combinationId = $productUpdate->getCombinationId() ? $productUpdate->getCombinationId()->getValue() : 0; 165 foreach ($order->getProducts() as $product) { 166 if ( 167 (int) $product['product_id'] === $productUpdate->getProductId()->getValue() 168 && (int) $product['product_attribute_id'] === $combinationId 169 ) { 170 return new OrderDetail($product['id_order_detail']); 171 } 172 } 173 174 foreach ($cart->getProducts() as $product) { 175 if ( 176 (int) $product['id_product'] === $productUpdate->getProductId()->getValue() 177 && (int) $product['id_product_attribute'] === $combinationId 178 ) { 179 $orderDetail = new OrderDetail(); 180 $orderDetail->createList($order, $cart, $order->getCurrentOrderState(), [$product]); 181 182 return $orderDetail; 183 } 184 } 185 186 return null; 187 } 188} 189