Magento 2: Nhập sản phẩm từ nguồn bên ngoài

Magento là một giải pháp thương mại điện tử, tức là nhằm mục đích bán sản phẩm hơn là lưu kho, hậu cần hoặc kế toán tài chính đi kèm với việc bán hàng. Các ứng dụng khác (ví dụ: hệ thống ERP) phù hợp hơn với các ứng dụng đi kèm. Do đó, trong quá trình sử dụng Magento, nhiệm vụ tích hợp cửa hàng với các hệ thống khác này (ví dụ: 1C) thường phát sinh.

Nhìn chung, việc tích hợp có thể được giảm xuống thành sao chép dữ liệu bằng cách:

  • danh mục (sản phẩm, danh mục);
  • dữ liệu tồn kho (số dư sản phẩm trong kho và giá cả);
  • khách hàng;
  • mệnh lệnh;

Magento cung cấp một lớp đối tượng riêng để thao tác dữ liệu trong cơ sở dữ liệu - kho lưu trữ. Do đặc thù của Magento, việc thêm dữ liệu vào cơ sở dữ liệu thông qua kho lưu trữ rất dễ viết mã, nhưng có thể nói là chậm. Trong ấn phẩm này, tôi xem xét các giai đoạn chính của việc lập trình thêm sản phẩm vào Magento 2 theo cách “cổ điển” - sử dụng các lớp repo.

Khách hàng và đơn đặt hàng thường được sao chép theo hướng khác - từ Magento sang hệ thống ERP bên ngoài. Vì vậy, với họ thì đơn giản hơn, về phía Magento bạn chỉ cần chọn dữ liệu phù hợp rồi “đạn bay ra từ phía chúng tôi".

Nguyên tắc ghi dữ liệu vào cơ sở dữ liệu

Hiện tại, việc tạo các đối tượng lưu trong cơ sở dữ liệu theo chương trình trong Magento được thực hiện thông qua Nhà máy:

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

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

và việc ghi vào cơ sở dữ liệu được thực hiện thông qua Kho:

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

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

Cách tiếp cận "Nhà máy" và "Kho lưu trữ" có thể được sử dụng cho tất cả các mô hình chính trong miền Magento 2.

Thông tin cơ bản về sản phẩm

Tôi đang xem cấu trúc dữ liệu phù hợp với phiên bản Magento 2.3. Thông tin cơ bản nhất về sản phẩm có trong bảng catalog_product_entity (đăng ký sản phẩm):

entity_id
attribute_set_id
type_id
sku
has_options
required_options
created_at
updated_at

Tôi bị giới hạn ở một loại sản phẩm (type_id='simple'), một tập hợp các thuộc tính mặc định (attribute_set_id=4) và bỏ qua các thuộc tính has_options и required_options. Vì các thuộc tính entity_id, created_at и updated_at được tạo tự động, trên thực tế, để thêm một sản phẩm mới, chúng ta chỉ cần đặt sku. Tôi làm việc này:

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

và tôi nhận được một ngoại lệ:

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

Tôi thêm tên sản phẩm vào yêu cầu và nhận được thông báo rằng thuộc tính bị thiếu Price. Sau khi thêm giá, sản phẩm sẽ được thêm vào cơ sở dữ liệu:

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

Tên sản phẩm được lưu trữ trong bảng thuộc tính varchar của sản phẩm (catalog_product_entity_varchar), giá - trong bảng catalog_product_entity_decimal. Trước khi thêm sản phẩm, bạn nên chỉ rõ rõ ràng rằng chúng tôi đang sử dụng mặt tiền cửa hàng quản trị để nhập dữ liệu:

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

Thuộc tính bổ sung

Việc xử lý các thuộc tính sản phẩm bổ sung bằng Magento là một điều thú vị. Mô hình dữ liệu EAV cho các thực thể chính (xem bảng eav_entity_type) là một trong những tính năng chính của nền tảng này. Chúng tôi chỉ cần thêm các thuộc tính thích hợp vào mô hình sản phẩm:

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

và khi lưu mô hình thông qua đối tượng repo:

$repoProd->save($prod);

các thuộc tính bổ sung cũng sẽ được lưu trữ trong các bảng cơ sở dữ liệu tương ứng.

Dữ liệu tồn kho

Nói một cách đơn giản - số lượng sản phẩm trong kho. Trong Magento 2.3, các cấu trúc trong cơ sở dữ liệu mô tả định dạng lưu trữ dữ liệu hàng tồn kho là khác nhau đáng kể từ những gì đã xảy ra trước đó. Tuy nhiên, việc thêm số lượng sản phẩm trong kho thông qua mô hình sản phẩm không khó hơn nhiều so với việc thêm các thuộc tính khác:

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

Phương tiện truyền thông

Theo quy định, hỗ trợ truyền thông cho một sản phẩm cho khách hàng trong cửa hàng (thương mại điện tử) khác với hỗ trợ truyền thông cho cùng một sản phẩm cho nhân viên trong hệ thống kế toán nội bộ (ERP). Trong trường hợp đầu tiên, nên trưng bày trực tiếp sản phẩm, trong trường hợp thứ hai, chỉ cần đưa ra ý tưởng chung về sản phẩm là đủ. Tuy nhiên, việc chuyển ít nhất hình ảnh chính của sản phẩm là khá phổ biến. case khi nhập dữ liệu.

Khi thêm hình ảnh thông qua bảng quản trị, hình ảnh đầu tiên sẽ được lưu vào thư mục tạm thời (./pub/media/tmp/catalog/product) và chỉ khi lưu sản phẩm mới được chuyển vào thư mục media (./pub/media/catalog/product). Ngoài ra, khi được thêm qua bảng quản trị, hình ảnh sẽ được gắn thẻ 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);

Vì lý do nào đó, phương tiện chỉ được liên kết sau lần lưu sản phẩm đầu tiên và truy xuất lại từ kho lưu trữ. Và bạn cần chỉ định thuộc tính label khi thêm mục nhập vào thư viện phương tiện sản phẩm (nếu không chúng tôi sẽ có một ngoại lệ Undefined index: label in .../module-catalog/Model/Product/Gallery/CreateHandler.php on line 516).

Thể loại

Thông thường, cấu trúc danh mục của cửa hàng và ứng dụng phụ trợ hoặc vị trí đặt sản phẩm trong đó có thể khác nhau đáng kể. Các chiến lược di chuyển dữ liệu về danh mục và sản phẩm trong đó phụ thuộc vào nhiều yếu tố. Trong ví dụ này tôi tuân theo những điều sau:

  • danh mục phụ trợ và cửa hàng được so sánh theo tên;
  • nếu một danh mục được nhập nhưng không có trong cửa hàng thì nó sẽ được tạo trong danh mục gốc (Default Category) và vị trí tiếp theo của nó trong danh mục cửa hàng được giả định theo cách thủ công;
  • một sản phẩm chỉ được gán cho một danh mục khi nó được tạo trong cửa hàng (lần nhập đầu tiên);

Thông tin cơ bản về danh mục có trong bảng catalog_category_entity (danh mục các danh mục). Tạo một danh mục trong Magento:

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

Việc liên kết sản phẩm với danh mục được thực hiện bằng ID danh mục và SKU sản phẩm:

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

trong tổng số

Viết mã để thêm sản phẩm theo chương trình vào Magento 2 khá dễ dàng. Tôi đã kết hợp mọi thứ nêu trên vào một mô-đun demo “flacer32/mage2_ext_demo_import". Chỉ có một lệnh console trong mô-đun fl32:import:prod, nhập các sản phẩm được mô tả trong tệp JSON "./etc/data/products.json":

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

Hình ảnh nhập khẩu có trong catalog ./etc/data/img.

Thời gian nhập 10 sản phẩm bằng phương pháp này trên máy tính xách tay của tôi là khoảng 10 giây. Nếu chúng ta phát triển ý tưởng này hơn nữa, chúng ta dễ dàng đi đến kết luận rằng có thể nhập khoảng 3600 sản phẩm mỗi giờ và có thể mất khoảng 100 giờ để nhập 30 nghìn sản phẩm. Việc thay thế máy tính xách tay bằng máy chủ cho phép bạn giải quyết phần nào tình hình. Thậm chí có thể vài lần. Nhưng không phải theo thứ tự độ lớn. Có lẽ tốc độ và sự chậm chạp này ở một mức độ nào đó là một trong những lý do dẫn đến sự xuất hiện của dự án magento/async-nhập.

Một giải pháp triệt để để tăng tốc độ nhập có thể là truy cập trực tiếp vào cơ sở dữ liệu, nhưng trong trường hợp này, tất cả những “điều tốt đẹp” liên quan đến khả năng mở rộng của Magento đều bị mất - bạn sẽ phải tự mình làm mọi thứ “nâng cao”. Tuy nhiên, nó đáng giá. Nếu thành công, tôi sẽ xem xét phương pháp ghi trực tiếp vào cơ sở dữ liệu trong bài viết tiếp theo.

Nguồn: www.habr.com

Thêm một lời nhận xét