1 | |
2 |
|
3 | |
4 | * Hold Fulfillment Order |
5 | * Put a fulfillment order on hold so it can't be fulfilled until the hold is released. Pass line_items ({ id, quantity } of fulfillment order line items) to hold only part of it; the rest is split into remainingFulfillmentOrder. Up to 10 holds per app per fulfillment order. |
6 | */ |
7 | export async function main( |
8 | auth: RT.Shopify, |
9 | fulfillment_order_id: string, |
10 | reason: |
11 | | "AWAITING_PAYMENT" |
12 | | "HIGH_RISK_OF_FRAUD" |
13 | | "INCORRECT_ADDRESS" |
14 | | "INVENTORY_OUT_OF_STOCK" |
15 | | "UNKNOWN_DELIVERY_DATE" |
16 | | "AWAITING_RETURN_ITEMS" |
17 | | "OTHER", |
18 | reason_notes: string | undefined, |
19 | notify_merchant: boolean | undefined, |
20 | handle: string | undefined, |
21 | line_items: { id: string; quantity: number }[] | undefined |
22 | ) { |
23 | const response = await fetch( |
24 | `https://${auth.store_name}.myshopify.com/admin/api/2026-10/graphql.json`, |
25 | { |
26 | method: "POST", |
27 | headers: { |
28 | "X-Shopify-Access-Token": auth.token, |
29 | "Content-Type": "application/json", |
30 | Accept: "application/json", |
31 | }, |
32 | body: JSON.stringify({ |
33 | query: `mutation ($id: ID!, $fulfillmentHold: FulfillmentOrderHoldInput!) { fulfillmentOrderHold(id: $id, fulfillmentHold: $fulfillmentHold) { fulfillmentHold { id reason reasonNotes handle } fulfillmentOrder { id status } remainingFulfillmentOrder { id status } userErrors { field message } } }`, |
34 | variables: { |
35 | id: fulfillment_order_id.startsWith("gid://") |
36 | ? fulfillment_order_id |
37 | : `gid://shopify/FulfillmentOrder/${fulfillment_order_id}`, |
38 | fulfillmentHold: { |
39 | reason, |
40 | reasonNotes: reason_notes || undefined, |
41 | notifyMerchant: notify_merchant || undefined, |
42 | handle: handle || undefined, |
43 | fulfillmentOrderLineItems: line_items?.length |
44 | ? line_items.map((li) => ({ |
45 | id: li.id.startsWith("gid://") |
46 | ? li.id |
47 | : `gid://shopify/FulfillmentOrderLineItem/${li.id}`, |
48 | quantity: li.quantity, |
49 | })) |
50 | : undefined, |
51 | }, |
52 | }, |
53 | }), |
54 | } |
55 | ) |
56 |
|
57 | if (!response.ok) { |
58 | throw new Error(`${response.status} ${await response.text()}`) |
59 | } |
60 |
|
61 | const { data, errors } = await response.json() |
62 | if (errors) { |
63 | throw new Error(JSON.stringify(errors)) |
64 | } |
65 |
|
66 | if (data.fulfillmentOrderHold.userErrors.length) { |
67 | throw new Error(JSON.stringify(data.fulfillmentOrderHold.userErrors)) |
68 | } |
69 |
|
70 | return data.fulfillmentOrderHold |
71 | } |
72 |
|