Skip to content

Commit 71d7f73

Browse files
committed
Merge branch '2.4-develop' of github.com:magento-gl/magento2ce into ACQE-6430-develop
2 parents 06c99ed + 651928c commit 71d7f73

File tree

145 files changed

+3716
-624
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

145 files changed

+3716
-624
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
/**
4+
* Copyright © Magento, Inc. All rights reserved.
5+
* See COPYING.txt for license details.
6+
* Copyright 2024 Adobe
7+
* All Rights Reserved.
8+
*/
9+
-->
10+
<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
11+
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/actionGroupSchema.xsd">
12+
<actionGroup name="AdminAddRestrictedRoleForGlobalSearchActionGroup" extends="AdminCreateRoleActionGroup">
13+
<remove keyForRemoval="navigateToNewRole"/>
14+
<remove keyForRemoval="waitForPageLoad1"/>
15+
<remove keyForRemoval="fillRoleName"/>
16+
<remove keyForRemoval="enterPassword"/>
17+
<remove keyForRemoval="clickRoleResourcesTab"/>
18+
<remove keyForRemoval="waitForScopeSelection"/>
19+
<remove keyForRemoval="clickSaveRoleButton"/>
20+
<remove keyForRemoval="waitForPageLoad2"/>
21+
<remove keyForRemoval="clickCheckbox"/>
22+
<scrollTo selector="{{AdminEditRoleInfoSection.blockName('restrictedRole')}}" x="0" y="-120" stepKey="scrollToResourceElement" after="selectResourceAccessCustom"/>
23+
<click stepKey="clickTFACheckbox" selector="{{AdminEditRoleInfoSection.checkboxByRole('Magento_TwoFactorAuth::tfa')}}" after="waitForTfaRole"/>
24+
</actionGroup>
25+
</actionGroups>

app/code/Magento/Backend/Test/Mftf/Test/AdminLoginWithRestrictPermissionTest.xml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
/**
44
* Copyright © Magento, Inc. All rights reserved.
55
* See COPYING.txt for license details.
6+
* Copyright 2024 Adobe
7+
* All Rights Reserved.
68
*/
79
-->
810

@@ -17,8 +19,8 @@
1719
<severity value="MAJOR" />
1820
<description value="Check login with restrict role."/>
1921
<group value="login"/>
20-
<group value="pr_exclude"/>
2122
<group value="cloud"/>
23+
<group value="pr_exclude"/>
2224
</annotations>
2325

2426
<before>
@@ -29,7 +31,7 @@
2931
<argument name="restrictedRole" value="Global Search"/>
3032
</actionGroup>
3133
<actionGroup ref="AdminUserClickRoleResourceTabActionGroup" stepKey="switchToRoleResourceTab"/>
32-
<actionGroup ref="AdminAddRestrictedRoleActionGroup" stepKey="addRestrictedRoleStores">
34+
<actionGroup ref="AdminAddRestrictedRoleForGlobalSearchActionGroup" stepKey="addRestrictedRoleStores">
3335
<argument name="User" value="adminRole"/>
3436
<argument name="restrictedRole" value="Global Search"/>
3537
</actionGroup>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
/**
4+
* Copyright 2024 Adobe
5+
* All Rights Reserved.
6+
*/
7+
-->
8+
9+
<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
10+
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
11+
<test name="StorefrontVerifyDiscountOnDynamicBundleProductDifferentCartRulesTest">
12+
<annotations>
13+
<features value="Bundle"/>
14+
<stories value="Discount on dynamic bundle products with different Cart Rules"/>
15+
<title value="Verify dynamic bundle product prices with different Cart Rules on storefront"/>
16+
<description value="Verify discount on dynamic-priced Bundle Product when associated Products are assigned to Categories with different Cart Rules"/>
17+
<severity value="MAJOR"/>
18+
<testCaseId value="AC-4709"/>
19+
</annotations>
20+
<before>
21+
<createData entity="SimpleSubCategory" stepKey="createFirstCategory"/>
22+
<createData entity="SimpleSubCategory" stepKey="createSecondCategory"/>
23+
<!--Create two simple product-->
24+
<createData entity="ApiSimpleProduct" stepKey="simpleProduct1">
25+
<requiredEntity createDataKey="createFirstCategory"/>
26+
<field key="price">99.99</field>
27+
</createData>
28+
<createData entity="ApiSimpleProduct" stepKey="simpleProduct2">
29+
<requiredEntity createDataKey="createSecondCategory"/>
30+
<field key="price">34.49</field>
31+
</createData>
32+
<!--Create Bundle product-->
33+
<createData entity="ApiBundleProductPriceViewRange" stepKey="createBundleProduct">
34+
<requiredEntity createDataKey="createFirstCategory"/>
35+
</createData>
36+
<createData entity="MultipleSelectOption" stepKey="createBundleOption1">
37+
<requiredEntity createDataKey="createBundleProduct"/>
38+
<field key="required">true</field>
39+
</createData>
40+
<createData entity="ApiBundleLink" stepKey="linkOptionToProduct">
41+
<requiredEntity createDataKey="createBundleProduct"/>
42+
<requiredEntity createDataKey="createBundleOption1"/>
43+
<requiredEntity createDataKey="simpleProduct1"/>
44+
</createData>
45+
<createData entity="ApiBundleLink" stepKey="linkOptionToProduct2">
46+
<requiredEntity createDataKey="createBundleProduct"/>
47+
<requiredEntity createDataKey="createBundleOption1"/>
48+
<requiredEntity createDataKey="simpleProduct2"/>
49+
</createData>
50+
</before>
51+
<after>
52+
<deleteData createDataKey="createFirstCategory" stepKey="deleteFirstCategory"/>
53+
<deleteData createDataKey="createSecondCategory" stepKey="deleteSecondCategory"/>
54+
<deleteData createDataKey="simpleProduct1" stepKey="deleteSimpleProduct1"/>
55+
<deleteData createDataKey="simpleProduct2" stepKey="deleteSimpleProduct2"/>
56+
<deleteData createDataKey="createBundleProduct" stepKey="deleteBundleProduct"/>
57+
<actionGroup ref="DeleteCartPriceRuleByName" stepKey="deleteCartPriceRule">
58+
<argument name="ruleName" value="{{CustomSalesRuleWithNoCouponCode.name}}"/>
59+
</actionGroup>
60+
<actionGroup ref="AdminLogoutActionGroup" stepKey="logout"/>
61+
</after>
62+
<actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/>
63+
<!-- Create cart price rule -->
64+
<actionGroup ref="AdminCreateCartPriceRuleActionGroup" stepKey="createCartPriceRule">
65+
<argument name="ruleName" value="CustomSalesRuleWithNoCouponCode"/>
66+
</actionGroup>
67+
<!-- Search and go to cart price rule page -->
68+
<actionGroup ref="AdminFilterCartPriceRuleActionGroup" stepKey="filterCreatedCartPriceRule">
69+
<argument name="ruleName" value="CustomSalesRuleWithNoCouponCode.name"/>
70+
</actionGroup>
71+
<actionGroup ref="AdminCreateCustomConditionInCartPriceRuleActionGroup" stepKey="createCustomCondition"/>
72+
<actionGroup ref="AssertCartPriceRuleSuccessSaveMessageActionGroup" stepKey="saveAndAssertCartPriceRuleSuccessSaveMessage"/>
73+
<!-- Open Bundle Product page on storefront-->
74+
<actionGroup ref="StorefrontOpenProductPageActionGroup" stepKey="openBundleProductPage">
75+
<argument name="productUrl" value="$createBundleProduct.custom_attributes[url_key]$"/>
76+
</actionGroup>
77+
<!-- Click on customize And Add To Cart Button -->
78+
<actionGroup ref="StorefrontSelectCustomizeAndAddToTheCartButtonActionGroup" stepKey="clickOnCustomizeAndAddToCartButton"/>
79+
<!-- Select Two Products, enter the quantity and add product to the cart -->
80+
<selectOption selector="{{StorefrontBundledSection.multiSelectOption}}" parameterArray="[$$simpleProduct1.name$$ +$99.99, $$simpleProduct2.name$$ +$34.49]" stepKey="selectOptions"/>
81+
<actionGroup ref="StorefrontEnterProductQuantityAndAddToTheCartActionGroup" stepKey="enterProductQuantityAndAddToTheCart">
82+
<argument name="quantity" value="1"/>
83+
</actionGroup>
84+
<!-- Go to shopping cart page -->
85+
<actionGroup ref="StorefrontCartPageOpenActionGroup" stepKey="openShoppingCartPage"/>
86+
<actionGroup ref="AssertStorefrontCartDiscountActionGroup" stepKey="seeDiscountTotal">
87+
<argument name="discount" value="13.45"/>
88+
</actionGroup>
89+
<!-- Search and go to cart price rule page and remove condition-->
90+
<actionGroup ref="AdminOpenCartPriceRulesPageActionGroup" stepKey="goToCartPriceRulePage"/>
91+
<actionGroup ref="AdminFilterCartPriceRuleActionGroup" stepKey="filterCartPriceRule">
92+
<argument name="ruleName" value="CustomSalesRuleWithNoCouponCode.name"/>
93+
</actionGroup>
94+
<scrollTo selector="{{AdminCartPriceRulesFormSection.conditionsHeader}}" stepKey="scrollToConditionsHeader"/>
95+
<conditionalClick selector="{{AdminCartPriceRulesFormSection.conditionsHeader}}" dependentSelector="{{AdminCartPriceRulesFormSection.conditionsHeader}}" visible="true" stepKey="clickToExpandConditions"/>
96+
<waitForElementClickable selector="{{AdminCartPriceRulesFormSection.removeCondition('1--1')}}" stepKey="waitForRemoveToBeClickable"/>
97+
<click selector="{{AdminCartPriceRulesFormSection.removeCondition('1--1')}}" stepKey="removeCondition"/>
98+
<actionGroup ref="AssertCartPriceRuleSuccessSaveMessageActionGroup" stepKey="saveCartPriceRuleSuccessSaveMessage"/>
99+
<!-- Go to shopping cart page -->
100+
<actionGroup ref="StorefrontCartPageOpenActionGroup" stepKey="goToShoppingCartPage"/>
101+
<actionGroup ref="AssertStorefrontCartDiscountActionGroup" stepKey="checkDiscount">
102+
<argument name="discount" value="13.45"/>
103+
</actionGroup>
104+
<!-- Assign category 1 to simple product 2 and unAssign category2 -->
105+
<actionGroup ref="AdminProductPageOpenByIdActionGroup" stepKey="OpenSimpleProductPage">
106+
<argument name="productId" value="$$simpleProduct2.id$$"/>
107+
</actionGroup>
108+
<waitForPageLoad stepKey="waitForProductPageLoad"/>
109+
<actionGroup ref="AdminUnassignCategoryOnProductAndSaveActionGroup" stepKey="unAssignCategoryTwo">
110+
<argument name="categoryName" value="$$createSecondCategory.name$$"/>
111+
</actionGroup>
112+
<createData entity="AssignProductToCategory" stepKey="assignCategoryOne">
113+
<requiredEntity createDataKey="createFirstCategory"/>
114+
<requiredEntity createDataKey="simpleProduct2"/>
115+
</createData>
116+
<!-- Search and go to cart price rule page and add condition in action tab -->
117+
<actionGroup ref="AdminOpenCartPriceRulesPageActionGroup" stepKey="againOpenCartPriceRulePage"/>
118+
<actionGroup ref="AdminFilterCartPriceRuleActionGroup" stepKey="againFilterCartPriceRule">
119+
<argument name="ruleName" value="CustomSalesRuleWithNoCouponCode.name"/>
120+
</actionGroup>
121+
<actionGroup ref="AdminCreateCustomConditionInActionTabInCartPriceRuleActionGroup" stepKey="createConditionInActionsTab"/>
122+
<actionGroup ref="AssertCartPriceRuleSuccessSaveMessageActionGroup" stepKey="saveCartPriceRule"/>
123+
<actionGroup ref="CliIndexerReindexActionGroup" stepKey="reindex">
124+
<argument name="indices" value="catalogsearch_fulltext catalog_category_product catalog_product_price catalogrule_rule"/>
125+
</actionGroup>
126+
<actionGroup ref="CliCacheCleanActionGroup" stepKey="cleanCache">
127+
<argument name="tags" value="config full_page"/>
128+
</actionGroup>
129+
<!-- Go to shopping cart page -->
130+
<actionGroup ref="StorefrontCartPageOpenActionGroup" stepKey="againGoToShoppingCartPage"/>
131+
<waitForElementNotVisible selector="{{CheckoutCartSummarySection.discountLabel}}" stepKey="discountIsNotApplied"/>
132+
</test>
133+
</tests>

app/code/Magento/Catalog/Model/CategoryRepository.php

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
<?php
22
/**
3-
*
4-
* Copyright © Magento, Inc. All rights reserved.
5-
* See COPYING.txt for license details.
3+
* Copyright 2014 Adobe
4+
* All Rights Reserved.
65
*/
76

87
namespace Magento\Catalog\Model;
@@ -149,7 +148,7 @@ public function save(CategoryInterface $category)
149148
*/
150149
public function get($categoryId, $storeId = null)
151150
{
152-
$cacheKey = $storeId ?? 'all';
151+
$cacheKey = $storeId ?? $this->storeManager->getStore()->getId();
153152
if (!isset($this->instances[$categoryId][$cacheKey])) {
154153
/** @var Category $category */
155154
$category = $this->categoryFactory->create();
@@ -231,7 +230,7 @@ protected function validateCategory(Category $category)
231230
* Lazy loader for the converter.
232231
*
233232
* @return ExtensibleDataObjectConverter
234-
*
233+
* phpcs:disable Magento2.Annotation.MethodAnnotationStructure
235234
* @deprecated 101.0.0
236235
* @see we don't recommend this approach anymore
237236
*/

app/code/Magento/Catalog/Model/ResourceModel/Category.php

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?php
22
/**
3-
* Copyright © Magento, Inc. All rights reserved.
4-
* See COPYING.txt for license details.
3+
* Copyright 2011 Adobe
4+
* All Rights Reserved.
55
*/
66

77
/**
@@ -37,8 +37,6 @@ class Category extends AbstractResource implements ResetAfterRequestInterface
3737
protected $_tree;
3838

3939
/**
40-
* Catalog products table name
41-
*
4240
* @var string
4341
*/
4442
protected $_categoryProductTable;
@@ -49,15 +47,11 @@ class Category extends AbstractResource implements ResetAfterRequestInterface
4947
private $entitiesWhereAttributesIs;
5048

5149
/**
52-
* Id of 'is_active' category attribute
53-
*
5450
* @var int
5551
*/
5652
protected $_isActiveAttributeId = null;
5753

5854
/**
59-
* Id of store
60-
*
6155
* @var int
6256
*/
6357
protected $_storeId = null;
@@ -455,7 +449,7 @@ protected function _saveCategoryProducts($category)
455449
'position' => (int)$position,
456450
];
457451
}
458-
$connection->insertMultiple($this->getCategoryProductTable(), $data);
452+
$connection->insertOnDuplicate($this->getCategoryProductTable(), $data, ['position']);
459453
}
460454

461455
/**

app/code/Magento/Catalog/Model/ResourceModel/Category/Collection.php

Lines changed: 52 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?php
22
/**
3-
* Copyright © Magento, Inc. All rights reserved.
4-
* See COPYING.txt for license details.
3+
* Copyright 2011 Adobe
4+
* All Rights Reserved.
55
*/
66
namespace Magento\Catalog\Model\ResourceModel\Category;
77

@@ -337,16 +337,63 @@ public function loadProductCount($items, $countRegular = true, $countAnchor = tr
337337
$categoryIds = array_keys($anchor);
338338
$countSelect = $this->getProductsCountQuery($categoryIds, (bool)$websiteId);
339339
$categoryProductsCount = $this->_conn->fetchPairs($countSelect);
340+
$countFromCategoryTable = $this->getCountFromCategoryTable($categoryIds, (int)$websiteId);
341+
340342
foreach ($anchor as $item) {
341-
$productsCount = isset($categoryProductsCount[$item->getId()])
342-
? (int)$categoryProductsCount[$item->getId()]
343-
: $this->getProductsCountFromCategoryTable($item, $websiteId);
343+
$productsCount = 0;
344+
if (isset($categoryProductsCount[$item->getId()])) {
345+
$productsCount = (int)$categoryProductsCount[$item->getId()];
346+
} elseif (isset($countFromCategoryTable[$item->getId()])) {
347+
$productsCount = (int)$countFromCategoryTable[$item->getId()];
348+
}
344349
$item->setProductCount($productsCount);
345350
}
346351
}
347352
return $this;
348353
}
349354

355+
/**
356+
* Get products number for each category with bulk query
357+
*
358+
* @param array $categoryIds
359+
* @param int $websiteId
360+
* @return array
361+
*/
362+
private function getCountFromCategoryTable(
363+
array $categoryIds,
364+
int $websiteId
365+
) : array {
366+
$subSelect = clone $this->_conn->select();
367+
$subSelect->from(['ce2' => $this->getTable('catalog_category_entity')], 'ce2.entity_id')
368+
->where("ce2.path LIKE CONCAT(ce.path, '/%')");
369+
370+
$select = clone $this->_conn->select();
371+
$select->from(
372+
['ce' => $this->getTable('catalog_category_entity')],
373+
'ce.entity_id'
374+
);
375+
$joinCondition = new \Zend_Db_Expr("ce.entity_id=cp.category_id OR cp.category_id IN ({$subSelect})");
376+
$select->joinLeft(
377+
['cp' => $this->getProductTable()],
378+
$joinCondition,
379+
'COUNT(DISTINCT cp.product_id) AS product_count'
380+
);
381+
if ($websiteId) {
382+
$select->join(
383+
['w' => $this->getProductWebsiteTable()],
384+
'cp.product_id = w.product_id',
385+
[]
386+
)->where(
387+
'w.website_id = ?',
388+
$websiteId
389+
);
390+
}
391+
$select->where('ce.entity_id IN(?)', $categoryIds);
392+
$select->group('ce.entity_id');
393+
394+
return $this->_conn->fetchPairs($select);
395+
}
396+
350397
/**
351398
* Add category path filter
352399
*
@@ -519,45 +566,6 @@ public function getProductTable()
519566
return $this->_productTable;
520567
}
521568

522-
/**
523-
* Get products count using catalog_category_entity table
524-
*
525-
* @param Category $item
526-
* @param string $websiteId
527-
* @return int
528-
*/
529-
private function getProductsCountFromCategoryTable(Category $item, string $websiteId): int
530-
{
531-
$productCount = 0;
532-
533-
if ($item->getAllChildren()) {
534-
$bind = ['entity_id' => $item->getId(), 'c_path' => $item->getPath() . '/%'];
535-
$select = $this->_conn->select();
536-
$select->from(
537-
['main_table' => $this->getProductTable()],
538-
new \Zend_Db_Expr('COUNT(DISTINCT main_table.product_id)')
539-
)->joinInner(
540-
['e' => $this->getTable('catalog_category_entity')],
541-
'main_table.category_id=e.entity_id',
542-
[]
543-
)->where(
544-
'(e.entity_id = :entity_id OR e.path LIKE :c_path)'
545-
);
546-
if ($websiteId) {
547-
$select->join(
548-
['w' => $this->getProductWebsiteTable()],
549-
'main_table.product_id = w.product_id',
550-
[]
551-
)->where(
552-
'w.website_id = ?',
553-
$websiteId
554-
);
555-
}
556-
$productCount = (int)$this->_conn->fetchOne($select, $bind);
557-
}
558-
return $productCount;
559-
}
560-
561569
/**
562570
* Get query for retrieve count of products per category
563571
*

0 commit comments

Comments
 (0)