Magento 2: внос на продукти от външни източници

Magento е решение за електронна търговия, т.е. по-скоро е насочено към продажба на продукти, отколкото към свързаните с продажбите складови, логистични или финансови записи. За тези цели по-подходящи са други приложения (например, ERP системи). Затова често в практиката на работа с Magento възниква нужда от интегриране на магазина с тези други системи (например, с 1С).

По принцип интеграцията може да се сведе до репликиране на данни по:

  • каталога (продукти, категории);
  • инвентарни данни (остатъци от продукти на складовете и цени);
  • клиентите;
  • поръчките;

Magento предлага отделен клас обекти за манипулиране с данни в базата — репозитории. Поради спецификата на Magento, добавянето на данни в базата чрез репозиториите лесно се кодира, но става, да кажем, не толкова бързо. В тази публикация разглеждам основните етапи на програмното добавяне на продукт в Magento 2 по "класически" начин — с използване на репо класове.

Клиентите и поръчките обикновено се репликират в друга посока — от Magento към външни ERP системи. Така че с тях е по-просто, на страната на Magento е нужно просто да се изберат съответните данни, а след това — "от наша страна куршумите излетяха«.

Принципи на запис на данни в базата

Към момента, създаването на обекти, които се съхраняват в базата, по програмен начин в Magento се прави чрез Factory:

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

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

а записът в базата — чрез Repository:

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

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

Подходът с използване на "Factory" и "Repository" може да се приложи за всички основни модели в предметната област на Magento 2.

Основна информация за продукта

Разглеждам структурата на данните, съответстваща на версията Magento 2.3. Най-основната информация за продукта се намира в таблицата catalog_product_entity (регистър на продуктите):

entity_id
attribute_set_id
type_id
sku
has_options
required_options
created_at
updated_at

Ограничавам се до един тип продукт (type_id='simple'), набор атрибути по подразбиране (attribute_set_id=4) и игнорирам атрибутите has_options и required_options. Тъй като атрибутите entity_id, created_at и updated_at се генерират автоматично, то всъщност, за добавяне на нов продукт, ни е достатъчно да зададем sku. Правя така:

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

и получавам изключение:

Атрибутът "Product Name" е празен. Задайте стойност за атрибута и опитайте отново.

Добавям към заявката името на продукта и получавам съобщение, че липсва атрибут. Цена. След добавяне на цената, продуктът се записва в базата:

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

Името на продукта се записва в таблицата varchar-атрибути на продукта (catalog_product_entity_varchar), цената — в таблицата catalog_product_entity_decimal. Преди добавяне на продукта, е желателно явно да се уточни, че използваме административен интерфейс за импортиране на данни:

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

Допълнителни атрибути

Обработката на допълнителни атрибути на продуктите с помощта на Magento е истинско удоволствие. EAV-моделът на данни за основните сущности (виж таблицата eav_entity_type) е една от ключовите характеристики на тази платформа. Просто добавяме съответните атрибути към модела на продукта:

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

и при записването на модела чрез репо-обект:

$repoProd->save($prod);

допълнителните атрибути също ще бъдат записани в съответните таблици на базата данни.

Данни за инвентара

Просто казано — количеството на продукта на склад. В Magento 2.3 структурите в базата данни, описващи формата на съхранение на инвентарни данни, значително се различават от предишните версии. Въпреки това, добавянето на количество на продукта на склад чрез модела на продукта не е много по-сложно от добавянето на други атрибути:

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

Медия

Като правило, медийната придружаване на продукта за клиента в магазина (e-commerce) се различава от медийната придружаване на същия продукт за служителя в външната система за отчитане (ERP). В първия случай е желателно да се покаже 'товар лицом', а във втория — е достатъчно да се даде общо представяне на продукта. Въпреки това, прехвърлянето на поне първичното изображение на продукта е доста разпространено case при импортиране на данни.

При добавянето на изображение чрез административния панел, картинката първо се запазва в временно каталога (./pub/media/tmp/catalog/product) и само при запазването на продукта, се премества в медийната каталог (./pub/media/catalog/product). Освен това, при добавянето чрез административния панел, на изображението се задават етикети 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);

Причината е, че медията се свързва само след предварителното запазване на продукта и последващото му извличане от репозиторията. И е необходимо да се посочи атрибутът label при добавяне на записа в медийната галерия на продукта (иначе получаваме изключение. Неопределённый индекс: label в .../module-catalog/Model/Product/Gallery/CreateHandler.php на строке 516).

Категории

Често структура категориите на магазина и backend приложението или разположението им на продуктите може значително да се различават. Стратегиите за пренасяне на данни за категориите и продуктите в тях зависят от множество фактори. В този пример ще следвам следното:

  • категориите на backend и магазина се съпоставят по име;
  • ако се импортира категория, която не съществува в магазина, тя се създава под кореновата категория (Default Category) и нейното последващо позициониране в каталога на магазина се предполага ръчно;
  • привързването на продукта към категория се извършва само при неговото създаване в магазина (първия импорт);

Основната информация за категорията се намира в таблицата catalog_category_entity (каталог на категориите). Създаване на категория в Magento:

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

Привързването на продукта към категория се извършва по ID на категория и SKU на продукта:

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

Общо

Написването на код за добавяне на продукт в Magento 2 по програмен път е доста лесно. Всичко, изложено по-горе, събрах в демо модул «flancer32/mage2_ext_demo_import«. В модула има само една конзолна команда fl32:import:prod, която импортира продукти, описани в JSON файл «./etc/data/products.json«:

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

Снимките за импортиране се намират в каталога . /etc/data/img.

Времето за импорт на 10 продукта по този начин е около 10 секунди на моя лаптоп. Ако продължим с това, не е трудно да стигнем до извода, че за един час могат да се импортират около 3600 продукта, а за импорт на 100К продукта може да отнеме около 30 часа. Замяната на лаптопа с сервер позволява значително да се подобри ситуацията. Може би дори многократно. Но не в порядъци. Вероятно тази скорост е относително бавна и в известна степен е една от причините за появата на проекта magento/async-import.

Радикално решение за увеличаване на скоростта на вноса може да бъде директното записване в базата данни, но в този случай се губят всички "плюшки", свързани с разширяемостта на Magento — всичко "разширено" ще трябва да правите сами. Въпреки това, то си струва. Ако успея, ще разгледам подхода с директно записване в БД в следващата статия.

Източник: habr.com

Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри 🔥 Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри | ProHoster