Skip to content

Commit c3c144b

Browse files
committed
ACP2E-3955: [Mainline] Price of product in cart affected by catalog price rule doesn't change when rule is updated
- Initial solution
1 parent fab20b0 commit c3c144b

File tree

4 files changed

+166
-10
lines changed

4 files changed

+166
-10
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\CatalogRule\Plugin\Model\Indexer;
9+
10+
use Magento\Catalog\Model\Indexer\Product\Price;
11+
use Magento\Quote\Model\ResourceModel\Quote as QuoteResourceModel;
12+
13+
/**
14+
* Recollect quote on product ids after rule change.
15+
*/
16+
class RecollectQuoteAfterRuleChange
17+
{
18+
/**
19+
* @param QuoteResourceModel $quoteResourceModel
20+
*/
21+
public function __construct(
22+
private readonly QuoteResourceModel $quoteResourceModel
23+
) {
24+
}
25+
26+
/**
27+
* Recollect quote on product ids after rule change.
28+
*
29+
* @param Price $subject
30+
* @param $result
31+
* @param array $ids
32+
* @return void
33+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
34+
*/
35+
public function afterExecute(Price $subject, $result, array $ids)
36+
{
37+
$this->quoteResourceModel->markQuotesRecollect($ids);
38+
}
39+
}

app/code/Magento/CatalogRule/composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
"magento/module-eav": "*",
1414
"magento/module-rule": "*",
1515
"magento/module-store": "*",
16-
"magento/module-ui": "*"
16+
"magento/module-ui": "*",
17+
"magento/module-quote": "*"
1718
},
1819
"suggest": {
1920
"magento/module-import-export": "*",

app/code/Magento/CatalogRule/etc/di.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,4 +164,7 @@
164164
<argument name="customConditionProvider" xsi:type="object">CatalogRuleCustomConditionProvider</argument>
165165
</arguments>
166166
</type>
167+
<type name="Magento\Catalog\Model\Indexer\Product\Price">
168+
<plugin name="recollect_quote_after_rule_change" type="Magento\CatalogRule\Plugin\Model\Indexer\RecollectQuoteAfterRuleChange"/>
169+
</type>
167170
</config>

dev/tests/integration/testsuite/Magento/CatalogRule/Model/RuleTest.php

Lines changed: 122 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,68 @@
11
<?php
22
/**
3-
* Copyright © Magento, Inc. All rights reserved.
4-
* See COPYING.txt for license details.
3+
* Copyright 2012 Adobe
4+
* All Rights Reserved.
55
*/
66
namespace Magento\CatalogRule\Model;
77

8-
class RuleTest extends \PHPUnit\Framework\TestCase
8+
use Exception;
9+
use Magento\Catalog\Model\Indexer\Product\Price\Processor as ProductPriceIndexerProcessor;
10+
use Magento\Catalog\Model\Product;
11+
use Magento\Catalog\Test\Fixture\Product as ProductFixture;
12+
use Magento\CatalogRule\Test\Fixture\Rule as CatalogRuleFixture;
13+
use Magento\Checkout\Model\CartFactory;
14+
use Magento\Customer\Test\Fixture\Customer as CustomerFixture;
15+
use Magento\Framework\ObjectManagerInterface;
16+
use Magento\Indexer\Cron\UpdateMview;
17+
use Magento\Indexer\Test\Fixture\UpdateMview as UpdateMviewCron;
18+
use Magento\Indexer\Test\Fixture\ScheduleMode;
19+
use Magento\Quote\Api\CartRepositoryInterface;
20+
use Magento\Quote\Test\Fixture\AddProductToCart as AddProductToCartFixture;
21+
use Magento\Quote\Test\Fixture\CustomerCart as CustomerCartFixture;
22+
use Magento\CatalogRule\Model\Indexer\Rule\RuleProductProcessor;
23+
use Magento\TestFramework\Fixture\DataFixture;
24+
use Magento\TestFramework\Fixture\DataFixtureStorage;
25+
use Magento\TestFramework\Fixture\DataFixtureStorageManager;
26+
use Magento\CatalogRule\Api\CatalogRuleRepositoryInterface;
27+
use Magento\TestFramework\Fixture\DbIsolation;
28+
use Magento\TestFramework\Helper\Bootstrap;
29+
use PHPUnit\Framework\TestCase;
30+
31+
class RuleTest extends TestCase
932
{
33+
/** @var ObjectManagerInterface */
34+
private $objectManager;
35+
1036
/**
11-
* @var \Magento\CatalogRule\Model\Rule
37+
* @var CartRepositoryInterface
38+
*/
39+
private $cartRepository;
40+
41+
/**
42+
* @var CatalogRuleRepositoryInterface
43+
*/
44+
private $catalogRuleRepository;
45+
46+
/**
47+
* @var Rule
1248
*/
1349
protected $_object;
1450

51+
/**
52+
* @var DataFixtureStorage
53+
*/
54+
private $fixtures;
55+
1556
/**
1657
* Sets up the fixture, for example, opens a network connection.
1758
* This method is called before a test is executed.
1859
*/
1960
protected function setUp(): void
2061
{
62+
$this->objectManager = Bootstrap::getObjectManager();
63+
$this->fixtures = $this->objectManager->get(DataFixtureStorageManager::class)->getStorage();
64+
$this->cartRepository = $this->objectManager->get(CartRepositoryInterface::class);
65+
$this->catalogRuleRepository = $this->objectManager->get(CatalogRuleRepositoryInterface::class);
2166
$resourceMock = $this->createPartialMock(
2267
\Magento\CatalogRule\Model\ResourceModel\Rule::class,
2368
['getIdFieldName', 'getRulesFromProduct']
@@ -31,20 +76,20 @@ protected function setUp(): void
3176
$this->_getCatalogRulesFixtures()
3277
);
3378

34-
$this->_object = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
35-
\Magento\CatalogRule\Model\Rule::class,
79+
$this->_object = $this->objectManager ->create(
80+
Rule::class,
3681
['ruleResourceModel' => $resourceMock]
3782
);
3883
}
3984

4085
/**
4186
* @magentoAppIsolation enabled
42-
* @covers \Magento\CatalogRule\Model\Rule::calcProductPriceRule
87+
* @covers Rule::calcProductPriceRule
4388
*/
4489
public function testCalcProductPriceRule()
4590
{
46-
$product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
47-
\Magento\Catalog\Model\Product::class
91+
$product = $this->objectManager->create(
92+
Product::class
4893
);
4994
$this->assertEquals($this->_object->calcProductPriceRule($product, 100), 45);
5095
$product->setParentId(true);
@@ -71,4 +116,72 @@ protected function _getCatalogRulesFixtures()
71116
]
72117
];
73118
}
119+
120+
/**
121+
* Test case where changing in catalog rule price updates the quote price.
122+
*
123+
* @throws Exception
124+
*/
125+
#[
126+
DbIsolation(false),
127+
DataFixture(ProductFixture::class, ['type_id' => 'simple', 'price' => 100], as: 'product'),
128+
DataFixture(
129+
CatalogRuleFixture::class,
130+
[
131+
'name' => '50% Discount Rule',
132+
'simple_action' => 'by_percent',
133+
'discount_amount' => 50,
134+
'conditions' => [],
135+
'actions' => [],
136+
'website_ids' => [1],
137+
'customer_group_ids' => [0, 1],
138+
'is_active' => 1
139+
],
140+
as: 'catalog_rule'
141+
),
142+
DataFixture(UpdateMviewCron::class, as: 'updateMviewCron'),
143+
DataFixture(CustomerFixture::class, as: 'customer'),
144+
DataFixture(CustomerCartFixture::class, ['customer_id' => '$customer.id$'], as: 'cart'),
145+
DataFixture(
146+
AddProductToCartFixture::class,
147+
['cart_id' => '$cart.id$', 'product_id' => '$product.id$', 'qty' => 1]
148+
149+
),
150+
DataFixture(ScheduleMode::class, ['indexer' => ProductPriceIndexerProcessor::INDEXER_ID]),
151+
DataFixture(ScheduleMode::class, ['indexer' => RuleProductProcessor::INDEXER_ID])
152+
]
153+
public function testChangeInCatalogPriceRuleUpdatesTheQuote()
154+
{
155+
$catalogRule = $this->fixtures->get('catalog_rule');
156+
$product = $this->fixtures->get('product');
157+
$cart = $this->fixtures->get('cart');
158+
$cartDetails = $this->objectManager->create(CartRepositoryInterface::class)
159+
->get($cart->getId());
160+
$items = $cartDetails->getAllItems();
161+
162+
//verify that the product is added to the cart with the correct price
163+
$this->assertCount(1, $items);
164+
$this->assertEquals($items[0]->getProduct()->getId(), $product->getId());
165+
$this->assertEquals((float) $items[0]->getPrice(), 50.00);
166+
167+
$catalogRuleDetails = $this->objectManager->create(CatalogRuleRepositoryInterface::class)
168+
->get($catalogRule->getId());
169+
$catalogRuleDetails->setDiscountAmount(40);
170+
$catalogRuleDetails->setSimpleAction('by_percent');
171+
$this->catalogRuleRepository->save($catalogRuleDetails);
172+
173+
/** @var $mViewCron UpdateMview */
174+
$mViewCron = $this->objectManager->create(UpdateMview::class);
175+
$mViewCron->execute();
176+
177+
$updatedCartRepo = $this->objectManager->create(CartRepositoryInterface::class);
178+
$updatedCartDetails = $updatedCartRepo->get($cart->getId());
179+
180+
$updatedCartDetails->collectTotals()->save();
181+
$updatedItems = $updatedCartDetails->getAllItems();
182+
//verify that the cart item price is updated after the catalog rule change
183+
$this->assertCount(1, $updatedItems);
184+
$this->assertEquals($updatedItems[0]->getProduct()->getId(), $product->getId());
185+
$this->assertEquals((float) $updatedItems[0]->getPrice(), 50.00);
186+
}
74187
}

0 commit comments

Comments
 (0)