1 | |
2 |
|
3 | export type DynSelect_location_id = string |
4 |
|
5 | export async function location_id(auth: RT.Shopify) { |
6 | const response = await fetch( |
7 | `https://${auth.store_name}.myshopify.com/admin/api/2026-10/graphql.json`, |
8 | { |
9 | method: "POST", |
10 | headers: { |
11 | "X-Shopify-Access-Token": auth.token, |
12 | "Content-Type": "application/json", |
13 | Accept: "application/json", |
14 | }, |
15 | body: JSON.stringify({ |
16 | query: `query { locations(first: 250) { nodes { id name } } }`, |
17 | }), |
18 | } |
19 | ) |
20 | if (!response.ok) { |
21 | throw new Error(`${response.status} ${await response.text()}`) |
22 | } |
23 | const { data, errors } = await response.json() |
24 | if (errors) { |
25 | throw new Error(JSON.stringify(errors)) |
26 | } |
27 | return data.locations.nodes.map((l: { id: string; name: string }) => ({ |
28 | value: l.id, |
29 | label: l.name, |
30 | })) |
31 | } |
32 |
|
33 | |
34 | * Update Inventory Level |
35 | * Set the available (or on-hand) quantity of an inventory item at a location. The inventory item ID is on each variant (variant.inventoryItem.id). Pass change_from_quantity (the quantity you expect is there now) to fail instead of overwriting a concurrent change; leave it empty to overwrite unconditionally. The item must be tracked and stocked at the location. |
36 | */ |
37 | export async function main( |
38 | auth: RT.Shopify, |
39 | inventory_item_id: string, |
40 | location_id: DynSelect_location_id, |
41 | quantity: number, |
42 | name: "available" | "on_hand" | undefined, |
43 | reason: |
44 | | "correction" |
45 | | "cycle_count_available" |
46 | | "received" |
47 | | "restock" |
48 | | "damaged" |
49 | | "shrinkage" |
50 | | "quality_control" |
51 | | "promotion" |
52 | | "safety_stock" |
53 | | "movement_created" |
54 | | "movement_updated" |
55 | | "movement_received" |
56 | | "movement_canceled" |
57 | | "reservation_created" |
58 | | "reservation_updated" |
59 | | "reservation_deleted" |
60 | | "other" |
61 | | undefined, |
62 | change_from_quantity: number | undefined, |
63 | reference_document_uri: string | undefined |
64 | ) { |
65 | const inventoryItemId = inventory_item_id.startsWith("gid://") |
66 | ? inventory_item_id |
67 | : `gid://shopify/InventoryItem/${inventory_item_id}` |
68 | const locationId = location_id.startsWith("gid://") |
69 | ? location_id |
70 | : `gid://shopify/Location/${location_id}` |
71 |
|
72 | const response = await fetch( |
73 | `https://${auth.store_name}.myshopify.com/admin/api/2026-10/graphql.json`, |
74 | { |
75 | method: "POST", |
76 | headers: { |
77 | "X-Shopify-Access-Token": auth.token, |
78 | "Content-Type": "application/json", |
79 | Accept: "application/json", |
80 | }, |
81 | body: JSON.stringify({ |
82 | query: `mutation ($input: InventorySetQuantitiesInput!, $key: String!) { inventorySetQuantities(input: $input) @idempotent(key: $key) { inventoryAdjustmentGroup { id createdAt reason referenceDocumentUri changes { name delta quantityAfterChange item { id } location { id name } } } userErrors { field message code } } }`, |
83 | variables: { |
84 | key: crypto.randomUUID(), |
85 | input: { |
86 | name: name || "available", |
87 | reason: reason || "correction", |
88 | referenceDocumentUri: reference_document_uri || undefined, |
89 | quantities: [ |
90 | { |
91 | inventoryItemId, |
92 | locationId, |
93 | quantity, |
94 | |
95 | changeFromQuantity: change_from_quantity ?? null, |
96 | }, |
97 | ], |
98 | }, |
99 | }, |
100 | }), |
101 | } |
102 | ) |
103 |
|
104 | if (!response.ok) { |
105 | throw new Error(`${response.status} ${await response.text()}`) |
106 | } |
107 |
|
108 | const { data, errors } = await response.json() |
109 | if (errors) { |
110 | throw new Error(JSON.stringify(errors)) |
111 | } |
112 | if (data.inventorySetQuantities.userErrors.length) { |
113 | throw new Error(JSON.stringify(data.inventorySetQuantities.userErrors)) |
114 | } |
115 |
|
116 | return data.inventorySetQuantities |
117 | } |
118 |
|