Magento 2: importul produselor din surse externe

Magento este o soluție de e-commerce, adică este mai mult concentrată pe vânzarea de produse decât pe gestionarea secundară a stocurilor, a logisticii sau a contabilității financiare. Pentru aceste procese secundare, sunt mai potrivite alte aplicații (de exemplu, sistemele ERP). Prin urmare, destul de des în practicile de utilizare a Magento apare necesitatea de a integra magazinul cu aceste alte sisteme (de exemplu, cu 1C).

În esență, integrarea poate fi redusă la replicarea datelor pe:

  • catalog (produse, categorii);
  • datele de inventar (stocurile de produse și prețurile);
  • clienți;
  • comenzi;

Magento oferă un tip de obiecte separate pentru manipularea datelor în baza de date — repository. Din cauza specificităților Magento, adăugarea de date în baza de date prin intermediul repository-urilor este ușor de codificat, dar se desfășoară, să spunem, nu foarte rapid. În această publicație, voi analiza etapele de bază pentru adăugarea programatică a unui produs în Magento 2 în „mod clasic” — utilizând clasele repo.

Clienții și comenzile sunt repli care, de obicei, în altă direcție — din Magento către sistemele ERP externe. Prin urmare, cu acestea este mai simplu, pe partea Magento trebuie doar să selectezi datele corespunzătoare, iar mai departe — „din partea noastră, gloanțele au ieșit«.

Principiile de scriere a datelor în baza de date

În prezent, crearea obiectelor care sunt salvate în baza de date din program se face prin Factory:

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

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

iar scrierea în baza — prin Repository:

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

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

Abordarea bazată pe „Factory” și „Repository” poate fi utilizată pentru toate modelele principale din domeniul Magento 2.

Informații de bază despre produs

Analizez structura de date corespunzătoare versiunii Magento 2.3. Cele mai esențiale informații despre produs se află în tabelul catalog_product_entity (registrul produselor):

entity_id
attribute_set_id
type_id
sku
has_options
required_options
created_at
updated_at

Mă limitez la un singur tip de produs (type_id='simple'), setul de atribute prestabilit (attribute_set_id=4) și ignor atributul has_options și required_options. Deoarece atributele entity_id, created_at și updated_at sunt generate automat, atunci, practic, pentru a adăuga un nou produs, este suficient să specificăm sku. Proced astfel:

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

și primesc o excepție:

Valoarea atributului "Numele produsului" este goală. Setați atributul și încercați din nou.

Adaug numele produsului în cerere și primesc un mesaj că lipsește un atribut Preț. După adăugarea prețului, produsul este salvat în baza de date:

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

Numele produsului este salvat în tabelul atributelor de tip varchar (catalog_product_entity_varchar), prețul – în tabelul catalog_product_entity_decimal. Înainte de a adăuga produsul, este de dorit să specificăm în mod explicit că folosim interfața de administrare pentru importul datelor:

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

Atribute suplimentare

Gestionarea atributelor suplimentare ale produselor prin intermediul Magento este o plăcere. Modelul de date EAV pentru entitățile fundamentale (vezi tabelul eav_entity_type) este una dintre caracteristicile cheie ale acestei platforme. Adăugăm pur și simplu atributele corespunzătoare modelului de produs:

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

și la salvarea modelului prin obiectul repo:

$repoProd->save($prod);

atributele suplimentare vor fi, de asemenea, salvate în tabelele corespunzătoare din baza de date.

Datele de inventar

Simplu spus — cantitatea de produs pe stoc. În Magento 2.3 structurile din baza de date care descriu formatul de stocare a datelor de inventar, diferă semnificativ de cele anterioare. Cu toate acestea, adăugarea cantității de produs pe stoc prin modelul de produs nu este cu mult mai complicată decât adăugarea altor atribute:

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

Media

În general, însoțirea media a produsului pentru client în magazin (e-commerce) diferă de însoțirea media a aceluiași produs pentru angajatul din sistemul intern de contabilitate (ERP). În primul caz, este de dorit să arătăm "produsul față în față", în al doilea — este suficient să oferim o imagine generală a produsului. Cu toate acestea, transferul măcar a primei imagini a produsului este destul de comun caz la importul datelor.

Atunci când se adaugă o imagine prin intermediul adminului, imaginea este mai întâi salvată în catalogul temporar (./pub/media/tmp/catalog/product) și numai la salvarea produsului este mutată în catalogul media (./pub/media/catalog/product). De asemenea, la adăugarea prin admin, imaginii i se adaugă etichete imagine, 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);

De parcă media este legată doar după salvarea preliminară a produsului și obținerea acestuia din nou din repo. Și trebuie să specifici atributul label atunci când se adaugă o înregistrare în galeria media a produsului (altfel se primește o excepție Index nedefinit: label in .../module-catalog/Model/Product/Gallery/CreateHandler.php pe linia 516).

Categorii

Structura categoriilor magazinului și a aplicației backend sau plasarea produselor în acestea poate varia semnificativ. Strategiile pentru transferul datelor despre categorii și produsele din acestea depind de numeroși factori. În acest exemplu, urmez următoarea strategie:

  • categoriile backend-ului și ale magazinului se potrivesc după nume;
  • dacă se importă o categorie care nu există în magazin, aceasta va fi creată sub categoria rădăcină (Categoria implicită) și poziționarea acesteia în catalogul magazinului va fi efectuată manual;
  • asocierea produsului cu categoria se face doar la crearea acestuia în magazin (la primul import);

Informațiile principale despre categorie se află în tabela catalog_category_entity (catalogul categoriilor). Crearea unei categorii în Magento:

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

Asocierea produsului cu categoria se face după ID-ul categoriei și SKU-ul produsului:

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

În concluzie

Scrierea codului pentru a adăuga un produs în Magento 2 programatic este destul de simplă. Tot ceea ce am expus mai sus am strâns într-un modul demo „flancer32/mage2_ext_demo_import„. Modulul are o singură comandă de consolă fl32:import:prod, care importă produsele descrise în fișierul JSON „./etc/data/products.json«:

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

Imaginile pentru import se află în directorul ./etc/data/img.

Timpul necesar pentru a importa 10 produse în acest mod este de aproximativ 10 secunde pe laptopul meu. Dacă dezvolt această idee mai departe, ajung ușor la concluzia că într-o oră se pot importa aproximativ 3600 de produse, iar importul a 100K de produse ar putea dura aproximativ 30 de ore. Înlocuirea laptopului cu un server poate atenua ceva situația. Poate chiar de mai multe ori. Dar nu cu ordine. Poate această viteză mai scăzută este, în oarecare măsură, una dintre cauzele apariției proiectului magento/async-import.

O soluție radicală pentru a crește viteza de import ar putea fi scrierea directă în bază de date, dar în acest caz se pierd toate „avantajele” legate de extensibilitatea Magento — va trebui să fac tot „extensibil” singur. Cu toate acestea, merită. Dacă se poate, voi analiza abordarea scrierii directe în BD în următorul articol.

Sursa: habr.com

Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS 🔥 Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS | ProHoster