6

I have a custom script that read CSV and creates products programmatically, it was working fine with Magento 2.2.6, now I upgraded it to Magento 2.3, and with upgradation, I configured Multi-Source Inventory. The issue I am facing is that while saving the product it is throwing error "The stock item was unable to be saved. Please try again."

I am getting below error in the log

 main.CRITICAL: The stock item was unable to be saved. Please try again. {"exception":"[object] (Magento\\Framework\\Exception\\CouldNotSaveException(code: 0): The stock item was unable to be saved. Please try again. at /magento_root/vendor/magento/module-catalog-inventory/Model/Stock/StockItemRepository.php:187,
 Magento\\Framework\\Exception\\CouldNotSaveException(code: 0): Could not save Source Item at /magento_root/vendor/magento/module-inventory/Model/SourceItem/Command/Handler/SourceItemsSaveHandler.php:78,
 Zend_Db_Statement_Exception(code: 23000): SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (`magento_db`.`inventory_source_item`, CONSTRAINT `INVENTORY_SOURCE_ITEM_SOURCE_CODE_INVENTORY_SOURCE_SOURCE_CODE` FOREIGN KEY (`source_code`) REFERENCES `inventory_source` (`source_code`) ON DEL), query was: INSERT INTO inventory_source_item (`source_code`, `sku`, `quantity`, `status`) VALUES (?, ?, ?, ?) ON DUPLICATE KEY UPDATE `quantity` = VALUES(`quantity`), `status` = VALUES(`status`) at /magento_root/vendor/magento/zendframework1/library/Zend/Db/Statement/Pdo.php:235,
 PDOException(code: 23000): SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (`magento_db`.`inventory_source_item`, CONSTRAINT `INVENTORY_SOURCE_ITEM_SOURCE_CODE_INVENTORY_SOURCE_SOURCE_CODE` FOREIGN KEY (`source_code`) REFERENCES `inventory_source` (`source_code`) ON DEL) at /magento_root/vendor/magento/zendframework1/library/Zend/Db/Statement/Pdo.php:228)"} []

I Injected \Magento\Catalog\Model\ProductFactory $productFactory and using the below code to create the product

$_product = $this->_productFactory->create();

$mainImage = "";
$imagesToImport = "";
if (isset($productData['images'])) {
    $images = explode(',', $productData['images']);
    $mainImage = $images[0];
    array_shift($images);
    if (count($images) > 0) {
        if (count($images) > 1) {
            $imagesToImport = implode(';', $images);
        } else {
            $imagesToImport = $images[0];
        }
    }
}
$urlKey = $this->geturlKey($productData['name']);
$_product->setName($productData['name']);
$_product->setTypeId('simple');
$_product->setAttributeSetId(4);
$_product->setCategoryIds($this->getCategoryId($productData['category']));
$_product->setSku($productData['sku']);
$_product->setStatus(2);
$_product->setUrlKey(strtolower($urlKey) . '-' . $productData['sku']);
$_product->setWebsiteIds(array(1));
$_product->setVisibility(4);
$_product->setDescription($productData['description']);
$_product->setShortDescription($productData['short_description']);
$_product->setPrice($productData['price']);
if (isset($productData['special_price'])) {
    $_product->setSpecialPrice($productData['special_price']);
    $_product->setSpecialFromDate(''); //special price from (MM-DD-YYYY)
    $_product->setSpecialToDate(''); //special price to (MM-DD-YYYY)
}
$_product->setMetaTitle($productData['meta_title']);
$_product->setMetaKeyword($productData['meta_keyword']);
if (!empty($productData['tier_price'])) {
    $_product->setTierPrices($productData['tier_price']);
}
$_product->setWeight($productData['weight']);
$_product->setMetaDescription($productData['meta_description']);
$_product->setTaxClassId($productData['tax_class_id']);
$shoeColorId = $this->_eavAttribute->getIdByCode('catalog_product', 'color');
$shoeBrandId = $this->_eavAttribute->getIdByCode('catalog_product', 'manufacturer');
$_product->setColor($this->getAttributeOptionId($productData['color'], $shoeColorId, 'color'));
$_product->setManufacturer($this->getAttributeOptionId($productData['manufacturer'], $shoeBrandId, 'manufacturer'));
$_product->setStockData(
    array(
        'use_config_manage_stock' => 0, //'Use config settings' checkbox
        'manage_stock' => 1, //manage stock
        'is_in_stock' => $productData['is_in_stock'], //Stock Availability
        'qty' => $productData['stock'], //qty
    )
);
$_product->save();

The issue with code is missing inventory source details, I am looking for a way to create product programmatically and assigning the source at the same time.

How can I create product programmatically with proper inventory management?

2
+25

Can you please set stock data this way in Magento 2.3

Also please inject product and productRepository like following

$_product->setStockData(
     [
        'use_config_manage_stock' => 0,
        'qty' => $productData['stock'],
        'is_qty_decimal' => 0,
        'manage_stock' => 1,
        'is_in_stock' => $productData['is_in_stock']
     ]
    );

UPDATE

I have tried this way and its working fine for me, Check this screenshot for more information : https://prnt.sc/me62gf and this https://prnt.sc/me637c

Check my controller below.

namespace Vendor\Module\Block\Index;

class Index extends \Magento\Framework\View\Element\Template
{

    protected $_productFactory;

    /**
     * Constructor
     *
     * @param \Magento\Framework\View\Element\Template\Context  $context
     * @param array $data
     */
    public function __construct(
        \Magento\Framework\View\Element\Template\Context $context,
        \Magento\Catalog\Model\ProductFactory $productFactory,
        array $data = []
    ) {
        parent::__construct($context, $data);
        $this->_productFactory = $productFactory;
    }

    public function FunctionName()
    {
        $_product = $this->_productFactory->create();

        $mainImage = "";
        $imagesToImport = "";

        $urlKey = $this->geturlKey('url_key');
        $_product->setName('name');
        $_product->setTypeId('simple');
        $_product->setAttributeSetId(4);
        $_product->setCategoryIds([]);
        $_product->setSku('psku');
        $_product->setStatus(2);
        $_product->setUrlKey('url_key');
        $_product->setWebsiteIds([1]);
        $_product->setVisibility(4);
        $_product->setDescription('description');
        $_product->setShortDescription('short_description');
        $_product->setPrice(30.3);
        //if (isset($productData['special_price'])) {
            $_product->setSpecialPrice(20.6);
            $_product->setSpecialFromDate(''); //special price from (MM-DD-YYYY)
            $_product->setSpecialToDate(''); //special price to (MM-DD-YYYY)
        //}
        $_product->setMetaTitle('meta_title');
        $_product->setMetaKeyword('meta_keyword');

        $_product->setWeight('1.0');
        $_product->setMetaDescription('meta_description');

        $_product->setColor('color');
        $_product->setManufacturer('manufacturer');
        $_product->setStockData(
            [
                'use_config_manage_stock' => 0, //'Use config settings' checkbox
                'manage_stock' => 1, //manage stock
                'is_in_stock' => 1, //Stock Availability
                'qty' => 100, //qty
            ]
        );
        //echo "<pre>";print_r($_product->debug()); exit();
        $_product->save();
    }
}
  • @Piyush please check my updated ans, hope it will help you. – Aasim Goriya Jan 30 at 9:08
  • @Piyush can you send sample csv and full code so I can check it here ? – Aasim Goriya Jan 30 at 9:35
  • I have added full code in the question for sample csv data i have just added random values as per attributes so you can set static values for each attribute – Piyush Jan 30 at 9:38
  • @Piyush check my updated ans and its working fine for me. – Aasim Goriya Jan 30 at 10:16
  • Have you created stocks and sources for the inventory managment? As the code I have posted in question was working well, but it stopped working after upgrading to 2.3 and creating stock and sources. – Piyush Jan 30 at 10:19
0

You can try the StockRegistryInterface for inventory update

Method 1 :

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

   // Create your custom method to update the inventory
    public function updateInventory() {
        $sku = 'test123';
        $qty = 10;
        $stockItem = $this->stockRegistry->getStockItemBySku($sku);
        $stockItem->setQty($qty);
        $stockItem->setIsInStock((bool)$qty); // this line
        $this->stockRegistry->updateStockItemBySku($sku, $stockItem);
    }

Method 2 :

Here we define function in helper file of module

<?php
namespace YourNameSpace\ModuleName\Helper;

use Magento\Framework\App\Filesystem\DirectoryList;

class Data extends \Magento\Framework\App\Helper\AbstractHelper
{
    protected $_product;

    /**
     * @var Magento\CatalogInventory\Api\StockStateInterface 
     */
    protected $_stockStateInterface;

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

    /**
    * @param Magento\Framework\App\Helper\Context $context
    * @param Magento\Catalog\Model\Product $product
    * @param Magento\CatalogInventory\Api\StockStateInterface $stockStateInterface,
    * @param Magento\CatalogInventory\Api\StockRegistryInterface $stockRegistry
    */
    public function __construct(
        \Magento\Framework\App\Helper\Context $context,
        \Magento\Catalog\Model\Product $product,
        \Magento\CatalogInventory\Api\StockStateInterface $stockStateInterface,
        \Magento\CatalogInventory\Api\StockRegistryInterface $stockRegistry, 
    ) {
        $this->_product = $product;
        $this->_stockStateInterface = $stockStateInterface;
        $this->_stockRegistry = $stockRegistry;
        parent::__construct($context);
    }

    /**
     * For Update stock of product
     * @param int $productId which stock you want to update
     * @param array $stockData your updated data
     * @return void 
    */
    public function updateProductStock($productId,$stockData) {
        $product=$this->_product->load($productId); //load product which you want to update stock
        $stockItem=$this->_stockRegistry->getStockItem($item['product_id']); // load stock of that product
        $stockItem->setData('is_in_stock',$stockData['is_in_stock']); //set updated data as your requirement
        $stockItem->setData('qty',$stockData['qty']); //set updated quantity 
        $stockItem->setData('manage_stock',$stockData['manage_stock']);
        $stockItem->setData('use_config_notify_stock_qty',1);
        $stockItem->save(); //save stock of item
        $product->save(); //  also save product
    }
}
  • not only inventory I want to add stock and sources based qty, code I added in my question was properly setting stock status and qty in magento 2.2.6 version, but it is not working for magento 2.3. – Piyush Jan 23 at 12:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.