[object Object]

← back to Filemaker Mcp

auto-save: 2026-07-12T07:46:59 (5 files) — scripts/_gl_recon.mjs scripts/_gl_recon2.mjs scripts/_gl_recon3.mjs scripts/bulk-create-greenland-cork.mjs scripts/bulk-series-cork-to-dwgl.mjs

b7ae2b75574bcb4689a42d736a9d349ed47be323 · 2026-07-12 07:47:02 -0700 · Steve Abrams

Files touched

Diff

commit b7ae2b75574bcb4689a42d736a9d349ed47be323
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Sun Jul 12 07:47:02 2026 -0700

    auto-save: 2026-07-12T07:46:59 (5 files) — scripts/_gl_recon.mjs scripts/_gl_recon2.mjs scripts/_gl_recon3.mjs scripts/bulk-create-greenland-cork.mjs scripts/bulk-series-cork-to-dwgl.mjs
---
 scripts/_gl_recon.mjs                  | 11 +++++++
 scripts/_gl_recon2.mjs                 | 18 ++++++++++++
 scripts/_gl_recon3.mjs                 | 14 +++++++++
 scripts/bulk-create-greenland-cork.mjs | 52 ++++++++++++++++++++++++++++++++++
 scripts/bulk-series-cork-to-dwgl.mjs   | 21 ++++++++++++++
 5 files changed, 116 insertions(+)

diff --git a/scripts/_gl_recon.mjs b/scripts/_gl_recon.mjs
new file mode 100644
index 0000000..96c36ab
--- /dev/null
+++ b/scripts/_gl_recon.mjs
@@ -0,0 +1,11 @@
+import * as fm from '../src/fm-client.js';
+const FULL = '*List Wallpapers - Full View';
+const byCork = await fm.findRecords('WALLPAPER', FULL, { 'combo sku': 'CORK*' }, { limit: 5 }).catch(e=>({records:[],err:e.fmCode}));
+console.log('existing combo sku CORK*:', byCork.records?.length ?? 0, byCork.err||'');
+byCork.records?.slice(0,3).forEach(r=>console.log('   combo=',r.fieldData['combo sku'],'| Mfr=',r.fieldData['Mfr Pattern'],'| Series=',r.fieldData['Series'],'| Supplier=',r.fieldData['Supplier'],'| Name=',r.fieldData['Name of Pattern']));
+const pr = await fm.findRecords('WALLPAPER', FULL, { 'Supplier': 'Phillipe Romano' }, { limit: 3 }).catch(e=>({records:[],err:e.fmCode}));
+console.log('existing Supplier=Phillipe Romano:', pr.records?.length ?? 0, pr.err||'');
+pr.records?.slice(0,3).forEach(r=>console.log('   combo=',r.fieldData['combo sku'],'| Mfr=',r.fieldData['Mfr Pattern'],'| Series=',r.fieldData['Series'],'| Name=',r.fieldData['Name of Pattern'],'| vid=',r.fieldData['vid']));
+const any = pr.records?.[0] || byCork.records?.[0];
+if (any) console.log('KEY FIELDS:', Object.keys(any.fieldData).filter(k=>/pattern|color|series|supplier|width|vid|jpg|combo|name|sku|mfr/i.test(k)).join(' | '));
+else console.log('(no sample record to list fields)');
diff --git a/scripts/_gl_recon2.mjs b/scripts/_gl_recon2.mjs
new file mode 100644
index 0000000..1c98799
--- /dev/null
+++ b/scripts/_gl_recon2.mjs
@@ -0,0 +1,18 @@
+import * as fm from '../src/fm-client.js';
+const FULL = '*List Wallpapers - Full View';
+// how are existing DW SKUs stored? sample any record to see combo format + supplier values
+const s = await fm.findRecords('WALLPAPER', FULL, { 'combo sku': 'CORK98*' }, { limit: 3 }).catch(e=>({records:[],err:e.fmCode}));
+console.log('CORK98* (existing PR cork line):', s.records?.length ?? 0, s.err||'');
+s.records?.slice(0,3).forEach(r=>console.log('   combo=',r.fieldData['combo sku'],'| Supplier=',r.fieldData['Supplier'],'| Series=',r.fieldData['Series'],'| Name=',r.fieldData['Name of Pattern']));
+// try Corkytown by name
+const c = await fm.findRecords('WALLPAPER', FULL, { 'Name of Pattern': 'Corkytown*' }, { limit: 3 }).catch(e=>({records:[],err:e.fmCode}));
+console.log('Name=Corkytown*:', c.records?.length ?? 0, c.err||'');
+c.records?.slice(0,3).forEach(r=>console.log('   combo=',r.fieldData['combo sku'],'| Supplier=',r.fieldData['Supplier'],'| Series=',r.fieldData['Series'],'| Mfr=',r.fieldData['Mfr Pattern']));
+// what supplier values look like "phillipe" / "romano"?
+for (const q of ['Phillipe*','*Romano*','Phillip*']) {
+  const r = await fm.findRecords('WALLPAPER', FULL, { 'Supplier': q }, { limit: 2 }).catch(e=>({records:[],err:e.fmCode}));
+  console.log(`Supplier ${q}:`, r.records?.length??0, r.records?.[0]?.fieldData?.['Supplier']||'');
+}
+// grab ANY record to confirm field names + combo-dash convention
+const any = await fm.findRecords('WALLPAPER', FULL, { 'combo sku': 'DWKK*' }, { limit: 1 }).catch(e=>({records:[]}));
+if(any.records?.[0]) console.log('sample DWKK combo:', any.records[0].fieldData['combo sku'], '| ALL keys:', Object.keys(any.records[0].fieldData).slice(0,40).join(','));
diff --git a/scripts/_gl_recon3.mjs b/scripts/_gl_recon3.mjs
new file mode 100644
index 0000000..ac22d8c
--- /dev/null
+++ b/scripts/_gl_recon3.mjs
@@ -0,0 +1,14 @@
+import * as fm from '../src/fm-client.js';
+const FULL = '*List Wallpapers - Full View';
+// bare fetch — list a few records, no filter
+try {
+  const r = await fm.listRecords ? await fm.listRecords('WALLPAPER', FULL, { limit: 3 }) : null;
+  if(r) console.log('listRecords works:', r.records?.length);
+} catch(e){ console.log('no listRecords', e.message); }
+// try a findRecords with a very broad query
+for (const q of [{'Supplier':'*'}, {'combo sku':'*'}]) {
+  try { const r = await fm.findRecords('WALLPAPER', FULL, q, { limit: 2 });
+    console.log('query', JSON.stringify(q), '→', r.records?.length, 'records');
+    if(r.records?.[0]){ const f=r.records[0].fieldData; console.log('   combo sku=',f['combo sku'],'| Supplier=',f['Supplier']); console.log('   FIELD KEYS:', Object.keys(f).join(' | ').slice(0,600)); break; }
+  } catch(e){ console.log('query', JSON.stringify(q), 'ERR', e.fmCode||e.message); }
+}
diff --git a/scripts/bulk-create-greenland-cork.mjs b/scripts/bulk-create-greenland-cork.mjs
new file mode 100644
index 0000000..d8baae1
--- /dev/null
+++ b/scripts/bulk-create-greenland-cork.mjs
@@ -0,0 +1,52 @@
+// Create FileMaker WALLPAPER master records for the Greenland→Phillipe Romano cork line.
+// One record per SKU: Series=CORK, JS Pattern & Mfr Pattern = mfr code, Name=<City> Cork
+// Wallcovering, Color, Width, vid=GL. combo sku auto-calcs to CORK-<mfr> (= Shopify DW SKU).
+// Idempotent: skips any SKU already in WALLPAPER (Series=CORK + that Mfr Pattern).
+//   node bulk-create-greenland-cork.mjs            # DRY-RUN (plan)
+//   node bulk-create-greenland-cork.mjs --apply [--limit=N]
+import { execFileSync } from 'node:child_process';
+import * as fm from '../src/fm-client.js';
+
+const APPLY = process.argv.includes('--apply');
+const LIMIT = parseInt((process.argv.find(a => a.startsWith('--limit=')) || '').split('=')[1] || '0', 10);
+const ENTRY = 'Add wallcovering', FULL = '*List Wallpapers - Full View';
+const PSQL = process.env.PSQL_BIN || '/opt/homebrew/opt/postgresql@14/bin/psql';
+const sleep = ms => new Promise(r => setTimeout(r, ms));
+
+const CITY = { S300:'Montauk', H171:'Nantucket', G0174:'Newport', S176:'Sag Harbor', G0181:'Cape May', G0155:'Palm Beach', G0111:'Kiawah', G0110:'Hilton Head', G0182:'Chatham', G0154:'Southampton', G0148:'Amagansett', H192:"Martha's Vineyard" };
+const seriesOf = m => (String(m).match(/^[A-Za-z]+[0-9]{2,4}/) || [''])[0];
+const tc = s => (s || '').replace(/\w\S*/g, w => w[0].toUpperCase() + w.slice(1).toLowerCase()).trim();
+const widthOf = w => { const m = String(w||'').match(/([\d.]+)/); return m ? `${Math.round(parseFloat(m[1]))}"` : ''; };
+
+const rows = JSON.parse(execFileSync(PSQL, ['dw_unified','-tAc',
+  `select coalesce(json_agg(json_build_object('mfr',trim(mfr_sku),'color',color_name,'pattern',pattern_name,'wi',width_inches,'rep',pattern_repeat) order by trim(mfr_sku))::text,'[]')
+   from greenland_catalog`], { encoding:'utf8', maxBuffer:64e6 }).trim());
+
+async function exists(mfr) {
+  const r = await fm.findRecords('WALLPAPER', FULL, { 'Series':'CORK', 'Mfr Pattern':'=='+mfr }, { limit:1 }).catch(()=>({records:[]}));
+  return (r.records?.length||0) > 0;
+}
+
+async function main() {
+  let todo = rows.filter(r => r.mfr && CITY[seriesOf(r.mfr)]);
+  if (LIMIT) todo = todo.slice(0, LIMIT);
+  console.log(`greenland_catalog cork rows: ${rows.length} · mappable: ${todo.length} · ${APPLY?'APPLY':'DRY-RUN'}`);
+  let ok=0, skip=0, fail=0;
+  for (const r of todo) {
+    const city = CITY[seriesOf(r.mfr)];
+    const color = tc(r.color || r.pattern || '');
+    const fd = { Series:'CORK', 'JS Pattern':r.mfr, 'Mfr Pattern':r.mfr,
+      'Name of Pattern':`${city} Cork Wallcovering`, 'Color of Pattern':color,
+      Width: widthOf(r.wi ? r.wi+'' : ''), vid:'GL' };
+    if (r.rep) fd.Repeat = r.rep;
+    if (!APPLY) { if (ok<5) console.log(`  [${r.mfr}] ${fd['Name of Pattern']} (${color}) w=${fd.Width} vid=GL`); ok++; continue; }
+    try {
+      if (await exists(r.mfr)) { skip++; continue; }
+      await fm.createRecord('WALLPAPER', ENTRY, fd, { dryRun:false });
+      ok++; if (ok%25===0) console.log(`  ...created ${ok} (skip ${skip}, fail ${fail})`);
+      await sleep(120);
+    } catch (e) { fail++; console.error(`  FAIL ${r.mfr}: ${e.fmCode||e.message}`); await sleep(300); }
+  }
+  console.log(`\nDONE. ${APPLY?'created':'planned'}=${ok} skipped=${skip} fail=${fail}`);
+}
+main().catch(e=>{console.error(e);process.exit(1);});
diff --git a/scripts/bulk-series-cork-to-dwgl.mjs b/scripts/bulk-series-cork-to-dwgl.mjs
new file mode 100644
index 0000000..ad8e88c
--- /dev/null
+++ b/scripts/bulk-series-cork-to-dwgl.mjs
@@ -0,0 +1,21 @@
+// Update the Greenland cork WALLPAPER records: Series 'CORK' -> 'DWGL' so the DW SKU
+// (combo sku) becomes DWGL-<mfr>. Idempotent (finds remaining CORK+GL rows each pass).
+//   node bulk-series-cork-to-dwgl.mjs --apply
+import * as fm from '../src/fm-client.js';
+const APPLY = process.argv.includes('--apply');
+const ENTRY = 'Add wallcovering', FULL = '*List Wallpapers - Full View';
+const sleep = ms => new Promise(r => setTimeout(r, ms));
+
+let ok = 0, fail = 0;
+for (let pass = 0; pass < 20; pass++) {
+  const r = await fm.findRecords('WALLPAPER', FULL, { Series: '==CORK', vid: 'GL' }, { limit: 100 }).catch(() => ({ records: [] }));
+  const recs = r.records || [];
+  if (!recs.length) break;
+  console.log(`pass ${pass + 1}: ${recs.length} CORK records`);
+  if (!APPLY) { console.log('DRY-RUN — pass --apply'); break; }
+  for (const rec of recs) {
+    try { await fm.updateRecord('WALLPAPER', ENTRY, rec.recordId, { Series: 'DWGL' }, { dryRun: false }); ok++; if (ok % 25 === 0) console.log(`  ...${ok}`); await sleep(90); }
+    catch (e) { fail++; console.error(`  FAIL ${rec.recordId}: ${e.fmCode || e.message}`); await sleep(250); }
+  }
+}
+console.log(`\nDONE. updated=${ok} fail=${fail}`);

← 81207d4 chore: v0.2.2 (session close — invoice mfr backfill + flag-o  ·  back to Filemaker Mcp  ·  auto-save: 2026-07-12T08:17:05 (1 files) — scripts/bulk-set- c23bb05 →