Magento 2: importazione di prodotti da fonti esterne

Magento è una soluzione e-commerce, cioè più orientata alla vendita di prodotti piuttosto che alla gestione del magazzino, della logistica o della contabilità finanziaria. Per queste ultime, sono più adatte altre applicazioni (come i sistemi ERP). Di conseguenza, nella pratica dell'utilizzo di Magento, si presenta spesso la necessità di integrare il negozio con questi altri sistemi (ad esempio, con 1C).

In linea di massima, l'integrazione può essere ridotta alla replicazione dei dati riguardanti:

  • catalogo (prodotti, categorie);
  • dati inventariali (giacenze dei prodotti nei magazzini e prezzi);
  • clienti;
  • ordini;

Magento offre una classe separata di oggetti per gestire i dati nel database — repository. A causa della specificità di Magento, l'aggiunta di dati al database tramite i repository è facilmente codificabile, ma avviene, per così dire, non in fretta. In questa pubblicazione esamino le fasi principali per aggiungere un prodotto in Magento 2 in modo “classico” — utilizzando le classi repo.

I clienti e gli ordini vengono replicati, di solito, nell'altra direzione — da Magento ai sistemi ERP esterni. Pertanto, per questi è più semplice, su Magento è sufficiente selezionare i dati corrispondenti, e poi —Le pallottole sono partite dalla nostra parte«.

Principi di registrazione dei dati nel database

Attualmente, la creazione di oggetti da salvare nel database in modo programmatico in Magento avviene tramite Factory:

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

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

e la registrazione nel database avviene tramite Repository:

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

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

L'approccio che utilizza «Factory» e «Repository» può essere utilizzato per tutti i modelli principali nel dominio di Magento 2.

Informazioni di base sul prodotto

Sto esaminando la struttura dei dati corrispondente alla versione Magento 2.3. Le informazioni più basilari sul prodotto si trovano nella tabella catalog_product_entity (registro dei prodotti):

entity_id
attribute_set_id
type_id
sku
has_options
required_options
created_at
updated_at

Mi limito a un tipo di prodotto (type_id='simple'), un insieme di attributi predefiniti (attribute_set_id=4) e ignoro gli attributi has_options e required_options. Poiché gli attributi entity_id, created_at e updated_at vengono generati automaticamente, per aggiungere un nuovo prodotto è sufficiente specificare sku. Procedo in questo modo:

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

e ricevo un'eccezione:

Il valore dell'attributo "Nome Prodotto" è vuoto. Imposta l'attributo e riprova.

Aggiungo nel richiesta il nome del prodotto e ricevo un messaggio che manca un attributo Prezzo. Dopo aver aggiunto il prezzo, il prodotto viene salvato nel database:

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

Il nome del prodotto viene salvato nella tabella degli attributi varchar del prodotto (catalog_product_entity_varchar), il prezzo — nella tabella catalog_product_entity_decimal. Prima di aggiungere il prodotto è consigliabile specificare chiaramente che stiamo utilizzando l'interfaccia amministrativa per importare i dati:

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

Attributi aggiuntivi

Gestire gli attributi aggiuntivi dei prodotti tramite Magento è un vero piacere. Il modello di dati EAV per le entità principali (vedi tabella eav_entity_type) è una delle caratteristiche chiave di questa piattaforma. Basta aggiungere gli attributi corrispondenti al modello di prodotto:

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

e, salvando il modello tramite l'oggetto repo:

$repoProd->save($prod);

gli attributi aggiuntivi verranno salvati anche nelle tabelle corrispondenti del DB.

Dati di inventario

In modo semplice, si parla della quantità di prodotto disponibile in magazzino. In Magento 2.3, le strutture nel database che descrivono il formato di archiviazione dei dati di inventario, differiscono notevolmente da quelle precedenti. Tuttavia, aggiungere la quantità di prodotto in magazzino tramite il modello di prodotto non è molto più complicato rispetto all'aggiunta di altri attributi:

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

Media

In generale, il supporto multimediale del prodotto per il cliente nel negozio (e-commerce) è diverso dal supporto multimediale dello stesso prodotto per il personale nel sistema di contabilità interno (ERP). Nel primo caso, è preferibile mostrare il "prodotto in evidenza", mentre nel secondo è sufficiente fornire una visione generale del prodotto. Tuttavia, il trasferimento di almeno un'immagine primaria del prodotto è piuttosto comune case durante l'importazione dei dati.

Quando si aggiunge un'immagine tramite il pannello di amministrazione, l'immagine viene prima salvata in una cartella temporanea (./pub/media/tmp/catalog/product) e solo al momento del salvataggio del prodotto viene spostata nella cartella multimediale (./pub/media/catalog/product). Inoltre, quando si aggiunge tramite il pannello di amministrazione, vengono applicati dei tag all'immagine. 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);

In qualche modo, i media si collegano solo dopo aver salvato preventivamente il prodotto e recuperandolo nuovamente dal repository. È necessario specificare l'attributo etichetta quando si aggiunge un record alla galleria media del prodotto (altrimenti otteniamo un'eccezione Indice non definito: label in .../module-catalog/Model/Product/Gallery/CreateHandler.php alla riga 516).

Categorie

Spesso la struttura delle categorie del negozio e quella dell'applicazione backend o la loro disposizione possono differire notevolmente. Le strategie per il trasferimento dei dati riguardanti le categorie e i relativi prodotti dipendono da numerosi fattori. In questo esempio seguirò la seguente strategia:

  • le categorie del backend e del negozio sono mappate per nome;
  • se viene importata una categoria che non esiste nel negozio, verrà creata sotto la categoria radice (Default Category) e il suo successivo posizionamento nel catalogo del negozio dovrà essere fatto manualmente;
  • l'associazione del prodotto alla categoria avviene solo al momento della sua creazione nel negozio (primo import);

Le informazioni principali sulla categoria si trovano nella tabella catalog_category_entity (catalogo delle categorie). Creazione di una categoria in Magento:

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

L'associazione del prodotto alla categoria avviene tramite l'ID della categoria e il SKU del prodotto:

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

Totale

Scrivere il codice per aggiungere un prodotto in Magento 2 in modo programmato è piuttosto semplice. Ho riassunto tutto quanto sopra in un modulo demo «flancer32/mage2_ext_demo_import«. Il modulo ha solo un comando da console fl32:import:prod, che importa i prodotti descritti nel file JSON «./etc/data/products.json«:

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

Le immagini per l'importazione si trovano nella directory ./etc/data/img.

Il tempo necessario per importare 10 prodotti in questo modo è di circa 10 secondi sul mio laptop. Se approfondiamo questo concetto, si può facilmente concludere che in un'ora si possono importare circa 3600 prodotti, mentre l'importazione di 100K prodotti potrebbe richiedere circa 30 ore. Sostituendo il laptop con un server la situazione può migliorare notevolmente. Forse anche di diverse volte. Ma non in modo esponenziale. Questa lentezza potrebbe essere in parte una delle ragioni dell'emergere del progetto magento/async-import.

Una soluzione radicale per aumentare la velocità di importazione potrebbe essere la scrittura diretta nel database, ma in questo caso si perdono tutti i vantaggi riguardanti l'espandibilità di Magento - sarà necessario fare tutto il resto da soli. Tuttavia, ne vale la pena. Se possibile, considererò l'approccio della scrittura diretta nel DB nel prossimo articolo.

Fonte: habr.com

Acquista un hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista un hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster