forked from mage-os/mirror-commerce-data-export
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' of https://github.com/mage-os/mirror-commerce-dat…
- Loading branch information
Showing
18 changed files
with
922 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
<?php | ||
/** | ||
* Copyright © Magento, Inc. All rights reserved. | ||
* See COPYING.txt for license details. | ||
*/ | ||
declare(strict_types=1); | ||
|
||
namespace Magento\BundleProductDataExporter\Model\Provider\Product; | ||
|
||
use Magento\QueryXml\Model\QueryProcessor; | ||
use Magento\Catalog\Model\Product\Type as ProductType; | ||
|
||
/** | ||
* Determine bundle product type | ||
*/ | ||
class Type | ||
{ | ||
private const BUNDLE_FIXED_TYPE = 'bundle_fixed'; | ||
|
||
private QueryProcessor $queryProcessor; | ||
|
||
/** | ||
* @param QueryProcessor $queryProcessor | ||
*/ | ||
public function __construct( | ||
QueryProcessor $queryProcessor | ||
) { | ||
$this->queryProcessor = $queryProcessor; | ||
} | ||
|
||
/** | ||
* Get provider data | ||
* | ||
* @param array $values | ||
* @return array | ||
* @throws \Zend_Db_Statement_Exception | ||
*/ | ||
public function get(array $values) : array | ||
{ | ||
$output = []; | ||
$bundleIds = []; | ||
foreach ($values as $value) { | ||
if (!isset($output[$value['sku']])) { | ||
$output[$value['sku']] = [ | ||
'type' => $value['type'], | ||
'sku' => $value['sku'] | ||
]; | ||
// Get list of bundle products | ||
if ($value['type'] === ProductType::TYPE_BUNDLE) { | ||
$bundleIds[] = $value['productId']; | ||
} | ||
} | ||
} | ||
$cursor = $this->queryProcessor->execute('bundleFixedProductType', ['ids' => $bundleIds]); | ||
while ($row = $cursor->fetch()) { | ||
// Set bundle_fixed product type if product has price (only bundle fixed products have it) | ||
if (isset($output[$row['sku']])) { | ||
$output[$row['sku']]['type'] = self::BUNDLE_FIXED_TYPE; | ||
} | ||
} | ||
|
||
return $output; | ||
} | ||
} |
73 changes: 73 additions & 0 deletions
73
BundleProductDataExporter/Plugin/ExtendProductParentQuery.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
<?php | ||
/** | ||
* Copyright 2023 Adobe | ||
* All rights reserved | ||
* | ||
* See COPYING.txt for license details. | ||
*/ | ||
declare(strict_types=1); | ||
|
||
namespace Magento\BundleProductDataExporter\Plugin; | ||
|
||
use Magento\Framework\App\ResourceConnection; | ||
use Magento\Framework\DB\Select; | ||
use Magento\ParentProductDataExporter\Model\Query\ProductParentQuery; | ||
|
||
/** | ||
* Plugin for get parent products query class | ||
*/ | ||
class ExtendProductParentQuery | ||
{ | ||
private const BUNDLE_FIXED_TYPE = 'bundle_fixed'; | ||
|
||
/** | ||
* @var ResourceConnection | ||
*/ | ||
private ResourceConnection $resourceConnection; | ||
|
||
/** | ||
* MainProductQuery constructor. | ||
* | ||
* @param ResourceConnection $resourceConnection | ||
*/ | ||
public function __construct( | ||
ResourceConnection $resourceConnection | ||
) { | ||
$this->resourceConnection = $resourceConnection; | ||
} | ||
|
||
/** | ||
* Add bundle product type data to select | ||
* | ||
* @param ProductParentQuery $subject | ||
* @param Select $select | ||
* @param array $arguments | ||
* @return Select | ||
* @SuppressWarnings(PHPMD.UnusedFormalParameter) | ||
*/ | ||
public function afterGetQuery(ProductParentQuery $subject, Select $select, array $arguments): Select | ||
{ | ||
$connection = $this->resourceConnection->getConnection(); | ||
$joinField = $connection->getAutoIncrementField( | ||
$this->resourceConnection->getTableName('catalog_product_entity') | ||
); | ||
|
||
$select->joinLeft( | ||
['eav_attribute' => $this->resourceConnection->getTableName('eav_attribute')], | ||
'eav_attribute.attribute_code = \'price_type\'', | ||
[] | ||
)->joinLeft( | ||
['eavi_parent' => $this->resourceConnection->getTableName('catalog_product_entity_int')], | ||
\sprintf('parent_cpe.%1$s = eavi_parent.%1$s', $joinField) . | ||
' AND eavi_parent.attribute_id = eav_attribute.attribute_id' . | ||
' AND eavi_parent.store_id = 0', | ||
[] | ||
)->columns( | ||
[ | ||
'productType' => 'IF(eavi_parent.value = 1, \'' . self::BUNDLE_FIXED_TYPE . '\', cpe.type_id)' | ||
] | ||
); | ||
|
||
return $select; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
177 changes: 177 additions & 0 deletions
177
BundleProductDataExporter/Test/Integration/ExportBundleOptionWithParentTest.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,177 @@ | ||
<?php | ||
/** | ||
* Copyright © Magento, Inc. All rights reserved. | ||
* See COPYING.txt for license details. | ||
*/ | ||
declare(strict_types=1); | ||
|
||
namespace Magento\BundleProductDataExporter\Test\Integration; | ||
|
||
use DateTime; | ||
use DateTimeInterface; | ||
use Magento\Catalog\Api\ProductRepositoryInterface; | ||
use Magento\Framework\App\ResourceConnection; | ||
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; | ||
|
||
/** | ||
* Check parents fields for options bundle products | ||
* | ||
* @magentoDbIsolation disabled | ||
* @magentoAppIsolation enabled | ||
* @SuppressWarnings(PHPMD.UnusedPrivateMethod) | ||
* @SuppressWarnings(PHPMD.CouplingBetweenObjects) | ||
*/ | ||
class ExportBundleOptionWithParentTest extends TestCase | ||
{ | ||
private const PRODUCT_FEED_INDEXER = 'catalog_data_exporter_products'; | ||
|
||
/** | ||
* @var Indexer | ||
*/ | ||
private Indexer $indexer; | ||
|
||
/** | ||
* @var FeedInterface | ||
*/ | ||
private FeedInterface $productsFeed; | ||
|
||
/** | ||
* @var ProductRepositoryInterface | ||
*/ | ||
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); | ||
$this->productsFeed = Bootstrap::getObjectManager()->get(FeedPool::class)->getFeed('products'); | ||
$this->resourceConnection = Bootstrap::getObjectManager()->create(ResourceConnection::class); | ||
} | ||
|
||
/** | ||
* @magentoDataFixture Magento/Bundle/_files/product_with_multiple_options.php | ||
* @magentoDataFixture Magento/Bundle/_files/bundle_product_with_dynamic_price.php | ||
* | ||
* @dataProvider expectedBundleOptionsWithParentData | ||
* @throws NoSuchEntityException | ||
* @throws Zend_Db_Statement_Exception | ||
*/ | ||
public function testExportBundleOptionsWithParentData(array $expectedSimpleProduct): void | ||
{ | ||
$this->checkExpectedItemsAreExportedInFeed($expectedSimpleProduct); | ||
} | ||
|
||
/** | ||
* @return \array[][] | ||
*/ | ||
private function expectedBundleOptionsWithParentData(): array | ||
{ | ||
return [ | ||
[ | ||
[ | ||
[ | ||
'sku' => 'simple1', | ||
'type' => 'SIMPLE', | ||
'parents' => [ | ||
0 => ['sku' => 'bundle-product', 'productType' => 'bundle_fixed'], | ||
1 => ['sku' => 'bundle_product_with_dynamic_price', 'productType' => 'bundle'], | ||
], | ||
], | ||
] | ||
] | ||
]; | ||
} | ||
|
||
/** | ||
* @param array $expectedItems | ||
* @return void | ||
* @throws NoSuchEntityException | ||
* @throws Zend_Db_Statement_Exception | ||
*/ | ||
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)); | ||
|
||
self::assertNotEmpty($actualProductsFeed['feed'], '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}" | ||
); | ||
|
||
self::assertEqualsCanonicalizing( | ||
$product['parents'], | ||
$actualProductsFeed['feed'][$index]['parents'], | ||
"Parents is not equal" | ||
); | ||
} | ||
} | ||
|
||
/** | ||
* 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); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
<?xml version="1.0"?> | ||
<!-- | ||
/** | ||
* Copyright © Magento, Inc. All rights reserved. | ||
* See COPYING.txt for license details. | ||
*/ | ||
--> | ||
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_QueryXml:etc/query.xsd"> | ||
<query name="bundleFixedProductType"> | ||
<source name="catalog_product_entity"> | ||
<attribute name="sku"/> | ||
<filter glue="and"> | ||
<condition attribute="entity_id" operator="in" type="placeholder">ids</condition> | ||
</filter> | ||
<link-source name="eav_entity_type" alias="entity_type"> | ||
<using glue="and"> | ||
<condition attribute="entity_type_code" operator="eq" type="value">catalog_product</condition> | ||
</using> | ||
</link-source> | ||
<link-source name="eav_attribute"> | ||
<using glue="and"> | ||
<condition attribute="entity_type_id" operator="eq" type="identifier">entity_type.entity_type_id</condition> | ||
<condition attribute="attribute_code" operator="eq" type="value">price_type</condition> | ||
</using> | ||
</link-source> | ||
<link-source name="catalog_product_entity_int" link-type="inner"> | ||
<using glue="and"> | ||
<condition attribute="Magento\Catalog\Api\Data\ProductInterface:LinkField" operator="eq" type="identifier">catalog_product_entity.Primary Key</condition> | ||
<condition attribute="attribute_id" operator="eq" type="identifier">eav_attribute.attribute_id</condition> | ||
<condition attribute="value" operator="eq" type="value">1</condition> | ||
</using> | ||
</link-source> | ||
</source> | ||
</query> | ||
</config> |
Oops, something went wrong.