← back to Filemaker Mcp

scripts/backfill-blank-mfr.mjs

48 lines

// Backfill VID + Detail 1 Mfr Number onto EXISTING Otto-imported invoice lines that
// have a blank mfr (the pre-hook backlog — orders Otto invoiced before ensureWallpaper
// was wired into the live path). For each distinct SKU: ensureWallpaper() once (creates/
// completes its FileMaker WALLPAPER master from dw_unified), then direct-write the
// copy-lookup fields onto every blank-mfr line carrying that SKU. SKUs with no findable
// mfr stay FLAGGED (Steve's rule — never guessed). See memory
// filemaker-wallpaper-record-for-invoice. Reuses lib/wallpaper.js ensureWallpaper().
//
//   node scripts/backfill-blank-mfr.mjs [--dry-run]
import { readFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..');
for (const l of readFileSync(join(ROOT, '.env'), 'utf8').split('\n')) {
  const m = l.match(/^([A-Z0-9_]+)=(.*)$/); if (m && !process.env[m[1]]) process.env[m[1]] = m[2].replace(/^['"]|['"]$/g, '');
}
const DRY = process.argv.includes('--dry-run');
const fm = await import('../src/fm-client.js');
const { ensureWallpaper, resolveWallpaperSource } = await import('../lib/wallpaper.js');
const ISHIP = 'Order Detail - Main - Shipping';
const combo = (f) => ((f['WC Pattern Number AKA DW SKU(1)'] ?? f['WC Pattern Number AKA DW SKU'] ?? '') + '').trim();

// 1. Find the backlog: Otto-imported invoice lines with a blank Detail 1 Mfr Number.
const { records } = await fm.findRecords('invoice', ISHIP, [{ 'Notes': 'Otto', 'Detail 1 Mfr Number': '=' }], { limit: 1000 });
const lines = records.filter((r) => combo(r.fieldData)); // must have a SKU to resolve
const bySku = new Map();
for (const rec of lines) { const s = combo(rec.fieldData); if (!bySku.has(s)) bySku.set(s, []); bySku.get(s).push(rec); }
console.log(`${DRY ? '[DRY-RUN] ' : ''}backlog: ${records.length} blank-mfr Otto records; ${lines.length} have a SKU; ${bySku.size} distinct SKU(s)\n`);

let updated = 0, wpOk = 0, flagged = 0; const flagList = [];
for (const [sku, recs] of bySku) {
  // DRY = read-only resolve (no FileMaker writes); LIVE = ensureWallpaper (creates/completes master).
  const wp = DRY ? await resolveWallpaperSource(sku) : await ensureWallpaper(sku);
  if (!wp.ok) { flagged++; flagList.push(`${sku} (${wp.reason})`); console.log(`  FLAG ${sku}: ${wp.reason}  [${recs.length} line(s) left blank]`); continue; }
  wpOk++;
  if (DRY) { console.log(`  WOULD  ${sku}  mfr=${wp.mfr} vid=${wp.vid}  -> ${recs.length} line(s)  [${wp.src}]`); updated += recs.length; continue; }
  for (const rec of recs) {
    try { await fm.updateRecord('invoice', ISHIP, rec.recordId, { 'VID': wp.vid || '', 'Detail 1 Mfr Number': wp.mfr }, { dryRun: false }); updated++; }
    catch (e) { console.log(`  ${sku} inv line err ${e.fmCode}`); }
  }
  console.log(`  OK   ${sku}  mfr=${wp.mfr} vid=${wp.vid}  -> ${recs.length} line(s)  [${wp.src}]`);
}
console.log(`\n=== ${DRY ? 'DRY-RUN ' : ''}SUMMARY ===`);
console.log(`  distinct SKUs resolved (mfr found): ${wpOk}`);
console.log(`  invoice lines ${DRY ? 'that WOULD be' : ''} updated: ${updated}`);
console.log(`  SKUs FLAGGED (no findable mfr, left blank): ${flagged}`);
if (flagList.length) console.log(`  FLAGGED: ${flagList.join(' | ')}`);