Magento 2: Actualización de inventario mediante programación

12

En el siguiente código, puedo almacenar toda la información con la exclusión de los datos de stock. ¿Ha cambiado algo en Magento 2?

public function __construct(
    ScopeConfigInterface $scopeConfig, CollectionFactory $product,
    Magento\Catalog\Api\ProductRepositoryInterface $productRepository
) {
    $this->scopeConfig = $scopeConfig;
    $this->product = $product;
    $this->productRepository = $productRepository;
}

public function update(\XXXXXX\XXXXXX\Api\Data\InventoryCollectionInterface $data) {
    foreach ($data['list'] as $d) {
        $product = $this->productRepository->getById($d['entity_id']);
        $product->setStatus(($d['quantity'] > 0 ? 1 : 0));
        $product->setUpc($d['upc']);
        $product->setStockData(array(
            'qty' => $d['quantity'],
            'is_in_stock' => ($d['quantity'] > 0 ? 1 : 0)
        ));

        $this->productRepository->save($product);
    }

    return "Done";
}
Stephen Malenshek
fuente
1
Esto podría ayudar: github.com/magento/magento2/issues/5771
Mukesh Chapagain

Respuestas:

33

Esto funciona para mi:

$item = ['qty' => 11]; // For example
$product->setStockData(['qty' => $item['qty'], 'is_in_stock' => $item['qty'] > 0]);
$product->save();

Editar :

Esta ya no es la forma correcta de manejar esto, porque $product->save()está en desuso desde Magento 2.1. La forma correcta de hacer esto es mediante el uso de StockRegistryInterface:

/**
 * @var StockRegistryInterface
 */
protected $stockRegistry;

/**
 * Inventory constructor.
 * @param StockRegistryInterface $stockRegistry
 */
public function __construct(
    StockRegistryInterface $stockRegistry
)
{
    $this->stockRegistry = $stockRegistry;
    parent::__construct();
}

Con el código anterior, puede usar lo siguiente:

$sku = 'ABC123';
$qty = 10;
$stockItem = $this->stockRegistry->getStockItemBySku($sku);
$stockItem->setQty($qty);
$this->stockRegistry->updateStockItemBySku($sku, $stockItem);

Use los gerentes tanto como sea posible. Mantenga sus módulos desacoplados entre sí.

Es el camino de Magento ™

Giel Berkers
fuente
setStockData es lo que se requiere. No hay necesidad de llamar -> setQuantityAndStockStatuses, aunque parece no hacer daño.
Robert Egginton
99
Funciona muy bien para un producto. Sin embargo, cuando lee un archivo CSV con 5k SKU, el rendimiento es bastante malo. ¿Alguien tiene el mismo problema?
medina
+1 para actualizar su publicación a la versión 2.1 de magento.
ZFNerd
+1 para mejores prácticas (y actualización de respuesta)
Akif
Realmente aprecio el método actualizado! ¡Magento está mejorando para todos nosotros debido a que miembros de la comunidad como tú hacen publicaciones como esta! Así se hace
JustinP
16

Si está utilizando la solución @ giel-berkers, es posible que también deba configurar isInStock, ya que no se configurará automáticamente. Entonces, el siguiente código fue útil para mí:

public function __construct(
    \Magento\CatalogInventory\Api\StockRegistryInterface $stockRegistry
)
{
    $this->stockRegistry = $stockRegistry;
    parent::__construct();
}

public function yourMethod() {
    $sku = 'ABC123';
    $qty = 10;
    $stockItem = $this->stockRegistry->getStockItemBySku($sku);
    $stockItem->setQty($qty);
    $stockItem->setIsInStock((bool)$qty); // this line
    $this->stockRegistry->updateStockItemBySku($sku, $stockItem);
}
spiil
fuente
¿Cómo puedo usar esta respuesta para actualizar Qty Store Wise en Magento 2?
Mujahidh
@Mujahidh se puede tratar de pasar ScopeId como segundo parámetro al getStockItemBySku()método
spiil
1
gracias, qty se está actualizando, pero no es una tienda inteligente, ya que ambas tiendas actualizan la misma cantidad.
Mujahidh
8

Una cosa que las otras respuestas perdieron es que si usted setQty($qty)aplicará el valor exacto que proporcione. Pero si se realizó una venta para ese producto un momento antes de su ahorro, la cantidad original podría haber cambiado. Entonces, lo que realmente quiere hacer es decirle a Magento la diferencia que desea aplicar a la cantidad.

Afortunadamente, Magento 2 proporciona un buen mecanismo para esto. Echa un vistazo a Magento\CatalogInventory\Model\ResourceModel\Stock\Item:

protected function _prepareDataForTable(\Magento\Framework\DataObject $object, $table)
{
    $data = parent::_prepareDataForTable($object, $table);
    $ifNullSql = $this->getConnection()->getIfNullSql('qty');
    if (!$object->isObjectNew() && $object->getQtyCorrection()) {
        if ($object->getQty() === null) {
            $data['qty'] = null;
        } elseif ($object->getQtyCorrection() < 0) {
            $data['qty'] = new \Zend_Db_Expr($ifNullSql . '-' . abs($object->getQtyCorrection()));
        } else {
            $data['qty'] = new \Zend_Db_Expr($ifNullSql . '+' . $object->getQtyCorrection());
        }
    }
    return $data;
}

Aquí vemos que si establece el qty_correctionvalor, aplicará la diferencia de forma incremental en lugar de aplicar una cantidad exacta.

Entonces, mi sugerencia para un ahorro de cantidad más seguro es esta:

/**
 * @var \Magento\CatalogInventory\Api\StockRegistryInterface
 */
protected $stockRegistry;

public function __construct(StockRegistryInterface $stockRegistry)
{
    $this->stockRegistry = $stockRegistry;
}

/**
* Set the quantity in stock for a product
*
*/
public function applyNewQty($sku, $newQty)
{
    $stockItem = $this->stockRegistry->getStockItemBySku($sku);
    $origQty = $stockItem->getQty();
    $difference = $newQty - $origQty;
    $stockItem->setQtyCorrection($difference);
    $this->stockRegistry->updateStockItemBySku($sku, $stockItem);

    // note that at this point, $stockItem->getQty() is incorrect, so you'll need to reload if you need that value
}
cyk
fuente
7

Luché con este mismo problema. Durante la depuración descubrí que los datos del producto tienen una matriz cantidad_y_stock_estado, así que intenté configurarlo con:

$product->setQuantityAndStockStatus(['qty' => $quantity, 'is_in_stock' => 1]);

y comenzó a funcionar para mí Todavía estoy configurando $ product-> setStockData también si editas un producto e inspeccionas el elemento en los campos, verás que tiene ambos, uno está en la pestaña general y el otro en los campos de inventario avanzado. No he investigado completamente por qué hay 2 de ellos.

Kevin Chavez
fuente
tipo y simple, muy buena solución !!! funciona para mí +1
Manthan Dave
Solución preferida, ya que esto funciona y requiere mucho menos edición que las otras +1
leedch
Cuando el producto está desactivado, la cantidad no se actualiza; más en estado habilitado funciona correctamente. ¿Me pueden ayudar? Mi sitio está en 2.1.9
Anil
1

El siguiente código funciona bien para mí para actualizar la cantidad de productos,

public function __construct(
    \Magento\Catalog\Model\ProductFactory $productFactory
) {
    $this->productFactory = $productFactory;
}

public function updateQty(){
    $sku = '24-mb01';
    $product = $this->productFactory->create();
    $productId = $product->getIdBySku($sku);
    if($productId){
        $product->load($productId);
    }

    $product->setStockData(
        array(
            'use_config_manage_stock' => 0,
            'manage_stock' => 1,
            'is_in_stock' => 1,
            'qty' => 10
        )
    );

    try {
        $product->save(); 
        echo $sku.' updated. '; 
    } catch (Exception $e) {
        echo $e->getException();
    }
}
Rakesh Jesadiya
fuente
Cuando el estado del producto está desactivado, la cantidad no se actualiza en mi caso. ¿Me pueden ayudar a resolverlo?
Anil
1
$objectManager = $bootstrap->getObjectManager();
$stockRegistry = $objectManager->create('Magento\CatalogInventory\Api\StockRegistryInterface');

$stockItem = $stockRegistry->getStockItemBySku($sku);
$stockItem->setQty($qty);
$stockItem->setIsInStock((bool)$qty);
$stockRegistry->updateStockItemBySku($sku, $stockItem);
Desarrollador MHK
fuente
0

Intente configurar StoreId en $ product antes de todo, y tal vez reemplace:

$product->setStockData(...) para $product->setData('stock_data', '...') // A Paranoid Recommendation

Por cierto, si mira el Save ActionController en el backend, M2 usa un filtro para preparar stock_data, puede encontrar ese filtro en:

Magento \ Catálogo \ Controlador \ Adminhtml \ Producto \ Inicialización \ StockDataFilter

MauroNigrele
fuente
Agradezco la respuesta, pero esa opción no funcionó. Gracias por la ayuda.
Stephen Malenshek
0

Intente esto, al guardar el producto en admin, guardaron los datos de inventario mediante el evento catalog_product_save_after en el Magento_CatalogInventorymódulo observador

Magento \ CatalogInventory \ Observer \ SaveInventoryDataObserver

saravanavelu
fuente
0

Tuve el mismo problema para magento 2.0.9 y el siguiente código funciona en mi caso

$productStock = $this->_productRepository->getById($item->getMageproductId());
$productStock->setQuantityAndStockStatus(['qty' => 12, 'is_in_stock' => 1]);
$res = $productStock->save();
Nitin Pawar
fuente
0

Magento2 también viene con la función Multi stock, por lo que para actualizar una fuente de stock en particular puede seguir esta solución

https://magento.stackexchange.com/questions/272296/how-to-set-qty-to-product-on-msi-magento-2-3
Alam Zaib
fuente