Magento 2: importando produtos de fontes externas

Magento é uma solução de comércio eletrônico, ou seja, mais focado na venda de produtos do que nas vendas associadas de armazém, logística ou contabilidade financeira. Outras aplicações (como sistemas ERP) são mais adequadas para acompanhantes. Portanto, muitas vezes na prática de usar o Magento, surge a tarefa de integrar uma loja com esses outros sistemas (por exemplo, com 1C).


Em geral, a integração pode ser reduzida à replicação de dados por:


  • catálogo (produtos, categorias);
  • dados de inventário (estoques de produtos em armazéns e preços);
  • para clientes;
  • pedidos;

O Magento para manipular dados no banco de dados oferece uma classe separada de objetos - repositórios . Devido às especificidades do Magento, adicionar dados ao banco de dados através de repositórios é fácil de codificar, mas acontece, digamos, não rapidamente. Nesta publicação, considero os principais estágios da adição programática de um produto ao Magento 2 de maneira "clássica" - usando classes de repo.


Clientes e pedidos geralmente são replicados para o outro lado - do Magento aos sistemas externos de ERP. Portanto, é mais fácil para eles, no lado do Magento, você só precisa selecionar os dados apropriados e, em seguida, " as balas dispararam do nosso lado ".


Princípios de gravação de dados no banco de dados


No momento, a criação de objetos armazenados no banco de dados programaticamente no Magento é feita através do Factory :


function __construct (\Magento\Cms\Model\BlockFactory $blockFactory) { $this->blockFactory = $blockFactory; } /** @var \Magento\Cms\Model\Block $block */ $block = $this->blockFactory->create(); 

e gravando no banco de dados através do Repositório :


 function __construct (\Magento\Cms\Api\BlockRepositoryInterface $blockRepo) { $this->blockRepo = $blockRepo; } $this->blockRepo->save($block); 

A abordagem Factory e Repository pode ser usada para todos os principais modelos na área de assunto do Magento 2.


Informações Básicas do Produto


Estou pensando em uma estrutura de dados correspondente ao Magento 2.3. As informações mais básicas do produto estão na tabela catalog_product_entity (registro do produto):


 entity_id attribute_set_id type_id sku has_options required_options created_at updated_at 

type_id='simple' um tipo de produto ( type_id='simple' ), um conjunto de attribute_set_id=4 padrão ( attribute_set_id=4 ) e ignoro os atributos has_options e required_options . Como os atributos entity_id , created_at e updated_at são gerados automaticamente, então, em essência, precisamos especificar o sku para adicionar um novo produto. Eu faço isso:


 /** @var \Magento\Catalog\Api\Data\ProductInterfaceFactory $factProd */ /** @var \Magento\Catalog\Api\ProductRepositoryInterface $repoProd */ /** @var \Magento\Catalog\Api\Data\ProductInterface $prod */ $prod = $factProd->create(); $prod->setAttributeSetId(4); $prod->setTypeId('simple'); $prod->setSku($sku); $repoProd->save($prod); 

e obtenha uma exceção:


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

Eu adiciono o nome do produto à solicitação e recebo uma mensagem informando que o atributo Price está ausente. Após adicionar o preço, o produto cai no banco de dados:


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

O nome do produto é armazenado na tabela de atributos varchar do produto ( catalog_product_entity_varchar ), o preço é armazenado na tabela catalog_product_entity_decimal . Antes de adicionar um produto, é aconselhável indicar explicitamente que estamos usando uma loja administrativa para importar dados:


 /** @var \Magento\Store\Model\StoreManagerInterface $manStore */ $manStore->setCurrentStore(0); 

Atributos adicionais


Processar atributos adicionais do produto com o Magento é um prazer. O modelo de dados EAV para entidades principais (consulte a tabela eav_entity_type ) é um dos principais recursos desta plataforma. Basta adicionar os atributos apropriados ao modelo do produto:


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

e ao salvar o modelo através do objeto repo:


 $repoProd->save($prod); 

atributos adicionais também serão armazenados nas tabelas correspondentes do banco de dados.


Dados de inventário


De uma maneira simples - a quantidade de produto em estoque. No Magento 2.3, as estruturas de banco de dados que descrevem o formato para armazenar dados de inventário são significativamente diferentes do que eram antes. No entanto, adicionar quantidades de produtos em estoque através de um modelo de produto não é muito mais difícil do que adicionar outros atributos:


 /** @var \Magento\Catalog\Model\Product $prodEntity */ /** @var \Magento\Catalog\Api\ProductRepositoryInterface $repoProd */ $inventory = [ 'is_in_stock' => true, 'qty' => 1234 ]; $prodEntity->setData('quantity_and_stock_status', $inventory); $repoProd->save($prodEntity); 

Mídia


Como regra, o suporte de mídia para um produto para um cliente em uma loja (comércio eletrônico) é diferente do suporte de mídia para o mesmo produto para um funcionário no sistema de contabilidade interno (ERP). No primeiro caso, é desejável mostrar a "face do produto", no segundo - basta dar uma idéia geral do produto. No entanto, a transferência de pelo menos a imagem principal do produto é um case bastante comum na importação de dados.


Ao adicionar uma imagem no painel do administrador, a imagem é salva primeiro no diretório temporário ( ./pub/media/tmp/catalog/product ) e somente quando o produto é salvo é movida para o diretório de mídia ( ./pub/media/catalog/product ). Além disso, ao adicionar através do small_image do administrador, a imagem é configurada para as swatch_image image , image small_image , thumbnail , imagem de swatch_image .


 /** @var \Magento\Catalog\Api\ProductRepositoryInterface $repoProd */ /** @var \Magento\Catalog\Model\Product\Gallery\CreateHandler $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); 

Por alguma razão, a mídia é amarrada somente após salvar preliminarmente o produto e recebê-lo do repositório novamente. E você precisa especificar o atributo label ao adicionar uma entrada à galeria de mídia do produto (caso contrário, obteremos a exceção Undefined index: label in .../module-catalog/Model/Product/Gallery/CreateHandler.php on line 516 ).


Categorias


Geralmente, a estrutura das categorias de lojas e aplicativos de back-end ou a colocação de produtos nelas podem variar significativamente. As estratégias para transferir dados sobre categorias e produtos nelas dependem de muitos fatores. Neste exemplo, continuo com o seguinte:


  • categorias de back-end e loja são comparadas por nome;
  • se uma categoria é importada e não está na loja, ela é criada na categoria raiz ( Default Category ) e seu posicionamento adicional no catálogo da loja é assumido manualmente;
  • um produto é atribuído a uma categoria somente quando é criado em uma loja (primeira importação);

As informações básicas da categoria estão na tabela catalog_category_entity (catálogo da categoria). Criando uma categoria no Magento:


 /** @var \Magento\Catalog\Api\Data\CategoryInterfaceFactory $factCat */ /** @var \Magento\Catalog\Api\CategoryRepositoryInterface $repoCat */ $cat = $factCat->create(); $cat->setName($name); $cat->setIsActive(true); $repoCat->save($cat); 

O produto é atribuído a uma categoria por ID da categoria e SKU do produto:


 /** @var \Magento\Catalog\Model\CategoryProductLinkFactory $factCatProdLink */ /** @var \Magento\Catalog\Api\CategoryLinkRepositoryInterface $repoCatLink */ $link = $factCatProdLink->create(); $link->setCategoryId($catMageId); $link->setSku($prodSku); $repoCatLink->save($link); 

Total


Escrever código para adicionar um produto ao Magento 2 programaticamente é muito fácil. Todas as opções acima, reduzi o módulo de demonstração " flancer32 / mage2_ext_demo_import ". Há apenas um fl32:import:prod console no fl32:import:prod , que importa os produtos descritos no arquivo JSON " ./etc/data/products.json ":


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

As imagens para importação estão localizadas no diretório ./etc/data/img .


O tempo de importação de 10 produtos dessa maneira é de aproximadamente 10 segundos no meu laptop. Se continuarmos desenvolvendo essa idéia, é fácil concluir que cerca de 3.600 produtos podem ser importados por hora e cerca de 30 horas para a importação de 100 mil produtos. Substituir um laptop por um servidor permite suavizar a situação. Talvez até às vezes. Mas não por ordens de magnitude. Talvez isso velocidade a lentidão é, em certa medida, uma das razões para o surgimento do projeto magento / async-import .


Uma decisão fundamental para aumentar a velocidade de importação pode ser escrever diretamente no banco de dados, mas nesse caso todos os "pães" relacionados à extensibilidade do Magento são perdidos - você deve fazer tudo "avançado" por conta própria. No entanto, vale a pena. Se funcionar, considerarei a abordagem com gravação direta no banco de dados no próximo artigo.

Source: https://habr.com/ru/post/pt436020/


All Articles