← 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
A scripts/test-sync-dryrun.mjs
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 →