Skip to content

Commit 1511c75

Browse files
MAGETWO-93167: [2.3] Order Summary does not show free shipping after applying coupon during checkout
1 parent 1cb9235 commit 1511c75

File tree

6 files changed

+458
-114
lines changed

6 files changed

+458
-114
lines changed

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

Lines changed: 131 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
namespace Magento\Quote\Model\Quote\Address\Total;
77

88
use Magento\Framework\Pricing\PriceCurrencyInterface;
9+
use Magento\Quote\Api\Data\AddressInterface;
910
use Magento\Quote\Model\Quote\Address\FreeShippingInterface;
1011

1112
class Shipping extends \Magento\Quote\Model\Quote\Address\Total\AbstractTotal
@@ -40,7 +41,6 @@ public function __construct(
4041
* @param \Magento\Quote\Api\Data\ShippingAssignmentInterface $shippingAssignment
4142
* @param \Magento\Quote\Model\Quote\Address\Total $total
4243
* @return $this
43-
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
4444
* @SuppressWarnings(PHPMD.NPathComplexity)
4545
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
4646
*/
@@ -54,111 +54,27 @@ public function collect(
5454
$address = $shippingAssignment->getShipping()->getAddress();
5555
$method = $shippingAssignment->getShipping()->getMethod();
5656

57-
$address->setWeight(0);
58-
$address->setFreeMethodWeight(0);
59-
60-
$addressWeight = $address->getWeight();
61-
$freeMethodWeight = $address->getFreeMethodWeight();
62-
$addressFreeShipping = $address->getFreeShipping();
63-
6457
$total->setTotalAmount($this->getCode(), 0);
6558
$total->setBaseTotalAmount($this->getCode(), 0);
6659

6760
if (!count($shippingAssignment->getItems())) {
6861
return $this;
6962
}
7063

71-
$addressQty = 0;
72-
foreach ($shippingAssignment->getItems() as $item) {
73-
/**
74-
* Skip if this item is virtual
75-
*/
76-
if ($item->getProduct()->isVirtual()) {
77-
continue;
78-
}
79-
80-
/**
81-
* Children weight we calculate for parent
82-
*/
83-
if ($item->getParentItem()) {
84-
continue;
85-
}
86-
87-
if ($item->getHasChildren() && $item->isShipSeparately()) {
88-
foreach ($item->getChildren() as $child) {
89-
if ($child->getProduct()->isVirtual()) {
90-
continue;
91-
}
92-
$addressQty += $child->getTotalQty();
93-
94-
if (!$item->getProduct()->getWeightType()) {
95-
$itemWeight = $child->getWeight();
96-
$itemQty = $child->getTotalQty();
97-
$rowWeight = $itemWeight * $itemQty;
98-
$addressWeight += $rowWeight;
99-
if ($addressFreeShipping || $child->getFreeShipping() === true) {
100-
$rowWeight = 0;
101-
} elseif (is_numeric($child->getFreeShipping())) {
102-
$freeQty = $child->getFreeShipping();
103-
if ($itemQty > $freeQty) {
104-
$rowWeight = $itemWeight * ($itemQty - $freeQty);
105-
} else {
106-
$rowWeight = 0;
107-
}
108-
}
109-
$freeMethodWeight += $rowWeight;
110-
$item->setRowWeight($rowWeight);
111-
}
112-
}
113-
if ($item->getProduct()->getWeightType()) {
114-
$itemWeight = $item->getWeight();
115-
$rowWeight = $itemWeight * $item->getQty();
116-
$addressWeight += $rowWeight;
117-
if ($addressFreeShipping || $item->getFreeShipping() === true) {
118-
$rowWeight = 0;
119-
} elseif (is_numeric($item->getFreeShipping())) {
120-
$freeQty = $item->getFreeShipping();
121-
if ($item->getQty() > $freeQty) {
122-
$rowWeight = $itemWeight * ($item->getQty() - $freeQty);
123-
} else {
124-
$rowWeight = 0;
125-
}
126-
}
127-
$freeMethodWeight += $rowWeight;
128-
$item->setRowWeight($rowWeight);
129-
}
130-
} else {
131-
if (!$item->getProduct()->isVirtual()) {
132-
$addressQty += $item->getQty();
133-
}
134-
$itemWeight = $item->getWeight();
135-
$rowWeight = $itemWeight * $item->getQty();
136-
$addressWeight += $rowWeight;
137-
if ($addressFreeShipping || $item->getFreeShipping() === true) {
138-
$rowWeight = 0;
139-
} elseif (is_numeric($item->getFreeShipping())) {
140-
$freeQty = $item->getFreeShipping();
141-
if ($item->getQty() > $freeQty) {
142-
$rowWeight = $itemWeight * ($item->getQty() - $freeQty);
143-
} else {
144-
$rowWeight = 0;
145-
}
146-
}
147-
$freeMethodWeight += $rowWeight;
148-
$item->setRowWeight($rowWeight);
149-
}
64+
$data = $this->getAssignmentWeightData($address, $shippingAssignment->getItems());
65+
$address->setItemQty($data['addressQty']);
66+
$address->setWeight($data['addressWeight']);
67+
$address->setFreeMethodWeight($data['freeMethodWeight']);
68+
$addressFreeShipping = (bool)$address->getFreeShipping();
69+
$isFreeShipping = $this->freeShipping->isFreeShipping($quote, $shippingAssignment->getItems());
70+
$address->setFreeShipping($isFreeShipping);
71+
if (!$addressFreeShipping && $isFreeShipping) {
72+
$data = $this->getAssignmentWeightData($address, $shippingAssignment->getItems());
73+
$address->setItemQty($data['addressQty']);
74+
$address->setWeight($data['addressWeight']);
75+
$address->setFreeMethodWeight($data['freeMethodWeight']);
15076
}
15177

152-
if (isset($addressQty)) {
153-
$address->setItemQty($addressQty);
154-
}
155-
156-
$address->setWeight($addressWeight);
157-
$address->setFreeMethodWeight($freeMethodWeight);
158-
$address->setFreeShipping(
159-
$this->freeShipping->isFreeShipping($quote, $shippingAssignment->getItems())
160-
);
161-
16278
$address->collectShippingRates();
16379

16480
if ($method) {
@@ -215,4 +131,122 @@ public function getLabel()
215131
{
216132
return __('Shipping');
217133
}
134+
135+
/**
136+
* Gets shipping assignments data like items weight, address weight, items quantity.
137+
*
138+
* @param AddressInterface $address
139+
* @param array $items
140+
* @return array
141+
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
142+
*/
143+
private function getAssignmentWeightData(AddressInterface $address, array $items): array
144+
{
145+
$address->setWeight(0);
146+
$address->setFreeMethodWeight(0);
147+
$addressWeight = $address->getWeight();
148+
$freeMethodWeight = $address->getFreeMethodWeight();
149+
$addressFreeShipping = (bool)$address->getFreeShipping();
150+
$addressQty = 0;
151+
foreach ($items as $item) {
152+
/**
153+
* Skip if this item is virtual
154+
*/
155+
if ($item->getProduct()->isVirtual()) {
156+
continue;
157+
}
158+
159+
/**
160+
* Children weight we calculate for parent
161+
*/
162+
if ($item->getParentItem()) {
163+
continue;
164+
}
165+
166+
$itemQty = (float)$item->getQty();
167+
$itemWeight = (float)$item->getWeight();
168+
169+
if ($item->getHasChildren() && $item->isShipSeparately()) {
170+
foreach ($item->getChildren() as $child) {
171+
if ($child->getProduct()->isVirtual()) {
172+
continue;
173+
}
174+
$addressQty += $child->getTotalQty();
175+
176+
if (!$item->getProduct()->getWeightType()) {
177+
$itemWeight = (float)$child->getWeight();
178+
$itemQty = (float)$child->getTotalQty();
179+
$addressWeight += ($itemWeight * $itemQty);
180+
$rowWeight = $this->getItemRowWeight(
181+
$addressFreeShipping,
182+
$itemWeight,
183+
$itemQty,
184+
$child->getFreeShipping()
185+
);
186+
$freeMethodWeight += $rowWeight;
187+
$item->setRowWeight($rowWeight);
188+
}
189+
}
190+
if ($item->getProduct()->getWeightType()) {
191+
$addressWeight += ($itemWeight * $itemQty);
192+
$rowWeight = $this->getItemRowWeight(
193+
$addressFreeShipping,
194+
$itemWeight,
195+
$itemQty,
196+
$item->getFreeShipping()
197+
);
198+
$freeMethodWeight += $rowWeight;
199+
$item->setRowWeight($rowWeight);
200+
}
201+
} else {
202+
if (!$item->getProduct()->isVirtual()) {
203+
$addressQty += $itemQty;
204+
}
205+
$addressWeight += ($itemWeight * $itemQty);
206+
$rowWeight = $this->getItemRowWeight(
207+
$addressFreeShipping,
208+
$itemWeight,
209+
$itemQty,
210+
$item->getFreeShipping()
211+
);
212+
$freeMethodWeight += $rowWeight;
213+
$item->setRowWeight($rowWeight);
214+
}
215+
}
216+
217+
return [
218+
'addressQty' => $addressQty,
219+
'addressWeight' => $addressWeight,
220+
'freeMethodWeight' => $freeMethodWeight
221+
];
222+
}
223+
224+
/**
225+
* Calculates item row weight.
226+
*
227+
* @param bool $addressFreeShipping
228+
* @param float $itemWeight
229+
* @param float $itemQty
230+
* @param $freeShipping
231+
* @return float
232+
*/
233+
private function getItemRowWeight(
234+
bool $addressFreeShipping,
235+
float $itemWeight,
236+
float $itemQty,
237+
$freeShipping
238+
): float {
239+
$rowWeight = $itemWeight * $itemQty;
240+
if ($addressFreeShipping || $freeShipping === true) {
241+
$rowWeight = 0;
242+
} elseif (is_numeric($freeShipping)) {
243+
$freeQty = $freeShipping;
244+
if ($itemQty > $freeQty) {
245+
$rowWeight = $itemWeight * ($itemQty - $freeQty);
246+
} else {
247+
$rowWeight = 0;
248+
}
249+
}
250+
return (float)$rowWeight;
251+
}
218252
}

app/code/Magento/Quote/Test/Unit/Model/Quote/Address/Total/ShippingTest.php

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ class ShippingTest extends \PHPUnit\Framework\TestCase
4242
/** @var \Magento\Framework\Pricing\PriceCurrencyInterface|\PHPUnit_Framework_MockObject_MockObject */
4343
protected $priceCurrency;
4444

45+
/**
46+
* @inheritdoc
47+
*/
4548
protected function setUp()
4649
{
4750
$this->freeShipping = $this->getMockForAbstractClass(
@@ -123,7 +126,10 @@ protected function setUp()
123126
$this->store = $this->createMock(\Magento\Store\Model\Store::class);
124127
}
125128

126-
public function testFetch()
129+
/**
130+
* @return void
131+
*/
132+
public function testFetch(): void
127133
{
128134
$shippingAmount = 100;
129135
$shippingDescription = 100;
@@ -144,7 +150,10 @@ public function testFetch()
144150
$this->assertEquals($expectedResult, $this->shippingModel->fetch($quoteMock, $totalMock));
145151
}
146152

147-
public function testCollect()
153+
/**
154+
* @return void
155+
*/
156+
public function testCollect(): void
148157
{
149158
$this->shippingAssignment->expects($this->exactly(3))
150159
->method('getShipping')
@@ -158,12 +167,10 @@ public function testCollect()
158167
$this->shippingAssignment->expects($this->atLeastOnce())
159168
->method('getItems')
160169
->willReturn([$this->cartItem]);
161-
$this->freeShipping->expects($this->once())
162-
->method('isFreeShipping')
170+
$this->freeShipping->method('isFreeShipping')
163171
->with($this->quote, [$this->cartItem])
164172
->willReturn(true);
165-
$this->address->expects($this->once())
166-
->method('setFreeShipping')
173+
$this->address->method('setFreeShipping')
167174
->with(true);
168175
$this->total->expects($this->atLeastOnce())
169176
->method('setTotalAmount');
@@ -175,24 +182,19 @@ public function testCollect()
175182
$this->cartItem->expects($this->atLeastOnce())
176183
->method('isVirtual')
177184
->willReturn(false);
178-
$this->cartItem->expects($this->once())
179-
->method('getParentItem')
185+
$this->cartItem->method('getParentItem')
180186
->willReturn(false);
181-
$this->cartItem->expects($this->once())
182-
->method('getHasChildren')
187+
$this->cartItem->method('getHasChildren')
183188
->willReturn(false);
184-
$this->cartItem->expects($this->once())
185-
->method('getWeight')
189+
$this->cartItem->method('getWeight')
186190
->willReturn(2);
187191
$this->cartItem->expects($this->atLeastOnce())
188192
->method('getQty')
189193
->willReturn(2);
190194
$this->freeShippingAssertions();
191-
$this->cartItem->expects($this->once())
192-
->method('setRowWeight')
195+
$this->cartItem->method('setRowWeight')
193196
->with(0);
194-
$this->address->expects($this->once())
195-
->method('setItemQty')
197+
$this->address->method('setItemQty')
196198
->with(2);
197199
$this->address->expects($this->atLeastOnce())
198200
->method('setWeight');
@@ -241,7 +243,10 @@ public function testCollect()
241243
$this->shippingModel->collect($this->quote, $this->shippingAssignment, $this->total);
242244
}
243245

244-
protected function freeShippingAssertions()
246+
/**
247+
* @return void
248+
*/
249+
protected function freeShippingAssertions(): void
245250
{
246251
$this->address->expects($this->at(0))
247252
->method('getFreeShipping')

0 commit comments

Comments
 (0)