ShippingInformationManagement.php 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Checkout\Model;
  7. use Magento\Framework\Exception\InputException;
  8. use Magento\Framework\Exception\StateException;
  9. use Magento\Framework\Exception\NoSuchEntityException;
  10. use Magento\Quote\Api\Data\AddressInterface;
  11. use Magento\Quote\Api\Data\CartInterface;
  12. use Psr\Log\LoggerInterface as Logger;
  13. use Magento\Quote\Model\QuoteAddressValidator;
  14. use Magento\Quote\Api\Data\CartExtensionFactory;
  15. use Magento\Quote\Model\ShippingAssignmentFactory;
  16. use Magento\Quote\Model\ShippingFactory;
  17. use Magento\Framework\App\ObjectManager;
  18. /**
  19. * Class ShippingInformationManagement
  20. *
  21. * @package Magento\Checkout\Model
  22. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  23. */
  24. class ShippingInformationManagement implements \Magento\Checkout\Api\ShippingInformationManagementInterface
  25. {
  26. /**
  27. * @var \Magento\Quote\Api\PaymentMethodManagementInterface
  28. */
  29. protected $paymentMethodManagement;
  30. /**
  31. * @var PaymentDetailsFactory
  32. */
  33. protected $paymentDetailsFactory;
  34. /**
  35. * @var \Magento\Quote\Api\CartTotalRepositoryInterface
  36. */
  37. protected $cartTotalsRepository;
  38. /**
  39. * @var \Magento\Quote\Api\CartRepositoryInterface
  40. */
  41. protected $quoteRepository;
  42. /**
  43. * @var Logger
  44. */
  45. protected $logger;
  46. /**
  47. * @var QuoteAddressValidator
  48. * @deprecated 100.2.0
  49. */
  50. protected $addressValidator;
  51. /**
  52. * @var \Magento\Customer\Api\AddressRepositoryInterface
  53. * @deprecated 100.2.0
  54. */
  55. protected $addressRepository;
  56. /**
  57. * @var \Magento\Framework\App\Config\ScopeConfigInterface
  58. * @deprecated 100.2.0
  59. */
  60. protected $scopeConfig;
  61. /**
  62. * @var \Magento\Quote\Model\Quote\TotalsCollector
  63. * @deprecated 100.2.0
  64. */
  65. protected $totalsCollector;
  66. /**
  67. * @var \Magento\Quote\Api\Data\CartExtensionFactory
  68. */
  69. private $cartExtensionFactory;
  70. /**
  71. * @var \Magento\Quote\Model\ShippingAssignmentFactory
  72. */
  73. protected $shippingAssignmentFactory;
  74. /**
  75. * @var \Magento\Quote\Model\ShippingFactory
  76. */
  77. private $shippingFactory;
  78. /**
  79. * Constructor
  80. *
  81. * @param \Magento\Quote\Api\PaymentMethodManagementInterface $paymentMethodManagement
  82. * @param \Magento\Checkout\Model\PaymentDetailsFactory $paymentDetailsFactory
  83. * @param \Magento\Quote\Api\CartTotalRepositoryInterface $cartTotalsRepository
  84. * @param \Magento\Quote\Api\CartRepositoryInterface $quoteRepository
  85. * @param \Magento\Quote\Model\QuoteAddressValidator $addressValidator
  86. * @param Logger $logger
  87. * @param \Magento\Customer\Api\AddressRepositoryInterface $addressRepository
  88. * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
  89. * @param \Magento\Quote\Model\Quote\TotalsCollector $totalsCollector
  90. * @param CartExtensionFactory|null $cartExtensionFactory
  91. * @param ShippingAssignmentFactory|null $shippingAssignmentFactory
  92. * @param ShippingFactory|null $shippingFactory
  93. * @SuppressWarnings(PHPMD.ExcessiveParameterList)
  94. */
  95. public function __construct(
  96. \Magento\Quote\Api\PaymentMethodManagementInterface $paymentMethodManagement,
  97. \Magento\Checkout\Model\PaymentDetailsFactory $paymentDetailsFactory,
  98. \Magento\Quote\Api\CartTotalRepositoryInterface $cartTotalsRepository,
  99. \Magento\Quote\Api\CartRepositoryInterface $quoteRepository,
  100. QuoteAddressValidator $addressValidator,
  101. Logger $logger,
  102. \Magento\Customer\Api\AddressRepositoryInterface $addressRepository,
  103. \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
  104. \Magento\Quote\Model\Quote\TotalsCollector $totalsCollector,
  105. CartExtensionFactory $cartExtensionFactory = null,
  106. ShippingAssignmentFactory $shippingAssignmentFactory = null,
  107. ShippingFactory $shippingFactory = null
  108. ) {
  109. $this->paymentMethodManagement = $paymentMethodManagement;
  110. $this->paymentDetailsFactory = $paymentDetailsFactory;
  111. $this->cartTotalsRepository = $cartTotalsRepository;
  112. $this->quoteRepository = $quoteRepository;
  113. $this->addressValidator = $addressValidator;
  114. $this->logger = $logger;
  115. $this->addressRepository = $addressRepository;
  116. $this->scopeConfig = $scopeConfig;
  117. $this->totalsCollector = $totalsCollector;
  118. $this->cartExtensionFactory = $cartExtensionFactory ?: ObjectManager::getInstance()
  119. ->get(CartExtensionFactory::class);
  120. $this->shippingAssignmentFactory = $shippingAssignmentFactory ?: ObjectManager::getInstance()
  121. ->get(ShippingAssignmentFactory::class);
  122. $this->shippingFactory = $shippingFactory ?: ObjectManager::getInstance()
  123. ->get(ShippingFactory::class);
  124. }
  125. /**
  126. * Save address information.
  127. *
  128. * @param int $cartId
  129. * @param \Magento\Checkout\Api\Data\ShippingInformationInterface $addressInformation
  130. * @return \Magento\Checkout\Api\Data\PaymentDetailsInterface
  131. * @throws InputException
  132. * @throws NoSuchEntityException
  133. * @throws StateException
  134. */
  135. public function saveAddressInformation(
  136. $cartId,
  137. \Magento\Checkout\Api\Data\ShippingInformationInterface $addressInformation
  138. ) {
  139. $address = $addressInformation->getShippingAddress();
  140. $billingAddress = $addressInformation->getBillingAddress();
  141. $carrierCode = $addressInformation->getShippingCarrierCode();
  142. $methodCode = $addressInformation->getShippingMethodCode();
  143. if (!$address->getCustomerAddressId()) {
  144. $address->setCustomerAddressId(null);
  145. }
  146. if ($billingAddress && !$billingAddress->getCustomerAddressId()) {
  147. $billingAddress->setCustomerAddressId(null);
  148. }
  149. if (!$address->getCountryId()) {
  150. throw new StateException(__('The shipping address is missing. Set the address and try again.'));
  151. }
  152. /** @var \Magento\Quote\Model\Quote $quote */
  153. $quote = $this->quoteRepository->getActive($cartId);
  154. $address->setLimitCarrier($carrierCode);
  155. $quote = $this->prepareShippingAssignment($quote, $address, $carrierCode . '_' . $methodCode);
  156. $this->validateQuote($quote);
  157. $quote->setIsMultiShipping(false);
  158. if ($billingAddress) {
  159. $quote->setBillingAddress($billingAddress);
  160. }
  161. try {
  162. $this->quoteRepository->save($quote);
  163. } catch (\Exception $e) {
  164. $this->logger->critical($e);
  165. throw new InputException(
  166. __('The shipping information was unable to be saved. Verify the input data and try again.')
  167. );
  168. }
  169. $shippingAddress = $quote->getShippingAddress();
  170. if (!$shippingAddress->getShippingRateByCode($shippingAddress->getShippingMethod())) {
  171. throw new NoSuchEntityException(
  172. __('Carrier with such method not found: %1, %2', $carrierCode, $methodCode)
  173. );
  174. }
  175. /** @var \Magento\Checkout\Api\Data\PaymentDetailsInterface $paymentDetails */
  176. $paymentDetails = $this->paymentDetailsFactory->create();
  177. $paymentDetails->setPaymentMethods($this->paymentMethodManagement->getList($cartId));
  178. $paymentDetails->setTotals($this->cartTotalsRepository->get($cartId));
  179. return $paymentDetails;
  180. }
  181. /**
  182. * Validate quote
  183. *
  184. * @param \Magento\Quote\Model\Quote $quote
  185. * @throws InputException
  186. * @throws NoSuchEntityException
  187. * @return void
  188. */
  189. protected function validateQuote(\Magento\Quote\Model\Quote $quote)
  190. {
  191. if (0 == $quote->getItemsCount()) {
  192. throw new InputException(
  193. __("The shipping method can't be set for an empty cart. Add an item to cart and try again.")
  194. );
  195. }
  196. }
  197. /**
  198. * Prepare shipping assignment.
  199. *
  200. * @param CartInterface $quote
  201. * @param AddressInterface $address
  202. * @param string $method
  203. * @return CartInterface
  204. */
  205. private function prepareShippingAssignment(CartInterface $quote, AddressInterface $address, $method)
  206. {
  207. $cartExtension = $quote->getExtensionAttributes();
  208. if ($cartExtension === null) {
  209. $cartExtension = $this->cartExtensionFactory->create();
  210. }
  211. $shippingAssignments = $cartExtension->getShippingAssignments();
  212. if (empty($shippingAssignments)) {
  213. $shippingAssignment = $this->shippingAssignmentFactory->create();
  214. } else {
  215. $shippingAssignment = $shippingAssignments[0];
  216. }
  217. $shipping = $shippingAssignment->getShipping();
  218. if ($shipping === null) {
  219. $shipping = $this->shippingFactory->create();
  220. }
  221. $shipping->setAddress($address);
  222. $shipping->setMethod($method);
  223. $shippingAssignment->setShipping($shipping);
  224. $cartExtension->setShippingAssignments([$shippingAssignment]);
  225. return $quote->setExtensionAttributes($cartExtension);
  226. }
  227. }