Skip to content

Commit 61482bd

Browse files
committed
Merge remote-tracking branch 'origin/MC-29579' into 2.4-develop-pr11
2 parents d68555c + 52a5fb6 commit 61482bd

File tree

6 files changed

+348
-27
lines changed

6 files changed

+348
-27
lines changed

app/code/Magento/Customer/etc/fieldset.xml

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -57,23 +57,6 @@
5757
<aspect name="update" />
5858
</field>
5959
</fieldset>
60-
<fieldset id="customer_address">
61-
<field name="vat_id">
62-
<aspect name="to_quote_address" />
63-
</field>
64-
<field name="vat_is_valid">
65-
<aspect name="to_quote_address" />
66-
</field>
67-
<field name="vat_request_id">
68-
<aspect name="to_quote_address" />
69-
</field>
70-
<field name="vat_request_date">
71-
<aspect name="to_quote_address" />
72-
</field>
73-
<field name="vat_request_success">
74-
<aspect name="to_quote_address" />
75-
</field>
76-
</fieldset>
7760
<fieldset id="sales_convert_order_address">
7861
<field name="vat_id">
7962
<aspect name="to_quote_address" />

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

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
namespace Magento\Quote\Model;
88

99
use Magento\Customer\Api\Data\AddressInterfaceFactory;
10+
use Magento\Customer\Model\Session as CustomerSession;
1011
use Magento\Framework\App\ObjectManager;
1112
use Magento\Framework\Exception\CouldNotSaveException;
1213
use Magento\Framework\Exception\InputException;
@@ -22,6 +23,7 @@
2223
* Shipping method read service
2324
*
2425
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
26+
* @SuppressWarnings(PHPMD.CookieAndSessionMisuse)
2527
*/
2628
class ShippingMethodManagement implements
2729
\Magento\Quote\Api\ShippingMethodManagementInterface,
@@ -69,6 +71,11 @@ class ShippingMethodManagement implements
6971
*/
7072
private $quoteAddressResource;
7173

74+
/**
75+
* @var CustomerSession
76+
*/
77+
private $customerSession;
78+
7279
/**
7380
* Constructor
7481
*
@@ -78,14 +85,16 @@ class ShippingMethodManagement implements
7885
* @param Quote\TotalsCollector $totalsCollector
7986
* @param AddressInterfaceFactory|null $addressFactory
8087
* @param QuoteAddressResource|null $quoteAddressResource
88+
* @param CustomerSession|null $customerSession
8189
*/
8290
public function __construct(
8391
\Magento\Quote\Api\CartRepositoryInterface $quoteRepository,
8492
Cart\ShippingMethodConverter $converter,
8593
\Magento\Customer\Api\AddressRepositoryInterface $addressRepository,
8694
\Magento\Quote\Model\Quote\TotalsCollector $totalsCollector,
8795
AddressInterfaceFactory $addressFactory = null,
88-
QuoteAddressResource $quoteAddressResource = null
96+
QuoteAddressResource $quoteAddressResource = null,
97+
CustomerSession $customerSession = null
8998
) {
9099
$this->quoteRepository = $quoteRepository;
91100
$this->converter = $converter;
@@ -95,10 +104,11 @@ public function __construct(
95104
->get(AddressInterfaceFactory::class);
96105
$this->quoteAddressResource = $quoteAddressResource ?: ObjectManager::getInstance()
97106
->get(QuoteAddressResource::class);
107+
$this->customerSession = $customerSession ?? ObjectManager::getInstance()->get(CustomerSession::class);
98108
}
99109

100110
/**
101-
* {@inheritDoc}
111+
* @inheritDoc
102112
*/
103113
public function get($cartId)
104114
{
@@ -126,7 +136,7 @@ public function get($cartId)
126136
}
127137

128138
/**
129-
* {@inheritDoc}
139+
* @inheritDoc
130140
*/
131141
public function getList($cartId)
132142
{
@@ -155,7 +165,7 @@ public function getList($cartId)
155165
}
156166

157167
/**
158-
* {@inheritDoc}
168+
* @inheritDoc
159169
*/
160170
public function set($cartId, $carrierCode, $methodCode)
161171
{
@@ -176,6 +186,8 @@ public function set($cartId, $carrierCode, $methodCode)
176186
}
177187

178188
/**
189+
* Apply carrier code.
190+
*
179191
* @param int $cartId The shopping cart ID.
180192
* @param string $carrierCode The carrier code.
181193
* @param string $methodCode The shipping method code.
@@ -209,7 +221,7 @@ public function apply($cartId, $carrierCode, $methodCode)
209221
}
210222

211223
/**
212-
* {@inheritDoc}
224+
* @inheritDoc
213225
*/
214226
public function estimateByAddress($cartId, \Magento\Quote\Api\Data\EstimateAddressInterface $address)
215227
{
@@ -240,7 +252,7 @@ public function estimateByExtendedAddress($cartId, AddressInterface $address)
240252
}
241253

242254
/**
243-
* {@inheritDoc}
255+
* @inheritDoc
244256
*/
245257
public function estimateByAddressId($cartId, $addressId)
246258
{
@@ -266,6 +278,7 @@ public function estimateByAddressId($cartId, $addressId)
266278
* @param string $region
267279
* @param \Magento\Framework\Api\ExtensibleDataInterface|null $address
268280
* @return \Magento\Quote\Api\Data\ShippingMethodInterface[] An array of shipping methods.
281+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
269282
* @deprecated 100.2.0
270283
*/
271284
protected function getEstimatedRates(
@@ -277,11 +290,10 @@ protected function getEstimatedRates(
277290
$address = null
278291
) {
279292
if (!$address) {
280-
$address = $this->getAddressFactory()->create()
293+
$address = $this->addressFactory->create()
281294
->setCountryId($country)
282295
->setPostcode($postcode)
283-
->setRegionId($regionId)
284-
->setRegion($region);
296+
->setRegionId($regionId);
285297
}
286298
return $this->getShippingMethods($quote, $address);
287299
}
@@ -301,12 +313,21 @@ private function getShippingMethods(Quote $quote, $address)
301313
$shippingAddress->setCollectShippingRates(true);
302314

303315
$this->totalsCollector->collectAddressTotals($quote, $shippingAddress);
316+
$quoteCustomerGroupId = $quote->getCustomerGroupId();
317+
$customerGroupId = $this->customerSession->getCustomerGroupId();
318+
$isCustomerGroupChanged = $quoteCustomerGroupId !== $customerGroupId;
319+
if ($isCustomerGroupChanged) {
320+
$quote->setCustomerGroupId($customerGroupId);
321+
}
304322
$shippingRates = $shippingAddress->getGroupedAllShippingRates();
305323
foreach ($shippingRates as $carrierRates) {
306324
foreach ($carrierRates as $rate) {
307325
$output[] = $this->converter->modelToDataObject($rate, $quote->getQuoteCurrencyCode());
308326
}
309327
}
328+
if ($isCustomerGroupChanged) {
329+
$quote->setCustomerGroupId($quoteCustomerGroupId);
330+
}
310331
return $output;
311332
}
312333

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
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+
use Magento\Framework\Api\SearchCriteriaBuilder;
9+
use Magento\Customer\Api\GroupRepositoryInterface;
10+
use Magento\TestFramework\Helper\Bootstrap;
11+
use Magento\Framework\ObjectManagerInterface;
12+
use Magento\Framework\Exception\NoSuchEntityException;
13+
use Magento\Customer\Api\Data\GroupInterface;
14+
15+
/** @var ObjectManagerInterface $objectManager */
16+
$objectManager = Bootstrap::getObjectManager();
17+
$groupRepository = $objectManager->get(GroupRepositoryInterface::class);
18+
/** @var SearchCriteriaBuilder $searchBuilder */
19+
$searchBuilder = $objectManager->get(SearchCriteriaBuilder::class);
20+
$searchCriteria = $searchBuilder->addFilter(GroupInterface::CODE, 'custom_group')
21+
->create();
22+
$groups = $groupRepository->getList($searchCriteria)
23+
->getItems();
24+
foreach ($groups as $group) {
25+
try {
26+
$groupRepository->delete($group);
27+
} catch (NoSuchEntityException $exception) {
28+
//Group already removed
29+
}
30+
}

dev/tests/integration/testsuite/Magento/Quote/Model/ShippingMethodManagementTest.php

Lines changed: 166 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,52 @@
66

77
namespace Magento\Quote\Model;
88

9+
use Magento\Customer\Model\Vat;
10+
use Magento\Store\Model\ScopeInterface;
11+
use Magento\Tax\Model\Config as TaxConfig;
12+
use Magento\TestFramework\Helper\Bootstrap;
13+
use Magento\TestFramework\Quote\Model\GetQuoteByReservedOrderId;
14+
use Magento\Framework\ObjectManagerInterface;
15+
use Magento\Customer\Api\Data\GroupInterface;
16+
use Magento\Customer\Api\GroupRepositoryInterface;
17+
use Magento\Tax\Model\ClassModel;
18+
use Magento\Framework\App\Config\MutableScopeConfigInterface;
19+
use Magento\Customer\Api\AddressRepositoryInterface;
20+
use Magento\Customer\Api\Data\CustomerInterface;
21+
use Magento\Customer\Api\CustomerRepositoryInterface;
22+
use Magento\Quote\Api\ShippingMethodManagementInterface;
23+
use Magento\Customer\Api\Data\AddressInterface;
24+
use Magento\Framework\Api\SearchCriteriaBuilder;
25+
use Magento\Tax\Api\TaxClassRepositoryInterface;
26+
use Magento\Tax\Api\Data\TaxClassInterface;
27+
928
/**
10-
* Class ShippingMethodManagementTest
29+
* Test for shipping methods management
1130
*
1231
* @magentoDbIsolation enabled
32+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
1333
*/
1434
class ShippingMethodManagementTest extends \PHPUnit\Framework\TestCase
1535
{
36+
/** @var ObjectManagerInterface $objectManager */
37+
private $objectManager;
38+
39+
/** @var GroupRepositoryInterface $groupRepository */
40+
private $groupRepository;
41+
42+
/** @var TaxClassRepositoryInterface $taxClassRepository */
43+
private $taxClassRepository;
44+
45+
/**
46+
* @inheritdoc
47+
*/
48+
protected function setUp()
49+
{
50+
$this->objectManager = Bootstrap::getObjectManager();
51+
$this->groupRepository = $this->objectManager->get(GroupRepositoryInterface::class);
52+
$this->taxClassRepository = $this->objectManager->get(TaxClassRepositoryInterface::class);
53+
}
54+
1655
/**
1756
* @magentoDataFixture Magento/SalesRule/_files/cart_rule_100_percent_off.php
1857
* @magentoDataFixture Magento/Sales/_files/quote_with_customer.php
@@ -173,4 +212,130 @@ private function executeTestFlow($flatRateAmount, $tableRateAmount)
173212
$this->assertEquals($expectedResult[$rate->getCarrierCode()]['method_code'], $rate->getMethodCode());
174213
}
175214
}
215+
216+
/**
217+
* Test for estimate shipping with tax and changed VAT customer group
218+
*
219+
* @magentoDbIsolation disabled
220+
* @magentoDataFixture Magento/Tax/_files/tax_classes_de.php
221+
* @magentoDataFixture Magento/Sales/_files/quote_with_customer.php
222+
* @magentoDataFixture Magento/Customer/_files/customer_group.php
223+
* @magentoDataFixture Magento/Customer/_files/customer_address.php
224+
* @magentoConfigFixture current_store customer/create_account/tax_calculation_address_type shipping
225+
* @magentoConfigFixture current_store customer/create_account/default_group 1
226+
* @magentoConfigFixture current_store customer/create_account/auto_group_assign 1
227+
* @magentoConfigFixture current_store tax/calculation/price_includes_tax 1
228+
* @magentoConfigFixture current_store tax/calculation/shipping_includes_tax 1
229+
*/
230+
public function testEstimateByAddressWithInclExclTaxAndVATGroup()
231+
{
232+
/** @var CustomerRepositoryInterface $customerRepository */
233+
$customerRepository = $this->objectManager->get(CustomerRepositoryInterface::class);
234+
$customer = $customerRepository->get('customer@example.com');
235+
236+
/** @var GroupInterface $customerGroup */
237+
$customerGroup = $this->findCustomerGroupByCode('custom_group');
238+
$customerGroup->setTaxClassId($this->getTaxClass('CustomerTaxClass')->getClassId());
239+
$this->groupRepository->save($customerGroup);
240+
241+
$customer->setGroupId($customerGroup->getId());
242+
$customer->setTaxvat('12');
243+
$customerRepository->save($customer);
244+
$this->setConfig($customerGroup->getId(), $this->getTaxClass('ProductTaxClass')->getClassId());
245+
$this->changeCustomerAddress($customer->getDefaultShipping());
246+
247+
$quote = $this->objectManager->get(GetQuoteByReservedOrderId::class)->execute('test01');
248+
249+
/** @var ShippingMethodManagementInterface $shippingEstimation */
250+
$shippingEstimation = $this->objectManager->get(ShippingMethodManagementInterface::class);
251+
$result = $shippingEstimation->estimateByAddressId($quote->getId(), $customer->getDefaultShipping());
252+
253+
$this->assertEquals(6.05, $result[0]->getPriceInclTax());
254+
$this->assertEquals(5.0, $result[0]->getPriceExclTax());
255+
}
256+
257+
/**
258+
* Find the group with a given code.
259+
*
260+
* @param string $code
261+
*
262+
* @return GroupInterface
263+
*/
264+
protected function findCustomerGroupByCode(string $code): ?GroupInterface
265+
{
266+
/** @var SearchCriteriaBuilder $searchBuilder */
267+
$searchBuilder = $this->objectManager->get(SearchCriteriaBuilder::class);
268+
$searchCriteria = $searchBuilder->addFilter('code', $code)
269+
->create();
270+
$groups = $this->groupRepository->getList($searchCriteria)
271+
->getItems();
272+
273+
return array_shift($groups);
274+
}
275+
276+
/**
277+
* Change customer address
278+
*
279+
* @param int $customerAddressId
280+
*
281+
* @return AddressInterface
282+
*/
283+
private function changeCustomerAddress(int $customerAddressId): AddressInterface
284+
{
285+
$addressRepository = $this->objectManager->get(AddressRepositoryInterface::class);
286+
$address = $addressRepository->getById($customerAddressId);
287+
$address->setVatId(12345);
288+
$address->setCountryId('DE');
289+
$address->setRegionId(0);
290+
$address->setPostcode(10178);
291+
292+
return $addressRepository->save($address);
293+
}
294+
295+
/**
296+
* Get tax class.
297+
*
298+
* @param string $name
299+
*
300+
* @return TaxClassInterface
301+
*/
302+
private function getTaxClass(string $name): ?TaxClassInterface
303+
{
304+
/** @var SearchCriteriaBuilder $searchBuilder */
305+
$searchBuilder = $this->objectManager->get(SearchCriteriaBuilder::class);
306+
$searchCriteria = $searchBuilder->addFilter(ClassModel::KEY_NAME, $name)
307+
->create();
308+
$searchResults = $this->taxClassRepository->getList($searchCriteria)
309+
->getItems();
310+
311+
return array_shift($searchResults);
312+
}
313+
314+
/**
315+
* Set the configuration.
316+
*
317+
* @param int $customerGroupId
318+
* @param int $productTaxClassId
319+
*
320+
* @return void
321+
*/
322+
private function setConfig(int $customerGroupId, int $productTaxClassId): void
323+
{
324+
$configData = [
325+
[
326+
'path' => Vat::XML_PATH_CUSTOMER_VIV_INVALID_GROUP,
327+
'value' => $customerGroupId,
328+
'scope' => ScopeInterface::SCOPE_STORE,
329+
],
330+
[
331+
'path' => TaxConfig::CONFIG_XML_PATH_SHIPPING_TAX_CLASS,
332+
'value' => $productTaxClassId,
333+
'scope' => ScopeInterface::SCOPE_STORE,
334+
],
335+
];
336+
$config = $this->objectManager->get(MutableScopeConfigInterface::class);
337+
foreach ($configData as $data) {
338+
$config->setValue($data['path'], $data['value'], $data['scope']);
339+
}
340+
}
176341
}

0 commit comments

Comments
 (0)