Skip to content

Commit 79f4f31

Browse files
authored
Merge branch '2.4-develop' into purchase-order-graphql
2 parents 385b57a + c82c795 commit 79f4f31

File tree

14 files changed

+369
-24
lines changed

14 files changed

+369
-24
lines changed

app/code/Magento/Catalog/Model/Product/Attribute/Repository.php

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
namespace Magento\Catalog\Model\Product\Attribute;
88

99
use Laminas\Validator\Regex;
10-
use Magento\Eav\Api\Data\AttributeInterface;
10+
use Magento\Catalog\Api\Data\EavAttributeInterface;
1111
use Magento\Eav\Model\Entity\Attribute;
1212
use Magento\Framework\Exception\InputException;
1313
use Magento\Framework\Exception\NoSuchEntityException;
@@ -19,6 +19,8 @@
1919
*/
2020
class Repository implements \Magento\Catalog\Api\ProductAttributeRepositoryInterface
2121
{
22+
private const FILTERABLE_ALLOWED_INPUT_TYPES = ['date', 'datetime', 'text', 'textarea', 'texteditor'];
23+
2224
/**
2325
* @var \Magento\Catalog\Model\ResourceModel\Attribute
2426
*/
@@ -110,6 +112,22 @@ public function getList(\Magento\Framework\Api\SearchCriteriaInterface $searchCr
110112
*/
111113
public function save(\Magento\Catalog\Api\Data\ProductAttributeInterface $attribute)
112114
{
115+
if (in_array($attribute->getFrontendInput(), self::FILTERABLE_ALLOWED_INPUT_TYPES)) {
116+
if ($attribute->getIsFilterable()) {
117+
throw InputException::invalidFieldValue(
118+
EavAttributeInterface::IS_FILTERABLE,
119+
$attribute->getIsFilterable()
120+
);
121+
}
122+
123+
if ($attribute->getIsFilterableInSearch()) {
124+
throw InputException::invalidFieldValue(
125+
EavAttributeInterface::IS_FILTERABLE_IN_SEARCH,
126+
$attribute->getIsFilterableInSearch()
127+
);
128+
}
129+
}
130+
113131
$attribute->setEntityTypeId(
114132
$this->eavConfig
115133
->getEntityType(\Magento\Catalog\Api\Data\ProductAttributeInterface::ENTITY_TYPE_CODE)
@@ -156,7 +174,7 @@ public function save(\Magento\Catalog\Api\Data\ProductAttributeInterface $attrib
156174
);
157175
$attribute->setIsUserDefined(1);
158176
}
159-
if (!empty($attribute->getData(AttributeInterface::OPTIONS))) {
177+
if (!empty($attribute->getData(EavAttributeInterface::OPTIONS))) {
160178
$options = [];
161179
$sortOrder = 0;
162180
$default = [];

app/code/Magento/Catalog/Test/Mftf/Data/ProductAttributeData.xml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@
2020
<data key="is_wysiwyg_enabled">true</data>
2121
<data key="is_visible_in_advanced_search">true</data>
2222
<data key="is_visible_on_front">true</data>
23-
<data key="is_filterable">true</data>
24-
<data key="is_filterable_in_search">true</data>
23+
<data key="is_filterable">false</data>
24+
<data key="is_filterable_in_search">false</data>
2525
<data key="used_in_product_listing">true</data>
2626
<data key="is_used_for_promo_rules">true</data>
2727
<data key="is_comparable">true</data>
@@ -227,8 +227,8 @@
227227
<data key="is_visible">true</data>
228228
<data key="is_visible_in_advanced_search">true</data>
229229
<data key="is_visible_on_front">true</data>
230-
<data key="is_filterable">true</data>
231-
<data key="is_filterable_in_search">true</data>
230+
<data key="is_filterable">false</data>
231+
<data key="is_filterable_in_search">false</data>
232232
<data key="used_in_product_listing">true</data>
233233
<data key="is_used_for_promo_rules">true</data>
234234
<data key="is_comparable">true</data>
@@ -356,8 +356,8 @@
356356
<data key="is_wysiwyg_enabled">true</data>
357357
<data key="is_visible_in_advanced_search">true</data>
358358
<data key="is_visible_on_front">true</data>
359-
<data key="is_filterable">true</data>
360-
<data key="is_filterable_in_search">true</data>
359+
<data key="is_filterable">false</data>
360+
<data key="is_filterable_in_search">false</data>
361361
<data key="used_in_product_listing">true</data>
362362
<data key="is_used_for_promo_rules">true</data>
363363
<data key="is_comparable">true</data>

app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/RepositoryTest.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,42 @@ public function testSaveInputExceptionRequiredField()
241241
$this->model->save($attributeMock);
242242
}
243243

244+
/**
245+
* @param string $field
246+
* @param string $method
247+
* @param bool $filterable
248+
*
249+
* @return void
250+
* @dataProvider filterableDataProvider
251+
*/
252+
public function testSaveInputExceptionInvalidIsFilterableFieldValue(
253+
string $field,
254+
string $method,
255+
bool $filterable
256+
) : void {
257+
$this->expectException('Magento\Framework\Exception\InputException');
258+
$this->expectExceptionMessage('Invalid value of "'.$filterable.'" provided for the '.$field.' field.');
259+
$attributeMock = $this->createPartialMock(
260+
Attribute::class,
261+
['getFrontendInput', $method]
262+
);
263+
$attributeMock->expects($this->atLeastOnce())->method('getFrontendInput')->willReturn('text');
264+
$attributeMock->expects($this->atLeastOnce())->method($method)->willReturn($filterable);
265+
266+
$this->model->save($attributeMock);
267+
}
268+
269+
/**
270+
* @return array
271+
*/
272+
public function filterableDataProvider(): array
273+
{
274+
return [
275+
[ProductAttributeInterface::IS_FILTERABLE, 'getIsFilterable', true],
276+
[ProductAttributeInterface::IS_FILTERABLE_IN_SEARCH, 'getIsFilterableInSearch', true]
277+
];
278+
}
279+
244280
public function testSaveInputExceptionInvalidFieldValue()
245281
{
246282
$this->expectException('Magento\Framework\Exception\InputException');

app/code/Magento/CatalogImportExport/Model/Export/Product.php

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,7 +1086,7 @@ protected function collectRawData()
10861086

10871087
if ($storeId != Store::DEFAULT_STORE_ID
10881088
&& isset($data[$itemId][Store::DEFAULT_STORE_ID][$fieldName])
1089-
&& $data[$itemId][Store::DEFAULT_STORE_ID][$fieldName] == htmlspecialchars_decode($attrValue)
1089+
&& $data[$itemId][Store::DEFAULT_STORE_ID][$fieldName] == $attrValue
10901090
) {
10911091
continue;
10921092
}
@@ -1097,7 +1097,7 @@ protected function collectRawData()
10971097
$additionalAttributes[$fieldName] = $fieldName .
10981098
ImportProduct::PAIR_NAME_VALUE_SEPARATOR . $this->wrapValue($attrValue);
10991099
}
1100-
$data[$itemId][$storeId][$fieldName] = htmlspecialchars_decode($attrValue);
1100+
$data[$itemId][$storeId][$fieldName] = $attrValue;
11011101
}
11021102
} else {
11031103
$this->collectMultiselectValues($item, $code, $storeId);
@@ -1112,7 +1112,6 @@ protected function collectRawData()
11121112
}
11131113

11141114
if (!empty($additionalAttributes)) {
1115-
$additionalAttributes = array_map('htmlspecialchars_decode', $additionalAttributes);
11161115
$data[$itemId][$storeId][self::COL_ADDITIONAL_ATTRIBUTES] =
11171116
implode(Import::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR, $additionalAttributes);
11181117
} else {
@@ -1123,7 +1122,7 @@ protected function collectRawData()
11231122
$data[$itemId][$storeId][self::COL_STORE] = $storeCode;
11241123
$data[$itemId][$storeId][self::COL_ATTR_SET] = $this->_attrSetIdToName[$attrSetId];
11251124
$data[$itemId][$storeId][self::COL_TYPE] = $item->getTypeId();
1126-
$data[$itemId][$storeId][self::COL_SKU] = htmlspecialchars_decode($item->getSku());
1125+
$data[$itemId][$storeId][self::COL_SKU] = $item->getSku();
11271126
$data[$itemId][$storeId]['store_id'] = $storeId;
11281127
$data[$itemId][$storeId]['product_id'] = $itemId;
11291128
$data[$itemId][$storeId]['product_link_id'] = $productLinkId;

app/code/Magento/Customer/Controller/Section/Load.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class Load extends \Magento\Framework\App\Action\Action implements HttpGetAction
2424
/**
2525
* @var Identifier
2626
* @deprecated 101.0.0
27+
* @see Used only for backward compatibility for do not break current class implementation with its dependencies
2728
*/
2829
protected $sectionIdentifier;
2930

@@ -69,7 +70,9 @@ public function execute()
6970
$resultJson->setHeader('Pragma', 'no-cache', true);
7071
try {
7172
$sectionNames = $this->getRequest()->getParam('sections');
72-
$sectionNames = $sectionNames ? array_unique(\explode(',', $sectionNames)) : null;
73+
$sectionNames = $sectionNames
74+
? array_unique(is_array($sectionNames) ? $sectionNames : explode(',', $sectionNames))
75+
: null;
7376

7477
$forceNewSectionTimestamp = $this->getRequest()->getParam('force_new_section_timestamp');
7578
if ('false' === $forceNewSectionTimestamp) {

app/code/Magento/Customer/Test/Unit/Controller/Section/LoadTest.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,12 @@ public function executeDataProvider()
146146
'sectionNamesAsArray' => null,
147147
'forceNewTimestamp' => false
148148
],
149+
[
150+
'sectionNames' => ['sectionName1', 'sectionName2', 'sectionName3'],
151+
'forceNewSectionTimestamp' => 'forceNewSectionTimestamp',
152+
'sectionNamesAsArray' => ['sectionName1', 'sectionName2', 'sectionName3'],
153+
'forceNewTimestamp' => true
154+
],
149155
];
150156
}
151157

app/code/Magento/CustomerGraphQl/Model/Resolver/ChangePassword.php

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@
88
namespace Magento\CustomerGraphQl\Model\Resolver;
99

1010
use Magento\Customer\Api\AccountManagementInterface;
11+
use Magento\Customer\Model\EmailNotificationInterface;
1112
use Magento\CustomerGraphQl\Model\Customer\CheckCustomerPassword;
1213
use Magento\CustomerGraphQl\Model\Customer\ExtractCustomerData;
1314
use Magento\CustomerGraphQl\Model\Customer\GetCustomer;
15+
use Magento\Framework\App\ObjectManager;
1416
use Magento\Framework\Exception\LocalizedException;
1517
use Magento\Framework\GraphQl\Config\Element\Field;
1618
use Magento\Framework\GraphQl\Exception\GraphQlAuthorizationException;
@@ -44,22 +46,31 @@ class ChangePassword implements ResolverInterface
4446
*/
4547
private $extractCustomerData;
4648

49+
/**
50+
* @var EmailNotificationInterface
51+
*/
52+
private $emailNotification;
53+
4754
/**
4855
* @param GetCustomer $getCustomer
4956
* @param CheckCustomerPassword $checkCustomerPassword
5057
* @param AccountManagementInterface $accountManagement
5158
* @param ExtractCustomerData $extractCustomerData
59+
* @param EmailNotificationInterface|null $emailNotification
5260
*/
5361
public function __construct(
5462
GetCustomer $getCustomer,
5563
CheckCustomerPassword $checkCustomerPassword,
5664
AccountManagementInterface $accountManagement,
57-
ExtractCustomerData $extractCustomerData
65+
ExtractCustomerData $extractCustomerData,
66+
?EmailNotificationInterface $emailNotification = null
5867
) {
5968
$this->getCustomer = $getCustomer;
6069
$this->checkCustomerPassword = $checkCustomerPassword;
6170
$this->accountManagement = $accountManagement;
6271
$this->extractCustomerData = $extractCustomerData;
72+
$this->emailNotification = $emailNotification
73+
?? ObjectManager::getInstance()->get(EmailNotificationInterface::class);
6374
}
6475

6576
/**
@@ -89,12 +100,25 @@ public function resolve(
89100
$this->checkCustomerPassword->execute($args['currentPassword'], $customerId);
90101

91102
try {
92-
$this->accountManagement->changePasswordById($customerId, $args['currentPassword'], $args['newPassword']);
103+
$isPasswordChanged = $this->accountManagement->changePasswordById(
104+
$customerId,
105+
$args['currentPassword'],
106+
$args['newPassword']
107+
);
93108
} catch (LocalizedException $e) {
94109
throw new GraphQlInputException(__($e->getMessage()), $e);
95110
}
96111

97112
$customer = $this->getCustomer->execute($context);
113+
114+
if ($isPasswordChanged) {
115+
$this->emailNotification->credentialsChanged(
116+
$customer,
117+
$customer->getEmail(),
118+
$isPasswordChanged
119+
);
120+
}
121+
98122
return $this->extractCustomerData->execute($customer);
99123
}
100124
}

app/code/Magento/Quote/Model/Quote/Item/Compare.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
*/
66
namespace Magento\Quote\Model\Quote\Item;
77

8-
use Magento\Quote\Model\Quote\Item;
9-
use Magento\Framework\Serialize\Serializer\Json;
108
use Magento\Framework\App\ObjectManager;
119
use Magento\Framework\Serialize\JsonValidator;
10+
use Magento\Framework\Serialize\Serializer\Json;
11+
use Magento\Quote\Model\Quote\Item;
1212

1313
/**
1414
* Compare quote items
@@ -68,6 +68,10 @@ protected function getOptionValues($value)
6868
*/
6969
public function compare(Item $target, Item $compared)
7070
{
71+
if ($target->getSku() !== null && $target->getSku() === $compared->getSku()) {
72+
return true;
73+
}
74+
7175
if ($target->getProductId() != $compared->getProductId()) {
7276
return false;
7377
}

app/code/Magento/Quote/Test/Unit/Model/Quote/Item/CompareTest.php

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,12 @@ protected function setUp(): void
6161
);
6262
$this->itemMock = $this->getMockBuilder(Item::class)
6363
->addMethods(['getProductId'])
64-
->onlyMethods(['__wakeup', 'getOptions', 'getOptionsByCode'])
64+
->onlyMethods(['__wakeup', 'getOptions', 'getOptionsByCode', 'getSku'])
6565
->setConstructorArgs($constrArgs)
6666
->getMock();
6767
$this->comparedMock = $this->getMockBuilder(Item::class)
6868
->addMethods(['getProductId'])
69-
->onlyMethods(['__wakeup', 'getOptions', 'getOptionsByCode'])
69+
->onlyMethods(['__wakeup', 'getOptions', 'getOptionsByCode', 'getSku'])
7070
->setConstructorArgs($constrArgs)
7171
->getMock();
7272
$this->optionMock = $this->getMockBuilder(Option::class)
@@ -236,4 +236,19 @@ public function testCompareItemWithoutOptionWithCompared()
236236
->willReturn([]);
237237
$this->assertFalse($this->helper->compare($this->itemMock, $this->comparedMock));
238238
}
239+
240+
/**
241+
* test compare two items- when configurable products has assigned sku of its selected variant
242+
*/
243+
public function testCompareConfigurableProductAndItsVariant()
244+
{
245+
$this->itemMock->expects($this->exactly(2))
246+
->method('getSku')
247+
->willReturn('cr1-r');
248+
$this->comparedMock->expects($this->once())
249+
->method('getSku')
250+
->willReturn('cr1-r');
251+
252+
$this->assertTrue($this->helper->compare($this->itemMock, $this->comparedMock));
253+
}
239254
}

app/code/Magento/User/view/adminhtml/email/password_reset_confirmation.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
{{trans "If you requested this change, reset your password here:"}}
2222

23-
{{store url="admin/auth/resetpassword/" _query_id=$user.user_id _query_token=$user.rp_token _nosid=1}}
23+
{{store url="admin/auth/resetpassword/" _type="web" _query_id=$user.user_id _query_token=$user.rp_token _nosid=1 }}
2424

2525
{{trans "If you did not make this request, you can ignore this email and your password will remain the same."}}
2626

0 commit comments

Comments
 (0)