Skip to content

Commit c74d384

Browse files
committed
Merge remote-tracking branch 'origin/MAGETWO-97456' into 2.2.8-develop-pr71
2 parents c1d928e + 12507a8 commit c74d384

File tree

9 files changed

+400
-44
lines changed

9 files changed

+400
-44
lines changed

app/code/Magento/Quote/Model/Quote/Address/BillingAddressPersister.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
use Magento\Quote\Model\QuoteAddressValidator;
1313
use Magento\Customer\Api\AddressRepositoryInterface;
1414

15+
/**
16+
* Saves billing address for quotes.
17+
*/
1518
class BillingAddressPersister
1619
{
1720
/**
@@ -37,17 +40,17 @@ public function __construct(
3740
}
3841

3942
/**
43+
* Save address for billing.
44+
*
4045
* @param CartInterface $quote
4146
* @param AddressInterface $address
4247
* @param bool $useForShipping
4348
* @return void
44-
* @throws NoSuchEntityException
45-
* @throws InputException
4649
*/
4750
public function save(CartInterface $quote, AddressInterface $address, $useForShipping = false)
4851
{
4952
/** @var \Magento\Quote\Model\Quote $quote */
50-
$this->addressValidator->validate($address);
53+
$this->addressValidator->validateForCart($quote, $address);
5154
$customerAddressId = $address->getCustomerAddressId();
5255
$shippingAddress = null;
5356
$addressData = [];

app/code/Magento/Quote/Model/QuoteAddressValidator.php

Lines changed: 51 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@
66
namespace Magento\Quote\Model;
77

88
use Magento\Framework\Exception\NoSuchEntityException;
9+
use Magento\Quote\Api\Data\AddressInterface;
10+
use Magento\Quote\Api\Data\CartInterface;
911

1012
/**
1113
* Quote shipping/billing address validator service.
1214
*
15+
* @SuppressWarnings(PHPMD.CookieAndSessionMisuse)
1316
*/
1417
class QuoteAddressValidator
1518
{
@@ -28,7 +31,7 @@ class QuoteAddressValidator
2831
protected $customerRepository;
2932

3033
/**
31-
* @var \Magento\Customer\Model\Session
34+
* @deprecated This class is not a part of HTML presentation layer and should not use sessions.
3235
*/
3336
protected $customerSession;
3437

@@ -50,44 +53,68 @@ public function __construct(
5053
}
5154

5255
/**
53-
* Validates the fields in a specified address data object.
56+
* Validate address.
5457
*
55-
* @param \Magento\Quote\Api\Data\AddressInterface $addressData The address data object.
56-
* @return bool
57-
* @throws \Magento\Framework\Exception\InputException The specified address belongs to another customer.
58-
* @throws \Magento\Framework\Exception\NoSuchEntityException The specified customer ID or address ID is not valid.
58+
* @param AddressInterface $address
59+
* @param int|null $customerId Cart belongs to
60+
* @return void
61+
* @throws NoSuchEntityException The specified customer ID or address ID is not valid.
5962
*/
60-
public function validate(\Magento\Quote\Api\Data\AddressInterface $addressData)
63+
private function doValidate(AddressInterface $address, $customerId)
6164
{
6265
//validate customer id
63-
if ($addressData->getCustomerId()) {
64-
$customer = $this->customerRepository->getById($addressData->getCustomerId());
65-
if (!$customer->getId()) {
66-
throw new \Magento\Framework\Exception\NoSuchEntityException(
67-
__('Invalid customer id %1', $addressData->getCustomerId())
68-
);
66+
if ($customerId) {
67+
try {
68+
$this->customerRepository->getById($customerId);
69+
} catch (NoSuchEntityException $exception) {
70+
throw new NoSuchEntityException(__('Invalid customer id %1', $customerId));
6971
}
7072
}
7173

72-
if ($addressData->getCustomerAddressId()) {
74+
if ($address->getCustomerAddressId()) {
75+
//Existing address cannot belong to a guest
76+
if (!$customerId) {
77+
throw new NoSuchEntityException(__('Invalid customer address id %1', $address->getCustomerAddressId()));
78+
}
79+
//Validating address ID
7380
try {
74-
$this->addressRepository->getById($addressData->getCustomerAddressId());
81+
$this->addressRepository->getById($address->getCustomerAddressId());
7582
} catch (NoSuchEntityException $e) {
76-
throw new \Magento\Framework\Exception\NoSuchEntityException(
77-
__('Invalid address id %1', $addressData->getId())
78-
);
83+
throw new NoSuchEntityException(__('Invalid address id %1', $address->getId()));
7984
}
80-
85+
//Finding available customer's addresses
8186
$applicableAddressIds = array_map(function ($address) {
8287
/** @var \Magento\Customer\Api\Data\AddressInterface $address */
8388
return $address->getId();
84-
}, $this->customerRepository->getById($addressData->getCustomerId())->getAddresses());
85-
if (!in_array($addressData->getCustomerAddressId(), $applicableAddressIds)) {
86-
throw new \Magento\Framework\Exception\NoSuchEntityException(
87-
__('Invalid customer address id %1', $addressData->getCustomerAddressId())
88-
);
89+
}, $this->customerRepository->getById($customerId)->getAddresses());
90+
if (!in_array($address->getCustomerAddressId(), $applicableAddressIds)) {
91+
throw new NoSuchEntityException(__('Invalid customer address id %1', $address->getCustomerAddressId()));
8992
}
9093
}
94+
}
95+
96+
/**
97+
* Validates the fields in a specified address data object.
98+
*
99+
* @param \Magento\Quote\Api\Data\AddressInterface $addressData The address data object.
100+
* @return bool
101+
*/
102+
public function validate(AddressInterface $addressData): bool
103+
{
104+
$this->doValidate($addressData, $addressData->getCustomerId());
105+
91106
return true;
92107
}
108+
109+
/**
110+
* Validate address to be used for cart.
111+
*
112+
* @param CartInterface $cart
113+
* @param AddressInterface $address
114+
* @return void
115+
*/
116+
public function validateForCart(CartInterface $cart, AddressInterface $address)
117+
{
118+
$this->doValidate($address, $cart->getCustomerIsGuest() ? null : $cart->getCustomer()->getId());
119+
}
93120
}

app/code/Magento/Quote/Model/ShippingAddressManagement.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ public function __construct(
7878
}
7979

8080
/**
81-
* {@inheritDoc}
81+
* @inheritdoc
8282
* @SuppressWarnings(PHPMD.NPathComplexity)
8383
*/
8484
public function assign($cartId, \Magento\Quote\Api\Data\AddressInterface $address)
@@ -94,7 +94,7 @@ public function assign($cartId, \Magento\Quote\Api\Data\AddressInterface $addres
9494
$saveInAddressBook = $address->getSaveInAddressBook() ? 1 : 0;
9595
$sameAsBilling = $address->getSameAsBilling() ? 1 : 0;
9696
$customerAddressId = $address->getCustomerAddressId();
97-
$this->addressValidator->validate($address);
97+
$this->addressValidator->validateForCart($quote, $address);
9898
$quote->setShippingAddress($address);
9999
$address = $quote->getShippingAddress();
100100

@@ -122,7 +122,7 @@ public function assign($cartId, \Magento\Quote\Api\Data\AddressInterface $addres
122122
}
123123

124124
/**
125-
* {@inheritDoc}
125+
* @inheritdoc
126126
*/
127127
public function get($cartId)
128128
{

app/code/Magento/Quote/Test/Unit/Model/QuoteAddressValidatorTest.php

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -67,27 +67,22 @@ public function testValidateInvalidCustomer()
6767
{
6868
$customerId = 100;
6969
$address = $this->createMock(\Magento\Quote\Api\Data\AddressInterface::class);
70-
$customerMock = $this->createMock(\Magento\Customer\Api\Data\CustomerInterface::class);
7170

7271
$address->expects($this->atLeastOnce())->method('getCustomerId')->willReturn($customerId);
7372
$this->customerRepositoryMock->expects($this->once())->method('getById')->with($customerId)
74-
->willReturn($customerMock);
73+
->willThrowException(new \Magento\Framework\Exception\NoSuchEntityException());
7574
$this->model->validate($address);
7675
}
7776

7877
/**
7978
* @expectedException \Magento\Framework\Exception\NoSuchEntityException
80-
* @expectedExceptionMessage Invalid address id 101
79+
* @expectedExceptionMessage Invalid customer address id 101
8180
*/
8281
public function testValidateInvalidAddress()
8382
{
8483
$address = $this->createMock(\Magento\Quote\Api\Data\AddressInterface::class);
8584
$this->customerRepositoryMock->expects($this->never())->method('getById');
86-
$address->expects($this->atLeastOnce())->method('getCustomerAddressId')->willReturn(101);
87-
$address->expects($this->once())->method('getId')->willReturn(101);
88-
89-
$this->addressRepositoryMock->expects($this->once())->method('getById')
90-
->willThrowException(new \Magento\Framework\Exception\NoSuchEntityException());
85+
$address->expects($this->exactly(2))->method('getCustomerAddressId')->willReturn(101);
9186

9287
$this->model->validate($address);
9388
}
@@ -115,7 +110,6 @@ public function testValidateWithValidAddress()
115110
$customerAddress = $this->createMock(\Magento\Quote\Api\Data\AddressInterface::class);
116111

117112
$this->customerRepositoryMock->expects($this->exactly(2))->method('getById')->willReturn($customerMock);
118-
$customerMock->expects($this->once())->method('getId')->willReturn($addressCustomer);
119113

120114
$this->addressRepositoryMock->expects($this->once())->method('getById')->willReturn($this->quoteAddressMock);
121115
$this->quoteAddressMock->expects($this->any())->method('getCustomerId')->willReturn($addressCustomer);

app/code/Magento/Quote/Test/Unit/Model/ShippingAddressManagementTest.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ public function testSetAddressValidationFailed()
110110
->with('cart654')
111111
->will($this->returnValue($quoteMock));
112112

113-
$this->validatorMock->expects($this->once())->method('validate')
113+
$this->validatorMock->expects($this->once())->method('validateForCart')
114114
->will($this->throwException(new \Magento\Framework\Exception\NoSuchEntityException(__('error345'))));
115115

116116
$this->service->assign('cart654', $this->quoteAddressMock);
@@ -143,8 +143,8 @@ public function testSetAddress()
143143
->with($customerAddressId)
144144
->willReturn($customerAddressMock);
145145

146-
$this->validatorMock->expects($this->once())->method('validate')
147-
->with($this->quoteAddressMock)
146+
$this->validatorMock->expects($this->once())->method('validateForCart')
147+
->with($quoteMock, $this->quoteAddressMock)
148148
->willReturn(true);
149149

150150
$quoteMock->expects($this->exactly(3))->method('getShippingAddress')->willReturn($this->quoteAddressMock);
@@ -218,8 +218,8 @@ public function testSetAddressWithInabilityToSaveQuote()
218218
->with($customerAddressId)
219219
->willReturn($customerAddressMock);
220220

221-
$this->validatorMock->expects($this->once())->method('validate')
222-
->with($this->quoteAddressMock)
221+
$this->validatorMock->expects($this->once())->method('validateForCart')
222+
->with($quoteMock, $this->quoteAddressMock)
223223
->willReturn(true);
224224

225225
$this->quoteAddressMock->expects($this->once())->method('getSaveInAddressBook')->willReturn(1);
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Checkout\Api;
9+
10+
use Magento\Checkout\Api\Data\ShippingInformationInterface;
11+
use Magento\Checkout\Api\Data\ShippingInformationInterfaceFactory;
12+
use Magento\Customer\Api\CustomerRepositoryInterface;
13+
use Magento\Framework\Api\SearchCriteriaBuilder;
14+
use Magento\Quote\Api\CartRepositoryInterface;
15+
use Magento\Quote\Api\Data\ShippingAssignmentInterface;
16+
use Magento\TestFramework\Helper\Bootstrap;
17+
use PHPUnit\Framework\TestCase;
18+
use Magento\Quote\Model\QuoteIdMask;
19+
use Magento\Quote\Model\QuoteIdMaskFactory;
20+
21+
/**
22+
* Test GuestShippingInformationManagement API.
23+
*/
24+
class GuestShippingInformationManagementTest extends TestCase
25+
{
26+
/**
27+
* @var GuestShippingInformationManagementInterface
28+
*/
29+
private $management;
30+
31+
/**
32+
* @var CartRepositoryInterface
33+
*/
34+
private $cartRepo;
35+
36+
/**
37+
* @var CustomerRepositoryInterface
38+
*/
39+
private $customerRepo;
40+
41+
/**
42+
* @var ShippingInformationInterfaceFactory
43+
*/
44+
private $shippingFactory;
45+
46+
/**
47+
* @var SearchCriteriaBuilder
48+
*/
49+
private $searchCriteria;
50+
51+
/**
52+
* @var QuoteIdMaskFactory
53+
*/
54+
private $maskFactory;
55+
56+
/**
57+
* @inheritdoc
58+
*/
59+
protected function setUp()
60+
{
61+
$objectManager = Bootstrap::getObjectManager();
62+
$this->management = $objectManager->get(GuestShippingInformationManagementInterface::class);
63+
$this->cartRepo = $objectManager->get(CartRepositoryInterface::class);
64+
$this->customerRepo = $objectManager->get(CustomerRepositoryInterface::class);
65+
$this->shippingFactory = $objectManager->get(ShippingInformationInterfaceFactory::class);
66+
$this->searchCriteria = $objectManager->get(SearchCriteriaBuilder::class);
67+
$this->maskFactory = $objectManager->get(QuoteIdMaskFactory::class);
68+
}
69+
70+
/**
71+
* Test using another address for quote.
72+
*
73+
* @param bool $swapShipping Whether to swap shipping or billing addresses.
74+
* @return void
75+
*
76+
* @magentoDataFixture Magento/Sales/_files/quote.php
77+
* @magentoDataFixture Magento/Customer/_files/customer_with_addresses.php
78+
* @dataProvider differentAddressesDataProvider
79+
* @expectedException \Magento\Framework\Exception\InputException
80+
* @expectedExceptionMessage Unable to save shipping information. Please check input data.
81+
*/
82+
public function testDifferentAddresses(bool $swapShipping)
83+
{
84+
$carts = $this->cartRepo->getList(
85+
$this->searchCriteria->addFilter('reserved_order_id', 'test01')->create()
86+
)->getItems();
87+
$cart = array_pop($carts);
88+
$otherCustomer = $this->customerRepo->get('customer_with_addresses@test.com');
89+
$otherAddresses = $otherCustomer->getAddresses();
90+
$otherAddress = array_pop($otherAddresses);
91+
92+
//Setting invalid IDs.
93+
/** @var ShippingAssignmentInterface $shippingAssignment */
94+
$shippingAssignment = $cart->getExtensionAttributes()->getShippingAssignments()[0];
95+
$shippingAddress = $shippingAssignment->getShipping()->getAddress();
96+
$billingAddress = $cart->getBillingAddress();
97+
if ($swapShipping) {
98+
$address = $shippingAddress;
99+
} else {
100+
$address = $billingAddress;
101+
}
102+
$address->setCustomerAddressId($otherAddress->getId());
103+
$address->setCustomerId($otherCustomer->getId());
104+
$address->setId(null);
105+
/** @var ShippingInformationInterface $shippingInformation */
106+
$shippingInformation = $this->shippingFactory->create();
107+
$shippingInformation->setBillingAddress($billingAddress);
108+
$shippingInformation->setShippingAddress($shippingAddress);
109+
$shippingInformation->setShippingMethodCode('flatrate');
110+
/** @var QuoteIdMask $idMask */
111+
$idMask = $this->maskFactory->create();
112+
$idMask->load($cart->getId(), 'quote_id');
113+
$this->management->saveAddressInformation($idMask->getMaskedId(), $shippingInformation);
114+
}
115+
116+
/**
117+
* @return array
118+
*/
119+
public function differentAddressesDataProvider(): array
120+
{
121+
return [
122+
'Shipping address swap' => [true],
123+
'Billing address swap' => [false],
124+
];
125+
}
126+
}

0 commit comments

Comments
 (0)