From e83b225a16505505e765af6af48bf4d84688577b Mon Sep 17 00:00:00 2001 From: Senthilkumar Muppidathi Date: Tue, 28 Oct 2025 10:48:19 +0530 Subject: [PATCH 01/12] #40226 - Conditionally add salesrule attributes to eav query for FE/REST Post requests and graphql Mutations --- .../Model/Plugin/FrontController.php | 34 +++++++ .../SalesRule/Model/Plugin/QueryParser.php | 44 +++++++++ .../Plugin/QuoteConfigProductAttributes.php | 43 +++++++- .../Model/Plugin/RequestTypeRegistry.php | 41 ++++++++ .../QuoteConfigProductAttributesTest.php | 98 +++++++++++++++++-- .../Model/Plugin/RequestTypeRegistryTest.php | 56 +++++++++++ .../Magento/SalesRule/etc/frontend/di.xml | 5 + app/code/Magento/SalesRule/etc/graphql/di.xml | 10 ++ .../Magento/SalesRule/etc/webapi_rest/di.xml | 9 ++ 9 files changed, 326 insertions(+), 14 deletions(-) create mode 100644 app/code/Magento/SalesRule/Model/Plugin/FrontController.php create mode 100644 app/code/Magento/SalesRule/Model/Plugin/QueryParser.php create mode 100644 app/code/Magento/SalesRule/Model/Plugin/RequestTypeRegistry.php create mode 100644 app/code/Magento/SalesRule/Test/Unit/Model/Plugin/RequestTypeRegistryTest.php create mode 100644 app/code/Magento/SalesRule/etc/graphql/di.xml create mode 100644 app/code/Magento/SalesRule/etc/webapi_rest/di.xml diff --git a/app/code/Magento/SalesRule/Model/Plugin/FrontController.php b/app/code/Magento/SalesRule/Model/Plugin/FrontController.php new file mode 100644 index 0000000000000..6b7f3c3efe478 --- /dev/null +++ b/app/code/Magento/SalesRule/Model/Plugin/FrontController.php @@ -0,0 +1,34 @@ +getMethod()); + $isReadOnly = ($method === 'GET'); + + // Set flag in TotalCollectionState + $this->requestTypeRegistry->setIsGetRequestOrQuery($isReadOnly); + + return $request; + } +} diff --git a/app/code/Magento/SalesRule/Model/Plugin/QueryParser.php b/app/code/Magento/SalesRule/Model/Plugin/QueryParser.php new file mode 100644 index 0000000000000..07a6f71ed1efe --- /dev/null +++ b/app/code/Magento/SalesRule/Model/Plugin/QueryParser.php @@ -0,0 +1,44 @@ +definitions as $definition) { + if ($definition instanceof \GraphQL\Language\AST\OperationDefinitionNode) { + $operation = $definition; + break; + } + } + + if ($operation) { + $isOperationTypeQuery = ($operation->operation === 'query'); + $this->requestTypeRegistry->setIsGetRequestOrQuery($isOperationTypeQuery); + } + + return $documentNode; + } +} diff --git a/app/code/Magento/SalesRule/Model/Plugin/QuoteConfigProductAttributes.php b/app/code/Magento/SalesRule/Model/Plugin/QuoteConfigProductAttributes.php index 61755966ad0f1..e9e9a35cde51f 100644 --- a/app/code/Magento/SalesRule/Model/Plugin/QuoteConfigProductAttributes.php +++ b/app/code/Magento/SalesRule/Model/Plugin/QuoteConfigProductAttributes.php @@ -6,6 +6,8 @@ namespace Magento\SalesRule\Model\Plugin; +use Magento\Framework\App\CacheInterface; +use Magento\Framework\Serialize\SerializerInterface; use Magento\Quote\Model\Quote\Config; use Magento\SalesRule\Model\ResourceModel\Rule as RuleResource; @@ -21,11 +23,28 @@ class QuoteConfigProductAttributes */ private $activeAttributeCodes; + /** + * Cache key for active salesrule attributes + */ + private const CACHE_KEY = 'salesrule_active_product_attributes'; + + /** + * Cache tag for salesrule attributes + */ + private const CACHE_TAG = 'salesrule'; + /** * @param RuleResource $ruleResource + * @param RequestTypeRegistry $requestTypeRegistry + * @param CacheInterface $cache + * @param SerializerInterface $serializer */ - public function __construct(RuleResource $ruleResource) - { + public function __construct( + RuleResource $ruleResource, + private RequestTypeRegistry $requestTypeRegistry, + private CacheInterface $cache, + private SerializerInterface $serializer + ) { $this->ruleResource = $ruleResource; } @@ -40,8 +59,24 @@ public function __construct(RuleResource $ruleResource) */ public function afterGetProductAttributes(Config $subject, array $attributeKeys): array { - if ($this->activeAttributeCodes === null) { - $this->activeAttributeCodes = array_column($this->ruleResource->getActiveAttributes(), 'attribute_code'); + if ($this->requestTypeRegistry->isGetRequestOrQuery()) { + return $attributeKeys; + } + + $cachedData = $this->cache->load(self::CACHE_KEY); + + if ($cachedData !== false) { + $this->activeAttributeCodes = $this->serializer->unserialize($cachedData); + } else { + $this->activeAttributeCodes = array_column( + $this->ruleResource->getActiveAttributes(), + 'attribute_code' + ); + $this->cache->save( + $this->serializer->serialize($this->activeAttributeCodes), + self::CACHE_KEY, + [self::CACHE_TAG] + ); } return array_merge($attributeKeys, $this->activeAttributeCodes); diff --git a/app/code/Magento/SalesRule/Model/Plugin/RequestTypeRegistry.php b/app/code/Magento/SalesRule/Model/Plugin/RequestTypeRegistry.php new file mode 100644 index 0000000000000..e6c85ffe06f9b --- /dev/null +++ b/app/code/Magento/SalesRule/Model/Plugin/RequestTypeRegistry.php @@ -0,0 +1,41 @@ +isGetRequestOrQuery = $state; + } + + /** + * Check if request is a get or query + * + * @return bool + */ + public function isGetRequestOrQuery(): bool + { + return $this->isGetRequestOrQuery; + } +} diff --git a/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/QuoteConfigProductAttributesTest.php b/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/QuoteConfigProductAttributesTest.php index f8f000528db56..4d7affa320f8f 100644 --- a/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/QuoteConfigProductAttributesTest.php +++ b/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/QuoteConfigProductAttributesTest.php @@ -7,9 +7,11 @@ namespace Magento\SalesRule\Test\Unit\Model\Plugin; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Framework\App\CacheInterface; +use Magento\Framework\Serialize\SerializerInterface; use Magento\Quote\Model\Quote\Config; use Magento\SalesRule\Model\Plugin\QuoteConfigProductAttributes; +use Magento\SalesRule\Model\Plugin\RequestTypeRegistry; use Magento\SalesRule\Model\ResourceModel\Rule; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -26,24 +28,82 @@ class QuoteConfigProductAttributesTest extends TestCase */ protected $ruleResource; + /** + * @var RequestTypeRegistry|MockObject + */ + protected $requestTypeRegistry; + + /** + * @var CacheInterface|MockObject + */ + protected $cache; + + /** + * @var SerializerInterface|MockObject + */ + protected $serializer; + + /** + * @var Config|MockObject + */ + protected $subject; + protected function setUp(): void { - $objectManager = new ObjectManager($this); $this->ruleResource = $this->createMock(Rule::class); + $this->requestTypeRegistry = $this->createMock(RequestTypeRegistry::class); + $this->cache = $this->createMock(CacheInterface::class); + $this->serializer = $this->createMock(SerializerInterface::class); + $this->subject = $this->createMock(Config::class); - $this->plugin = $objectManager->getObject( - QuoteConfigProductAttributes::class, - [ - 'ruleResource' => $this->ruleResource - ] + $this->plugin = new QuoteConfigProductAttributes( + $this->ruleResource, + $this->requestTypeRegistry, + $this->cache, + $this->serializer ); } - public function testAfterGetProductAttributes() + public function testAfterGetProductAttributesWithCache() + { + $attributeCode = 'code of the attribute'; + $expected = [0 => $attributeCode]; + $serializedData = '["' . $attributeCode . '"]'; + + $this->requestTypeRegistry->expects($this->once()) + ->method('isGetRequestOrQuery') + ->willReturn(false); + + $this->cache->expects($this->once()) + ->method('load') + ->with('salesrule_active_product_attributes') + ->willReturn($serializedData); + + $this->serializer->expects($this->once()) + ->method('unserialize') + ->with($serializedData) + ->willReturn([$attributeCode]); + + $this->ruleResource->expects($this->never()) + ->method('getActiveAttributes'); + + $this->assertEquals($expected, $this->plugin->afterGetProductAttributes($this->subject, [])); + } + + public function testAfterGetProductAttributesWithoutCache() { - $subject = $this->createMock(Config::class); $attributeCode = 'code of the attribute'; $expected = [0 => $attributeCode]; + $serializedData = '["' . $attributeCode . '"]'; + + $this->requestTypeRegistry->expects($this->once()) + ->method('isGetRequestOrQuery') + ->willReturn(false); + + $this->cache->expects($this->once()) + ->method('load') + ->with('salesrule_active_product_attributes') + ->willReturn(false); $this->ruleResource->expects($this->once()) ->method('getActiveAttributes') @@ -53,6 +113,24 @@ public function testAfterGetProductAttributes() ] ); - $this->assertEquals($expected, $this->plugin->afterGetProductAttributes($subject, [])); + $this->serializer->expects($this->once()) + ->method('serialize') + ->with([$attributeCode]) + ->willReturn($serializedData); + + $this->cache->expects($this->once()) + ->method('save') + ->with($serializedData, 'salesrule_active_product_attributes', ['salesrule']); + + $this->assertEquals($expected, $this->plugin->afterGetProductAttributes($this->subject, [])); + } + + public function testAfterGetProductAttributesRequestTypePostOrMutation() + { + $this->requestTypeRegistry->expects($this->once()) + ->method('isGetRequestOrQuery') + ->willReturn(true); + + $this->assertEquals([], $this->plugin->afterGetProductAttributes($this->subject, [])); } } diff --git a/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/RequestTypeRegistryTest.php b/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/RequestTypeRegistryTest.php new file mode 100644 index 0000000000000..5ac2ca3d08771 --- /dev/null +++ b/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/RequestTypeRegistryTest.php @@ -0,0 +1,56 @@ +state = new RequestTypeRegistry(); + } + + public function testDefaultStateIsFalse() + { + $this->assertFalse($this->state->isGetRequestOrQuery()); + } + + public function testIsGetRequestOrQueryTrue() + { + $this->state->setIsGetRequestOrQuery(true); + $this->assertTrue($this->state->isGetRequestOrQuery()); + } + + public function testIsGetRequestOrQueryFalse() + { + $this->state->setIsGetRequestOrQuery(true); + $this->state->setIsGetRequestOrQuery(false); + $this->assertFalse($this->state->isGetRequestOrQuery()); + } + + public function testMultipleToggle() + { + $this->assertFalse($this->state->isGetRequestOrQuery()); + + $this->state->setIsGetRequestOrQuery(true); + $this->assertTrue($this->state->isGetRequestOrQuery()); + + $this->state->setIsGetRequestOrQuery(false); + $this->assertFalse($this->state->isGetRequestOrQuery()); + + $this->state->setIsGetRequestOrQuery(true); + $this->assertTrue($this->state->isGetRequestOrQuery()); + } +} diff --git a/app/code/Magento/SalesRule/etc/frontend/di.xml b/app/code/Magento/SalesRule/etc/frontend/di.xml index 0b51ac2b566d9..a3da7be83e883 100644 --- a/app/code/Magento/SalesRule/etc/frontend/di.xml +++ b/app/code/Magento/SalesRule/etc/frontend/di.xml @@ -32,4 +32,9 @@ + + + diff --git a/app/code/Magento/SalesRule/etc/graphql/di.xml b/app/code/Magento/SalesRule/etc/graphql/di.xml new file mode 100644 index 0000000000000..6032558e5c3c4 --- /dev/null +++ b/app/code/Magento/SalesRule/etc/graphql/di.xml @@ -0,0 +1,10 @@ + + + + + + + diff --git a/app/code/Magento/SalesRule/etc/webapi_rest/di.xml b/app/code/Magento/SalesRule/etc/webapi_rest/di.xml new file mode 100644 index 0000000000000..5998928ea433b --- /dev/null +++ b/app/code/Magento/SalesRule/etc/webapi_rest/di.xml @@ -0,0 +1,9 @@ + + + + + + From 781845d8e5f01464edece2554275dbb6a5d68a8e Mon Sep 17 00:00:00 2001 From: Senthilkumar Muppidathi Date: Tue, 28 Oct 2025 10:52:10 +0530 Subject: [PATCH 02/12] #40226 - Adding copyright for Static Tests --- app/code/Magento/SalesRule/Model/Plugin/FrontController.php | 5 ++++- .../SalesRule/Model/Plugin/QuoteConfigProductAttributes.php | 5 ++--- .../Unit/Model/Plugin/QuoteConfigProductAttributesTest.php | 4 ++-- app/code/Magento/SalesRule/etc/frontend/di.xml | 4 ++-- app/code/Magento/SalesRule/etc/graphql/di.xml | 6 ++++++ app/code/Magento/SalesRule/etc/webapi_rest/di.xml | 6 ++++++ 6 files changed, 22 insertions(+), 8 deletions(-) diff --git a/app/code/Magento/SalesRule/Model/Plugin/FrontController.php b/app/code/Magento/SalesRule/Model/Plugin/FrontController.php index 6b7f3c3efe478..20df152f762f0 100644 --- a/app/code/Magento/SalesRule/Model/Plugin/FrontController.php +++ b/app/code/Magento/SalesRule/Model/Plugin/FrontController.php @@ -1,5 +1,8 @@ diff --git a/app/code/Magento/SalesRule/etc/graphql/di.xml b/app/code/Magento/SalesRule/etc/graphql/di.xml index 6032558e5c3c4..b5ae390888028 100644 --- a/app/code/Magento/SalesRule/etc/graphql/di.xml +++ b/app/code/Magento/SalesRule/etc/graphql/di.xml @@ -1,4 +1,10 @@ + diff --git a/app/code/Magento/SalesRule/etc/webapi_rest/di.xml b/app/code/Magento/SalesRule/etc/webapi_rest/di.xml index 5998928ea433b..377063359a35a 100644 --- a/app/code/Magento/SalesRule/etc/webapi_rest/di.xml +++ b/app/code/Magento/SalesRule/etc/webapi_rest/di.xml @@ -1,4 +1,10 @@ + From e3040a0764425e10816ffecf8900a11b5dd00bbf Mon Sep 17 00:00:00 2001 From: Senthilkumar Muppidathi Date: Tue, 28 Oct 2025 14:07:52 +0530 Subject: [PATCH 03/12] #40226 - Made Before Dispatch to return void --- app/code/Magento/SalesRule/Model/Plugin/FrontController.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/code/Magento/SalesRule/Model/Plugin/FrontController.php b/app/code/Magento/SalesRule/Model/Plugin/FrontController.php index 20df152f762f0..92f2250046283 100644 --- a/app/code/Magento/SalesRule/Model/Plugin/FrontController.php +++ b/app/code/Magento/SalesRule/Model/Plugin/FrontController.php @@ -20,7 +20,7 @@ public function __construct( * * @param \Magento\Framework\App\FrontControllerInterface $subject * @param \Magento\Framework\App\RequestInterface $request - * @return $request + * @return void */ public function beforeDispatch( \Magento\Framework\App\FrontControllerInterface $subject, @@ -31,7 +31,5 @@ public function beforeDispatch( // Set flag in TotalCollectionState $this->requestTypeRegistry->setIsGetRequestOrQuery($isReadOnly); - - return $request; } } From 332adf6e37431b9545465c2a1d3af2f285e4d905 Mon Sep 17 00:00:00 2001 From: Senthilkumar Muppidathi Date: Tue, 28 Oct 2025 21:52:10 +0530 Subject: [PATCH 04/12] #40226 - Skip optimisation if trigger_recollect is set to 1 in DB to seamlessly process collectTotals --- .../Model/Plugin/QuoteItemCollection.php | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 app/code/Magento/SalesRule/Model/Plugin/QuoteItemCollection.php diff --git a/app/code/Magento/SalesRule/Model/Plugin/QuoteItemCollection.php b/app/code/Magento/SalesRule/Model/Plugin/QuoteItemCollection.php new file mode 100644 index 0000000000000..be409b1b9f918 --- /dev/null +++ b/app/code/Magento/SalesRule/Model/Plugin/QuoteItemCollection.php @@ -0,0 +1,33 @@ +getTriggerRecollect() && $this->requestTypeRegistry->isGetRequestOrQuery()) { + $this->requestTypeRegistry->setIsGetRequestOrQuery(false); + } + } +} From d045762a3d0bad03589e8b9f7e53567258b5bf0d Mon Sep 17 00:00:00 2001 From: Senthilkumar Muppidathi Date: Tue, 28 Oct 2025 23:25:51 +0530 Subject: [PATCH 05/12] #40226 - Static Test Fixes & Removed confusing comments --- app/code/Magento/SalesRule/Model/Plugin/FrontController.php | 4 +++- app/code/Magento/SalesRule/Model/Plugin/QueryParser.php | 4 +++- .../SalesRule/Model/Plugin/QuoteConfigProductAttributes.php | 2 ++ .../Magento/SalesRule/Model/Plugin/QuoteItemCollection.php | 2 ++ .../Magento/SalesRule/Model/Plugin/RequestTypeRegistry.php | 2 ++ 5 files changed, 12 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/SalesRule/Model/Plugin/FrontController.php b/app/code/Magento/SalesRule/Model/Plugin/FrontController.php index 92f2250046283..bf01769630284 100644 --- a/app/code/Magento/SalesRule/Model/Plugin/FrontController.php +++ b/app/code/Magento/SalesRule/Model/Plugin/FrontController.php @@ -3,6 +3,8 @@ * Copyright 2025 Adobe * All Rights Reserved. */ +declare(strict_types=1); + namespace Magento\SalesRule\Model\Plugin; class FrontController @@ -21,6 +23,7 @@ public function __construct( * @param \Magento\Framework\App\FrontControllerInterface $subject * @param \Magento\Framework\App\RequestInterface $request * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function beforeDispatch( \Magento\Framework\App\FrontControllerInterface $subject, @@ -29,7 +32,6 @@ public function beforeDispatch( $method = strtoupper($request->getMethod()); $isReadOnly = ($method === 'GET'); - // Set flag in TotalCollectionState $this->requestTypeRegistry->setIsGetRequestOrQuery($isReadOnly); } } diff --git a/app/code/Magento/SalesRule/Model/Plugin/QueryParser.php b/app/code/Magento/SalesRule/Model/Plugin/QueryParser.php index 07a6f71ed1efe..477a437dd68b9 100644 --- a/app/code/Magento/SalesRule/Model/Plugin/QueryParser.php +++ b/app/code/Magento/SalesRule/Model/Plugin/QueryParser.php @@ -3,6 +3,8 @@ * Copyright 2025 Adobe * All Rights Reserved. */ +declare(strict_types=1); + namespace Magento\SalesRule\Model\Plugin; class QueryParser @@ -17,7 +19,7 @@ public function __construct( } /** - * Set QueryType to CartItemDataForSaleRule + * Set QueryType to RequestTypeRegistry * * @param \Magento\Framework\GraphQl\Query\QueryParser $subject * @param \GraphQL\Language\AST\DocumentNode $documentNode diff --git a/app/code/Magento/SalesRule/Model/Plugin/QuoteConfigProductAttributes.php b/app/code/Magento/SalesRule/Model/Plugin/QuoteConfigProductAttributes.php index 8623e94fa424b..8afd48d7a63b0 100644 --- a/app/code/Magento/SalesRule/Model/Plugin/QuoteConfigProductAttributes.php +++ b/app/code/Magento/SalesRule/Model/Plugin/QuoteConfigProductAttributes.php @@ -3,6 +3,8 @@ * Copyright 2025 Adobe * All Rights Reserved. */ +declare(strict_types=1); + namespace Magento\SalesRule\Model\Plugin; use Magento\Framework\App\CacheInterface; diff --git a/app/code/Magento/SalesRule/Model/Plugin/QuoteItemCollection.php b/app/code/Magento/SalesRule/Model/Plugin/QuoteItemCollection.php index be409b1b9f918..bed60401bc038 100644 --- a/app/code/Magento/SalesRule/Model/Plugin/QuoteItemCollection.php +++ b/app/code/Magento/SalesRule/Model/Plugin/QuoteItemCollection.php @@ -3,6 +3,8 @@ * Copyright 2025 Adobe * All Rights Reserved. */ +declare(strict_types=1); + namespace Magento\SalesRule\Model\Plugin; class QuoteItemCollection diff --git a/app/code/Magento/SalesRule/Model/Plugin/RequestTypeRegistry.php b/app/code/Magento/SalesRule/Model/Plugin/RequestTypeRegistry.php index e6c85ffe06f9b..523819ece3873 100644 --- a/app/code/Magento/SalesRule/Model/Plugin/RequestTypeRegistry.php +++ b/app/code/Magento/SalesRule/Model/Plugin/RequestTypeRegistry.php @@ -3,6 +3,8 @@ * Copyright 2025 Adobe * All Rights Reserved. */ +declare(strict_types=1); + namespace Magento\SalesRule\Model\Plugin; /** From f00101c39bfc7469a05e74daaaa91c2ae5d0f045 Mon Sep 17 00:00:00 2001 From: Senthilkumar Muppidathi Date: Wed, 29 Oct 2025 12:16:58 +0530 Subject: [PATCH 06/12] #40226 - Introduced separate file for persisting trigger recollect & static test fixes --- .../Plugin/QuoteConfigProductAttributes.php | 7 ++- .../Model/Plugin/QuoteItemCollection.php | 11 ++-- .../Model/Plugin/TriggerRecollectState.php | 37 ++++++++++++ .../Plugin/TriggerRecollectStateTest.php | 56 +++++++++++++++++++ 4 files changed, 106 insertions(+), 5 deletions(-) create mode 100644 app/code/Magento/SalesRule/Model/Plugin/TriggerRecollectState.php create mode 100644 app/code/Magento/SalesRule/Test/Unit/Model/Plugin/TriggerRecollectStateTest.php diff --git a/app/code/Magento/SalesRule/Model/Plugin/QuoteConfigProductAttributes.php b/app/code/Magento/SalesRule/Model/Plugin/QuoteConfigProductAttributes.php index 8afd48d7a63b0..92e2ff14507ed 100644 --- a/app/code/Magento/SalesRule/Model/Plugin/QuoteConfigProductAttributes.php +++ b/app/code/Magento/SalesRule/Model/Plugin/QuoteConfigProductAttributes.php @@ -10,6 +10,7 @@ use Magento\Framework\App\CacheInterface; use Magento\Framework\Serialize\SerializerInterface; use Magento\Quote\Model\Quote\Config; +use Magento\Quote\Model\Quote; use Magento\SalesRule\Model\ResourceModel\Rule as RuleResource; class QuoteConfigProductAttributes @@ -37,12 +38,14 @@ class QuoteConfigProductAttributes /** * @param RuleResource $ruleResource * @param RequestTypeRegistry $requestTypeRegistry + * @param TriggerRecollectState $triggerRecollectState * @param CacheInterface $cache * @param SerializerInterface $serializer */ public function __construct( RuleResource $ruleResource, private RequestTypeRegistry $requestTypeRegistry, + private TriggerRecollectState $triggerRecollectState, private CacheInterface $cache, private SerializerInterface $serializer ) { @@ -60,7 +63,9 @@ public function __construct( */ public function afterGetProductAttributes(Config $subject, array $attributeKeys): array { - if ($this->requestTypeRegistry->isGetRequestOrQuery()) { + if ($this->requestTypeRegistry->isGetRequestOrQuery() && + !$this->triggerRecollectState->canRecollect() + ) { return $attributeKeys; } diff --git a/app/code/Magento/SalesRule/Model/Plugin/QuoteItemCollection.php b/app/code/Magento/SalesRule/Model/Plugin/QuoteItemCollection.php index bed60401bc038..846e12cc9e735 100644 --- a/app/code/Magento/SalesRule/Model/Plugin/QuoteItemCollection.php +++ b/app/code/Magento/SalesRule/Model/Plugin/QuoteItemCollection.php @@ -10,10 +10,12 @@ class QuoteItemCollection { /** - * @param RequestTypeRegistry $requestTypeRegistry + * @param RequestTypeRegistry $requestTypeRegistry + * @param TriggerRecollectState $triggerRecollectState */ public function __construct( - private RequestTypeRegistry $requestTypeRegistry + private RequestTypeRegistry $requestTypeRegistry, + private TriggerRecollectState $triggerRecollectState ) { } @@ -23,13 +25,14 @@ public function __construct( * @param \Magento\Quote\Model\ResourceModel\Quote\Item\Collection $subject The collection instance. * @param \Magento\Quote\Model\Quote $quote The quote to be processed. * @return void + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function beforeSetQuote( \Magento\Quote\Model\ResourceModel\Quote\Item\Collection $subject, \Magento\Quote\Model\Quote $quote ) { - if ($quote->getTriggerRecollect() && $this->requestTypeRegistry->isGetRequestOrQuery()) { - $this->requestTypeRegistry->setIsGetRequestOrQuery(false); + if ($quote->getTriggerRecollect() == 1 && $this->requestTypeRegistry->isGetRequestOrQuery()) { + $this->triggerRecollectState->setTriggerRecollect(1); } } } diff --git a/app/code/Magento/SalesRule/Model/Plugin/TriggerRecollectState.php b/app/code/Magento/SalesRule/Model/Plugin/TriggerRecollectState.php new file mode 100644 index 0000000000000..d174195c87f4c --- /dev/null +++ b/app/code/Magento/SalesRule/Model/Plugin/TriggerRecollectState.php @@ -0,0 +1,37 @@ +triggerRecollect = $collect; + } + + /** + * Check recollect will be triggered + * + * @return int + */ + public function canRecollect(): int + { + return $this->triggerRecollect; + } +} diff --git a/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/TriggerRecollectStateTest.php b/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/TriggerRecollectStateTest.php new file mode 100644 index 0000000000000..f00b0da657bd3 --- /dev/null +++ b/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/TriggerRecollectStateTest.php @@ -0,0 +1,56 @@ +state = new TriggerRecollectState(); + } + + public function testDefaultStateIsZero() + { + $this->assertEquals(0, $this->state->canRecollect()); + } + + public function testCanRecollectOne() + { + $this->state->setTriggerRecollect(1); + $this->assertEquals(1, $this->state->canRecollect()); + } + + public function testIsGetRequestOrQueryFalse() + { + $this->state->setTriggerRecollect(1); + $this->state->setTriggerRecollect(0); + $this->assertEquals(0, $this->state->canRecollect()); + } + + public function testMultipleToggle() + { + $this->assertEquals(0, $this->state->canRecollect()); + + $this->state->setTriggerRecollect(1); + $this->assertEquals(1, $this->state->canRecollect()); + + $this->state->setTriggerRecollect(0); + $this->assertEquals(0, $this->state->canRecollect()); + + $this->state->setTriggerRecollect(1); + $this->assertEquals(1, $this->state->canRecollect()); + } +} From 9874caf6c13b443241b216b92c7e9d1c698afc55 Mon Sep 17 00:00:00 2001 From: Senthilkumar Muppidathi Date: Wed, 29 Oct 2025 13:59:29 +0530 Subject: [PATCH 07/12] #40226 - Unit Test Fixes and Suppress warning on Query Parser --- .../SalesRule/Model/Plugin/QueryParser.php | 1 + .../Plugin/QuoteConfigProductAttributesTest.php | 15 +++++++++++++++ .../Model/Plugin/TriggerRecollectStateTest.php | 2 +- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/SalesRule/Model/Plugin/QueryParser.php b/app/code/Magento/SalesRule/Model/Plugin/QueryParser.php index 477a437dd68b9..48d3e519055a0 100644 --- a/app/code/Magento/SalesRule/Model/Plugin/QueryParser.php +++ b/app/code/Magento/SalesRule/Model/Plugin/QueryParser.php @@ -24,6 +24,7 @@ public function __construct( * @param \Magento\Framework\GraphQl\Query\QueryParser $subject * @param \GraphQL\Language\AST\DocumentNode $documentNode * @return \GraphQL\Language\AST\DocumentNode $documentNode + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function afterParse(\Magento\Framework\GraphQl\Query\QueryParser $subject, $documentNode) { diff --git a/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/QuoteConfigProductAttributesTest.php b/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/QuoteConfigProductAttributesTest.php index c855d678d622d..28ee068ad506f 100644 --- a/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/QuoteConfigProductAttributesTest.php +++ b/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/QuoteConfigProductAttributesTest.php @@ -12,6 +12,7 @@ use Magento\Quote\Model\Quote\Config; use Magento\SalesRule\Model\Plugin\QuoteConfigProductAttributes; use Magento\SalesRule\Model\Plugin\RequestTypeRegistry; +use Magento\SalesRule\Model\Plugin\TriggerRecollectState; use Magento\SalesRule\Model\ResourceModel\Rule; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -52,6 +53,7 @@ protected function setUp(): void { $this->ruleResource = $this->createMock(Rule::class); $this->requestTypeRegistry = $this->createMock(RequestTypeRegistry::class); + $this->triggerRecollectState = $this->createMock(TriggerRecollectState::class); $this->cache = $this->createMock(CacheInterface::class); $this->serializer = $this->createMock(SerializerInterface::class); $this->subject = $this->createMock(Config::class); @@ -59,6 +61,7 @@ protected function setUp(): void $this->plugin = new QuoteConfigProductAttributes( $this->ruleResource, $this->requestTypeRegistry, + $this->triggerRecollectState, $this->cache, $this->serializer ); @@ -74,6 +77,10 @@ public function testAfterGetProductAttributesWithCache() ->method('isGetRequestOrQuery') ->willReturn(false); + $this->triggerRecollectState->expects($this->once()) + ->method('canRecollect') + ->willReturn(0); + $this->cache->expects($this->once()) ->method('load') ->with('salesrule_active_product_attributes') @@ -100,6 +107,10 @@ public function testAfterGetProductAttributesWithoutCache() ->method('isGetRequestOrQuery') ->willReturn(false); + $this->triggerRecollectState->expects($this->once()) + ->method('canRecollect') + ->willReturn(0); + $this->cache->expects($this->once()) ->method('load') ->with('salesrule_active_product_attributes') @@ -131,6 +142,10 @@ public function testAfterGetProductAttributesRequestTypePostOrMutation() ->method('isGetRequestOrQuery') ->willReturn(true); + $this->triggerRecollectState->expects($this->once()) + ->method('canRecollect') + ->willReturn(0); + $this->assertEquals([], $this->plugin->afterGetProductAttributes($this->subject, [])); } } diff --git a/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/TriggerRecollectStateTest.php b/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/TriggerRecollectStateTest.php index f00b0da657bd3..1be8d103ddbed 100644 --- a/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/TriggerRecollectStateTest.php +++ b/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/TriggerRecollectStateTest.php @@ -10,7 +10,7 @@ use Magento\SalesRule\Model\Plugin\TriggerRecollectState; use PHPUnit\Framework\TestCase; -class TriggerRecollectStateTest +class TriggerRecollectStateTest extends TestCase { /** * @var TriggerRecollectState From 3d0d5e8a6526acaa03f2584382cd019e92cb9eb4 Mon Sep 17 00:00:00 2001 From: Senthilkumar Muppidathi Date: Wed, 29 Oct 2025 15:03:43 +0530 Subject: [PATCH 08/12] #40226 - Added missed property --- .../Unit/Model/Plugin/QueryParserTest.php | 147 ++++++++++++++++++ .../QuoteConfigProductAttributesTest.php | 5 + 2 files changed, 152 insertions(+) create mode 100644 app/code/Magento/SalesRule/Test/Unit/Model/Plugin/QueryParserTest.php diff --git a/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/QueryParserTest.php b/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/QueryParserTest.php new file mode 100644 index 0000000000000..277a0cccf4677 --- /dev/null +++ b/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/QueryParserTest.php @@ -0,0 +1,147 @@ +requestTypeRegistry = $this->createMock(RequestTypeRegistry::class); + $this->queryParser = new QueryParser($this->requestTypeRegistry); + $this->subject = $this->createMock(FrameworkQueryParser::class); + $this->documentNode = $this->createMock(DocumentNode::class); + } + + /** + * Test afterParse method with query operation + */ + public function testAfterParseWithQueryOperation(): void + { + // Create a mock operation definition node with 'query' operation + $operationNode = $this->createMock(OperationDefinitionNode::class); + $operationNode->operation = 'query'; + + // Create a mock definitions list with the operation node + $definitions = new NodeList([$operationNode]); + $this->documentNode->definitions = $definitions; + + // Expect RequestTypeRegistry to be called with true + $this->requestTypeRegistry->expects($this->once()) + ->method('setIsGetRequestOrQuery') + ->with(true); + + // Call the method + $result = $this->queryParser->afterParse($this->subject, $this->documentNode); + + // Assert the document node is returned unchanged + $this->assertSame($this->documentNode, $result); + } + + /** + * Test afterParse method with mutation operation + */ + public function testAfterParseWithMutationOperation(): void + { + // Create a mock operation definition node with 'mutation' operation + $operationNode = $this->createMock(OperationDefinitionNode::class); + $operationNode->operation = 'mutation'; + + // Create a mock definitions list with the operation node + $definitions = new NodeList([$operationNode]); + $this->documentNode->definitions = $definitions; + + // Expect RequestTypeRegistry to be called with false + $this->requestTypeRegistry->expects($this->once()) + ->method('setIsGetRequestOrQuery') + ->with(false); + + // Call the method + $result = $this->queryParser->afterParse($this->subject, $this->documentNode); + + // Assert the document node is returned unchanged + $this->assertSame($this->documentNode, $result); + } + + /** + * Test afterParse method with no operation definitions + */ + public function testAfterParseWithNoOperationDefinitions(): void + { + // Create an empty definitions list + $definitions = new NodeList([]); + $this->documentNode->definitions = $definitions; + + // Expect RequestTypeRegistry not to be called + $this->requestTypeRegistry->expects($this->never()) + ->method('setIsGetRequestOrQuery'); + + // Call the method + $result = $this->queryParser->afterParse($this->subject, $this->documentNode); + + // Assert the document node is returned unchanged + $this->assertSame($this->documentNode, $result); + } + + /** + * Test afterParse method with non-operation definition nodes + */ + public function testAfterParseWithNonOperationDefinitions(): void + { + // Create a mock node that is not an OperationDefinitionNode + $nonOperationNode = $this->createMock(\GraphQL\Language\AST\Node::class); + + // Create a mock definitions list with the non-operation node + $definitions = new NodeList([$nonOperationNode]); + $this->documentNode->definitions = $definitions; + + // Expect RequestTypeRegistry not to be called + $this->requestTypeRegistry->expects($this->never()) + ->method('setIsGetRequestOrQuery'); + + // Call the method + $result = $this->queryParser->afterParse($this->subject, $this->documentNode); + + // Assert the document node is returned unchanged + $this->assertSame($this->documentNode, $result); + } +} diff --git a/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/QuoteConfigProductAttributesTest.php b/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/QuoteConfigProductAttributesTest.php index 28ee068ad506f..e6f6179ef781d 100644 --- a/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/QuoteConfigProductAttributesTest.php +++ b/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/QuoteConfigProductAttributesTest.php @@ -49,6 +49,11 @@ class QuoteConfigProductAttributesTest extends TestCase */ protected $subject; + /** + * @var TriggerRecollectState|MockObject + */ + protected $triggerRecollectState; + protected function setUp(): void { $this->ruleResource = $this->createMock(Rule::class); From e08b0c6838046565f6563a4a8888a345b9f04da2 Mon Sep 17 00:00:00 2001 From: Senthilkumar Muppidathi Date: Wed, 29 Oct 2025 21:30:32 +0530 Subject: [PATCH 09/12] #40226 - Reset State Post GraphQl Dispatch and Remove additional State for Trigger Recollect --- .../Model/Plugin/GraphQlController.php | 35 +++++++++++++++++++ .../Plugin/QuoteConfigProductAttributes.php | 6 +--- .../Model/Plugin/QuoteItemCollection.php | 6 ++-- .../Model/Plugin/RequestTypeRegistry.php | 10 ++++++ .../QuoteConfigProductAttributesTest.php | 19 ---------- .../Model/Plugin/RequestTypeRegistryTest.php | 4 +-- app/code/Magento/SalesRule/etc/graphql/di.xml | 5 +++ 7 files changed, 55 insertions(+), 30 deletions(-) create mode 100644 app/code/Magento/SalesRule/Model/Plugin/GraphQlController.php diff --git a/app/code/Magento/SalesRule/Model/Plugin/GraphQlController.php b/app/code/Magento/SalesRule/Model/Plugin/GraphQlController.php new file mode 100644 index 0000000000000..c0790ab668b04 --- /dev/null +++ b/app/code/Magento/SalesRule/Model/Plugin/GraphQlController.php @@ -0,0 +1,35 @@ +requestTypeRegistry->reset(); + return $result; + } +} diff --git a/app/code/Magento/SalesRule/Model/Plugin/QuoteConfigProductAttributes.php b/app/code/Magento/SalesRule/Model/Plugin/QuoteConfigProductAttributes.php index 92e2ff14507ed..9b96cee5b43b2 100644 --- a/app/code/Magento/SalesRule/Model/Plugin/QuoteConfigProductAttributes.php +++ b/app/code/Magento/SalesRule/Model/Plugin/QuoteConfigProductAttributes.php @@ -38,14 +38,12 @@ class QuoteConfigProductAttributes /** * @param RuleResource $ruleResource * @param RequestTypeRegistry $requestTypeRegistry - * @param TriggerRecollectState $triggerRecollectState * @param CacheInterface $cache * @param SerializerInterface $serializer */ public function __construct( RuleResource $ruleResource, private RequestTypeRegistry $requestTypeRegistry, - private TriggerRecollectState $triggerRecollectState, private CacheInterface $cache, private SerializerInterface $serializer ) { @@ -63,9 +61,7 @@ public function __construct( */ public function afterGetProductAttributes(Config $subject, array $attributeKeys): array { - if ($this->requestTypeRegistry->isGetRequestOrQuery() && - !$this->triggerRecollectState->canRecollect() - ) { + if ($this->requestTypeRegistry->isGetRequestOrQuery()) { return $attributeKeys; } diff --git a/app/code/Magento/SalesRule/Model/Plugin/QuoteItemCollection.php b/app/code/Magento/SalesRule/Model/Plugin/QuoteItemCollection.php index 846e12cc9e735..be5720d9d57de 100644 --- a/app/code/Magento/SalesRule/Model/Plugin/QuoteItemCollection.php +++ b/app/code/Magento/SalesRule/Model/Plugin/QuoteItemCollection.php @@ -11,11 +11,9 @@ class QuoteItemCollection { /** * @param RequestTypeRegistry $requestTypeRegistry - * @param TriggerRecollectState $triggerRecollectState */ public function __construct( - private RequestTypeRegistry $requestTypeRegistry, - private TriggerRecollectState $triggerRecollectState + private RequestTypeRegistry $requestTypeRegistry ) { } @@ -32,7 +30,7 @@ public function beforeSetQuote( \Magento\Quote\Model\Quote $quote ) { if ($quote->getTriggerRecollect() == 1 && $this->requestTypeRegistry->isGetRequestOrQuery()) { - $this->triggerRecollectState->setTriggerRecollect(1); + $this->requestTypeRegistry->setIsGetRequestOrQuery(false); } } } diff --git a/app/code/Magento/SalesRule/Model/Plugin/RequestTypeRegistry.php b/app/code/Magento/SalesRule/Model/Plugin/RequestTypeRegistry.php index 523819ece3873..d536deed37d86 100644 --- a/app/code/Magento/SalesRule/Model/Plugin/RequestTypeRegistry.php +++ b/app/code/Magento/SalesRule/Model/Plugin/RequestTypeRegistry.php @@ -40,4 +40,14 @@ public function isGetRequestOrQuery(): bool { return $this->isGetRequestOrQuery; } + + /** + * Resets the state of the object by setting the isGetRequestOrQuery property to false. + * + * @return void + */ + public function reset(): void + { + $this->isGetRequestOrQuery = false; + } } diff --git a/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/QuoteConfigProductAttributesTest.php b/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/QuoteConfigProductAttributesTest.php index e6f6179ef781d..6502857d23ecb 100644 --- a/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/QuoteConfigProductAttributesTest.php +++ b/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/QuoteConfigProductAttributesTest.php @@ -12,7 +12,6 @@ use Magento\Quote\Model\Quote\Config; use Magento\SalesRule\Model\Plugin\QuoteConfigProductAttributes; use Magento\SalesRule\Model\Plugin\RequestTypeRegistry; -use Magento\SalesRule\Model\Plugin\TriggerRecollectState; use Magento\SalesRule\Model\ResourceModel\Rule; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -49,16 +48,10 @@ class QuoteConfigProductAttributesTest extends TestCase */ protected $subject; - /** - * @var TriggerRecollectState|MockObject - */ - protected $triggerRecollectState; - protected function setUp(): void { $this->ruleResource = $this->createMock(Rule::class); $this->requestTypeRegistry = $this->createMock(RequestTypeRegistry::class); - $this->triggerRecollectState = $this->createMock(TriggerRecollectState::class); $this->cache = $this->createMock(CacheInterface::class); $this->serializer = $this->createMock(SerializerInterface::class); $this->subject = $this->createMock(Config::class); @@ -82,10 +75,6 @@ public function testAfterGetProductAttributesWithCache() ->method('isGetRequestOrQuery') ->willReturn(false); - $this->triggerRecollectState->expects($this->once()) - ->method('canRecollect') - ->willReturn(0); - $this->cache->expects($this->once()) ->method('load') ->with('salesrule_active_product_attributes') @@ -112,10 +101,6 @@ public function testAfterGetProductAttributesWithoutCache() ->method('isGetRequestOrQuery') ->willReturn(false); - $this->triggerRecollectState->expects($this->once()) - ->method('canRecollect') - ->willReturn(0); - $this->cache->expects($this->once()) ->method('load') ->with('salesrule_active_product_attributes') @@ -147,10 +132,6 @@ public function testAfterGetProductAttributesRequestTypePostOrMutation() ->method('isGetRequestOrQuery') ->willReturn(true); - $this->triggerRecollectState->expects($this->once()) - ->method('canRecollect') - ->willReturn(0); - $this->assertEquals([], $this->plugin->afterGetProductAttributes($this->subject, [])); } } diff --git a/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/RequestTypeRegistryTest.php b/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/RequestTypeRegistryTest.php index 5ac2ca3d08771..3dcd6b16ad626 100644 --- a/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/RequestTypeRegistryTest.php +++ b/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/RequestTypeRegistryTest.php @@ -40,14 +40,14 @@ public function testIsGetRequestOrQueryFalse() $this->assertFalse($this->state->isGetRequestOrQuery()); } - public function testMultipleToggle() + public function testResetAndMultipleToggle() { $this->assertFalse($this->state->isGetRequestOrQuery()); $this->state->setIsGetRequestOrQuery(true); $this->assertTrue($this->state->isGetRequestOrQuery()); - $this->state->setIsGetRequestOrQuery(false); + $this->state->reset(); $this->assertFalse($this->state->isGetRequestOrQuery()); $this->state->setIsGetRequestOrQuery(true); diff --git a/app/code/Magento/SalesRule/etc/graphql/di.xml b/app/code/Magento/SalesRule/etc/graphql/di.xml index b5ae390888028..2885d4d03e2cf 100644 --- a/app/code/Magento/SalesRule/etc/graphql/di.xml +++ b/app/code/Magento/SalesRule/etc/graphql/di.xml @@ -13,4 +13,9 @@ type="Magento\SalesRule\Model\Plugin\QueryParser" sortOrder="10" /> + + + From dfd5889360627221162fda9f9c4fffa3e6fb878d Mon Sep 17 00:00:00 2001 From: Senthilkumar Muppidathi Date: Thu, 30 Oct 2025 00:13:28 +0530 Subject: [PATCH 10/12] #40226 - Correcting typos in di --- .../SalesRule/Model/Plugin/GraphQlController.php | 15 +++++++++------ .../Plugin/QuoteConfigProductAttributesTest.php | 1 - app/code/Magento/SalesRule/etc/di.xml | 5 +++++ app/code/Magento/SalesRule/etc/graphql/di.xml | 4 ++-- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/app/code/Magento/SalesRule/Model/Plugin/GraphQlController.php b/app/code/Magento/SalesRule/Model/Plugin/GraphQlController.php index c0790ab668b04..7c98b73d7ee88 100644 --- a/app/code/Magento/SalesRule/Model/Plugin/GraphQlController.php +++ b/app/code/Magento/SalesRule/Model/Plugin/GraphQlController.php @@ -7,6 +7,9 @@ namespace Magento\SalesRule\Model\Plugin; +use Magento\Framework\App\ResponseInterface; +use Magento\Framework\App\FrontControllerInterface; + class GraphQlController { /** @@ -20,15 +23,15 @@ public function __construct( /** * Reset request type registry after dispatching GraphQL controller * - * @param \Magento\Framework\App\FrontControllerInterface $subject - * @param \Magento\Framework\App\ResponseInterface $result - * @return \Magento\Framework\App\ResponseInterface $result + * @param FrontControllerInterface $subject + * @param ResponseInterface $result + * @return ResponseInterface $result * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function afterDispatch( - \Magento\Framework\App\FrontControllerInterface $subject, - \Magento\Framework\App\ResponseInterface $result - ) { + FrontControllerInterface $subject, + ResponseInterface $result + ) : ResponseInterface { $this->requestTypeRegistry->reset(); return $result; } diff --git a/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/QuoteConfigProductAttributesTest.php b/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/QuoteConfigProductAttributesTest.php index 6502857d23ecb..c855d678d622d 100644 --- a/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/QuoteConfigProductAttributesTest.php +++ b/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/QuoteConfigProductAttributesTest.php @@ -59,7 +59,6 @@ protected function setUp(): void $this->plugin = new QuoteConfigProductAttributes( $this->ruleResource, $this->requestTypeRegistry, - $this->triggerRecollectState, $this->cache, $this->serializer ); diff --git a/app/code/Magento/SalesRule/etc/di.xml b/app/code/Magento/SalesRule/etc/di.xml index cd841b36338e4..b3aa5b68191d3 100644 --- a/app/code/Magento/SalesRule/etc/di.xml +++ b/app/code/Magento/SalesRule/etc/di.xml @@ -54,6 +54,11 @@ + + + diff --git a/app/code/Magento/SalesRule/etc/graphql/di.xml b/app/code/Magento/SalesRule/etc/graphql/di.xml index 2885d4d03e2cf..c844dbf6d64c6 100644 --- a/app/code/Magento/SalesRule/etc/graphql/di.xml +++ b/app/code/Magento/SalesRule/etc/graphql/di.xml @@ -13,9 +13,9 @@ type="Magento\SalesRule\Model\Plugin\QueryParser" sortOrder="10" /> - + From 776bbf0f48483bdf4f3236e9826556b3b6c0588f Mon Sep 17 00:00:00 2001 From: Senthilkumar Muppidathi Date: Thu, 30 Oct 2025 16:20:50 +0530 Subject: [PATCH 11/12] #40226-Removing Unwanted files and added test cases for all new plugins --- .../Model/Plugin/TriggerRecollectState.php | 37 ------ .../Unit/Model/Plugin/FrontControllerTest.php | 72 +++++++++++ .../Model/Plugin/GraphQlControllerTest.php | 68 +++++++++++ .../Model/Plugin/QuoteItemCollectionTest.php | 114 ++++++++++++++++++ .../Plugin/TriggerRecollectStateTest.php | 56 --------- 5 files changed, 254 insertions(+), 93 deletions(-) delete mode 100644 app/code/Magento/SalesRule/Model/Plugin/TriggerRecollectState.php create mode 100644 app/code/Magento/SalesRule/Test/Unit/Model/Plugin/FrontControllerTest.php create mode 100644 app/code/Magento/SalesRule/Test/Unit/Model/Plugin/GraphQlControllerTest.php create mode 100644 app/code/Magento/SalesRule/Test/Unit/Model/Plugin/QuoteItemCollectionTest.php delete mode 100644 app/code/Magento/SalesRule/Test/Unit/Model/Plugin/TriggerRecollectStateTest.php diff --git a/app/code/Magento/SalesRule/Model/Plugin/TriggerRecollectState.php b/app/code/Magento/SalesRule/Model/Plugin/TriggerRecollectState.php deleted file mode 100644 index d174195c87f4c..0000000000000 --- a/app/code/Magento/SalesRule/Model/Plugin/TriggerRecollectState.php +++ /dev/null @@ -1,37 +0,0 @@ -triggerRecollect = $collect; - } - - /** - * Check recollect will be triggered - * - * @return int - */ - public function canRecollect(): int - { - return $this->triggerRecollect; - } -} diff --git a/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/FrontControllerTest.php b/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/FrontControllerTest.php new file mode 100644 index 0000000000000..e9b32b1ba1ea4 --- /dev/null +++ b/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/FrontControllerTest.php @@ -0,0 +1,72 @@ +requestTypeRegistry = $this->createMock(RequestTypeRegistry::class); + $this->plugin = new FrontController($this->requestTypeRegistry); + } + + public function testBeforeDispatchSetsTrueForGetRequests(): void + { + $subject = $this->createMock(FrontControllerInterface::class); + $request = $this->createMock(RequestInterface::class); + $request->method('getMethod')->willReturn('GET'); + + $this->requestTypeRegistry + ->expects($this->once()) + ->method('setIsGetRequestOrQuery') + ->with(true); + + $this->plugin->beforeDispatch($subject, $request); + } + + public function testBeforeDispatchSetsFalseForPostRequests(): void + { + $subject = $this->createMock(FrontControllerInterface::class); + $request = $this->createMock(RequestInterface::class); + $request->method('getMethod')->willReturn('POST'); + + $this->requestTypeRegistry + ->expects($this->once()) + ->method('setIsGetRequestOrQuery') + ->with(false); + + $this->plugin->beforeDispatch($subject, $request); + } + + public function testBeforeDispatchIsCaseInsensitive(): void + { + $subject = $this->createMock(FrontControllerInterface::class); + $request = $this->createMock(RequestInterface::class); + $request->method('getMethod')->willReturn('get'); // lowercase + + $this->requestTypeRegistry + ->expects($this->once()) + ->method('setIsGetRequestOrQuery') + ->with(true); + + $this->plugin->beforeDispatch($subject, $request); + } +} diff --git a/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/GraphQlControllerTest.php b/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/GraphQlControllerTest.php new file mode 100644 index 0000000000000..9bf94fbe15805 --- /dev/null +++ b/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/GraphQlControllerTest.php @@ -0,0 +1,68 @@ +requestTypeRegistry = $this->createMock(RequestTypeRegistry::class); + $this->graphQlController = new GraphQlController($this->requestTypeRegistry); + $this->frontController = $this->createMock(FrontControllerInterface::class); + $this->response = $this->createMock(ResponseInterface::class); + } + + /** + * Test afterDispatch calls reset on RequestTypeRegistry + */ + public function testAfterDispatchResetsRequestTypeRegistry(): void + { + // Expect reset to be called on the RequestTypeRegistry + $this->requestTypeRegistry->expects($this->once()) + ->method('reset'); + + // Call the afterDispatch method + $result = $this->graphQlController->afterDispatch($this->frontController, $this->response); + + // Verify the response is returned unchanged + $this->assertSame($this->response, $result); + } +} diff --git a/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/QuoteItemCollectionTest.php b/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/QuoteItemCollectionTest.php new file mode 100644 index 0000000000000..a5140969eddda --- /dev/null +++ b/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/QuoteItemCollectionTest.php @@ -0,0 +1,114 @@ +requestTypeRegistry = $this->createMock(RequestTypeRegistry::class); + $this->plugin = new QuoteItemCollection($this->requestTypeRegistry); + $this->quoteItemCollection = $this->createMock(QuoteItemCollection::class); + $this->quote = $this->createMock(Quote::class); + } + + /** + * Test beforeSetQuote when triggerRecollect is 1 and request is GET/Query + */ + public function testBeforeSetQuoteWithTriggerRecollectAndGetRequest(): void + { + // Set up the quote mock to return 1 for getTriggerRecollect + $this->quote->expects($this->once()) + ->method('getTriggerRecollect') + ->willReturn(1); + + // Set up the request type registry to indicate this is a GET request + $this->requestTypeRegistry->expects($this->once()) + ->method('isGetRequestOrQuery') + ->willReturn(true); + + // Expect setIsGetRequestOrQuery to be called with false + $this->requestTypeRegistry->expects($this->once()) + ->method('setIsGetRequestOrQuery') + ->with(false); + + // Execute the method + $this->plugin->beforeSetQuote($this->quoteItemCollection, $this->quote); + } + + /** + * Test beforeSetQuote when triggerRecollect is 0 and request is GET/Query + */ + public function testBeforeSetQuoteWithNoTriggerRecollectAndGetRequest(): void + { + // Set up the quote mock to return 0 for getTriggerRecollect + $this->quote->expects($this->once()) + ->method('getTriggerRecollect') + ->willReturn(0); + + // Expect setIsGetRequestOrQuery NOT to be called + $this->requestTypeRegistry->expects($this->never()) + ->method('setIsGetRequestOrQuery'); + + // Execute the method + $this->plugin->beforeSetQuote($this->quoteItemCollection, $this->quote); + } + + /** + * Test beforeSetQuote when triggerRecollect is 1 but request is not GET/Query + */ + public function testBeforeSetQuoteWithTriggerRecollectAndNonGetRequest(): void + { + // Set up the quote mock to return 1 for getTriggerRecollect + $this->quote->expects($this->once()) + ->method('getTriggerRecollect') + ->willReturn(1); + + // Set up the request type registry to indicate this is NOT a GET request + $this->requestTypeRegistry->expects($this->once()) + ->method('isGetRequestOrQuery') + ->willReturn(false); + + // Expect setIsGetRequestOrQuery NOT to be called + $this->requestTypeRegistry->expects($this->never()) + ->method('setIsGetRequestOrQuery'); + + // Execute the method + $this->plugin->beforeSetQuote($this->quoteItemCollection, $this->quote); + } +} diff --git a/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/TriggerRecollectStateTest.php b/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/TriggerRecollectStateTest.php deleted file mode 100644 index 1be8d103ddbed..0000000000000 --- a/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/TriggerRecollectStateTest.php +++ /dev/null @@ -1,56 +0,0 @@ -state = new TriggerRecollectState(); - } - - public function testDefaultStateIsZero() - { - $this->assertEquals(0, $this->state->canRecollect()); - } - - public function testCanRecollectOne() - { - $this->state->setTriggerRecollect(1); - $this->assertEquals(1, $this->state->canRecollect()); - } - - public function testIsGetRequestOrQueryFalse() - { - $this->state->setTriggerRecollect(1); - $this->state->setTriggerRecollect(0); - $this->assertEquals(0, $this->state->canRecollect()); - } - - public function testMultipleToggle() - { - $this->assertEquals(0, $this->state->canRecollect()); - - $this->state->setTriggerRecollect(1); - $this->assertEquals(1, $this->state->canRecollect()); - - $this->state->setTriggerRecollect(0); - $this->assertEquals(0, $this->state->canRecollect()); - - $this->state->setTriggerRecollect(1); - $this->assertEquals(1, $this->state->canRecollect()); - } -} From e079e876493e81dfd4632f6948fe1e616cef0b8a Mon Sep 17 00:00:00 2001 From: Senthilkumar Muppidathi Date: Thu, 30 Oct 2025 20:27:36 +0530 Subject: [PATCH 12/12] #40226 - Final Unit Test updates and Static test fixes --- .../Unit/Model/Plugin/FrontControllerTest.php | 33 ++++++++++++------- .../Model/Plugin/QuoteItemCollectionTest.php | 12 +++++-- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/FrontControllerTest.php b/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/FrontControllerTest.php index e9b32b1ba1ea4..d15dd20b4c707 100644 --- a/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/FrontControllerTest.php +++ b/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/FrontControllerTest.php @@ -22,51 +22,60 @@ class FrontControllerTest extends TestCase /** @var FrontController */ private $plugin; + /** + * @var RequestInterface|MockObject + */ + private RequestInterface $request; + + /** + * @var FrontControllerInterface|MockObject + */ + private FrontControllerInterface $subject; + protected function setUp(): void { $this->requestTypeRegistry = $this->createMock(RequestTypeRegistry::class); $this->plugin = new FrontController($this->requestTypeRegistry); + $this->request = $this->getMockBuilder(RequestInterface::class) + ->addMethods(['getMethod']) + ->getMockForAbstractClass(); + $this->subject = $this->createMock(FrontControllerInterface::class); } public function testBeforeDispatchSetsTrueForGetRequests(): void { - $subject = $this->createMock(FrontControllerInterface::class); - $request = $this->createMock(RequestInterface::class); - $request->method('getMethod')->willReturn('GET'); + $this->request->method('getMethod')->willReturn('GET'); $this->requestTypeRegistry ->expects($this->once()) ->method('setIsGetRequestOrQuery') ->with(true); - $this->plugin->beforeDispatch($subject, $request); + $this->plugin->beforeDispatch($this->subject, $this->request); } public function testBeforeDispatchSetsFalseForPostRequests(): void { - $subject = $this->createMock(FrontControllerInterface::class); - $request = $this->createMock(RequestInterface::class); - $request->method('getMethod')->willReturn('POST'); + $this->request->method('getMethod')->willReturn('POST'); $this->requestTypeRegistry ->expects($this->once()) ->method('setIsGetRequestOrQuery') ->with(false); - $this->plugin->beforeDispatch($subject, $request); + $this->plugin->beforeDispatch($this->subject, $this->request); } public function testBeforeDispatchIsCaseInsensitive(): void { - $subject = $this->createMock(FrontControllerInterface::class); - $request = $this->createMock(RequestInterface::class); - $request->method('getMethod')->willReturn('get'); // lowercase + + $this->request->method('getMethod')->willReturn('get'); // lowercase $this->requestTypeRegistry ->expects($this->once()) ->method('setIsGetRequestOrQuery') ->with(true); - $this->plugin->beforeDispatch($subject, $request); + $this->plugin->beforeDispatch($this->subject, $this->request); } } diff --git a/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/QuoteItemCollectionTest.php b/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/QuoteItemCollectionTest.php index a5140969eddda..8b9ff3a39ddf7 100644 --- a/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/QuoteItemCollectionTest.php +++ b/app/code/Magento/SalesRule/Test/Unit/Model/Plugin/QuoteItemCollectionTest.php @@ -6,9 +6,12 @@ declare(strict_types=1); namespace Magento\SalesRule\Test\Unit\Model\Plugin; + use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Magento\SalesRule\Model\Plugin\QuoteItemCollection; +use Magento\Quote\Model\ResourceModel\Quote\Item\Collection; +use Magento\SalesRule\Model\Plugin\RequestTypeRegistry; use Magento\Quote\Model\Quote; /** @@ -43,8 +46,13 @@ protected function setUp(): void { $this->requestTypeRegistry = $this->createMock(RequestTypeRegistry::class); $this->plugin = new QuoteItemCollection($this->requestTypeRegistry); - $this->quoteItemCollection = $this->createMock(QuoteItemCollection::class); - $this->quote = $this->createMock(Quote::class); + $this->quoteItemCollection = $this->getMockBuilder(Collection::class) + ->disableOriginalConstructor() + ->getMock(); + $this->quote = $this->getMockBuilder(Quote::class) + ->disableOriginalConstructor() + ->addMethods(['getTriggerRecollect']) + ->getMock(); } /**