diff --git a/app/code/Magento/Multishipping/Controller/Checkout.php b/app/code/Magento/Multishipping/Controller/Checkout.php index 0fc451bfe7e65..c3d68f6519e99 100644 --- a/app/code/Magento/Multishipping/Controller/Checkout.php +++ b/app/code/Magento/Multishipping/Controller/Checkout.php @@ -8,6 +8,7 @@ use Magento\Customer\Api\AccountManagementInterface; use Magento\Customer\Api\CustomerRepositoryInterface; use Magento\Framework\App\RequestInterface; +use Magento\Framework\Exception\StateException; /** * Multishipping checkout controller @@ -83,6 +84,7 @@ protected function _getCheckoutSession() * * @param RequestInterface $request * @return \Magento\Framework\App\ResponseInterface + * @throws \Magento\Framework\Exception\NotFoundException * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) */ @@ -149,7 +151,14 @@ public function dispatch(RequestInterface $request) return parent::dispatch($request); } - $quote = $this->_getCheckout()->getQuote(); + try { + $checkout = $this->_getCheckout(); + } catch (StateException $e) { + $this->getResponse()->setRedirect($this->_getHelper()->getMSNewShippingUrl()); + $this->_actionFlag->set('', self::FLAG_NO_DISPATCH, true); + return parent::dispatch($request); + } + $quote = $checkout->getQuote(); if (!$quote->hasItems() || $quote->getHasError() || $quote->isVirtual()) { $this->getResponse()->setRedirect($this->_getHelper()->getCartUrl()); $this->_actionFlag->set('', self::FLAG_NO_DISPATCH, true); diff --git a/app/code/Magento/Multishipping/Helper/Url.php b/app/code/Magento/Multishipping/Helper/Url.php index e293e3d4d7121..eaefa8fe8bee3 100644 --- a/app/code/Magento/Multishipping/Helper/Url.php +++ b/app/code/Magento/Multishipping/Helper/Url.php @@ -63,6 +63,16 @@ public function getMSShippingAddressSavedUrl() return $this->_getUrl('multishipping/checkout_address/shippingSaved'); } + /** + * Retrieve register url + * + * @return string + */ + public function getMSNewShippingUrl() + { + return $this->_getUrl('multishipping/checkout_address/newShipping'); + } + /** * Retrieve register url * diff --git a/app/code/Magento/Quote/Model/ShippingMethodManagement.php b/app/code/Magento/Quote/Model/ShippingMethodManagement.php index ccd4f598226cc..3aacc48f472ac 100644 --- a/app/code/Magento/Quote/Model/ShippingMethodManagement.php +++ b/app/code/Magento/Quote/Model/ShippingMethodManagement.php @@ -5,17 +5,17 @@ */ namespace Magento\Quote\Model; +use Magento\Customer\Api\Data\AddressInterfaceFactory; +use Magento\Framework\App\ObjectManager; use Magento\Framework\Exception\CouldNotSaveException; use Magento\Framework\Exception\InputException; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\Exception\StateException; +use Magento\Framework\Reflection\DataObjectProcessor; use Magento\Quote\Api\Data\AddressInterface; use Magento\Quote\Api\Data\EstimateAddressInterface; use Magento\Quote\Api\ShipmentEstimationInterface; -use Magento\Quote\Model\Quote; -use Magento\Framework\Reflection\DataObjectProcessor; -use Magento\Framework\App\ObjectManager; -use Magento\Customer\Api\Data\AddressInterfaceFactory; +use Magento\Quote\Model\ResourceModel\Quote\Address as QuoteAddressResource; /** * Shipping method read service. @@ -66,6 +66,11 @@ class ShippingMethodManagement implements */ private $addressFactory; + /** + * @var QuoteAddressResource + */ + private $quoteAddressResource; + /** * Constructs a shipping method read service object. * @@ -75,6 +80,7 @@ class ShippingMethodManagement implements * @param Quote\TotalsCollector $totalsCollector * @param DataObjectProcessor|null $dataProcessor * @param AddressInterfaceFactory|null $addressFactory + * @param QuoteAddressResource|null $quoteAddressResource */ public function __construct( \Magento\Quote\Api\CartRepositoryInterface $quoteRepository, @@ -82,7 +88,8 @@ public function __construct( \Magento\Customer\Api\AddressRepositoryInterface $addressRepository, \Magento\Quote\Model\Quote\TotalsCollector $totalsCollector, DataObjectProcessor $dataProcessor = null, - AddressInterfaceFactory $addressFactory = null + AddressInterfaceFactory $addressFactory = null, + QuoteAddressResource $quoteAddressResource = null ) { $this->quoteRepository = $quoteRepository; $this->converter = $converter; @@ -90,6 +97,8 @@ public function __construct( $this->totalsCollector = $totalsCollector; $this->dataProcessor = $dataProcessor ?: ObjectManager::getInstance()->get(DataObjectProcessor::class); $this->addressFactory = $addressFactory ?: ObjectManager::getInstance()->get(AddressInterfaceFactory::class); + $this->quoteAddressResource = $quoteAddressResource ?: ObjectManager::getInstance() + ->get(QuoteAddressResource::class); } /** @@ -176,9 +185,9 @@ public function set($cartId, $carrierCode, $methodCode) * @param string $methodCode The shipping method code. * @return void * @throws InputException The shipping method is not valid for an empty cart. - * @throws CouldNotSaveException The shipping method could not be saved. * @throws NoSuchEntityException Cart contains only virtual products. Shipping method is not applicable. * @throws StateException The billing or shipping address is not set. + * @throws \Exception */ public function apply($cartId, $carrierCode, $methodCode) { @@ -194,6 +203,8 @@ public function apply($cartId, $carrierCode, $methodCode) } $shippingAddress = $quote->getShippingAddress(); if (!$shippingAddress->getCountryId()) { + // Remove empty quote address + $this->quoteAddressResource->delete($shippingAddress); throw new StateException(__('Shipping address is not set')); } $shippingAddress->setShippingMethod($carrierCode . '_' . $methodCode); diff --git a/app/code/Magento/Quote/Test/Unit/Model/ShippingMethodManagementTest.php b/app/code/Magento/Quote/Test/Unit/Model/ShippingMethodManagementTest.php index 5629ae296cc29..65ff987076f46 100644 --- a/app/code/Magento/Quote/Test/Unit/Model/ShippingMethodManagementTest.php +++ b/app/code/Magento/Quote/Test/Unit/Model/ShippingMethodManagementTest.php @@ -15,7 +15,9 @@ use Magento\Quote\Model\Quote\Address\Rate; use Magento\Quote\Model\Quote\TotalsCollector; use Magento\Quote\Model\QuoteRepository; +use Magento\Quote\Model\ResourceModel\Quote\Address as QuoteAddressResource; use Magento\Quote\Model\ShippingMethodManagement; +use Magento\Store\Model\Store; use PHPUnit_Framework_MockObject_MockObject as MockObject; /** @@ -83,6 +85,16 @@ class ShippingMethodManagementTest extends \PHPUnit_Framework_TestCase */ private $totalsCollector; + /** + * @var Store|MockObject + */ + private $storeMock; + + /** + * @var QuoteAddressResource|MockObject + */ + private $quoteAddressResource; + protected function setUp() { $this->objectManager = new ObjectManager($this); @@ -97,8 +109,8 @@ protected function setUp() $className = \Magento\Framework\Reflection\DataObjectProcessor::class; $this->dataProcessor = $this->getMock($className, [], [], '', false); - - $this->storeMock = $this->getMock(\Magento\Store\Model\Store::class, [], [], '', false); + $this->quoteAddressResource = $this->getMock(QuoteAddressResource::class, [], [], '', false); + $this->storeMock = $this->getMock(Store::class, [], [], '', false); $this->quote = $this->getMockBuilder(Quote::class) ->disableOriginalConstructor() ->setMethods([ @@ -151,7 +163,8 @@ protected function setUp() 'totalsCollector' => $this->totalsCollector, 'addressRepository' => $this->addressRepository, 'dataProcessor' => $this->dataProcessor, - 'addressFactory' => $this->addressFactory + 'addressFactory' => $this->addressFactory, + 'quoteAddressResource' => $this->quoteAddressResource, ] ); } @@ -349,6 +362,7 @@ public function testSetMethodWithoutShippingAddress() $this->quote->expects($this->once()) ->method('getShippingAddress')->will($this->returnValue($this->shippingAddress)); $this->shippingAddress->expects($this->once())->method('getCountryId')->will($this->returnValue(null)); + $this->quoteAddressResource->expects($this->once())->method('delete')->with($this->shippingAddress); $this->model->set($cartId, $carrierCode, $methodCode); } @@ -432,6 +446,7 @@ public function testSetMethodWithoutAddress() $this->quote->expects($this->once()) ->method('getShippingAddress')->will($this->returnValue($this->shippingAddress)); $this->shippingAddress->expects($this->once())->method('getCountryId'); + $this->quoteAddressResource->expects($this->once())->method('delete')->with($this->shippingAddress); $this->model->set($cartId, $carrierCode, $methodCode); }