Magento 2 : importer des produits depuis des sources externes

Magento est une solution de commerce électronique, c'est-à-dire est davantage destiné à la vente de produits qu'à l'entreposage, à la logistique ou à la comptabilité financière accompagnant les ventes. D'autres applications (par exemple, les systèmes ERP) sont mieux adaptées aux applications d'accompagnement. Par conséquent, très souvent, dans la pratique de l'utilisation de Magento, la tâche d'intégrer un magasin à ces autres systèmes (par exemple, 1C) se pose.

Dans l'ensemble, l'intégration peut être réduite à la réplication des données en :

  • catalogue (produits, catégories) ;
  • données d'inventaire (soldes des produits dans les entrepôts et prix) ;
  • clients ;
  • ordres;

Magento propose une classe distincte d'objets pour manipuler les données dans la base de données - référentiels. En raison des spécificités de Magento, l’ajout de données à la base de données via des référentiels est facile à coder, mais c’est, disons, lent. Dans cette publication, je considère les principales étapes de l'ajout par programmation d'un produit à Magento 2 de la manière « classique » - en utilisant des classes repo.

Les clients et les commandes sont généralement répliqués dans l’autre sens – de Magento vers des systèmes ERP externes. C’est donc plus simple avec eux, côté Magento il vous suffit de sélectionner les données appropriées, puis «les balles ont volé de notre côté«.

Principes d'enregistrement des données dans une base de données

À l'heure actuelle, la création d'objets enregistrés dans la base de données par programmation dans Magento se fait via Usine:

function __construct (MagentoCmsModelBlockFactory $blockFactory) {
    $this->blockFactory = $blockFactory;
}

/** @var MagentoCmsModelBlock $block */
$block = $this->blockFactory->create();

et l'écriture dans la base de données se fait via Dépôt:

function __construct (MagentoCmsApiBlockRepositoryInterface $blockRepo) {
    $this->blockRepo = $blockRepo;
}

$this->blockRepo->save($block);

L'approche « Factory » et « Repository » peut être utilisée pour tous les modèles majeurs du domaine Magento 2.

Informations de base sur le produit

Je regarde une structure de données qui correspond à la version Magento 2.3. Les informations les plus élémentaires sur le produit se trouvent dans le tableau catalog_product_entity (registre des produits) :

entity_id
attribute_set_id
type_id
sku
has_options
required_options
created_at
updated_at

Je suis limité à un seul type de produit (type_id='simple'), un ensemble d'attributs par défaut (attribute_set_id=4) et ignorer les attributs has_options и required_options. Puisque les attributs entity_id, created_at и updated_at sont générés automatiquement, alors, en fait, pour ajouter un nouveau produit, il suffit de définir sku. Je fais ça:

/** @var MagentoCatalogApiDataProductInterfaceFactory $factProd */
/** @var MagentoCatalogApiProductRepositoryInterface $repoProd */
/** @var MagentoCatalogApiDataProductInterface $prod */
$prod = $factProd->create();
$prod->setAttributeSetId(4);
$prod->setTypeId('simple');
$prod->setSku($sku);
$repoProd->save($prod);

et j'obtiens une exception :

The "Product Name" attribute value is empty. Set the attribute and try again.

J'ajoute le nom du produit à la demande et je reçois un message indiquant que l'attribut est manquant Price. Après avoir ajouté le prix, le produit est ajouté à la base de données :

$prod = $factProd->create();
$prod->setAttributeSetId(4);
$prod->setTypeId('simple');
$prod->setSku($sku);
$prod->setName($name);
$prod->setPrice($price);
$repoProd->save($prod);

Le nom du produit est stocké dans la table attributaire du produit varchar (catalog_product_entity_varchar), prix - dans le tableau catalog_product_entity_decimal. Avant d'ajouter un produit, il convient d'indiquer explicitement que l'on utilise la vitrine administrative pour importer des données :

/** @var MagentoStoreModelStoreManagerInterface $manStore */
$manStore->setCurrentStore(0);

Attributs supplémentaires

Traiter des attributs de produit supplémentaires à l'aide de Magento est un plaisir. Modèle de données EAV pour les principales entités (voir tableau eav_entity_type) est l'une des fonctionnalités clés de cette plateforme. Nous ajoutons simplement les attributs appropriés au modèle de produit :

$prodEntity->setData('description', $desc);
$prodEntity->setData('short_description', $desc_short);
// или
$prodEntity->setDescription($desc);
$prodEntity->setShortDescription($desc_short);

et lors de la sauvegarde du modèle via l'objet repo :

$repoProd->save($prod);

des attributs supplémentaires seront également stockés dans les tables de base de données correspondantes.

Données d'inventaire

En termes simples, la quantité de produit en stock. Dans Magento 2.3, les structures de la base de données qui décrivent le format de stockage des données d'inventaire sont significativement différent de ce qui s'est passé auparavant. Cependant, ajouter la quantité d’un produit en stock via le modèle produit n’est pas beaucoup plus difficile que d’ajouter d’autres attributs :

/** @var MagentoCatalogModelProduct $prodEntity */
/** @var MagentoCatalogApiProductRepositoryInterface $repoProd */
$inventory = [
    'is_in_stock' => true,
    'qty' => 1234
];
$prodEntity->setData('quantity_and_stock_status', $inventory);
$repoProd->save($prodEntity);

médias

En règle générale, le support média d'un produit pour un client dans un magasin (e-commerce) diffère du support média du même produit pour un collaborateur dans un système comptable interne (ERP). Dans le premier cas, il convient de montrer le produit face à face ; dans le second, il suffit de donner une idée générale du produit. Cependant, transférer au moins l’image principale d’un produit est assez courant. case lors de l'importation de données.

Lors de l'ajout d'une image via le panneau d'administration, l'image est d'abord enregistrée dans un répertoire temporaire (./pub/media/tmp/catalog/product) et seulement lors de l'enregistrement, le produit est déplacé vers le répertoire multimédia (./pub/media/catalog/product). De plus, lorsqu'elle est ajoutée via le panneau d'administration, l'image est étiquetée image, small_image, thumbnail, swatch_image.

/** @var MagentoCatalogApiProductRepositoryInterface $repoProd */
/** @var MagentoCatalogModelProductGalleryCreateHandler $hndlGalleryCreate */
/* $imagePath = '/path/to/file.png';  $imagePathRelative = '/f/i/file.png' */
$imagePathRelative = $this->imagePlaceToTmpMedia($imagePath);
/* reload product with gallery data */
$product = $repoProd->get($sku);
/* add image to product's gallery */
$gallery['images'][] = [
    'file' => $imagePathRelative,
    'media_type' => 'image'
    'label' => ''
];
$product->setData('media_gallery', $gallery);
/* set usage areas */
$product->setData('image', $imagePathRelative);
$product->setData('small_image', $imagePathRelative);
$product->setData('thumbnail', $imagePathRelative);
$product->setData('swatch_image', $imagePathRelative);
/* create product's gallery */
$hndlGalleryCreate->execute($product);

Pour une raison quelconque, les médias ne sont liés qu'après avoir d'abord enregistré le produit et l'avoir récupéré à nouveau du référentiel. Et vous devez spécifier l'attribut label lors de l'ajout d'une entrée à la galerie multimédia du produit (sinon nous obtenons une exception Undefined index: label in .../module-catalog/Model/Product/Gallery/CreateHandler.php on line 516).

catégorie

Souvent, la structure des catégories du magasin et de l'application backend ou le placement des produits dans celles-ci peuvent différer considérablement. Les stratégies de migration des données sur les catégories et les produits qu'elles contiennent dépendent de nombreux facteurs. Dans cet exemple, je m'en tiens à ce qui suit :

  • Les catégories de backend et de magasin sont comparées par nom ;
  • si une catégorie importée n'est pas dans le magasin, elle est alors créée sous la catégorie racine (Default Category) et son positionnement ultérieur dans le catalogue du magasin est supposé manuellement ;
  • un produit est affecté à une catégorie uniquement lors de sa création en magasin (premier import) ;

Les informations de base sur la catégorie sont dans le tableau catalog_category_entity (catalogue des catégories). Créer une catégorie dans Magento :

/** @var MagentoCatalogApiDataCategoryInterfaceFactory $factCat */
/** @var MagentoCatalogApiCategoryRepositoryInterface $repoCat */
$cat = $factCat->create();
$cat->setName($name);
$cat->setIsActive(true);
$repoCat->save($cat);

La liaison d'un produit à une catégorie s'effectue à l'aide de l'ID de catégorie et du SKU du produit :

/** @var MagentoCatalogModelCategoryProductLinkFactory $factCatProdLink */
/** @var MagentoCatalogApiCategoryLinkRepositoryInterface $repoCatLink */
$link = $factCatProdLink->create();
$link->setCategoryId($catMageId);
$link->setSku($prodSku);
$repoCatLink->save($link);

En tout

Écrire du code pour ajouter un produit par programmation à Magento 2 est assez simple. J'ai combiné tout ce qui est indiqué ci-dessus dans un module de démonstration "flancer32/mage2_ext_demo_import". Il n'y a qu'une seule commande de console dans le module fl32:import:prod, qui importe les produits décrits dans le fichier JSON "./etc/data/products.json":

[
  {
    "sku": "...",
    "name": "...",
    "desc": "...",
    "desc_short": "...",
    "price": ...,
    "qty": ...,
    "categories": ["..."],
    "image_path": "..."
  }
]

Les photos à importer sont dans le catalogue ./etc/data/img.

Le temps nécessaire pour importer 10 produits en utilisant cette méthode est d'environ 10 secondes sur mon ordinateur portable. Si nous développons cette idée plus en détail, il est facile de conclure qu'environ 3600 100 produits peuvent être importés par heure, et qu'il faut environ 30 heures pour importer XNUMX XNUMX produits. Remplacer un ordinateur portable par un serveur permet d'aplanir quelque peu la situation. Peut-être même plusieurs fois. Mais pas par ordres de grandeur. Peut-être que cette rapidité et cette lenteur sont dans une certaine mesure l'une des raisons de l'émergence du projet magento/importation asynchrone.

Une solution radicale pour augmenter la vitesse d'importation pourrait être l'entrée directe dans la base de données, mais dans ce cas, tous les « avantages » concernant l'extensibilité de Magento sont perdus - vous devrez faire tout ce qui est « avancé » vous-même. Cependant, cela en vaut la peine. Si cela fonctionne, j'envisagerai l'approche avec écriture directe dans la base de données dans le prochain article.

Source: habr.com

Ajouter un commentaire