Skip to content

Commit ffe2962

Browse files
[Magento Community Engineering] Community Contributions - 2.4-develop
- merged latest code from mainline branch
2 parents 7e174b6 + cac512f commit ffe2962

File tree

11 files changed

+568
-32
lines changed

11 files changed

+568
-32
lines changed

app/code/Magento/Customer/Model/Customer.php

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
use Magento\Store\Model\ScopeInterface;
2222
use Magento\Framework\App\ObjectManager;
2323
use Magento\Framework\Math\Random;
24+
use Magento\Framework\Indexer\IndexerInterface;
2425

2526
/**
2627
* Customer model
@@ -62,8 +63,7 @@ class Customer extends \Magento\Framework\Model\AbstractModel
6263
const XML_PATH_RESET_PASSWORD_TEMPLATE = 'customer/password/reset_password_template';
6364

6465
/**
65-
* @deprecated
66-
* @see AccountConfirmation::XML_PATH_IS_CONFIRM
66+
* @deprecated @see \Magento\Customer\Model\AccountConfirmation::XML_PATH_IS_CONFIRM
6767
*/
6868
const XML_PATH_IS_CONFIRM = 'customer/create_account/confirm';
6969

@@ -227,6 +227,11 @@ class Customer extends \Magento\Framework\Model\AbstractModel
227227
*/
228228
private $storedAddress;
229229

230+
/**
231+
* @var IndexerInterface|null
232+
*/
233+
private $indexer;
234+
230235
/**
231236
* @param \Magento\Framework\Model\Context $context
232237
* @param \Magento\Framework\Registry $registry
@@ -304,6 +309,19 @@ public function __construct(
304309
);
305310
}
306311

312+
/**
313+
* Micro-caching optimization
314+
*
315+
* @return IndexerInterface
316+
*/
317+
private function getIndexer() : IndexerInterface
318+
{
319+
if ($this->indexer === null) {
320+
$this->indexer = $this->indexerRegistry->get(self::CUSTOMER_GRID_INDEXER_ID);
321+
}
322+
return $this->indexer;
323+
}
324+
307325
/**
308326
* Initialize customer model
309327
*
@@ -985,6 +1003,7 @@ public function getSharedWebsiteIds()
9851003
*/
9861004
public function getAttributeSetId()
9871005
{
1006+
// phpstan:ignore "Call to an undefined static method*"
9881007
return parent::getAttributeSetId() ?: CustomerMetadataInterface::ATTRIBUTE_SET_ID_CUSTOMER;
9891008
}
9901009

@@ -1075,8 +1094,7 @@ public function resetErrors()
10751094
*/
10761095
public function afterSave()
10771096
{
1078-
$indexer = $this->indexerRegistry->get(self::CUSTOMER_GRID_INDEXER_ID);
1079-
if ($indexer->getState()->getStatus() == StateInterface::STATUS_VALID) {
1097+
if ($this->getIndexer()->getState()->getStatus() == StateInterface::STATUS_VALID) {
10801098
$this->_getResource()->addCommitCallback([$this, 'reindex']);
10811099
}
10821100
return parent::afterSave();
@@ -1100,9 +1118,7 @@ public function afterDeleteCommit()
11001118
*/
11011119
public function reindex()
11021120
{
1103-
/** @var \Magento\Framework\Indexer\IndexerInterface $indexer */
1104-
$indexer = $this->indexerRegistry->get(self::CUSTOMER_GRID_INDEXER_ID);
1105-
$indexer->reindexRow($this->getId());
1121+
$this->getIndexer()->reindexRow($this->getId());
11061122
}
11071123

11081124
/**

app/code/Magento/Customer/Setup/RecurringData.php

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
namespace Magento\Customer\Setup;
88

99
use Magento\Framework\Indexer\IndexerRegistry;
10+
use Magento\Framework\Indexer\StateInterface;
1011
use Magento\Framework\Setup\InstallDataInterface;
1112
use Magento\Framework\Setup\ModuleContextInterface;
1213
use Magento\Framework\Setup\ModuleDataSetupInterface;
@@ -27,17 +28,34 @@ class RecurringData implements InstallDataInterface
2728
*
2829
* @param IndexerRegistry $indexerRegistry
2930
*/
30-
public function __construct(IndexerRegistry $indexerRegistry)
31-
{
31+
public function __construct(
32+
IndexerRegistry $indexerRegistry
33+
) {
3234
$this->indexerRegistry = $indexerRegistry;
3335
}
3436

3537
/**
36-
* {@inheritdoc}
38+
* @inheritDoc
3739
*/
3840
public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
3941
{
40-
$indexer = $this->indexerRegistry->get(Customer::CUSTOMER_GRID_INDEXER_ID);
41-
$indexer->reindexAll();
42+
if ($this->isNeedToDoReindex($setup)) {
43+
$indexer = $this->indexerRegistry->get(Customer::CUSTOMER_GRID_INDEXER_ID);
44+
$indexer->reindexAll();
45+
}
46+
}
47+
48+
/**
49+
* Check is re-index needed
50+
*
51+
* @param ModuleDataSetupInterface $setup
52+
* @return bool
53+
*/
54+
private function isNeedToDoReindex(ModuleDataSetupInterface $setup) : bool
55+
{
56+
return !$setup->tableExists('customer_grid_flat')
57+
|| $this->indexerRegistry->get(Customer::CUSTOMER_GRID_INDEXER_ID)
58+
->getState()
59+
->getStatus() == StateInterface::STATUS_INVALID;
4260
}
4361
}
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Customer\Test\Unit\Setup;
9+
10+
use Magento\Framework\Indexer\IndexerInterface;
11+
use Magento\Framework\Indexer\StateInterface;
12+
use Magento\Framework\Indexer\IndexerRegistry;
13+
use Magento\Framework\Setup\ModuleDataSetupInterface;
14+
use Magento\Framework\Setup\ModuleContextInterface;
15+
use Magento\Customer\Model\Customer;
16+
use Magento\Customer\Setup\RecurringData;
17+
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
18+
19+
/**
20+
* Test for recurring data
21+
*/
22+
class RecurringDataTest extends \PHPUnit\Framework\TestCase
23+
{
24+
/**
25+
* @var ObjectManagerHelper
26+
*/
27+
private $objectManagerHelper;
28+
29+
/**
30+
* @var IndexerInterface|\PHPUnit_Framework_MockObject_MockObject
31+
*/
32+
private $indexer;
33+
34+
/**
35+
* @var StateInterface|\PHPUnit_Framework_MockObject_MockObject
36+
*/
37+
private $state;
38+
39+
/**
40+
* @var IndexerRegistry|\PHPUnit_Framework_MockObject_MockObject
41+
*/
42+
private $indexerRegistry;
43+
44+
/**
45+
* @var ModuleDataSetupInterface|\PHPUnit_Framework_MockObject_MockObject
46+
*/
47+
private $setup;
48+
49+
/**
50+
* @var ModuleContextInterface|\PHPUnit_Framework_MockObject_MockObject
51+
*/
52+
private $context;
53+
54+
/**
55+
* @var RecurringData
56+
*/
57+
private $recurringData;
58+
59+
/**
60+
* @inheritdoc
61+
*/
62+
protected function setUp()
63+
{
64+
$this->objectManagerHelper = new ObjectManagerHelper($this);
65+
$this->state = $this->getMockBuilder(StateInterface::class)
66+
->setMethods(['getStatus'])
67+
->getMockForAbstractClass();
68+
$this->indexer = $this->getMockBuilder(IndexerInterface::class)
69+
->setMethods(['getState', 'reindexAll'])
70+
->getMockForAbstractClass();
71+
$this->indexer->expects($this->any())
72+
->method('getState')
73+
->willReturn($this->state);
74+
$this->indexerRegistry = $this->getMockBuilder(IndexerRegistry::class)
75+
->disableOriginalConstructor()
76+
->setMethods(['get'])
77+
->getMock();
78+
$this->indexerRegistry->expects($this->any())
79+
->method('get')
80+
->with(Customer::CUSTOMER_GRID_INDEXER_ID)
81+
->willReturn($this->indexer);
82+
$this->setup = $this->getMockBuilder(ModuleDataSetupInterface::class)
83+
->setMethods(['tableExists'])
84+
->getMockForAbstractClass();
85+
$this->context = $this->getMockBuilder(ModuleContextInterface::class)
86+
->getMockForAbstractClass();
87+
88+
$this->recurringData = $this->objectManagerHelper->getObject(
89+
RecurringData::class,
90+
[
91+
'indexerRegistry' => $this->indexerRegistry
92+
]
93+
);
94+
}
95+
96+
/**
97+
* @param bool $isTableExists
98+
* @param string $indexerState
99+
* @param int $countReindex
100+
* @return void
101+
* @dataProvider installDataProvider
102+
*/
103+
public function testInstall(bool $isTableExists, string $indexerState, int $countReindex)
104+
{
105+
$this->setup->expects($this->any())
106+
->method('tableExists')
107+
->with('customer_grid_flat')
108+
->willReturn($isTableExists);
109+
$this->state->expects($this->any())
110+
->method('getStatus')
111+
->willReturn($indexerState);
112+
$this->indexer->expects($this->exactly($countReindex))
113+
->method('reindexAll');
114+
$this->recurringData->install($this->setup, $this->context);
115+
}
116+
117+
/**
118+
* @return array
119+
*/
120+
public function installDataProvider() : array
121+
{
122+
return [
123+
[true, StateInterface::STATUS_INVALID, 1],
124+
[false, StateInterface::STATUS_INVALID, 1],
125+
[true, StateInterface::STATUS_VALID, 0],
126+
[false, StateInterface::STATUS_VALID, 1],
127+
];
128+
}
129+
}

app/code/Magento/SalesRule/Model/Rule/Action/Discount/CartFixed.php

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -64,25 +64,13 @@ public function calculate($rule, $item, $qty)
6464
$ruleTotals = $this->validator->getRuleItemTotalsInfo($rule->getId());
6565

6666
$quote = $item->getQuote();
67-
$address = $item->getAddress();
6867

6968
$itemPrice = $this->validator->getItemPrice($item);
7069
$baseItemPrice = $this->validator->getItemBasePrice($item);
7170
$itemOriginalPrice = $this->validator->getItemOriginalPrice($item);
7271
$baseItemOriginalPrice = $this->validator->getItemBaseOriginalPrice($item);
7372

74-
/**
75-
* prevent applying whole cart discount for every shipping order, but only for first order
76-
*/
77-
if ($quote->getIsMultiShipping()) {
78-
$usedForAddressId = $this->getCartFixedRuleUsedForAddress($rule->getId());
79-
if ($usedForAddressId && $usedForAddressId != $address->getId()) {
80-
return $discountData;
81-
} else {
82-
$this->setCartFixedRuleUsedForAddress($rule->getId(), $address->getId());
83-
}
84-
}
85-
$cartRules = $address->getCartFixedRules();
73+
$cartRules = $quote->getCartFixedRules();
8674
if (!isset($cartRules[$rule->getId()])) {
8775
$cartRules[$rule->getId()] = $rule->getDiscountAmount();
8876
}
@@ -122,14 +110,15 @@ public function calculate($rule, $item, $qty)
122110
$discountData->setOriginalAmount(min($itemOriginalPrice * $qty, $quoteAmount));
123111
$discountData->setBaseOriginalAmount($this->priceCurrency->round($baseItemOriginalPrice));
124112
}
125-
$address->setCartFixedRules($cartRules);
113+
$quote->setCartFixedRules($cartRules);
126114

127115
return $discountData;
128116
}
129117

130118
/**
131119
* Set information about usage cart fixed rule by quote address
132120
*
121+
* @deprecated should be removed as it is not longer used
133122
* @param int $ruleId
134123
* @param int $itemId
135124
* @return void
@@ -142,6 +131,7 @@ protected function setCartFixedRuleUsedForAddress($ruleId, $itemId)
142131
/**
143132
* Retrieve information about usage cart fixed rule by quote address
144133
*
134+
* @deprecated should be removed as it is not longer used
145135
* @param int $ruleId
146136
* @return int|null
147137
*/
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\SalesRule\Model\Rule;
9+
10+
use Magento\SalesRule\Model\Spi\QuoteResetAppliedRulesInterface;
11+
12+
/**
13+
* Reset applied rules to quote
14+
*/
15+
class QuoteResetAppliedRules implements QuoteResetAppliedRulesInterface
16+
{
17+
/**
18+
* @inheritDoc
19+
*/
20+
public function execute(\Magento\Quote\Api\Data\CartInterface $quote): void
21+
{
22+
$quote->setCartFixedRules([]);
23+
}
24+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\SalesRule\Model\Spi;
9+
10+
/**
11+
* Reset applied rules to quote
12+
*/
13+
interface QuoteResetAppliedRulesInterface
14+
{
15+
/**
16+
* Reset applied rules to quote
17+
*
18+
* @param \Magento\Quote\Api\Data\CartInterface $quote
19+
* @return void
20+
*/
21+
public function execute(\Magento\Quote\Api\Data\CartInterface $quote): void;
22+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\SalesRule\Observer;
9+
10+
use Magento\Framework\Event\Observer;
11+
use Magento\Framework\Event\ObserverInterface;
12+
use Magento\SalesRule\Model\Spi\QuoteResetAppliedRulesInterface;
13+
14+
/**
15+
* Reset applied rules to quote before collecting totals
16+
*/
17+
class QuoteResetAppliedRulesObserver implements ObserverInterface
18+
{
19+
/**
20+
* @var QuoteResetAppliedRulesInterface
21+
*/
22+
private $resetAppliedRules;
23+
24+
/**
25+
* @param QuoteResetAppliedRulesInterface $resetAppliedRules
26+
*/
27+
public function __construct(QuoteResetAppliedRulesInterface $resetAppliedRules)
28+
{
29+
$this->resetAppliedRules = $resetAppliedRules;
30+
}
31+
32+
/**
33+
* @inheritDoc
34+
*/
35+
public function execute(Observer $observer)
36+
{
37+
$this->resetAppliedRules->execute($observer->getQuote());
38+
}
39+
}

0 commit comments

Comments
 (0)