Covers all questions related to inventory management, order fulfillment, and shipping.
I've spent hours reading the migration guide, docs, forum posts, and more, and I'm hardly closer to understanding how to properly migrate to fulfillment orders for API v2022-07 than when I started. We don't seem to fully fit any of the models described, and much of the information is unclear or lacking in enough detail. I'm sincerely hoping that someone can provide some specific guidance for our scenarios.
Overview
Our system sits in between a "wholesale" Shopify store and many client Shopify stores. It gets inventory values from the wholesale store and updates client Shopify stores. It also get orders from the client Shopify stores and creates analogous orders on the wholesale store for fulfillment. When an order is fulfilled on the wholesale store, the system pushes the fulfillment info (tracking, etc.) back to the source client store and marks the appropriate order line items as fulfilled. All this is accomplished with a custom/private app between our system and the wholesale store, and a published (unlisted) app that is installed by all client stores.
Workflow 1 - Receive & Store Wholesale Fulfillment Info
Step one in the process is to receive and persist wholesale fulfillment info, which will then be pushed in the next workflow to the analogous order on the client store that placed the order. Our wholesale store private app has registered the fulfillments/create webhook. When an order's line items are fulfilled, we get the webhook payload and save it in our database. The structure of this data is a `fulfillments` table and a `fulfillment_line_items` table with foreign key linking it to the `fulfillments` table. These two tables essentially represent the Shopify Fulfillments resource from the perspective of the wholesale store, where the `fulfillments` table primarily stores the shopify fulfillment ID and tracking info, and the `fulfillment_line_items` table stores the internal ID for the line item and the quantity that was fulfilled.
Migration Questions:
Workflow 2 - Send Fulfillment Info to Client Stores
With the wholesale order fulfillment information stored, we now need to push the fulfillment data back to the store that originally placed the order. This is done via the REST API's `[POST] /orders/{order_id}/fulfillments` endpoint. We then take the response data and save it to our database. The structure of this data is essentially the same as wholesale order fulfillments, except that there's a different `shop_fulfillments` table for the main Fulfillment record. Since the wholesale order and client store orders are analogous, at least for our purposes, the original `fulfillment_line_items` table from workflow 1 also includes a foreign key to this `shop_fulfillments` table. So, these two tables together represent a Fulfillment resource, but from the perspective of the client store. All of this info is saved internally because our client stores may log into our system directly to perform various actions and view data, such as their orders and order fulfillment statuses.
Migration Questions:
Conclusion & Final Questions
I'm not even sure if I'm asking the right questions because there is still gap in my understanding of FulfillmentOrders and what aspects of fulfillments are being replaced by fulfillment orders. There are other aspects of the migration that are discussed in various documents and articles that I'm not even sure how or if they apply. My main, remaining questions/concerns are:
A huge thank you to anyone who is willing to answer any of my questions. Or, if skipping the bulk of my questions and just cutting to the chase based on my described workflows and goals makes more sense, that's great too. Either way, drinks are on me.
I've found more info on my permissions question, and I think my original assumption is correct. FWIW, and for anyone who also had questions about fulfillment orders permissions, the Shopify API access scopes documentation page provides a bit more information that helped me better understand these. The options, according tot he migration guide, include:
So, assuming your app is like mine and has NOT registered a fulfillment service on merchant stores, and you're just managing fulfillment orders created for items in a merchant-managed location, then I think that the [read/write]_merchant_managed_fulfillment_orders is all you need. If your app is managing all fulfillments on a merchant store, then you likely need *_merchant_managed_fulfillment_orders AND *_third_party_fulfillment_orders. And, finally, if your app is registered as a fulfillment service, then you'd need the *_assigned_fulfillment_orders permission to manage fulfillment orders in your own fulfillment service's location.
After scouring additional sources of information and a bunch of trial and error, I think I can now answer most of my own questions. I'm posting in case someone can correct me, and/or for reference by others who may have similar questions. Referring back to my original post:
Workflow 1
Workflow 2
Final Questions
Hopefully this puts me on the right track! Corrections and/or additional information are welcome and appreciated.
Hi,
Thank you for your questions and suggestions. Your guesses are correct. I will answer all your questions in detail soon. Just one clarification question first.
Do I understand your case correctly that client stores do not own inventory, and when the customer places an order, the wholesale store is asked to fulfill and ship this order directly to the customer? The client store is more like a storefront for placing orders. Does the backward integration happen only to update the order status and shipping information for the customer and the store owner?
Also, a reworked FulfillmentOrder resource documentation will be released in a few days, and it will cover about the half of your questions.
To learn more visit the Shopify Help Center or the Community Blog.
Hi @Michael_AG,
Do I understand your case correctly that client stores do not own inventory, and when the customer places an order, the wholesale store is asked to fulfill and ship this order directly to the customer? The client store is more like a storefront for placing orders.
Yes, that is correct. When an order is placed by a customer on the merchant's store, our app receives the order and "passes" it to (by creating a new, corresponding order on) the wholesale store. Then, the order is fulfilled/shipped via the wholesale store directly to the customer.
Does the backward integration happen only to update the order status and shipping information for the customer and the store owner?
Exactly. The fulfillment information is passed from wholesale back to the app, and then the app marks the corresponding order items on the merchant's store as fulfilled. So, essentially, our app is the middle man and is storing (and creating in the case of the merchant) both the wholesale fulfillment resource info and the merchant shop's fulfillment resource info.
I've completed implementation of the new FulfillmentOrders paradigm based on my findings and assumptions listed in this thread and will be deploying this weekend. Thanks for confirming that my final understanding was correct. I look forward to seeing updated docs on this topic.
> Fulfillment Service
As you do not create a fulfillment service entity for every shop your app work with, your app is not a fulfillment service. In terms of permissions and interactions with client shops, you are an order management app. You manage orders from merchant-managed locations, take care of them being fulfilled, and close them. So you do not need assigned_fulfillment_orders access scope. I see you have managed to get merchant_managed_fulfillment_orders access scope with request_granular_access_scopes based on the read/write_orders access scope you have had. That's it. I'll think about how we can improve steps 1-2 in the migration guide to make it more clear.
Your app could be a fulfillment service app and offer the same service. Merchants communicate with fulfillment service apps via fulfillment and cancellation requests, and the fulfillment service app has an option to reject requests.
> Can (should) we continue to use the fulfillments/create webhook to get fulfillment notifications from wholesale? Even the latest API version still includes this webhook topic, so it doesn't appear to be deprecated.
That's right. The Fulfillment resource and fulfillment webhooks remain. When some or all of order line items are fulfilled, you will receive `fulfillments/create` webhook.
> The `[POST] orders/{order_id}/fulfillments` endpoint has been deprecated. It appears that the `[POST] /fulfillments` endpoint is the closest replacement for this action. Is this the best method?
Right. FulfillmentOrder entity stays in the middle of orders and fulfillments, and now we granularly fulfill fulfillment orders rather then orders directly.
> The `[POST] /fulfillments` endpoint requires passing fulfilled line items by FulfillmentOrderID. At what point is a FulfillmentOrder created? Who creates it and how?
Shopify creates fulfillment orders automatically when an order is created. It is not possible to manually create fulfillment orders.
> Correct me if I'm wrong, but neither the fulfillments/create payload nor the Fulfillments resource via the REST API include the ID of the parent FulfillmentOrder resource.
Fulfillment entity does not contain fulfillment_order_id. The thing here is, the relationship between Fulfillments and FulfillmentOrders on the same order is many-to-many. One FulfillmentOrder may be fulfilled via several partial Fulfillments. One Fulfillment can contain line items from several fulfillment orders on the same order. See
FulfillmentV2Input.lineItemsByFulfillmentOrder (same for the REST api).
So the question you ask is "How do I map line items from the client store order to the items fulfilled by the wholesale store".
1. You receive the "fulfillments/create" webhook from the wholesale site. The webhook gives you the fulfillment_id and order_id.
2. You map this order_id to the client's order_id (you keep this mapping in your DB). Your query GET /order/<client_shop_order_id>/fulfillment_orders on the client shop.
3. If there is only one FulfillmentOrder in the client's shop on this order and in the wholesale store has fulfilled the entire order at once, you can fulfill the whole order on the client site with POST /fulfillments
{
"fulfillment": {
"line_items_by_fulfillment_order": [
{
"fulfillment_order_id": <client_site_fulfillment_order_id>
}
]
}
}
To learn more visit the Shopify Help Center or the Community Blog.