Spamworldpro Mini Shell
Spamworldpro


Server : Apache
System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64
User : corals ( 1002)
PHP Version : 7.4.33
Disable Function : exec,passthru,shell_exec,system
Directory :  /home/corals/old/app/code/Cnc/Catalog/Console/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/corals/old/app/code/Cnc/Catalog/Console/CreateProducts.php
<?php
/**
 * Copyright (c) 2020 Kaliop Digital Commerce (https://digitalcommerce.kaliop.com) All Rights Reserved.
 * https://opensource.org/licenses/OSL-3.0  Open Software License (OSL 3.0)
 * Cnc
 * Radosław Stępień <[email protected]> <[email protected]>
 */

namespace Cnc\Catalog\Console;

use Cnc\Catalog\Model\Attribute\MsiAttributes;
use Cnc\Catalog\Model\Config;
use Cnc\Catalog\Model\Product\ImportFactory;
use Cnc\Catalog\Model\ResourceModel\DataFactory as SourceDataFactory;
use Cnc\Catalog\Setup\Patch\Data\UpdateCustomTablesAttributesData;
use Exception;
use Magento\Catalog\Api\AttributeSetRepositoryInterface;
use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Catalog\Model\ProductFactory;
use Magento\Catalog\Model\ResourceModel\Category\CollectionFactory as CategoryCollectionFactory;
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory;
use Magento\Eav\Api\Data\AttributeSetInterface;
use Magento\Framework\Api\FilterBuilder;
use Magento\Framework\Api\SearchCriteriaBuilder;
use Magento\Framework\App\Area;
use Magento\Framework\App\ResourceConnection;
use Magento\Framework\App\State;
use Magento\Framework\Exception\FileSystemException;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Filesystem\Driver\File;
use Magento\Framework\Registry;
use Magento\Framework\Setup\SampleData\FixtureManager;
use Magento\Framework\Url\Validator as UrlValidator;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class CreateProducts extends Command
{
    const FILE_PART = 'part';
    const CLEAR_CATALOG = 'clear_catalog';

    const MULTIPLE_VALUES_SEPARATOR = ';;';

    const NOT_VISIBLE_INDIVIDUALLY = 'not visible individually';
    const CATALOG_SEARCH = 'catalog, search';

    const FR_LANGUAGE_IMPORT_ID = 4;
    const EN_LANGUAGE_IMPORT_ID = 1;

    const FIXTURE_PRODUCTS_FR_FILE_PATH = 'Cnc_Catalog::fixtures/products.csv';
    const FIXTURE_PRODUCTS_DESCRIPTION_FR_FILE_PATH = 'Cnc_Catalog::fixtures/products_description.csv';
    const FIXTURE_ATTRIBUTE_SETS_FR_FILE_PATH = 'Cnc_Catalog::fixtures/type_products.csv';
    const FIXTURE_ATTRIBUTE_SETS_RELATION_FR_FILE_PATH = 'Cnc_Catalog::fixtures/products_to_type_products.csv';
    const FIXTURE_CATEGORIES_DESCRIPTION_FR_FILE_PATH = 'Cnc_Catalog::fixtures/categories_description.csv';
    const FIXTURE_PRODUCTS_TO_CATEGORIES_FR_FILE_PATH = 'Cnc_Catalog::fixtures/products_to_categories.csv';
    const FIXTURE_CROSSSELLING_FILE_PATH = 'Cnc_Catalog::fixtures/cross_selling.csv';

    const PRODUCT_DESCRIPTION_FIELDS_MAPPING = [
        'name' => 'products_name',
        'description' => 'products_description',
        'grouped_url_key' => 'products_url',
        'short_description' => 'products_small_desc',
        'meta_title' => 'products_head_title_tag',
        'meta_description' => 'products_head_desc_tag',
        'meta_keywords' => 'products_head_keywords_tag'
    ];

    /**
     * @var LoggerInterface
     */
    private $logger;

    /**
     * @var File
     */
    private $file;

    /**
     * @var FixtureManager
     */
    private $fixtureManager;

    /**
     * @var Registry
     */
    private $registry;

    /**
     * @var State
     */
    protected $state;

    /**
     * @var CollectionFactory
     */
    private $productCollectionFactory;

    /**
     * @var ProductRepositoryInterface
     */
    private $productRepository;

    /**
     * @var ProductFactory
     */
    private $productFactory;

    /**
     * @var AttributeSetRepositoryInterface
     */
    private $attributeSetRepository;

    /**
     * @var FilterBuilder
     */
    private $filterBuilder;

    /**
     * @var SearchCriteriaBuilder
     */
    private $searchCriteriaBuilder;

    /**
     * @var SourceDataFactory
     */
    private $sourceDataFactory;

    /**
     * @var ImportFactory
     */
    private $importFactory;

    /**
     * @var ResourceConnection
     */
    private $resource;

    /**
     * @var UrlValidator
     */
    private $urlValidator;

    /**
     * @var CategoryCollectionFactory
     */
    private $categoryCollectionFactory;

    /**
     * @var MsiAttributes
     */
    private $msiAttributes;

    private $productModel;
    private $productData;
    private $preparedData = [];
    private $productDescriptionData;
    private $productToAttributeSetData;
    private $productsToCategoriesData;
    private $productsCategoriesPaths;
    private $crossSellsData;
    private $importPart;
    private $msiAttributesData = [];
    protected $errors = [];

    /**
     * CreateProducts constructor.
     * @param LoggerInterface $logger
     * @param File $file
     * @param FixtureManager $fixtureManager
     * @param Registry $registry
     * @param State $state
     * @param CollectionFactory $productCollectionFactory
     * @param ProductRepositoryInterface $productRepository
     * @param ProductFactory $productFactory
     * @param AttributeSetRepositoryInterface $attributeSetRepository
     * @param FilterBuilder $filterBuilder
     * @param SearchCriteriaBuilder $searchCriteriaBuilder
     * @param SourceDataFactory $sourceDataFactory
     * @param ImportFactory $importFactory
     * @param ResourceConnection $resource
     * @param UrlValidator $urlValidator
     * @param CategoryCollectionFactory $categoryCollectionFactory
     * @param MsiAttributes $msiAttributes
     * @param string|null $name
     */
    public function __construct(
        LoggerInterface $logger,
        File $file,
        FixtureManager $fixtureManager,
        Registry $registry,
        State $state,
        CollectionFactory $productCollectionFactory,
        ProductRepositoryInterface $productRepository,
        ProductFactory $productFactory,
        AttributeSetRepositoryInterface $attributeSetRepository,
        FilterBuilder $filterBuilder,
        SearchCriteriaBuilder $searchCriteriaBuilder,
        SourceDataFactory $sourceDataFactory,
        ImportFactory $importFactory,
        ResourceConnection $resource,
        UrlValidator $urlValidator,
        CategoryCollectionFactory $categoryCollectionFactory,
        MsiAttributes $msiAttributes,
        string $name = null
    ) {
        parent::__construct($name);
        $this->logger = $logger;
        $this->file = $file;
        $this->fixtureManager = $fixtureManager;
        $this->registry = $registry;
        $this->state = $state;
        $this->productCollectionFactory = $productCollectionFactory;
        $this->productRepository = $productRepository;
        $this->productFactory = $productFactory;
        $this->attributeSetRepository = $attributeSetRepository;
        $this->filterBuilder = $filterBuilder;
        $this->searchCriteriaBuilder = $searchCriteriaBuilder;
        $this->sourceDataFactory = $sourceDataFactory;
        $this->importFactory = $importFactory;
        $this->resource = $resource;
        $this->urlValidator = $urlValidator;
        $this->categoryCollectionFactory = $categoryCollectionFactory;
        $this->msiAttributes = $msiAttributes;
        $this->productModel = $productFactory->create();
    }

    /**
     * @inheritDoc
     */
    protected function configure()
    {
        $this->setName('catalog:products:create');
        $this->setDescription('Products migration');
        $this->addOption(
            self::FILE_PART,
            null,
            InputOption::VALUE_OPTIONAL,
            'Choose one of two parts of file to import'
        );
        $this->addOption(
            self::CLEAR_CATALOG,
            null,
            InputOption::VALUE_OPTIONAL,
            'Clear products entities'
        );
        parent::configure();
    }

    /**
     * @param InputInterface $input
     * @param OutputInterface $output
     * @return int|void|null
     */
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $this->prepareMsiMapping();
        try {
            $this->productToAttributeSetData = [];
            $this->importPart = $input->getOption(self::FILE_PART);
            $this->productData = $this->getDataFromFile(self::FIXTURE_PRODUCTS_FR_FILE_PATH);
            $this->productToAttributeSetData
                = $this->getDataFromFile(self::FIXTURE_ATTRIBUTE_SETS_RELATION_FR_FILE_PATH);
            $this->productsToCategoriesData
                = $this->getDataFromFile(self::FIXTURE_PRODUCTS_TO_CATEGORIES_FR_FILE_PATH);
            $this->getProductDescriptionFields(self::FIXTURE_PRODUCTS_DESCRIPTION_FR_FILE_PATH);
            $this->getCrossSellingData(self::FIXTURE_CROSSSELLING_FILE_PATH);
            $this->state->setAreaCode(Area::AREA_ADMINHTML);
            $output->writeln("Removing all products before import new ones...");
            if ($input->getOption(self::CLEAR_CATALOG)) {
                //Clear products entities only when true parameter was passed
                $this->removeAllProducts();
            }
            $output->writeln("Clean done!");
            $output->writeln(
                "Preparing categories paths with names, to assign products to the right categories..."
            );
            $this->prepareCategoriesPaths();
            $output->writeln("Categories mapping done!");
            $output->writeln("Preparing rest of products data mapping...");
            $this->prepareData();
            $output->writeln("Products data mapping done!");
            $output->writeln("Begin products import...");
            $this->toMagentoProducts();
            $output->writeln("End Importing products!");
        } catch (Exception $e) {
            $output->writeln($e->getMessage());
            $this->logger->critical($e->getMessage());
        }
    }

    /**
     * Clear table before importing new products
     */
    public function removeAllProducts()
    {
        $connection = $this->resource->getConnection();
        //Clear products table before importing new ones
        $connection->query("DELETE FROM catalog_product_entity;");
        //Clear url rewrites table to avoid error with 'already defined url for current store'
        $connection->query("DELETE FROM url_rewrite WHERE entity_type = 'product';");
    }

    /**
     * Data mapping to the structure required by magento importer
     * @throws FileSystemException
     * @throws LocalizedException
     */
    public function prepareData()
    {
        $configuredGroupedSkus = [];
        $changedGroupedSkus = [];
        $groupedProducts = [];
        $importedUrlKeys = [];
        $connection = $this->resource->getConnection();
        foreach ($this->productData as $key => $item) {
            if ($simpleSku = $this->getImportField('products_model', $item)) {
                $this->preparedData[$key]['id'] = $this->getImportField('products_id', $item) ?: 0;
                if ($this->preparedData[$key]['id'] == 0) {
                    // Cannot import product without OSCommerce ID, it's needed to get related data from other files
                    var_export("Product ID not found in import files
                    (it's needed to find related data from other files), skipping!\r\n");
                    unset($this->preparedData[$key]);
                    continue;
                }
                if ($this->importPart == 1) {
                    if ($this->preparedData[$key]['id'] > 5000) {
                        unset($this->preparedData[$key]);
                        continue;
                    }
                } elseif ($this->importPart == 2) {
                    if ($this->preparedData[$key]['id'] <= 5000) {
                        unset($this->preparedData[$key]);
                        continue;
                    }
                }
                //Prepare description fields for EN store view
                foreach (self::PRODUCT_DESCRIPTION_FIELDS_MAPPING as $magentoField => $importField) {
                    $description = $this->getDescriptionData(
                        $this->preparedData[$key]['id'],
                        self::EN_LANGUAGE_IMPORT_ID,
                        $magentoField
                    );
                    $this->preparedData[$key][$magentoField] = $description;
                }
                if ($this->preparedData[$key]['name'] == false) {
                    // Cannot import product without Name
                    var_export("Name not found in import files for product ID: "
                        . $this->preparedData[$key]['id'] . ", skipping!\r\n");
                    unset($this->preparedData[$key]);
                    continue;
                }
                $this->preparedData[$key]['_product_websites'] = 'cnc_eu'
                    . self::MULTIPLE_VALUES_SEPARATOR . 'cnc_gb'
                    . self::MULTIPLE_VALUES_SEPARATOR . 'cnc_us';

                //Commented, to check if nothing broken, becasue we do not use default stock, but SOURCES with MSI
                //$this->preparedData[$key]['qty'] = $this->getImportField('products_quantity', $item) ?: 0;

                $this->preparedData[$key]['sku'] = $simpleSku;
                $qty = $this->getImportField('products_quantity', $item) ?: 0;
                $connection->insert(
                    $connection->getTableName('cnc_stock_import'),
                    ['source_code' => 'cnc_fr', 'sku' => $this->preparedData[$key]['sku'], 'qty' => $qty],
                );

                if ($this->preparedData[$key]['sku'] == false) {
                    // Cannot import product without SKU
                    var_export("SKU not found in import files for product ID: "
                        . $this->preparedData[$key]['id'] . ", skipping!\r\n");
                    unset($this->preparedData[$key]);
                    continue;
                }
                //Prepare unique sku for url key generation, because of problem with duplicated
                // when sku contains '-' at the end (magento truncate this char)
                if (substr($this->preparedData[$key]['sku'], -1) == '-') {
                    $skuForUrlKey = $this->preparedData[$key]['sku'] . uniqid();
                } else {
                    $skuForUrlKey = $this->preparedData[$key]['sku'];
                }

                $this->preparedData[$key]['price'] = $this->getImportField('products_price', $item) ?: 0;
                $this->preparedData[$key]['product_type'] = 'simple';
                $this->preparedData[$key]['image'] = $this->getImportField('products_image', $item) ?: 'empty.png';
                $this->preparedData[$key]['created_at'] = $this->getImportField('products_date_added', $item);
                $this->preparedData[$key]['updated_at'] = $this->getImportField('products_last_modified', $item);
                $this->preparedData[$key]['status'] = $this->getImportField('products_status', $item);
                $this->preparedData[$key]['weight'] = $this->getImportField('products_weight', $item) ?: 0;
                $this->preparedData[$key]['visibility'] = self::CATALOG_SEARCH;
                $this->preparedData[$key]['tax_class_name'] = 'Biens et services soumis à la TVA à 20%';
                $this->preparedData[$key]['merchant_center_category']
                    = $this->getImportField('products_google_merchant', $item);
                $this->preparedData[$key]['_attribute_set'] = $this->getAttributeSetForProduct(
                    $this->preparedData[$key]['id']
                )->getAttributeSetName();
                $this->preparedData[$key]['url_key'] = $this->productModel->formatUrlKey(
                    $this->preparedData[$key]['name']
                    . '-' . $skuForUrlKey
                    . '-p-'
                    . $this->preparedData[$key]['id']
                );
                //Get categories for import data for EN store
                if (array_key_exists($this->preparedData[$key]['id'], $this->productsCategoriesPaths)) {
                    $this->preparedData[$key]['categories']
                        = $this->productsCategoriesPaths[$this->preparedData[$key]['id']];
                }

                //Get categories for import data for FR store and rest of data for FR store if categories are set
                if (array_key_exists($this->preparedData[$key]['id'], $this->productsCategoriesPaths)) {
                    //Prepare description fields for EN store view
                    foreach (self::PRODUCT_DESCRIPTION_FIELDS_MAPPING as $magentoField => $importField) {
                        $this->preparedData[$key . 'cnc_fr_eu'][$magentoField]
                            = $this->getDescriptionData(
                                $this->preparedData[$key]['id'],
                                self::FR_LANGUAGE_IMPORT_ID,
                                $magentoField
                            );
                    }
                    // Exit from FR store product creating when Name is not configured for it
                    if ($this->preparedData[$key . 'cnc_fr_eu']['name'] != false) {
                        $this->preparedData[$key . 'cnc_fr_eu']['sku'] = $this->preparedData[$key]['sku'];
                        $this->preparedData[$key . 'cnc_fr_eu']['url_key'] = $this->productModel->formatUrlKey(
                            $this->preparedData[$key . 'cnc_fr_eu']['name']
                            . '-' . $skuForUrlKey . '-p-' . $this->preparedData[$key]['id']
                        );
                        $this->preparedData[$key . 'cnc_fr_eu']['_product_websites'] = 'cnc_eu';
                        /**
                         * Commented, to check if nothing broken,
                         * becasue we do not use default stock,
                         * but SOURCES with MSI
                         */
                        // $this->preparedData[$key . 'cnc_fr_eu']['qty'] = $this->preparedData[$key]['qty'];
                        $this->preparedData[$key . 'cnc_fr_eu']['price'] = $this->preparedData[$key]['price'];
                        $this->preparedData[$key . 'cnc_fr_eu']['cnc_net_weight'] = 0;
                        $this->preparedData[$key . 'cnc_fr_eu']['product_type']
                            = $this->preparedData[$key]['product_type'];
                        $this->preparedData[$key . 'cnc_fr_eu']['_attribute_set']
                            = $this->preparedData[$key]['_attribute_set'];
                        $this->preparedData[$key . 'cnc_fr_eu']['store_view_code'] = 'cnc_fr_eu';
                        $this->preparedData[$key . 'cnc_fr_eu']['_store'] = 'cnc_fr_eu';
                        $this->preparedData[$key . 'cnc_fr_eu']['categories']
                            = $this->productsCategoriesPaths[$this->preparedData[$key]['id']];
                    } else {
                        // Cannot import product without Name
                        unset($this->preparedData[$key . 'cnc_fr_eu']);
                    }
                }
                if (isset($item['products_group'])) {
                    // take already changed sku of grouped to avoid problems with different grouped products assignment
                    if (array_key_exists($item['products_group'], $changedGroupedSkus)) {
                        $item['products_group'] = $changedGroupedSkus[$item['products_group']];
                    }
                    if ($item['products_model'] == $item['products_group']) {
                        //Change sku of grouped product when it's the same as simple associated, to avoid errors
                        $groupedProductSku = $item['products_group'] . '-g';
                        $changedGroupedSkus[$item['products_group']] = $groupedProductSku;
                        $item['products_group'] = $groupedProductSku;
                    }
                }
                $youtube = 0; //TODO: Currently native Magento Importer is not supporting Media video import
                //Populate cnc data on Simple Product
                $this->preparedData[$key]['cnc_manufacturer'] = $this->getCncAttribute('manufacturers_id', $item);
                $this->preparedData[$key]['cnc_number_ordered'] = $this->getImportField('products_ordered', $item);
                $this->preparedData[$key]['cnc_state_of_wear'] = $this->getCncAttribute('etats_id', $item);
                $this->preparedData[$key]['cnc_guarantee_duration'] = $this->getCncAttribute('garanties_id', $item);
                $this->preparedData[$key]['cnc_guarantee_type'] = $this->getCncAttribute('types_id', $item);
                $availabilityValueId = $this->getCncAttribute('disponibilites_id', $item);
                $connection->insertOnDuplicate(
                    $connection->getTableName('msi_custom_attribute_value'),
                    [
                        'source_code' => 'cnc_fr',
                        'sku' => $this->preparedData[$key]['sku'],
                        'attribute_id' => $this->msiAttributes->getAttributeId('cnc_availability'),
                        'value' => (int) $availabilityValueId
                    ],
                );

                $this->preparedData[$key]['cnc_oscom_id'] = $this->getImportField('products_id', $item);
                $this->preparedData[$key]['cnc_net_weight'] = 0;
                $this->preparedData[$key]['cnc_salable_out_of_stock']
                    = $this->getImportField('products_achat_hors_stock_ok', $item);
                $this->preparedData[$key]['cnc_customs_code']
                    = $this->getImportField('products_code_douanier', $item) ?: 0;

                if ($manufacturerPriceDate = $this->getImportField('products_price_constate_date', $item)) {
                    if ($manufacturerPriceDate != null
                        && $manufacturerPriceDate !== 'NULL'
                        && strtotime($manufacturerPriceDate) !== false) {
                        $this->preparedData[$key]['cnc_manufacturer_price_date'] = $manufacturerPriceDate;
                    }
                }
                if ($manufacturerPrice = $this->getImportField('products_price_constate', $item)) {
                    if ($manufacturerPrice != null && $manufacturerPrice !== 'NULL') {
                        $this->preparedData[$key]['cnc_manufacturer_price'] = $manufacturerPrice;
                    }
                }
                //Assign crossSell products from OsCommerce as Upsell products in Magento2
                if (isset($this->crossSellsData[$simpleSku])) {
                    $this->preparedData[$key]['_upsell_sku'] = $this->crossSellsData[$simpleSku];
                }

                //Populate data on Grouped Product
                if ($groupedSku = $this->getImportField('products_group', $item)) {
                    $groupedProducts[$groupedSku]['product_type'] = 'grouped';
                    if (!isset($groupedProducts[$groupedSku]['sku'])) {
                        $groupedProducts[$groupedSku]['sku'] = $groupedSku;
                    }
                    if ($this->getImportField('products_order', $item) == 1
                        || !in_array($groupedSku, $configuredGroupedSkus)) {
                        $groupedProducts[$groupedSku]['_product_websites'] = 'cnc_eu'
                            . self::MULTIPLE_VALUES_SEPARATOR . 'cnc_gb'
                            . self::MULTIPLE_VALUES_SEPARATOR . 'cnc_us';
                        $groupedProducts[$groupedSku]['visibility'] = self::CATALOG_SEARCH;
                        if (isset($this->preparedData[$key]['cnc_manufacturer_price_date'])) {
                            $groupedProducts[$groupedSku]['cnc_manufacturer_price_date']
                                = $this->preparedData[$key]['cnc_manufacturer_price_date'];
                        }
                        if (isset($this->preparedData[$key]['cnc_manufacturer_price'])) {
                            $groupedProducts[$groupedSku]['cnc_manufacturer_price']
                                = $this->preparedData[$key]['cnc_manufacturer_price'];
                        }
                        $groupedProducts[$groupedSku]['_attribute_set'] = $this->preparedData[$key]['_attribute_set'];
                        //Add custom string to the name, because of url keys generation error during import,
                        //some of simple products have the same names and change the grouped name helps here.
                        $groupedProducts[$groupedSku]['name'] = $this->preparedData[$key]['name'];
                        //Take url keys exported from M1 if exists, in other way create unique url key, because of
                        // problem with duplicated skus and names which gives errors for duplicated urls
                        if (isset($this->preparedData[$key]['grouped_url_key'])
                            && !in_array($this->preparedData[$key]['grouped_url_key'], $importedUrlKeys)) {
                            $groupedProducts[$groupedSku]['url_key'] = $this->preparedData[$key]['grouped_url_key']
                                . '-p-' . $this->preparedData[$key]['id'];
                            $importedUrlKeys[] = $groupedProducts[$groupedSku]['url_key'];
                        } else {
                            $groupedProducts[$groupedSku]['url_key'] = $this->productModel->formatUrlKey(
                                $groupedProducts[$groupedSku]['name']
                                . '-' . uniqid() . '-p-' . $this->preparedData[$key]['id']
                            );
                        }
                        $groupedProducts[$groupedSku]['display_product_options_in'] = 'Block after Info Column';
                        $groupedProducts[$groupedSku]['description'] = $this->preparedData[$key]['description'];
                        $groupedProducts[$groupedSku]['cnc_manufacturer'] = $this->preparedData[$key]['cnc_manufacturer'];
                        $groupedProducts[$groupedSku]['cnc_net_weight'] = 0;
                        $groupedProducts[$groupedSku]['cnc_oscom_id'] = $this->preparedData[$key]['cnc_oscom_id'];

                        //Prepare grouped products FR store view data
                        if (isset($this->preparedData[$key . 'cnc_fr_eu']['name']) ) {
                            $groupedProducts[$groupedSku . 'cnc_fr_eu']['product_type'] = 'grouped';
                            $groupedProducts[$groupedSku . 'cnc_fr_eu']['name'] =
                                $this->preparedData[$key . 'cnc_fr_eu']['name'];
                            $groupedProducts[$groupedSku . 'cnc_fr_eu']['description'] =
                                $this->preparedData[$key . 'cnc_fr_eu']['description'];
                            $groupedProducts[$groupedSku . 'cnc_fr_eu']['sku'] = $groupedSku;
                            $groupedProducts[$groupedSku . 'cnc_fr_eu']['url_key'] = $this->productModel->formatUrlKey(
                                $this->preparedData[$key . 'cnc_fr_eu']['name']
                                . '-' . uniqid() . '-p-' . $this->preparedData[$key]['id']
                            );
                            $groupedProducts[$groupedSku . 'cnc_fr_eu']['_product_websites'] =
                                $this->preparedData[$key . 'cnc_fr_eu']['_product_websites'];
                            $groupedProducts[$groupedSku . 'cnc_fr_eu']['cnc_net_weight'] = 0;
                            $groupedProducts[$groupedSku . 'cnc_fr_eu']['_attribute_set'] =
                                $this->preparedData[$key . 'cnc_fr_eu']['_attribute_set'];
                            $groupedProducts[$groupedSku . 'cnc_fr_eu']['store_view_code'] =
                                $this->preparedData[$key . 'cnc_fr_eu']['store_view_code'];
                            $groupedProducts[$groupedSku . 'cnc_fr_eu']['_store'] =
                                $this->preparedData[$key . 'cnc_fr_eu']['_store'];
                            $groupedProducts[$groupedSku . 'cnc_fr_eu']['categories'] =
                                $this->preparedData[$key . 'cnc_fr_eu']['categories'];
                        }


                        //We are not saving some attributes data on Simple Product if Grouped Product exist
                        unset($this->preparedData[$key]['description']);
                        unset($this->preparedData[$key]['cnc_manufacturer']);
                        if (isset($this->preparedData[$key . 'cnc_fr_eu']['description'])) {
                            unset($this->preparedData[$key . 'cnc_fr_eu']['description']);
                        }
                        $groupedProducts[$groupedSku]['image'] = $this->preparedData[$key]['image'];
                        if (isset($this->preparedData[$key]['categories'])) {
                            $groupedProducts[$groupedSku]['categories'] = $this->preparedData[$key]['categories'];
                        }
                        //Assign crossSell products from OsCommerce as Upsell products in Magento2
                        if (isset($this->crossSellsData[$groupedSku])) {
                            $groupedProducts[$groupedSku]['_upsell_sku'] = $this->crossSellsData[$groupedSku];
                        }
                        $configuredGroupedSkus[] = $groupedProducts[$groupedSku]['sku'];
                    }
                    if (isset($groupedProducts[$groupedSku]['associated_skus'])) {
                        //prepare custom format, because only this format is acceptable in Magento importer
                        $multipleSkusFormat = trim($groupedProducts[$groupedSku]['associated_skus'], '"')
                            . ',' . $simpleSku . '=' . 1;
                        $groupedProducts[$groupedSku]['associated_skus'] = $multipleSkusFormat;
                    } else {
                        $groupedProducts[$groupedSku]['associated_skus'] = $simpleSku . '=' . 1;
                    }
                    //Disable simple product visibility when it's assigned to grouped
                    $this->preparedData[$key]['visibility'] = self::NOT_VISIBLE_INDIVIDUALLY;
                }
            } elseif (array_key_exists('products_id', $item)) {
                var_export("Missing products_model field (SKU) for product ID "
                    . $item['products_id'] . "\r\n");
            } else {
                var_export("Missing products_model field (SKU) and ID for one of products\r\n");
            }
        }
        $this->preparedData = array_merge($this->preparedData, $groupedProducts);
    }

    /**
     * Mapping for products assignment to categories used in import field 'categories'
     * @throws LocalizedException
     */
    public function prepareCategoriesPaths()
    {
        $productsToCategory = [];
        foreach ($this->productsToCategoriesData as $productCategoryRelation) {
            if (array_key_exists('products_id', $productCategoryRelation)
                && array_key_exists('categories_id', $productCategoryRelation)) {
                $productsToCategory[$productCategoryRelation['products_id']][]
                    = $productCategoryRelation['categories_id'];
            }
        }
        $categoriesPaths = $this->getCategoriesPaths();
        foreach ($productsToCategory as $productId => $categoriesIds) {
            foreach ($categoriesIds as $categoryId) {
                if (isset($categoriesPaths[$categoryId]) && $categoriesPaths[$categoryId] != false) {
                    if (isset($this->productsCategoriesPaths[$productId])) {
                        $this->productsCategoriesPaths[$productId] =
                            $this->productsCategoriesPaths[$productId]
                            . self::MULTIPLE_VALUES_SEPARATOR . $categoriesPaths[$categoryId];
                    } else {
                        $this->productsCategoriesPaths[$productId] = $categoriesPaths[$categoryId];
                    }
                }
            }
        }
    }

    /**
     * Build categories paths using names instead of IDs, needed in magento product importer to assign categories
     * @param $categoryName
     * @return bool|string|string[]
     * @throws LocalizedException
     */
    public function getCategoryNamesPath($categoryName)
    {
        $storeId = 0;
        $categoriesNamesPath = false;
        $categoryCollection = $this->categoryCollectionFactory->create();
        $categoryCollection->setStoreId($storeId)
            ->addAttributeToFilter('name', $categoryName)
            ->setPageSize(1);
        $result = $categoryCollection->getFirstItem();
        if ($result->getId()) {
            $pathIds = $result->getPathIds();
            $pathCategoriesCollection = $this->categoryCollectionFactory->create();
            $pathCategoriesCollection->setStoreId($storeId)
                ->addAttributeToSelect('name')
                ->addAttributeToFilter('entity_id', ['in' => $pathIds]);
            $categoriesNamesPath = '';
            foreach ($pathCategoriesCollection as $pathCategory) {
                $categoryName = $pathCategory->getName();
                if (strpos($categoryName, '/')) {
                    //Fix for categories with slash in name. Magento divides categories by slash,
                    // but with \ before this slash it will be treated like one category
                    $categoryName = str_replace('/', '\/', $categoryName);
                }
                $categoriesNamesPath .= $categoryName . '/';
            }
            $categoriesNamesPath = substr($categoriesNamesPath, 0, -1);
            $categoriesNamesPath = str_replace(
                'Root Catalog/',
                '',
                $categoriesNamesPath
            );
        }
        return $categoriesNamesPath;
    }

    /**
     * Import!
     */
    protected function toMagentoProducts()
    {
        $sourceModel = $this->sourceDataFactory->create(['data' => [$this->preparedData]]);

        $product = $this->importFactory->create(['importData' => $sourceModel]);

        //Set double semi column as Multiple value separator.
        $parameters = $product->getParameters();
        $parameters[\Magento\ImportExport\Model\Import::FIELD_FIELD_MULTIPLE_VALUE_SEPARATOR]
            = self::MULTIPLE_VALUES_SEPARATOR;
        $product->setParameters($parameters);

        //Launch import of bunch.
        try {
            $product->importData();
        } catch (Exception $exception) {
            var_export($exception->getMessage());
        }
        //Check errors
        $errors = $product->getErrorAggregator()->getAllErrors();
        if (count($errors)) {
            array_map(function ($error) {
                $this->logger->info(
                    sprintf(
                        "Error on line %s (%s) : %s",
                        $error->getRowNumber(),
                        $error->getErrorCode(),
                        $error->getErrorMessage()
                    )
                );

                $this->errors[] = $error->getRowNumber();
            }, $errors);
        }
        unset($this->preparedData);
        unset($this->errors);
    }

    /**
     * Get attribute sets data from attribute sets import file to make attribute set field importable
     * @param $productId
     * @return AttributeSetInterface
     * @throws FileSystemException
     * @throws LocalizedException
     */
    public function getAttributeSetForProduct($productId)
    {
        $attributeSetData = $this->getDataFromFile(self::FIXTURE_ATTRIBUTE_SETS_FR_FILE_PATH);
        // Default attribute set for products
        $attributeSetName = 'Other';
        foreach ($this->productToAttributeSetData as $relation) {
            if (isset($relation['products_id']) && $relation['products_id'] == $productId) {
                $setId = $relation['type_products_id'];
                foreach ($attributeSetData as $attributeSet) {
                    if ($attributeSet['type_products_id'] == $setId
                        && $attributeSet['language_id'] == self::EN_LANGUAGE_IMPORT_ID) {
                        $attributeSetName = $attributeSet['type_products_name'];
                    }
                }
            }
        }
        $filter = $this->filterBuilder
            ->setField('attribute_set_name')
            ->setValue($attributeSetName)
            ->setConditionType('eq')
            ->create();
        $searchCriteria = $this->searchCriteriaBuilder
            ->addFilters([$filter])
            ->create();
        $attributeSet = $this->attributeSetRepository->getList($searchCriteria);
        $items = $attributeSet->getItems();
        return reset($items);
    }

    /**
     * Get description data of product from mapped array
     *
     * @param $productId
     * @param $languageId
     * @param $field
     * @return bool
     */
    public function getDescriptionData($productId, $languageId, $field)
    {
        $result = false;
        if (array_key_exists($productId, $this->productDescriptionData)
            && array_key_exists($languageId, $this->productDescriptionData[$productId])
            && array_key_exists($field, $this->productDescriptionData[$productId][$languageId])) {
            $result = $this->productDescriptionData[$productId][$languageId][$field];
        }
        return $result;
    }

    /**
     * Get CNC attributes data from corresponding import files for each of these attributes,
     * because it's the same as in magento (we import it before products import from the same files)
     * @param $field
     * @param $item
     * @return bool
     * @throws FileSystemException
     * @throws LocalizedException
     */
    public function getCncAttribute($field, $item)
    {
        $attributeValue = false;
        if ($value = $this->getImportField($field, $item)) {
            $fileName = false;
            switch ($field) {
                case 'manufacturers_id':
                    $fileName = UpdateCustomTablesAttributesData::FIXTURE_MANUFACTURER_DATA_FILE_PATH;
                    break;
                case 'etats_id':
                    $fileName = UpdateCustomTablesAttributesData::FIXTURE_STATE_OF_WEAR_DATA_FILE_PATH;
                    break;
                case 'garanties_id':
                    $fileName = UpdateCustomTablesAttributesData::FIXTURE_GUARANTEE_DURATION_DATA_FILE_PATH;
                    break;
                case 'types_id':
                    $fileName = UpdateCustomTablesAttributesData::FIXTURE_GUARANTEE_TYPE_DATA_FILE_PATH;
                    break;
                case 'disponibilites_id':
                    $mapping = [
                        1 => Config::PRODUCT_AVAILABILITY_ICON_SHIPMENT_WITHIN_3_DAYS_VALUE,
                        2 => Config::PRODUCT_AVAILABILITY_ICON_IMMEDIATE_SHIPMENT_VALUE,
                        3 => Config::PRODUCT_AVAILABILITY_ICON_AVAILABLE_IN_5_TO_8_DAYS_VALUE,
                        4 => Config::PRODUCT_AVAILABILITY_ICON_CONFIRMATION_OF_SHIPPING_TIME_ON_REQUEST_VALUE,
                        6 => Config::PRODUCT_AVAILABILITY_ICON_OUT_OF_STOCK_VALUE
                    ];
                    return $this->msiAttributesData['cnc_availability'][$mapping[$value]];
            }
            if ($fileName) {
                $attributeFileData = $this->getDataFromFile($fileName);
                foreach ($attributeFileData as $row) {
                    //ID is always at first element and the name in second, in the attributes files.
                    $dataRow = array_values($row);
                    if ($value == $dataRow[0]) {
                        $attributeValue = $dataRow[1];
                    }
                }
            }
        }
        return $attributeValue;
    }

    /**
     * Get single import field
     *
     * @param $key
     * @param $item
     * @return string|bool
     * @throws FileSystemException
     */
    public function getImportField($key, $item)
    {
        $returnValue = false;
        if (array_key_exists($key, $item)) {
            if ($key == 'products_image') {
                if ($this->file->isExists($this->file->getRealPath('pub/media/import/' . $item[$key]))
                    && $this->urlValidator->isValid($item[$key])) {
                    $returnValue = $item[$key];
                } else {
                    var_export("Image file not exists or has invalid name in pub/media/import dir: {$item[$key]}\r\n");
                }
            } else {
                $returnValue = $item[$key];
            }
        }
        return $returnValue;
    }

    /**
     * Set product description to smaller array than comes from whole file
     *
     * @param $fileName
     * @throws FileSystemException
     * @throws LocalizedException
     */
    public function getProductDescriptionFields($fileName)
    {
        $data = $this->getDataFromFile($fileName);
        foreach ($data as $row) {
            if (array_key_exists('products_id', $row) && array_key_exists('language_id', $row)) {
                foreach (self::PRODUCT_DESCRIPTION_FIELDS_MAPPING as $magentoField => $importField) {
                    $this->productDescriptionData[$row['products_id']][$row['language_id']][$magentoField]
                        = array_key_exists($importField, $row)
                        ? $row[$importField]
                        : null;
                }
            }
        }
    }

    /**
     * @param $fileName
     * @throws FileSystemException
     * @throws LocalizedException
     */
    public function getCrossSellingData($fileName)
    {
        $IdToSkuMapping = [];
        $data = $this->getDataFromFile($fileName);
        //Prepare specific mapping used only in crossSells/upsells association in this import
        foreach ($this->productData as $productRow) {
            if (isset($productRow['products_id']) && isset($productRow['products_model'])) {
                //get grouped product sku when current simple is linked to one
                if (isset($productRow['products_group'])) {
                    $IdToSkuMapping[$productRow['products_id']] =
                        [
                            'simpleSku' => $productRow['products_model'],
                            'groupedSku' => $productRow['products_group']
                        ];
                } else {
                    $IdToSkuMapping[$productRow['products_id']] = $productRow['products_model'];
                }
            }
        }

        foreach ($data as $row) {
            if (isset($row['products_id']) && isset($row['list_id']) && isset($IdToSkuMapping[$row['products_id']])) {
                //prepare mapping from id's to skus of crossSell products
                foreach (explode(',', $row['list_id']) as $crossSellId) {
                    if (isset($IdToSkuMapping[$crossSellId]) && isset($IdToSkuMapping[$row['products_id']])) {
                        //Get sku of new upsell product (osCommerce crossells will be imported as Magento upsells)
                        if (isset($IdToSkuMapping[$crossSellId]['groupedSku'])) {
                            $crossSellSku = $IdToSkuMapping[$crossSellId]['groupedSku'];
                        } else {
                            $crossSellSku = $IdToSkuMapping[$crossSellId];
                        }
                        //Get the sku of product to which we assign
                        if (isset($IdToSkuMapping[$row['products_id']]['groupedSku'])) {
                            $keySku = $IdToSkuMapping[$row['products_id']]['groupedSku'];
                        } else {
                            $keySku = $IdToSkuMapping[$row['products_id']];
                        }
                        //Set data to be used in import main logic
                        if (isset($this->crossSellsData[$keySku])) {
                            $crossSellsSkusFormat = $this->crossSellsData[$keySku]
                                . self::MULTIPLE_VALUES_SEPARATOR
                                . $crossSellSku;
                            $this->crossSellsData[$keySku] = $crossSellsSkusFormat;
                        } else {
                            $this->crossSellsData[$keySku] = $crossSellSku;
                        }
                    }
                }
            }
        }
    }

    /**
     * Get simplier mapping of category path with parents names, needed in magento importer
     * to assign product to the right category.
     * @return array
     * @throws LocalizedException
     */
    public function getCategoriesPaths()
    {
        $categoriesData = $this->getDataFromFile(self::FIXTURE_CATEGORIES_DESCRIPTION_FR_FILE_PATH);
        $categoriesPaths = [];
        foreach ($categoriesData as $categoryData) {
            if (array_key_exists('categories_id', $categoryData)
                && array_key_exists('categories_name', $categoryData)) {
                if (!isset($categoriesPaths[$categoryData['categories_id']])) {
                    $categoriesPaths[$categoryData['categories_id']]
                        = $this->getCategoryNamesPath($categoryData['categories_name']);
                } elseif ($categoriesPaths[$categoryData['categories_id']] == false) {
                    $categoriesPaths[$categoryData['categories_id']]
                        = $this->getCategoryNamesPath($categoryData['categories_name']);
                }
            }
        }
        return $categoriesPaths;
    }

    /**
     * Read the data from provided import/relation file
     * @param $name
     * @return array
     * @throws FileSystemException
     * @throws LocalizedException
     */
    public function getDataFromFile($name)
    {
        $data = [];
        $fileName = $this->fixtureManager->getFixture($name);
        $file = $this->file->fileOpen($fileName, "r");
        $header = $this->file->fileGetCsv($file, 0, ",");

        while ($row = $this->file->fileGetCsv($file, 0, ",")) {
            $data[] = array_filter(array_combine($header, $row));
        }
        return $data;
    }

    /**
     * Prepare mapping for msi custom attributes.
     */
    private function prepareMsiMapping()
    {
        $attributesCode = ['cnc_availability', 'cnc_localization'];
        foreach ($attributesCode as $attributeCode) {
            $attribute = $this->msiAttributes->getAttribute($attributeCode);
            $this->msiAttributesData[$attributeCode] = $this->msiAttributes->getDropdownOptions($attribute->getId());
        }
    }
}

Spamworldpro Mini