diff --git a/app/code/Magento/Backend/Test/Mftf/ActionGroup/AdminAddRestrictedRoleForGlobalSearchActionGroup.xml b/app/code/Magento/Backend/Test/Mftf/ActionGroup/AdminAddRestrictedRoleForGlobalSearchActionGroup.xml
new file mode 100644
index 0000000000000..e4f285038b9da
--- /dev/null
+++ b/app/code/Magento/Backend/Test/Mftf/ActionGroup/AdminAddRestrictedRoleForGlobalSearchActionGroup.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Backend/Test/Mftf/Test/AdminLoginWithRestrictPermissionTest.xml b/app/code/Magento/Backend/Test/Mftf/Test/AdminLoginWithRestrictPermissionTest.xml
index 06a433e17ae6f..7bece6cf6fdc4 100644
--- a/app/code/Magento/Backend/Test/Mftf/Test/AdminLoginWithRestrictPermissionTest.xml
+++ b/app/code/Magento/Backend/Test/Mftf/Test/AdminLoginWithRestrictPermissionTest.xml
@@ -3,6 +3,8 @@
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
+ * Copyright 2024 Adobe
+ * All Rights Reserved.
*/
-->
@@ -17,8 +19,8 @@
-
+
@@ -29,7 +31,7 @@
-
+
diff --git a/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontVerifyDiscountOnDynamicBundleProductDifferentCartRulesTest.xml b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontVerifyDiscountOnDynamicBundleProductDifferentCartRulesTest.xml
new file mode 100644
index 0000000000000..4b7ae5666b5b2
--- /dev/null
+++ b/app/code/Magento/Bundle/Test/Mftf/Test/StorefrontVerifyDiscountOnDynamicBundleProductDifferentCartRulesTest.xml
@@ -0,0 +1,133 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 99.99
+
+
+
+ 34.49
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Block/Adminhtml/Category/Tree.php b/app/code/Magento/Catalog/Block/Adminhtml/Category/Tree.php
index 824703abba62d..fa5943f0e773c 100644
--- a/app/code/Magento/Catalog/Block/Adminhtml/Category/Tree.php
+++ b/app/code/Magento/Catalog/Block/Adminhtml/Category/Tree.php
@@ -1,7 +1,7 @@
getId();
$item['store'] = (int)$this->getStore()->getId();
$item['path'] = $node->getData('path');
-
- $item['cls'] = 'folder ' . ($node->getIsActive() ? 'active-category' : 'no-active-category');
+ $item['a_attr'] = ['class' => $node->getIsActive() ? 'active-category' : 'not-active-category'];
//$item['allowDrop'] = ($level<3) ? true : false;
$allowMove = $this->_isCategoryMoveable($node);
$item['allowDrop'] = $allowMove;
diff --git a/app/code/Magento/Catalog/Model/CategoryRepository.php b/app/code/Magento/Catalog/Model/CategoryRepository.php
index 4e85853cd33bc..c9b8c2027408b 100644
--- a/app/code/Magento/Catalog/Model/CategoryRepository.php
+++ b/app/code/Magento/Catalog/Model/CategoryRepository.php
@@ -1,8 +1,7 @@
storeManager->getStore()->getId();
if (!isset($this->instances[$categoryId][$cacheKey])) {
/** @var Category $category */
$category = $this->categoryFactory->create();
@@ -231,7 +230,7 @@ protected function validateCategory(Category $category)
* Lazy loader for the converter.
*
* @return ExtensibleDataObjectConverter
- *
+ * phpcs:disable Magento2.Annotation.MethodAnnotationStructure
* @deprecated 101.0.0
* @see we don't recommend this approach anymore
*/
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Category.php b/app/code/Magento/Catalog/Model/ResourceModel/Category.php
index f56fecb8dc556..2fb2d17335ec1 100644
--- a/app/code/Magento/Catalog/Model/ResourceModel/Category.php
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Category.php
@@ -1,7 +1,7 @@
(int)$position,
];
}
- $connection->insertMultiple($this->getCategoryProductTable(), $data);
+ $connection->insertOnDuplicate($this->getCategoryProductTable(), $data, ['position']);
}
/**
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Category/Collection.php b/app/code/Magento/Catalog/Model/ResourceModel/Category/Collection.php
index 259399ece827b..238f8ad730645 100644
--- a/app/code/Magento/Catalog/Model/ResourceModel/Category/Collection.php
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Category/Collection.php
@@ -1,7 +1,7 @@
getProductsCountQuery($categoryIds, (bool)$websiteId);
$categoryProductsCount = $this->_conn->fetchPairs($countSelect);
+ $countFromCategoryTable = $this->getCountFromCategoryTable($categoryIds, (int)$websiteId);
+
foreach ($anchor as $item) {
- $productsCount = isset($categoryProductsCount[$item->getId()])
- ? (int)$categoryProductsCount[$item->getId()]
- : $this->getProductsCountFromCategoryTable($item, $websiteId);
+ $productsCount = 0;
+ if (isset($categoryProductsCount[$item->getId()])) {
+ $productsCount = (int)$categoryProductsCount[$item->getId()];
+ } elseif (isset($countFromCategoryTable[$item->getId()])) {
+ $productsCount = (int)$countFromCategoryTable[$item->getId()];
+ }
$item->setProductCount($productsCount);
}
}
return $this;
}
+ /**
+ * Get products number for each category with bulk query
+ *
+ * @param array $categoryIds
+ * @param int $websiteId
+ * @return array
+ */
+ private function getCountFromCategoryTable(
+ array $categoryIds,
+ int $websiteId
+ ) : array {
+ $subSelect = clone $this->_conn->select();
+ $subSelect->from(['ce2' => $this->getTable('catalog_category_entity')], 'ce2.entity_id')
+ ->where("ce2.path LIKE CONCAT(ce.path, '/%')");
+
+ $select = clone $this->_conn->select();
+ $select->from(
+ ['ce' => $this->getTable('catalog_category_entity')],
+ 'ce.entity_id'
+ );
+ $joinCondition = new \Zend_Db_Expr("ce.entity_id=cp.category_id OR cp.category_id IN ({$subSelect})");
+ $select->joinLeft(
+ ['cp' => $this->getProductTable()],
+ $joinCondition,
+ 'COUNT(DISTINCT cp.product_id) AS product_count'
+ );
+ if ($websiteId) {
+ $select->join(
+ ['w' => $this->getProductWebsiteTable()],
+ 'cp.product_id = w.product_id',
+ []
+ )->where(
+ 'w.website_id = ?',
+ $websiteId
+ );
+ }
+ $select->where('ce.entity_id IN(?)', $categoryIds);
+ $select->group('ce.entity_id');
+
+ return $this->_conn->fetchPairs($select);
+ }
+
/**
* Add category path filter
*
@@ -519,45 +566,6 @@ public function getProductTable()
return $this->_productTable;
}
- /**
- * Get products count using catalog_category_entity table
- *
- * @param Category $item
- * @param string $websiteId
- * @return int
- */
- private function getProductsCountFromCategoryTable(Category $item, string $websiteId): int
- {
- $productCount = 0;
-
- if ($item->getAllChildren()) {
- $bind = ['entity_id' => $item->getId(), 'c_path' => $item->getPath() . '/%'];
- $select = $this->_conn->select();
- $select->from(
- ['main_table' => $this->getProductTable()],
- new \Zend_Db_Expr('COUNT(DISTINCT main_table.product_id)')
- )->joinInner(
- ['e' => $this->getTable('catalog_category_entity')],
- 'main_table.category_id=e.entity_id',
- []
- )->where(
- '(e.entity_id = :entity_id OR e.path LIKE :c_path)'
- );
- if ($websiteId) {
- $select->join(
- ['w' => $this->getProductWebsiteTable()],
- 'main_table.product_id = w.product_id',
- []
- )->where(
- 'w.website_id = ?',
- $websiteId
- );
- }
- $productCount = (int)$this->_conn->fetchOne($select, $bind);
- }
- return $productCount;
- }
-
/**
* Get query for retrieve count of products per category
*
diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml
index 0df039a14f7ea..948c126821ad7 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml
@@ -1,8 +1,8 @@
@@ -325,6 +325,19 @@
EavStockItem
CustomAttributeProductAttribute
+
+ Api Simple Product
+ api-simple-product
+ api-simple-product
+ simple
+ 4
+ 4
+ 1
+ 1
+ 1
+ EavStockItem
+ CustomAttributeProductAttribute
+
CustomAttributeCategoryIds
@@ -357,6 +370,19 @@
EavStockItem
CustomAttributeProductAttribute
+
+ Api Simple Product Two
+ api-simple-product-two
+ api-simple-product-two
+ simple
+ 4
+ 4
+ 1
+ 1
+ 1
+ EavStockItem
+ CustomAttributeProductAttribute
+
50
diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontCheckCustomOptionPriceDifferentCurrencyTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontCheckCustomOptionPriceDifferentCurrencyTest.xml
index e7808728acbae..05988a60287a7 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontCheckCustomOptionPriceDifferentCurrencyTest.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontCheckCustomOptionPriceDifferentCurrencyTest.xml
@@ -3,6 +3,8 @@
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
+ * Copyright 2024 Adobe
+ * All Rights Reserved.
*/
-->
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Category/CollectionTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Category/CollectionTest.php
new file mode 100644
index 0000000000000..cadb6c5a8d2e9
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Category/CollectionTest.php
@@ -0,0 +1,221 @@
+entityFactory = $this->getMockBuilder(EntityFactory::class)
+ ->disableOriginalConstructor(true)
+ ->getMock();
+ $this->logger = $this->getMockBuilder(LoggerInterface::class)
+ ->getMock();
+ $this->fetchStrategy = $this->getMockBuilder(FetchStrategyInterface::class)
+ ->getMock();
+ $this->eventManager = $this->getMockBuilder(ManagerInterface::class)
+ ->getMock();
+ $this->eavConfig = $this->getMockBuilder(Config::class)
+ ->disableOriginalConstructor(true)
+ ->getMock();
+ $this->resource = $this->getMockBuilder(ResourceConnection::class)
+ ->disableOriginalConstructor(true)
+ ->getMock();
+ $this->eavEntityFactory = $this->getMockBuilder(EavEntityFactory::class)
+ ->disableOriginalConstructor(true)
+ ->getMock();
+ $this->resourceHelper = $this->getMockBuilder(Helper::class)
+ ->disableOriginalConstructor(true)
+ ->getMock();
+ $this->universalFactory = $this->getMockBuilder(UniversalFactory::class)
+ ->disableOriginalConstructor(true)
+ ->getMock();
+ $this->storeManager = $this->getMockBuilder(StoreManagerInterface::class)
+ ->getMock();
+ $this->connection = $this->getMockBuilder(AdapterInterface::class)
+ ->getMock();
+ $this->scopeConfig = $this->getMockBuilder(ScopeConfigInterface::class)
+ ->getMock();
+ $this->catalogProductVisibility = $this->getMockBuilder(Visibility::class)
+ ->disableOriginalConstructor(true)
+ ->getMock();
+
+ $this->categoryEntity = $this->getMockBuilder(CategoryEntity::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->universalFactory->expects($this->any())
+ ->method('create')
+ ->willReturn($this->categoryEntity);
+ $this->categoryEntity->expects($this->any())
+ ->method('getConnection')
+ ->willReturn($this->connection);
+ $this->categoryEntity->expects($this->any())
+ ->method('getDefaultAttributes')
+ ->willReturn([]);
+
+ $this->select = $this->getMockBuilder(Select::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->connection->expects($this->any())
+ ->method('select')
+ ->willReturn($this->select);
+
+ $this->store = $this->getMockBuilder(StoreInterface::class)
+ ->getMock();
+ $this->storeManager->expects($this->any())
+ ->method('getStore')
+ ->willReturn($this->store);
+
+ $this->collection = new Collection(
+ $this->entityFactory,
+ $this->logger,
+ $this->fetchStrategy,
+ $this->eventManager,
+ $this->eavConfig,
+ $this->resource,
+ $this->eavEntityFactory,
+ $this->resourceHelper,
+ $this->universalFactory,
+ $this->storeManager,
+ $this->connection,
+ $this->scopeConfig,
+ $this->catalogProductVisibility
+ );
+ }
+
+ public function testLoadProductCount() : void
+ {
+ $this->select->expects($this->exactly(3))
+ ->method('from')
+ ->willReturnSelf();
+ $this->select->expects($this->exactly(3))
+ ->method('where')
+ ->willReturnSelf();
+ $this->select->expects($this->exactly(1))
+ ->method('group')
+ ->willReturnSelf();
+ $this->connection->expects($this->exactly(2))
+ ->method('fetchPairs')
+ ->with($this->select)
+ ->willReturn([]);
+ $this->collection->loadProductCount([]);
+ }
+}
diff --git a/app/code/Magento/Catalog/etc/di.xml b/app/code/Magento/Catalog/etc/di.xml
index 4b4e0b17fe25c..2ba1898629e7e 100644
--- a/app/code/Magento/Catalog/etc/di.xml
+++ b/app/code/Magento/Catalog/etc/di.xml
@@ -1,8 +1,8 @@
@@ -73,7 +73,6 @@
-
diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/category/widget/tree.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/category/widget/tree.phtml
index 27042e07f963b..c2043570e0dd7 100644
--- a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/category/widget/tree.phtml
+++ b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/category/widget/tree.phtml
@@ -1,7 +1,7 @@
getUseMassaction() ? 1 : 0;
$isAnchorOnly = $block->getIsAnchorOnly() ? 1 : 0;
+
$scriptString = <<
\n\n")),n.set("\n\n