Skip to content

Commit ff5d733

Browse files
committed
Merge branch 'ACP2E-2646' of https://github.com/magento-l3/magento2ce into PR-01-26-2024
2 parents d62ea3e + b25d3d2 commit ff5d733

File tree

5 files changed

+164
-59
lines changed

5 files changed

+164
-59
lines changed

app/code/Magento/Rule/Model/Condition/AbstractCondition.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -905,6 +905,7 @@ protected function _compareValues($validatedValue, $value, $strict = true)
905905
public function validate(\Magento\Framework\Model\AbstractModel $model)
906906
{
907907
if (!$model->hasData($this->getAttribute())) {
908+
$model = clone $model;
908909
$model->load($model->getId());
909910
}
910911
$attributeValue = $model->getData($this->getAttribute());

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ public function collect(
181181
$child->setDiscountPercent(0);
182182
}
183183
}
184+
$item->getAddress()->setBaseDiscountAmount(0);
184185
}
185186
$this->calculator->initFromQuote($quote);
186187
$this->calculator->initTotals($items, $address);
@@ -193,9 +194,6 @@ public function collect(
193194
foreach ($rules as $rule) {
194195
/** @var Item $item */
195196
foreach ($itemsToApplyRules as $key => $item) {
196-
if ($quote->getIsMultiShipping() && $item->getAddress()->getId() !== $address->getId()) {
197-
continue;
198-
}
199197
if ($item->getNoDiscount() || !$this->calculator->canApplyDiscount($item) || $item->getParentItem()) {
200198
continue;
201199
}

app/code/Magento/SalesRule/Test/Unit/Model/Quote/DiscountTest.php

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,9 @@ function ($argument) {
130130

131131
$this->addressMock = $this->getMockBuilder(Address::class)
132132
->addMethods(['getShippingAmount'])
133-
->onlyMethods(['getQuote', 'getAllItems', 'getExtensionAttributes', 'getCustomAttributesCodes'])
133+
->onlyMethods(
134+
['getQuote','getAllItems','getExtensionAttributes','getCustomAttributesCodes','setBaseDiscountAmount']
135+
)
134136
->disableOriginalConstructor()
135137
->getMock();
136138
$addressExtension = $this->getMockBuilder(
@@ -178,7 +180,7 @@ public function testCollectItemNoDiscount()
178180
{
179181
$itemNoDiscount = $this->getMockBuilder(Item::class)
180182
->addMethods(['getNoDiscount'])
181-
->onlyMethods(['getExtensionAttributes', 'getParentItem', 'getId'])
183+
->onlyMethods(['getExtensionAttributes', 'getParentItem', 'getId', 'getAddress'])
182184
->disableOriginalConstructor()
183185
->getMock();
184186
$itemExtension = $this->getMockBuilder(
@@ -191,6 +193,7 @@ public function testCollectItemNoDiscount()
191193
$itemNoDiscount->expects($this->any())->method('getExtensionAttributes')->willReturn($itemExtension);
192194
$itemNoDiscount->expects($this->any())->method('getId')->willReturn(1);
193195
$itemNoDiscount->expects($this->once())->method('getNoDiscount')->willReturn(true);
196+
$itemNoDiscount->expects($this->once())->method('getAddress')->willReturn($this->addressMock);
194197
$this->validatorMock->expects($this->once())->method('sortItemsByPriority')
195198
->with([$itemNoDiscount], $this->addressMock)
196199
->willReturnArgument(0);
@@ -213,6 +216,7 @@ public function testCollectItemNoDiscount()
213216
$this->addressMock->expects($this->any())->method('getQuote')->willReturn($quoteMock);
214217
$this->shippingAssignmentMock->expects($this->any())->method('getItems')->willReturn([$itemNoDiscount]);
215218
$this->addressMock->expects($this->any())->method('getShippingAmount')->willReturn(true);
219+
$this->addressMock->expects($this->atLeastOnce())->method('setBaseDiscountAmount')->with(0)->willReturnSelf();
216220

217221
$totalMock = $this->getMockBuilder(Total::class)
218222
->addMethods(
@@ -234,13 +238,14 @@ public function testCollectItemHasParent()
234238
{
235239
$itemWithParentId = $this->getMockBuilder(Item::class)
236240
->addMethods(['getNoDiscount'])
237-
->onlyMethods(['getParentItem', 'getId', 'getExtensionAttributes'])
241+
->onlyMethods(['getParentItem', 'getId', 'getExtensionAttributes', 'getAddress'])
238242
->disableOriginalConstructor()
239243
->getMock();
240244
$itemWithParentId->expects($this->once())->method('getNoDiscount')->willReturn(false);
241245
$itemWithParentId->expects($this->any())->method('getId')->willReturn(1);
242246
$itemWithParentId->expects($this->any())->method('getParentItem')->willReturn(true);
243247
$itemWithParentId->expects($this->any())->method('getExtensionAttributes')->willReturn(false);
248+
$itemWithParentId->expects($this->once())->method('getAddress')->willReturn($this->addressMock);
244249

245250
$this->validatorMock->expects($this->any())->method('canApplyDiscount')->willReturn(true);
246251
$this->validatorMock->expects($this->any())->method('sortItemsByPriority')
@@ -267,6 +272,7 @@ public function testCollectItemHasParent()
267272

268273
$this->addressMock->expects($this->any())->method('getQuote')->willReturn($quoteMock);
269274
$this->addressMock->expects($this->any())->method('getShippingAmount')->willReturn(true);
275+
$this->addressMock->expects($this->atLeastOnce())->method('setBaseDiscountAmount')->with(0)->willReturnSelf();
270276
$this->shippingAssignmentMock->expects($this->any())->method('getItems')->willReturn([$itemWithParentId]);
271277
$totalMock = $this->getMockBuilder(Total::class)
272278
->addMethods(
@@ -295,6 +301,7 @@ public function testCollectItemHasNoChildren()
295301
'getChildren',
296302
'getExtensionAttributes',
297303
'getId',
304+
'getAddress',
298305
]
299306
)->addMethods(
300307
[
@@ -318,6 +325,7 @@ public function testCollectItemHasNoChildren()
318325
$itemWithChildren->expects($this->any())->method('getParentItem')->willReturn(false);
319326
$itemWithChildren->expects($this->once())->method('getHasChildren')->willReturn(false);
320327
$itemWithChildren->expects($this->any())->method('getId')->willReturn(2);
328+
$itemWithChildren->expects($this->once())->method('getAddress')->willReturn($this->addressMock);
321329

322330
$this->validatorMock->expects($this->any())->method('canApplyDiscount')->willReturn(true);
323331
$this->validatorMock->expects($this->once())->method('sortItemsByPriority')
@@ -343,6 +351,7 @@ public function testCollectItemHasNoChildren()
343351
$this->addressMock->expects($this->any())->method('getAllItems')->willReturn([$itemWithChildren]);
344352
$this->addressMock->expects($this->any())->method('getQuote')->willReturn($quoteMock);
345353
$this->addressMock->expects($this->any())->method('getShippingAmount')->willReturn(true);
354+
$this->addressMock->expects($this->atLeastOnce())->method('setBaseDiscountAmount')->with(0)->willReturnSelf();
346355
$this->shippingAssignmentMock->expects($this->any())->method('getItems')->willReturn([$itemWithChildren]);
347356

348357
$totalMock = $this->getMockBuilder(Total::class)
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
<?php
2+
/************************************************************************
3+
*
4+
* Copyright 2024 Adobe
5+
* All Rights Reserved.
6+
*
7+
* NOTICE: All information contained herein is, and remains
8+
* the property of Adobe and its suppliers, if any. The intellectual
9+
* and technical concepts contained herein are proprietary to Adobe
10+
* and its suppliers and are protected by all applicable intellectual
11+
* property laws, including trade secret and copyright laws.
12+
* Dissemination of this information or reproduction of this material
13+
* is strictly forbidden unless prior written permission is obtained
14+
* from Adobe.
15+
* **********************************************************************
16+
*/
17+
declare(strict_types=1);
18+
19+
namespace Magento\SalesRule\Model\Rule\Action\Discount;
20+
21+
use Magento\Checkout\Model\Session as CheckoutSession;
22+
use Magento\Framework\Api\SearchCriteriaBuilder;
23+
use Magento\Multishipping\Model\Checkout\Type\Multishipping;
24+
use Magento\Quote\Api\CartRepositoryInterface;
25+
use Magento\Quote\Model\Quote;
26+
use Magento\Sales\Api\OrderRepositoryInterface;
27+
use Magento\Sales\Model\Order;
28+
use Magento\SalesRule\Model\Rule;
29+
use Magento\SalesRule\Test\Fixture\Rule as RuleFixture;
30+
use Magento\TestFramework\Fixture\AppArea;
31+
use Magento\TestFramework\Fixture\DataFixture;
32+
use Magento\TestFramework\Helper\Bootstrap;
33+
use PHPUnit\Framework\TestCase;
34+
35+
#[
36+
AppArea('frontend'),
37+
]
38+
class ByPercentTest extends TestCase
39+
{
40+
/**
41+
* @var SearchCriteriaBuilder
42+
*/
43+
private $searchCriteriaBuilder;
44+
45+
/**
46+
* @var CartRepositoryInterface
47+
*/
48+
private $quoteRepository;
49+
50+
/**
51+
* @var OrderRepositoryInterface
52+
*/
53+
private $orderRepository;
54+
55+
protected function setUp(): void
56+
{
57+
$this->searchCriteriaBuilder = Bootstrap::getObjectManager()->get(SearchCriteriaBuilder::class);
58+
$this->quoteRepository = Bootstrap::getObjectManager()->get(CartRepositoryInterface::class);
59+
$this->orderRepository = Bootstrap::getObjectManager()->get(OrderRepositoryInterface::class);
60+
}
61+
62+
#[
63+
DataFixture(
64+
RuleFixture::class,
65+
['simple_action' => Rule::BY_PERCENT_ACTION, 'discount_amount' => 10, 'coupon_code' => 'COUPON10']
66+
),
67+
DataFixture('Magento/Multishipping/Fixtures/quote_with_split_items.php'),
68+
]
69+
public function testMultishipping(): void
70+
{
71+
$quote = $this->getQuote('multishipping_quote_id');
72+
$quote->setCouponCode('COUPON10');
73+
$quote->collectTotals();
74+
$this->quoteRepository->save($quote);
75+
76+
$session = Bootstrap::getObjectManager()->get(CheckoutSession::class);
77+
$session->replaceQuote($quote);
78+
$multishipping = Bootstrap::getObjectManager()->get(Multishipping::class);
79+
$multishipping->createOrders();
80+
$orderList = array_values($this->getOrderList((int) $quote->getId()));
81+
self::assertCount(3, $orderList);
82+
83+
foreach ($orderList as $order) {
84+
self::assertNotEmpty($order->getAppliedRuleIds());
85+
$discountAmount = $order->getSubtotal() * 0.1;
86+
self::assertEquals($discountAmount * -1, $order->getDiscountAmount());
87+
$grandTotal = $order->getSubtotal() + $order->getShippingAmount() - $discountAmount;
88+
self::assertEquals($grandTotal, $order->getGrandTotal());
89+
$orderItem = array_values($order->getItems())[0];
90+
self::assertNotEmpty($orderItem->getAppliedRuleIds());
91+
self::assertEquals($discountAmount, $orderItem->getDiscountAmount());
92+
}
93+
}
94+
95+
/**
96+
* Load cart from fixture.
97+
*
98+
* @param string $reservedOrderId
99+
* @return Quote
100+
*/
101+
private function getQuote(string $reservedOrderId): Quote
102+
{
103+
$searchCriteria = $this->searchCriteriaBuilder->addFilter('reserved_order_id', $reservedOrderId)
104+
->create();
105+
$quoteList = $this->quoteRepository->getList($searchCriteria);
106+
107+
return array_values($quoteList->getItems())[0];
108+
}
109+
110+
/**
111+
* Get list of orders by quote id.
112+
*
113+
* @param int $quoteId
114+
* @return Order[]
115+
*/
116+
private function getOrderList(int $quoteId): array
117+
{
118+
$searchCriteria = $this->searchCriteriaBuilder->addFilter('quote_id', $quoteId)->create();
119+
$orderList = $this->orderRepository->getList($searchCriteria);
120+
121+
return $orderList->getItems();
122+
}
123+
}

dev/tests/integration/testsuite/Magento/SalesRule/Model/Rule/Action/Discount/CartFixedTest.php

Lines changed: 27 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -362,78 +362,52 @@ public function testMultishipping(
362362
$orderSender = $this->getMockBuilder(OrderSender::class)
363363
->disableOriginalConstructor()
364364
->getMock();
365-
366-
$model = $this->objectManager->create(
367-
Multishipping::class,
368-
['orderSender' => $orderSender]
369-
);
365+
$model = $this->objectManager->create(Multishipping::class, ['orderSender' => $orderSender]);
370366
$model->createOrders();
371367
$orderList = $this->getOrderList((int)$quote->getId());
372368
$this->assertCount(3, $orderList);
369+
373370
/**
374371
* The order with $10 simple product
375372
* @var Order $firstOrder
376373
*/
377374
$firstOrder = array_shift($orderList);
375+
$this->assertNotEmpty($firstOrder->getAppliedRuleIds());
376+
$this->assertEquals($firstOrderTotals['subtotal'], $firstOrder->getSubtotal());
377+
$this->assertEquals($firstOrderTotals['discount_amount'], $firstOrder->getDiscountAmount());
378+
$this->assertEquals($firstOrderTotals['shipping_amount'], $firstOrder->getShippingAmount());
379+
$this->assertEquals($firstOrderTotals['grand_total'], $firstOrder->getGrandTotal());
380+
$firstOrderItem = array_values($firstOrder->getItems())[0];
381+
$this->assertNotEmpty($firstOrderItem->getAppliedRuleIds());
382+
$this->assertEquals($firstOrderTotals['discount_amount'] * -1, $firstOrderItem->getDiscountAmount());
378383

379-
$this->assertEquals(
380-
$firstOrderTotals['subtotal'],
381-
$firstOrder->getSubtotal()
382-
);
383-
$this->assertEquals(
384-
$firstOrderTotals['discount_amount'],
385-
$firstOrder->getDiscountAmount()
386-
);
387-
$this->assertEquals(
388-
$firstOrderTotals['shipping_amount'],
389-
$firstOrder->getShippingAmount()
390-
);
391-
$this->assertEquals(
392-
$firstOrderTotals['grand_total'],
393-
$firstOrder->getGrandTotal()
394-
);
395384
/**
396385
* The order with $20 simple product
397386
* @var Order $secondOrder
398387
*/
399388
$secondOrder = array_shift($orderList);
400-
$this->assertEquals(
401-
$secondOrderTotals['subtotal'],
402-
$secondOrder->getSubtotal()
403-
);
404-
$this->assertEquals(
405-
$secondOrderTotals['discount_amount'],
406-
$secondOrder->getDiscountAmount()
407-
);
408-
$this->assertEquals(
409-
$secondOrderTotals['shipping_amount'],
410-
$secondOrder->getShippingAmount()
411-
);
412-
$this->assertEquals(
413-
$secondOrderTotals['grand_total'],
414-
$secondOrder->getGrandTotal()
415-
);
389+
$this->assertNotEmpty($secondOrder->getAppliedRuleIds());
390+
$this->assertEquals($secondOrderTotals['subtotal'], $secondOrder->getSubtotal());
391+
$this->assertEquals($secondOrderTotals['discount_amount'], $secondOrder->getDiscountAmount());
392+
$this->assertEquals($secondOrderTotals['shipping_amount'], $secondOrder->getShippingAmount());
393+
$this->assertEquals($secondOrderTotals['grand_total'], $secondOrder->getGrandTotal());
394+
$secondOrderItem = array_values($secondOrder->getItems())[0];
395+
$this->assertNotEmpty($secondOrderItem->getAppliedRuleIds());
396+
$this->assertEquals($secondOrderTotals['discount_amount'] * -1, $secondOrderItem->getDiscountAmount());
397+
416398
/**
417399
* The order with $5 virtual product and billing address as shipping
418400
* @var Order $thirdOrder
419401
*/
420402
$thirdOrder = array_shift($orderList);
421-
$this->assertEquals(
422-
$thirdOrderTotals['subtotal'],
423-
$thirdOrder->getSubtotal()
424-
);
425-
$this->assertEquals(
426-
$thirdOrderTotals['discount_amount'],
427-
$thirdOrder->getDiscountAmount()
428-
);
429-
$this->assertEquals(
430-
$thirdOrderTotals['shipping_amount'],
431-
$thirdOrder->getShippingAmount()
432-
);
433-
$this->assertEquals(
434-
$thirdOrderTotals['grand_total'],
435-
$thirdOrder->getGrandTotal()
436-
);
403+
$this->assertNotEmpty($thirdOrder->getAppliedRuleIds());
404+
$this->assertEquals($thirdOrderTotals['subtotal'], $thirdOrder->getSubtotal());
405+
$this->assertEquals($thirdOrderTotals['discount_amount'], $thirdOrder->getDiscountAmount());
406+
$this->assertEquals($thirdOrderTotals['shipping_amount'], $thirdOrder->getShippingAmount());
407+
$this->assertEquals($thirdOrderTotals['grand_total'], $thirdOrder->getGrandTotal());
408+
$thirdOrderItem = array_values($thirdOrder->getItems())[0];
409+
$this->assertNotEmpty($thirdOrderItem->getAppliedRuleIds());
410+
$this->assertEquals($thirdOrderTotals['discount_amount'] * -1, $thirdOrderItem->getDiscountAmount());
437411
}
438412

439413
/**

0 commit comments

Comments
 (0)