/** * Phase 1 smoke test: posts a balanced manual journal entry, confirms an unbalanced one is * rejected, then prints a simple Main + per-branch debit/credit sum to confirm everything * still balances. Run after `npm run prisma:seed` against a real database: * npm run smoke */ import { PrismaClient } from '@prisma/client'; import { PostingService } from '../src/modules/gl/posting.service'; import { UnbalancedEntryError } from '../src/modules/gl/posting.types'; const prisma = new PrismaClient(); async function getAccount(accountCode: string) { return prisma.gLAccount.findUniqueOrThrow({ where: { accountCode } }); } async function main() { const admin = await prisma.user.findUniqueOrThrow({ where: { email: 'joosth2002@icloud.com' } }); const bankHQ = await getAccount('1000-000-000-HQ'); const salesHQ = await getAccount('4000-000-000-HQ'); const bankAMA = await getAccount('1000-000-000-AMA'); const salesAMA = await getAccount('4000-000-000-AMA'); console.log('Posting a balanced entry at HQ...'); const hqEntry = await PostingService.postEntry({ journalCode: 'GJ', entryDate: new Date(), description: 'Smoke test cash sale — HQ', sourceModule: 'GL', sourceType: 'SmokeTest', createdById: admin.id, lines: [ { glAccountId: bankHQ.id, debit: 1000, credit: 0, branchSegmentValueId: bankHQ.id }, { glAccountId: salesHQ.id, debit: 0, credit: 1000, branchSegmentValueId: salesHQ.id }, ], }); console.log(` Posted ${hqEntry.entryNumber}: debits ${hqEntry.totalDebits} / credits ${hqEntry.totalCredits}`); console.log('Posting a balanced entry at AMA...'); const amaEntry = await PostingService.postEntry({ journalCode: 'GJ', entryDate: new Date(), description: 'Smoke test cash sale — AMA', sourceModule: 'GL', sourceType: 'SmokeTest', createdById: admin.id, lines: [ { glAccountId: bankAMA.id, debit: 400, credit: 0 }, { glAccountId: salesAMA.id, debit: 0, credit: 400 }, ], }); console.log(` Posted ${amaEntry.entryNumber}: debits ${amaEntry.totalDebits} / credits ${amaEntry.totalCredits}`); console.log('Attempting an unbalanced entry (should be rejected)...'); try { await PostingService.postEntry({ journalCode: 'GJ', entryDate: new Date(), description: 'This should never persist', sourceModule: 'GL', sourceType: 'SmokeTest', createdById: admin.id, lines: [ { glAccountId: bankHQ.id, debit: 100, credit: 0 }, { glAccountId: salesHQ.id, debit: 0, credit: 50 }, ], }); throw new Error('Unbalanced entry was accepted — this is a bug in PostingService'); } catch (error) { if (error instanceof UnbalancedEntryError) { console.log(` Correctly rejected: ${error.message}`); } else { throw error; } } console.log('Trial balance check (sum of all posted lines, grouped by account type)...'); const lines = await prisma.journalEntryLine.findMany({ include: { glAccount: true } }); const totalDebits = lines.reduce((total, line) => total + Number(line.debit), 0); const totalCredits = lines.reduce((total, line) => total + Number(line.credit), 0); console.log(` Main: total debits ${totalDebits.toFixed(2)}, total credits ${totalCredits.toFixed(2)}`); if (totalDebits !== totalCredits) { throw new Error('Trial balance does not sum to zero — double-entry invariant violated'); } console.log('Smoke test passed: every posted entry balances.'); } main() .catch((error) => { console.error(error); process.exitCode = 1; }) .finally(async () => { await prisma.$disconnect(); });