feat(migration): add expenses + interest EOI status to NocoDB→CRM pipeline
A single idempotent --apply now seeds the full legacy dataset: - Expenses: fetch the separate "Expenses" NocoDB base (mxfcefkk4dqs6uq), transform (price→amount+currency, payment status, receipt marker), apply to the expenses table under a new nocodb_expenses ledger tag. - Interest EOI display state: set interests.eoiStatus/eoiDocStatus from the legacy EOI Status / LOI process so deals show signed / awaiting-signature (in-flight) state, not only a separate documents row. - Runner reports expenses + tags createdBy with the seeded super-admin id. Validated via --apply on the dev DB: 239 clients (multi-deal grouping intact), 255 interests (qualified 171/eoi 51/nurturing 30/reservation 2/contract 1), 48 signed + 3 in-flight EOIs, 165 expenses (5 currencies), 41 docs + 119 signers, 45 residential. tsc clean; 67 dedup unit tests pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -30,6 +30,7 @@ import { eq } from 'drizzle-orm';
|
||||
|
||||
import { db } from '@/lib/db';
|
||||
import { ports } from '@/lib/db/schema/ports';
|
||||
import { SUPER_ADMIN_USER_ID } from '@/lib/db/seed-bootstrap';
|
||||
import { applyPlan } from '@/lib/dedup/migration-apply';
|
||||
import { fetchSnapshot, loadNocoDbConfig } from '@/lib/dedup/nocodb-source';
|
||||
import { transformSnapshot } from '@/lib/dedup/migration-transform';
|
||||
@@ -154,7 +155,7 @@ async function main(): Promise<void> {
|
||||
const snapshot = await fetchSnapshot(config);
|
||||
const elapsed = ((Date.now() - start) / 1000).toFixed(1);
|
||||
console.log(
|
||||
`[migrate] Snapshot fetched in ${elapsed}s — ${snapshot.interests.length} interests, ${snapshot.residentialInterests.length} residential, ${snapshot.berths.length} berths.`,
|
||||
`[migrate] Snapshot fetched in ${elapsed}s — ${snapshot.interests.length} interests, ${snapshot.residentialInterests.length} residential, ${snapshot.berths.length} berths, ${snapshot.expenses?.length ?? 0} expenses.`,
|
||||
);
|
||||
|
||||
console.log('[migrate] Running transform + dedup pipeline…');
|
||||
@@ -184,6 +185,7 @@ async function main(): Promise<void> {
|
||||
console.log(
|
||||
` ${s.outputResidentialClients} residential clients (with default-stage interests)`,
|
||||
);
|
||||
console.log(` ${s.outputExpenses} expenses`);
|
||||
console.log(
|
||||
` Dedup: ${s.autoLinkedClusters} auto-linked clusters, ${s.needsReviewPairs} pairs flagged for review`,
|
||||
);
|
||||
@@ -208,7 +210,7 @@ async function main(): Promise<void> {
|
||||
console.log('[migrate] Inserting…');
|
||||
|
||||
const applyStart = Date.now();
|
||||
const result = await applyPlan(plan, { port, applyId });
|
||||
const result = await applyPlan(plan, { port, applyId, appliedBy: SUPER_ADMIN_USER_ID });
|
||||
const applyElapsed = ((Date.now() - applyStart) / 1000).toFixed(1);
|
||||
|
||||
console.log('');
|
||||
@@ -231,6 +233,9 @@ async function main(): Promise<void> {
|
||||
` Res-Clt: ${result.residentialClientsInserted} inserted, ${result.residentialClientsSkipped} already linked`,
|
||||
);
|
||||
console.log(` Res-Int: ${result.residentialInterestsInserted} inserted`);
|
||||
console.log(
|
||||
` Expenses: ${result.expensesInserted} inserted, ${result.expensesSkipped} already linked`,
|
||||
);
|
||||
|
||||
if (result.warnings.length > 0) {
|
||||
console.log('');
|
||||
|
||||
Reference in New Issue
Block a user