Magento 2: mise à jour programmée de l'inventaire

12

Dans le code suivant, je suis en mesure de stocker toutes les informations à l'exclusion des données de stock. Quelque chose a-t-il changé dans 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
la source
1
Cela pourrait aider: github.com/magento/magento2/issues/5771
Mukesh Chapagain

Réponses:

33

Cela fonctionne pour moi:

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

Modifier :

Ce n'est plus la bonne façon de gérer cela, car il $product->save()est obsolète depuis Magento 2.1. La bonne façon de procéder consiste à utiliser StockRegistryInterface:

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

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

Avec le code ci-dessus, vous pouvez utiliser les éléments suivants:

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

Utilisez autant que possible les gestionnaires . Gardez vos modules découplés les uns des autres.

C'est The Magento Way ™

Giel Berkers
la source
setStockData est ce qui est requis. Il n'est pas nécessaire d'appeler -> setQuantityAndStockStatuses, bien que cela ne semble pas faire de mal.
Robert Egginton
9
Cela fonctionne très bien pour un produit. Cependant, lorsque vous lisez un fichier CSV avec des SKU 5k, les performances sont assez mauvaises. Quelqu'un a-t-il le même problème?
medina
+1 pour mettre à jour votre message vers la version magento 2.1.
ZFNerd
+1 pour les meilleures pratiques (et la mise à jour de la réponse)
Akif
Appréciez vraiment la méthode mise à jour! Magento s'améliore pour nous tous grâce aux membres de la communauté comme vous qui publiez des articles comme celui-ci! Way to go
JustinP
16

Si vous utilisez la solution @ giel-berkers, vous devrez peut-être également définir isInStock, car il ne sera pas défini automatiquement. Ainsi, le code suivant m'a été utile:

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
la source
comment puis-je utiliser cette réponse pour mettre à jour le magasin de quantité dans magento 2?
Mujahidh
@Mujahidh vous pouvez essayer de passer scopeId comme second paramètre à la getStockItemBySku()méthode
spiil
1
merci, la quantité est mise à jour mais pas en magasin, car les deux magasins mettent à jour la même quantité.
Mujahidh
8

Une chose que les autres réponses ont manqué, c'est que si vous setQty($qty), il appliquera la valeur exacte que vous fournissez. Mais si une vente avait été faite pour ce produit un moment avant votre sauvegarde, la quantité d'origine aurait pu changer. Donc, ce que vous voulez vraiment faire, c'est dire à Magento la différence que vous souhaitez appliquer à la quantité.

Heureusement, Magento 2 fournit un bon mécanisme pour cela. Jetez un œil à 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;
}

Ici, nous voyons que si vous définissez la qty_correctionvaleur, il appliquera la différence de manière incrémentielle au lieu d'appliquer un montant exact.

Donc, ma suggestion pour une sauvegarde de quantité plus sûre est la suivante:

/**
 * @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
la source
7

J'ai eu du mal avec ce même problème. Lors du débogage, j'ai constaté que les données du produit avaient un tableau quantity_and_stock_status, j'ai donc essayé de le définir avec:

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

et ça a commencé à marcher pour moi. Je suis toujours en train de définir $ product-> setStockData aussi si vous modifiez un produit et inspectez un élément sur les champs, vous verrez qu'il a les deux, l'un sur l'onglet général, l'autre sur les champs d'inventaire avancés. Je n'ai pas cherché à savoir pourquoi il y en a 2.

Kevin Chavez
la source
sorte et simple, très bonne solution !!! travaille pour moi +1
Manthan Dave
Solution préférée, car cela fonctionne et prend beaucoup moins de modifications que les autres +1
leedch
Lorsque le produit est désactivé, la quantité n'est pas mise à jour; sinon, le statut d'activation fonctionne correctement. Pouvez-vous m'aider pour cela. Mon site est en 2.1.9
Anil
1

Le code ci-dessous fonctionne bien pour moi pour mettre à jour la quantité de produit,

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
la source
Lorsque l'état du produit est désactivé, la quantité n'est pas mise à jour dans mon cas. Pouvez-vous m'aider à le résoudre.
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);
Développeur MHK
la source
0

Essayez de définir StoreId sur $ product avant tout, et remplacez peut-être:

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

BTW Si vous regardez Save ActionController sur le backend M2 utilise un filtre pour préparer stock_data, vous pouvez trouver ce filtre dans:

Magento \ Catalog \ Controller \ Adminhtml \ Product \ Initialization \ StockDataFilter

MauroNigrele
la source
J'apprécie la réponse, mais cette option n'a pas fonctionné. Merci pour l'aide.
Stephen Malenshek
0

Essayez ceci, tout en enregistrant le produit dans admin, ils ont enregistré les données d'inventaire en utilisant l'événement catalog_product_save_after dans le Magento_CatalogInventorymodule observer

Magento \ CatalogInventory \ Observer \ SaveInventoryDataObserver

saravanavelu
la source
0

J'ai eu le même problème pour magento 2.0.9 et le code suivant fonctionne dans mon cas

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

Magento2 propose également la fonction Multi stock, donc pour mettre à jour sur une source de stock particulière, vous pouvez suivre cette solution

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