@@ -325,6 +325,103 @@ const VARIANT_BULK_UPDATE = `
325325 }
326326` ;
327327
328+ // ---------------------------------------------------------------------------
329+ // Inventory queries & mutations
330+ // ---------------------------------------------------------------------------
331+
332+ const LOCATIONS_QUERY = `
333+ query GetLocations {
334+ locations(first: 1) {
335+ edges { node { id name } }
336+ }
337+ }
338+ ` ;
339+
340+ const VARIANT_INVENTORY_ITEMS = `
341+ query VariantInventoryItems($productId: ID!) {
342+ product(id: $productId) {
343+ variants(first: 100) {
344+ edges {
345+ node {
346+ id
347+ sku
348+ inventoryItem { id }
349+ }
350+ }
351+ }
352+ }
353+ }
354+ ` ;
355+
356+ const INVENTORY_SET_QUANTITIES = `
357+ mutation InventorySetQuantities($input: InventorySetQuantitiesInput!) {
358+ inventorySetQuantities(input: $input) {
359+ inventoryAdjustmentGroup { reason }
360+ userErrors { field message }
361+ }
362+ }
363+ ` ;
364+
365+ let cachedLocationId : string | null = null ;
366+
367+ async function getPrimaryLocationId ( ) : Promise < string > {
368+ if ( cachedLocationId ) return cachedLocationId ;
369+ const data = await adminGraphQL ( LOCATIONS_QUERY ) ;
370+ const loc = data ?. locations ?. edges ?. [ 0 ] ?. node ;
371+ if ( ! loc ) throw new Error ( "No Shopify locations found. Create a location first." ) ;
372+ cachedLocationId = loc . id ;
373+ console . log ( ` 📍 Primary location: ${ loc . name } (${ loc . id } )` ) ;
374+ return loc . id ;
375+ }
376+
377+ async function setInventoryQuantities (
378+ productId : string ,
379+ variants : { sku : string ; inventoryQty : number } [ ] ,
380+ tag : string
381+ ) {
382+ const locationId = await getPrimaryLocationId ( ) ;
383+
384+ // Fetch inventoryItemIds for the product's variants
385+ const data = await adminGraphQL ( VARIANT_INVENTORY_ITEMS , { productId } ) ;
386+ const variantEdges = data ?. product ?. variants ?. edges || [ ] ;
387+
388+ const quantities : { inventoryItemId : string ; locationId : string ; quantity : number } [ ] = [ ] ;
389+
390+ for ( const edge of variantEdges ) {
391+ const node = edge . node ;
392+ const inventoryItemId = node . inventoryItem ?. id ;
393+ if ( ! inventoryItemId ) continue ;
394+
395+ // Match by SKU or by position
396+ const csvMatch = variants . find ( ( v ) => v . sku && v . sku === node . sku ) ;
397+ const qty = csvMatch ?. inventoryQty ?? variants [ variantEdges . indexOf ( edge ) ] ?. inventoryQty ;
398+
399+ if ( qty !== undefined && qty >= 0 ) {
400+ quantities . push ( { inventoryItemId, locationId, quantity : qty } ) ;
401+ }
402+ }
403+
404+ if ( quantities . length === 0 ) return ;
405+
406+ try {
407+ const result = await adminGraphQL ( INVENTORY_SET_QUANTITIES , {
408+ input : {
409+ name : "available" ,
410+ reason : "correction" ,
411+ quantities,
412+ } ,
413+ } ) ;
414+ const errors = result ?. inventorySetQuantities ?. userErrors ;
415+ if ( errors ?. length ) {
416+ console . warn ( ` ⚠️ ${ tag } inventory warnings:` , errors ) ;
417+ } else {
418+ console . log ( ` 📦 ${ tag } : set inventory for ${ quantities . length } variant(s)` ) ;
419+ }
420+ } catch ( invErr : any ) {
421+ console . warn ( ` ⚠️ ${ tag } inventory update failed: ${ invErr . message } ` ) ;
422+ }
423+ }
424+
328425// ---------------------------------------------------------------------------
329426// Sync logic
330427// ---------------------------------------------------------------------------
@@ -454,6 +551,14 @@ async function syncProduct(product: ProductGroup, index: number) {
454551 }
455552 }
456553 }
554+ // 3. Set inventory quantities at the primary location
555+ if ( variantEdges ?. length > 0 && product . variants . some ( ( v ) => v . inventoryQty > 0 ) ) {
556+ await setInventoryQuantities (
557+ productId ,
558+ product . variants . map ( ( v ) => ( { sku : v . sku , inventoryQty : v . inventoryQty } ) ) ,
559+ tag
560+ ) ;
561+ }
457562
458563 return { status : existing ? "updated" : "created" , handle : product . handle } ;
459564}
0 commit comments