Inventory decremented twice - by Shopify and App

Jeff-Blake
Shopify Partner
41 0 8

I have a client shop that is experiencing an inventory issue I cannot reproduce.

 

My app creates a Fulfillment service and manages it's own inventory (via the fetch_stock endpoint that Shopify calls).

 

I'm seeing inventory getting decremented twice, once by Shopify (expected) and once by my app (unexpected).

 

Here is a screenshot of the inventory history:

Screen Shot 2019-10-29 at 9.27.42 PM.png

 

In my own dev store, it only shows Shopify adjusting the inventory ("Online Store"), and I never see "Manually removed" from the app.

 

The fetch_stock endpoint is correctly returning available inventory, for example:

 

{"14975":20,"14978":16}

 

I've tried turning automatic fulfillment on and off in my test store, no difference.

 

Is there some setting or behavior I'm not aware of?

 

I'm pretty sure it's related to an order pending fulfillment, as my fetch_stock endpoint will return the count as if all orders have been fulfilled. I.e, if total original inventory = 10, item count pending fulfillment = 2, fetch_stock will return 8. I think it's supposed to still return 10.  However, I can't reproduce this theory on a test store.

 

Full test case to attempt reproduce:

Add product, inventory = 10

Checkout order for 1, order is still unfulfilled. Shopify decrements 1

Wait 1 hour, and/or toggle Track quantity on/off, verified fetch_stock is returning 9.

Expecting Shopify to report that my app decrements 1 more inventory, to prove my theory above, so I can go ahead and fix the fetch_stock endpoint. But inventory stays at 9.

 

Replies 19 (19)
Jeff-Blake
Shopify Partner
41 0 8

In summary, it seems Shopify is calculating inventory differently on my clients store vs my store:

 

On clients store:

Inventory  = fetch_stock endpoint minus pending unfulfilled 

 

On my dev store:

Inventory = fetch_stock endpoint 

 

As explained in this thread: https://community.shopify.com/c/Shopify-APIs-SDKs/Product-Variant-Level-Lower-Than-Fetch-Stock-Endpo...

 

It makes sense why I need to change inventory on my end to only decrement stock after fulfillment, however if I did that change, then the inventory count on my test store would be incorrect (because my test store seems to ignore pending unfulfilled orders - and I've tripled checked that the fetch_stock endpoint is being called by Shopify)

_JB
Shopify Staff
Shopify Staff
836 99 215

Hey @Jeff-Blake,

 

When responding to fetch_stock requests, can you confirm if you're preforming any logic yourself to account for pending unfulfilled orders in the Shopify shop? Shopify already takes these orders into account when processing your response, so if you're also trying to account for this in your response as well it can result in inventory being decremented twice as you described. You shouldn't do any additional calculations on your end when responding to fetch_stock requests, and just respond with the quantity that's actually in stock at the fulfillment service location. 

 

For example:

12:00 : T-Shirt (managed by your app) has 20 stock

12:05 : 1 shirt is sold on the Shopify online store (Shopify stock 19 : Warehouse stock 20)

12:30: Fetch_stock request occurs, warehouse responds with qty 20. (Shopify has qty 19 in stock + 1 pending unfulfilled = 20 (no adjustment necessary))

12:50: Order fulfilled by warehouse (Warehouse stock now qty 19, Shopify stock also qty 19)

1:30: Fetch_stock request occurs, warehouse responds with 19. (Shopify has qty 19 in stock with 0 pending unfulfilled = 19 (no adjustment necessary))

 

In the above scenario, responding with qty 19 on the 12:30 fetch_stock (to account for the unfulfilled order) would result in 1 more item being decremented by your app. Since Shopify assumes you aren't accounting for pending unfulfilled orders on the shop, a response of 19 indicates that 1 item was removed outside Shopify, and so Shopify needs to decrement the quantity on our side by 1 more.

 

If your app is configured the same for your client's store and dev store, I would expect to see a similar behaviour on both. Are you subscribed to the same webhooks on the client's store and your dev store? If you're still seeing a behaviour that looks unexpected, please provide the shop_ids and approximate timeframes from when the actions were taken on the shop, and we can investigate further.

JB | Solutions Engineer @ Shopify 
 - Was your question answered? Mark it as an Accepted Solution
 - To learn more visit Shopify.dev or the Shopify Web Design and Development Blog

Jeff-Blake
Shopify Partner
41 0 8

Hi JB,

 

Yes, I'm currently responding with 19 at the 12:30 mark in your example. This makes sense to me why I need to change it to respond with 20, but I'm not getting the same behavior on my dev store, and yes I've checked the logs to see the webhooks and fetch_stock endpoints firing.

 

Test store: gm-development-test-store.myshopify.com

October 30, 2019 at 12:31 pm EST

Order #1002 was placed. Order is still un-fulfilled

Screen Shot 2019-11-05 at 8.16.10 AM.png

 

Fetch stock endpoint: https://shopify.guestmanager.com/fetch_stock.json?max_retries=3&shop=gm-development-test-store.mysho...

Returns 9 for SKU 15227

 

I would expect this to cause Shopify to manually decrement the stock to 8 (so that I can reproduce the bug occurring on a client store), and implement the fix you've prescribed, by moving fulfillment/inventory adustment out of the orders/create webhook.

 

The test store is using the same app as the client (not the Dev/unpublished app)

 

Thanks.

_JB
Shopify Staff
Shopify Staff
836 99 215

Hey @Jeff-Blake,

 

I had a look at your test store order, and I'm not sure why that one didn't exhibit the same behaviour. From what I can see I would've expected the fetch_stock Shopify did after the order was placed to result in SKU 15227 being decremented to 8. Do you mind if I issue some API credentials on your test shop to test this out myself?

 

 

JB | Solutions Engineer @ Shopify 
 - Was your question answered? Mark it as an Accepted Solution
 - To learn more visit Shopify.dev or the Shopify Web Design and Development Blog

Jeff-Blake
Shopify Partner
41 0 8

Sure, please do. I tested it on one of my other dev stores as well - and same behavior. So far I'm only seeing the 'expected' behavior on that client store.

_JB
Shopify Staff
Shopify Staff
836 99 215

Hey @Jeff-Blake,

 

I've completed my testing and can confirm the expected behaviour is happening on your test store. I created my own fulfillment service and saw the inventory number decrement again after placing an order for a product and adjusting my fetch_stock response by -1. I also made another test order using the same test product, and the inventory decremented by 1 as expected on that as well.

 

I checked our logs for your original test order, and I can see why this didn't work the first time. The test order was created at 12:31pm, and Shopify made a fetch_stock request at 1:25 pm which only included 2 SKUs in the response: GET response action=fetch_stock in 0.4528s {"14877":99,"14879":50}

 

Since this fetch_stock didn't include the variant on your test order, the stock wasn't updated accordingly. Now that your endpoint includes the variant in question, this should work as expected on a new test order with your fulfillment service. If you'd like to test that, please adjust the fetch_stock response and make another test order, and adjust the fetch_stock again to match the quantity Shopify shows after your test order is placed. Don't hesitate to reach out if you run into any issues.

JB | Solutions Engineer @ Shopify 
 - Was your question answered? Mark it as an Accepted Solution
 - To learn more visit Shopify.dev or the Shopify Web Design and Development Blog

Jeff-Blake
Shopify Partner
41 0 8

@_JB , wouldn't Shopify be fetching the stock every hour or so and eventually seeing the SKU in the response and adjusting the inventory accordingly? 

Jeff-Blake
Shopify Partner
41 0 8

@_JB I created two more orders, and not seeing expected behavior.

 

First of all, after your test order, yes -1 was removed manually, but what about the first order at 12:31pm? There is no matching -1 adjustment for that.

 

Expectations:

- Original inventory was 10

- There are 5 completed, unfulfilled orders

- fetch_stock is returning 5

- Shopify should be showing out of stock, or 0/10 remaining

 

I'm not seeing any -1 Manually Removed adjustments for the orders I create via the Online Store, or Admin. Somehow you got it to trigger the -1 behavior (Order 1004, but I couldn't for either Order 1002, 1005, 1006

_JB
Shopify Staff
Shopify Staff
836 99 215

Hey @Jeff-Blake,

 

For the 2 test orders you created, one adjustment was made at 3:26pm for order 1006. I'm checking our logs and the number being returned for this SKU on fetch_stock requests keeps changing, so the system is only adjusting when the number returned is greater than the number Shopify shows+ pending unfulfilled. Here's the timeline:

 

11:36 am- I created order #1004, which decremented the quantity in Shopify to 8

12:26 pm- Fetch_stock occurs. Your response = qty 8. Shopify = qty 8+ 1 pending unfulfilled. Inventory in Shopify decremented to 7.

2:38 pm- Order #1005 created, inventory in Shopify decremented to 6.

2:50 pm- Order #1006 created, inventory in Shopify decremented to 5.

3:25pm- Fetch_stock occurs. This time, your response returned qty 6 for this variant. Shopify had 5+2 pending unfulfilled so 7. Since your response returned qty 6, Shopify decremented by 1 to bring the variant to it's current stock level of 4.

 

With regards to your expectations, keep in mind that Shopify only accounts for the pending unfulfilled orders once. Once an adjustment is made to account for a pending_unfulfilled unit, we don't make that adjustment again on future fetch_stock calls.

 

At this point it's difficult to say why this didn't work as expected on the original test order, but since our logs show inconsistent responses on the initial fetch_stocks after that order was placed, I recommend testing from scratch on a new variant. If you can setup a new variant or remove these test orders and reset the stock from the variant we've been testing with, I can verify in our logs that the fetch_stock response matches expectations and we should see the expected behaviour. If we don't see the expected behaviour, a new example will allow us to investigate further by being aware of any pending unfulfilled orders for that variant.

JB | Solutions Engineer @ Shopify 
 - Was your question answered? Mark it as an Accepted Solution
 - To learn more visit Shopify.dev or the Shopify Web Design and Development Blog

Jeff-Blake
Shopify Partner
41 0 8

@_JB Thanks for helping me through this. I've made the code changes to reflect how it should work, and I'm now seeing the opposite (wrong) behavior).

 

 

Here's the timeline.

 

Store: event-ticketing-integration-testing-leave-alone.myshopify.com

Variant: 31336084504650 ("inv test")

SKU: 15744

Date: This morning, November 22nd

 

7:32AM PST: SKU added with inventory 10. fetch_stock returns {"15740":5,"15742":5,"15743":4,"15744":10}

Inventory is 10 in Shopify.

 

7:33AM PST: Order #1005 placed for 1 item. 

Inventory is 9 in Shopify.

 

7:33-8:28AM PST: Order remains unfulfilled, no calls to fetch_stock logged. Inventory is correct @9

 

8:28AM PST: Shopify calls fetch_stock and application returns {"15740":5,"15742":5,"15743":4,"15744":10}

 

Inventory is now 10 in Shopify. (it should stay at 9!) 

10 returned from fetch_stock - 1 pending unfulfilled = Shopify inventory should be 9.

 

Screen Shot 2019-11-22 at 8.57.17 AM.png

Inventory history: https://event-ticketing-integration-testing-leave-alone.myshopify.com/admin/products/4388137140298/v...

 

Please advise. Thanks.

 

jayknott
Shopify Partner
5 0 1

Hi everyone,

 

I am experiencing the same behavior. Isn't this an incorrect behavior?  As a "Fulfillment Service" I provide fulfillment products and services to a wide range of stores. When an order comes though my system I respond back to Shopify's fetch_stock request with an updated stock number based on pending orders.  If I didn't do this, then other stores with the same product would show and inflated amount of available stock and possibly cause order issues. This means that I now have to track pending stock for each store and reply to fetch_stock different depending on if the store has pending orders or not.  Seems like this introduces a place for errors to happen.

Dyego_Costa
Shopify Partner
6 1 11

@_JB is this a new behavior? I've recently started receiving a lot of reports from multiple merchants claiming their inventory was not reflecting their apps'. I double checked our fetch_stock.json responses to Shopify requests and confirmed we're returning the correct (or what it used to be correct) inventory.

 

When an order is placed in Shopify we sync it to our app and decrease the inventory from the items of that order, that's how we've always done it.

 

Should we change the behavior of our fetch_stock.json endpoint to stop considering unfulfilled quantities from shopify orders?

jayknott
Shopify Partner
5 0 1

@_JB  Can we get an update on this for the last few questions.  This behavior doesn't make sense when tracking inventory across multiple Shopify stores and we even track inventory across multiple platforms (not just Shopify).

_JB
Shopify Staff
Shopify Staff
836 99 215

Hey @Dyego_Costa,

 

Should we change the behavior of our fetch_stock.json endpoint to stop considering unfulfilled quantities from shopify orders?

This behaviour isn't new, but yes you should definitely change this behaviour on your end since Shopify already accounts for pending unfulfilled orders. The assumption being made here is that your FulfillmentService will decrement inventory at the moment the item ships, so when Shopify makes a fetch_stock request it's expected for the response count to include pending unfulfilled items.

 

Our documentation here outlines the best practices to use with the fetch_stock endpoint.

 

Hey @jayknott,

 

The purpose of the hourly fetch_stock call is to keep inventory levels in sync between Shopify and your warehouse, particularly when units from the warehouse are being sold outside Shopify. If a unit sells from another store/platform, you can respond to fetch_stock with a decremented number, and Shopify will adjust accordingly. The current behaviour makes it so that when building, you don't need to account for pending unfulfilled orders in Shopify. If you're selling through other platforms or connecting a single warehouse to multiple Shopify stores, you may need to build out your own logic to "commit" sold inventory, so that Shopify is made aware of the new inventory level in the hourly fetch_stock request.

JB | Solutions Engineer @ Shopify 
 - Was your question answered? Mark it as an Accepted Solution
 - To learn more visit Shopify.dev or the Shopify Web Design and Development Blog

Colin_M
Shopify Partner
2 0 0

The assumption being made here is that your FulfillmentService will decrement inventory at the moment the item ships, so when Shopify makes a fetch_stock request it's expected for the response count to include pending unfulfilled items.

Hi @_JB, we've experienced the exact same thing as @Dyego_Costa. We implemented the fulfillment service on the 2017 API and everything was great and now recently we are getting complaints that inventory is off. Here is what is happening currently:

 

  • Customer places order in Shopify.
  • Shopify creates new Fulfillment, we receive notice via webhook from Shopify.
  • We create a new order in the WMS and then call 'fulfillments/:id/open.json' to mark the fulfillment as received/processing.
    • At this point the WMS has deducted the order from the available amount as it is now reserved for that order. The reserved inventory is not advertised in the response to `fetch_stock.json`.
  • The order is split into one or more shipments which are eventually each picked and packed.
  • We PUT the tracking numbers back to the fulfillment as shipments are packed.
  • Once the last shipment is complete we call 'fulfillments/:id/complete.json' to mark the Shopify fulfillment as complete.

Is this incorrect? There is a lot of mixed terminology floating around here.. Can you clarify what "pending unfulfilled orders" means to Shopify? E.g. does it transition from "unfulfilled" to "fulfilled" after `open.json` or `complete.json`?

 

Thanks!

Colin

_JB
Shopify Staff
Shopify Staff
836 99 215

Hey @Colin_M,

 

Your current flow requires a change to how you're responding to fetch_stock. The golden rule here is:

 

Fetch_stock expects your response to include inventory for any items on existing orders that have a fulfillment_status of null or unfulfilled in Shopify.

 

From your description, it sounds like your fetch_stock response doesn't isn't including these numbers right now, since you're not advertising the "unavailable" inventory to Shopify. From Shopify's perspective, your fetch_stock response should include any units that are still physically located at your warehouse and have not been shipped.

 

The fulfillment_status for line items will change to fulfilled once you complete the fulfillment. At this point it's assumed the items are no longer in your warehouse, and shouldn't be included in the fetch_stock response.

 

Definitely agree that all the terminology floating around can make this hard to decipher. Let me know if there's anything I can clarify further.

JB | Solutions Engineer @ Shopify 
 - Was your question answered? Mark it as an Accepted Solution
 - To learn more visit Shopify.dev or the Shopify Web Design and Development Blog

Colin_M
Shopify Partner
2 0 0

Hi @_JB,

 

There is no "unfulfilled" status listed in the docs, only these:

 

  • pending: The fulfillment is pending.
  • open: The fulfillment has been acknowledged by the service and is in processing.
  • success: The fulfillment was successful.
  • cancelled: The fulfillment was cancelled.
  • error: There was an error with the fulfillment request.
  • failure: The fulfillment request failed.

Please clarify your statement as it relates to the above status names.

 

For what it's worth, when testing individual orders it seems to work as I'm expecting which is the "open" status is not subtracted from the Shopify inventory (e.g. if we return 99 to fetch_stock then 99 is available for sale while the one fulfillment for the item is in "open" status). In production with thousands of orders in different statuses it is hard to verify this but this is what we're seeing with our test environment.

 

Thanks,

Colin

_JB
Shopify Staff
Shopify Staff
836 99 215

Hey @Colin_M,

 

The statuses you mentioned relate to the actual fulfillment object. Fulfillments can have a status of pending, open, success, etc.

 

What I mentioned was in reference to the line_items on an order. When an order is created, each line_item has it's own fulfillment status (usually starts as null). Until the line_item's fulfillment_status is changed to fulfilled, you need to include that unit of inventory in your fetch_stock response. A line_item's fulfillment status will change to fulfilled once a fulfillment for that item has been completed ( status:success for the fulfillment object)

. If you're seeing unexpected results, the first thing to check is make sure the store isn't using the same SKU value on multiple variants. If they are, this will product unexpected results, and will need to be changed so that each SKU value is only used once. If that doesn't explain it, please provide an example of a variant_id including the expected vs actual inventory count in the Shopify admin, and the response on the fetch_stock call.

JB | Solutions Engineer @ Shopify 
 - Was your question answered? Mark it as an Accepted Solution
 - To learn more visit Shopify.dev or the Shopify Web Design and Development Blog

Diluka
New Member
1 0 0

@_JB 

I ran into the exact same situation as above. I didn't fulfill any order, so inventory kept returning the same number, but Shopify miscalculated and went up and down.