magento / inventory

Magento Inventory Project (a.k.a MSI)
Open Software License 3.0
336 stars 248 forks source link

can't change/edit SKU of any products with a source assigned #3330

Closed IanFiretoys closed 2 years ago

IanFiretoys commented 3 years ago

Preconditions (*)

  1. 2.4.3 multiple sources enabled in MSI
  2. product with an SKU and a source assigned

Steps to reproduce (*)

  1. with a source assigned, change the SKU of the product by 1 letter/number and hit save

Expected result (*)

  1. product saves, reloads with the amended SKU

Actual result (*)

  1. error code drops, on production it mentioned logs in the exception logs, but nothing appears

  2. on development the following error and stack trace

    TypeError: Argument 1 passed to Magento\InventoryConfiguration\Model\IsSourceItemManagementAllowedForProductType\Interceptor::execute() must be of the type string, null given, called in /var/www/firetoys-sand7/public_html/vendor/magento/module-inventory-sales/Model/GetProductSalableQty.php on line 108 and defined in /var/www/firetoys-sand7/public_html/generated/code/Magento/InventoryConfiguration/Model/IsSourceItemManagementAllowedForProductType/Interceptor.php:20

    Temp Workaround (*)

  3. unassign all sources from the product

  4. change the SKU, and save

  5. reassign the sources and reset the stocks

obviously this workaround won't work for any product that's live and could potentially have sales, but for new products that need amending before launch it works ok.

m2-assistant[bot] commented 3 years ago

Hi @IanFiretoys. Thank you for your report. To speed up processing of this issue, make sure that you provided sufficient information.

Add a comment to assign the issue: @magento I am working on this


plastikschnitzer commented 2 years ago

I can confirm its also on Magento 2.4.3-p1 and the workaround pointed out by @IanFiretoys is working fine. See my full stack trace:

main.CRITICAL: TypeError: Argument 1 passed to Magento\InventoryConfiguration\Model\IsSourceItemManagementAllowedForProductType\Interceptor::execute() must be of the type string, null given, called in /var/www/magento2/vendor/magento/module-inventory-sales/Model/GetProductSalableQty.php on line 108 and defined in /var/www/magento2/generated/code/Magento/InventoryConfiguration/Model/IsSourceItemManagementAllowedForProductType/Interceptor.php:20
Stack trace:
#0 /var/www/magento2/vendor/magento/module-inventory-sales/Model/GetProductSalableQty.php(108): Magento\InventoryConfiguration\Model\IsSourceItemManagementAllowedForProductType\Interceptor->execute()
#1 /var/www/magento2/vendor/magento/module-inventory-sales/Model/GetProductSalableQty.php(75): Magento\InventorySales\Model\GetProductSalableQty->validateProductType()
#2 /var/www/magento2/vendor/bsscommerce/inventory-report/Helper/StorageReport.php(137): Magento\InventorySales\Model\GetProductSalableQty->execute()
#3 /var/www/magento2/vendor/bsscommerce/inventory-report/Observer/SaveObserver.php(108): Bss\InventoryReport\Helper\StorageReport->getSaleableQtyByStockId()
#4 /var/www/magento2/vendor/magento/framework/Event/Invoker/InvokerDefault.php(88): Bss\InventoryReport\Observer\SaveObserver->execute()
#5 /var/www/magento2/vendor/magento/framework/Event/Invoker/InvokerDefault.php(74): Magento\Framework\Event\Invoker\InvokerDefault->_callObserverMethod()
#6 /var/www/magento2/vendor/magento/framework/Event/Manager.php(66): Magento\Framework\Event\Invoker\InvokerDefault->dispatch()
#7 /var/www/magento2/generated/code/Magento/Framework/Event/Manager/Proxy.php(95): Magento\Framework\Event\Manager->dispatch()
#8 /var/www/magento2/vendor/magento/framework/Model/AbstractModel.php(702): Magento\Framework\Event\Manager\Proxy->dispatch()
#9 /var/www/magento2/vendor/magento/module-catalog/Model/AbstractModel.php(383): Magento\Framework\Model\AbstractModel->beforeSave()
#10 /var/www/magento2/vendor/magento/module-catalog/Model/Product.php(934): Magento\Catalog\Model\AbstractModel->beforeSave()
#11 /var/www/magento2/generated/code/Magento/Catalog/Model/Product/Interceptor.php(230): Magento\Catalog\Model\Product->beforeSave()
#12 /var/www/magento2/vendor/magento/framework/EntityManager/Observer/BeforeEntitySave.php(34): Magento\Catalog\Model\Product\Interceptor->beforeSave()
#13 /var/www/magento2/vendor/magento/framework/Event/Invoker/InvokerDefault.php(88): Magento\Framework\EntityManager\Observer\BeforeEntitySave->execute()
#14 /var/www/magento2/vendor/magento/framework/Event/Invoker/InvokerDefault.php(74): Magento\Framework\Event\Invoker\InvokerDefault->_callObserverMethod()
#15 /var/www/magento2/vendor/magento/framework/Event/Manager.php(66): Magento\Framework\Event\Invoker\InvokerDefault->dispatch()
#16 /var/www/magento2/generated/code/Magento/Framework/Event/Manager/Proxy.php(95): Magento\Framework\Event\Manager->dispatch()
#17 /var/www/magento2/vendor/magento/framework/EntityManager/EventManager.php(51): Magento\Framework\Event\Manager\Proxy->dispatch()
#18 /var/www/magento2/vendor/magento/framework/EntityManager/Operation/Update.php(106): Magento\Framework\EntityManager\EventManager->dispatchEntityEvent()
#19 /var/www/magento2/vendor/magento/framework/EntityManager/EntityManager.php(106): Magento\Framework\EntityManager\Operation\Update->execute()
#20 /var/www/magento2/vendor/magento/module-catalog/Model/ResourceModel/Product.php(773): Magento\Framework\EntityManager\EntityManager->save()
#21 /var/www/magento2/vendor/magento/framework/Interception/Interceptor.php(58): Magento\Catalog\Model\ResourceModel\Product->save()
#22 /var/www/magento2/vendor/magento/framework/Interception/Interceptor.php(138): Magento\Catalog\Model\ResourceModel\Product\Interceptor->___callParent()
#23 /var/www/magento2/vendor/magento/module-catalog-search/Model/Indexer/Fulltext/Plugin/Product.php(58): Magento\Catalog\Model\ResourceModel\Product\Interceptor->Magento\Framework\Interception\{closure}()
#24 /var/www/magento2/vendor/magento/module-catalog-search/Model/Indexer/Fulltext/Plugin/Product.php(28): Magento\CatalogSearch\Model\Indexer\Fulltext\Plugin\Product->addCommitCallback()
#25 /var/www/magento2/vendor/magento/framework/Interception/Interceptor.php(135): Magento\CatalogSearch\Model\Indexer\Fulltext\Plugin\Product->aroundSave()
#26 /var/www/magento2/vendor/magento/framework/Interception/Interceptor.php(153): Magento\Catalog\Model\ResourceModel\Product\Interceptor->Magento\Framework\Interception\{closure}()
#27 /var/www/magento2/generated/code/Magento/Catalog/Model/ResourceModel/Product/Interceptor.php(32): Magento\Catalog\Model\ResourceModel\Product\Interceptor->___callPlugins()
#28 /var/www/magento2/vendor/magento/framework/Model/AbstractModel.php(655): Magento\Catalog\Model\ResourceModel\Product\Interceptor->save()
#29 /var/www/magento2/generated/code/Magento/Catalog/Model/Product/Interceptor.php(1706): Magento\Framework\Model\AbstractModel->save()
#30 /var/www/magento2/vendor/magento/module-catalog/Controller/Adminhtml/Product/Save.php(143): Magento\Catalog\Model\Product\Interceptor->save()
#31 /var/www/magento2/vendor/magento/framework/Interception/Interceptor.php(58): Magento\Catalog\Controller\Adminhtml\Product\Save->execute()
#32 /var/www/magento2/vendor/magento/framework/Interception/Interceptor.php(138): Magento\Catalog\Controller\Adminhtml\Product\Save\Interceptor->___callParent()
#33 /var/www/magento2/vendor/magento/framework/Interception/Interceptor.php(153): Magento\Catalog\Controller\Adminhtml\Product\Save\Interceptor->Magento\Framework\Interception\{closure}()
#34 /var/www/magento2/generated/code/Magento/Catalog/Controller/Adminhtml/Product/Save/Interceptor.php(23): Magento\Catalog\Controller\Adminhtml\Product\Save\Interceptor->___callPlugins()
#35 /var/www/magento2/vendor/magento/framework/App/Action/Action.php(111): Magento\Catalog\Controller\Adminhtml\Product\Save\Interceptor->execute()
#36 /var/www/magento2/vendor/magento/module-backend/App/AbstractAction.php(151): Magento\Framework\App\Action\Action->dispatch()
#37 /var/www/magento2/vendor/magento/framework/Interception/Interceptor.php(58): Magento\Backend\App\AbstractAction->dispatch()
#38 /var/www/magento2/vendor/magento/framework/Interception/Interceptor.php(138): Magento\Catalog\Controller\Adminhtml\Product\Save\Interceptor->___callParent()
#39 /var/www/magento2/vendor/magento/module-backend/App/Action/Plugin/Authentication.php(143): Magento\Catalog\Controller\Adminhtml\Product\Save\Interceptor->Magento\Framework\Interception\{closure}()
#40 /var/www/magento2/vendor/magento/framework/Interception/Interceptor.php(135): Magento\Backend\App\Action\Plugin\Authentication->aroundDispatch()
#41 /var/www/magento2/vendor/magento/framework/Interception/Interceptor.php(153): Magento\Catalog\Controller\Adminhtml\Product\Save\Interceptor->Magento\Framework\Interception\{closure}()
#42 /var/www/magento2/generated/code/Magento/Catalog/Controller/Adminhtml/Product/Save/Interceptor.php(32): Magento\Catalog\Controller\Adminhtml\Product\Save\Interceptor->___callPlugins()
#43 /var/www/magento2/vendor/magento/framework/App/FrontController.php(245): Magento\Catalog\Controller\Adminhtml\Product\Save\Interceptor->dispatch()
#44 /var/www/magento2/vendor/magento/framework/App/FrontController.php(212): Magento\Framework\App\FrontController->getActionResponse()
#45 /var/www/magento2/vendor/magento/framework/App/FrontController.php(147): Magento\Framework\App\FrontController->processRequest()
#46 /var/www/magento2/vendor/magento/framework/Interception/Interceptor.php(58): Magento\Framework\App\FrontController->dispatch()
#47 /var/www/magento2/vendor/magento/framework/Interception/Interceptor.php(138): Magento\Framework\App\FrontController\Interceptor->___callParent()
#48 /var/www/magento2/vendor/m2e/ebay-amazon-magento2/Plugin/HealthStatus/Magento/Framework/App/FrontController.php(81): Magento\Framework\App\FrontController\Interceptor->Magento\Framework\Interception\{closure}()
#49 /var/www/magento2/vendor/m2e/ebay-amazon-magento2/Plugin/AbstractPlugin.php(45): Ess\M2ePro\Plugin\HealthStatus\Magento\Framework\App\FrontController->processDispatch()
#50 /var/www/magento2/vendor/m2e/ebay-amazon-magento2/Plugin/HealthStatus/Magento/Framework/App/FrontController.php(45): Ess\M2ePro\Plugin\AbstractPlugin->execute()
#51 /var/www/magento2/vendor/magento/framework/Interception/Interceptor.php(135): Ess\M2ePro\Plugin\HealthStatus\Magento\Framework\App\FrontController->aroundDispatch()
#52 /var/www/magento2/vendor/magento/framework/Interception/Interceptor.php(153): Magento\Framework\App\FrontController\Interceptor->Magento\Framework\Interception\{closure}()
#53 /var/www/magento2/generated/code/Magento/Framework/App/FrontController/Interceptor.php(23): Magento\Framework\App\FrontController\Interceptor->___callPlugins()
#54 /var/www/magento2/vendor/magento/framework/App/Http.php(116): Magento\Framework\App\FrontController\Interceptor->dispatch()
#55 /var/www/magento2/generated/code/Magento/Framework/App/Http/Interceptor.php(23): Magento\Framework\App\Http->launch()
#56 /var/www/magento2/vendor/magento/framework/App/Bootstrap.php(264): Magento\Framework\App\Http\Interceptor->launch()
#57 /var/www/magento2/pub/index.php(374): Magento\Framework\App\Bootstrap->run()
#58 {main} [] []
IanFiretoys commented 2 years ago

I can confirm its also on Magento 2.4.3-p1 and the workaround pointed out by @IanFiretoys is working fine. See my full stack trace:

main.CRITICAL: TypeError: Argument 1 passed to Magento\InventoryConfiguration\Model\IsSourceItemManagementAllowedForProductType\Interceptor::execute() must be of the type string, null given, called in /var/www/magento2/vendor/magento/module-inventory-sales/Model/GetProductSalableQty.php on line 108 and defined in /var/www/magento2/generated/code/Magento/InventoryConfiguration/Model/IsSourceItemManagementAllowedForProductType/Interceptor.php:20
Stack trace:
#0 /var/www/magento2/vendor/magento/module-inventory-sales/Model/GetProductSalableQty.php(108): Magento\InventoryConfiguration\Model\IsSourceItemManagementAllowedForProductType\Interceptor->execute()
#1 /var/www/magento2/vendor/magento/module-inventory-sales/Model/GetProductSalableQty.php(75): Magento\InventorySales\Model\GetProductSalableQty->validateProductType()
#2 /var/www/magento2/vendor/bsscommerce/inventory-report/Helper/StorageReport.php(137): Magento\InventorySales\Model\GetProductSalableQty->execute()
#3 /var/www/magento2/vendor/bsscommerce/inventory-report/Observer/SaveObserver.php(108): Bss\InventoryReport\Helper\StorageReport->getSaleableQtyByStockId()
#4 /var/www/magento2/vendor/magento/framework/Event/Invoker/InvokerDefault.php(88): Bss\InventoryReport\Observer\SaveObserver->execute()
#5 /var/www/magento2/vendor/magento/framework/Event/Invoker/InvokerDefault.php(74): Magento\Framework\Event\Invoker\InvokerDefault->_callObserverMethod()
#6 /var/www/magento2/vendor/magento/framework/Event/Manager.php(66): Magento\Framework\Event\Invoker\InvokerDefault->dispatch()
#7 /var/www/magento2/generated/code/Magento/Framework/Event/Manager/Proxy.php(95): Magento\Framework\Event\Manager->dispatch()
#8 /var/www/magento2/vendor/magento/framework/Model/AbstractModel.php(702): Magento\Framework\Event\Manager\Proxy->dispatch()
#9 /var/www/magento2/vendor/magento/module-catalog/Model/AbstractModel.php(383): Magento\Framework\Model\AbstractModel->beforeSave()
#10 /var/www/magento2/vendor/magento/module-catalog/Model/Product.php(934): Magento\Catalog\Model\AbstractModel->beforeSave()
#11 /var/www/magento2/generated/code/Magento/Catalog/Model/Product/Interceptor.php(230): Magento\Catalog\Model\Product->beforeSave()
#12 /var/www/magento2/vendor/magento/framework/EntityManager/Observer/BeforeEntitySave.php(34): Magento\Catalog\Model\Product\Interceptor->beforeSave()
#13 /var/www/magento2/vendor/magento/framework/Event/Invoker/InvokerDefault.php(88): Magento\Framework\EntityManager\Observer\BeforeEntitySave->execute()
#14 /var/www/magento2/vendor/magento/framework/Event/Invoker/InvokerDefault.php(74): Magento\Framework\Event\Invoker\InvokerDefault->_callObserverMethod()
#15 /var/www/magento2/vendor/magento/framework/Event/Manager.php(66): Magento\Framework\Event\Invoker\InvokerDefault->dispatch()
#16 /var/www/magento2/generated/code/Magento/Framework/Event/Manager/Proxy.php(95): Magento\Framework\Event\Manager->dispatch()
#17 /var/www/magento2/vendor/magento/framework/EntityManager/EventManager.php(51): Magento\Framework\Event\Manager\Proxy->dispatch()
#18 /var/www/magento2/vendor/magento/framework/EntityManager/Operation/Update.php(106): Magento\Framework\EntityManager\EventManager->dispatchEntityEvent()
#19 /var/www/magento2/vendor/magento/framework/EntityManager/EntityManager.php(106): Magento\Framework\EntityManager\Operation\Update->execute()
#20 /var/www/magento2/vendor/magento/module-catalog/Model/ResourceModel/Product.php(773): Magento\Framework\EntityManager\EntityManager->save()
#21 /var/www/magento2/vendor/magento/framework/Interception/Interceptor.php(58): Magento\Catalog\Model\ResourceModel\Product->save()
#22 /var/www/magento2/vendor/magento/framework/Interception/Interceptor.php(138): Magento\Catalog\Model\ResourceModel\Product\Interceptor->___callParent()
#23 /var/www/magento2/vendor/magento/module-catalog-search/Model/Indexer/Fulltext/Plugin/Product.php(58): Magento\Catalog\Model\ResourceModel\Product\Interceptor->Magento\Framework\Interception\{closure}()
#24 /var/www/magento2/vendor/magento/module-catalog-search/Model/Indexer/Fulltext/Plugin/Product.php(28): Magento\CatalogSearch\Model\Indexer\Fulltext\Plugin\Product->addCommitCallback()
#25 /var/www/magento2/vendor/magento/framework/Interception/Interceptor.php(135): Magento\CatalogSearch\Model\Indexer\Fulltext\Plugin\Product->aroundSave()
#26 /var/www/magento2/vendor/magento/framework/Interception/Interceptor.php(153): Magento\Catalog\Model\ResourceModel\Product\Interceptor->Magento\Framework\Interception\{closure}()
#27 /var/www/magento2/generated/code/Magento/Catalog/Model/ResourceModel/Product/Interceptor.php(32): Magento\Catalog\Model\ResourceModel\Product\Interceptor->___callPlugins()
#28 /var/www/magento2/vendor/magento/framework/Model/AbstractModel.php(655): Magento\Catalog\Model\ResourceModel\Product\Interceptor->save()
#29 /var/www/magento2/generated/code/Magento/Catalog/Model/Product/Interceptor.php(1706): Magento\Framework\Model\AbstractModel->save()
#30 /var/www/magento2/vendor/magento/module-catalog/Controller/Adminhtml/Product/Save.php(143): Magento\Catalog\Model\Product\Interceptor->save()
#31 /var/www/magento2/vendor/magento/framework/Interception/Interceptor.php(58): Magento\Catalog\Controller\Adminhtml\Product\Save->execute()
#32 /var/www/magento2/vendor/magento/framework/Interception/Interceptor.php(138): Magento\Catalog\Controller\Adminhtml\Product\Save\Interceptor->___callParent()
#33 /var/www/magento2/vendor/magento/framework/Interception/Interceptor.php(153): Magento\Catalog\Controller\Adminhtml\Product\Save\Interceptor->Magento\Framework\Interception\{closure}()
#34 /var/www/magento2/generated/code/Magento/Catalog/Controller/Adminhtml/Product/Save/Interceptor.php(23): Magento\Catalog\Controller\Adminhtml\Product\Save\Interceptor->___callPlugins()
#35 /var/www/magento2/vendor/magento/framework/App/Action/Action.php(111): Magento\Catalog\Controller\Adminhtml\Product\Save\Interceptor->execute()
#36 /var/www/magento2/vendor/magento/module-backend/App/AbstractAction.php(151): Magento\Framework\App\Action\Action->dispatch()
#37 /var/www/magento2/vendor/magento/framework/Interception/Interceptor.php(58): Magento\Backend\App\AbstractAction->dispatch()
#38 /var/www/magento2/vendor/magento/framework/Interception/Interceptor.php(138): Magento\Catalog\Controller\Adminhtml\Product\Save\Interceptor->___callParent()
#39 /var/www/magento2/vendor/magento/module-backend/App/Action/Plugin/Authentication.php(143): Magento\Catalog\Controller\Adminhtml\Product\Save\Interceptor->Magento\Framework\Interception\{closure}()
#40 /var/www/magento2/vendor/magento/framework/Interception/Interceptor.php(135): Magento\Backend\App\Action\Plugin\Authentication->aroundDispatch()
#41 /var/www/magento2/vendor/magento/framework/Interception/Interceptor.php(153): Magento\Catalog\Controller\Adminhtml\Product\Save\Interceptor->Magento\Framework\Interception\{closure}()
#42 /var/www/magento2/generated/code/Magento/Catalog/Controller/Adminhtml/Product/Save/Interceptor.php(32): Magento\Catalog\Controller\Adminhtml\Product\Save\Interceptor->___callPlugins()
#43 /var/www/magento2/vendor/magento/framework/App/FrontController.php(245): Magento\Catalog\Controller\Adminhtml\Product\Save\Interceptor->dispatch()
#44 /var/www/magento2/vendor/magento/framework/App/FrontController.php(212): Magento\Framework\App\FrontController->getActionResponse()
#45 /var/www/magento2/vendor/magento/framework/App/FrontController.php(147): Magento\Framework\App\FrontController->processRequest()
#46 /var/www/magento2/vendor/magento/framework/Interception/Interceptor.php(58): Magento\Framework\App\FrontController->dispatch()
#47 /var/www/magento2/vendor/magento/framework/Interception/Interceptor.php(138): Magento\Framework\App\FrontController\Interceptor->___callParent()
#48 /var/www/magento2/vendor/m2e/ebay-amazon-magento2/Plugin/HealthStatus/Magento/Framework/App/FrontController.php(81): Magento\Framework\App\FrontController\Interceptor->Magento\Framework\Interception\{closure}()
#49 /var/www/magento2/vendor/m2e/ebay-amazon-magento2/Plugin/AbstractPlugin.php(45): Ess\M2ePro\Plugin\HealthStatus\Magento\Framework\App\FrontController->processDispatch()
#50 /var/www/magento2/vendor/m2e/ebay-amazon-magento2/Plugin/HealthStatus/Magento/Framework/App/FrontController.php(45): Ess\M2ePro\Plugin\AbstractPlugin->execute()
#51 /var/www/magento2/vendor/magento/framework/Interception/Interceptor.php(135): Ess\M2ePro\Plugin\HealthStatus\Magento\Framework\App\FrontController->aroundDispatch()
#52 /var/www/magento2/vendor/magento/framework/Interception/Interceptor.php(153): Magento\Framework\App\FrontController\Interceptor->Magento\Framework\Interception\{closure}()
#53 /var/www/magento2/generated/code/Magento/Framework/App/FrontController/Interceptor.php(23): Magento\Framework\App\FrontController\Interceptor->___callPlugins()
#54 /var/www/magento2/vendor/magento/framework/App/Http.php(116): Magento\Framework\App\FrontController\Interceptor->dispatch()
#55 /var/www/magento2/generated/code/Magento/Framework/App/Http/Interceptor.php(23): Magento\Framework\App\Http->launch()
#56 /var/www/magento2/vendor/magento/framework/App/Bootstrap.php(264): Magento\Framework\App\Http\Interceptor->launch()
#57 /var/www/magento2/pub/index.php(374): Magento\Framework\App\Bootstrap->run()
#58 {main} [] []

I have recently found this is related to a 3rd party extension, can you confirm if you have the bss inventory report extension installed?

plastikschnitzer commented 2 years ago

@IanFiretoys yes I have installed BSS Inventory report, latest version 1.1.6 see its also included in my stack trace line 2 and 3. The extension also causes other problems with Magento 2.4.3 like this here: https://support.bsscommerce.com/support/solutions/articles/19000133595-v1-1-6-how-to-fix-error-registry-key-bss-salable-qty-before-already-exists-

Can you confirm its fixed with the extension disabled? If yes, its worth a bug report to BSS Commerce, what do you think?

IanFiretoys commented 2 years ago

it is confirmed to work without the extension, this issue also cropped up and the cause was the bss inventory report not dealing with getSaleableQuantity properly. https://github.com/magento/magento2/issues/35257#issuecomment-1089872925

plastikschnitzer commented 2 years ago

Outch, looks like this Extension is really buggy and its worth thinking about how to replace it …

I sent a bugreport to BSS Commerce, basically this makes it not being compatible for Magento 2.4. – lets hope they fix it.

IanFiretoys commented 2 years ago

yep, same, if anyone can suggest an alternative stock history extension i'm all ears

plastikschnitzer commented 2 years ago

The Plugin provider made a fix and published it: https://bsscommerce.freshdesk.com/support/solutions/articles/19000135701

Working for me. I know no other alternate stock history module, I guess most others rely on external stock management solutions and not 100% on MSI only – imho the stock tracking&history / reporting function should be Magento core anyway to give MSI the "next level". We will see ;-)