diff --git a/BundleProductDataExporter/Test/Integration/BundleProductTest.php b/BundleProductDataExporter/Test/Integration/BundleProductTest.php
index 9acd66f6..27776946 100644
--- a/BundleProductDataExporter/Test/Integration/BundleProductTest.php
+++ b/BundleProductDataExporter/Test/Integration/BundleProductTest.php
@@ -17,6 +17,9 @@
*/
class BundleProductTest extends AbstractProductTestHelper
{
+ private const BUNDLE_SKU = 'bundle-product';
+ private const DYNAMIC_BUNDLE_SKU = 'dynamic_bundle_product_with_special_price';
+
/**
* @var ArrayUtils
*/
@@ -47,7 +50,7 @@ protected function setUp() : void
*/
public function testBundleFixedProductOptions(array $bundleProductOptionsDataProvider) : void
{
- $extractedProduct = $this->getExtractedProduct('bundle-product', 'default');
+ $extractedProduct = $this->getExtractedProduct(self::BUNDLE_SKU, 'default');
$this->assertNotEmpty($extractedProduct, 'Feed data must not be empty');
foreach ($bundleProductOptionsDataProvider as $key => $expectedData) {
@@ -72,7 +75,7 @@ public function testBundleFixedProductOptions(array $bundleProductOptionsDataPro
*/
public function testBundleDynamicProductOptions(array $bundleProductOptionsDataProvider) : void
{
- $extractedProduct = $this->getExtractedProduct('dynamic_bundle_product_with_special_price', 'default');
+ $extractedProduct = $this->getExtractedProduct(self::DYNAMIC_BUNDLE_SKU, 'default');
$this->assertNotEmpty($extractedProduct, 'Feed data must not be empty');
foreach ($bundleProductOptionsDataProvider as $key => $expectedData) {
@@ -92,7 +95,7 @@ public function getBundleFixedProductOptionsDataProvider() : array
'bundleProduct' => [
'item' => [
'feedData' => [
- 'sku' => 'bundle-product',
+ 'sku' => self::BUNDLE_SKU,
'storeViewCode' => 'default',
'name' => 'Bundle Product',
'type' => 'bundle_fixed',
@@ -134,7 +137,7 @@ public function getBundleDynamicProductOptionsDataProvider() : array
'bundleProduct' => [
'item' => [
'feedData' => [
- 'sku' => 'dynamic_bundle_product_with_special_price',
+ 'sku' => self::DYNAMIC_BUNDLE_SKU,
'storeViewCode' => 'default',
'name' => 'Bundle Product',
'type' => 'bundle',
diff --git a/BundleProductDataExporter/Test/Integration/ExportBundleOptionWithParentTest.php b/BundleProductDataExporter/Test/Integration/ExportBundleOptionWithParentTest.php
index aa15a38f..63fb1b24 100644
--- a/BundleProductDataExporter/Test/Integration/ExportBundleOptionWithParentTest.php
+++ b/BundleProductDataExporter/Test/Integration/ExportBundleOptionWithParentTest.php
@@ -7,18 +7,12 @@
namespace Magento\BundleProductDataExporter\Test\Integration;
-use DateTime;
-use DateTimeInterface;
-use Magento\Catalog\Api\ProductRepositoryInterface;
-use Magento\Framework\App\ResourceConnection;
+use Magento\CatalogDataExporter\Test\Integration\AbstractProductTestHelper;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\DataExporter\Model\FeedInterface;
use Magento\DataExporter\Model\FeedPool;
-use Magento\Indexer\Model\Indexer;
use Magento\TestFramework\Helper\Bootstrap;
use PHPUnit\Framework\TestCase;
-use RuntimeException;
-use Throwable;
use Zend_Db_Statement_Exception;
/**
@@ -29,45 +23,22 @@
* @SuppressWarnings(PHPMD.UnusedPrivateMethod)
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
-class ExportBundleOptionWithParentTest extends TestCase
+class ExportBundleOptionWithParentTest extends AbstractProductTestHelper
{
- private const PRODUCT_FEED_INDEXER = 'catalog_data_exporter_products';
-
- /**
- * @var Indexer
- */
- private Indexer $indexer;
-
+ private const SIMPLE_SKU = 'simple1';
/**
* @var FeedInterface
*/
private FeedInterface $productsFeed;
/**
- * @var ProductRepositoryInterface
+ * @inheritDoc
*/
- private ProductRepositoryInterface $productRepository;
-
- /**
- * @var ResourceConnection
- */
- private ResourceConnection $resourceConnection;
-
- /**
- * @param string|null $name
- * @param array $data
- * @param $dataName
- */
- public function __construct(
- ?string $name = null,
- array $data = [],
- $dataName = ''
- ) {
- parent::__construct($name, $data, $dataName);
- $this->indexer = Bootstrap::getObjectManager()->create(Indexer::class);
- $this->productRepository = Bootstrap::getObjectManager()->create(ProductRepositoryInterface::class);
+ protected function setUp() : void
+ {
$this->productsFeed = Bootstrap::getObjectManager()->get(FeedPool::class)->getFeed('products');
- $this->resourceConnection = Bootstrap::getObjectManager()->create(ResourceConnection::class);
+
+ parent::setUp();
}
/**
@@ -92,7 +63,7 @@ private function expectedBundleOptionsWithParentData(): array
[
[
[
- 'sku' => 'simple1',
+ 'sku' => self::SIMPLE_SKU,
'type' => 'SIMPLE',
'parents' => [
0 => ['sku' => 'bundle-product', 'productType' => 'bundle_fixed'],
@@ -112,66 +83,18 @@ private function expectedBundleOptionsWithParentData(): array
*/
private function checkExpectedItemsAreExportedInFeed(array $expectedItems): void
{
- $ids = [];
- foreach ($expectedItems as $expectedItem) {
- $ids[] = $this->productRepository->get($expectedItem['sku'])->getId();
- }
- $timestamp = new DateTime('Now - 1 second');
- $this->runIndexer($ids);
- $actualProductsFeed = $this->productsFeed->getFeedSince($timestamp->format(DateTimeInterface::W3C));
+ $extractedProduct = $this->getExtractedProduct(self::SIMPLE_SKU, 'default');
- self::assertNotEmpty($actualProductsFeed['feed'], 'Product Feed should not be empty');
+ self::assertNotEmpty($extractedProduct, 'Product Feed should not be empty');
- foreach ($expectedItems as $index => $product) {
- if (!isset($actualProductsFeed['feed'][$index])) {
- self::fail("Cannot find product feed");
- }
-
- self::assertEquals(
- $product['sku'],
- $actualProductsFeed['feed'][$index]['sku'],
- "Sku is not equal for index {$index}"
- );
+ foreach ($expectedItems as $product) {
+ self::assertEquals($product['sku'], $extractedProduct['sku']);
self::assertEqualsCanonicalizing(
$product['parents'],
- $actualProductsFeed['feed'][$index]['parents'],
- "Parents is not equal"
+ $extractedProduct['feedData']['parents'],
+ "Expected Parents are not equal to Actual"
);
}
}
-
- /**
- * Run the indexer to extract product data
- * @param $ids
- * @return void
- */
- private function runIndexer($ids): void
- {
- try {
- $this->indexer->load(self::PRODUCT_FEED_INDEXER);
- $this->indexer->reindexList($ids);
- } catch (Throwable) {
- throw new RuntimeException('Could not reindex product data');
- }
- }
-
- /**
- * @return void
- */
- protected function tearDown(): void
- {
- parent::tearDown();
- $this->truncateIndexTable();
- }
-
- /**
- * Truncates index table
- */
- private function truncateIndexTable(): void
- {
- $connection = $this->resourceConnection->getConnection();
- $feedTable = $this->resourceConnection->getTableName('catalog_data_exporter_products');
- $connection->truncateTable($feedTable);
- }
}
diff --git a/CatalogDataExporter/Test/Integration/AbstractProductTestHelper.php b/CatalogDataExporter/Test/Integration/AbstractProductTestHelper.php
index 63c26dcb..16a79e17 100644
--- a/CatalogDataExporter/Test/Integration/AbstractProductTestHelper.php
+++ b/CatalogDataExporter/Test/Integration/AbstractProductTestHelper.php
@@ -14,6 +14,7 @@
use Magento\Catalog\Helper\Product as ProductHelper;
use Magento\Catalog\Model\Product\Attribute\Source\Status;
use Magento\Catalog\Model\Product\Visibility;
+use Magento\Framework\Api\SearchCriteriaInterface;
use Magento\Framework\App\ResourceConnection;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Exception\NoSuchEntityException;
@@ -126,18 +127,9 @@ protected function setUp(): void
$this->taxClassSource = Bootstrap::getObjectManager()->create(TaxClassSource::class);
$this->jsonSerializer = Bootstrap::getObjectManager()->create(Json::class);
- }
- /**
- * Run the indexer to extract product data
- *
- * @param array $ids
- * @return void
- */
- protected function runIndexer(array $ids = []) : void
- {
$this->indexer->load(self::CATALOG_DATA_EXPORTER);
- $this->indexer->reindexList($ids);
+ $this->reindexProductDataExporter();
}
/**
@@ -146,10 +138,10 @@ protected function runIndexer(array $ids = []) : void
* @param string $sku
* @param string $storeViewCode
* @return array
- * @throws \Zend_Db_Statement_Exception
*/
protected function getExtractedProduct(string $sku, string $storeViewCode) : array
{
+ // Select data from exporter table
$query = $this->connection->select()
->from(['ex' => $this->resource->getTableName(self::CATALOG_DATA_EXPORTER)])
->where('ex.sku = ?', $sku)
@@ -163,7 +155,37 @@ protected function getExtractedProduct(string $sku, string $storeViewCode) : arr
$data[$row['sku']]['is_deleted'] = $row['is_deleted'];
$data[$row['sku']]['feedData'] = $this->jsonSerializer->unserialize($row['feed_data']);
}
- return $data[$sku];
+
+ return !empty($data[$sku]) ? $data[$sku] : $data;
+ }
+
+ /**
+ * Run partial exported indexer
+ *
+ * @param array $ids
+ * @return void
+ */
+ protected function emulatePartialReindexBehavior(array $ids = []) : void
+ {
+ $this->indexer->reindexList($ids);
+ }
+
+ /**
+ * Reindex all the product data exporter table for existing products
+ *
+ * @return void
+ */
+ private function reindexProductDataExporter() : void
+ {
+ $searchCriteria = Bootstrap::getObjectManager()->create(SearchCriteriaInterface::class);
+
+ $productIds = array_map(function ($product) {
+ return $product->getId();
+ }, $this->productRepository->getList($searchCriteria)->getItems());
+
+ if (!empty($productIds)) {
+ $this->indexer->reindexList($productIds);
+ }
}
/**
@@ -232,6 +254,8 @@ protected function validateCategoryData(ProductInterface $product, array $extrac
*/
protected function validateBaseProductData(ProductInterface $product, array $extract, string $storeViewCode) : void
{
+ $this->assertNotEmpty($extract, "Exported Product Data is empty");
+
$storeViewId = $this->storeRepositoryInterface->get($storeViewCode)->getCode();
$storeView = $this->storeManager->getStore($storeViewId);
$websiteCode = $this->websiteRepositoryInterface->getById($storeView->getWebsiteId())->getCode();
@@ -498,4 +522,34 @@ protected function emulateCustomersBehaviorAfterDeleteAction(): void
// \Magento\DataExporter\Model\Query\RemovedEntitiesByModifiedAtQuery::getQuery
sleep(1);
}
+
+ /**
+ * @param string $sku
+ * @return int|null
+ * @throws NoSuchEntityException
+ */
+ public function getProductId(string $sku): ?int
+ {
+ $product = $this->productRepository->get($sku);
+ return (int)$product->getId();
+ }
+
+ /**
+ * @return void
+ */
+ protected function tearDown(): void
+ {
+ parent::tearDown();
+ $this->truncateProductDataExporterIndexTable();
+ }
+
+ /**
+ * Truncates index table
+ */
+ private function truncateProductDataExporterIndexTable(): void
+ {
+ $connection = $this->resource->getConnection();
+ $feedTable = $this->resource->getTableName(self::CATALOG_DATA_EXPORTER);
+ $connection->truncateTable($feedTable);
+ }
}
diff --git a/CatalogDataExporter/Test/Integration/Category/AbstractCategoryTest.php b/CatalogDataExporter/Test/Integration/Category/AbstractCategoryTest.php
index 0458b9e3..89072910 100644
--- a/CatalogDataExporter/Test/Integration/Category/AbstractCategoryTest.php
+++ b/CatalogDataExporter/Test/Integration/Category/AbstractCategoryTest.php
@@ -78,18 +78,9 @@ protected function setUp() : void
$this->categoryRepository = Bootstrap::getObjectManager()->create(CategoryRepositoryInterface::class);
$this->storeManager = Bootstrap::getObjectManager()->create(StoreManagerInterface::class);
$this->categoryFeed = Bootstrap::getObjectManager()->get(FeedPool::class)->getFeed('categories');
- }
- /**
- * Run the indexer to extract categories data
- *
- * @param array $ids
- * @return void
- */
- protected function runIndexer(array $ids) : void
- {
$this->indexer->load(self::CATEGORY_FEED_INDEXER);
- $this->indexer->reindexList($ids);
+ $this->reindexCategoryDataExporterTable();
}
/**
@@ -101,6 +92,8 @@ protected function runIndexer(array $ids) : void
*/
protected function assertBaseCategoryData(CategoryInterface $category, array $extract, StoreInterface $store) : void
{
+ $this->assertNotEmpty($extract, "Exported Category Data is empty");
+
$storeCode = $this->storeManager->getGroup($store->getStoreGroupId())->getCode();
$websiteCode = $this->storeManager->getWebsite($store->getWebsiteId())->getCode();
$this->assertEquals($store->getCode(), $extract['storeViewCode']);
@@ -136,4 +129,44 @@ public function getCategoryById(int $categoryId, string $storeViewCode) : array
}
return [];
}
+
+ /**
+ * Run the category exporter indexer
+ *
+ * @param array $ids
+ * @return void
+ */
+ protected function emulatePartialReindexBehavior(array $ids = []) : void
+ {
+ $this->indexer->reindexList($ids);
+ }
+
+ /**
+ * Reindex the full category data exporter table
+ *
+ * @return void
+ */
+ private function reindexCategoryDataExporterTable() : void
+ {
+ $this->indexer->reindexAll();
+ }
+
+ /**
+ * @return void
+ */
+ protected function tearDown(): void
+ {
+ parent::tearDown();
+ $this->truncateCategoryDataExporterIndexTable();
+ }
+
+ /**
+ * Truncates index table
+ */
+ private function truncateCategoryDataExporterIndexTable(): void
+ {
+ $connection = $this->resource->getConnection();
+ $feedTable = $this->resource->getTableName(self::CATEGORY_FEED_INDEXER);
+ $connection->truncateTable($feedTable);
+ }
}
diff --git a/CatalogDataExporter/Test/Integration/Category/CategoryRemovalTest.php b/CatalogDataExporter/Test/Integration/Category/CategoryRemovalTest.php
index e95d09c3..e5a56444 100644
--- a/CatalogDataExporter/Test/Integration/Category/CategoryRemovalTest.php
+++ b/CatalogDataExporter/Test/Integration/Category/CategoryRemovalTest.php
@@ -28,11 +28,16 @@ class CategoryRemovalTest extends AbstractCategoryTest
public function testCategoryRemoval() : void
{
$categoryId = 600;
- $extractedCategory = $this->getCategoryById(600, 'default');
+
+ $extractedCategory = $this->getCategoryById($categoryId, 'default');
+ $this->assertNotEmpty($extractedCategory, "Exported Category Data is empty");
$this->assertEquals(false, $extractedCategory['deleted']);
+
$this->deleteCategory($categoryId);
- $extractedCategory = $this->getCategoryById(600, 'default');
- $this->assertTrue($extractedCategory['deleted']);
+ $this->emulatePartialReindexBehavior([$categoryId]);
+
+ $extractedCategory = $this->getCategoryById($categoryId, 'default');
+ $this->assertTrue($extractedCategory['deleted'], "Category is not set as deleted");
}
/**
diff --git a/CatalogDataExporter/Test/Integration/Category/CategoryTest.php b/CatalogDataExporter/Test/Integration/Category/CategoryTest.php
index 58561eaa..9da5749c 100644
--- a/CatalogDataExporter/Test/Integration/Category/CategoryTest.php
+++ b/CatalogDataExporter/Test/Integration/Category/CategoryTest.php
@@ -32,19 +32,24 @@ public function testCategoriesInDifferentStoreViews() : void
$storeCustomOne = $this->storeManager->getStore('custom_store_view_one');
$storeCustomTwo = $this->storeManager->getStore('custom_store_view_two');
+ $categoryIdsInCustomStore = [400, 401, 402];
+ $categoryIdsInDefaultStore = [500, 501, 502];
+
try {
- foreach ([400, 401, 402] as $categoryId) {
+ foreach ($categoryIdsInCustomStore as $categoryId) {
foreach ([$storeCustomOne, $storeCustomTwo] as $store) {
$this->storeManager->setCurrentStore($store);
$category = $this->categoryRepository->get($categoryId, $store->getId());
+ $this->emulatePartialReindexBehavior([$categoryId]);
$extractedCategoryData = $this->getCategoryById($categoryId, $store->getCode());
$this->assertBaseCategoryData($category, $extractedCategoryData, $store);
}
}
- foreach ([500, 501, 502] as $categoryId) {
+ foreach ($categoryIdsInDefaultStore as $categoryId) {
$this->storeManager->setCurrentStore($storeDefault);
$category = $this->categoryRepository->get($categoryId, $storeDefault->getId());
+ $this->emulatePartialReindexBehavior([$categoryId]);
$extractedCategoryData = $this->getCategoryById($categoryId, $storeDefault->getCode());
$this->assertBaseCategoryData($category, $extractedCategoryData, $storeDefault);
}
diff --git a/CatalogDataExporter/Test/Integration/GroupedProductsTest.php b/CatalogDataExporter/Test/Integration/GroupedProductsTest.php
index b98a8e12..e971fdfc 100644
--- a/CatalogDataExporter/Test/Integration/GroupedProductsTest.php
+++ b/CatalogDataExporter/Test/Integration/GroupedProductsTest.php
@@ -17,12 +17,13 @@
*/
class GroupedProductsTest extends AbstractProductTestHelper
{
+ private const GROUPED_PRODUCT_SKU = 'grouped-product';
+
/**
* @var ArrayUtils
*/
private $arrayUtils;
-
/**
* @inheritDoc
*/
@@ -48,7 +49,7 @@ protected function setUp() : void
*/
public function testGroupedProductOptions(array $groupedProductOptionsDataProvider) : void
{
- $extractedProduct = $this->getExtractedProduct('grouped-product', 'default');
+ $extractedProduct = $this->getExtractedProduct(self::GROUPED_PRODUCT_SKU, 'default');
$this->assertNotEmpty($extractedProduct, 'Feed data must not be empty');
foreach ($groupedProductOptionsDataProvider as $key => $expectedData) {
@@ -76,7 +77,7 @@ public function testGroupedProductOptionsInMultipleWebsites(array $groupedProduc
$storeViews = ['fixture_second_store','fixture_third_store'];
foreach ($storeViews as $store) {
- $extractedProduct = $this->getExtractedProduct('grouped-product', $store);
+ $extractedProduct = $this->getExtractedProduct(self::GROUPED_PRODUCT_SKU, $store);
$this->assertNotEmpty($extractedProduct, 'Feed data must not be empty');
// Assert values are equal for fixture_second_store
@@ -99,7 +100,7 @@ public function getGroupedProductOptionsDataProvider() : array
'groupedProduct' => [
'item' => [
'feedData' => [
- 'sku' => 'grouped-product',
+ 'sku' => self::GROUPED_PRODUCT_SKU,
'storeViewCode' => 'default',
'name' => 'Grouped Product',
'type' => 'grouped',
diff --git a/CatalogDataExporter/Test/Integration/ProductRemovalTest.php b/CatalogDataExporter/Test/Integration/ProductRemovalTest.php
index eccea4d0..0e58a962 100644
--- a/CatalogDataExporter/Test/Integration/ProductRemovalTest.php
+++ b/CatalogDataExporter/Test/Integration/ProductRemovalTest.php
@@ -67,7 +67,7 @@ protected function deleteProduct(string $sku) : void
if ($productId) {
$this->productRepository->delete($product);
$this->emulateCustomersBehaviorAfterDeleteAction();
- $this->runIndexer([$productId]);
+ $this->emulatePartialReindexBehavior([$productId]);
}
} catch (\Exception $e) {
//Nothing to delete
diff --git a/CatalogDataExporter/Test/Integration/ResubmitFailedFeedTest.php b/CatalogDataExporter/Test/Integration/ResubmitFailedFeedTest.php
index bd950de2..32d6e678 100644
--- a/CatalogDataExporter/Test/Integration/ResubmitFailedFeedTest.php
+++ b/CatalogDataExporter/Test/Integration/ResubmitFailedFeedTest.php
@@ -23,16 +23,23 @@
/**
* Test class to check that only feeds with "resyncable" statuses would be re-submitted
*/
-class ResubmitFailedFeedTest extends TestCase
+class ResubmitFailedFeedTest extends AbstractProductTestHelper
{
private const EXPORT_SUCCESS_STATUS = 200;
+ /**
+ * @var FeedInterface
+ */
private FeedInterface $productFeed;
+ /**
+ * @var SubmitFeedInterface|ProductSubmitFeed|mixed
+ */
private SubmitFeedInterface $submitFeed;
- private ProductRepositoryInterface $productRepository;
-
+ /**
+ * @var ResourceConnection|mixed
+ */
private ResourceConnection $resourceConnection;
public static function setUpBeforeClass(): void
@@ -98,13 +105,15 @@ private function updateFeeds(array $expectedProducts): void
{
$queryData = [];
foreach ($expectedProducts as $productData) {
+ $productId = $this->productRepository->get($productData['sku'])->getId();
$queryData[] = [
- 'id' => $this->productRepository->get($productData['sku'])->getId(),
+ 'id' => $productId,
'sku' => $productData['sku'],
'store_view_code' => $productData['store_view_code'],
'status' => $productData['status']
];
}
+
$connection = $this->resourceConnection->getConnection();
$connection->insertOnDuplicate(
$connection->getTableName($this->productFeed->getFeedMetadata()->getFeedTableName()),
diff --git a/CatalogDataExporter/Test/Integration/SimpleProductsWebsiteUnassignTest.php b/CatalogDataExporter/Test/Integration/SimpleProductsWebsiteUnassignTest.php
index 03e9260d..f359b475 100644
--- a/CatalogDataExporter/Test/Integration/SimpleProductsWebsiteUnassignTest.php
+++ b/CatalogDataExporter/Test/Integration/SimpleProductsWebsiteUnassignTest.php
@@ -33,7 +33,6 @@ protected function setUp(): void
$this->objectManager = Bootstrap::getObjectManager();
$this->action = $this->objectManager->create(Action::class);
parent::setUp();
- $this->emulateCustomersBehaviorAfterDeleteAction();
}
/**
@@ -58,15 +57,24 @@ public function testSimpleProductsOnSave(array $testData) : void
$websiteRepository = $this->objectManager->get(WebsiteRepositoryInterface::class);
foreach ($testData as $productData) {
$product = $this->productRepository->get($productData['sku']);
+
$websiteIds = [];
foreach ($productData['websites'] as $websiteCode) {
$websiteIds[] = $websiteRepository->get($websiteCode)->getId();
}
$product->setWebsiteIds($websiteIds);
$this->productRepository->save($product);
+
+ $this->emulateCustomersBehaviorAfterDeleteAction();
+ $this->emulatePartialReindexBehavior([$product->getId()]);
+
foreach ($productData['expected_data'] as $storeViewCode => $isDeleted) {
$extractedProduct = $this->getExtractedProduct($productData['sku'], $storeViewCode);
- self::assertEquals($isDeleted, $extractedProduct['is_deleted']);
+ self::assertEquals(
+ $isDeleted,
+ $extractedProduct['is_deleted'],
+ "Product {$productData['sku']} is not deleted in store view {$storeViewCode}"
+ );
}
}
}
@@ -103,10 +111,17 @@ public function testSimpleProductsOnBulkUpdate(array $skus, array $websitesToUna
$this->action->updateWebsites($productIds, $websiteIds, 'remove');
+ $this->emulateCustomersBehaviorAfterDeleteAction();
+ $this->emulatePartialReindexBehavior($productIds);
+
foreach ($expectedData as $storeViewCode => $isDeleted) {
foreach ($skus as $sku) {
$extractedProduct = $this->getExtractedProduct($sku, $storeViewCode);
- self::assertEquals($isDeleted, $extractedProduct['is_deleted']);
+ self::assertEquals(
+ $isDeleted,
+ $extractedProduct['is_deleted'],
+ "Product {$sku} is not deleted in store view {$storeViewCode}"
+ );
}
}
}
diff --git a/CatalogInventoryDataExporter/Test/Integration/ProductBuyableTest.php b/CatalogInventoryDataExporter/Test/Integration/ProductBuyableTest.php
index 9bfc6002..0134649c 100644
--- a/CatalogInventoryDataExporter/Test/Integration/ProductBuyableTest.php
+++ b/CatalogInventoryDataExporter/Test/Integration/ProductBuyableTest.php
@@ -7,11 +7,15 @@
namespace Magento\CatalogInventoryDataExporter\Test\Integration;
+use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Catalog\Model\Product\Attribute\Source\Status;
use Magento\CatalogDataExporter\Test\Integration\AbstractProductTestHelper;
use Magento\CatalogInventory\Model\Stock\Item;
+use Magento\Framework\Exception\CouldNotSaveException;
+use Magento\Framework\Exception\InputException;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Exception\NoSuchEntityException;
+use Magento\Framework\Exception\StateException;
use Magento\TestFramework\Helper\Bootstrap;
/**
@@ -26,8 +30,8 @@ class ProductBuyableTest extends AbstractProductTestHelper
/**
* Test constants
*/
- const SKU = 'simple7';
- const STORE_VIEW_CODE = 'default';
+ private const SKU = 'simple7';
+ private const STORE_VIEW_CODE = 'default';
/**
* Validate buyable status of out of stock product
@@ -40,7 +44,12 @@ class ProductBuyableTest extends AbstractProductTestHelper
*/
public function testOutOfStockProduct() : void
{
- $this->setIsInStock(false);
+ $product = $this->productRepository->get(self::SKU);
+ $productId = $product->getId();
+
+ $this->setIsInStock((int)$productId, false);
+
+ $this->emulatePartialReindexBehavior([$productId]);
$this->validateProductBuyable($this->getExtractedProduct(self::SKU, self::STORE_VIEW_CODE));
}
@@ -54,7 +63,12 @@ public function testOutOfStockProduct() : void
*/
public function testDisabledProduct() : void
{
- $this->disableProduct();
+ $product = $this->productRepository->get(self::SKU);
+ $productId = $product->getId();
+
+ $this->disableProduct($product);
+
+ $this->emulatePartialReindexBehavior([$productId]);
$this->validateDisabledProduct($this->getExtractedProduct(self::SKU, self::STORE_VIEW_CODE));
}
@@ -68,24 +82,26 @@ public function testDisabledProduct() : void
*/
public function testEnabledProduct() : void
{
- $this->enableProduct();
- $this->setIsInStock(true);
+ $product = $this->productRepository->get(self::SKU);
+ $productId = $product->getId();
+
+ $this->enableProduct($product);
+ $this->setIsInStock((int)$productId, true);
+
+ $this->emulatePartialReindexBehavior([$productId]);
$this->validateEnabledProduct($this->getExtractedProduct(self::SKU, self::STORE_VIEW_CODE));
}
/**
* Set is in stock value of product
*
+ * @param int $productId
* @param bool $isInStock
* @return void
- * @throws NoSuchEntityException
* @throws \Exception
*/
- protected function setIsInStock(bool $isInStock) : void
+ protected function setIsInStock(int $productId, bool $isInStock) : void
{
- $product = $this->productRepository->get(self::SKU);
- $productId = $product->getId();
-
/** @var \Magento\CatalogInventory\Model\Stock\Item $stockItem */
$stockItem = Bootstrap::getObjectManager()->create(Item::class);
$stockItem->load($productId, 'product_id');
@@ -96,13 +112,16 @@ protected function setIsInStock(bool $isInStock) : void
/**
* Set product status to disabled
*
+ * @param ProductInterface $product
+ *
* @return void
- * @throws NoSuchEntityException
- * @throws \Exception
+ *
+ * @throws CouldNotSaveException
+ * @throws InputException
+ * @throws StateException
*/
- protected function disableProduct() : void
+ protected function disableProduct(ProductInterface $product) : void
{
- $product = $this->productRepository->get(self::SKU, true);
$product->setStatus(Status::STATUS_DISABLED);
$this->productRepository->save($product);
}
@@ -110,13 +129,16 @@ protected function disableProduct() : void
/**
* Set product status to enabled
*
+ * @param ProductInterface $product
+ *
* @return void
- * @throws NoSuchEntityException
- * @throws \Exception
+ *
+ * @throws CouldNotSaveException
+ * @throws InputException
+ * @throws StateException
*/
- protected function enableProduct() : void
+ protected function enableProduct(ProductInterface $product) : void
{
- $product = $this->productRepository->get(self::SKU, true);
$product->setStatus(Status::STATUS_ENABLED);
$this->productRepository->save($product);
}
diff --git a/CatalogInventoryDataExporter/Test/Integration/ProductInStockTest.php b/CatalogInventoryDataExporter/Test/Integration/ProductInStockTest.php
index dad08358..bd2e516e 100644
--- a/CatalogInventoryDataExporter/Test/Integration/ProductInStockTest.php
+++ b/CatalogInventoryDataExporter/Test/Integration/ProductInStockTest.php
@@ -33,8 +33,11 @@ public function testProductInStock() : void
$sku = 'simple5';
$storeViewCode = 'default';
- $this->changeInStockStatus($sku);
+ $productId = $this->getProductId($sku);
+ $this->changeInStockStatus($productId);
+
+ $this->emulatePartialReindexBehavior([$productId]);
$extractedProduct = $this->getExtractedProduct($sku, $storeViewCode);
$this->validateProductInStock($extractedProduct);
}
@@ -42,16 +45,12 @@ public function testProductInStock() : void
/**
* Change inStock status of product
*
- * @param string $sku
+ * @param int $productId
* @return void
- * @throws NoSuchEntityException
* @throws \Exception
*/
- protected function changeInStockStatus(string $sku) : void
+ protected function changeInStockStatus(int $productId) : void
{
- $product = $this->productRepository->get($sku);
- $productId = $product->getId();
-
/** @var \Magento\CatalogInventory\Model\Stock\Item $stockItem */
$stockItem = Bootstrap::getObjectManager()->create(Item::class);
$stockItem->load($productId, 'product_id');
diff --git a/CatalogInventoryDataExporter/Test/Integration/ProductLowStockTest.php b/CatalogInventoryDataExporter/Test/Integration/ProductLowStockTest.php
index 597e1c4a..533f18a4 100644
--- a/CatalogInventoryDataExporter/Test/Integration/ProductLowStockTest.php
+++ b/CatalogInventoryDataExporter/Test/Integration/ProductLowStockTest.php
@@ -33,8 +33,11 @@ public function testProductLowStock() : void
$sku = 'simple6';
$storeViewCode = 'default';
- $this->changeLowStockStatus($sku);
+ $productId = $this->getProductId($sku);
+ $this->changeLowStockStatus($productId);
+
+ $this->emulatePartialReindexBehavior([$productId]);
$extractedProduct = $this->getExtractedProduct($sku, $storeViewCode);
$this->validateProductLowStock($extractedProduct);
}
@@ -42,16 +45,12 @@ public function testProductLowStock() : void
/**
* Change lowStock status of product
*
- * @param string $sku
+ * @param int $productId
* @return void
- * @throws NoSuchEntityException
* @throws \Exception
*/
- protected function changeLowStockStatus(string $sku) : void
+ protected function changeLowStockStatus(int $productId) : void
{
- $product = $this->productRepository->get($sku);
- $productId = $product->getId();
-
/** @var \Magento\CatalogInventory\Model\Stock\Item $stockItem */
$stockItem = Bootstrap::getObjectManager()->create(Item::class);
$stockItem->load($productId, 'product_id');
diff --git a/CatalogUrlRewriteDataExporter/Test/Integration/ProductUrlsTest.php b/CatalogUrlRewriteDataExporter/Test/Integration/ProductUrlsTest.php
index d576cb08..72757df6 100644
--- a/CatalogUrlRewriteDataExporter/Test/Integration/ProductUrlsTest.php
+++ b/CatalogUrlRewriteDataExporter/Test/Integration/ProductUrlsTest.php
@@ -96,8 +96,8 @@ public function testGetTechUrlIfUrlRewriteEmpty() : void
$storeViewCode = 'default';
$UrlRewrite = Bootstrap::getObjectManager()->get(DbStorage::class);
$UrlRewrite->deleteByData(['entity_id'=>10]);
- $this->runIndexer([10]);
$product = $this->productRepository->get($sku);
+ $this->emulatePartialReindexBehavior([$product->getId()]);
$extractedProduct = $this->getExtractedProduct($sku, $storeViewCode);
$this->assertEquals(strtok($product->getUrlInStore(), '?'), $extractedProduct['feedData']['url']);
}
diff --git a/ConfigurableProductDataExporter/Model/Provider/Product/Options.php b/ConfigurableProductDataExporter/Model/Provider/Product/Options.php
index b1a7a53a..be0acd74 100755
--- a/ConfigurableProductDataExporter/Model/Provider/Product/Options.php
+++ b/ConfigurableProductDataExporter/Model/Provider/Product/Options.php
@@ -7,7 +7,6 @@
namespace Magento\ConfigurableProductDataExporter\Model\Provider\Product;
-use Exception;
use Magento\CatalogDataExporter\Model\Provider\Product\OptionProviderInterface;
use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
use Magento\ConfigurableProductDataExporter\Model\Query\ProductOptionQuery;
@@ -91,7 +90,7 @@ private function getTable(string $reference)
}
/**
- * Returns possible attribute valies for a product
+ * Returns possible attribute values for a product
*
* @param int $entityId
* @param int $attributeId
@@ -225,6 +224,8 @@ private function getOptionKey($row): string
/**
* @inheritDoc
+ *
+ * @throws UnableRetrieveData
*/
public function get(array $values): array
{
@@ -246,29 +247,12 @@ public function get(array $values): array
try {
$options = [];
$optionValuesData = $this->getOptionValuesData($queryArguments);
-
$select = $this->productOptionQuery->getQuery($queryArguments);
-
$cursor = $this->resourceConnection->getConnection()->query($select);
-
while ($row = $cursor->fetch()) {
- if (!isset($temp[$row['productId'] . '-' . $row['attribute_id']])) {
- $temp[$row['productId'] . '-' . $row['attribute_id']] =
- $this->getPossibleAttributeValues($row['productId'], $row['attribute_id']);
- }
- $filter = $temp[$row['productId'] . '-' . $row['attribute_id']];
-
- $key = $this->getOptionKey($row);
- $options[$key] = $options[$key] ?? $this->formatOptionsRow($row);
-
- if (isset($optionValuesData[$row['attribute_id']][$row['storeViewCode']])) {
- $options[$key]['optionsV2']['values'] = $this->getAssignedAttributeValues(
- $optionValuesData[$row['attribute_id']][$row['storeViewCode']],
- $filter
- );
- }
+ $options = $this->getOptions($row, $temp, $options, $optionValuesData);
}
- } catch (Exception $exception) {
+ } catch (\Throwable $exception) {
$this->logger->error($exception->getMessage(), ['exception' => $exception]);
throw new UnableRetrieveData('Unable to retrieve configurable product options data');
}
@@ -288,4 +272,46 @@ private function getAssignedAttributeValues(array $attributeValuesList, array $a
return !empty($assignedAttributeValues) ? \array_values($assignedAttributeValues) : [];
}
+
+ /**
+ * Get Options
+ *
+ * @param mixed $row
+ * @param array $temp
+ * @param array $options
+ * @param array $optionValuesData
+ * @return array
+ */
+ private function getOptions(mixed $row, array $temp, array $options, array $optionValuesData): array
+ {
+ try {
+ $key = $row['productId'] . '-' . $row['attribute_id'];
+ if (!isset($temp[$key])) {
+ $temp[$key] = $this->getPossibleAttributeValues($row['productId'], $row['attribute_id']);
+ }
+ $filter = $temp[$key];
+
+ $key = $this->getOptionKey($row);
+ $options[$key] = $options[$key] ?? $this->formatOptionsRow($row);
+
+ if (isset($optionValuesData[$row['attribute_id']][$row['storeViewCode']])) {
+ $options[$key]['optionsV2']['values'] = $this->getAssignedAttributeValues(
+ $optionValuesData[$row['attribute_id']][$row['storeViewCode']],
+ $filter
+ );
+ }
+ } catch (\Throwable $exception) {
+ $this->logger->error(
+ sprintf(
+ 'Unable to retrieve configurable product options data
+ (productId:%s, attributeId:%s, storeViewCode:%s)',
+ $row['productId'],
+ $row['attribute_id'],
+ $row['storeViewCode']
+ ),
+ ['exception' => $exception]
+ );
+ }
+ return $options;
+ }
}
diff --git a/ConfigurableProductDataExporter/Test/Integration/ConfigurableProductsTest.php b/ConfigurableProductDataExporter/Test/Integration/ConfigurableProductsTest.php
index 71fddb56..d7020446 100755
--- a/ConfigurableProductDataExporter/Test/Integration/ConfigurableProductsTest.php
+++ b/ConfigurableProductDataExporter/Test/Integration/ConfigurableProductsTest.php
@@ -138,8 +138,6 @@ public function testConfigurableProductsWithOutOfStockChilds(array $outOfStockSk
*/
public function testParentProducts() : void
{
- $this->runIndexer([40, 50, 60, 70]);
-
$skus = ['simple_option_50', 'simple_option_60', 'simple_option_70'];
$storeViewCodes = ['default', 'fixture_second_store'];
@@ -168,8 +166,6 @@ public function testParentProducts() : void
*/
public function testParentProductsOnDifferentWebsites() : void
{
- $this->runIndexer([40, 50, 60, 70, 55, 59, 65]);
-
$skus = [
'simple_option_50' => [
'custom_store_view_one' => true,
diff --git a/DataExporter/Plugin/ForceExporterIndexerModeOnSchedule.php b/DataExporter/Plugin/ForceExporterIndexerModeOnSchedule.php
new file mode 100644
index 00000000..8fff9cf4
--- /dev/null
+++ b/DataExporter/Plugin/ForceExporterIndexerModeOnSchedule.php
@@ -0,0 +1,69 @@
+actionFactory = $actionFactory;
+ $this->logger = $logger;
+ }
+
+ /**
+ * Intercept the setScheduled method to disable Update on Save for exporter indexers
+ *
+ * @param IndexerInterface $indexer
+ * @param callable $proceed
+ * @param bool $scheduled
+ * @return void
+ */
+ public function aroundSetScheduled(IndexerInterface $indexer, callable $proceed, bool $scheduled)
+ {
+ if ($scheduled === true) {
+ return $proceed($scheduled);
+ }
+
+ try {
+ $indexerAction = $this->actionFactory->create($indexer->getActionClass());
+
+ // Check if indexer is one of the DataExporter indexer
+ if ($indexerAction instanceof FeedIndexer) {
+ $this->logger->notice(
+ __("Update on Save (realtime) is not allowed for this indexer: %1", $indexer->getTitle())
+ );
+ return;
+ }
+ } catch (\Throwable $e) {
+ $this->logger->error(
+ 'Data Exporter exception has occurred: ' . $e->getMessage(),
+ ['exception' => $e]
+ );
+ return $proceed($scheduled);
+ }
+
+ return $proceed($scheduled);
+ }
+}
diff --git a/DataExporter/README.md b/DataExporter/README.md
index 94c66620..c82f5bd1 100644
--- a/DataExporter/README.md
+++ b/DataExporter/README.md
@@ -1,3 +1,5 @@
+# Magento_DataExporter module
+
## Release notes
-*Magento_DataExporter* module
\ No newline at end of file
+*Magento_DataExporter* module
diff --git a/DataExporter/Setup/Patch/Schema/SetExporterIndexerOnUpdateOnSchedule.php b/DataExporter/Setup/Patch/Schema/SetExporterIndexerOnUpdateOnSchedule.php
new file mode 100644
index 00000000..e779f75d
--- /dev/null
+++ b/DataExporter/Setup/Patch/Schema/SetExporterIndexerOnUpdateOnSchedule.php
@@ -0,0 +1,105 @@
+schemaSetup = $schemaSetup;
+ $this->logger = $logger;
+ $this->indexerCollection = $indexerCollection;
+ $this->actionFactory = $actionFactory;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function apply()
+ {
+ $this->schemaSetup->startSetup();
+
+ $indexers = $this->indexerCollection->getItems();
+
+ foreach ($indexers as $indexer) {
+ try {
+ $indexerAction = $this->actionFactory->create($indexer->getActionClass());
+
+ if ($indexerAction instanceof \Magento\DataExporter\Model\Indexer\FeedIndexer) {
+ $this->logger->info(
+ sprintf("Setting mode Update On Schedule for indexer %s", $indexer->getTitle())
+ );
+ $indexer->setScheduled(true);
+ }
+ } catch (\Throwable $e) {
+ continue;
+ }
+ }
+
+ $this->schemaSetup->endSetup();
+
+ return $this;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public static function getDependencies()
+ {
+ return [];
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function getAliases()
+ {
+ return [];
+ }
+}
diff --git a/DataExporter/Test/Integration/_files/overrides.xml b/DataExporter/Test/Integration/_files/overrides.xml
index f03d3300..b75e509a 100644
--- a/DataExporter/Test/Integration/_files/overrides.xml
+++ b/DataExporter/Test/Integration/_files/overrides.xml
@@ -29,4 +29,10 @@
+
+
+
+
+
+
diff --git a/DataExporter/composer.json b/DataExporter/composer.json
index b60b3b32..c525cb0b 100644
--- a/DataExporter/composer.json
+++ b/DataExporter/composer.json
@@ -18,6 +18,7 @@
"php": "~8.1.0||~8.2.0",
"magento/framework": ">=103.0.4",
"magento/module-analytics": ">=100.4.4",
- "magento/module-query-xml": "self.version"
+ "magento/module-query-xml": "self.version",
+ "magento/module-indexer": ">=100.4.4"
}
}
diff --git a/DataExporter/etc/di.xml b/DataExporter/etc/di.xml
index ab99bc26..be3f164e 100644
--- a/DataExporter/etc/di.xml
+++ b/DataExporter/etc/di.xml
@@ -67,4 +67,10 @@
+
+
+
+
+
diff --git a/InventoryDataExporter/README.md b/InventoryDataExporter/README.md
index b6c07ca1..07487174 100644
--- a/InventoryDataExporter/README.md
+++ b/InventoryDataExporter/README.md
@@ -7,6 +7,6 @@
- `qtyForSale` calculated based on Reservations API
- Stock is considered as infinite in the following cases:
- Manage Stock disabled
- - [Backorders](https://docs.magento.com/user-guide/catalog/inventory-backorders.html?itm_source=devdocs&itm_medium=quick_search&itm_campaign=federated_search&itm_term=backorer) enabled and Out-of-Stock threshold is set to 0.
+ - [Backorders](https://experienceleague.adobe.com/docs/commerce-admin/inventory/configuration/backorders.html) enabled and Out-of-Stock threshold is set to 0.
- To calculate salable quantity Reservations API is used.
- salable qty is calculated only for indexer in "on schedule" mode to prevent frequent reindexation during place order
diff --git a/InventoryDataExporter/Test/Integration/AbstractInventoryTestHelper.php b/InventoryDataExporter/Test/Integration/AbstractInventoryTestHelper.php
new file mode 100644
index 00000000..ee0e03ea
--- /dev/null
+++ b/InventoryDataExporter/Test/Integration/AbstractInventoryTestHelper.php
@@ -0,0 +1,96 @@
+resource = Bootstrap::getObjectManager()->create(ResourceConnection::class);
+ $this->indexer = Bootstrap::getObjectManager()->create(Indexer::class);
+
+ $this->indexer->load(self::STOCK_STATUS_FEED_INDEXER);
+ $this->reindexStockStatusDataExporterTable();
+ }
+
+ /**
+ * Reindex the full stock status data exporter table
+ *
+ * @return void
+ * @throws \Throwable
+ */
+ private function reindexStockStatusDataExporterTable() : void
+ {
+ $this->indexer->reindexAll();
+ }
+
+ /**
+ * Run partial indexer
+ *
+ * @param array $ids
+ * @return void
+ */
+ protected function emulatePartialReindexBehavior(array $ids = []) : void
+ {
+ $this->indexer->reindexList($ids);
+ }
+
+ /**
+ * @return void
+ */
+ protected function tearDown(): void
+ {
+ parent::tearDown();
+ $this->truncateStockStatusDataExporterIndexTable();
+ }
+
+ /**
+ * Truncates index table
+ */
+ private function truncateStockStatusDataExporterIndexTable(): void
+ {
+ $connection = $this->resource->getConnection();
+ $feedTable = $this->resource->getTableName(self::STOCK_STATUS_FEED_INDEXER);
+ $connection->truncateTable($feedTable);
+
+ $changeLogTable = $this->indexer->getView()->getChangelog()->getName();
+ $connection->truncateTable($changeLogTable);
+ }
+}
diff --git a/InventoryDataExporter/Test/Integration/PartialReindexCheckTest.php b/InventoryDataExporter/Test/Integration/PartialReindexCheckTest.php
index b45c2dd9..491fd3d9 100644
--- a/InventoryDataExporter/Test/Integration/PartialReindexCheckTest.php
+++ b/InventoryDataExporter/Test/Integration/PartialReindexCheckTest.php
@@ -10,6 +10,7 @@
use Magento\DataExporter\Model\FeedInterface;
use Magento\DataExporter\Model\FeedPool;
+use Magento\Indexer\Model\Indexer;
use Magento\InventoryApi\Api\Data\SourceItemInterface;
use Magento\InventoryApi\Api\Data\SourceItemInterfaceFactory;
use Magento\InventoryApi\Api\SourceItemsSaveInterface;
@@ -23,6 +24,8 @@
*/
class PartialReindexCheckTest extends TestCase
{
+ private const STOCK_STATUS_FEED_INDEXER = 'inventory_data_exporter_stock_status';
+
/**
* @var FeedInterface
*/
@@ -43,6 +46,11 @@ class PartialReindexCheckTest extends TestCase
*/
private $bulkSourceUnassign;
+ /**
+ * @var Indexer
+ */
+ protected $indexer;
+
/**
* @inheritDoc
*/
@@ -52,6 +60,7 @@ protected function setUp(): void
$this->sourceItemsFactory = Bootstrap::getObjectManager()->get(SourceItemInterfaceFactory::class);
$this->sourceItemsSave = Bootstrap::getObjectManager()->get(SourceItemsSaveInterface::class);
$this->bulkSourceUnassign = Bootstrap::getObjectManager()->get(BulkSourceUnassignInterface::class);
+ $this->indexer = Bootstrap::getObjectManager()->create(Indexer::class);
}
/**
@@ -59,20 +68,23 @@ protected function setUp(): void
*/
public function testSourceItemQtyUpdated()
{
+ $sku = 'product_in_EU_stock_with_2_sources';
+
$sourceItem = $this->sourceItemsFactory->create(['data' => [
SourceItemInterface::SOURCE_CODE => 'eu-2',
- SourceItemInterface::SKU => 'product_in_EU_stock_with_2_sources',
+ SourceItemInterface::SKU => $sku,
SourceItemInterface::QUANTITY => 2,
SourceItemInterface::STATUS => SourceItemInterface::STATUS_IN_STOCK,
]]);
$this->sourceItemsSave->execute([$sourceItem]);
- $sku = 'product_in_EU_stock_with_2_sources';
+ $this->runIndexer([$sku]);
+
$feedData = $this->getFeedData([$sku]);
self::assertEquals(
[
- 'sku' => 'product_in_EU_stock_with_2_sources',
+ 'sku' => $sku,
'stock_id' => 10,
'qty' => 7.5 // 5.5 (eu-1) + 2 (changed for eu-2)
],
@@ -113,6 +125,8 @@ public function testSourceBulkUnassign()
['eu-1', 'default']
);
+ $this->runIndexer($skus);
+
$feedData = $this->getFeedData($skus);
$sku = 'product_with_default_stock_only';
@@ -193,4 +207,16 @@ private function getFeedData(array $skus): array
}
return $output;
}
+
+ /**
+ * Run the indexer to extract stock item data
+ *
+ * @param array $skus
+ * @return void
+ */
+ private function runIndexer(array $skus = []) : void
+ {
+ $this->indexer->load(self::STOCK_STATUS_FEED_INDEXER);
+ $this->indexer->reindexList($skus);
+ }
}
diff --git a/InventoryDataExporter/Test/Integration/StockStatusScheduledReindexTest.php b/InventoryDataExporter/Test/Integration/StockStatusScheduledReindexTest.php
index b932767a..d889f4fa 100644
--- a/InventoryDataExporter/Test/Integration/StockStatusScheduledReindexTest.php
+++ b/InventoryDataExporter/Test/Integration/StockStatusScheduledReindexTest.php
@@ -8,30 +8,17 @@
namespace Magento\InventoryDataExporter\Test\Integration;
-use Magento\Framework\Indexer\IndexerInterface;
-use Magento\Framework\Indexer\IndexerRegistry;
use Magento\InventoryApi\Api\Data\SourceItemInterface;
use Magento\InventoryApi\Api\Data\SourceItemInterfaceFactory;
use Magento\InventoryApi\Api\SourceItemsSaveInterface;
use Magento\TestFramework\Helper\Bootstrap;
-use PHPUnit\Framework\TestCase;
/**
* @magentoDbIsolation disabled
* @magentoAppIsolation enabled
*/
-class StockStatusScheduledReindexTest extends TestCase
+class StockStatusScheduledReindexTest extends AbstractInventoryTestHelper
{
- /**
- * feed indexer
- */
- private const STOCK_STATUS_FEED_INDEXER = 'inventory_data_exporter_stock_status';
-
- /**
- * @var IndexerInterface
- */
- private $indexer;
-
/**
* @var SourceItemsSaveInterface
*/
@@ -47,20 +34,10 @@ class StockStatusScheduledReindexTest extends TestCase
*/
protected function setUp(): void
{
+ parent::setUp();
+
$this->sourceItemsFactory = Bootstrap::getObjectManager()->get(SourceItemInterfaceFactory::class);
$this->sourceItemsSave = Bootstrap::getObjectManager()->get(SourceItemsSaveInterface::class);
- $indexer = Bootstrap::getObjectManager()->create(IndexerRegistry::class);
- $this->indexer = $indexer->get(self::STOCK_STATUS_FEED_INDEXER);
- $this->indexer->setScheduled(true);
- }
-
- protected function tearDown(): void
- {
- parent::tearDown();
- $changelog = $this->indexer->getView()->getChangelog();
- $currentVersion = $changelog->getVersion();
- $changelog->clear($currentVersion + 1);
- $this->indexer->setScheduled(false);
}
/**
@@ -74,8 +51,8 @@ public function testScheduledUpdate()
$currentVersion = $this->indexer->getView()->getChangelog()->getVersion();
- // check no product added to changelog yet to prevent false-positive result
- self::assertEmpty($this->indexer->getView()->getChangelog()->getList(0, $currentVersion + 1));
+ // check the product is added to changelog due to reindex in the setUp
+ self::assertNotEmpty($this->indexer->getView()->getChangelog()->getList(0, $currentVersion));
$sourceItem = $this->sourceItemsFactory->create(['data' => [
SourceItemInterface::SOURCE_CODE => 'default',
@@ -85,9 +62,9 @@ public function testScheduledUpdate()
]]);
$this->sourceItemsSave->execute([$sourceItem]);
- $currentVersion = $this->indexer->getView()->getChangelog()->getVersion();
+ $newVersion = $this->indexer->getView()->getChangelog()->getVersion();
// verify SKU is present in changelog
- self::assertEquals([$sku], $this->indexer->getView()->getChangelog()->getList(0, $currentVersion + 1));
+ self::assertEquals([$sku], $this->indexer->getView()->getChangelog()->getList($currentVersion, $newVersion));
}
}
diff --git a/InventoryDataExporter/Test/Integration/UnassignProductFromStockTest.php b/InventoryDataExporter/Test/Integration/UnassignProductFromStockTest.php
index a1e7fa6b..57b9a0f0 100644
--- a/InventoryDataExporter/Test/Integration/UnassignProductFromStockTest.php
+++ b/InventoryDataExporter/Test/Integration/UnassignProductFromStockTest.php
@@ -21,7 +21,7 @@
* @magentoDbIsolation disabled
* @magentoAppIsolation enabled
*/
-class UnassignProductFromStockTest extends TestCase
+class UnassignProductFromStockTest extends AbstractInventoryTestHelper
{
/**
* @var FeedInterface
@@ -43,6 +43,8 @@ class UnassignProductFromStockTest extends TestCase
*/
protected function setUp(): void
{
+ parent::setUp();
+
$this->stockStatusFeed = Bootstrap::getObjectManager()->get(FeedPool::class)->getFeed('inventoryStockStatus');
$this->sourceItemProcessor = Bootstrap::getObjectManager()->get(SourceItemsProcessorInterface::class);
$this->bulkSourceUnassign = Bootstrap::getObjectManager()->get(BulkSourceUnassignInterface::class);
@@ -62,6 +64,7 @@ public function testSourceItemStockUnassigned(string $sku, array $sourcesToLeave
$sourceItems = $this->getSourcesData($sku, $sourcesToLeave);
$this->sourceItemProcessor->execute($sku, $sourceItems);
+ $this->emulatePartialReindexBehavior([$sku]);
$feedData = $this->getFeedData([$sku]);
$this->verifyResults($feedData, $sku, $expectedData);
@@ -84,6 +87,7 @@ public function testSourceItemsBulkUnassign(array $skus, array $sourcesToUnassig
$sourcesToUnassign
);
+ $this->emulatePartialReindexBehavior($skus);
$feedData = $this->getFeedData($skus);
foreach ($skus as $sku) {
@@ -108,6 +112,7 @@ private function getFeedData(array $skus): array
}
/**
+ * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
* @return array[]
*/
public function stocksUnassignDataProvider(): array
@@ -237,6 +242,7 @@ public function stocksUnassignDataProvider(): array
}
/**
+ * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
* @return array[]
*/
public function stocksBulkUnassignDataProvider(): array
diff --git a/ProductPriceDataExporter/Test/Integration/AbstractProductPriceTestHelper.php b/ProductPriceDataExporter/Test/Integration/AbstractProductPriceTestHelper.php
index 6aa93d44..cc61768d 100644
--- a/ProductPriceDataExporter/Test/Integration/AbstractProductPriceTestHelper.php
+++ b/ProductPriceDataExporter/Test/Integration/AbstractProductPriceTestHelper.php
@@ -8,6 +8,7 @@
namespace Magento\ProductPriceDataExporter\Test\Integration;
use Magento\Catalog\Api\ProductRepositoryInterface;
+use Magento\Framework\Api\SearchCriteriaInterface;
use Magento\Framework\App\ResourceConnection;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Framework\ObjectManagerInterface;
@@ -55,6 +56,9 @@ protected function setUp(): void
$this->productRepository = $this->objectManager->create(ProductRepositoryInterface::class);
$this->indexer = $this->objectManager->create(Indexer::class);
$this->resourceConnection = $this->objectManager->create(ResourceConnection::class);
+
+ $this->indexer->load(self::PRODUCT_PRICE_FEED_INDEXER);
+ $this->reindexProductPriceDataExporter();
}
/**
@@ -105,17 +109,20 @@ protected function checkExpectedItemsAreExportedInFeed(array $expectedItems): vo
}
/**
- * Run the indexer to extract product prices data
- * @param $ids
+ * Reindex all the product price data exporter table for existing products
+ *
* @return void
*/
- protected function runIndexer($ids): void
+ private function reindexProductPriceDataExporter() : void
{
- try {
- $this->indexer->load(self::PRODUCT_PRICE_FEED_INDEXER);
- $this->indexer->reindexList($ids);
- } catch (\Throwable) {
- throw new \RuntimeException('Could not reindex product prices data');
+ $searchCriteria = Bootstrap::getObjectManager()->create(SearchCriteriaInterface::class);
+
+ $productIds = array_map(function ($product) {
+ return $product->getId();
+ }, $this->productRepository->getList($searchCriteria)->getItems());
+
+ if (!empty($productIds)) {
+ $this->indexer->reindexList($productIds);
}
}
diff --git a/ProductPriceDataExporter/Test/Integration/ExportSingleProductPriceTest.php b/ProductPriceDataExporter/Test/Integration/ExportSingleProductPriceTest.php
index 5e04aa85..91af1a25 100644
--- a/ProductPriceDataExporter/Test/Integration/ExportSingleProductPriceTest.php
+++ b/ProductPriceDataExporter/Test/Integration/ExportSingleProductPriceTest.php
@@ -25,6 +25,9 @@
*/
class ExportSingleProductPriceTest extends AbstractProductPriceTestHelper
{
+ /**
+ * @var CatalogRuleRepositoryInterface $catalogRuleRepository
+ */
private CatalogRuleRepositoryInterface $catalogRuleRepository;
protected function setUp(): void
@@ -82,11 +85,6 @@ public function testExportSimpleProductsWithDisabledCatalogPriceRulePrices(array
*/
public function testExportDownloadableProductsPrices(array $expectedDownloadableProductPricesDataProvider): void
{
- $affectedIds = [];
- foreach ($expectedDownloadableProductPricesDataProvider as $expectedItem) {
- $affectedIds[] = $this->productRepository->get($expectedItem['sku'])->getId();
- }
- $this->runIndexer($affectedIds);
$this->checkExpectedItemsAreExportedInFeed($expectedDownloadableProductPricesDataProvider);
}
diff --git a/ProductPriceDataExporter/Test/Integration/ExportSingleProductPriceUpdateOperationsTest.php b/ProductPriceDataExporter/Test/Integration/ExportSingleProductPriceUpdateOperationsTest.php
index 010cfaf9..c2df2552 100644
--- a/ProductPriceDataExporter/Test/Integration/ExportSingleProductPriceUpdateOperationsTest.php
+++ b/ProductPriceDataExporter/Test/Integration/ExportSingleProductPriceUpdateOperationsTest.php
@@ -39,11 +39,6 @@ class ExportSingleProductPriceUpdateOperationsTest extends AbstractProductPriceT
*/
public function testUnassignProductFromWebsite(array $expectedSimpleProductPrices): void
{
- $affectedIds = [];
- foreach ($expectedSimpleProductPrices as $expectedItem) {
- $affectedIds[] = $this->productRepository->get($expectedItem['sku'])->getId();
- }
- $this->runIndexer($affectedIds);
$product = $this->productRepository->get('simple_product_with_tier_price');
$websiteRepository = $this->objectManager->get(WebsiteRepositoryInterface::class);
$secondWebsiteId = $websiteRepository->get('test')->getId();
@@ -66,11 +61,6 @@ public function testUnassignProductFromWebsite(array $expectedSimpleProductPrice
*/
public function testDisableProductGlobally(array $expectedSimpleProductPrices): void
{
- $affectedIds = [];
- foreach ($expectedSimpleProductPrices as $expectedItem) {
- $affectedIds[] = $this->productRepository->get($expectedItem['sku'])->getId();
- }
- $this->runIndexer($affectedIds);
//Get product for edit in general scope (all websites)
$product = $this->productRepository->get('simple_product_with_tier_price', true, 0);
//Disable it on general level
@@ -94,11 +84,6 @@ public function testDisableProductGlobally(array $expectedSimpleProductPrices):
*/
public function testEnableProductOnWebsite(array $expectedSimpleProductPrices): void
{
- $affectedIds = [];
- foreach ($expectedSimpleProductPrices as $expectedItem) {
- $affectedIds[] = $this->productRepository->get($expectedItem['sku'])->getId();
- }
- $this->runIndexer($affectedIds);
//Get product for edit in general scope (all websites)
$product = $this->productRepository->get('simple_product_with_tier_price', true, 0);
//Disable it on general level
@@ -133,18 +118,12 @@ public function testEnableProductOnWebsite(array $expectedSimpleProductPrices):
*/
public function testReassignProductToWebsite(array $expectedSimpleProductPrices): void
{
- $affectedIds = [];
- foreach ($expectedSimpleProductPrices as $expectedItem) {
- $affectedIds[] = $this->productRepository->get($expectedItem['sku'])->getId();
- }
- $this->runIndexer($affectedIds);
$product = $this->productRepository->get('simple_product_with_tier_price');
$websiteRepository = $this->objectManager->get(WebsiteRepositoryInterface::class);
$firstWebsiteId = $websiteRepository->get('base')->getId();
$secondWebsiteId = $websiteRepository->get('test')->getId();
$product->setWebsiteIds([$secondWebsiteId]);
$this->productRepository->save($product);
- $this->runIndexer($affectedIds);
$product->setWebsiteIds([$firstWebsiteId, $secondWebsiteId]);
$this->productRepository->save($product);
diff --git a/ProductPriceDataExporter/etc/mview.xml b/ProductPriceDataExporter/etc/mview.xml
index 9a3e3caf..c7258943 100644
--- a/ProductPriceDataExporter/etc/mview.xml
+++ b/ProductPriceDataExporter/etc/mview.xml
@@ -11,7 +11,6 @@
-
diff --git a/SalesOrdersDataExporter/Model/Provider/CreditMemoComment.php b/SalesOrdersDataExporter/Model/Provider/CreditMemoComment.php
new file mode 100644
index 00000000..1d6b12bd
--- /dev/null
+++ b/SalesOrdersDataExporter/Model/Provider/CreditMemoComment.php
@@ -0,0 +1,32 @@
+ $creditMemo['entityId'],
+ 'creditMemoComments' => $creditMemo['comment'],
+ ];
+ }
+ }
+ return $output;
+ }
+}
diff --git a/SalesOrdersDataExporter/Setup/Recurring.php b/SalesOrdersDataExporter/Setup/Recurring.php
deleted file mode 100644
index 27dab00e..00000000
--- a/SalesOrdersDataExporter/Setup/Recurring.php
+++ /dev/null
@@ -1,83 +0,0 @@
-logger = $logger;
- $this->indexerInterfaceFactory = $indexerInterfaceFactory;
- }
-
- /**
- * If orders indexer is found, will force mode to be On Schedule
- *
- * @param SchemaSetupInterface $setup
- * @param ModuleContextInterface $context
- * @return void
- *
- * @SuppressWarnings(PHPMD.UnusedFormalParameter)
- */
- public function install(SchemaSetupInterface $setup, ModuleContextInterface $context): void
- {
- $setup->startSetup();
-
- $ordersIndexer = $this->findOrdersIndexer();
- if ($ordersIndexer && !$ordersIndexer->isScheduled()) {
- $ordersIndexer->setScheduled(true);
- $this->logger->info(
- 'Mode for indexer sales_order_data_exporter_v2 has been forced to \'Update by Schedule\'.'
- );
- }
-
- $setup->endSetup();
- }
-
- /**
- * Finds orders indexer in the set of available indexers
- *
- * @return IndexerInterface|null
- */
- private function findOrdersIndexer(): ?IndexerInterface
- {
- try {
- return $this->indexerInterfaceFactory->create()->load(self::ORDERS_INDEXER_NAME);
- } catch (InvalidArgumentException) {
- // ignored, if not found is expected to do nothing
- return null;
- }
- }
-}
diff --git a/SalesOrdersDataExporter/Test/Integration/AbstractOrderFeedTest.php b/SalesOrdersDataExporter/Test/Integration/AbstractOrderFeedTest.php
index acb7ce89..9317b73e 100644
--- a/SalesOrdersDataExporter/Test/Integration/AbstractOrderFeedTest.php
+++ b/SalesOrdersDataExporter/Test/Integration/AbstractOrderFeedTest.php
@@ -118,7 +118,7 @@ protected function runIndexer(array $ids) : void
$this->indexer->load(self::ORDER_FEED_INDEXER);
$this->indexer->reindexList($ids);
} catch (Throwable $e) {
- throw new RuntimeException('Could not reindex orders data');
+ throw new RuntimeException('Could not reindex orders data', $e);
}
}
}
diff --git a/SalesOrdersDataExporter/Test/Integration/CreateOrderTest.php b/SalesOrdersDataExporter/Test/Integration/CreateOrderTest.php
index eb51e7b9..7d781693 100644
--- a/SalesOrdersDataExporter/Test/Integration/CreateOrderTest.php
+++ b/SalesOrdersDataExporter/Test/Integration/CreateOrderTest.php
@@ -7,17 +7,19 @@
namespace Magento\SalesOrdersDataExporter\Test\Integration;
+use Magento\DataExporter\Uuid\ResourceModel\UuidResource;
+use Magento\Framework\Exception\InputException;
+use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Sales\Api\Data\OrderInterface;
use Magento\Sales\Api\Data\OrderInterfaceFactory;
-use Magento\DataExporter\Uuid\ResourceModel\UuidResource;
use Magento\Sales\Api\Data\OrderItemInterface;
use Magento\Sales\Api\Data\ShipmentTrackInterface;
use Magento\Sales\Model\Order;
use Magento\Sales\Model\Order\Creditmemo;
use Magento\Sales\Model\Order\Invoice;
+use Magento\Sales\Model\Order\Payment\Transaction\Repository as TransactionRepository;
use Magento\Sales\Model\Order\Shipment;
use Magento\TestFramework\Helper\Bootstrap;
-use Magento\Sales\Model\Order\Payment\Transaction\Repository as TransactionRepository;
/**
* Test for orders data exporter functionality
@@ -60,425 +62,208 @@ protected function setUp(): void
}
/**
- * @param string $orderNumber
- * @param string[] $dataToVerify
- *
- * @dataProvider orderWithTwoItemsDataProvider
* @magentoDataFixture Magento/Sales/_files/customer_order_with_two_items.php
*
* @return void
* @throws \Zend_Db_Statement_Exception
- * @throws \Magento\Framework\Exception\InputException
+ * @throws InputException|NoSuchEntityException
*/
- public function testOrderWithTwoProductsInformation(string $orderNumber, array $dataToVerify): void
+ public function testOrderWithTwoProductsInformation(): void
{
/** @var OrderInterface $order */
- $order = $this->orderFactory->create()->loadByIncrementId($orderNumber);
+ $order = $this->orderFactory->create()->loadByIncrementId('100000555');
$orderId = $order->getEntityId();
$this->runIndexer([$orderId]);
+
$orderFeed = $this->getOrderFeedByIds([$orderId])[0];
- $expectedOrdersData = $this->getOrderDataToVerify($order, $dataToVerify);
+ $expectedOrderData = $this->getOrderDataToVerify($order);
- $this->checkFields($expectedOrdersData, $orderFeed);
+ $this->checkFields($expectedOrderData, $orderFeed);
}
/**
- * @param string $orderNumber
- * @param string[] $dataToVerify
- *
- * @dataProvider orderFullWorkflowDataProvider
- * @magentoDataFixture Magento_SalesOrdersDataExporter::Test/_files/order_full_work_flow.php
+ * @magentoDataFixture Magento/Sales/_files/customer_order_with_taxable_product.php
*
* @return void
* @throws \Zend_Db_Statement_Exception
*/
- public function testOrderFullWorkflowInformation(string $orderNumber, array $dataToVerify): void
+ public function testOrderWithTaxableProductInformation(): void
{
/** @var OrderInterface $order */
- $order = $this->orderFactory->create()->loadByIncrementId($orderNumber);
+ $order = $this->orderFactory->create()->loadByIncrementId('test_order_with_taxable_product');
$orderId = $order->getEntityId();
$this->runIndexer([$orderId]);
+
$orderFeed = $this->getOrderFeedByIds([$orderId])[0];
- $expectedOrdersData = $this->getOrderDataToVerify($order, $dataToVerify);
+ $expectedOrderData = $this->getOrderDataToVerify($order);
- $this->checkFields($expectedOrdersData, $orderFeed);
+ $this->checkFields($expectedOrderData, $orderFeed);
}
/**
- * @param string $orderNumber
- * @param string[] $dataToVerify
- *
- * @dataProvider orderWithTaxableProductDataProvider
- * @magentoDataFixture Magento/Sales/_files/customer_order_with_taxable_product.php
+ * @magentoDataFixture Magento/Sales/_files/order_with_invoice_and_custom_status.php
*
* @return void
* @throws \Zend_Db_Statement_Exception
*/
- public function testOrderWithTaxableProductInformation(string $orderNumber, array $dataToVerify): void
+ public function testOrderWithInvoiceAndCustomStatus(): void
{
/** @var OrderInterface $order */
- $order = $this->orderFactory->create()->loadByIncrementId($orderNumber);
+ $order = $this->orderFactory->create()->loadByIncrementId('100000001');
$orderId = $order->getEntityId();
$this->runIndexer([$orderId]);
+
$orderFeed = $this->getOrderFeedByIds([$orderId])[0];
- $expectedOrdersData = $this->getOrderDataToVerify($order, $dataToVerify);
+ $expectedOrderData = $this->getOrderDataToVerify($order);
- $this->checkFields($expectedOrdersData, $orderFeed);
+ $this->checkFields($expectedOrderData, $orderFeed);
}
/**
- * @param string $orderNumber
- * @param string[] $dataToVerify
- *
- * @dataProvider orderWithInvoiceAndCustomStatusDataProvider
- * @magentoDataFixture Magento/Sales/_files/order_with_invoice_and_custom_status.php
+ * @magentoDataFixture Magento_SalesOrdersDataExporter::Test/_files/order_full_work_flow.php
*
* @return void
* @throws \Zend_Db_Statement_Exception
*/
- public function testOrderWithInvoiceAndCustomStatus(string $orderNumber, array $dataToVerify): void
+ public function testOrderFullWorkflowInformation(): void
{
/** @var OrderInterface $order */
- $order = $this->orderFactory->create()->loadByIncrementId($orderNumber);
+ $order = $this->orderFactory->create()->loadByIncrementId('100000001');
$orderId = $order->getEntityId();
$this->runIndexer([$orderId]);
+
$orderFeed = $this->getOrderFeedByIds([$orderId])[0];
- $expectedOrdersData = $this->getOrderDataToVerify($order, $dataToVerify);
+ $expectedOrderData = $this->getOrderDataToVerify($order);
- $this->checkFields($expectedOrdersData, $orderFeed);
+ $this->checkFields($expectedOrderData, $orderFeed);
}
/**
- * @param string $orderNumber
- * @param string[] $dataToVerify
- *
- * @dataProvider orderWithCreditMemoDataProvider
* @magentoDataFixture Magento_SalesOrdersDataExporter::Test/_files/order_with_invoice_shipment_creditmemo.php
*
* @return void
* @throws \Zend_Db_Statement_Exception
*/
- public function testOrderWithCreditMemo(string $orderNumber, array $dataToVerify): void
+ public function testOrderWithCreditMemo(): void
{
/** @var OrderInterface $order */
- $order = $this->orderFactory->create()->loadByIncrementId($orderNumber);
+ $order = $this->orderFactory->create()->loadByIncrementId('100000111');
$orderId = $order->getEntityId();
$this->runIndexer([$orderId]);
+
$orderFeed = $this->getOrderFeedByIds([$orderId])[0];
- $expectedOrdersData = $this->getOrderDataToVerify($order, $dataToVerify);
+ $expectedOrderData = $this->getOrderDataToVerify($order);
- $this->checkFields($expectedOrdersData, $orderFeed);
+ $this->checkFields($expectedOrderData, $orderFeed);
}
/**
- * @param string $orderNumber
- * @param string[] $dataToVerify
- *
- * @dataProvider orderWithConfigurableProductDataProvider
* @magentoDataFixture Magento_SalesOrdersDataExporter::Test/_files/order_configurable_product.php
*
* @return void
* @throws \Zend_Db_Statement_Exception
*/
- public function testOrderWithConfigurableProduct(string $orderNumber, array $dataToVerify): void
+ public function testOrderWithConfigurableProduct(): void
{
/** @var OrderInterface $order */
- $order = $this->orderFactory->create()->loadByIncrementId($orderNumber);
+ $order = $this->orderFactory->create()->loadByIncrementId('100000001');
$orderId = $order->getEntityId();
$this->runIndexer([$orderId]);
+
$orderFeed = $this->getOrderFeedByIds([$orderId])[0];
- $expectedOrdersData = $this->getOrderDataToVerify($order, $dataToVerify);
+ $expectedOrderData = $this->getOrderDataToVerify($order);
- $this->checkFields($expectedOrdersData, $orderFeed);
+ $this->checkFields($expectedOrderData, $orderFeed);
}
/**
- * @param string $orderNumber
- * @param string[] $dataToVerify
- *
- * @dataProvider orderWithTransactionsDataProvider
* @magentoDataFixture Magento_SalesOrdersDataExporter::Test/_files/transactions_detailed.php
*
* @return void
* @throws \Zend_Db_Statement_Exception
*/
- public function testOrderWithTransactions(string $orderNumber, array $dataToVerify): void
+ public function testOrderWithTransactions(): void
{
/** @var OrderInterface $order */
- $order = $this->orderFactory->create()->loadByIncrementId($orderNumber);
+ $order = $this->orderFactory->create()->loadByIncrementId('100000001');
$orderId = $order->getEntityId();
$this->runIndexer([$orderId]);
+
$orderFeed = $this->getOrderFeedByIds([$orderId])[0];
- $expectedOrdersData = $this->getOrderDataToVerify($order, $dataToVerify);
+ $expectedOrderData = $this->getOrderDataToVerify($order);
- $this->checkFields($expectedOrdersData, $orderFeed);
+ $this->checkFields($expectedOrderData, $orderFeed);
}
/**
- * @param string $orderNumber
- * @param string[] $dataToVerify
- *
- * @dataProvider orderWithAdditionalInformationDataProvider
* @magentoDataFixture Magento_SalesOrdersDataExporter::Test/_files/order_with_additional_information.php
*
* @return void
* @throws \Zend_Db_Statement_Exception
*/
- public function testOrderWithAdditionalData(string $orderNumber, array $dataToVerify): void
+ public function testOrderWithAdditionalData(): void
{
/** @var OrderInterface $order */
- $order = $this->orderFactory->create()->loadByIncrementId($orderNumber);
+ $order = $this->orderFactory->create()->loadByIncrementId('100000001');
$orderId = $order->getEntityId();
$this->runIndexer([$orderId]);
- $orderFeed = $this->getOrderFeedByIds([$orderId])[0];
- $expectedOrdersData = $this->getOrderDataToVerify($order, $dataToVerify);
-
- $this->checkFields($expectedOrdersData, $orderFeed);
- }
-
- /**
- * @return array[]
- */
- public function orderWithTwoItemsDataProvider(): array
- {
- return [
- [
- 'order_number' => '100000555', //customer_order_with_two_items
- 'entities_to_verify' => [
- 'order_data',
- 'items'
- ]
- ]
- ];
- }
-
- /**
- * @return array[]
- */
- public function orderWithTaxableProductDataProvider(): array
- {
- return [
- [
- 'order_number' => 'test_order_with_taxable_product', //customer_order_with_taxable_product
- 'entities_to_verify' => [
- 'order_data',
- 'items'
- ]
- ]
- ];
- }
- /**
- * @return array[]
- */
- public function orderFullWorkflowDataProvider(): array
- {
- return [
- [
- 'order_number' => '100000001', //order_full_work_flow
- 'entities_to_verify' => [
- 'order_data',
- 'items',
- 'shipments',
- 'invoice'
- ]
- ]
- ];
- }
-
- /**
- * @return array[]
- */
- public function orderWithInvoiceAndCustomStatusDataProvider(): array
- {
- return [
- [
- 'order_number' => '100000001', //order_with_invoice_and_custom_status
- 'entities_to_verify' => [
- 'order_data',
- 'items',
- 'invoice'
- ]
- ],
- ];
- }
-
- /**
- * @return array[]
- */
- public function orderWithCreditMemoDataProvider(): array
- {
- return [
- [
- 'order_number' => '100000111', //order_with_invoice_shipment_creditmemo
- 'entities_to_verify' => [
- 'order_data',
- 'items',
- 'credit_memo'
- ]
- ],
- ];
- }
+ $orderFeed = $this->getOrderFeedByIds([$orderId])[0];
+ $expectedOrderData = $this->getOrderDataToVerify($order);
- /**
- * @return array[]
- */
- public function orderWithConfigurableProductDataProvider(): array
- {
- return [
- [
- 'order_number' => '100000001', //order_configurable_product
- 'entities_to_verify' => [
- 'order_data',
- 'items'
- ]
- ],
- ];
+ $this->checkFields($expectedOrderData, $orderFeed);
}
/**
- * @return array[]
+ * @param array $expectedData
+ * @param array $feedData
*/
- public function orderWithTransactionsDataProvider(): array
+ private function checkFields(array $expectedData, array $feedData): void
{
- return [
- [
- 'order_number' => '100000001', //transactions_detailed
- 'entities_to_verify' => [
- 'order_data',
- 'transactions'
- ]
- ],
- ];
+ foreach ($expectedData as $field => $expectedValue) {
+ if (is_array($expectedValue)) {
+ $this->assertArrayHasKey($field, $feedData, sprintf('Field %s is not set in feed', $field));
+ $this->checkFields($expectedValue, $feedData[$field]);
+ } else {
+ $this->assertFieldEquals($field, $expectedValue, $feedData);
+ }
+ }
}
/**
- * @return array[]
+ * @param mixed $fieldName
+ * @param mixed $expectedValue
+ * @param array $actualData
*/
- public function orderWithAdditionalInformationDataProvider(): array
+ private function assertFieldEquals(mixed $fieldName, mixed $expectedValue, array $actualData): void
{
- return [
- [
- 'order_number' => '100000001', //additional_information
- 'entities_to_verify' => [
- 'order_data',
- 'items',
- 'additional_information'
- ]
- ],
- ];
- }
-
- /**
- * @param array $expectedOrderData
- * @param array $feedData
- *
- * @SuppressWarnings(PHPMD.CyclomaticComplexity)
- * @SuppressWarnings(PHPMD.NPathComplexity)
- */
- private function checkFields(array $expectedOrderData, array $feedData): void
- {
- foreach ($expectedOrderData as $expectedField => $expectedData) {
- if ($expectedField === 'items') {
- $uncheckedIds = \array_flip(array_keys($expectedData));
- foreach ($feedData['items'] as $itemData) {
- $itemIdField = isset($itemData['itemId']) ? 'itemId' : 'orderItemId';
- $expectedDataId = $itemData[$itemIdField]['id'];
- if (isset($itemData[$itemIdField])) {
- $this->checkFields($expectedData[$expectedDataId], $itemData);
- unset($uncheckedIds[$expectedDataId]);
- }
- }
- self::assertEmpty($uncheckedIds, "Some items are missed in feed");
- continue;
- }
- if ($expectedField === 'shipments') {
- $uncheckedIds = \array_flip(array_keys($expectedData));
- foreach ($feedData['shipments'] as $itemData) {
- $this->checkFields($expectedData[$itemData['shipmentId']['id']], $itemData);
- unset($uncheckedIds[$itemData['shipmentId']['id']]);
- }
- self::assertEmpty($uncheckedIds, "Some shipment items are missed in feed");
- continue;
- }
- if ($expectedField === 'invoices') {
- $uncheckedIds = \array_flip(array_keys($expectedData));
- foreach ($feedData['invoices'] as $itemData) {
- $invoiceId = $itemData['entityId'];
- $expectedInvoiceData = $expectedData[$invoiceId];
- $this->checkFields($expectedInvoiceData, $itemData);
- unset($uncheckedIds[$invoiceId]);
- }
- self::assertEmpty($uncheckedIds, "Some invoice items are missed in feed");
- continue;
- }
-
- if ($expectedField === 'creditMemos') {
- $uncheckedIds = \array_flip(array_keys($expectedData));
- foreach ($feedData[$expectedField] as $itemData) {
- $this->checkFields($expectedData[$itemData['creditMemoId']['id']], $itemData);
- unset($uncheckedIds[$itemData['creditMemoId']['id']]);
- }
- self::assertEmpty($uncheckedIds, "Some credit memo items are missed in feed");
- continue;
- }
-
- if ($expectedField === 'transactions') {
- $uncheckedIds = \array_flip(array_keys($expectedData));
- foreach ($feedData[$expectedField] as $itemData) {
- $this->checkFields($expectedData[$itemData['entityId']], $itemData);
- unset($uncheckedIds[$itemData['entityId']]);
- }
- self::assertEmpty($uncheckedIds, "Some transaction items are missed in feed");
- continue;
- }
-
- if (isset($feedData[$expectedField])) {
- if (!\is_array($feedData[$expectedField])) {
- self::assertEquals(
- $expectedData,
- $feedData[$expectedField],
- sprintf(
- "Expected data: %s doesn't equal to real field %s value: %s",
- $expectedData,
- $expectedField,
- $feedData[$expectedField]
- )
- );
- } else {
- $this->checkFields($expectedData, $feedData[$expectedField]);
- }
- }
+ if (array_key_exists($fieldName, $actualData)) {
+ self::assertEquals(
+ $expectedValue,
+ $actualData[$fieldName],
+ "Expected data: $expectedValue doesn't equal to real field $fieldName value: {$actualData[$fieldName]}"
+ );
+ } else {
+ self::assertNull(
+ $expectedValue,
+ "Field $fieldName is not set in feed but the expected value was $expectedValue"
+ );
}
}
/**
* @param OrderInterface $order
- * @param array $dataToVerify
* @return array
- * @throws \Magento\Framework\Exception\InputException
+ * @throws InputException
*/
- private function getOrderDataToVerify(OrderInterface $order, array $dataToVerify): array
+ private function getOrderDataToVerify(OrderInterface $order): array
{
- $expectedOrderData = [];
- if (array_contains($dataToVerify, 'order_data')) {
- $expectedOrderData = $this->getExpectedOrderData($order);
- }
- if (array_contains($dataToVerify, 'transactions')) {
- $expectedOrderData['transactions'] = $this->getExpectedTransactionsData($order);
- }
- if (array_contains($dataToVerify, 'items')) {
- $expectedOrderData['items'] = $this->getExpectedOrderItemsData($order);
- }
- if (array_contains($dataToVerify, 'invoice')) {
- $expectedOrderData['invoices'] = $this->getExpectedInvoicesData($order);
- }
- if (array_contains($dataToVerify, 'credit_memo')) {
- $expectedOrderData['creditMemos'] = $this->getExpectedCreditMemosData($order);
- }
- if (array_contains($dataToVerify, 'shipments')) {
- $expectedOrderData['shipments'] = $this->getExpectedShipmentData($order);
- }
+ $expectedOrderData = $this->getExpectedOrderData($order);
+ $expectedOrderData['transactions'] = $this->getExpectedTransactionsData($order);
+ $expectedOrderData['items'] = $this->getExpectedOrderItemsData($order);
+ $expectedOrderData['invoices'] = $this->getExpectedInvoicesData($order);
+ $expectedOrderData['creditMemos'] = $this->getExpectedCreditMemosData($order);
+ $expectedOrderData['shipments'] = $this->getExpectedShipmentData($order);
return $expectedOrderData;
}
@@ -493,13 +278,13 @@ private function getOrderDataToVerify(OrderInterface $order, array $dataToVerify
*/
private function getOrderFeedByIds(array $ids, bool $excludeDeleted = false): array
{
- $output = [];
- foreach ($this->ordersFeed->getFeedSince('1')['feed'] as $item) {
- if ((!$excludeDeleted || !$item['deleted']) && \in_array($item['commerceOrderId'], $ids)) {
- $output[] = $item;
+ $filteredFeed = array_filter(
+ $this->ordersFeed->getFeedSince('1')['feed'],
+ function ($item) use ($ids, $excludeDeleted) {
+ return (!$excludeDeleted || !$item['deleted']) && in_array($item['commerceOrderId'], $ids);
}
- }
- return $output;
+ );
+ return array_values($filteredFeed);
}
/**
@@ -540,7 +325,7 @@ private function getExpectedOrderData(OrderInterface $order): array
{
$orderId = $order->getEntityId();
return [
- 'entityId' => $order->getEntityId(),
+ 'commerceOrderId' => $order->getEntityId(),
'commerceOrderNumber' => $order->getIncrementId(),
'orderId' => ['id' => $this->uuidResource->getAssignedIds([$orderId], 'order')[$orderId]],
'externalId' => ['id' => $orderId, 'salesChannel' => 'magento'],
@@ -549,15 +334,23 @@ private function getExpectedOrderData(OrderInterface $order): array
'state' => $this->mapOrderState($order->getState()),
'status' => $order->getStatus(),
'totalInvoiced' => $order->getBaseTotalInvoiced(),
+ 'totalQtyOrdered' => $order->getTotalQtyOrdered(),
+ 'isVirtual' => $this->convertIntToBool($order->getIsVirtual()),
+ 'currency' => $order->getBaseCurrencyCode(),
'subtotal' => $order->getBaseSubtotal(),
'grandTotal' => $order->getBaseGrandTotal(),
'discountAmount' => $order->getBaseDiscountAmount(),
- 'currency' => $order->getBaseCurrencyCode(),
+ 'amountCapturedOnline' => $order->getPayment()->getBaseAmountPaidOnline(),
+ 'amountRefundedOnline' => $order->getPayment()->getBaseAmountRefundedOnline(),
+ 'amountAuthorized' => $order->getPayment()->getBaseAmountAuthorized(),
'amountPaid' => $order->getPayment()->getBaseAmountPaid(),
+ 'amountRefunded' => $order->getPayment()->getBaseAmountRefunded(),
+ 'amountCanceled' => $order->getPayment()->getBaseAmountCanceled(),
'storeViewCode' => $order->getStore()->getCode(),
'websiteCode' => $order->getStore()->getWebsite()->getCode(),
'storeCode' => $order->getStore()->getWebsite()->getDefaultGroup()->getCode(),
'customerEmail' => $order->getCustomerEmail(),
+ 'customerNote' => $order->getCustomerNote(),
'additionalInformation' => $this->getExpectedOrderAdditionalInformationData($order),
'payment' => [
'billingAddress' => [
@@ -570,8 +363,8 @@ private function getExpectedOrderData(OrderInterface $order): array
'country' => $order->getBillingAddress()->getCountryId(),
'firstname' => $order->getBillingAddress()->getFirstname()
],
- 'paymentMethodName' => $order->getPayment()->getAdditionalInformation()['method_title'] ?? '',
- 'paymentMethodCode' => $order->getPayment()->getMethod() ?? '',
+ 'paymentMethodName' => $order->getPayment()->getAdditionalInformation()['method_title'] ?? null,
+ 'paymentMethodCode' => $order->getPayment()->getMethod() ?? null,
'totalAmount' => $order->getBaseSubtotal(),
'taxAmount' => $order->getBaseTaxAmount(),
'currency' => $order->getOrderCurrencyCode()
@@ -598,10 +391,10 @@ private function getExpectedOrderData(OrderInterface $order): array
/**
* @param OrderInterface $order
- * @return array
- * @throws \Magento\Framework\Exception\InputException
+ * @return array|null
+ * @throws InputException
*/
- private function getExpectedTransactionsData(OrderInterface $order): array
+ private function getExpectedTransactionsData(OrderInterface $order): ?array
{
$transactions = [];
foreach (self::TRANSACTION_TYPES as $transactionType) {
@@ -610,8 +403,8 @@ private function getExpectedTransactionsData(OrderInterface $order): array
$order->getPayment()->getEntityId()
);
if ($transaction) {
- $transactions[$transaction->getId()] = [
- 'id' => $transaction->getId(),
+ $transactions[] = [
+ 'entityId' => $transaction->getId(),
'txnId' => $transaction->getTxnId(),
'type' => $transaction->getTxnType(),
'createdAt' => $this->convertDate($transaction->getCreatedAt())
@@ -619,24 +412,24 @@ private function getExpectedTransactionsData(OrderInterface $order): array
}
}
- return $transactions;
+ return empty($transactions) ? null : $transactions;
}
/**
* @param OrderInterface $order
- * @return array
+ * @return array|null
*/
- private function getExpectedOrderItemsData(OrderInterface $order): array
+ private function getExpectedOrderItemsData(OrderInterface $order): ?array
{
$items = [];
foreach ($order->getItems() as $orderItem) {
$itemId = $orderItem->getItemId();
$itemUuid = $this->uuidResource->getAssignedIds([$itemId], 'order_item')[$itemId];
- $items[$itemUuid] = [
+ $items[] = [
'itemId' => ['id' => $itemUuid],
'entityId' => $itemId,
'parentEntityId' => $orderItem->getParentItemId(),
- 'isVirtual' => (bool)$orderItem->getIsVirtual(),
+ 'isVirtual' => $this->convertIntToBool($orderItem->getIsVirtual()),
'qtyInvoiced' => $orderItem->getQtyInvoiced(),
'qtyShipped' => $orderItem->getQtyShipped(),
'qtyBackordered' => $orderItem->getQtyBackordered(),
@@ -646,7 +439,7 @@ private function getExpectedOrderItemsData(OrderInterface $order): array
'productType' => $orderItem->getProductType(),
'itemsShippedTogether' => $orderItem->getProductType() === 'configurable',
'sku' => $orderItem->getSku(),
- 'productSku' => $orderItem->getProduct()->getSku(),
+ 'productSku' => $this->getExpectedOrderItemProductSku($orderItem),
'name' => $orderItem->getName(),
'qty' => $orderItem->getQtyOrdered(),
'unitPrice' => $orderItem->getBasePrice(),
@@ -658,17 +451,31 @@ private function getExpectedOrderItemsData(OrderInterface $order): array
'additionalInformation' => $this->getExpectedItemAdditionalInformationData($orderItem)
];
}
- return $items;
+ return empty($items) ? null : $items;
+ }
+
+ /**
+ * Get the product SKU based on the product type.
+ *
+ * @param OrderItemInterface $orderItem
+ * @return string|null
+ */
+ private function getExpectedOrderItemProductSku(OrderItemInterface $orderItem): ?string
+ {
+ if (in_array($orderItem->getProductType(), ['configurable', 'bundle'], true)) {
+ return $orderItem->getProduct()->getSku();
+ }
+
+ return $orderItem->getSku();
}
/**
* @param OrderInterface $order
- * @return array
+ * @return array|null
*/
- private function getExpectedInvoicesData(OrderInterface $order): array
+ private function getExpectedInvoicesData(OrderInterface $order): ?array
{
$invoices = [];
-
/** @var Invoice $invoice */
foreach ($order->getInvoiceCollection() as $invoice) {
$invoiceId = $invoice->getId();
@@ -677,28 +484,29 @@ private function getExpectedInvoicesData(OrderInterface $order): array
foreach ($invoice->getItems() as $invoiceItem) {
$orderItemId = $invoiceItem->getOrderItemId();
$itemUuid = $this->uuidResource->getAssignedIds([$orderItemId], 'order_item')[$orderItemId];
- $invoiceItems[$orderItemId] = [
+ $invoiceItems[] = [
'orderItemId' => ['id' => $itemUuid],
'qtyInvoiced' => $invoiceItem->getQty()
];
}
- $invoices[$invoiceId] = [
+ $invoices[] = [
'entityId' => $invoiceId,
- 'isUsedForRefund' => false,
+ 'isUsedForRefund' => $this->convertIntToBool($invoice->getIsUsedForRefund()),
'grandTotal' => $invoice->getBaseGrandTotal(),
'createdAt' => $this->convertDate($invoice->getCreatedAt()),
'commerceInvoiceNumber' => $invoice->getIncrementId(),
'invoiceItems' => $invoiceItems
];
}
- return $invoices;
+
+ return empty($invoices) ? null : $invoices;
}
/**
* @param OrderInterface $order
- * @return array
+ * @return array|null
*/
- private function getExpectedCreditMemosData(OrderInterface $order): array
+ private function getExpectedCreditMemosData(OrderInterface $order): ?array
{
$creditMemos = [];
/** @var Creditmemo $creditMemo */
@@ -706,49 +514,63 @@ private function getExpectedCreditMemosData(OrderInterface $order): array
$creditMemoItems = null;
$creditMemoId = $creditMemo->getId();
$creditMemoUuid = $this->uuidResource->getAssignedIds([$creditMemoId], 'credit_memo')[$creditMemoId];
- $creditMemos[$creditMemoUuid] = [
+
+ foreach ($creditMemo->getItems() as $creditmemoItem) {
+ $creditMemoItemId = $creditmemoItem->getOrderItemId();
+ $itemUuid = $this->uuidResource->getAssignedIds(
+ [$creditMemoItemId],
+ 'order_item'
+ )[$creditMemoItemId];
+ $creditMemoItems[] = [
+ 'orderItemId' => ['id' => $itemUuid],
+ 'qtyRefunded' => $creditmemoItem->getQty(),
+ 'basePrice' => $creditmemoItem->getBasePrice(),
+ 'baseRowTotal' => $creditmemoItem->getQty() * $creditmemoItem->getBasePrice()
+ - $creditmemoItem->getBaseDiscountAmount(),
+ //TODO: Need to be implemented
+ //'productTaxes' => ''
+ ];
+ }
+
+ $creditMemos[] = [
'creditMemoId' => ['id' => $creditMemoUuid],
'entityId' => $creditMemoId,
'state' => $creditMemo->getState(),
'createdAt' => $this->convertDate($creditMemo->getCreatedAt()),
'shippingAmount' => $creditMemo->getBaseShippingAmount(),
'shippingTaxAmount' => $creditMemo->getBaseShippingTaxAmount(),
- 'adjustment' => $creditMemo->getAdjustment(),
+ 'adjustment' => $creditMemo->getBaseAdjustment(),
'currency' => $creditMemo->getOrderCurrencyCode(),
//TODO: Need to be implemented
//'refundTaxes' => $creditMemo->getTaxAmount()
'subtotal' => $creditMemo->getBaseSubtotal(),
'productsTaxAmount' => $creditMemo->getBaseTaxAmount(),
'commerceCreditMemoNumber' => $creditMemo->getIncrementId(),
- 'grandTotal' => $creditMemo->getBaseGrandTotal()
+ 'grandTotal' => $creditMemo->getBaseGrandTotal(),
+ 'refundItems' => $creditMemoItems,
+ 'creditMemoComments' => $this->extractComments($creditMemo->getComments())
];
- foreach ($creditMemo->getItems() as $creditmemoItem) {
- $creditMemoItemId = $creditmemoItem->getOrderItemId();
- $itemUuid = $this->uuidResource->getAssignedIds(
- [$creditMemoItemId],
- 'order_item'
- )[$creditMemoItemId];
- $creditMemoItems[$itemUuid] = [
- 'orderItemId' => ['id' => $itemUuid],
- 'qtyRefunded' => $creditmemoItem->getQty(),
- 'basePrice' => $creditmemoItem->getBasePrice() . 1,
- //TODO: Need to be implement
- //'baseRowTotal' => $creditmemoItem->getBaseRowTotal(),
- //TODO: Need to be implemented
- //'productTaxes' => ''
- ];
- }
- $creditMemos[$creditMemoUuid]['refundItems'] = $creditMemoItems;
}
- return $creditMemos;
+ return empty($creditMemos) ? null : $creditMemos;
+ }
+
+ private function extractComments(array $comments): ?array
+ {
+ $commentValues = array_map(
+ function ($comment) {
+ return $comment->getComment();
+ },
+ $comments
+ );
+ return $commentValues ? array_values($commentValues) : null;
}
/**
* @param OrderInterface $order
- * @return array
+ * @return array|null
*/
- private function getExpectedShipmentData(OrderInterface $order): array
+ private function getExpectedShipmentData(OrderInterface $order): ?array
{
$shipments = [];
@@ -759,35 +581,34 @@ private function getExpectedShipmentData(OrderInterface $order): array
$shipmentId = $orderShipment->getId();
$shipmentUuid = $this->uuidResource->getAssignedIds([$shipmentId], 'order_shipment')[$shipmentId];
- $shipments[$shipmentUuid] = [
- 'shipmentId' => ['id' => $shipmentUuid],
- 'createdAt' => $this->convertDate($orderShipment->getCreatedAt()),
- 'updatedAt' => $this->convertDate($orderShipment->getUpdatedAt()),
- 'commerceShipmentNumber' => $orderShipment->getIncrementId()
- ];
+
foreach ($orderShipment->getItems() as $shipmentItem) {
- $shippingOrderItemId = $shipmentItem->getOrderItemId();
- $itemUuid = $this->uuidResource->getAssignedIds(
- [$shippingOrderItemId],
- 'order_item'
- )[$shippingOrderItemId];
- $shipmentItems[$itemUuid] = [
+ $itemId = $shipmentItem->getOrderItemId();
+ $itemUuid = $this->uuidResource->getAssignedIds([$itemId], 'order_item')[$itemId];
+ $shipmentItems[] = [
'orderItemId' => ['id' => $itemUuid],
'qtyShipped' => $shipmentItem->getQty()
];
}
+
/** @var ShipmentTrackInterface $shipmentTrack */
foreach ($orderShipment->getTracks() as $shipmentTrack) {
- $shipmentTrackItems[$shipmentTrack->getEntityId()] = [
+ $shipmentTrackItems[] = [
'qty' => $shipmentTrack->getQty()
];
}
- $shipments[$shipmentUuid]['trackingInfo'] = $shipmentTrackItems;
- $shipments[$shipmentUuid]['items'] = $shipmentItems;
+ $shipments[] = [
+ 'shipmentId' => ['id' => $shipmentUuid],
+ 'createdAt' => $this->convertDate($orderShipment->getCreatedAt()),
+ 'updatedAt' => $this->convertDate($orderShipment->getUpdatedAt()),
+ 'commerceShipmentNumber' => $orderShipment->getIncrementId(),
+ 'trackingInfo' => $shipmentTrackItems,
+ 'items' => $shipmentItems
+ ];
}
- return $shipments;
+ return empty($shipments) ? null : $shipments;
}
/**
@@ -806,7 +627,7 @@ private function getExpectedItemAdditionalInformationData(OrderItemInterface $or
}
}
- return $additionalInformation;
+ return empty($additionalInformation) ? null : $additionalInformation;
}
/**
@@ -824,6 +645,11 @@ private function getExpectedOrderAdditionalInformationData(OrderInterface $order
];
}
}
- return $additionalInformation;
+ return empty($additionalInformation) ? null : $additionalInformation;
+ }
+
+ private function convertIntToBool($value): ?bool
+ {
+ return $value !== null ? (bool) $value : null;
}
}
diff --git a/SalesOrdersDataExporter/Test/_files/order_configurable_product.php b/SalesOrdersDataExporter/Test/_files/order_configurable_product.php
index 1715d67f..3d857d3a 100644
--- a/SalesOrdersDataExporter/Test/_files/order_configurable_product.php
+++ b/SalesOrdersDataExporter/Test/_files/order_configurable_product.php
@@ -7,8 +7,6 @@
use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Sales\Api\OrderRepositoryInterface;
use Magento\Sales\Model\Order;
-use Magento\Sales\Model\Order\Address as OrderAddress;
-use Magento\Sales\Model\Order\Item as OrderItem;
use Magento\Sales\Model\Order\Payment;
use Magento\Store\Model\StoreManagerInterface;
use Magento\TestFramework\Workaround\Override\Fixture\Resolver;
@@ -44,7 +42,7 @@
);
$qtyOrdered = 2;
-$productOptions = array('color' => 'red', 'size' => 'medium');
+$productOptions = ['color' => 'red', 'size' => 'medium'];
/** @var \Magento\Sales\Model\Order\Item $orderItem */
$orderConfigurableItem = $objectManager->create(\Magento\Sales\Model\Order\Item::class);
$orderConfigurableItem->setProductId($configurableProduct->getId())->setQtyOrdered($qtyOrdered);
diff --git a/SalesOrdersDataExporter/Test/_files/order_full_work_flow.php b/SalesOrdersDataExporter/Test/_files/order_full_work_flow.php
index 9c14aea3..dddedbb6 100644
--- a/SalesOrdersDataExporter/Test/_files/order_full_work_flow.php
+++ b/SalesOrdersDataExporter/Test/_files/order_full_work_flow.php
@@ -13,37 +13,20 @@
/** @var \Magento\Sales\Model\Order $order */
$order = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Sales\Model\Order::class);
$order->loadByIncrementId('100000001');
-$order->setData(
- 'base_to_global_rate',
- 2.1
-)->setData(
- 'base_shipping_amount',
- 20.1
-)->setData(
- 'base_shipping_canceled',
- 2.1
-)->setData(
- 'base_shipping_invoiced',
- 20.1
-)->setData(
- 'base_shipping_refunded',
- 3.1
-)->setData(
- 'is_virtual',
- 0
-)->setData(
- 'shipping_method',
- 'flatrate_flatrate'
-)->setData(
- 'shipping_description',
- 'flatrate description'
-)->setData(
- 'shipping_amount',
- 1.5
-)->setData(
- 'shipping_tax_amount',
- 0.5
-)->save();
+$order->setData('base_to_global_rate', 2.1)
+ ->setData('base_shipping_amount', 20.1)
+ ->setData('base_shipping_canceled', 2.1)
+ ->setData('base_shipping_invoiced', 20.1)
+ ->setData('base_shipping_refunded', 3.1)
+ ->setData('is_virtual', 0)
+ ->setData('shipping_method', 'flatrate_flatrate')
+ ->setData('shipping_description', 'flatrate description')
+ ->setData('shipping_amount', 1.5)
+ ->setBaseShippingTaxAmount(2)
+ ->setBaseTaxAmount(3)
+ ->setBaseDiscountAmount(5)
+ ->setBaseTotalInvoiced(30)
+ ->save();
$orderItems = $order->getItems();
/** @var \Magento\Sales\Api\Data\OrderItemInterface $orderItem */
@@ -53,6 +36,7 @@
$invoiceItem = $objectManager->create(\Magento\Sales\Api\Data\InvoiceItemCreationInterface::class);
$invoiceItem->setOrderItemId($orderItem->getItemId());
$invoiceItem->setQty($orderItem->getQtyOrdered());
+
/** @var \Magento\Sales\Api\InvoiceOrderInterface $invoiceOrder */
$invoiceOrder = $objectManager->create(\Magento\Sales\Api\InvoiceOrderInterface::class);
$invoiceOrder->execute($order->getEntityId(), false, [$invoiceItem]);
@@ -61,6 +45,7 @@
$shipmentItem = $objectManager->create(\Magento\Sales\Api\Data\ShipmentItemCreationInterface::class);
$shipmentItem->setOrderItemId($orderItem->getItemId());
$shipmentItem->setQty($orderItem->getQtyOrdered());
+
/** @var \Magento\Sales\Api\ShipOrderInterface $shipOrder */
$shipOrder = $objectManager->create(\Magento\Sales\Api\ShipOrderInterface::class);
$shipOrder->execute($order->getEntityId(), [$shipmentItem]);
diff --git a/SalesOrdersDataExporter/Test/_files/order_with_additional_information.php b/SalesOrdersDataExporter/Test/_files/order_with_additional_information.php
index 841206b0..b436d8f7 100644
--- a/SalesOrdersDataExporter/Test/_files/order_with_additional_information.php
+++ b/SalesOrdersDataExporter/Test/_files/order_with_additional_information.php
@@ -10,7 +10,6 @@
use Magento\Sales\Model\Order\Address as OrderAddress;
use Magento\Sales\Model\Order\Item as OrderItem;
use Magento\Sales\Model\Order\Payment;
-use Magento\Sales\Model\Order\Payment\Transaction;
use Magento\Store\Model\StoreManagerInterface;
use Magento\TestFramework\Helper\Bootstrap;
use Magento\TestFramework\Workaround\Override\Fixture\Resolver;
diff --git a/SalesOrdersDataExporter/Test/_files/order_with_additional_information_rollback.php b/SalesOrdersDataExporter/Test/_files/order_with_additional_information_rollback.php
index 512c6384..cd9a7a3a 100644
--- a/SalesOrdersDataExporter/Test/_files/order_with_additional_information_rollback.php
+++ b/SalesOrdersDataExporter/Test/_files/order_with_additional_information_rollback.php
@@ -7,4 +7,4 @@
use Magento\TestFramework\Workaround\Override\Fixture\Resolver;
Resolver::getInstance()->requireDataFixture('Magento/Catalog/_files/product_simple.php');
-Resolver::getInstance()->requireDataFixture('Magento/Sales/_files/order_rollback.php');
\ No newline at end of file
+Resolver::getInstance()->requireDataFixture('Magento/Sales/_files/order_rollback.php');
diff --git a/SalesOrdersDataExporter/Test/_files/order_with_invoice_shipment_creditmemo.php b/SalesOrdersDataExporter/Test/_files/order_with_invoice_shipment_creditmemo.php
index 4d062dc4..a117d944 100644
--- a/SalesOrdersDataExporter/Test/_files/order_with_invoice_shipment_creditmemo.php
+++ b/SalesOrdersDataExporter/Test/_files/order_with_invoice_shipment_creditmemo.php
@@ -16,9 +16,9 @@
use Magento\Sales\Api\Data\OrderInterface;
use Magento\Sales\Api\Data\OrderInterfaceFactory;
use Magento\Sales\Api\Data\OrderItemInterface;
+use Magento\Sales\Api\Data\OrderItemInterfaceFactory;
use Magento\Sales\Api\Data\OrderPaymentInterfaceFactory;
use Magento\Sales\Api\InvoiceManagementInterface;
-use Magento\Sales\Api\Data\OrderItemInterfaceFactory;
use Magento\Sales\Api\OrderRepositoryInterface;
use Magento\Sales\Model\Order;
use Magento\Sales\Model\Order\Address;
@@ -142,12 +142,15 @@
$orderData['items'][$item->getId()] = $item;
}
$order->setItems($orderData['items']);
+
$creditmemo = $creditmemoFactory->createByOrder($order, $orderData);
$creditmemo->setBaseShippingAmount(3.14);
$creditmemo->setBaseShippingTaxAmount(1.14);
$creditmemo->setAdjustment(2.77);
$creditmemo->setBaseTaxAmount(1.5);
$creditmemo->setIncrementId($order->getIncrementId());
+$creditmemo->addComment("note");
+$creditmemo->addComment("note2");
$creditItem = $creditmemoItemFactory->create();
$creditItem->setCreditmemo($creditmemo)
diff --git a/SalesOrdersDataExporter/Test/_files/transactions_detailed_rollback.php b/SalesOrdersDataExporter/Test/_files/transactions_detailed_rollback.php
index 512c6384..cd9a7a3a 100644
--- a/SalesOrdersDataExporter/Test/_files/transactions_detailed_rollback.php
+++ b/SalesOrdersDataExporter/Test/_files/transactions_detailed_rollback.php
@@ -7,4 +7,4 @@
use Magento\TestFramework\Workaround\Override\Fixture\Resolver;
Resolver::getInstance()->requireDataFixture('Magento/Catalog/_files/product_simple.php');
-Resolver::getInstance()->requireDataFixture('Magento/Sales/_files/order_rollback.php');
\ No newline at end of file
+Resolver::getInstance()->requireDataFixture('Magento/Sales/_files/order_rollback.php');
diff --git a/SalesOrdersDataExporter/etc/et_schema.xml b/SalesOrdersDataExporter/etc/et_schema.xml
index 994eb285..dd0bc3b8 100644
--- a/SalesOrdersDataExporter/etc/et_schema.xml
+++ b/SalesOrdersDataExporter/etc/et_schema.xml
@@ -214,7 +214,10 @@
provider="Magento\DataExporter\Model\Provider\DateConverter">
-
+
+
+
diff --git a/SalesOrdersDataExporter/etc/events.xml b/SalesOrdersDataExporter/etc/events.xml
index 047ec890..a153d834 100644
--- a/SalesOrdersDataExporter/etc/events.xml
+++ b/SalesOrdersDataExporter/etc/events.xml
@@ -7,10 +7,10 @@
-->
-
+
-
+
diff --git a/SalesOrdersDataExporter/etc/query.xml b/SalesOrdersDataExporter/etc/query.xml
index 05153992..29d0f9d4 100644
--- a/SalesOrdersDataExporter/etc/query.xml
+++ b/SalesOrdersDataExporter/etc/query.xml
@@ -245,14 +245,14 @@
-
+
commerceOrderId
-
+
entity_id
diff --git a/dev/tests/integration/testsuite/Magento/CatalogRule/Model/Indexer/IndexerBuilderTest.php b/dev/tests/integration/testsuite/Magento/CatalogRule/Model/Indexer/IndexerBuilderTest.php
new file mode 100644
index 00000000..85d1b69c
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/CatalogRule/Model/Indexer/IndexerBuilderTest.php
@@ -0,0 +1,243 @@
+indexerBuilder = Bootstrap::getObjectManager()->get(
+ \Magento\CatalogRule\Model\Indexer\IndexBuilder::class
+ );
+ $this->resourceRule = Bootstrap::getObjectManager()->get(\Magento\CatalogRule\Model\ResourceModel\Rule::class);
+ $this->product = Bootstrap::getObjectManager()->get(\Magento\Catalog\Model\Product::class);
+ $this->storeManager = Bootstrap::getObjectManager()->get(StoreManagerInterface::class);
+ $this->productRepository = Bootstrap::getObjectManager()->get(ProductRepositoryInterface::class);
+ $this->connection = Bootstrap::getObjectManager()->get(ResourceConnection::class);
+ $this->indexProductProcessor = Bootstrap::getObjectManager()->get(Processor::class);
+ }
+
+ protected function tearDown(): void
+ {
+ /** @var \Magento\Framework\Registry $registry */
+ $registry = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()
+ ->get(\Magento\Framework\Registry::class);
+
+ $registry->unregister('isSecureArea');
+ $registry->register('isSecureArea', true);
+
+ /** @var \Magento\Catalog\Model\ResourceModel\Product\Collection $productCollection */
+ $productCollection = Bootstrap::getObjectManager()->get(
+ \Magento\Catalog\Model\ResourceModel\Product\Collection::class
+ );
+ $productCollection->delete();
+
+ $registry->unregister('isSecureArea');
+ $registry->register('isSecureArea', false);
+
+ parent::tearDown();
+ }
+
+ /**
+ * @magentoDbIsolation disabled
+ * @magentoAppIsolation enabled
+ * @magentoDataFixture Magento/CatalogRule/_files/attribute.php
+ * @magentoDataFixture Magento/CatalogRule/_files/rule_by_attribute.php
+ * @magentoDataFixture Magento/Catalog/_files/product_simple.php
+ */
+ public function testReindexById()
+ {
+ $product = $this->product->loadByAttribute('sku', 'simple');
+ $product->load($product->getId());
+ $product->setData('test_attribute', 'test_attribute_value')->save();
+
+ $this->indexerBuilder->reindexById($product->getId());
+
+ $this->assertEquals(9.8, $this->resourceRule->getRulePrice(new \DateTime(), 1, 1, $product->getId()));
+ }
+
+ /**
+ * @magentoDbIsolation disabled
+ * @magentoAppIsolation enabled
+ * @magentoDataFixture Magento/CatalogRule/_files/simple_product_with_catalog_rule_50_percent_off_tomorrow.php
+ * @magentoConfigFixture base_website general/locale/timezone Europe/Amsterdam
+ * @magentoConfigFixture general/locale/timezone America/Chicago
+ */
+ public function testReindexByIdDifferentTimezones()
+ {
+ $productId = $this->productRepository->get('simple')->getId();
+ $this->indexerBuilder->reindexById($productId);
+
+ $mainWebsiteId = $this->storeManager->getWebsite('base')->getId();
+ $secondWebsiteId = $this->storeManager->getWebsite('test')->getId();
+ $rawTimestamp = (new \DateTime('+1 day'))->getTimestamp();
+ $timestamp = $rawTimestamp - ($rawTimestamp % (60 * 60 * 24));
+ $mainWebsiteActiveRules =
+ $this->resourceRule->getRulesFromProduct($timestamp, $mainWebsiteId, 1, $productId);
+ $secondWebsiteActiveRules =
+ $this->resourceRule->getRulesFromProduct($timestamp, $secondWebsiteId, 1, $productId);
+
+ $this->assertCount(1, $mainWebsiteActiveRules);
+ // Avoid failure when staging is enabled as it removes catalog rule timestamp.
+ if ((int)$mainWebsiteActiveRules[0]['from_time'] !== 0) {
+ $this->assertCount(0, $secondWebsiteActiveRules);
+ }
+ }
+
+ /**
+ * @magentoDbIsolation disabled
+ * @magentoAppIsolation enabled
+ * @magentoDataFixture Magento/CatalogRule/_files/attribute.php
+ * @magentoDataFixture Magento/CatalogRule/_files/rule_by_attribute.php
+ * @magentoDataFixture Magento/Catalog/_files/product_simple.php
+ */
+ public function testReindexByIds()
+ {
+ $this->prepareProducts();
+
+ $this->indexerBuilder->reindexByIds(
+ [
+ $this->product->getId(),
+ $this->productSecond->getId(),
+ $this->productThird->getId(),
+ ]
+ );
+
+ $this->assertEquals(9.8, $this->resourceRule->getRulePrice(new \DateTime(), 1, 1, $this->product->getId()));
+ $this->assertEquals(
+ 9.8,
+ $this->resourceRule->getRulePrice(new \DateTime(), 1, 1, $this->productSecond->getId())
+ );
+ $this->assertFalse($this->resourceRule->getRulePrice(new \DateTime(), 1, 1, $this->productThird->getId()));
+ }
+
+ /**
+ * @magentoDbIsolation disabled
+ * @magentoAppIsolation enabled
+ * @magentoDataFixtureBeforeTransaction Magento/CatalogRule/_files/attribute.php
+ * @magentoDataFixtureBeforeTransaction Magento/CatalogRule/_files/rule_by_attribute.php
+ * @magentoDataFixture Magento/Catalog/_files/product_simple.php
+ */
+ public function testReindexFull()
+ {
+ $this->prepareProducts();
+
+ $this->indexerBuilder->reindexFull();
+
+ $rulePrice = $this->resourceRule->getRulePrice(new \DateTime(), 1, 1, $this->product->getId());
+ $this->assertEquals(9.8, $rulePrice);
+ $rulePrice = $this->resourceRule->getRulePrice(new \DateTime(), 1, 1, $this->productSecond->getId());
+ $this->assertEquals(9.8, $rulePrice);
+ $this->assertFalse($this->resourceRule->getRulePrice(new \DateTime(), 1, 1, $this->productThird->getId()));
+ }
+
+ /**
+ * Tests restoring triggers on `catalogrule_product_price` table after full reindexing in 'Update by schedule' mode.
+ *
+ * @magentoDbIsolation disabled
+ * @magentoAppIsolation enabled
+ */
+ public function testRestoringTriggersAfterFullReindex()
+ {
+ $this->markTestSkipped('Skip this test as it fails with SaaS-Export extension MDEE-389');
+ $tableName = $this->connection->getTableName('catalogrule_product_price');
+
+ $this->indexProductProcessor->getIndexer()->setScheduled(false);
+ $this->assertEquals(0, $this->getTriggersCount($tableName));
+
+ $this->indexProductProcessor->getIndexer()->setScheduled(true);
+ $this->assertGreaterThan(0, $this->getTriggersCount($tableName));
+
+ $this->indexerBuilder->reindexFull();
+ $this->assertGreaterThan(0, $this->getTriggersCount($tableName));
+
+ $this->indexProductProcessor->getIndexer()->setScheduled(false);
+ $this->assertEquals(0, $this->getTriggersCount($tableName));
+ }
+
+ /**
+ * Returns triggers count.
+ *
+ * @param string $tableName
+ * @return int
+ * @throws \Zend_Db_Statement_Exception
+ */
+ private function getTriggersCount(string $tableName): int
+ {
+ return count(
+ $this->connection->getConnection()
+ ->query('SHOW TRIGGERS LIKE \''. $tableName . '\'')
+ ->fetchAll()
+ );
+ }
+
+ protected function prepareProducts()
+ {
+ $product = $this->product->loadByAttribute('sku', 'simple');
+ $product->load($product->getId());
+ $this->product = $product;
+
+ $this->product->setStoreId(0)->setData('test_attribute', 'test_attribute_value')->save();
+ $this->productSecond = clone $this->product;
+ $this->productSecond->setId(null)->setUrlKey('product-second')->save();
+ $this->productThird = clone $this->product;
+ $this->productThird->setId(null)
+ ->setUrlKey('product-third')
+ ->setData('test_attribute', 'NO_test_attribute_value')
+ ->save();
+ }
+}