Skip to content

[5.x]: "Reserved" stock is not updated after order fulfillment or inventory transfer #4268

@yoannisj

Description

@yoannisj

What happened?

Description

Due to issue #4267 , all “Inventory Transfer” related behaviour described below was observed and tested with Craft-Commerce v5.4.10. The rest of the behaviour was tested both with v5.4.10 and v5.6.1.1.

When the “allow out of stock purchases” option is enabled for a given purchasable, it is possible to create orders which include that purchasable in a quantity greater than the “available” level in any of the store’s stock locations, but less than the total stock available across all of the store’s locations.

The way Craft-Commerce handles such orders seems counter-intuitive to us, as it requires manually adjusting stock levels after Inventory Transfers and/or order Fulfillments:

  1. The total ordered quantity is retained as “committed” stock in the store’s first location
  2. The remainder quantity –i.e. the difference between the total ordered quantity and the stock available in the first store’s location– is retained as “reserved” stock in one or multiple subsequent location(s).
  3. It is possible to fulfill the purchasable in quantities greater than the first location’s “on hand” stock level, which feels like a mistake and kind of impossible in real life.
  4. Doing so effectively decreases the purchasable’s “committed” stock level in the first location, but does not change the “reserved” stock level in subsequent locations.
  5. Creating a pending stock transfer from the subsequent location(s) to the first location increases the “incoming” stock level in the first/target location, AND decreases the “available” stock level in subsequent/origin locations. Based on the documentation, we would expect it to keep the “available” stock as is and decrease the “incoming” stock level in the subsequent/origin location(s) accordingly to indicate an ongoing transfer.
  6. Receiving stock transferred from the subsequent/origin location(s) into the first/target location decreases the “incoming” stock level in the first/target location and increases its “available” stock, but it does NOT automatically adjust the stock levels in the subsequent/origin location(s). We would expect the “incoming” stock level to be increased again, and the “reserved” stock level to be decreased back.

This seems error-prone, as it requires that editors do the following adjustments to keep stock levels in Craft-Commerce in sync:
a) make sure they never fulfill quantities superior to the stock currently “on hand” in the first location with stock
b) always transfer remainder stock from subsequent location(s) to the first location before fulfilling it
c) adjust the “reserved” stock level in the subsequent location(s) manually after receiving that stock in the first stock location.

Steps to reproduce

  1. Create two separate stock locations in Craft-Commerce, and attach both to a Commerce store
  2. Enable the “track inventory” and “allow out of stock purchases” option on a given product variant
  3. Set the “available” stock level for that purchasable to “10” in both locations
  4. Create and complete an order which includes “15” units of the purchasable (line item quantity = 15)
  5. Do a full database backup
  6. Fulfill 15 units of that purchasable on the order (in one go or multiple steps, that does not matter).
  7. Note that the “available” and “on hand” stock levels are now both at “-5” in the first location attached to the store, and the “reserved” stock level is still “5” in the second location attached to the store.
  8. Restore the database backup created in step 5
  9. Create a stock transfer with the following parameters:
    • origin: second stock location attached to the store
    • target: first stock location attached to the store
    • line-items: the product variant from step 2, with quantity of 5
  10. Mark the stock transfer as “pending”.
  11. Note that the “available” stock in the origin location decreased but the “incoming” stock did not change.
  12. Receive all the stock in the transfer (in one go or multiple steps, that does not matter)
  13. Note that the “reserved” stock in the origin location did not change (this needs to be decreased manually and the “available” stock to be increased accordingly again to reflect the stock’s real state).

Expected behavior

If all ordered quantity is retained as “committed” stock in the store’s first location (current behaviour), our understanding is that all the order's fulfillments must be based on the stock found in that location, and we would expect that:

  • Commerce prevents fulfilling purchasables in quantities greater than the stock "fulfillable" in that first location (i.e. "available" plus "committed for the order being fulfilled").
  • Transferring a purchasable’s stock from a location that has “reserved” stock to a location that has committed stock should remove the transferred quantity from the origin location’s “reserved” stock level first (before removing it from its “available” stock level) and add it to the “available” stock level in the target location.

A different approach, would be to allow fulfilling the order from multiple stock locations, in which case we would expect that:

  • Commerce retains only up to maximum the available stock as “committed” in the first location
  • If needed, the rest of the purchasable’s ordered quantity also gets retained as “committed” stock in subsequent stock location(s) (also only up to maximum the available stock level)
  • Fulfillments include a “stock location” parameter, which allows editors to choose from which stock location ordered quantity is being fulfilled.
  • Commerce prevents fulfilling more than the purchasable’s total committed stock in the selected location.
  • Transferring a purchasable’s stock from a location that has “committed” stock to another location that has “committed stock” should remove the transferred quantity from the origin location’s “committed stock” level first (before removing it from its “available” stock level) and add it to the “committed” stock of the target location first (before adding it to its “available” stock level). This behaviour still makes it possible to fulfill the order’s contents from one single location by transferring the missing stock to that location before fulfilling it from there (either in one go, or in multiple steps).

We may be missing something, but the second approach seems more flexible to use, and –if viable– it may also remove the need for “reserved” stock levels.

Actual behavior

(See description).

Craft CMS version

5.9.18 (Craft Pro)

Craft Commerce version

5.4.10 and 5.6.1.1

PHP version

8.4.14

Operating system and version

Linux 6.17.8-orbstack-00308-g8f9c941121b1 (DDEV w/ Orbstack)

Database type and version

MySQL 8.0.40

Image driver and version

Imagick 3.8.0 (ImageMagick 6.9.11-60)

Installed plugins and versions

  • CKEditor 5.4.0
  • Imager X 5.2.1
  • Phone Number 3.0.0
  • Preparse 3.0.0-alpha.2
  • Retour 5.0.14
  • SEO 5.1.21
  • Wordsmith 5.0.0

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions