<?php /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Magento\Checkout\Model; use Magento\Framework\Exception\InputException; use Magento\Framework\Exception\StateException; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Quote\Api\Data\AddressInterface; use Magento\Quote\Api\Data\CartInterface; use Psr\Log\LoggerInterface as Logger; use Magento\Quote\Model\QuoteAddressValidator; use Magento\Quote\Api\Data\CartExtensionFactory; use Magento\Quote\Model\ShippingAssignmentFactory; use Magento\Quote\Model\ShippingFactory; use Magento\Framework\App\ObjectManager; /** * Class ShippingInformationManagement * * @package Magento\Checkout\Model * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class ShippingInformationManagement implements \Magento\Checkout\Api\ShippingInformationManagementInterface { /** * @var \Magento\Quote\Api\PaymentMethodManagementInterface */ protected $paymentMethodManagement; /** * @var PaymentDetailsFactory */ protected $paymentDetailsFactory; /** * @var \Magento\Quote\Api\CartTotalRepositoryInterface */ protected $cartTotalsRepository; /** * @var \Magento\Quote\Api\CartRepositoryInterface */ protected $quoteRepository; /** * @var Logger */ protected $logger; /** * @var QuoteAddressValidator * @deprecated 100.2.0 */ protected $addressValidator; /** * @var \Magento\Customer\Api\AddressRepositoryInterface * @deprecated 100.2.0 */ protected $addressRepository; /** * @var \Magento\Framework\App\Config\ScopeConfigInterface * @deprecated 100.2.0 */ protected $scopeConfig; /** * @var \Magento\Quote\Model\Quote\TotalsCollector * @deprecated 100.2.0 */ protected $totalsCollector; /** * @var \Magento\Quote\Api\Data\CartExtensionFactory */ private $cartExtensionFactory; /** * @var \Magento\Quote\Model\ShippingAssignmentFactory */ protected $shippingAssignmentFactory; /** * @var \Magento\Quote\Model\ShippingFactory */ private $shippingFactory; /** * Constructor * * @param \Magento\Quote\Api\PaymentMethodManagementInterface $paymentMethodManagement * @param \Magento\Checkout\Model\PaymentDetailsFactory $paymentDetailsFactory * @param \Magento\Quote\Api\CartTotalRepositoryInterface $cartTotalsRepository * @param \Magento\Quote\Api\CartRepositoryInterface $quoteRepository * @param \Magento\Quote\Model\QuoteAddressValidator $addressValidator * @param Logger $logger * @param \Magento\Customer\Api\AddressRepositoryInterface $addressRepository * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig * @param \Magento\Quote\Model\Quote\TotalsCollector $totalsCollector * @param CartExtensionFactory|null $cartExtensionFactory * @param ShippingAssignmentFactory|null $shippingAssignmentFactory * @param ShippingFactory|null $shippingFactory * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( \Magento\Quote\Api\PaymentMethodManagementInterface $paymentMethodManagement, \Magento\Checkout\Model\PaymentDetailsFactory $paymentDetailsFactory, \Magento\Quote\Api\CartTotalRepositoryInterface $cartTotalsRepository, \Magento\Quote\Api\CartRepositoryInterface $quoteRepository, QuoteAddressValidator $addressValidator, Logger $logger, \Magento\Customer\Api\AddressRepositoryInterface $addressRepository, \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, \Magento\Quote\Model\Quote\TotalsCollector $totalsCollector, CartExtensionFactory $cartExtensionFactory = null, ShippingAssignmentFactory $shippingAssignmentFactory = null, ShippingFactory $shippingFactory = null ) { $this->paymentMethodManagement = $paymentMethodManagement; $this->paymentDetailsFactory = $paymentDetailsFactory; $this->cartTotalsRepository = $cartTotalsRepository; $this->quoteRepository = $quoteRepository; $this->addressValidator = $addressValidator; $this->logger = $logger; $this->addressRepository = $addressRepository; $this->scopeConfig = $scopeConfig; $this->totalsCollector = $totalsCollector; $this->cartExtensionFactory = $cartExtensionFactory ?: ObjectManager::getInstance() ->get(CartExtensionFactory::class); $this->shippingAssignmentFactory = $shippingAssignmentFactory ?: ObjectManager::getInstance() ->get(ShippingAssignmentFactory::class); $this->shippingFactory = $shippingFactory ?: ObjectManager::getInstance() ->get(ShippingFactory::class); } /** * Save address information. * * @param int $cartId * @param \Magento\Checkout\Api\Data\ShippingInformationInterface $addressInformation * @return \Magento\Checkout\Api\Data\PaymentDetailsInterface * @throws InputException * @throws NoSuchEntityException * @throws StateException */ public function saveAddressInformation( $cartId, \Magento\Checkout\Api\Data\ShippingInformationInterface $addressInformation ) { $address = $addressInformation->getShippingAddress(); $billingAddress = $addressInformation->getBillingAddress(); $carrierCode = $addressInformation->getShippingCarrierCode(); $methodCode = $addressInformation->getShippingMethodCode(); if (!$address->getCustomerAddressId()) { $address->setCustomerAddressId(null); } if ($billingAddress && !$billingAddress->getCustomerAddressId()) { $billingAddress->setCustomerAddressId(null); } if (!$address->getCountryId()) { throw new StateException(__('The shipping address is missing. Set the address and try again.')); } /** @var \Magento\Quote\Model\Quote $quote */ $quote = $this->quoteRepository->getActive($cartId); $address->setLimitCarrier($carrierCode); $quote = $this->prepareShippingAssignment($quote, $address, $carrierCode . '_' . $methodCode); $this->validateQuote($quote); $quote->setIsMultiShipping(false); if ($billingAddress) { $quote->setBillingAddress($billingAddress); } try { $this->quoteRepository->save($quote); } catch (\Exception $e) { $this->logger->critical($e); throw new InputException( __('The shipping information was unable to be saved. Verify the input data and try again.') ); } $shippingAddress = $quote->getShippingAddress(); if (!$shippingAddress->getShippingRateByCode($shippingAddress->getShippingMethod())) { throw new NoSuchEntityException( __('Carrier with such method not found: %1, %2', $carrierCode, $methodCode) ); } /** @var \Magento\Checkout\Api\Data\PaymentDetailsInterface $paymentDetails */ $paymentDetails = $this->paymentDetailsFactory->create(); $paymentDetails->setPaymentMethods($this->paymentMethodManagement->getList($cartId)); $paymentDetails->setTotals($this->cartTotalsRepository->get($cartId)); return $paymentDetails; } /** * Validate quote * * @param \Magento\Quote\Model\Quote $quote * @throws InputException * @throws NoSuchEntityException * @return void */ protected function validateQuote(\Magento\Quote\Model\Quote $quote) { if (0 == $quote->getItemsCount()) { throw new InputException( __("The shipping method can't be set for an empty cart. Add an item to cart and try again.") ); } } /** * Prepare shipping assignment. * * @param CartInterface $quote * @param AddressInterface $address * @param string $method * @return CartInterface */ private function prepareShippingAssignment(CartInterface $quote, AddressInterface $address, $method) { $cartExtension = $quote->getExtensionAttributes(); if ($cartExtension === null) { $cartExtension = $this->cartExtensionFactory->create(); } $shippingAssignments = $cartExtension->getShippingAssignments(); if (empty($shippingAssignments)) { $shippingAssignment = $this->shippingAssignmentFactory->create(); } else { $shippingAssignment = $shippingAssignments[0]; } $shipping = $shippingAssignment->getShipping(); if ($shipping === null) { $shipping = $this->shippingFactory->create(); } $shipping->setAddress($address); $shipping->setMethod($method); $shippingAssignment->setShipping($shipping); $cartExtension->setShippingAssignments([$shippingAssignment]); return $quote->setExtensionAttributes($cartExtension); } }