Files
NeoCom/prisma/seed.ts
2026-04-09 20:36:10 -07:00

1759 lines
78 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { PrismaClient, AccountType, RoleType, FiscalPeriodStatus, InvoiceStatus } from "@prisma/client";
import bcrypt from "bcryptjs";
const prisma = new PrismaClient();
async function main() {
console.log("🌱 Starting database seed...");
// Create Organization
console.log("📊 Creating organization...");
const organization = await prisma.organization.create({
data: {
name: "Acme Holdings",
legalName: "Acme Holdings Inc.",
fiscalYearStartMonth: 1,
fiscalYearStartDay: 1,
defaultCurrency: "USD",
timezone: "America/New_York",
},
});
console.log(`✓ Organization created: ${organization.name}`);
// Create Entities
console.log("🏢 Creating entities...");
const acmeSoftware = await prisma.entity.create({
data: {
organizationId: organization.id,
name: "Acme Software Inc",
code: "ACM-US",
type: "SUBSIDIARY",
defaultCurrency: "USD",
status: "ACTIVE",
},
});
const acmeCloud = await prisma.entity.create({
data: {
organizationId: organization.id,
name: "Acme Cloud Services Ltd",
code: "ACM-UK",
type: "SUBSIDIARY",
defaultCurrency: "GBP",
status: "ACTIVE",
},
});
const acmeEurope = await prisma.entity.create({
data: {
organizationId: organization.id,
name: "Acme Europe GmbH",
code: "ACM-DE",
type: "SUBSIDIARY",
defaultCurrency: "EUR",
status: "ACTIVE",
},
});
const acmePacific = await prisma.entity.create({
data: {
organizationId: organization.id,
name: "Acme Pacific Pty Ltd",
code: "ACM-AU",
type: "SUBSIDIARY",
defaultCurrency: "AUD",
status: "ACTIVE",
},
});
const entities = [acmeSoftware, acmeCloud, acmeEurope, acmePacific];
console.log(`✓ Created ${entities.length} entities`);
// Create Roles
console.log("👥 Creating roles...");
const roleConfigs: { name: string; roleType: RoleType }[] = [
{ name: "CEO", roleType: "CEO" },
{ name: "CFO", roleType: "CFO" },
{ name: "Controller", roleType: "CONTROLLER" },
{ name: "Manager", roleType: "MANAGER" },
{ name: "Analyst", roleType: "ANALYST" },
{ name: "Clerk", roleType: "CLERK" },
];
const roles = [];
for (const rc of roleConfigs) {
const role = await prisma.role.create({
data: {
organizationId: organization.id,
name: rc.name,
roleType: rc.roleType,
description: `${rc.name} role`,
isSystem: true,
},
});
roles.push(role);
}
console.log(`✓ Created ${roles.length} roles`);
// Create Admin User
console.log("👤 Creating admin user...");
const hashedPassword = await bcrypt.hash("demo123", 10);
const user = await prisma.user.create({
data: {
organizationId: organization.id,
email: "ryan@acme.com",
passwordHash: hashedPassword,
name: "Ryan Francis",
firstName: "Ryan",
lastName: "Francis",
status: "ACTIVE",
},
});
// Assign CEO role
await prisma.userRole.create({
data: {
userId: user.id,
roleId: roles[0].id,
},
});
console.log(`✓ Admin user created: ${user.email}`);
// Create Chart of Accounts
console.log("📈 Creating chart of accounts...");
const accountsData: { code: string; name: string; type: AccountType; parent: string | null }[] = [
{ code: "1000", name: "Cash and Cash Equivalents", type: "ASSET", parent: null },
{ code: "1010", name: "Operating Account", type: "ASSET", parent: "1000" },
{ code: "1020", name: "Payroll Account", type: "ASSET", parent: "1000" },
{ code: "1100", name: "Accounts Receivable", type: "ASSET", parent: null },
{ code: "1200", name: "Prepaid Expenses", type: "ASSET", parent: null },
{ code: "1500", name: "Fixed Assets", type: "ASSET", parent: null },
{ code: "1550", name: "Accumulated Depreciation", type: "ASSET", parent: null },
{ code: "2000", name: "Accounts Payable", type: "LIABILITY", parent: null },
{ code: "2100", name: "Deferred Revenue", type: "LIABILITY", parent: null },
{ code: "2200", name: "Accrued Liabilities", type: "LIABILITY", parent: null },
{ code: "2500", name: "Long-Term Debt", type: "LIABILITY", parent: null },
{ code: "3000", name: "Common Stock", type: "EQUITY", parent: null },
{ code: "3100", name: "Additional Paid-In Capital", type: "EQUITY", parent: null },
{ code: "3200", name: "Retained Earnings", type: "EQUITY", parent: null },
{ code: "4000", name: "Software Revenue", type: "REVENUE", parent: null },
{ code: "4100", name: "Services Revenue", type: "REVENUE", parent: null },
{ code: "4500", name: "Interest Income", type: "REVENUE", parent: null },
{ code: "5000", name: "Cost of Goods Sold", type: "EXPENSE", parent: null },
{ code: "6000", name: "Operating Expenses", type: "EXPENSE", parent: null },
{ code: "6100", name: "Sales & Marketing", type: "EXPENSE", parent: "6000" },
{ code: "6200", name: "Engineering", type: "EXPENSE", parent: "6000" },
{ code: "6300", name: "General & Administrative", type: "EXPENSE", parent: "6000" },
{ code: "6400", name: "IT & Infrastructure", type: "EXPENSE", parent: "6000" },
{ code: "7000", name: "Interest Expense", type: "EXPENSE", parent: null },
];
// First pass: create all accounts without parents
const accounts: Record<string, any> = {};
for (const a of accountsData) {
const account = await prisma.chartOfAccount.create({
data: {
organizationId: organization.id,
accountCode: a.code,
accountName: a.name,
accountType: a.type,
status: "ACTIVE",
level: a.parent ? 2 : 1,
hierarchy: a.parent ? `${a.parent}/${a.code}` : a.code,
},
});
accounts[a.code] = account;
}
// Second pass: set parent relationships
for (const a of accountsData) {
if (a.parent && accounts[a.parent]) {
await prisma.chartOfAccount.update({
where: { id: accounts[a.code].id },
data: { parentAccountId: accounts[a.parent].id },
});
}
}
console.log(`✓ Created ${accountsData.length} accounts`);
// ========================================
// Create Fiscal Periods for FY2024, FY2025, FY2026
// ========================================
console.log("📅 Creating fiscal periods...");
const months = [
"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December",
];
const allPeriods: Record<string, any> = {};
// FY2024 — all CLOSED
for (let i = 0; i < 12; i++) {
const startDate = new Date(2024, i, 1);
const endDate = new Date(2024, i + 1, 0);
const period = await prisma.fiscalPeriod.create({
data: {
organizationId: organization.id,
fiscalYear: 2024,
periodNumber: i + 1,
periodName: `${months[i]} 2024`,
startDate,
endDate,
status: "CLOSED" as FiscalPeriodStatus,
},
});
allPeriods[`2024-${i + 1}`] = period;
}
// FY2025 — all CLOSED (year is complete)
for (let i = 0; i < 12; i++) {
const startDate = new Date(2025, i, 1);
const endDate = new Date(2025, i + 1, 0);
const period = await prisma.fiscalPeriod.create({
data: {
organizationId: organization.id,
fiscalYear: 2025,
periodNumber: i + 1,
periodName: `${months[i]} 2025`,
startDate,
endDate,
status: "CLOSED" as FiscalPeriodStatus,
},
});
allPeriods[`2025-${i + 1}`] = period;
}
// FY2026 — JanMar CLOSED, AprDec OPEN (current date: April 5, 2026)
for (let i = 0; i < 12; i++) {
const startDate = new Date(2026, i, 1);
const endDate = new Date(2026, i + 1, 0);
const status: FiscalPeriodStatus = i < 3 ? "CLOSED" : "OPEN";
const period = await prisma.fiscalPeriod.create({
data: {
organizationId: organization.id,
fiscalYear: 2026,
periodNumber: i + 1,
periodName: `${months[i]} 2026`,
startDate,
endDate,
status,
},
});
allPeriods[`2026-${i + 1}`] = period;
}
console.log(`✓ Created 36 fiscal periods (FY2024-FY2026)`);
// ========================================
// COMPREHENSIVE JOURNAL ENTRIES
// Spanning Jan 2025 March 2026 across all account types
// ========================================
console.log("📝 Creating comprehensive journal entries...");
let jeCounter = 0;
async function createJE(opts: {
periodKey: string;
date: string;
description: string;
sourceModule: string;
status: "POSTED" | "DRAFT" | "PENDING_APPROVAL";
entityRef: any;
lines: { accountCode: string; debit: number; credit: number; desc: string }[];
}) {
jeCounter++;
const entryNumber = `JE-${opts.date.slice(0, 4)}-${String(jeCounter).padStart(4, "0")}`;
const totalDebits = opts.lines.reduce((s, l) => s + l.debit, 0);
const totalCredits = opts.lines.reduce((s, l) => s + l.credit, 0);
const isPosted = opts.status === "POSTED";
const entryDate = new Date(opts.date);
return prisma.journalEntry.create({
data: {
organizationId: organization.id,
fiscalPeriodId: allPeriods[opts.periodKey].id,
entryNumber,
entryDate,
description: opts.description,
sourceModule: opts.sourceModule,
status: opts.status,
totalDebits,
totalCredits,
isBalanced: totalDebits === totalCredits,
postedAt: isPosted ? entryDate : null,
postedBy: isPosted ? user.id : null,
createdBy: user.name,
journalEntryLines: {
create: opts.lines.map((l, idx) => ({
organizationId: organization.id,
entityId: opts.entityRef.id,
accountId: accounts[l.accountCode].id,
debitAmount: l.debit,
creditAmount: l.credit,
lineNumber: idx + 1,
description: l.desc,
})),
},
},
});
}
// ---- FY2025 MONTHLY JOURNAL ENTRIES ----
// We'll create recurring monthly entries + some one-off transactions
for (let month = 1; month <= 12; month++) {
const mm = String(month).padStart(2, "0");
const periodKey = `2025-${month}`;
const monthName = months[month - 1];
// 1) Monthly Software Revenue (ACM-US) — DR AR, CR Revenue
await createJE({
periodKey,
date: `2025-${mm}-05`,
description: `${monthName} 2025 software license revenue`,
sourceModule: "AR",
status: "POSTED",
entityRef: acmeSoftware,
lines: [
{ accountCode: "1100", debit: 185000, credit: 0, desc: `AR - software licenses ${monthName}` },
{ accountCode: "4000", debit: 0, credit: 185000, desc: `Software revenue ${monthName}` },
],
});
// 2) Monthly Services Revenue (ACM-US) — DR AR, CR Services Revenue
await createJE({
periodKey,
date: `2025-${mm}-08`,
description: `${monthName} 2025 consulting & services revenue`,
sourceModule: "AR",
status: "POSTED",
entityRef: acmeSoftware,
lines: [
{ accountCode: "1100", debit: 92000, credit: 0, desc: `AR - consulting services ${monthName}` },
{ accountCode: "4100", debit: 0, credit: 92000, desc: `Services revenue ${monthName}` },
],
});
// 3) Monthly Cash Collection (ACM-US) — DR Cash, CR AR
await createJE({
periodKey,
date: `2025-${mm}-20`,
description: `${monthName} 2025 customer payments received`,
sourceModule: "AR",
status: "POSTED",
entityRef: acmeSoftware,
lines: [
{ accountCode: "1010", debit: 245000, credit: 0, desc: `Cash received from customers ${monthName}` },
{ accountCode: "1100", debit: 0, credit: 245000, desc: `AR collections ${monthName}` },
],
});
// 4) Monthly COGS (ACM-US) — DR COGS, CR Cash
await createJE({
periodKey,
date: `2025-${mm}-10`,
description: `${monthName} 2025 cost of goods sold`,
sourceModule: "GL",
status: "POSTED",
entityRef: acmeSoftware,
lines: [
{ accountCode: "5000", debit: 55000, credit: 0, desc: `COGS - hosting & delivery ${monthName}` },
{ accountCode: "1010", debit: 0, credit: 55000, desc: `Payment for COGS ${monthName}` },
],
});
// 5) Monthly Engineering Payroll (ACM-US) — DR Engineering, CR Payroll Account
await createJE({
periodKey,
date: `2025-${mm}-25`,
description: `${monthName} 2025 engineering payroll`,
sourceModule: "PAYROLL",
status: "POSTED",
entityRef: acmeSoftware,
lines: [
{ accountCode: "6200", debit: 210000, credit: 0, desc: `Engineering salaries ${monthName}` },
{ accountCode: "1020", debit: 0, credit: 210000, desc: `Payroll disbursement ${monthName}` },
],
});
// 6) Monthly S&M Expenses — DR S&M, CR AP
await createJE({
periodKey,
date: `2025-${mm}-12`,
description: `${monthName} 2025 sales & marketing expenses`,
sourceModule: "AP",
status: "POSTED",
entityRef: acmeSoftware,
lines: [
{ accountCode: "6100", debit: 45000, credit: 0, desc: `Marketing campaigns & sales ops ${monthName}` },
{ accountCode: "2000", debit: 0, credit: 45000, desc: `AP - marketing vendors ${monthName}` },
],
});
// 7) Monthly G&A Expenses — DR G&A, CR AP
await createJE({
periodKey,
date: `2025-${mm}-15`,
description: `${monthName} 2025 general & administrative`,
sourceModule: "AP",
status: "POSTED",
entityRef: acmeSoftware,
lines: [
{ accountCode: "6300", debit: 38000, credit: 0, desc: `Office rent, insurance, admin ${monthName}` },
{ accountCode: "2000", debit: 0, credit: 38000, desc: `AP - G&A vendors ${monthName}` },
],
});
// 8) Monthly IT & Infrastructure — DR IT, CR AP
await createJE({
periodKey,
date: `2025-${mm}-14`,
description: `${monthName} 2025 IT & infrastructure`,
sourceModule: "AP",
status: "POSTED",
entityRef: acmeSoftware,
lines: [
{ accountCode: "6400", debit: 22000, credit: 0, desc: `Cloud hosting, SaaS tools ${monthName}` },
{ accountCode: "2000", debit: 0, credit: 22000, desc: `AP - IT vendors ${monthName}` },
],
});
// 9) Monthly AP Payments — DR AP, CR Cash (pay last month's bills)
await createJE({
periodKey,
date: `2025-${mm}-18`,
description: `${monthName} 2025 vendor payments`,
sourceModule: "AP",
status: "POSTED",
entityRef: acmeSoftware,
lines: [
{ accountCode: "2000", debit: 95000, credit: 0, desc: `AP payments to vendors ${monthName}` },
{ accountCode: "1010", debit: 0, credit: 95000, desc: `Cash disbursed ${monthName}` },
],
});
// 10) Monthly Depreciation — DR Depreciation Expense (G&A), CR Accumulated Depreciation
await createJE({
periodKey,
date: `2025-${mm}-28`,
description: `${monthName} 2025 depreciation expense`,
sourceModule: "GL",
status: "POSTED",
entityRef: acmeSoftware,
lines: [
{ accountCode: "6300", debit: 8500, credit: 0, desc: `Monthly depreciation ${monthName}` },
{ accountCode: "1550", debit: 0, credit: 8500, desc: `Accumulated depreciation ${monthName}` },
],
});
// 11) Monthly Interest on Long-Term Debt — DR Interest Expense, CR Accrued Liabilities
await createJE({
periodKey,
date: `2025-${mm}-28`,
description: `${monthName} 2025 interest expense on long-term debt`,
sourceModule: "GL",
status: "POSTED",
entityRef: acmeSoftware,
lines: [
{ accountCode: "7000", debit: 4200, credit: 0, desc: `Interest on term loan ${monthName}` },
{ accountCode: "2200", debit: 0, credit: 4200, desc: `Accrued interest ${monthName}` },
],
});
// 12) Monthly Interest Income — DR Cash, CR Interest Income (small)
await createJE({
periodKey,
date: `2025-${mm}-28`,
description: `${monthName} 2025 interest income earned`,
sourceModule: "GL",
status: "POSTED",
entityRef: acmeSoftware,
lines: [
{ accountCode: "1010", debit: 1800, credit: 0, desc: `Interest earned on deposits ${monthName}` },
{ accountCode: "4500", debit: 0, credit: 1800, desc: `Interest income ${monthName}` },
],
});
// UK Entity Revenue (quarterly — Q1, Q2, Q3, Q4)
if (month % 3 === 0) {
await createJE({
periodKey,
date: `2025-${mm}-15`,
description: `Q${month / 3} 2025 Acme Cloud UK revenue`,
sourceModule: "AR",
status: "POSTED",
entityRef: acmeCloud,
lines: [
{ accountCode: "1100", debit: 125000, credit: 0, desc: `AR - UK cloud services Q${month / 3}` },
{ accountCode: "4000", debit: 0, credit: 125000, desc: `UK cloud revenue Q${month / 3}` },
],
});
}
// Europe Entity Revenue (quarterly)
if (month % 3 === 0) {
await createJE({
periodKey,
date: `2025-${mm}-16`,
description: `Q${month / 3} 2025 Acme Europe revenue`,
sourceModule: "AR",
status: "POSTED",
entityRef: acmeEurope,
lines: [
{ accountCode: "1100", debit: 95000, credit: 0, desc: `AR - Europe consulting Q${month / 3}` },
{ accountCode: "4100", debit: 0, credit: 95000, desc: `Europe services revenue Q${month / 3}` },
],
});
}
// Pacific Entity Revenue (quarterly)
if (month % 3 === 0) {
await createJE({
periodKey,
date: `2025-${mm}-17`,
description: `Q${month / 3} 2025 Acme Pacific revenue`,
sourceModule: "AR",
status: "POSTED",
entityRef: acmePacific,
lines: [
{ accountCode: "1100", debit: 68000, credit: 0, desc: `AR - Pacific software Q${month / 3}` },
{ accountCode: "4000", debit: 0, credit: 68000, desc: `Pacific software revenue Q${month / 3}` },
],
});
}
}
// ---- ONE-OFF FY2025 ENTRIES ----
// Fixed Asset Purchase (Q1 2025) — DR Fixed Assets, CR Cash
await createJE({
periodKey: "2025-2",
date: "2025-02-15",
description: "Server hardware and office equipment purchase",
sourceModule: "AP",
status: "POSTED",
entityRef: acmeSoftware,
lines: [
{ accountCode: "1500", debit: 350000, credit: 0, desc: "Server hardware, networking gear" },
{ accountCode: "1010", debit: 0, credit: 350000, desc: "Cash payment for fixed assets" },
],
});
// Additional Fixed Asset Purchase (Q3 2025)
await createJE({
periodKey: "2025-8",
date: "2025-08-10",
description: "Office furniture and developer workstations",
sourceModule: "AP",
status: "POSTED",
entityRef: acmeSoftware,
lines: [
{ accountCode: "1500", debit: 125000, credit: 0, desc: "Office furniture & workstations" },
{ accountCode: "1010", debit: 0, credit: 125000, desc: "Cash payment for equipment" },
],
});
// Prepaid Expenses — annual insurance (Jan 2025)
await createJE({
periodKey: "2025-1",
date: "2025-01-05",
description: "Annual business insurance premium prepayment",
sourceModule: "GL",
status: "POSTED",
entityRef: acmeSoftware,
lines: [
{ accountCode: "1200", debit: 96000, credit: 0, desc: "Prepaid D&O and E&O insurance" },
{ accountCode: "1010", debit: 0, credit: 96000, desc: "Cash payment for insurance" },
],
});
// Deferred Revenue Recognition (Q2 2025) — large annual license prepaid
await createJE({
periodKey: "2025-4",
date: "2025-04-01",
description: "Received annual license prepayment from Global Partners",
sourceModule: "AR",
status: "POSTED",
entityRef: acmeSoftware,
lines: [
{ accountCode: "1010", debit: 480000, credit: 0, desc: "Cash received - annual prepayment" },
{ accountCode: "2100", debit: 0, credit: 480000, desc: "Deferred revenue - Global Partners" },
],
});
// Deferred Revenue Recognition monthly (Q2-Q4, 9 months of $53,333)
for (let m = 4; m <= 12; m++) {
const mm = String(m).padStart(2, "0");
await createJE({
periodKey: `2025-${m}`,
date: `2025-${mm}-28`,
description: `${months[m - 1]} 2025 deferred revenue recognition`,
sourceModule: "AR",
status: "POSTED",
entityRef: acmeSoftware,
lines: [
{ accountCode: "2100", debit: 53333, credit: 0, desc: `Deferred rev recognition ${months[m - 1]}` },
{ accountCode: "4000", debit: 0, credit: 53333, desc: `Revenue recognized ${months[m - 1]}` },
],
});
}
// Long-term Debt Drawdown (Mar 2025) — DR Cash, CR Long-Term Debt
await createJE({
periodKey: "2025-3",
date: "2025-03-01",
description: "Term loan drawdown - growth capital",
sourceModule: "GL",
status: "POSTED",
entityRef: acmeSoftware,
lines: [
{ accountCode: "1010", debit: 2000000, credit: 0, desc: "Loan proceeds received" },
{ accountCode: "2500", debit: 0, credit: 2000000, desc: "Term loan - 5yr facility" },
],
});
// Equity Contribution (Jan 2025) — Series B round
await createJE({
periodKey: "2025-1",
date: "2025-01-15",
description: "Series B equity investment received",
sourceModule: "GL",
status: "POSTED",
entityRef: acmeSoftware,
lines: [
{ accountCode: "1010", debit: 5000000, credit: 0, desc: "Series B investment proceeds" },
{ accountCode: "3000", debit: 0, credit: 500000, desc: "Common stock par value" },
{ accountCode: "3100", debit: 0, credit: 4500000, desc: "Additional paid-in capital" },
],
});
// Quarterly debt principal repayment
for (const q of [6, 9, 12]) {
const mm = String(q).padStart(2, "0");
await createJE({
periodKey: `2025-${q}`,
date: `2025-${mm}-30`,
description: `Q${q / 3} 2025 loan principal repayment`,
sourceModule: "GL",
status: "POSTED",
entityRef: acmeSoftware,
lines: [
{ accountCode: "2500", debit: 100000, credit: 0, desc: `Term loan principal Q${q / 3}` },
{ accountCode: "1010", debit: 0, credit: 100000, desc: `Cash - loan repayment Q${q / 3}` },
],
});
}
// Payroll Account Funding (monthly — DR Payroll, CR Operating)
for (let month = 1; month <= 12; month++) {
const mm = String(month).padStart(2, "0");
await createJE({
periodKey: `2025-${month}`,
date: `2025-${mm}-22`,
description: `${months[month - 1]} 2025 payroll account funding`,
sourceModule: "GL",
status: "POSTED",
entityRef: acmeSoftware,
lines: [
{ accountCode: "1020", debit: 210000, credit: 0, desc: `Payroll funding ${months[month - 1]}` },
{ accountCode: "1010", debit: 0, credit: 210000, desc: `Transfer to payroll ${months[month - 1]}` },
],
});
}
// ---- FY2026 Q1 JOURNAL ENTRIES (JanMar 2026) ----
for (let month = 1; month <= 3; month++) {
const mm = String(month).padStart(2, "0");
const periodKey = `2026-${month}`;
const monthName = months[month - 1];
// Revenue entries (growing 10% over FY2025)
await createJE({
periodKey,
date: `2026-${mm}-05`,
description: `${monthName} 2026 software license revenue`,
sourceModule: "AR",
status: "POSTED",
entityRef: acmeSoftware,
lines: [
{ accountCode: "1100", debit: 203500, credit: 0, desc: `AR - software licenses ${monthName}` },
{ accountCode: "4000", debit: 0, credit: 203500, desc: `Software revenue ${monthName}` },
],
});
await createJE({
periodKey,
date: `2026-${mm}-08`,
description: `${monthName} 2026 services revenue`,
sourceModule: "AR",
status: "POSTED",
entityRef: acmeSoftware,
lines: [
{ accountCode: "1100", debit: 101200, credit: 0, desc: `AR - consulting services ${monthName}` },
{ accountCode: "4100", debit: 0, credit: 101200, desc: `Services revenue ${monthName}` },
],
});
// Cash collections
await createJE({
periodKey,
date: `2026-${mm}-20`,
description: `${monthName} 2026 customer payments received`,
sourceModule: "AR",
status: "POSTED",
entityRef: acmeSoftware,
lines: [
{ accountCode: "1010", debit: 270000, credit: 0, desc: `Cash received ${monthName}` },
{ accountCode: "1100", debit: 0, credit: 270000, desc: `AR collections ${monthName}` },
],
});
// COGS
await createJE({
periodKey,
date: `2026-${mm}-10`,
description: `${monthName} 2026 cost of goods sold`,
sourceModule: "GL",
status: "POSTED",
entityRef: acmeSoftware,
lines: [
{ accountCode: "5000", debit: 60500, credit: 0, desc: `COGS ${monthName}` },
{ accountCode: "1010", debit: 0, credit: 60500, desc: `COGS payment ${monthName}` },
],
});
// Engineering Payroll
await createJE({
periodKey,
date: `2026-${mm}-25`,
description: `${monthName} 2026 engineering payroll`,
sourceModule: "PAYROLL",
status: "POSTED",
entityRef: acmeSoftware,
lines: [
{ accountCode: "6200", debit: 225000, credit: 0, desc: `Engineering salaries ${monthName}` },
{ accountCode: "1020", debit: 0, credit: 225000, desc: `Payroll disbursement ${monthName}` },
],
});
// S&M
await createJE({
periodKey,
date: `2026-${mm}-12`,
description: `${monthName} 2026 sales & marketing`,
sourceModule: "AP",
status: "POSTED",
entityRef: acmeSoftware,
lines: [
{ accountCode: "6100", debit: 49500, credit: 0, desc: `Marketing ${monthName}` },
{ accountCode: "2000", debit: 0, credit: 49500, desc: `AP - marketing ${monthName}` },
],
});
// G&A
await createJE({
periodKey,
date: `2026-${mm}-15`,
description: `${monthName} 2026 G&A expenses`,
sourceModule: "AP",
status: "POSTED",
entityRef: acmeSoftware,
lines: [
{ accountCode: "6300", debit: 41800, credit: 0, desc: `G&A expenses ${monthName}` },
{ accountCode: "2000", debit: 0, credit: 41800, desc: `AP - G&A ${monthName}` },
],
});
// IT
await createJE({
periodKey,
date: `2026-${mm}-14`,
description: `${monthName} 2026 IT & infrastructure`,
sourceModule: "AP",
status: "POSTED",
entityRef: acmeSoftware,
lines: [
{ accountCode: "6400", debit: 24200, credit: 0, desc: `IT costs ${monthName}` },
{ accountCode: "2000", debit: 0, credit: 24200, desc: `AP - IT ${monthName}` },
],
});
// AP Payments
await createJE({
periodKey,
date: `2026-${mm}-18`,
description: `${monthName} 2026 vendor payments`,
sourceModule: "AP",
status: "POSTED",
entityRef: acmeSoftware,
lines: [
{ accountCode: "2000", debit: 105000, credit: 0, desc: `AP payments ${monthName}` },
{ accountCode: "1010", debit: 0, credit: 105000, desc: `Cash disbursed ${monthName}` },
],
});
// Depreciation
await createJE({
periodKey,
date: `2026-${mm}-28`,
description: `${monthName} 2026 depreciation`,
sourceModule: "GL",
status: "POSTED",
entityRef: acmeSoftware,
lines: [
{ accountCode: "6300", debit: 9900, credit: 0, desc: `Depreciation ${monthName}` },
{ accountCode: "1550", debit: 0, credit: 9900, desc: `Accum depreciation ${monthName}` },
],
});
// Interest Expense
await createJE({
periodKey,
date: `2026-${mm}-28`,
description: `${monthName} 2026 interest expense`,
sourceModule: "GL",
status: "POSTED",
entityRef: acmeSoftware,
lines: [
{ accountCode: "7000", debit: 3500, credit: 0, desc: `Interest on debt ${monthName}` },
{ accountCode: "2200", debit: 0, credit: 3500, desc: `Accrued interest ${monthName}` },
],
});
// Interest Income
await createJE({
periodKey,
date: `2026-${mm}-28`,
description: `${monthName} 2026 interest income`,
sourceModule: "GL",
status: "POSTED",
entityRef: acmeSoftware,
lines: [
{ accountCode: "1010", debit: 2100, credit: 0, desc: `Interest earned ${monthName}` },
{ accountCode: "4500", debit: 0, credit: 2100, desc: `Interest income ${monthName}` },
],
});
// Payroll funding
await createJE({
periodKey,
date: `2026-${mm}-22`,
description: `${monthName} 2026 payroll account funding`,
sourceModule: "GL",
status: "POSTED",
entityRef: acmeSoftware,
lines: [
{ accountCode: "1020", debit: 225000, credit: 0, desc: `Payroll funding ${monthName}` },
{ accountCode: "1010", debit: 0, credit: 225000, desc: `Transfer to payroll ${monthName}` },
],
});
}
// Q1 2026 subsidiary revenues
await createJE({
periodKey: "2026-3",
date: "2026-03-15",
description: "Q1 2026 Acme Cloud UK revenue",
sourceModule: "AR",
status: "POSTED",
entityRef: acmeCloud,
lines: [
{ accountCode: "1100", debit: 142000, credit: 0, desc: "AR - UK cloud services Q1 2026" },
{ accountCode: "4000", debit: 0, credit: 142000, desc: "UK cloud revenue Q1 2026" },
],
});
await createJE({
periodKey: "2026-3",
date: "2026-03-16",
description: "Q1 2026 Acme Europe revenue",
sourceModule: "AR",
status: "POSTED",
entityRef: acmeEurope,
lines: [
{ accountCode: "1100", debit: 108000, credit: 0, desc: "AR - Europe consulting Q1 2026" },
{ accountCode: "4100", debit: 0, credit: 108000, desc: "Europe services revenue Q1 2026" },
],
});
await createJE({
periodKey: "2026-3",
date: "2026-03-17",
description: "Q1 2026 Acme Pacific revenue",
sourceModule: "AR",
status: "POSTED",
entityRef: acmePacific,
lines: [
{ accountCode: "1100", debit: 78000, credit: 0, desc: "AR - Pacific software Q1 2026" },
{ accountCode: "4000", debit: 0, credit: 78000, desc: "Pacific revenue Q1 2026" },
],
});
// FY2026 Opening retained earnings entry (close FY2025 net income)
// FY2025 Net Income calc: Revenue (185k*12+92k*12+125k*4+95k*4+68k*4+53.3k*9+1.8k*12) - Expenses
// Approx: Revenue ~$4.87M, Expenses ~$4.61M → Net income ~$260k → round to closing entry
await createJE({
periodKey: "2026-1",
date: "2026-01-01",
description: "FY2025 year-end close - retained earnings",
sourceModule: "GL",
status: "POSTED",
entityRef: acmeSoftware,
lines: [
{ accountCode: "3200", debit: 0, credit: 258400, desc: "FY2025 net income to retained earnings" },
{ accountCode: "1010", debit: 258400, credit: 0, desc: "Opening balance adjustment" },
],
});
// A couple DRAFT entries in April 2026 (current month)
await createJE({
periodKey: "2026-4",
date: "2026-04-03",
description: "April 2026 software revenue accrual (draft)",
sourceModule: "AR",
status: "DRAFT",
entityRef: acmeSoftware,
lines: [
{ accountCode: "1100", debit: 203500, credit: 0, desc: "AR - April software" },
{ accountCode: "4000", debit: 0, credit: 203500, desc: "April software revenue" },
],
});
await createJE({
periodKey: "2026-4",
date: "2026-04-04",
description: "April 2026 payroll accrual (pending approval)",
sourceModule: "PAYROLL",
status: "PENDING_APPROVAL",
entityRef: acmeSoftware,
lines: [
{ accountCode: "6200", debit: 225000, credit: 0, desc: "April engineering payroll" },
{ accountCode: "2200", debit: 0, credit: 225000, desc: "Accrued payroll" },
],
});
console.log(`✓ Created ${jeCounter} journal entries`);
// ========================================
// VENDORS
// ========================================
console.log("🏪 Creating vendors...");
const vendors = [];
const vendorData = [
{ code: "V001", name: "Amazon Web Services", termDays: 30, type: "Cloud Services", email: "billing@aws.amazon.com", phone: "206-555-0100" },
{ code: "V002", name: "Salesforce Inc", termDays: 45, type: "Software", email: "invoices@salesforce.com", phone: "415-555-0200" },
{ code: "V003", name: "WeWork", termDays: 30, type: "Real Estate", email: "accounts@wework.com", phone: "212-555-0300" },
{ code: "V004", name: "ADP Inc", termDays: 15, type: "HR Services", email: "billing@adp.com", phone: "973-555-0400" },
{ code: "V005", name: "Dell Technologies", termDays: 60, type: "Hardware", email: "orders@dell.com", phone: "512-555-0500" },
{ code: "V006", name: "Google Cloud Platform", termDays: 30, type: "Cloud Services", email: "billing@google.com", phone: "650-555-0600" },
{ code: "V007", name: "Datadog Inc", termDays: 30, type: "Software", email: "billing@datadoghq.com", phone: "646-555-0700" },
{ code: "V008", name: "Marsh McLennan", termDays: 45, type: "Insurance", email: "accounts@marsh.com", phone: "212-555-0800" },
];
for (const v of vendorData) {
const vendor = await prisma.vendor.create({
data: {
organizationId: organization.id,
vendorCode: v.code,
vendorName: v.name,
vendorType: v.type,
paymentTermDays: v.termDays,
email: v.email,
phone: v.phone,
status: "ACTIVE",
},
});
vendors.push(vendor);
}
console.log(`✓ Created ${vendors.length} vendors`);
// ========================================
// PURCHASE ORDERS
// ========================================
console.log("📦 Creating purchase orders...");
const purchaseOrders = [];
const poData = [
{
poNumber: "PO-2026-001", vendor: vendors[0], orderDate: new Date("2026-01-15"), expectedDate: new Date("2026-02-01"),
status: "RECEIVED", subtotal: 22000, tax: 1980,
lines: [{ lineNumber: 1, description: "AWS Reserved Instances - Q1 2026", quantity: 1, unitPrice: 22000 }],
},
{
poNumber: "PO-2026-002", vendor: vendors[1], orderDate: new Date("2026-01-20"), expectedDate: new Date("2026-02-15"),
status: "RECEIVED", subtotal: 48000, tax: 4320,
lines: [{ lineNumber: 1, description: "Salesforce Enterprise - Annual Renewal", quantity: 1, unitPrice: 48000 }],
},
{
poNumber: "PO-2026-003", vendor: vendors[2], orderDate: new Date("2026-02-01"), expectedDate: new Date("2026-03-01"),
status: "APPROVED", subtotal: 30000, tax: 2700,
lines: [
{ lineNumber: 1, description: "Office lease - Q2 2026", quantity: 3, unitPrice: 8000 },
{ lineNumber: 2, description: "Common area + utilities", quantity: 1, unitPrice: 6000 },
],
},
{
poNumber: "PO-2026-004", vendor: vendors[4], orderDate: new Date("2026-02-10"), expectedDate: new Date("2026-03-10"),
status: "PARTIALLY_RECEIVED", subtotal: 75000, tax: 6750,
lines: [{ lineNumber: 1, description: "Developer workstations - new hires", quantity: 15, unitPrice: 5000 }],
},
{
poNumber: "PO-2026-005", vendor: vendors[5], orderDate: new Date("2026-03-01"), expectedDate: new Date("2026-03-15"),
status: "SENT", subtotal: 18000, tax: 1620,
lines: [{ lineNumber: 1, description: "GCP BigQuery & Vertex AI credits", quantity: 1, unitPrice: 18000 }],
},
{
poNumber: "PO-2026-006", vendor: vendors[6], orderDate: new Date("2026-03-05"), expectedDate: new Date("2026-03-20"),
status: "APPROVED", subtotal: 9600, tax: 864,
lines: [{ lineNumber: 1, description: "Datadog Pro - Annual", quantity: 1, unitPrice: 9600 }],
},
{
poNumber: "PO-2026-007", vendor: vendors[3], orderDate: new Date("2026-03-15"), expectedDate: new Date("2026-04-01"),
status: "SENT", subtotal: 12000, tax: 1080,
lines: [{ lineNumber: 1, description: "ADP Workforce Now - Q2 processing", quantity: 1, unitPrice: 12000 }],
},
{
poNumber: "PO-2026-008", vendor: vendors[7], orderDate: new Date("2026-01-10"), expectedDate: new Date("2026-01-31"),
status: "RECEIVED", subtotal: 96000, tax: 8640,
lines: [{ lineNumber: 1, description: "Annual D&O and E&O insurance premium", quantity: 1, unitPrice: 96000 }],
},
];
for (const po of poData) {
const subtotal = po.lines.reduce((sum, line) => sum + (line.quantity * line.unitPrice), 0);
const totalAmount = subtotal + po.tax;
const purchaseOrder = await prisma.purchaseOrder.create({
data: {
organizationId: organization.id,
poNumber: po.poNumber,
vendorId: po.vendor.id,
orderDate: po.orderDate,
expectedDate: po.expectedDate,
status: po.status,
subtotal: subtotal.toString(),
taxAmount: po.tax.toString(),
totalAmount: totalAmount.toString(),
notes: null,
createdBy: user.id,
lines: {
create: po.lines.map(line => ({
lineNumber: line.lineNumber,
description: line.description,
quantity: line.quantity,
unitPrice: line.unitPrice,
lineAmount: (line.quantity * line.unitPrice).toString(),
glAccountCode: null,
})),
},
},
include: { vendor: true, lines: true },
});
purchaseOrders.push(purchaseOrder);
}
console.log(`✓ Created ${purchaseOrders.length} purchase orders`);
// ========================================
// CUSTOMERS
// ========================================
console.log("👥 Creating customers...");
const customers = [];
const customerData = [
{ code: "C001", name: "ABC Corporation", termDays: 30, type: "Enterprise", email: "ap@abccorp.com", phone: "212-555-1001" },
{ code: "C002", name: "TechVenture Inc", termDays: 30, type: "SaaS", email: "billing@techventure.io", phone: "415-555-1002" },
{ code: "C003", name: "Global Partners Ltd", termDays: 45, type: "Consulting", email: "finance@globalpartners.com", phone: "44-20-555-1003" },
{ code: "C004", name: "Premier Solutions Group", termDays: 30, type: "Enterprise", email: "accounts@premiersolutions.com", phone: "312-555-1004" },
{ code: "C005", name: "StartUp Ventures", termDays: 15, type: "Startup", email: "cfo@startupventures.co", phone: "650-555-1005" },
{ code: "C006", name: "Northern Health Systems", termDays: 45, type: "Enterprise", email: "procurement@northernhealth.org", phone: "617-555-1006" },
{ code: "C007", name: "Pacific Retail Group", termDays: 30, type: "Enterprise", email: "finance@pacificretail.com", phone: "503-555-1007" },
{ code: "C008", name: "Atlas Financial Corp", termDays: 30, type: "Financial Services", email: "vendor-mgmt@atlasfinancial.com", phone: "704-555-1008" },
];
for (const c of customerData) {
const customer = await prisma.customer.create({
data: {
organizationId: organization.id,
customerCode: c.code,
customerName: c.name,
customerType: c.type,
paymentTermDays: c.termDays,
email: c.email,
phone: c.phone,
status: "ACTIVE",
},
});
customers.push(customer);
}
console.log(`✓ Created ${customers.length} customers`);
// ========================================
// AP INVOICES (FY2026 Q1)
// ========================================
console.log("📄 Creating AP invoices...");
const apInvoices = [];
const apInvoiceData = [
{ number: "INV-AP-2026-0001", vendor: vendors[0], amount: 22000, status: "PAID" as InvoiceStatus, issueDate: new Date("2026-01-10"), dueDate: new Date("2026-02-15"), paidAmount: 22000,
lines: [{ accountCode: "6400", description: "AWS Reserved Instances - Jan", amount: 22000 }] },
{ number: "INV-AP-2026-0002", vendor: vendors[1], amount: 48000, status: "PAID" as InvoiceStatus, issueDate: new Date("2026-01-20"), dueDate: new Date("2026-03-05"), paidAmount: 48000,
lines: [{ accountCode: "6100", description: "Salesforce Enterprise - Annual", amount: 48000 }] },
{ number: "INV-AP-2026-0003", vendor: vendors[2], amount: 30000, status: "APPROVED" as InvoiceStatus, issueDate: new Date("2026-02-01"), dueDate: new Date("2026-04-01"),
lines: [{ accountCode: "6300", description: "Office lease - Q2", amount: 24000 }, { accountCode: "6300", description: "Utilities Q2", amount: 6000 }] },
{ number: "INV-AP-2026-0004", vendor: vendors[3], amount: 12000, status: "PENDING_APPROVAL" as InvoiceStatus, issueDate: new Date("2026-03-15"), dueDate: new Date("2026-04-15"),
lines: [{ accountCode: "6300", description: "ADP Payroll Processing Q2", amount: 12000 }] },
{ number: "INV-AP-2026-0005", vendor: vendors[4], amount: 75000, status: "PARTIALLY_PAID" as InvoiceStatus, issueDate: new Date("2026-02-10"), dueDate: new Date("2026-04-10"), paidAmount: 37500,
lines: [{ accountCode: "6400", description: "Developer workstations", amount: 75000 }] },
{ number: "INV-AP-2026-0006", vendor: vendors[0], amount: 24200, status: "APPROVED" as InvoiceStatus, issueDate: new Date("2026-02-28"), dueDate: new Date("2026-03-30"),
lines: [{ accountCode: "6400", description: "AWS usage - February", amount: 24200 }] },
{ number: "INV-AP-2026-0007", vendor: vendors[5], amount: 18000, status: "DRAFT" as InvoiceStatus, issueDate: new Date("2026-03-25"), dueDate: new Date("2026-04-30"),
lines: [{ accountCode: "6400", description: "GCP BigQuery & AI credits", amount: 18000 }] },
{ number: "INV-AP-2026-0008", vendor: vendors[6], amount: 9600, status: "APPROVED" as InvoiceStatus, issueDate: new Date("2026-03-05"), dueDate: new Date("2026-04-05"),
lines: [{ accountCode: "6400", description: "Datadog Pro Annual", amount: 9600 }] },
{ number: "INV-AP-2026-0009", vendor: vendors[7], amount: 96000, status: "PAID" as InvoiceStatus, issueDate: new Date("2026-01-08"), dueDate: new Date("2026-02-10"), paidAmount: 96000,
lines: [{ accountCode: "1200", description: "Annual D&O + E&O insurance", amount: 96000 }] },
{ number: "INV-AP-2026-0010", vendor: vendors[2], amount: 8000, status: "OVERDUE" as InvoiceStatus, issueDate: new Date("2026-01-25"), dueDate: new Date("2026-03-01"), daysOverdue: 35,
lines: [{ accountCode: "6300", description: "Conference room rental Feb", amount: 8000 }] },
{ number: "INV-AP-2026-0011", vendor: vendors[0], amount: 24200, status: "APPROVED" as InvoiceStatus, issueDate: new Date("2026-03-28"), dueDate: new Date("2026-04-30"),
lines: [{ accountCode: "6400", description: "AWS usage - March", amount: 24200 }] },
{ number: "INV-AP-2026-0012", vendor: vendors[4], amount: 15000, status: "DRAFT" as InvoiceStatus, issueDate: new Date("2026-04-01"), dueDate: new Date("2026-05-10"),
lines: [{ accountCode: "1500", description: "Additional server hardware", amount: 15000 }] },
];
for (const apData of apInvoiceData) {
const invoiceLines = apData.lines.map((line, index) => ({
description: line.description, quantity: 1, unitPrice: line.amount, lineAmount: line.amount,
lineNumber: index + 1, glAccountCode: line.accountCode,
}));
const totalAmount = apData.lines.reduce((sum, line) => sum + line.amount, 0);
const paidAmount = apData.paidAmount ?? (apData.status === "PAID" ? totalAmount : 0);
const invoice = await prisma.invoice.create({
data: {
organizationId: organization.id, entityId: acmeSoftware.id, vendorId: apData.vendor.id,
invoiceNumber: apData.number, invoiceDate: apData.issueDate, dueDate: apData.dueDate,
invoiceType: "ACCOUNTS_PAYABLE", status: apData.status,
subtotalAmount: totalAmount, totalAmount, paidAmount, balanceDue: totalAmount - paidAmount,
daysOverdue: apData.daysOverdue ?? null,
invoiceLines: { create: invoiceLines },
},
});
apInvoices.push(invoice);
}
console.log(`✓ Created ${apInvoices.length} AP invoices`);
// ========================================
// AR INVOICES (FY2026 Q1)
// ========================================
console.log("📄 Creating AR invoices...");
const arInvoices = [];
const arInvoiceData = [
{ number: "INV-AR-2026-0001", customer: customers[0], amount: 185000, status: "PAID" as InvoiceStatus, issueDate: new Date("2026-01-05"), dueDate: new Date("2026-02-14"), paidAmount: 185000,
lines: [{ accountCode: "4000", description: "Enterprise platform license - Jan", amount: 185000 }] },
{ number: "INV-AR-2026-0002", customer: customers[1], amount: 45000, status: "PAID" as InvoiceStatus, issueDate: new Date("2026-01-08"), dueDate: new Date("2026-02-14"), paidAmount: 45000,
lines: [{ accountCode: "4100", description: "SaaS subscription Q1", amount: 45000 }] },
{ number: "INV-AR-2026-0003", customer: customers[2], amount: 92000, status: "APPROVED" as InvoiceStatus, issueDate: new Date("2026-02-10"), dueDate: new Date("2026-03-30"),
lines: [{ accountCode: "4100", description: "Consulting engagement - Feb/Mar", amount: 92000 }] },
{ number: "INV-AR-2026-0004", customer: customers[3], amount: 203500, status: "PAID" as InvoiceStatus, issueDate: new Date("2026-02-01"), dueDate: new Date("2026-03-14"), paidAmount: 203500,
lines: [{ accountCode: "4000", description: "Enterprise license renewal", amount: 203500 }] },
{ number: "INV-AR-2026-0005", customer: customers[4], amount: 24000, status: "OVERDUE" as InvoiceStatus, issueDate: new Date("2026-01-15"), dueDate: new Date("2026-02-20"), daysOverdue: 44,
lines: [{ accountCode: "4100", description: "Startup plan - 12 months", amount: 24000 }] },
{ number: "INV-AR-2026-0006", customer: customers[0], amount: 101200, status: "PARTIALLY_PAID" as InvoiceStatus, issueDate: new Date("2026-03-01"), dueDate: new Date("2026-04-14"), paidAmount: 50000,
lines: [{ accountCode: "4000", description: "Implementation services", amount: 101200 }] },
{ number: "INV-AR-2026-0007", customer: customers[5], amount: 156000, status: "APPROVED" as InvoiceStatus, issueDate: new Date("2026-03-10"), dueDate: new Date("2026-04-30"),
lines: [{ accountCode: "4000", description: "Healthcare platform license", amount: 156000 }] },
{ number: "INV-AR-2026-0008", customer: customers[6], amount: 78000, status: "DRAFT" as InvoiceStatus, issueDate: new Date("2026-03-20"), dueDate: new Date("2026-05-15"),
lines: [{ accountCode: "4000", description: "Retail analytics module", amount: 78000 }] },
{ number: "INV-AR-2026-0009", customer: customers[7], amount: 210000, status: "APPROVED" as InvoiceStatus, issueDate: new Date("2026-03-15"), dueDate: new Date("2026-04-20"),
lines: [{ accountCode: "4000", description: "Financial compliance suite", amount: 135000 }, { accountCode: "4100", description: "Integration services", amount: 75000 }] },
{ number: "INV-AR-2026-0010", customer: customers[1], amount: 15000, status: "APPROVED" as InvoiceStatus, issueDate: new Date("2026-03-28"), dueDate: new Date("2026-04-14"),
lines: [{ accountCode: "4100", description: "SaaS subscription Q2", amount: 15000 }] },
];
for (const arData of arInvoiceData) {
const invoiceLines = arData.lines.map((line, index) => ({
description: line.description, quantity: 1, unitPrice: line.amount, lineAmount: line.amount,
lineNumber: index + 1, glAccountCode: line.accountCode,
}));
const totalAmount = arData.lines.reduce((sum, line) => sum + line.amount, 0);
const paidAmount = arData.paidAmount ?? (arData.status === "PAID" ? totalAmount : 0);
const invoice = await prisma.invoice.create({
data: {
organizationId: organization.id, entityId: acmeSoftware.id, customerId: arData.customer.id,
invoiceNumber: arData.number, invoiceDate: arData.issueDate, dueDate: arData.dueDate,
invoiceType: "ACCOUNTS_RECEIVABLE", status: arData.status,
subtotalAmount: totalAmount, totalAmount, paidAmount, balanceDue: totalAmount - paidAmount,
daysOverdue: arData.daysOverdue ?? null,
invoiceLines: { create: invoiceLines },
},
});
arInvoices.push(invoice);
}
console.log(`✓ Created ${arInvoices.length} AR invoices`);
// ========================================
// PAYMENTS
// ========================================
console.log("💳 Creating payments...");
const payments = [];
const paymentConfigs = [
{ vendorId: vendors[0].id, invoiceIdx: 0, number: "PAY-2026-0001", date: "2026-02-10", method: "BANK_TRANSFER" as const, amount: 22000 },
{ vendorId: vendors[1].id, invoiceIdx: 1, number: "PAY-2026-0002", date: "2026-02-28", method: "BANK_TRANSFER" as const, amount: 48000 },
{ vendorId: vendors[7].id, invoiceIdx: 8, number: "PAY-2026-0003", date: "2026-02-05", method: "WIRE" as const, amount: 96000 },
{ vendorId: vendors[4].id, invoiceIdx: 4, number: "PAY-2026-0004", date: "2026-03-20", method: "BANK_TRANSFER" as const, amount: 37500 },
{ customerId: customers[0].id, invoiceIdx: 0, isAR: true, number: "PAY-2026-0005", date: "2026-02-12", method: "BANK_TRANSFER" as const, amount: 185000 },
{ customerId: customers[1].id, invoiceIdx: 1, isAR: true, number: "PAY-2026-0006", date: "2026-02-10", method: "ACH" as const, amount: 45000 },
{ customerId: customers[3].id, invoiceIdx: 3, isAR: true, number: "PAY-2026-0007", date: "2026-03-10", method: "WIRE" as const, amount: 203500 },
{ customerId: customers[0].id, invoiceIdx: 5, isAR: true, number: "PAY-2026-0008", date: "2026-04-01", method: "CHECK" as const, amount: 50000 },
];
for (const pc of paymentConfigs) {
const invoiceRef = pc.isAR ? arInvoices[pc.invoiceIdx] : apInvoices[pc.invoiceIdx];
const payment = await prisma.payment.create({
data: {
organizationId: organization.id,
vendorId: pc.vendorId || null,
customerId: pc.customerId || null,
invoiceId: invoiceRef.id,
paymentNumber: pc.number,
paymentDate: new Date(pc.date),
paymentMethod: pc.method,
status: "COMPLETED",
paymentAmount: pc.amount,
totalPaymentAmount: pc.amount,
paymentAllocations: {
create: [{ organizationId: organization.id, invoiceId: invoiceRef.id, allocatedAmount: pc.amount }],
},
},
});
payments.push(payment);
}
console.log(`✓ Created ${payments.length} payments`);
// ========================================
// BANK ACCOUNTS
// ========================================
console.log("🏦 Creating bank accounts...");
const bankAccounts = [];
const bankAccountsData = [
{ name: "Chase Business Checking", bank: "Chase Bank", number: "****2847", type: "Checking", balance: 2845600.75, entity: acmeSoftware },
{ name: "Bank of America Payroll", bank: "Bank of America", number: "****5923", type: "Checking", balance: 485340.50, entity: acmeSoftware },
{ name: "Silicon Valley Bank", bank: "Silicon Valley Bank", number: "****7412", type: "Checking", balance: 1524850.00, entity: acmeSoftware },
{ name: "Mercury Bank", bank: "Mercury", number: "****3156", type: "Savings", balance: 289750.25, entity: acmeSoftware },
{ name: "Wells Fargo Business Savings", bank: "Wells Fargo", number: "****9284", type: "Savings", balance: 756200.00, entity: acmeSoftware },
{ name: "Barclays UK Account", bank: "Barclays", number: "****6201", type: "Checking", balance: 342000.00, entity: acmeCloud },
{ name: "Deutsche Bank EUR", bank: "Deutsche Bank", number: "****8834", type: "Checking", balance: 215000.00, entity: acmeEurope },
{ name: "ANZ Business", bank: "ANZ", number: "****4477", type: "Checking", balance: 178500.00, entity: acmePacific },
];
for (const accData of bankAccountsData) {
const account = await prisma.bankAccount.create({
data: {
organizationId: organization.id,
entityId: accData.entity.id,
accountName: accData.name,
bankName: accData.bank,
accountNumber: accData.number,
accountNumberMasked: accData.number,
accountType: accData.type,
currencyCode: accData.entity === acmeCloud ? "GBP" : accData.entity === acmeEurope ? "EUR" : accData.entity === acmePacific ? "AUD" : "USD",
currentBalance: accData.balance,
availableBalance: accData.balance,
lastBalanceUpdate: new Date("2026-04-03"),
status: "ACTIVE",
},
});
bankAccounts.push(account);
}
console.log(`✓ Created ${bankAccounts.length} bank accounts`);
// ========================================
// BANK TRANSACTIONS (recent 30 days)
// ========================================
console.log("📊 Creating bank transactions...");
const bankTransactions = [];
const transactionData = [
{ account: bankAccounts[0], date: "2026-03-05", type: "CREDIT", amount: 185000, description: "Customer payment - ABC Corp", reconciled: true },
{ account: bankAccounts[0], date: "2026-03-10", type: "CREDIT", amount: 203500, description: "Customer payment - Premier Solutions", reconciled: true },
{ account: bankAccounts[0], date: "2026-03-12", type: "DEBIT", amount: 48000, description: "Salesforce annual renewal", reconciled: true },
{ account: bankAccounts[0], date: "2026-03-15", type: "DEBIT", amount: 22000, description: "AWS cloud hosting", reconciled: true },
{ account: bankAccounts[0], date: "2026-03-20", type: "DEBIT", amount: 37500, description: "Dell workstations partial", reconciled: true },
{ account: bankAccounts[0], date: "2026-03-25", type: "CREDIT", amount: 45000, description: "Customer payment - TechVenture", reconciled: true },
{ account: bankAccounts[0], date: "2026-04-01", type: "CREDIT", amount: 50000, description: "Customer payment - ABC Corp partial", reconciled: false },
{ account: bankAccounts[0], date: "2026-04-03", type: "DEBIT", amount: 24200, description: "AWS usage - March billing", reconciled: false },
{ account: bankAccounts[1], date: "2026-03-25", type: "DEBIT", amount: 225000, description: "March payroll - engineering", reconciled: true },
{ account: bankAccounts[1], date: "2026-03-25", type: "DEBIT", amount: 49500, description: "March payroll - S&M team", reconciled: true },
{ account: bankAccounts[1], date: "2026-03-25", type: "DEBIT", amount: 41800, description: "March payroll - G&A staff", reconciled: true },
{ account: bankAccounts[1], date: "2026-03-22", type: "CREDIT", amount: 225000, description: "Payroll account funding - Mar", reconciled: true },
{ account: bankAccounts[2], date: "2026-03-01", type: "DEBIT", amount: 96000, description: "Insurance premium - annual", reconciled: true },
{ account: bankAccounts[2], date: "2026-03-15", type: "CREDIT", amount: 92000, description: "Customer payment - Global Partners", reconciled: true },
{ account: bankAccounts[2], date: "2026-04-02", type: "DEBIT", amount: 105000, description: "Vendor payments batch", reconciled: false },
{ account: bankAccounts[3], date: "2026-03-31", type: "CREDIT", amount: 2100, description: "Interest earned Q1", reconciled: true },
{ account: bankAccounts[3], date: "2026-04-01", type: "DEBIT", amount: 150, description: "Monthly maintenance fee", reconciled: true },
{ account: bankAccounts[4], date: "2026-03-30", type: "DEBIT", amount: 100000, description: "Loan principal payment Q1", reconciled: true },
{ account: bankAccounts[4], date: "2026-03-30", type: "DEBIT", amount: 3500, description: "Interest payment Q1", reconciled: true },
{ account: bankAccounts[5], date: "2026-03-15", type: "CREDIT", amount: 142000, description: "UK customer payments Q1", reconciled: true },
{ account: bankAccounts[5], date: "2026-03-28", type: "DEBIT", amount: 45000, description: "UK operating expenses", reconciled: false },
{ account: bankAccounts[6], date: "2026-03-16", type: "CREDIT", amount: 108000, description: "Europe customer payments Q1", reconciled: true },
{ account: bankAccounts[6], date: "2026-03-30", type: "DEBIT", amount: 38000, description: "Europe operating expenses", reconciled: false },
{ account: bankAccounts[7], date: "2026-03-17", type: "CREDIT", amount: 78000, description: "Pacific customer payments Q1", reconciled: true },
{ account: bankAccounts[7], date: "2026-03-30", type: "DEBIT", amount: 28000, description: "Pacific operating expenses", reconciled: false },
];
for (const txData of transactionData) {
const txDate = new Date(txData.date);
const transaction = await prisma.bankTransaction.create({
data: {
organizationId: organization.id,
bankAccountId: txData.account.id,
transactionDate: txDate,
postDate: txDate,
transactionType: txData.type as "DEBIT" | "CREDIT" | "REVERSAL" | "ADJUSTMENT",
amount: txData.amount,
description: txData.description,
reconciled: txData.reconciled,
reconciledAt: txData.reconciled ? txDate : null,
status: "PENDING",
},
});
bankTransactions.push(transaction);
}
console.log(`✓ Created ${bankTransactions.length} bank transactions`);
// ========================================
// CASH POSITION SNAPSHOTS
// ========================================
console.log("💰 Creating cash position snapshots...");
const cashSnapshots = [
{ date: "2025-12-31", total: 5250000, byEntity: { "Acme Software Inc": 4450000, "Acme Cloud Services Ltd": 380000, "Acme Europe GmbH": 240000, "Acme Pacific Pty Ltd": 180000 } },
{ date: "2026-01-31", total: 5680000, byEntity: { "Acme Software Inc": 4820000, "Acme Cloud Services Ltd": 395000, "Acme Europe GmbH": 268000, "Acme Pacific Pty Ltd": 197000 } },
{ date: "2026-02-28", total: 5920000, byEntity: { "Acme Software Inc": 5010000, "Acme Cloud Services Ltd": 415000, "Acme Europe GmbH": 285000, "Acme Pacific Pty Ltd": 210000 } },
{ date: "2026-03-31", total: 6137241.50, byEntity: { "Acme Software Inc": 5201741.50, "Acme Cloud Services Ltd": 439000, "Acme Europe GmbH": 310000, "Acme Pacific Pty Ltd": 186500 } },
{ date: "2026-04-03", total: 6037241.50, byEntity: { "Acme Software Inc": 5101741.50, "Acme Cloud Services Ltd": 439000, "Acme Europe GmbH": 310000, "Acme Pacific Pty Ltd": 186500 } },
];
for (const snap of cashSnapshots) {
await prisma.cashPosition.create({
data: {
organizationId: organization.id,
snapshotDate: new Date(snap.date),
totalCash: snap.total,
totalAvailable: snap.total,
cashByEntity: snap.byEntity,
cashByCurrency: { USD: snap.byEntity["Acme Software Inc"], GBP: snap.byEntity["Acme Cloud Services Ltd"], EUR: snap.byEntity["Acme Europe GmbH"], AUD: snap.byEntity["Acme Pacific Pty Ltd"] },
},
});
}
console.log(`✓ Created ${cashSnapshots.length} cash position snapshots`);
// ========================================
// BUDGET LINES (FY2026)
// ========================================
console.log("📊 Creating budget lines...");
const budgetData = [
{ accountCode: "4000", annual: 2640000, monthly: [200000, 210000, 215000, 220000, 225000, 225000, 220000, 215000, 220000, 230000, 230000, 230000] },
{ accountCode: "4100", annual: 1200000, monthly: [95000, 98000, 100000, 102000, 100000, 100000, 100000, 102000, 103000, 100000, 100000, 100000] },
{ accountCode: "4500", annual: 25200, monthly: [2100, 2100, 2100, 2100, 2100, 2100, 2100, 2100, 2100, 2100, 2100, 2100] },
{ accountCode: "5000", annual: 726000, monthly: [60500, 60500, 60500, 60500, 60500, 60500, 60500, 60500, 60500, 60500, 60500, 60500] },
{ accountCode: "6100", annual: 594000, monthly: [49500, 49500, 49500, 49500, 49500, 49500, 49500, 49500, 49500, 49500, 49500, 49500] },
{ accountCode: "6200", annual: 2700000, monthly: [225000, 225000, 225000, 225000, 225000, 225000, 225000, 225000, 225000, 225000, 225000, 225000] },
{ accountCode: "6300", annual: 620400, monthly: [51700, 51700, 51700, 51700, 51700, 51700, 51700, 51700, 51700, 51700, 51700, 51700] },
{ accountCode: "6400", annual: 290400, monthly: [24200, 24200, 24200, 24200, 24200, 24200, 24200, 24200, 24200, 24200, 24200, 24200] },
{ accountCode: "7000", annual: 42000, monthly: [3500, 3500, 3500, 3500, 3500, 3500, 3500, 3500, 3500, 3500, 3500, 3500] },
];
for (const bd of budgetData) {
await prisma.budgetLine.create({
data: {
organizationId: organization.id,
accountId: accounts[bd.accountCode].id,
fiscalYear: 2026,
monthlyAmounts: bd.monthly,
annualBudget: bd.annual,
notes: `FY2026 budget for ${accounts[bd.accountCode].accountName}`,
},
});
}
console.log(`✓ Created ${budgetData.length} budget lines`);
// Also create FY2025 budgets (for YoY comparison)
const fy2025BudgetData = [
{ accountCode: "4000", annual: 2400000, monthly: [185000, 190000, 195000, 200000, 205000, 205000, 200000, 200000, 205000, 210000, 200000, 205000] },
{ accountCode: "4100", annual: 1104000, monthly: [92000, 92000, 92000, 92000, 92000, 92000, 92000, 92000, 92000, 92000, 92000, 92000] },
{ accountCode: "5000", annual: 660000, monthly: [55000, 55000, 55000, 55000, 55000, 55000, 55000, 55000, 55000, 55000, 55000, 55000] },
{ accountCode: "6200", annual: 2520000, monthly: [210000, 210000, 210000, 210000, 210000, 210000, 210000, 210000, 210000, 210000, 210000, 210000] },
{ accountCode: "6100", annual: 540000, monthly: [45000, 45000, 45000, 45000, 45000, 45000, 45000, 45000, 45000, 45000, 45000, 45000] },
{ accountCode: "6300", annual: 558000, monthly: [46500, 46500, 46500, 46500, 46500, 46500, 46500, 46500, 46500, 46500, 46500, 46500] },
{ accountCode: "6400", annual: 264000, monthly: [22000, 22000, 22000, 22000, 22000, 22000, 22000, 22000, 22000, 22000, 22000, 22000] },
];
for (const bd of fy2025BudgetData) {
await prisma.budgetLine.create({
data: {
organizationId: organization.id,
accountId: accounts[bd.accountCode].id,
fiscalYear: 2025,
monthlyAmounts: bd.monthly,
annualBudget: bd.annual,
notes: `FY2025 budget for ${accounts[bd.accountCode].accountName}`,
},
});
}
console.log(`✓ Created ${fy2025BudgetData.length} FY2025 budget lines`);
// ========================================
// LEASES (ASC 842)
// ========================================
console.log("🏢 Creating leases...");
const leases = [
{
description: "NYC Office Space - 5th Avenue",
type: "Operating",
startDate: new Date("2024-01-01"),
endDate: new Date("2028-12-31"),
monthlyPayment: 24000,
totalCommitment: 1440000,
discountRate: 4.5,
rouAsset: 1296000,
leaseLiability: 1310400,
currentPortion: 276480,
nonCurrentPortion: 1033920,
status: "Active",
},
{
description: "London Office - Canary Wharf",
type: "Operating",
startDate: new Date("2024-06-01"),
endDate: new Date("2027-05-31"),
monthlyPayment: 15000,
totalCommitment: 540000,
discountRate: 5.0,
rouAsset: 486000,
leaseLiability: 495000,
currentPortion: 175500,
nonCurrentPortion: 319500,
status: "Active",
},
{
description: "Server Co-location - Equinix NY5",
type: "Finance",
startDate: new Date("2025-03-01"),
endDate: new Date("2030-02-28"),
monthlyPayment: 35000,
totalCommitment: 2100000,
discountRate: 3.8,
rouAsset: 1890000,
leaseLiability: 1932000,
currentPortion: 396000,
nonCurrentPortion: 1536000,
status: "Active",
},
{
description: "Company Vehicles Fleet (12 units)",
type: "Operating",
startDate: new Date("2025-01-01"),
endDate: new Date("2027-12-31"),
monthlyPayment: 6000,
totalCommitment: 216000,
discountRate: 4.0,
rouAsset: 194400,
leaseLiability: 198000,
currentPortion: 70200,
nonCurrentPortion: 127800,
status: "Active",
},
{
description: "Berlin Office - Alexanderplatz",
type: "Operating",
startDate: new Date("2025-06-01"),
endDate: new Date("2028-05-31"),
monthlyPayment: 8500,
totalCommitment: 306000,
discountRate: 4.2,
rouAsset: 275400,
leaseLiability: 280800,
currentPortion: 99000,
nonCurrentPortion: 181800,
status: "Active",
},
{
description: "Old SF Office (terminated early)",
type: "Operating",
startDate: new Date("2022-01-01"),
endDate: new Date("2025-06-30"),
monthlyPayment: 18000,
totalCommitment: 756000,
discountRate: 3.5,
rouAsset: 0,
leaseLiability: 0,
currentPortion: 0,
nonCurrentPortion: 0,
status: "Expired",
},
];
for (const l of leases) {
await prisma.lease.create({
data: {
organizationId: organization.id,
description: l.description,
type: l.type,
startDate: l.startDate,
endDate: l.endDate,
monthlyPayment: l.monthlyPayment,
totalCommitment: l.totalCommitment,
discountRate: l.discountRate,
rouAsset: l.rouAsset,
leaseLiability: l.leaseLiability,
currentPortion: l.currentPortion,
nonCurrentPortion: l.nonCurrentPortion,
status: l.status,
},
});
}
console.log(`✓ Created ${leases.length} leases`);
// ========================================
// SHAREHOLDERS / CAP TABLE
// ========================================
console.log("📋 Creating shareholders...");
const shareholders = [
{ name: "Ryan Francis", type: "founder", sharesOwned: 4000000, shareClass: "Common", vestingCliffMonths: 12, vestingTotalMonths: 48, vestedPercent: 87.50, grantDate: new Date("2020-01-01"), exercisePrice: 0.01, status: "ACTIVE" },
{ name: "Sarah Chen", type: "founder", sharesOwned: 3000000, shareClass: "Common", vestingCliffMonths: 12, vestingTotalMonths: 48, vestedPercent: 87.50, grantDate: new Date("2020-01-01"), exercisePrice: 0.01, status: "ACTIVE" },
{ name: "Velocity Partners Fund III", type: "investor", sharesOwned: 2500000, shareClass: "Series A", vestingCliffMonths: 0, vestingTotalMonths: 0, vestedPercent: 100.00, grantDate: new Date("2022-06-15"), exercisePrice: 1.20, status: "ACTIVE" },
{ name: "Summit Capital Growth", type: "investor", sharesOwned: 3500000, shareClass: "Series B", vestingCliffMonths: 0, vestingTotalMonths: 0, vestedPercent: 100.00, grantDate: new Date("2025-01-15"), exercisePrice: 2.85, status: "ACTIVE" },
{ name: "Emily Rodriguez", type: "employee", sharesOwned: 500000, shareClass: "Options", vestingCliffMonths: 12, vestingTotalMonths: 48, vestedPercent: 62.50, grantDate: new Date("2021-06-01"), exercisePrice: 0.50, status: "ACTIVE" },
{ name: "James Park", type: "employee", sharesOwned: 400000, shareClass: "Options", vestingCliffMonths: 12, vestingTotalMonths: 48, vestedPercent: 50.00, grantDate: new Date("2022-01-15"), exercisePrice: 0.80, status: "ACTIVE" },
{ name: "Aisha Patel", type: "employee", sharesOwned: 350000, shareClass: "Options", vestingCliffMonths: 12, vestingTotalMonths: 48, vestedPercent: 37.50, grantDate: new Date("2023-01-01"), exercisePrice: 1.50, status: "ACTIVE" },
{ name: "David Kim", type: "advisor", sharesOwned: 150000, shareClass: "Options", vestingCliffMonths: 6, vestingTotalMonths: 24, vestedPercent: 100.00, grantDate: new Date("2022-01-01"), exercisePrice: 0.80, status: "ACTIVE" },
{ name: "Maria Santos", type: "employee", sharesOwned: 250000, shareClass: "Options", vestingCliffMonths: 12, vestingTotalMonths: 48, vestedPercent: 18.75, grantDate: new Date("2024-04-01"), exercisePrice: 2.00, status: "ACTIVE" },
{ name: "Alex Thompson (departed)", type: "employee", sharesOwned: 200000, shareClass: "Options", vestingCliffMonths: 12, vestingTotalMonths: 48, vestedPercent: 25.00, grantDate: new Date("2023-01-01"), exercisePrice: 1.50, status: "TERMINATED" },
];
for (const sh of shareholders) {
await prisma.shareholder.create({
data: {
organizationId: organization.id,
name: sh.name,
type: sh.type,
sharesOwned: sh.sharesOwned,
shareClass: sh.shareClass,
vestingCliffMonths: sh.vestingCliffMonths,
vestingTotalMonths: sh.vestingTotalMonths,
vestedPercent: sh.vestedPercent,
grantDate: sh.grantDate,
exercisePrice: sh.exercisePrice,
status: sh.status,
},
});
}
console.log(`✓ Created ${shareholders.length} shareholders`);
// ========================================
// SUBSCRIPTIONS (customer recurring revenue)
// ========================================
console.log("🔄 Creating subscriptions...");
const subscriptions = [
{ customer: customers[0], plan: "Enterprise Platform", cycle: "ANNUAL", amount: 2220000, start: "2025-01-01", next: "2026-01-01", status: "ACTIVE" },
{ customer: customers[1], plan: "SaaS Professional", cycle: "MONTHLY", amount: 15000, start: "2025-03-01", next: "2026-05-01", status: "ACTIVE" },
{ customer: customers[2], plan: "Consulting Retainer", cycle: "QUARTERLY", amount: 92000, start: "2025-01-01", next: "2026-07-01", status: "ACTIVE" },
{ customer: customers[3], plan: "Enterprise License", cycle: "ANNUAL", amount: 2442000, start: "2026-01-01", next: "2027-01-01", status: "ACTIVE" },
{ customer: customers[4], plan: "Startup Plan", cycle: "ANNUAL", amount: 24000, start: "2025-06-01", next: "2026-06-01", status: "ACTIVE" },
{ customer: customers[5], plan: "Healthcare Suite", cycle: "ANNUAL", amount: 1872000, start: "2026-01-01", next: "2027-01-01", status: "ACTIVE" },
{ customer: customers[6], plan: "Retail Analytics", cycle: "MONTHLY", amount: 6500, start: "2025-09-01", next: "2026-05-01", status: "ACTIVE" },
{ customer: customers[7], plan: "Financial Compliance", cycle: "ANNUAL", amount: 2520000, start: "2026-02-01", next: "2027-02-01", status: "ACTIVE" },
{ customer: customers[1], plan: "SaaS Basic (old)", cycle: "MONTHLY", amount: 8000, start: "2024-01-01", end: "2025-02-28", status: "CANCELLED" },
];
for (const sub of subscriptions) {
await prisma.subscription.create({
data: {
organizationId: organization.id,
customerId: sub.customer.id,
planName: sub.plan,
billingCycle: sub.cycle,
amount: sub.amount,
startDate: new Date(sub.start),
endDate: sub.end ? new Date(sub.end) : null,
nextBillingDate: sub.next ? new Date(sub.next) : null,
cancelledAt: sub.status === "CANCELLED" ? new Date(sub.end!) : null,
status: sub.status,
},
});
}
console.log(`✓ Created ${subscriptions.length} subscriptions`);
// ========================================
// FORECASTS
// ========================================
console.log("🔮 Creating forecasts...");
const forecasts = [
{
name: "FY2026 Base Case Forecast",
description: "Conservative growth scenario based on current pipeline and retention rates",
scenarioType: "BASE",
startDate: new Date("2026-01-01"),
endDate: new Date("2026-12-31"),
status: "ACTIVE",
assumptions: { revenueGrowth: 0.10, expenseGrowth: 0.08, churnRate: 0.05, newCustomers: 12 },
projections: {
months: months.map((m, i) => ({
month: `${m} 2026`,
revenue: 304700 + (i * 3000),
expenses: 350400 + (i * 1500),
netIncome: -45700 + (i * 1500),
cashBalance: 6037241 + (i * 45000),
})),
},
},
{
name: "FY2026 Optimistic Scenario",
description: "Aggressive growth with accelerated enterprise sales and expansion revenue",
scenarioType: "OPTIMISTIC",
startDate: new Date("2026-01-01"),
endDate: new Date("2026-12-31"),
status: "ACTIVE",
assumptions: { revenueGrowth: 0.25, expenseGrowth: 0.15, churnRate: 0.03, newCustomers: 24 },
projections: {
months: months.map((m, i) => ({
month: `${m} 2026`,
revenue: 345000 + (i * 8000),
expenses: 365000 + (i * 3000),
netIncome: -20000 + (i * 5000),
cashBalance: 6037241 + (i * 85000),
})),
},
},
{
name: "FY2026 Pessimistic Scenario",
description: "Downturn scenario with reduced pipeline and higher churn",
scenarioType: "PESSIMISTIC",
startDate: new Date("2026-01-01"),
endDate: new Date("2026-12-31"),
status: "ACTIVE",
assumptions: { revenueGrowth: -0.05, expenseGrowth: 0.03, churnRate: 0.12, newCustomers: 4 },
projections: {
months: months.map((m, i) => ({
month: `${m} 2026`,
revenue: 270000 - (i * 2000),
expenses: 345000 + (i * 500),
netIncome: -75000 - (i * 2500),
cashBalance: 6037241 - (i * 35000),
})),
},
},
];
for (const f of forecasts) {
await prisma.forecast.create({
data: {
organizationId: organization.id,
name: f.name,
description: f.description,
scenarioType: f.scenarioType,
startDate: f.startDate,
endDate: f.endDate,
status: f.status,
assumptions: f.assumptions,
projections: f.projections,
createdBy: user.name,
},
});
}
console.log(`✓ Created ${forecasts.length} forecasts`);
// ========================================
// DOCUMENTS
// ========================================
console.log("📁 Creating documents...");
const documents = [
{ name: "FY2025 Annual Report.pdf", category: "report", mimeType: "application/pdf", fileSize: 2450000, storagePath: "/documents/reports/fy2025-annual.pdf", tags: ["annual", "FY2025", "financial"] },
{ name: "Series B Term Sheet.pdf", category: "legal", mimeType: "application/pdf", fileSize: 185000, storagePath: "/documents/legal/series-b-term-sheet.pdf", tags: ["legal", "fundraising", "Series B"] },
{ name: "AWS MSA.pdf", category: "contract", mimeType: "application/pdf", fileSize: 420000, storagePath: "/documents/contracts/aws-msa.pdf", tags: ["contract", "vendor", "AWS"] },
{ name: "Q1 2026 Board Deck.pptx", category: "report", mimeType: "application/vnd.openxmlformats-officedocument.presentationml.presentation", fileSize: 5200000, storagePath: "/documents/reports/q1-2026-board-deck.pptx", tags: ["board", "Q1", "2026"] },
{ name: "Office Lease Agreement - NYC.pdf", category: "contract", mimeType: "application/pdf", fileSize: 890000, storagePath: "/documents/contracts/nyc-office-lease.pdf", tags: ["lease", "real estate", "NYC"] },
{ name: "D&O Insurance Policy.pdf", category: "legal", mimeType: "application/pdf", fileSize: 340000, storagePath: "/documents/legal/do-insurance-2026.pdf", tags: ["insurance", "D&O", "2026"] },
{ name: "Employee Stock Option Plan.pdf", category: "legal", mimeType: "application/pdf", fileSize: 275000, storagePath: "/documents/legal/esop-plan.pdf", tags: ["ESOP", "equity", "options"] },
{ name: "SOC 2 Type II Report.pdf", category: "report", mimeType: "application/pdf", fileSize: 1800000, storagePath: "/documents/compliance/soc2-type2-2025.pdf", tags: ["compliance", "SOC2", "audit"] },
{ name: "Revenue Recognition Policy.docx", category: "report", mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document", fileSize: 125000, storagePath: "/documents/policies/rev-rec-policy.docx", tags: ["policy", "ASC 606", "revenue"] },
{ name: "ABC Corp Master Agreement.pdf", category: "contract", mimeType: "application/pdf", fileSize: 560000, storagePath: "/documents/contracts/abc-corp-msa.pdf", tags: ["contract", "customer", "ABC Corp"] },
];
for (const doc of documents) {
await prisma.document.create({
data: {
organizationId: organization.id,
name: doc.name,
category: doc.category,
mimeType: doc.mimeType,
fileSize: doc.fileSize,
storagePath: doc.storagePath,
status: "ACTIVE",
tags: doc.tags,
uploadedBy: user.name,
},
});
}
console.log(`✓ Created ${documents.length} documents`);
// ========================================
// AUDIT LOG
// ========================================
console.log("📜 Creating audit log entries...");
const auditEntries = [
{ action: "LOGIN", module: "auth", entityType: "User", description: "User logged in", date: "2026-04-05T08:30:00Z" },
{ action: "CREATE", module: "general-ledger", entityType: "JournalEntry", description: "Created JE-2026-0001 - January software revenue", date: "2026-01-06T09:15:00Z" },
{ action: "POST", module: "general-ledger", entityType: "JournalEntry", description: "Posted JE-2026-0001", date: "2026-01-06T09:20:00Z" },
{ action: "APPROVE", module: "ap", entityType: "Invoice", description: "Approved INV-AP-2026-0003 - WeWork office lease", date: "2026-02-15T14:00:00Z" },
{ action: "CREATE", module: "ap", entityType: "Payment", description: "Created payment PAY-2026-0001 for AWS", date: "2026-02-10T10:30:00Z" },
{ action: "APPROVE", module: "ar", entityType: "Invoice", description: "Approved INV-AR-2026-0007 - Northern Health Systems", date: "2026-03-20T11:00:00Z" },
{ action: "EXPORT", module: "reports", entityType: "Report", description: "Exported Q1 2026 Trial Balance to CSV", date: "2026-04-02T16:45:00Z" },
{ action: "UPDATE", module: "treasury", entityType: "BankAccount", description: "Updated Chase Business Checking balance", date: "2026-04-03T09:00:00Z" },
{ action: "CREATE", module: "general-ledger", entityType: "JournalEntry", description: "Created April 2026 revenue accrual (draft)", date: "2026-04-03T10:00:00Z" },
{ action: "CREATE", module: "ar", entityType: "Invoice", description: "Created INV-AR-2026-0008 - Pacific Retail Group", date: "2026-04-01T13:30:00Z" },
{ action: "LOGIN", module: "auth", entityType: "User", description: "User logged in from new device", date: "2026-04-04T07:45:00Z" },
{ action: "UPDATE", module: "planning", entityType: "BudgetLine", description: "Updated FY2026 engineering budget", date: "2026-03-15T15:20:00Z" },
];
for (const entry of auditEntries) {
await prisma.auditLog.create({
data: {
organizationId: organization.id,
userId: user.id,
userName: user.name,
action: entry.action,
module: entry.module,
entityType: entry.entityType,
description: entry.description,
createdAt: new Date(entry.date),
},
});
}
console.log(`✓ Created ${auditEntries.length} audit log entries`);
// ========================================
// SUMMARY
// ========================================
console.log("\n✅ Database seed completed successfully!");
console.log(`
Organization: ${organization.name}
Entities: ${entities.length}
Users: 1 (${user.email})
Accounts: ${accountsData.length}
Fiscal Periods: 36 (FY2024-FY2026)
Journal Entries: ${jeCounter} (spanning Jan 2025 - Apr 2026)
Vendors: ${vendors.length}
Purchase Orders: ${purchaseOrders.length}
Customers: ${customers.length}
AP Invoices: ${apInvoices.length}
AR Invoices: ${arInvoices.length}
Payments: ${payments.length}
Bank Accounts: ${bankAccounts.length}
Bank Transactions: ${bankTransactions.length}
Cash Position Snapshots: ${cashSnapshots.length}
Budget Lines: ${budgetData.length + fy2025BudgetData.length} (FY2025 + FY2026)
Leases: ${leases.length}
Shareholders: ${shareholders.length}
Subscriptions: ${subscriptions.length}
Forecasts: ${forecasts.length}
Documents: ${documents.length}
Audit Log Entries: ${auditEntries.length}
`);
}
main()
.then(async () => {
await prisma.$disconnect();
})
.catch(async (e) => {
console.error("❌ Seed error:", e);
await prisma.$disconnect();
process.exit(1);
});