Magento 2: Importowanie produktów ze źródeł zewnętrznych

Magento to rozwiązanie e-commerce, tj. jest nastawiona bardziej na sprzedaż produktów niż towarzyszącą sprzedaży magazynowanie, logistykę czy księgowość finansową. Inne aplikacje (na przykład systemy ERP) lepiej nadają się do zastosowań towarzyszących. Dlatego dość często w praktyce korzystania z Magento pojawia się zadanie integracji sklepu z tymi innymi systemami (na przykład 1C).

Ogólnie rzecz biorąc, integrację można sprowadzić do replikacji danych poprzez:

  • katalog (produkty, kategorie);
  • dane o stanach magazynowych (salda produktów w magazynach i ceny);
  • klienci;
  • Zamówienia;

Magento oferuje osobną klasę obiektów służących do manipulacji danymi w bazie danych - repozytoria. Ze względu na specyfikę Magento, dodawanie danych do bazy danych poprzez repozytoria jest łatwe do zakodowania, ale jest, powiedzmy, powolne. W tej publikacji omawiam główne etapy programowego dodawania produktu do Magento 2 w „klasyczny” sposób – z wykorzystaniem klas repo.

Klienci i zamówienia replikowane są zazwyczaj w drugą stronę – z Magento do zewnętrznych systemów ERP. Dlatego z nimi jest prościej, po stronie Magento wystarczy wybrać odpowiednie dane, a następnie „kule leciały z naszej strony".

Zasady zapisu danych do bazy danych

Na chwilę obecną tworzenie obiektów zapisanych w bazie danych programowo w Magento odbywa się poprzez Fabryka:

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

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

i zapis do bazy danych odbywa się poprzez Magazyn:

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

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

Podejście „Fabryka” i „Repozytorium” można zastosować w przypadku wszystkich głównych modeli w domenie Magento 2.

Podstawowe informacje o produkcie

Patrzę na strukturę danych pasującą do wersji Magento 2.3. Najbardziej podstawowe informacje o produkcie znajdują się w tabeli catalog_product_entity (rejestr produktów):

entity_id
attribute_set_id
type_id
sku
has_options
required_options
created_at
updated_at

Ograniczam się do jednego rodzaju produktu (type_id='simple'), zestaw atrybutów domyślnych (attribute_set_id=4) i zignoruj ​​atrybuty has_options и required_options. Ponieważ atrybuty entity_id, created_at и updated_at generowane są automatycznie, wówczas tak naprawdę, aby dodać nowy produkt, wystarczy je ustawić sku. Robię to:

/** @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 otrzymuję wyjątek:

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

Dodaję nazwę produktu do zapytania i otrzymuję komunikat, że brakuje atrybutu Price. Po dodaniu ceny produkt zostaje dodany do bazy:

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

Nazwa produktu jest przechowywana w tabeli atrybutów varchar produktu (catalog_product_entity_varchar), cena - w tabeli catalog_product_entity_decimal. Przed dodaniem produktu warto wyraźnie wskazać, że do importu danych wykorzystujemy stronę administracyjną sklepu:

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

Dodatkowe atrybuty

Obróbka dodatkowych atrybutów produktu za pomocą Magento to przyjemność. Model danych EAV dla głównych podmiotów (patrz tabela eav_entity_type) to jedna z kluczowych cech tej platformy. Po prostu dodajemy odpowiednie atrybuty do modelu produktu:

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

i podczas zapisywania modelu poprzez obiekt repo:

$repoProd->save($prod);

dodatkowe atrybuty będą również przechowywane w odpowiednich tabelach bazy danych.

Dane inwentarza

W uproszczeniu - ilość produktu w magazynie. W Magento 2.3 struktury w bazie danych opisujące format przechowywania danych inwentaryzacyjnych to znacząco różne od tego, co wydarzyło się wcześniej. Jednak dodanie ilości produktu w magazynie poprzez model produktu nie jest dużo trudniejsze niż dodanie innych atrybutów:

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

Media

Z reguły obsługa medialna produktu dla klienta w sklepie (e-commerce) różni się od obsługi medialnej tego samego produktu dla pracownika w wewnętrznym systemie księgowym (ERP). W pierwszym przypadku wskazane jest pokazanie produktu twarzą w twarz, w drugim wystarczy ogólne wyobrażenie o produkcie. Jednak przenoszenie przynajmniej pierwotnego wizerunku produktu jest dość powszechne. case podczas importowania danych.

Podczas dodawania obrazu poprzez panel administracyjny, obraz jest najpierw zapisywany w katalogu tymczasowym (./pub/media/tmp/catalog/product) i dopiero przy zapisie produkt zostaje przeniesiony do katalogu multimediów (./pub/media/catalog/product). Ponadto, po dodaniu poprzez panel administracyjny, obraz zostaje oznaczony 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);

Z jakiegoś powodu media są łączone dopiero po pierwszym zapisaniu produktu i ponownym pobraniu go z repozytorium. I musisz określić atrybut label podczas dodawania wpisu do galerii multimediów produktu (w przeciwnym razie otrzymamy wyjątek Undefined index: label in .../module-catalog/Model/Product/Gallery/CreateHandler.php on line 516).

Kategorie

Często struktura kategorii sklepu oraz aplikacja backendowa czy rozmieszczenie w nich produktów może znacząco się od siebie różnić. Strategie migracji danych o kategoriach i znajdujących się w nich produktach zależą od wielu czynników. W tym przykładzie trzymam się następujących zasad:

  • kategorie backendu i sklepu są porównywane według nazwy;
  • jeśli zaimportowana zostanie kategoria, której nie ma w sklepie, to zostanie ona utworzona pod kategorią główną (Default Category) i dalsze jego pozycjonowanie w katalogu sklepu zakłada się ręcznie;
  • przypisanie produktu do kategorii następuje dopiero w momencie jego utworzenia w sklepie (pierwszy import);

Podstawowe informacje o kategorii znajdują się w tabeli catalog_category_entity (katalog kategorii). Tworzenie kategorii w Magento:

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

Powiązanie produktu z kategorią odbywa się za pomocą identyfikatora kategorii oraz SKU produktu:

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

Razem

Napisanie kodu umożliwiającego programowe dodanie produktu do Magento 2 jest dość łatwe. Połączyłem wszystko, co podano powyżej, w moduł demonstracyjny „flacer32/mage2_ext_demo_import„. W module znajduje się tylko jedno polecenie konsoli fl32:import:prod, który importuje produkty opisane w pliku JSON”./etc/data/products.json":

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

Zdjęcia do importu znajdują się w katalogu ./etc/data/img.

Czas zaimportowania 10 produktów tą metodą na moim laptopie to około 10 sekund. Jeśli rozwiniemy tę myśl dalej, łatwo dojść do wniosku, że na godzinę można zaimportować około 3600 produktów, a zaimportowanie 100 tys. produktów może zająć około 30 godzin. Wymiana laptopa na serwer pozwala nieco załagodzić sytuację. Może nawet kilka razy. Ale nie o rzędy wielkości. Być może ta szybkość i powolność jest w pewnym stopniu jedną z przyczyn powstania projektu magento/async-import.

Radykalnym rozwiązaniem na zwiększenie szybkości importu mógłby być bezpośredni wpis do bazy danych, ale w tym przypadku wszystkie „bajery” dotyczące rozszerzalności Magento przepadają – wszystko będziesz musiał zrobić „zaawansowane” sam. Jednak warto. Jeśli się sprawdzi, podejście z bezpośrednim zapisem do bazy rozważę w kolejnym artykule.

Źródło: www.habr.com

Dodaj komentarz