diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml
index 007529a06d9f4..298b51d7fbac0 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Data/ProductData.xml
@@ -263,4 +263,8 @@
EavStockItem
CustomAttributeCategoryIds
+
+ 1
+ EavStock1
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/ProductExtensionAttributeData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/ProductExtensionAttributeData.xml
index 0f6b383c3b743..5424e48261085 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Data/ProductExtensionAttributeData.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Data/ProductExtensionAttributeData.xml
@@ -11,4 +11,7 @@
Qty_1000
+
+ Qty_1
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/StockItemData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/StockItemData.xml
index 46a3fa3657f2c..99e072b91c3a9 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Data/StockItemData.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Data/StockItemData.xml
@@ -12,4 +12,8 @@
1000
true
+
+ 1
+ true
+
diff --git a/app/code/Magento/CatalogInventory/Model/Indexer/Stock/CacheCleaner.php b/app/code/Magento/CatalogInventory/Model/Indexer/Stock/CacheCleaner.php
index a32faa4640a86..b3fa07479a712 100644
--- a/app/code/Magento/CatalogInventory/Model/Indexer/Stock/CacheCleaner.php
+++ b/app/code/Magento/CatalogInventory/Model/Indexer/Stock/CacheCleaner.php
@@ -10,8 +10,10 @@
use Magento\CatalogInventory\Api\StockConfigurationInterface;
use Magento\Framework\App\ResourceConnection;
+use Magento\Framework\App\ObjectManager;
use Magento\Framework\DB\Adapter\AdapterInterface;
use Magento\Framework\Event\ManagerInterface;
+use Magento\Framework\EntityManager\MetadataPool;
use Magento\Framework\Indexer\CacheContext;
use Magento\CatalogInventory\Model\Stock;
use Magento\Catalog\Model\Product;
@@ -46,25 +48,35 @@ class CacheCleaner
*/
private $connection;
+ /**
+ * @var MetadataPool
+ */
+ private $metadataPool;
+
/**
* @param ResourceConnection $resource
* @param StockConfigurationInterface $stockConfiguration
* @param CacheContext $cacheContext
* @param ManagerInterface $eventManager
+ * @param MetadataPool|null $metadataPool
*/
public function __construct(
ResourceConnection $resource,
StockConfigurationInterface $stockConfiguration,
CacheContext $cacheContext,
- ManagerInterface $eventManager
+ ManagerInterface $eventManager,
+ MetadataPool $metadataPool = null
) {
$this->resource = $resource;
$this->stockConfiguration = $stockConfiguration;
$this->cacheContext = $cacheContext;
$this->eventManager = $eventManager;
+ $this->metadataPool = $metadataPool ?: ObjectManager::getInstance()->get(MetadataPool::class);
}
/**
+ * Clean cache by product ids.
+ *
* @param array $productIds
* @param callable $reindex
* @return void
@@ -76,22 +88,37 @@ public function clean(array $productIds, callable $reindex)
$productStatusesAfter = $this->getProductStockStatuses($productIds);
$productIds = $this->getProductIdsForCacheClean($productStatusesBefore, $productStatusesAfter);
if ($productIds) {
- $this->cacheContext->registerEntities(Product::CACHE_TAG, $productIds);
+ $this->cacheContext->registerEntities(Product::CACHE_TAG, array_unique($productIds));
$this->eventManager->dispatch('clean_cache_by_tags', ['object' => $this->cacheContext]);
}
}
/**
+ * Get current stock statuses for product ids.
+ *
* @param array $productIds
* @return array
*/
private function getProductStockStatuses(array $productIds)
{
+ $linkField = $this->metadataPool->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class)
+ ->getLinkField();
$select = $this->getConnection()->select()
->from(
- $this->resource->getTableName('cataloginventory_stock_status'),
+ ['css' => $this->resource->getTableName('cataloginventory_stock_status')],
['product_id', 'stock_status', 'qty']
- )->where('product_id IN (?)', $productIds)
+ )
+ ->joinLeft(
+ ['cpr' => $this->resource->getTableName('catalog_product_relation')],
+ 'css.product_id = cpr.child_id',
+ []
+ )
+ ->joinLeft(
+ ['cpe' => $this->resource->getTableName('catalog_product_entity')],
+ 'cpr.parent_id = cpe.' . $linkField,
+ ['parent_id' => 'cpe.entity_id']
+ )
+ ->where('product_id IN (?)', $productIds)
->where('stock_id = ?', Stock::DEFAULT_STOCK_ID)
->where('website_id = ?', $this->stockConfiguration->getDefaultScopeId());
@@ -125,6 +152,9 @@ private function getProductIdsForCacheClean(array $productStatusesBefore, array
if ($statusBefore['stock_status'] !== $statusAfter['stock_status']
|| ($stockThresholdQty && $statusAfter['qty'] <= $stockThresholdQty)) {
$productIds[] = $productId;
+ if (isset($statusAfter['parent_id'])) {
+ $productIds[] = $statusAfter['parent_id'];
+ }
}
}
@@ -132,6 +162,8 @@ private function getProductIdsForCacheClean(array $productStatusesBefore, array
}
/**
+ * Get database connection.
+ *
* @return AdapterInterface
*/
private function getConnection()
diff --git a/app/code/Magento/CatalogInventory/Test/Mftf/Test/AssociatedProductToConfigurableOutOfStockTest.xml b/app/code/Magento/CatalogInventory/Test/Mftf/Test/AssociatedProductToConfigurableOutOfStockTest.xml
new file mode 100644
index 0000000000000..9a5ad027da600
--- /dev/null
+++ b/app/code/Magento/CatalogInventory/Test/Mftf/Test/AssociatedProductToConfigurableOutOfStockTest.xml
@@ -0,0 +1,91 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/CatalogInventory/Test/Unit/Model/Indexer/Stock/CacheCleanerTest.php b/app/code/Magento/CatalogInventory/Test/Unit/Model/Indexer/Stock/CacheCleanerTest.php
index 5e4249685f8d3..a1282c45ce1fc 100644
--- a/app/code/Magento/CatalogInventory/Test/Unit/Model/Indexer/Stock/CacheCleanerTest.php
+++ b/app/code/Magento/CatalogInventory/Test/Unit/Model/Indexer/Stock/CacheCleanerTest.php
@@ -12,6 +12,7 @@
use Magento\Framework\DB\Adapter\AdapterInterface;
use Magento\Framework\DB\Select;
use Magento\Framework\Event\ManagerInterface;
+use Magento\Framework\EntityManager\MetadataPool;
use Magento\Framework\Indexer\CacheContext;
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
use Magento\Catalog\Model\Product;
@@ -43,6 +44,11 @@ class CacheCleanerTest extends \PHPUnit\Framework\TestCase
*/
private $cacheContextMock;
+ /**
+ * @var MetadataPool |\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $metadataPoolMock;
+
/**
* @var StockConfigurationInterface|\PHPUnit_Framework_MockObject_MockObject
*/
@@ -61,6 +67,8 @@ protected function setUp()
->setMethods(['getStockThresholdQty'])->getMockForAbstractClass();
$this->cacheContextMock = $this->getMockBuilder(CacheContext::class)->disableOriginalConstructor()->getMock();
$this->eventManagerMock = $this->getMockBuilder(ManagerInterface::class)->getMock();
+ $this->metadataPoolMock = $this->getMockBuilder(MetadataPool::class)
+ ->setMethods(['getMetadata', 'getLinkField'])->disableOriginalConstructor()->getMock();
$this->selectMock = $this->getMockBuilder(Select::class)->disableOriginalConstructor()->getMock();
$this->resourceMock->expects($this->any())
@@ -73,7 +81,8 @@ protected function setUp()
'resource' => $this->resourceMock,
'stockConfiguration' => $this->stockConfigurationMock,
'cacheContext' => $this->cacheContextMock,
- 'eventManager' => $this->eventManagerMock
+ 'eventManager' => $this->eventManagerMock,
+ 'metadataPool' => $this->metadataPoolMock,
]
);
}
@@ -90,6 +99,7 @@ public function testClean($stockStatusBefore, $stockStatusAfter, $qtyAfter, $sto
$productId = 123;
$this->selectMock->expects($this->any())->method('from')->willReturnSelf();
$this->selectMock->expects($this->any())->method('where')->willReturnSelf();
+ $this->selectMock->expects($this->any())->method('joinLeft')->willReturnSelf();
$this->connectionMock->expects($this->exactly(2))->method('select')->willReturn($this->selectMock);
$this->connectionMock->expects($this->exactly(2))->method('fetchAll')->willReturnOnConsecutiveCalls(
[
@@ -105,7 +115,10 @@ public function testClean($stockStatusBefore, $stockStatusAfter, $qtyAfter, $sto
->with(Product::CACHE_TAG, [$productId]);
$this->eventManagerMock->expects($this->once())->method('dispatch')
->with('clean_cache_by_tags', ['object' => $this->cacheContextMock]);
-
+ $this->metadataPoolMock->expects($this->exactly(2))->method('getMetadata')
+ ->willReturnSelf();
+ $this->metadataPoolMock->expects($this->exactly(2))->method('getLinkField')
+ ->willReturn('row_id');
$callback = function () {
};
$this->unit->clean([], $callback);
@@ -136,6 +149,7 @@ public function testNotCleanCache($stockStatusBefore, $stockStatusAfter, $qtyAft
$productId = 123;
$this->selectMock->expects($this->any())->method('from')->willReturnSelf();
$this->selectMock->expects($this->any())->method('where')->willReturnSelf();
+ $this->selectMock->expects($this->any())->method('joinLeft')->willReturnSelf();
$this->connectionMock->expects($this->exactly(2))->method('select')->willReturn($this->selectMock);
$this->connectionMock->expects($this->exactly(2))->method('fetchAll')->willReturnOnConsecutiveCalls(
[
@@ -149,6 +163,10 @@ public function testNotCleanCache($stockStatusBefore, $stockStatusAfter, $qtyAft
->willReturn($stockThresholdQty);
$this->cacheContextMock->expects($this->never())->method('registerEntities');
$this->eventManagerMock->expects($this->never())->method('dispatch');
+ $this->metadataPoolMock->expects($this->exactly(2))->method('getMetadata')
+ ->willReturnSelf();
+ $this->metadataPoolMock->expects($this->exactly(2))->method('getLinkField')
+ ->willReturn('row_id');
$callback = function () {
};
diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml
index db747dbdba657..aa168899ddb02 100644
--- a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml
+++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutActionGroup.xml
@@ -10,6 +10,7 @@
xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd">
+
@@ -66,4 +67,10 @@
+
+
+
+
+
+
diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateApiConfigurableProductActionGroup.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateApiConfigurableProductActionGroup.xml
index 75686d23a11b9..fafbe84fe568e 100644
--- a/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateApiConfigurableProductActionGroup.xml
+++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/AdminCreateApiConfigurableProductActionGroup.xml
@@ -62,4 +62,14 @@
+
+
+
+ {{productName}}
+
+
+
+
+
+
diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/StorefrontProductInfoMainSection.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/StorefrontProductInfoMainSection.xml
index 996a392230eea..be0c2b05e48ba 100644
--- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/StorefrontProductInfoMainSection.xml
+++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/StorefrontProductInfoMainSection.xml
@@ -13,5 +13,6 @@
+