Integração/atualização de estoque no Magento 2
Desenvolvimento, Magento 2
Publicado em 25 de setembro de 2018
A mais comum de todas as integrações pedidas por nossos clientes é a integração de estoque. Por isso, neste rápido tutorial mostrarei como fazer uma integração ativa de estoque, ou seja, onde o Magento fará a consulta a um webservice de terceiros e atualizará o estoque dos produtos da sua loja periodicamente usando tarefas agendadas (cron).
Conhecendo a Interface de estoque
A classe ou interface responsável por lidar com o inventário de nossa loja é a \Magento\CatalogInventory\Api\StockRegistryInterface
. Sendo assim, é ela que vamos usar para obter e alterar informações de estoque dos produtos de nossa loja.
Criando nosso módulo de integração
1. Módulo base
Crie um módulo padrão Magento 2. Se não sabe como fazê-lo, veja este artigo, ou se inscreva no curso de Magento 2. ♥
2. Criando nossa classe para atualização de estoque
Nossa classe será colocada dentro do nosso módulo, em Cron/InventoryUpdate.php
e ela será responsável por atualizar o estoque de todos os nossos produtos da nossa loja Magento.
No nosso exemplo, ela conterá apenas 3 métodos, e já está preparada para resolver um problema comum de consumo de memória que veremos na sequência.
public function __construct( StockRegistryInterface $stockRegistry, Iterator $iterator, ProductCollectionFactory $productCollection, LoggerInterface $logger ) { $this->stockRegistry = $stockRegistry; $this->iterator = $iterator; $this->productCollection = $productCollection; $this->logger = $logger; } public function execute() { $productCollection = $this->productCollection->create(); $this->iterator ->walk($productCollection->getSelect(), [[$this,'updateItems']]); } public function updateItems($args) { $sku = $args['row']['sku']; $currentQty = $this->stockRegistry->getStockItemBySku($sku); //qtd atual no estoque (você pode pular a atualização caso a quantidade não tenha sido alterada) $stockItem = $this->stockRegistry->getStockItemBySku($sku); //@TODO Buscar quantidade na fonte da integração. $newQty = 123; $stockItem->setQty($newQty); //Nova quantidade $stockItem->setIsInStock(($newQty > 0)); //Em estoque? true ou false $this->logger->debug('Atualizando inventário...', ['sku' => $sku, 'qtd anterior' => $currentQty, 'novaQtd'=> $newQty]); $this->stockRegistry->updateStockItemBySku($sku, $stockItem); }
O método
updateItems
é responsável por atualizar cada produto de nossa loja e gravar no var/log/debug.log
qual a quantidade disponível antes e depois da atualização. Idealmente, podemos fazer a integração ficar ainda mais rápida se não atualizarmos os itens que não sofreram atualização. Para isto basta verificar se $currentQty
é igual a $newQty
e devolver void (return;
).
Para o log funcionar corretamente, nossa loja deve estar com os logs habilitados. Você pode habilitá-los com bin/magento config:set dev/debug/debug_logging 1
.
Importante notar que não devemos fazer a consulta ao sistema externo (erp, etc) a cada iteração no nosso script. Isso deve ser carregado antes, em outro lugar antes mesmo de entrarmos no nosso método updateItems
.
O grande problema: consumo de memória em grandes loops
Um dos maiores problemas que vejo em módulos de integração acontece ao tentar fazer um loop em todos os produtos do estoque do Magento. Seria algo como…
/** @var \Magento\Catalog\Model\ResourceModel\Product\Collection $productCollection */ foreach ($productCollection->toArray() as $item) { ... }
Para uma loja com poucos produtos, não teremos muitos problemas. No entanto se a loja tiver algumas dezenas de milhares de produtos, isso logo causará alguma dor de cabeça no consumo de memória.
Esse problema pode ser facilmente contornado com o Iterator nativo do Magento 2, o Magento\Framework\Model\ResourceModel\Iterator
. Com ele, podemos alterar a forma como o PHP fará o loop em nossos produtos. O código fica um pouco mais chato e complexo (por isso quase ninguém usa), mas o resultado é ótimo para esse tipo de situação.
Com ele, nós chamamos um outro método para interagir com cada linha do nosso loop. Ficaria assim:
$this->iterator ->walk($productCollection->getSelect(), [[$this,'updateItems']]);
E na mesma classe, criamos um método chamado
updateItems
.public function updateItems($args) { $sku = $args['row']['sku']; $currentQty = $this->stockRegistry->getStockItemBySku($sku); //qtd atual no estoque (você pode pular a atualização caso a quantidade não tenha sido alterada) $stockItem = $this->stockRegistry->getStockItemBySku($sku); $stockItem->setQty(123); //Nova quantidade $stockItem->setIsInStock(true); //Em estoque? $this->stockRegistry->updateStockItemBySku($sku, $stockItem); }
Resultado: em um Magento 2 simples, com sample data (12 mil produtos), ao criar um console command que simplesmente exibe os sku’s de todos os produtos, o Iterator se mostra cerca de 16% mais eficiente no consumo de memória. Em operações mais complexas, envolvendo atualização de estoque e outras inteligências, usar o Iterator pode ser o que vai dizer se sua integração vai falhar por exceder o limite de memória, ou não.
Você poderá encontrar o comparativo de performance com o comando bin/magento magenteiro:inventoryTest
e bin/magento magenteiro:inventoryTestBetter
no módulo desta aula.
3. Criando a tarefa agendada no Magento 2
Como queremos que nosso cron seja disparado de tempos em tempos, vamos criar o agendador de tarefas no Magento 2. Para isso, crie um arquivo em etc/crontab.xml
do nosso módulo.
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Cron:etc/crontab.xsd"> <group id="default"> <job name="magenteiro_inventory_integration" instance="Magenteiro\InventoryIntegration\Cron\InventoryUpdate" method="execute"> <!-- Altere isso a gosto. http://crontab-generator.org/ --> <schedule>* * * * *</schedule> <!-- exemplos: Todo minuto <schedule>* * * * *</schedule> Todo dia ao meio dia e a meia noite <schedule>0 0,12 * * *</schedule> De 6 em 6 horas <schedule>0 */6 * * *</schedule> --> </job> </group> </config>
Com isso, nosso cron de estoque será executado a todo minuto, atualizando nosso estoque.
4. Testando nosso script do cron (sem um cron)
Para testar se nosso cron está funcionando, usarei o n98-magerun2 e o comando abaixo:
n98-magerun2 sys:cron:list | grep magenteiro
Com este comando poderemos listar todos os crons do magento e ver se o nosso
magenteiro_inventory_integration
está presente.
Para executar o nosso cron manualmente no Magento, usamos: n98-magerun2 sys:cron:run magenteiro_inventory_integration
.
Note que o caminho do seu n98 e o nome dele em seu sistema pode variar.
Conclusão: no ambiente local, levei cerca de 2 minutos para atualizar meus 12 mil produtos. 🙂
Download do módulo de integração e aula
A aula em vídeo sobre este assunto e o módulo inteiro para download está disponível no curso de Magento 2 do Magenteiro. Esta é uma aula bônus adicionada após o lançamento do curso.
- PagSeguro (PagBank) para Magento 1 recebe a Nova Geração - 9 de abril de 2024
- Recorrência no WooCommerce Sem Plugins Pagos - 28 de janeiro de 2024
- Chargeback. O que é, e como se livrar deles. - 19 de dezembro de 2023
Deixe seu comentário
[fbcomments url="https://www.magenteiro.com/blog/magento-2/integracao-atualizacao-de-estoque-no-magento-2/"]