[object Object]

← back to Filemaker Mcp

add read-only dry-run pipeline test: proves 1-invoice-per-order + zero per-SKU dups on latest Shopify orders

7b8fa26845b6c4729eadf218dcb373696ff0aae4 · 2026-07-07 07:22:09 -0700 · Steve Abrams

Files touched

Diff

commit 7b8fa26845b6c4729eadf218dcb373696ff0aae4
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Tue Jul 7 07:22:09 2026 -0700

    add read-only dry-run pipeline test: proves 1-invoice-per-order + zero per-SKU dups on latest Shopify orders
---
 scripts/test-sync-dryrun.mjs | 47 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/scripts/test-sync-dryrun.mjs b/scripts/test-sync-dryrun.mjs
new file mode 100644
index 0000000..4fb9c8f
--- /dev/null
+++ b/scripts/test-sync-dryrun.mjs
@@ -0,0 +1,47 @@
+// READ-ONLY end-to-end test of the order->invoice pipeline on THIS host.
+// Fetches the N most recent Shopify orders and runs syncOrder(commit:false) on
+// each — proving the fixed code would create exactly ONE invoice per order and
+// NO per-SKU "second invoice" (createSkuRecords). No writes, no Slack posts.
+//
+//   node scripts/test-sync-dryrun.mjs        # last 5 orders
+//   node scripts/test-sync-dryrun.mjs 8
+import { readFileSync } from 'node:fs';
+import { fileURLToPath } from 'node:url';
+import { dirname, join } from 'node:path';
+import { syncOrder } from '../lib/sync-core.js';
+
+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];
+}
+const STORE = process.env.FM_SHOPIFY_STORE || process.env.SHOPIFY_STORE;
+const TOKEN = process.env.SHOPIFY_ORDERS_TOKEN;
+const N = parseInt(process.argv[2] || '5', 10);
+
+async function main() {
+  if (!STORE || !TOKEN) throw new Error('SHOPIFY_STORE / SHOPIFY_ORDERS_TOKEN not set');
+  const url = `https://${STORE}/admin/api/2024-10/orders.json?status=any&limit=${N}`;
+  const r = await fetch(url, { headers: { 'X-Shopify-Access-Token': TOKEN } });
+  if (!r.ok) throw new Error(`Shopify fetch failed: ${r.status}`);
+  const orders = (await r.json()).orders || [];
+  console.log(`\n=== DRY-RUN pipeline test — ${orders.length} most-recent orders (NO writes, NO Slack) ===\n`);
+
+  let pass = 0, fail = 0;
+  for (const o of orders) {
+    const items = (o.line_items || []).length;
+    try {
+      const res = await syncOrder(o, { commit: false });
+      // The fix guarantees exactly one invoice and zero per-SKU second-invoice records.
+      const ok = res.action === 'would-process' && (res.skuRecords ?? 0) === 0;
+      console.log(`#${o.order_number}  ${(o.customer?.first_name||'')+' '+(o.customer?.last_name||'')}`.padEnd(34)
+        + `${items} line-item(s) → ${ok ? '1 invoice' : '??'}  · perSKU-dups=${res.skuRecords ?? 0}`
+        + `  · client=${res.client}${res.matchedOn ? ' (matched '+res.matchedOn.join('/')+')' : ''}  ${ok ? 'PASS ✓' : 'FAIL ✗'}`);
+      ok ? pass++ : fail++;
+    } catch (e) {
+      console.log(`#${o.order_number}  ERROR: ${e.message}  FAIL ✗`); fail++;
+    }
+  }
+  console.log(`\n=== RESULT: ${pass} PASS / ${fail} FAIL — one-invoice-per-order ${fail ? 'NOT ' : ''}confirmed ===`);
+  process.exit(fail ? 1 : 0);
+}
+main().catch((e) => { console.error('test error:', e.message, e.fmCode || ''); process.exit(1); });

← 4b94f5f audit: add --csv export (both categories, per-invoice rows)  ·  back to Filemaker Mcp  ·  auto-save: 2026-07-07T08:56:34 (2 files) — scripts/tmp-probe f3f4718 →