Magento – Magento 2: can’t ship order in the backend

magento2magento2.3.1

I've just migrated my Magento 1.9 data to Magento 2.3.1.

Everything works well, but in certain circonstances, I can't ship the order in the back end.

Let's take an example.

I place an order for a product that has stock = 0 but where backorder is configured as "Allow quantity below 0".

So the order is placed without any problem.

Now when trying to ship this order, I have the following message:

Source item not found by source code: default and sku: Jupon-Vivianna-H2-220cm-Ivoire-50 (4XL).

Here how this product looks like:
enter image description here

First guess was salable quantity is blank, so I went on Stores > Configuration > Inventory

And to put a Negative amount in the Out-of-Stock Threshold area (as suggested here (https://docs.magento.com/m2/ce/user_guide/catalog/inventory-backorders.html)

enter image description here

Now here how the product looks like now:

enter image description here

But when trying to ship the order after this configuration is done, I have now another error message:

Not all of your products are available in the requested quantity.

enter image description here

Already spent few days searching, modifying the configuration…. but still I'm not able to ship the order.

Note that when a configurable product has stock in real, I can ship.
It is only when stock is 0 with backorder on that I can't ship the order.

Any help would be great.

Thanks

PS: I was before testing that on Magento 2.3.0, and had the same issue.

Best Answer

There is no solution in settings for this problem as far as I'm aware. Here is a solution you can use for a Magento 2.3.6 with MSI: create a module and use an observer. Let's say we call our module Vendor_AlwaysShip. It would have an event for sales_order_shipment_save_before:

<event name="sales_order_shipment_save_before">
  <observer name="orderAlwaysShip" instance="Vendor\AlwaysShip\Observer\AlwaysShipOrder" 
</event>

your class AlwaysShipOrder could have a Config setting in the backend but for simplicity I will leave that out here.

use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;

class AlwaysShipOrder implements ObserverInterface
{
protected $stockState;
protected $sourceItemsSaveInterface;
protected $sourceItemFactory;

public function __construct(
   \Magento\CatalogInventory\Api\StockStateInterface $stockState,
   \Magento\InventoryApi\Api\SourceItemsSaveInterface $sourceItemsSaveInterface,
   \Magento\InventoryApi\Api\Data\SourceItemInterfaceFactory $sourceItemFactory
)
{
    $this->stockState = $stockState;
    $this->sourceItemsSaveInterface = $sourceItemsSaveInterface;
    $this->sourceItemFactory = $sourceItemFactory;
} 

public function execute(Observer $observer)
{
   $items = $observer->getEvent()->getShipment()->getAllItems();
   if($items) {
     foreach ($items as $item) {
       $productId = $item->getProductId();
       $qty = $this->stockState->getStockQty($productId);
       $itemQty = $item->getQty();
       if ($qty < $itemQty) {
         $sourceItem = $this->sourceItemFactory->create();
         $sourceItem->setSourceCode('default');
         $sourceItem->setSku($item->getSku());
         $sourceItem->setQuantity($itemQty);
         $sourceItem->setStatus(1);
         $this->sourceItemsSaveInterface->execute([$sourceItem]);
      }
   }
}

What the above does is simply check if the amount to ship is available, if not then it just adds the amount needed to the MSI (Multi Source Inventory) so the order can be shipped (hence the name AlwaysShip).

You can even use the registry or a cookie to save the original qty and use another event (sales_order_shipment_save_after) to set the (MSI) qty back to its original qty. In my case this was not needed as long as the qty was 0 again after shipment if it was not in stock before.

Related Topic