/** * Full-APEX importer CLI (D20): `npm run import:full -- --dir [--commit]` * Reads the nine workbook CSVs from (all optional except clients.csv), * prints the per-section stage report (problems block commit; notes are the * deliberate skips/merges), and — only with --commit and a problem-free report — * applies everything in one transaction. Without --commit it is a dry run that * writes nothing and needs no HQ_SECRET_KEY. DB path comes from HQ_DATA_DIR (run * from the repo root otherwise — the default resolves ./data from CWD). NEVER * prints credential values — the report carries counts and row numbers only. */ import fs from 'node:fs' import path from 'node:path' import { formatINR } from '@sims/domain' import { openDb } from '../src/db' import { seedIfEmpty } from '../src/seed' import { APEX_FILES, commitApexFull, stageApexFull } from '../src/import-apex-full' void (async () => { const args = process.argv.slice(2) const dirIdx = args.indexOf('--dir') const dir = dirIdx >= 0 ? args[dirIdx + 1] : undefined if (dir === undefined) { console.error('Usage: npm run import:full -- --dir [--commit]') process.exit(1) } const files: Record = {} for (const name of APEX_FILES) { const p = path.join(dir, `${name}.csv`) if (fs.existsSync(p)) files[name] = fs.readFileSync(p, 'utf8') } if (files['clients'] === undefined) { console.error(`clients.csv not found in ${dir} — it is the one required file (SID_NO is the join key)`) process.exit(1) } const absent = APEX_FILES.filter((n) => files[n] === undefined) if (absent.length > 0) console.log(`Not present (skipped): ${absent.join(', ')}`) const db = openDb(process.env['HQ_DATA_DIR']) await seedIfEmpty(db) const keyHex = process.env['HQ_SECRET_KEY'] ?? '' const { sections, summary } = await stageApexFull(db, files, keyHex) let problemTotal = 0 for (const section of APEX_FILES) { const r = sections[section] if (r.staged === 0 && r.problems.length === 0 && r.notes.length === 0) continue console.log(`${section}: ${r.staged} staged, ${r.problems.length} problem(s), ${r.notes.length} note(s)`) for (const p of r.problems) console.log(` ! ${p}`) for (const n of r.notes) console.log(` - ${n}`) problemTotal += r.problems.length } console.log('---') console.log(`Plan: ${summary.clients} clients, ${summary.client_modules} module assignments, ${summary.branches} branches,`) console.log(` ${summary.documents} documents totalling ${formatINR(summary.totalPayablePaise)} payable, ${summary.payments} payments,`) console.log(` ${summary.tickets} tickets, ${summary.interactions} interactions;`) console.log(` INVOICE series seed for ${summary.currentFy}: ${summary.seedTail ?? 'none (no current-FY docs)'}`) if (!args.includes('--commit')) { console.log('Dry run — nothing written. Re-run with --commit to apply.') } else if (problemTotal > 0) { console.error(`Refusing to commit: ${problemTotal} problem(s) above — fix the CSVs and re-run.`) process.exitCode = 1 } else { const counts = await commitApexFull(db, 'system', files, keyHex) console.log('Committed:', JSON.stringify(counts, null, 2)) } await db.close() })()