Skip to content

Commit 8c8ce98

Browse files
committed
MC-41343: Free Shipping Rule not applied when multiple items are in the cart [Online shipping methods + For matching items only]
- Fix free shipping is applied to one quantity only.
1 parent 2660e9b commit 8c8ce98

File tree

2 files changed

+136
-39
lines changed
  • app/code/Magento/Quote/Model/Quote/Address/Total
  • dev/tests/integration/testsuite/Magento/SalesRule/Model/Quote/Address/Total

2 files changed

+136
-39
lines changed

app/code/Magento/Quote/Model/Quote/Address/Total/Shipping.php

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -71,15 +71,14 @@ public function collect(
7171
$address->setItemQty($data['addressQty']);
7272
$address->setWeight($data['addressWeight']);
7373
$address->setFreeMethodWeight($data['freeMethodWeight']);
74-
$addressFreeShipping = (bool)$address->getFreeShipping();
74+
7575
$isFreeShipping = $this->freeShipping->isFreeShipping($quote, $shippingAssignment->getItems());
7676
$address->setFreeShipping($isFreeShipping);
77-
if (!$addressFreeShipping && $isFreeShipping) {
78-
$data = $this->getAssignmentWeightData($address, $shippingAssignment->getItems());
79-
$address->setItemQty($data['addressQty']);
80-
$address->setWeight($data['addressWeight']);
81-
$address->setFreeMethodWeight($data['freeMethodWeight']);
82-
}
77+
// recalculate weights
78+
$data = $this->getAssignmentWeightData($address, $shippingAssignment->getItems());
79+
$address->setItemQty($data['addressQty']);
80+
$address->setWeight($data['addressWeight']);
81+
$address->setFreeMethodWeight($data['freeMethodWeight']);
8382

8483
$address->collectShippingRates();
8584

dev/tests/integration/testsuite/Magento/SalesRule/Model/Quote/Address/Total/ShippingTest.php

Lines changed: 130 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,28 +6,49 @@
66

77
namespace Magento\SalesRule\Model\Quote\Address\Total;
88

9-
class ShippingTest extends \PHPUnit\Framework\TestCase
9+
use Magento\Catalog\Api\ProductRepositoryInterface;
10+
use Magento\Framework\Exception\NoSuchEntityException;
11+
use Magento\Framework\ObjectManagerInterface;
12+
use Magento\Framework\Registry;
13+
use Magento\Quote\Api\CartRepositoryInterface;
14+
use Magento\Quote\Api\Data\AddressInterface;
15+
use Magento\Quote\Api\Data\AddressInterfaceFactory;
16+
use Magento\Quote\Api\Data\CartInterface;
17+
use Magento\Quote\Api\Data\ShippingMethodInterface;
18+
use Magento\Quote\Api\GuestCartItemRepositoryInterface;
19+
use Magento\Quote\Api\GuestCartManagementInterface;
20+
use Magento\Quote\Api\GuestShipmentEstimationInterface;
21+
use Magento\Quote\Model\MaskedQuoteIdToQuoteIdInterface;
22+
use Magento\SalesRule\Model\Rule\Condition\Combine;
23+
use Magento\SalesRule\Model\Rule\Condition\Product;
24+
use Magento\TestFramework\Helper\Bootstrap;
25+
use PHPUnit\Framework\TestCase;
26+
27+
/**
28+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
29+
*/
30+
class ShippingTest extends TestCase
1031
{
1132
/**
12-
* @var \Magento\Quote\Api\GuestCartManagementInterface
33+
* @var GuestCartManagementInterface
1334
*/
1435
private $cartManagement;
1536

1637
/**
17-
* @var \Magento\Quote\Api\GuestCartItemRepositoryInterface
38+
* @var GuestCartItemRepositoryInterface
1839
*/
1940
private $itemRepository;
2041

2142
/**
22-
* @var \Magento\Framework\ObjectManagerInterface
43+
* @var ObjectManagerInterface
2344
*/
2445
private $objectManager;
2546

2647
protected function setUp(): void
2748
{
28-
$this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
29-
$this->cartManagement = $this->objectManager->get(\Magento\Quote\Api\GuestCartManagementInterface::class);
30-
$this->itemRepository = $this->objectManager->get(\Magento\Quote\Api\GuestCartItemRepositoryInterface::class);
49+
$this->objectManager = Bootstrap::getObjectManager();
50+
$this->cartManagement = $this->objectManager->get(GuestCartManagementInterface::class);
51+
$this->itemRepository = $this->objectManager->get(GuestCartItemRepositoryInterface::class);
3152
}
3253

3354
/**
@@ -37,7 +58,8 @@ protected function setUp(): void
3758
*/
3859
public function testRuleByProductWeightWithFreeShipping()
3960
{
40-
$cartId = $this->prepareQuote(1);
61+
$cartId = $this->cartManagement->createEmptyCart();
62+
$this->addToCart($cartId, 'simple-99', 1);
4163
$methods = $this->estimateShipping($cartId);
4264

4365
$this->assertTrue(count($methods) > 0);
@@ -52,55 +74,131 @@ public function testRuleByProductWeightWithFreeShipping()
5274
*/
5375
public function testRuleByProductWeightWithoutFreeShipping()
5476
{
55-
$cartId = $this->prepareQuote(5);
77+
$cartId = $this->cartManagement->createEmptyCart();
78+
$this->addToCart($cartId, 'simple-99', 5);
5679
$methods = $this->estimateShipping($cartId);
5780

5881
$this->assertTrue(count($methods) > 0);
5982
$this->assertEquals('flatrate', $methods[0]->getMethodCode());
6083
$this->assertEquals(25, $methods[0]->getAmount());
6184
}
6285

86+
/**
87+
* @magentoAppIsolation enabled
88+
* @magentoDataFixture Magento/SalesRule/_files/cart_rule_free_shipping.php
89+
* @magentoDataFixture Magento/Catalog/_files/products_list.php
90+
*/
91+
public function testFreeMethodWeight()
92+
{
93+
$this->setFreeShippingForProduct('simple-249');
94+
$cartId = $this->cartManagement->createEmptyCart();
95+
$this->addToCart($cartId, 'simple-249', 3);
96+
$this->addToCart($cartId, 'simple-156', 1);
97+
$this->estimateShipping($cartId);
98+
$quote = $this->getQuote($cartId);
99+
$this->assertEquals(10, $quote->getShippingAddress()->getFreeMethodWeight());
100+
}
101+
102+
/**
103+
* @magentoAppIsolation enabled
104+
* @magentoDataFixture Magento/SalesRule/_files/cart_rule_free_shipping.php
105+
* @magentoDataFixture Magento/Catalog/_files/products_list.php
106+
*/
107+
public function testFreeMethodWeightWithMaximumQtyDiscount()
108+
{
109+
$this->setFreeShippingForProduct('simple-249', 2);
110+
$cartId = $this->cartManagement->createEmptyCart();
111+
$this->addToCart($cartId, 'simple-249', 5);
112+
$this->addToCart($cartId, 'simple-156', 1);
113+
$this->estimateShipping($cartId);
114+
$quote = $this->getQuote($cartId);
115+
$this->assertEquals(40, $quote->getShippingAddress()->getFreeMethodWeight());
116+
}
117+
63118
/**
64119
* Estimate shipment for guest cart
65120
*
66121
* @param int $cartId
67-
* @return \Magento\Quote\Api\Data\ShippingMethodInterface[]
122+
* @return ShippingMethodInterface[]
68123
*/
69124
private function estimateShipping($cartId)
70125
{
71-
$addressFactory = $this->objectManager->get(\Magento\Quote\Api\Data\AddressInterfaceFactory::class);
72-
/** @var \Magento\Quote\Api\Data\AddressInterface $address */
126+
$addressFactory = $this->objectManager->get(AddressInterfaceFactory::class);
127+
/** @var AddressInterface $address */
73128
$address = $addressFactory->create();
74129
$address->setCountryId('US');
75130
$address->setRegionId(2);
76131

77-
/** @var \Magento\Quote\Api\GuestShipmentEstimationInterface $estimation */
78-
$estimation = $this->objectManager->get(\Magento\Quote\Api\GuestShipmentEstimationInterface::class);
132+
/** @var GuestShipmentEstimationInterface $estimation */
133+
$estimation = $this->objectManager->get(GuestShipmentEstimationInterface::class);
79134
return $estimation->estimateByExtendedAddress($cartId, $address);
80135
}
81136

82137
/**
83-
* Create guest quote with products
84-
*
85-
* @param int $itemQty
86-
* @return int
138+
* @param string $cartMaskId
139+
* @return CartInterface
140+
* @throws NoSuchEntityException
87141
*/
88-
private function prepareQuote($itemQty)
142+
private function getQuote(string $cartMaskId): CartInterface
89143
{
90-
$cartId = $this->cartManagement->createEmptyCart();
91-
92-
/** @var \Magento\Quote\Api\Data\CartItemInterfaceFactory $cartItemFactory */
93-
$cartItemFactory = $this->objectManager->get(\Magento\Quote\Api\Data\CartItemInterfaceFactory::class);
94-
95-
/** @var \Magento\Quote\Api\Data\CartItemInterface $cartItem */
96-
$cartItem = $cartItemFactory->create();
97-
$cartItem->setQuoteId($cartId);
98-
$cartItem->setQty($itemQty);
99-
$cartItem->setSku('simple-99');
100-
$cartItem->setProductType(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE);
144+
/** @var CartRepositoryInterface $cartRepository */
145+
$cartRepository = $this->objectManager->get(CartRepositoryInterface::class);
146+
/** @var MaskedQuoteIdToQuoteIdInterface $maskedQuoteIdToQuoteId */
147+
$maskedQuoteIdToQuoteId = $this->objectManager->get(MaskedQuoteIdToQuoteIdInterface::class);
148+
$cartId = $maskedQuoteIdToQuoteId->execute($cartMaskId);
149+
return $cartRepository->get($cartId);
150+
}
101151

102-
$this->itemRepository->save($cartItem);
152+
/**
153+
* @param string $cartMaskId
154+
* @param string $sku
155+
* @param int $qty
156+
* @throws NoSuchEntityException
157+
*/
158+
private function addToCart(string $cartMaskId, string $sku, int $qty): void
159+
{
160+
/** @var ProductRepositoryInterface $productRepository */
161+
$productRepository = $this->objectManager->get(ProductRepositoryInterface::class);
162+
/** @var CartRepositoryInterface $cartRepository */
163+
$cartRepository = $this->objectManager->get(CartRepositoryInterface::class);
164+
$product = $productRepository->get($sku);
165+
$quote = $this->getQuote($cartMaskId);
166+
$quote->addProduct($product, $qty);
167+
$cartRepository->save($quote);
168+
}
103169

104-
return $cartId;
170+
/**
171+
* @param string $sku
172+
* @param int $qty
173+
*/
174+
public function setFreeShippingForProduct(string $sku, int $qty = 0): void
175+
{
176+
/** @var Registry $registry */
177+
$registry = $this->objectManager->get(Registry::class);
178+
$salesRule = $registry->registry('cart_rule_free_shipping');
179+
$salesRule->setDiscountQty($qty);
180+
$data = [
181+
'actions' => [
182+
1 => [
183+
'type' => Combine::class,
184+
'attribute' => null,
185+
'operator' => null,
186+
'value' => '1',
187+
'is_value_processed' => null,
188+
'aggregator' => 'all',
189+
'actions' => [
190+
1 => [
191+
'type' => Product::class,
192+
'attribute' => 'sku',
193+
'operator' => '==',
194+
'value' => $sku,
195+
'is_value_processed' => false,
196+
]
197+
]
198+
]
199+
],
200+
];
201+
$salesRule->loadPost($data);
202+
$salesRule->save();
105203
}
106204
}

0 commit comments

Comments
 (0)