[object Object]

← back to Designer Wallcoverings

fix luxury importer: nextNumber reads staging max (no SKU reuse) + mirror-repair destructure + boolean coercion

1b49549326075a9838971bcaf80696c4eb35b6e1 · 2026-07-09 20:25:52 -0700 · Steve

Files touched

Diff

commit 1b49549326075a9838971bcaf80696c4eb35b6e1
Author: Steve <steve@designerwallcoverings.com>
Date:   Thu Jul 9 20:25:52 2026 -0700

    fix luxury importer: nextNumber reads staging max (no SKU reuse) + mirror-repair destructure + boolean coercion
---
 .../luxury-draft-import/import-luxury-drafts.js    | 39 +++++++++++++++++++---
 1 file changed, 34 insertions(+), 5 deletions(-)

diff --git a/shopify/scripts/luxury-draft-import/import-luxury-drafts.js b/shopify/scripts/luxury-draft-import/import-luxury-drafts.js
index 0c110b7b..ef19bca8 100644
--- a/shopify/scripts/luxury-draft-import/import-luxury-drafts.js
+++ b/shopify/scripts/luxury-draft-import/import-luxury-drafts.js
@@ -117,13 +117,16 @@ mutation ps($input: ProductSetInput!) {
   }
 }`;
 
-async function nextNumber(prefix) {
-  // highest existing suffix in registry OR shopify_products, +1; fresh lines start at 100001
+async function nextNumber(prefix, table) {
+  // highest existing suffix across registry, shopify_products, AND the staging table, +1.
+  // Staging MUST be included — a stamped-but-unmirrored row would otherwise let the number be reused. (bug fix 2026-07-09)
   const reg = psql(`SELECT COALESCE(MAX((regexp_replace(dw_sku,'^${prefix}-?',''))::int),0)
                     FROM dw_sku_registry WHERE dw_sku ~ '^${prefix}-?[0-9]+$'`) || '0';
   const shp = psql(`SELECT COALESCE(MAX((regexp_replace(sku,'^${prefix}-?','','i'))::int),0)
                     FROM shopify_products WHERE sku ~* '^${prefix}-?[0-9]+$'`) || '0';
-  const hi = Math.max(parseInt(reg, 10) || 0, parseInt(shp, 10) || 0);
+  const stg = psql(`SELECT COALESCE(MAX((regexp_replace(dw_sku,'^${prefix}-?',''))::int),0)
+                    FROM ${table} WHERE dw_sku ~ '^${prefix}-?[0-9]+$'`) || '0';
+  const hi = Math.max(parseInt(reg, 10) || 0, parseInt(shp, 10) || 0, parseInt(stg, 10) || 0);
   return hi >= 100000 ? hi + 1 : 100001; // fresh range
 }
 
@@ -160,13 +163,39 @@ async function nextNumber(prefix) {
     return;
   }
 
-  let num = await nextNumber(CFG.prefix);
+  // Mirror-repair: any staging row already stamped (dw_sku + shopify_product_id) but missing from
+  // shopify_products (e.g. a prior run created the Shopify product but the mirror INSERT failed).
+  const orphans = psql(`SELECT s.id, s.dw_sku, s.shopify_product_id, s.mfr_sku, s.pattern_name
+      FROM ${CFG.table} s
+      WHERE s.dw_sku IS NOT NULL AND s.shopify_product_id IS NOT NULL
+        AND NOT EXISTS (SELECT 1 FROM shopify_products p WHERE p.shopify_id = s.shopify_product_id)`)
+    .split('\n').filter(Boolean);
+  if (orphans.length) {
+    console.log(`Mirror-repair: ${orphans.length} stamped rows missing from shopify_products — re-syncing from live Shopify.`);
+    for (const line of orphans) {
+      const [, dw, pid, mfr, pat] = line.split('\x1f'); // cols: id, dw_sku, shopify_product_id, mfr_sku, pattern_name
+      const rr = await gql(`{ product(id:"gid://shopify/Product/${pid}") { handle title status vendor productType tags bodyHtml featuredImage{url} } }`);
+      const p = rr?.data?.product;
+      if (!p) { console.log(`  ✗ live product ${pid} not found for ${dw}`); continue; }
+      psql(`INSERT INTO shopify_products
+              (shopify_id, handle, title, vendor, product_type, sku, dw_sku, mfr_sku, vendor_prefix,
+               tags, status, image_url, pattern_name, body_html, has_sample_variant, synced_at)
+            VALUES ('${q(pid)}','${q(p.handle)}','${q(p.title)}','${q(p.vendor)}','${q(p.productType)}',
+               '${q(dw)}','${q(dw)}','${q(mfr)}','${CFG.prefix}',
+               '${q((p.tags || []).join(', '))}','${q((p.status || 'DRAFT').toLowerCase())}',
+               '${q(p.featuredImage?.url || '')}','${q(pat || mfr)}','${q(p.bodyHtml || '')}', true, now())
+            ON CONFLICT DO NOTHING`);
+      console.log(`  ✓ mirror-synced ${dw}`);
+    }
+  }
+
+  let num = await nextNumber(CFG.prefix, CFG.table);
   console.log(`Starting SKU: ${CFG.prefix}-${num}\n`);
   let ok = 0, fail = 0, batch = 0;
 
   for (const r of work) {
     const dwSku = `${CFG.prefix}-${num}`;
-    const isPriced = CFG.priced && r.price && parseFloat(r.price) > 0;
+    const isPriced = !!(CFG.priced && r.price && parseFloat(r.price) > 0);
     const isQuote = !isPriced;
     const title = buildTitle(r);
     if (/unknown/i.test(title)) { console.log(`  ✗ SKIP (Unknown in title): ${r.mfr_sku}`); fail++; continue; }

← 217795cb add luxury-line DRAFT importer (Fromental/Gracie/Zuber, quot  ·  back to Designer Wallcoverings  ·  auto-save: 2026-07-09T20:42:07 (53 files) — DW-Programming/I 1566feb7 →