Skip to content

Commit

Permalink
BB-7908: Product import fails (#8298)
Browse files Browse the repository at this point in the history
  • Loading branch information
x86demon authored and vitaliyberdylo committed Mar 13, 2017
1 parent 43eda8a commit f899234
Show file tree
Hide file tree
Showing 5 changed files with 243 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace Oro\Bundle\ProductBundle\ImportExport\Processor;

use Oro\Bundle\BatchBundle\Item\Support\ClosableInterface;
use Oro\Bundle\ImportExportBundle\Processor\ImportProcessor;

class ProductImportProcessor extends ImportProcessor implements ClosableInterface
{
/**
* {@inheritdoc}
*/
public function close()
{
if ($this->strategy instanceof ClosableInterface) {
$this->strategy->close();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Util\ClassUtils;
use Oro\Bundle\BatchBundle\Item\Support\ClosableInterface;
use Oro\Bundle\LocaleBundle\ImportExport\Strategy\LocalizedFallbackValueAwareStrategy;
use Oro\Bundle\OrganizationBundle\Entity\BusinessUnit;
use Oro\Bundle\ProductBundle\Entity\Product;
use Oro\Bundle\ProductBundle\ImportExport\Event\ProductStrategyEvent;
use Oro\Bundle\SecurityBundle\SecurityFacade;
use Oro\Bundle\UserBundle\Entity\User;

class ProductStrategy extends LocalizedFallbackValueAwareStrategy
class ProductStrategy extends LocalizedFallbackValueAwareStrategy implements ClosableInterface
{
/**
* @var SecurityFacade
Expand All @@ -34,6 +35,19 @@ class ProductStrategy extends LocalizedFallbackValueAwareStrategy
*/
protected $productClass;

/**
* @var array|Product[]
*/
protected $processedProducts = [];

/**
* {@inheritdoc}
*/
public function close()
{
$this->processedProducts = [];
}

/**
* @param SecurityFacade $securityFacade
*/
Expand Down Expand Up @@ -89,7 +103,11 @@ protected function afterProcessEntity($entity)
$event = new ProductStrategyEvent($entity, $this->context->getValue('itemData'));
$this->eventDispatcher->dispatch(ProductStrategyEvent::PROCESS_AFTER, $event);

return parent::afterProcessEntity($entity);
/** @var Product $entity */
$entity = parent::afterProcessEntity($entity);
$this->processedProducts[$entity->getSku()] = $entity;

return $entity;
}

/**
Expand Down Expand Up @@ -215,6 +233,25 @@ protected function updateRelations($entity, array $itemData = null)
}
}

/**
* {@inheritdoc}
*/
protected function processEntity(
$entity,
$isFullData = false,
$isPersistNew = false,
$itemData = null,
array $searchContext = [],
$entityIsRelation = false
) {
if ($entity instanceof Product && array_key_exists($entity->getSku(), $this->processedProducts)) {
return $this->processedProducts[$entity->getSku()];
}

return parent::processEntity($entity, $isFullData, $isPersistNew, $itemData, $searchContext, $entityIsRelation);
}


/**
* Get additional search parameter name to find only related entities
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ services:
oro_product.importexport.processor.import.product:
public: false
parent: oro_importexport.processor.import_abstract
class: Oro\Bundle\ProductBundle\ImportExport\Processor\ProductImportProcessor
calls:
- [setDataConverter, ['@oro_product.importexport.data_converter.product']]
- [setStrategy, ['@oro_product.importexport.strategy.product']]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
<?php

namespace Oro\Bundle\ProductBundle\Tests\Functional\ImportExport\Strategy;

use Oro\Bundle\EntityConfigBundle\Attribute\Entity\AttributeFamily;
use Oro\Bundle\EntityExtendBundle\Entity\AbstractEnumValue;
use Oro\Bundle\EntityExtendBundle\Tools\ExtendHelper;
use Oro\Bundle\ImportExportBundle\Context\Context;
use Oro\Bundle\LocaleBundle\Entity\LocalizedFallbackValue;
use Oro\Bundle\ProductBundle\Entity\Product;
use Oro\Bundle\ProductBundle\Entity\ProductUnit;
use Oro\Bundle\ProductBundle\Entity\ProductUnitPrecision;
use Oro\Bundle\ProductBundle\Entity\ProductVariantLink;
use Oro\Bundle\ProductBundle\ImportExport\Strategy\ProductStrategy;
use Oro\Bundle\ProductBundle\Tests\Functional\DataFixtures\LoadProductData;
use Oro\Bundle\ProductBundle\Tests\Functional\DataFixtures\LoadProductUnits;
use Oro\Bundle\TestFrameworkBundle\Test\WebTestCase;
use Oro\Component\Testing\Unit\EntityTrait;

/**
* @dbIsolation
*/
class ProductStrategyTest extends WebTestCase
{
use EntityTrait;

/**
* @var ProductStrategy
* */
protected $strategy;

protected function setUp()
{
$this->initClient();
$this->loadFixtures([LoadProductData::class]);
$container = $this->getContainer();

$container->get('oro_importexport.field.database_helper')->onClear();
$this->strategy = new ProductStrategy(
$container->get('event_dispatcher'),
$container->get('oro_importexport.strategy.import.helper'),
$container->get('oro_entity.helper.field_helper'),
$container->get('oro_importexport.field.database_helper'),
$container->get('oro_entity.entity_class_name_provider'),
$container->get('translator'),
$container->get('oro_importexport.strategy.new_entities_helper'),
$container->get('oro_entity.doctrine_helper')
);
$this->strategy->setEntityName(Product::class);
$this->strategy->setVariantLinkClass(ProductVariantLink::class);
$this->strategy->setLocalizedFallbackValueClass(LocalizedFallbackValue::class);
$this->strategy->setSecurityFacade($container->get('oro_security.security_facade'));
}

/**
* Impossible to import product when it's variant is in the same batch.
* Caused because variant is not in DB it could not be loaded by SKU and variant link contains invalid relation.
*
* @link https://magecore.atlassian.net/browse/BB-7908
*/
public function testProcessWithVariantLinks()
{
$context = new Context([]);
$context->setValue('itemData', []);
$this->strategy->setImportExportContext($context);

$inventoryStatusClassName = ExtendHelper::buildEnumValueClassName('prod_inventory_status');
/** @var AbstractEnumValue $inventoryStatus */
$inventoryStatus = $this->getContainer()
->get('doctrine')
->getRepository($inventoryStatusClassName)
->find('in_stock');

/** @var ProductUnit $unit */
$unit = $this->getReference(LoadProductUnits::BOX);
/** @var AttributeFamily $attributeFamily */
$attributeFamily = $this->getEntity(AttributeFamily::class, ['code' => 'default_family']);
$newProductSku = 'PR-V1';

// Prepare new product that is imported in same batch and will be used later as variant link
$newProduct = $this->createProduct($newProductSku, $attributeFamily, $unit, $inventoryStatus);
/** @var Product $processedNewProduct */
$processedNewProduct = $this->strategy->process($newProduct);
$this->assertEquals([], $context->getErrors());
$this->assertInstanceOf(Product::class, $processedNewProduct);
$this->assertSame($newProductSku, $processedNewProduct->getSku());

// Get existing product that should be found by SKU as variant link relation
/** @var Product $existingProduct */
$existingProduct = $this->getReference(LoadProductData::PRODUCT_1);

$linkToNewProduct = new ProductVariantLink();
$linkToNewProduct->setProduct((new Product())->setSku($newProductSku));
$linkToExistingProduct = new ProductVariantLink();
$linkToExistingProduct->setProduct((new Product())->setSku($existingProduct->getSku()));

// Add prepared variant links to newly imported product
$productWithVariants = $this->createProduct('PR-VV', $attributeFamily, $unit, $inventoryStatus);
$productWithVariants->addVariantLink($linkToNewProduct);
$productWithVariants->addVariantLink($linkToExistingProduct);

// Check that all variant links present and were attached correctly
/** @var Product $processedProductWithVariants */
$processedProductWithVariants = $this->strategy->process($productWithVariants);
$this->assertEquals([], $context->getErrors());
$this->assertInstanceOf(Product::class, $processedProductWithVariants);
$this->assertSame($productWithVariants->getSku(), $processedProductWithVariants->getSku());
$this->assertCount(2, $processedProductWithVariants->getVariantLinks());
$usedVariantLinksProductSkus = array_map(
function (ProductVariantLink $variantLink) {
return $variantLink->getProduct()->getSku();
},
$processedProductWithVariants->getVariantLinks()->toArray()
);
$this->assertContains($newProductSku, $usedVariantLinksProductSkus);
$this->assertContains($existingProduct->getSku(), $usedVariantLinksProductSkus);
}

/**
* @param string $sku
* @param AttributeFamily $attributeFamily
* @param ProductUnit $unit
* @param AbstractEnumValue $inventoryStatus
* @return Product
*/
protected function createProduct(
$sku,
AttributeFamily $attributeFamily,
ProductUnit $unit,
AbstractEnumValue $inventoryStatus
) {
$newProduct = new Product();
$newProduct->setSku($sku);
$newProduct->setAttributeFamily($attributeFamily);
$newProduct->setInventoryStatus($inventoryStatus);
$newProduct->setPrimaryUnitPrecision(
(new ProductUnitPrecision())->setUnit($unit)
);

return $newProduct;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

namespace Oro\Bundle\ProductBundle\Tests\Unit\ImportExport\Processor;

use Oro\Bundle\ImportExportBundle\Strategy\StrategyInterface;
use Oro\Bundle\ProductBundle\ImportExport\Processor\ProductImportProcessor;
use Oro\Bundle\ProductBundle\ImportExport\Strategy\ProductStrategy;

class ProductImportProcessorTest extends \PHPUnit_Framework_TestCase
{
/**
* @var ProductImportProcessor
*/
private $processor;

protected function setUp()
{
$this->processor = new ProductImportProcessor();
}

public function testCloseWithClosableStrategy()
{
/** @var ProductStrategy|\PHPUnit_Framework_MockObject_MockObject $strategy */
$strategy = $this->getMockBuilder(ProductStrategy::class)
->disableOriginalConstructor()
->getMock();
$strategy->expects($this->once())
->method('close');
$this->processor->setStrategy($strategy);
$this->processor->close();
}

public function testCloseWithNonClosableStrategy()
{
/** @var StrategyInterface|\PHPUnit_Framework_MockObject_MockObject $strategy */
$strategy = $this->createMock(StrategyInterface::class);
$strategy->expects($this->never())
->method($this->anything());
$this->processor->setStrategy($strategy);
$this->processor->close();
}
}

0 comments on commit f899234

Please sign in to comment.