From a7ef876a5a3863c7e8bf96664d628fbf57c221d1 Mon Sep 17 00:00:00 2001 From: Satish Ashilwar Date: Mon, 8 Dec 2025 01:11:18 +0530 Subject: [PATCH] Fix: Force current currency reload on currency code change Fixed an issue where calling setCurrentCurrencyCode() multiple times did not update the currency returned by getCurrentCurrency() due to internal caching. The issue occurred because getCurrentCurrency() caches the currency object in the store's data using the 'current_currency' key. When setCurrentCurrencyCode() was called to change the currency code, the cached currency object was not cleared, causing getCurrentCurrency() to return the old currency instead of loading the new one. Solution: - Added unsetData('current_currency') in setCurrentCurrencyCode() to clear the cached currency when the currency code changes - This forces getCurrentCurrency() to reload the currency based on the new currency code on its next call Changes: - Updated Store::setCurrentCurrencyCode() to clear cached currency - Added unit test to verify currency cache is cleared on code change Test coverage: - Added testSetCurrentCurrencyCodeClearsCachedCurrency() unit test - Test verifies unsetData() is called when currency code changes - Test verifies behavior with multiple currency code changes Manual testing: 1. Create store with multiple available currencies (USD, EUR) 2. Call $store->setCurrentCurrencyCode('USD') 3. Verify $store->getCurrentCurrency()->getCode() returns 'USD' 4. Call $store->setCurrentCurrencyCode('EUR') 5. Verify $store->getCurrentCurrency()->getCode() returns 'EUR' 6. Without this fix, step 5 would return 'USD' Fixes: #40333 --- app/code/Magento/Store/Model/Store.php | 3 + .../Store/Test/Unit/Model/StoreTest.php | 101 ++++++++++++++++++ 2 files changed, 104 insertions(+) diff --git a/app/code/Magento/Store/Model/Store.php b/app/code/Magento/Store/Model/Store.php index 05c762cce5164..4bb376b89d954 100644 --- a/app/code/Magento/Store/Model/Store.php +++ b/app/code/Magento/Store/Model/Store.php @@ -911,6 +911,9 @@ public function setCurrentCurrencyCode($code) : $this->_storeManager->getWebsite()->getDefaultStore()->getDefaultCurrency()->getCode(); $this->_httpContext->setValue(Context::CONTEXT_CURRENCY, $code, $defaultCode); + + // Force reload of current currency on currency code change + $this->unsetData('current_currency'); } return $this; } diff --git a/app/code/Magento/Store/Test/Unit/Model/StoreTest.php b/app/code/Magento/Store/Test/Unit/Model/StoreTest.php index 95c21a95e7643..0dfb0937da75d 100644 --- a/app/code/Magento/Store/Test/Unit/Model/StoreTest.php +++ b/app/code/Magento/Store/Test/Unit/Model/StoreTest.php @@ -819,6 +819,107 @@ public static function currencyCodeDataProvider(): array ]; } + /** + * Test that setCurrentCurrencyCode clears cached currency + * + * @return void + */ + public function testSetCurrentCurrencyCodeClearsCachedCurrency(): void + { + $currencyCodeFirst = 'USD'; + $currencyCodeSecond = 'EUR'; + + $sessionMock = $this->getMockBuilder(SessionManagerInterface::class) + ->getMockForAbstractClass(); + $sessionMock->expects($this->exactly(2)) + ->method('setCurrencyCode') + ->willReturnCallback(function ($code) use ($currencyCodeFirst, $currencyCodeSecond) { + static $callCount = 0; + $callCount++; + if ($callCount === 1) { + $this->assertEquals($currencyCodeFirst, $code); + } else { + $this->assertEquals($currencyCodeSecond, $code); + } + }); + + $httpContextMock = $this->getMockBuilder(\Magento\Framework\App\Http\Context::class) + ->disableOriginalConstructor() + ->getMock(); + + $currencyFactoryMock = $this->getMockBuilder(CurrencyFactory::class) + ->disableOriginalConstructor() + ->getMock(); + + $currencyMockFirst = $this->getMockBuilder(Currency::class) + ->disableOriginalConstructor() + ->getMock(); + $currencyMockFirst->expects($this->any()) + ->method('getCode') + ->willReturn($currencyCodeFirst); + + $currencyMockSecond = $this->getMockBuilder(Currency::class) + ->disableOriginalConstructor() + ->getMock(); + $currencyMockSecond->expects($this->any()) + ->method('getCode') + ->willReturn($currencyCodeSecond); + + $storeManagerMock = $this->getMockBuilder(StoreManagerInterface::class) + ->getMockForAbstractClass(); + $storeManagerMock->expects($this->any()) + ->method('getStore') + ->willReturn(null); + + $websiteMock = $this->getMockBuilder(WebsiteInterface::class) + ->getMockForAbstractClass(); + $websiteMock->expects($this->any()) + ->method('getDefaultStore') + ->willReturnSelf(); + $websiteMock->expects($this->any()) + ->method('getDefaultCurrency') + ->willReturn($currencyMockFirst); + + $storeManagerMock->expects($this->any()) + ->method('getWebsite') + ->willReturn($websiteMock); + + $storeMock = $this->getMockBuilder(Store::class) + ->setConstructorArgs([ + $this->createMock(\Magento\Framework\Model\Context::class), + $this->createMock(\Magento\Framework\Registry::class), + $this->createMock(\Magento\Framework\App\Cache\Type\Config::class), + $this->createMock(\Magento\Framework\Url::class), + $this->requestMock, + $this->createMock(\Magento\Config\Model\ResourceModel\Config\Data::class), + $this->configMock, + $storeManagerMock, + $this->filesystemMock, + $this->createMock(\Magento\Framework\Url\ModifierInterface::class), + $sessionMock, + $httpContextMock, + $this->createMock(\Magento\Framework\App\Config::class), + $currencyFactoryMock + ]) + ->onlyMethods(['getAvailableCurrencyCodes', 'getData', 'unsetData', 'setData']) + ->getMock(); + + $storeMock->expects($this->any()) + ->method('getAvailableCurrencyCodes') + ->willReturn([$currencyCodeFirst, $currencyCodeSecond]); + + // Expect unsetData to be called when currency code changes + $storeMock->expects($this->exactly(2)) + ->method('unsetData') + ->with('current_currency'); + + // First currency change + $storeMock->setCurrentCurrencyCode($currencyCodeFirst); + + // Second currency change - should clear cached currency + $storeMock->setCurrentCurrencyCode($currencyCodeSecond); + } + /** * @param Store $model */