Skip to content

Commit 210d825

Browse files
committed
ACP2E-3377: Cart rules "Fixed amount discount for whole cart" action applies discounts incorrectly when adding bundle products
1 parent 9e76ef8 commit 210d825

File tree

2 files changed

+63
-126
lines changed

2 files changed

+63
-126
lines changed

app/code/Magento/Quote/Model/Quote/Item/AbstractItem.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@
2626
* @method float getDiscountPercent()
2727
* @method \Magento\Quote\Model\Quote\Item\AbstractItem setDiscountPercent()
2828
* @method float getOriginalDiscountAmount()
29-
* @method \Magento\Quote\Model\Quote\Item\AbstractItem setOriginalDiscountAmount(float $amount)
29+
* @method \Magento\Quote\Model\Quote\Item\AbstractItem setOriginalDiscountAmount()
3030
* @method float getBaseOriginalDiscountAmount()
31-
* @method \Magento\Quote\Model\Quote\Item\AbstractItem setBaseOriginalDiscountAmount(float $amount)
31+
* @method \Magento\Quote\Model\Quote\Item\AbstractItem setBaseOriginalDiscountAmount()
3232
* @method float getDiscountCalculationPrice()
33-
* @method \Magento\Quote\Model\Quote\Item\AbstractItem setDiscountCalculationPrice(float $amount)
33+
* @method \Magento\Quote\Model\Quote\Item\AbstractItem setDiscountCalculationPrice()
3434
* @method float getBaseDiscountCalculationPrice()
3535
* @method \Magento\Quote\Model\Quote\Item\AbstractItem setBaseDiscountCalculationPrice($price)
3636
* @method int[] getAppliedRuleIds()

app/code/Magento/SalesRule/Model/Quote/Discount.php

Lines changed: 60 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
use Magento\Framework\App\ObjectManager;
99
use Magento\Framework\Event\ManagerInterface;
10-
use Magento\Framework\Exception\NoSuchEntityException;
1110
use Magento\Framework\Pricing\PriceCurrencyInterface;
1211
use Magento\Quote\Api\Data\AddressInterface;
1312
use Magento\Quote\Api\Data\ShippingAssignmentInterface;
@@ -129,34 +128,71 @@ public function _resetState(): void
129128
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
130129
* @SuppressWarnings(PHPMD.NPathComplexity)
131130
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
132-
* @throws \Zend_Db_Select_Exception|NoSuchEntityException
133131
*/
134132
public function collect(
135133
Quote $quote,
136134
ShippingAssignmentInterface $shippingAssignment,
137135
Total $total
138136
) {
139137
parent::collect($quote, $shippingAssignment, $total);
140-
$this->addressDiscountAggregator = [];
141-
142-
$address = $this->getAddress($shippingAssignment, $quote);
143-
$itemsAggregate = $this->getShippingItems($shippingAssignment);
144-
$items = $this->extractQuoteItems($quote, $address);
145-
138+
$store = $this->storeManager->getStore($quote->getStoreId());
139+
/** @var Address $address */
140+
$address = $shippingAssignment->getShipping()->getAddress();
141+
if ($quote->currentPaymentWasSet()) {
142+
$address->setPaymentMethod($quote->getPayment()->getMethod());
143+
}
144+
$this->calculator->reset($address);
145+
$itemsAggregate = [];
146+
foreach ($shippingAssignment->getItems() as $item) {
147+
$itemId = $item->getId();
148+
$itemsAggregate[$itemId] = $item;
149+
}
150+
$items = [];
151+
foreach ($quote->getAllAddresses() as $quoteAddress) {
152+
foreach ($quoteAddress->getAllItems() as $item) {
153+
$items[] = $item;
154+
}
155+
}
146156
if (!$items || !$itemsAggregate) {
147157
return $this;
148158
}
149-
$store = $this->storeManager->getStore($quote->getStoreId());
150-
159+
$eventArgs = [
160+
'website_id' => $store->getWebsiteId(),
161+
'customer_group_id' => $quote->getCustomerGroupId(),
162+
'coupon_code' => $quote->getCouponCode(),
163+
];
164+
$address->setDiscountDescription([]);
165+
$address->getExtensionAttributes()->setDiscounts([]);
166+
$this->addressDiscountAggregator = [];
167+
$address->setCartFixedRules([]);
151168
$quote->setCartFixedRules([]);
169+
foreach ($items as $item) {
170+
$item->setAppliedRuleIds(null);
171+
if ($item->getExtensionAttributes()) {
172+
$item->getExtensionAttributes()->setDiscounts(null);
173+
}
174+
$item->setDiscountAmount(0);
175+
$item->setBaseDiscountAmount(0);
176+
$item->setDiscountPercent(0);
177+
if ($item->getChildren() && $item->isChildrenCalculated()) {
178+
foreach ($item->getChildren() as $child) {
179+
$child->setDiscountAmount(0);
180+
$child->setBaseDiscountAmount(0);
181+
$child->setDiscountPercent(0);
182+
}
183+
}
184+
$item->getAddress()->setBaseDiscountAmount(0);
185+
}
152186
$this->calculator->initFromQuote($quote);
153187
$this->calculator->initTotals($items, $address);
154-
188+
$items = $this->calculator->sortItemsByPriority($items, $address);
155189
$itemsToApplyRules = $items;
156-
190+
$rules = $this->calculator->getRules($address);
191+
$totalDiscount = [];
192+
$address->setBaseDiscountAmount(0);
157193
/** @var Rule $rule */
158-
foreach ($this->calculator->getRules($address) as $rule) {
159-
$totalDiscount = 0;
194+
foreach ($rules as $rule) {
195+
/** @var Item $item */
160196
foreach ($itemsToApplyRules as $key => $item) {
161197
if ($item->getNoDiscount() || !$this->calculator->canApplyDiscount($item) || $item->getParentItem()) {
162198
continue;
@@ -176,25 +212,24 @@ public function collect(
176212
break;
177213
}
178214

179-
$this->eventManager->dispatch(
180-
'sales_quote_address_discount_item',
181-
[
182-
'website_id' => $store->getWebsiteId(),
183-
'customer_group_id' => $quote->getCustomerGroupId(),
184-
'coupon_code' => $quote->getCouponCode(),
185-
'item' => $item
186-
]
187-
);
215+
$eventArgs['item'] = $item;
216+
$this->eventManager->dispatch('sales_quote_address_discount_item', $eventArgs);
188217

189218
$this->calculator->process($item, $rule);
190219
$appliedRuleIds = $item->getAppliedRuleIds() ? explode(',', $item->getAppliedRuleIds()) : [];
191220
if ($rule->getStopRulesProcessing() && in_array($rule->getId(), $appliedRuleIds)) {
192221
unset($itemsToApplyRules[$key]);
193222
}
194223

195-
$totalDiscount += $this->getAggregatedItemBaseDiscount($item);
224+
if ($item->getChildren() && $item->isChildrenCalculated()) {
225+
foreach ($item->getChildren() as $child) {
226+
$totalDiscount[$item->getId()] += $child->getBaseDiscountAmount();
227+
}
228+
} else {
229+
$totalDiscount[$item->getId()] = $item->getBaseDiscountAmount();
230+
}
196231
}
197-
$address->setBaseDiscountAmount($totalDiscount);
232+
$address->setBaseDiscountAmount(array_sum(array_values($totalDiscount)));
198233
}
199234
$this->calculator->initTotals($items, $address);
200235
foreach ($items as $item) {
@@ -242,104 +277,6 @@ protected function aggregateItemDiscount(
242277
return $this;
243278
}
244279

245-
/**
246-
* Get quote items
247-
*
248-
* @param Quote $quote
249-
* @param AddressInterface $address
250-
* @return Address\Item[]
251-
* @throws \Zend_Db_Select_Exception
252-
*/
253-
private function extractQuoteItems(Quote $quote, AddressInterface $address): array
254-
{
255-
$items = [];
256-
foreach ($quote->getAllAddresses() as $quoteAddress) {
257-
foreach ($quoteAddress->getAllItems() as $item) {
258-
$item->setAppliedRuleIds(null);
259-
if ($item->getExtensionAttributes()) {
260-
$item->getExtensionAttributes()->setDiscounts(null);
261-
}
262-
$item->setDiscountAmount(0);
263-
$item->setBaseDiscountAmount(0);
264-
$item->setDiscountPercent(0);
265-
if ($item->getChildren() && $item->isChildrenCalculated()) {
266-
foreach ($item->getChildren() as $child) {
267-
$child->setDiscountAmount(0);
268-
$child->setBaseDiscountAmount(0);
269-
$child->setDiscountPercent(0);
270-
}
271-
}
272-
$item->getAddress()->setBaseDiscountAmount(0);
273-
$items[] = $item;
274-
}
275-
}
276-
277-
if ($items) {
278-
$items = $this->calculator->sortItemsByPriority($items, $address);
279-
}
280-
281-
return $items;
282-
}
283-
284-
/**
285-
* Get shipping items
286-
*
287-
* @param ShippingAssignmentInterface $shippingAssignment
288-
* @return array
289-
*/
290-
private function getShippingItems(ShippingAssignmentInterface $shippingAssignment): array
291-
{
292-
$itemsAggregate = [];
293-
foreach ($shippingAssignment->getItems() as $item) {
294-
$itemId = $item->getId();
295-
$itemsAggregate[$itemId] = $item;
296-
}
297-
298-
return $itemsAggregate;
299-
}
300-
301-
/**
302-
* Prepare quote address
303-
*
304-
* @param ShippingAssignmentInterface $shippingAssignment
305-
* @param Quote $quote
306-
* @return AddressInterface
307-
*/
308-
private function getAddress(ShippingAssignmentInterface $shippingAssignment, Quote $quote): AddressInterface
309-
{
310-
$address = $shippingAssignment->getShipping()->getAddress();
311-
if ($quote->currentPaymentWasSet()) {
312-
$address->setPaymentMethod($quote->getPayment()->getMethod());
313-
}
314-
315-
$this->calculator->reset($address);
316-
$address->setDiscountDescription([]);
317-
$address->getExtensionAttributes()->setDiscounts([]);
318-
$address->setCartFixedRules([]);
319-
$address->setBaseDiscountAmount(0);
320-
return $address;
321-
}
322-
323-
/**
324-
* Calculate quote item base discount
325-
*
326-
* @param Item $item
327-
* @return float
328-
*/
329-
private function getAggregatedItemBaseDiscount(Item $item): float
330-
{
331-
$baseDiscount = 0;
332-
if ($item->getChildren() && $item->isChildrenCalculated()) {
333-
foreach ($item->getChildren() as $child) {
334-
$baseDiscount += $child->getBaseDiscountAmount();
335-
}
336-
} else {
337-
$baseDiscount = $item->getBaseDiscountAmount();
338-
}
339-
340-
return $baseDiscount;
341-
}
342-
343280
/**
344281
* Distribute discount at parent item to children items
345282
*

0 commit comments

Comments
 (0)