← back to Dw Photo Capture
TK-12162: mint checks vendor catalog reservations + confirms the number is free LIVE (FileMaker + Shopify)
67566bdba43c8a5a7fa6ac42b379eb46a16bcada · 2026-09-24 17:19:56 -0700 · Steve Abrams
The mint's sources are all mirrors (shopify_products last synced 09-23) and none read the
vendor scrape catalog, which pre-assigns dw_skus (tres_tintas_catalog: DWTS-900001..901506).
So a mint could hand out a reserved number, or the same number twice before a sync.
- adds vendor_registry.catalog_table reservations to the used-number set
- JS Pattern is TEXT in FileMaker (no reliable max), so the chosen number is verified free by an
exact live FileMaker find + Shopify SKU prefix search, stepping past taken numbers (max 25);
if a live source can't answer, the mint still returns but carries a flag
- tested read-only on prod: 901507 taken=true, 987654 taken=false, DWTT-72290 taken=true,
Tres Tintas mint -> DWTS-901514, clear of both reserved ranges
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Files touched
Diff
commit 67566bdba43c8a5a7fa6ac42b379eb46a16bcada
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Thu Sep 24 17:19:56 2026 -0700
TK-12162: mint checks vendor catalog reservations + confirms the number is free LIVE (FileMaker + Shopify)
The mint's sources are all mirrors (shopify_products last synced 09-23) and none read the
vendor scrape catalog, which pre-assigns dw_skus (tres_tintas_catalog: DWTS-900001..901506).
So a mint could hand out a reserved number, or the same number twice before a sync.
- adds vendor_registry.catalog_table reservations to the used-number set
- JS Pattern is TEXT in FileMaker (no reliable max), so the chosen number is verified free by an
exact live FileMaker find + Shopify SKU prefix search, stepping past taken numbers (max 25);
if a live source can't answer, the mint still returns but carries a flag
- tested read-only on prod: 901507 taken=true, 987654 taken=false, DWTT-72290 taken=true,
Tres Tintas mint -> DWTS-901514, clear of both reserved ranges
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---
server.js | 38 +++++++++++++++++++++++++++++++++++++-
1 file changed, 37 insertions(+), 1 deletion(-)
diff --git a/server.js b/server.js
index ff90349..aa9f3c0 100644
--- a/server.js
+++ b/server.js
@@ -2757,10 +2757,46 @@ async function mintDwSku(vreg) {
if (fmq.ok) for (const r of fmq.rows) { const n = parseInt(r[0], 10); if (Number.isFinite(n)) used.add(n); }
const stg = await pgQuery(`select regexp_replace(dw_sku,'^${esc}','')::text from new_items_staging where to_regclass('public.new_items_staging') is not null and dw_sku ~ '^${esc}[0-9]+$'`);
if (stg.ok) for (const r of stg.rows) { const n = parseInt(r[0], 10); if (Number.isFinite(n)) used.add(n); }
+ // the vendor's own scrape catalog pre-assigns dw_skus to products not yet on Shopify/FM
+ // (tres_tintas_catalog reserves DWTS-900001..901506) — those numbers are taken too.
+ const cat = await pgQuery(`select catalog_table from vendor_registry where vendor_code='${String(vreg.vid || '').replace(/'/g, "''")}' limit 1`);
+ const catTable = cat.ok && cat.rows[0] && /^[a-z0-9_]+$/.test(cat.rows[0][0] || '') ? cat.rows[0][0] : null;
+ if (catTable) {
+ const cq = await pgQuery(`select regexp_replace(dw_sku,'^${esc}','')::text from ${catTable} where to_regclass('public.${catTable}') is not null and dw_sku ~ '^${esc}[0-9]+$'`);
+ if (cq.ok) for (const r of cq.rows) { const n = parseInt(r[0], 10); if (Number.isFinite(n)) used.add(n); }
+ }
const maxUsed = used.size ? Math.max(...used) : 0;
let n = Math.max(vreg.sku_range_start || 0, maxUsed + 1, 1);
while (used.has(n)) n++;
- return { dw_sku: `${prefix}${n}`, series: pfxNoDash, js_pattern: String(n), provisional: false, flag: null };
+ // Every source above is a mirror that can lag the live systems by a day. JS Pattern is a TEXT field
+ // in FileMaker, so "max" can't be asked of it reliably — instead confirm the chosen number is free
+ // LIVE (exact FileMaker match + Shopify SKU prefix search) and step past any number that is taken.
+ let liveFlag = null;
+ for (let tries = 0; tries < 25; tries++) {
+ const taken = await liveNumberTaken(pfxNoDash, n);
+ if (taken === null) { liveFlag = `could not confirm ${prefix}${n} is free in live FileMaker/Shopify — verify before go-live`; break; }
+ if (!taken) break;
+ n++; while (used.has(n)) n++;
+ }
+ return { dw_sku: `${prefix}${n}`, series: pfxNoDash, js_pattern: String(n), provisional: false, flag: liveFlag };
+}
+
+// true = the number is already used live, false = free, null = a live source could not answer.
+async function liveNumberTaken(series, n) {
+ let fmTaken, shopTaken;
+ try {
+ const r = await FM.fmFind(FM_DB, FM_WP_CREATE_LAYOUT, [{ 'Series': '==' + series, 'JS Pattern': '==' + n }], { limit: 1, portal: [] });
+ fmTaken = (r.records || r.data || []).length > 0;
+ } catch (e) { fmTaken = /\b401\b|no records match/i.test(e.message) ? false : null; }
+ try {
+ const q = `{ productVariants(first: 10, query: "sku:${series}-${n}*") { edges { node { sku } } } }`;
+ const b = await gql(q);
+ if (!b.data) shopTaken = null;
+ else shopTaken = b.data.productVariants.edges.some(e => new RegExp(`^${series}-${n}(\\D|$)`).test(e.node.sku || ''));
+ } catch (e) { shopTaken = null; }
+ if (fmTaken === true || shopTaken === true) return true;
+ if (fmTaken === null || shopTaken === null) return null;
+ return false;
}
// ── FileMaker WALLPAPER master fieldData builder ─────────────────────────────
← 2bc55d4 TK-12162: 582 FileMaker masters created for live Tres Tintas
·
back to Dw Photo Capture
·
auto-data-snapshot: 2026-09-24T20:29:39 (2 data files) — .cl e99e554 →