← back to Filemaker Mcp
scripts/fix-invoice-102332.mjs
74 lines
// One-off: repair invoice #102332 (Shopify order #32494).
// Usage: node scripts/fix-invoice-102332.mjs [--find-only] [--commit]
// Default (no flags) = find the record and show a dry-run diff; --commit writes.
import { readFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
const __dir = dirname(fileURLToPath(import.meta.url));
for (const line of readFileSync(join(__dir, '..', '.env'), 'utf8').split('\n')) {
const m = line.match(/^([A-Z_]+)=(.*)$/);
if (m && !process.env[m[1]]) process.env[m[1]] = m[2];
}
const { findRecords, fieldMetadata, updateRecord, getRecord } = await import('../src/fm-client.js');
const DB = 'invoice';
const LAYOUT = 'Order Detail';
const INVOICE_NO = '102332';
const findOnly = process.argv.includes('--find-only');
const commit = process.argv.includes('--commit');
const meta = await fieldMetadata(DB, LAYOUT);
const names = (meta.fieldMetaData || meta.response?.fieldMetaData || []).map((f) => f.name || f);
console.log('FIELDS:', JSON.stringify(names));
// locate the invoice-number field name on this layout
const invField = names.find((n) => /invoice/i.test(n) && /#|no|num/i.test(n)) ||
names.find((n) => /^invoice$/i.test(n));
if (!invField) { console.error('No invoice-number field found on layout — see FIELDS above.'); process.exit(2); }
console.log('Using invoice field:', invField);
const { records } = await findRecords(DB, LAYOUT, { [invField]: `==${INVOICE_NO}` }, { limit: 5 });
if (!records.length) { console.error('Invoice not found.'); process.exit(3); }
console.log(`Matches: ${records.length}`);
const rec = records[0];
console.log('recordId:', rec.recordId);
console.log('fieldData:', JSON.stringify(rec.fieldData, null, 1));
if (findOnly) process.exit(0);
// --- corrections (ground truth: Shopify #32494 3×131.95 −59.37 +44.50 ship = 380.98 paid;
// #32500 1×131.95 −19.79 free ship = 112.16 paid; total paid 493.14 = current PAID ON ACCOUNT, correct) ---
// Line 1: show RETAIL unit price (131.95), qty 4 → TOTAL calc 527.80
// Line 2: same qty, JS# "Discount at 15%", NET −19.79/unit → −79.16
// 527.80 − 79.16 = 448.64 merch (unchanged) + 44.50 ship = 493.14 paid, NET DUE 0
const fieldData = {
'NET 1(1)': 131.95,
'Q1(2)': 4,
'Unit 1(2)': 'S/R',
'DETAIL 1(2)': 'Discount at 15%',
'NET 1(2)': -19.79,
};
const res = await updateRecord(DB, LAYOUT, rec.recordId, fieldData, { dryRun: !commit });
console.log(commit ? 'COMMITTED:' : 'DRY RUN DIFF:', JSON.stringify(res, null, 1));
// RETAIL columns live on the canonical header layout (Otto's convention: invoice shows RETAIL)
const HDR = 'Invoice to Client Copy';
const retail = { 'RETAIL 1(1)': 131.95, 'RETAIL 1(2)': -19.79 };
const res2 = await updateRecord(DB, HDR, rec.recordId, retail, { dryRun: !commit });
console.log(commit ? 'COMMITTED (RETAIL):' : 'DRY RUN DIFF (RETAIL):', JSON.stringify(res2.changes ?? res2, null, 1));
if (commit) {
const after = await getRecord(DB, LAYOUT, rec.recordId);
const f = after.fieldData;
console.log('VERIFY:', JSON.stringify({
'Q1(2)': f['Q1(2)'], 'DETAIL 1(2)': f['DETAIL 1(2)'], 'NET 1(2)': f['NET 1(2)'],
'PAID ON ACCOUNT': f['PAID ON ACCOUNT'],
'MERCHANDISE TOTAL': f['MERCHANDISE TOTAL'], 'NET DUE 2': f['NET DUE 2'],
}, null, 1));
}