← back to Filemaker Mcp
scripts/bulk-create-greenland-cork.mjs
53 lines
// 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);});