@happyvertical/smrt-ledgers 0.60.0 → 0.60.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["journal"],"sources":["../src/__smrt-register__.ts","../src/prompts.ts","../src/collections/Accounts.ts","../src/models/JournalEntry.ts","../src/collections/JournalEntries.ts","../src/models/Journal.ts","../src/collections/Journals.ts","../src/collections/Ledgers.ts","../src/migrations/ledger-accounts-table.ts","../src/postings.ts","../src/recipes.ts"],"sourcesContent":["// Generated by @happyvertical/smrt-core smrtPlugin at library build time.\n// The package manifest is inlined so self-registration cannot miss when a\n// downstream bundler relocates this module away from dist/manifest.json\n// (https://github.com/happyvertical/smrt/issues/1506,\n// https://github.com/happyvertical/smrt/issues/1507).\nimport { ObjectRegistry } from '@happyvertical/smrt-core';\n\nObjectRegistry.registerPackageManifest(JSON.parse(\"{\\\"version\\\":\\\"1.0.0\\\",\\\"timestamp\\\":0,\\\"packageName\\\":\\\"@happyvertical/smrt-ledgers\\\",\\\"packageVersion\\\":\\\"0.60.0\\\",\\\"objects\\\":{\\\"@happyvertical/smrt-ledgers:AccountCollection\\\":{\\\"name\\\":\\\"accountcollection\\\",\\\"className\\\":\\\"AccountCollection\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-ledgers:AccountCollection\\\",\\\"collection\\\":\\\"accounts\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/ledgers/src/collections/Accounts.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-ledgers\\\",\\\"fields\\\":{},\\\"methods\\\":{\\\"findByNumber\\\":{\\\"name\\\":\\\"findByNumber\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"number\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Account | null>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findByType\\\":{\\\"name\\\":\\\"findByType\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"type\\\",\\\"type\\\":\\\"AccountType\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Account[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findActive\\\":{\\\"name\\\":\\\"findActive\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<Account[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findTopLevel\\\":{\\\"name\\\":\\\"findTopLevel\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<Account[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findChildren\\\":{\\\"name\\\":\\\"findChildren\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"parentId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Account[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getTree\\\":{\\\"name\\\":\\\"getTree\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<AccountTree>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getOrCreateByNumber\\\":{\\\"name\\\":\\\"getOrCreateByNumber\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"number\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"defaults\\\",\\\"type\\\":\\\"Partial<object>\\\",\\\"optional\\\":true,\\\"memberTypes\\\":[\\\"string\\\",\\\"AccountType\\\",\\\"string | null\\\"]}],\\\"returnType\\\":\\\"Promise<Account>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"groupByType\\\":{\\\"name\\\":\\\"groupByType\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<Record<AccountType, Account[]>>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getDescendants\\\":{\\\"name\\\":\\\"getDescendants\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"accountId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Account[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findByTenant\\\":{\\\"name\\\":\\\"findByTenant\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"tenantId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Account[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findGlobal\\\":{\\\"name\\\":\\\"findGlobal\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<Account[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findWithGlobals\\\":{\\\"name\\\":\\\"findWithGlobals\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"tenantId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Account[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"ledger_accounts\\\",\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\",\\\"delete\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\"]}},\\\"extends\\\":\\\"SmrtCollection\\\",\\\"extendsTypeArg\\\":\\\"Account\\\",\\\"exportName\\\":\\\"AccountCollection\\\",\\\"collectionExportName\\\":\\\"AccountCollectionCollection\\\",\\\"collectionOf\\\":\\\"@happyvertical/smrt-ledgers:Account\\\",\\\"inheritedExposure\\\":[\\\"api\\\",\\\"mcp\\\"],\\\"schema\\\":{\\\"tableName\\\":\\\"ledger_accounts\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"ledger_accounts\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"parent_id\\\\\\\" UUID,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"number\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"name\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"description\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"type\\\\\\\" TEXT DEFAULT 'asset',\\\\n \\\\\\\"ledger_id\\\\\\\" UUID,\\\\n \\\\\\\"active\\\\\\\" BOOLEAN DEFAULT TRUE,\\\\n \\\\\\\"metadata\\\\\\\" JSON DEFAULT '{}'\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"parent_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"ledger_accounts\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"NO ACTION\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"number\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"name\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"description\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"type\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"asset\\\"},\\\"ledger_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"ledgers\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"NO ACTION\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"active\\\":{\\\"type\\\":\\\"BOOLEAN\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":true},\\\"metadata\\\":{\\\"type\\\":\\\"JSON\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":{}}},\\\"indexes\\\":[{\\\"name\\\":\\\"ledger_accounts_slug_context_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"],\\\"unique\\\":true,\\\"nullsNotDistinct\\\":true},{\\\"name\\\":\\\"ledger_accounts_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"ledger_accounts_parent_id_idx\\\",\\\"columns\\\":[\\\"parent_id\\\"]},{\\\"name\\\":\\\"ledger_accounts_ledger_id_idx\\\",\\\"columns\\\":[\\\"ledger_id\\\"]}],\\\"version\\\":\\\"caea63eb\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-ledgers\\\"},\\\"@happyvertical/smrt-ledgers:JournalEntryCollection\\\":{\\\"name\\\":\\\"journalentrycollection\\\",\\\"className\\\":\\\"JournalEntryCollection\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-ledgers:JournalEntryCollection\\\",\\\"collection\\\":\\\"journalentries\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/ledgers/src/collections/JournalEntries.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-ledgers\\\",\\\"fields\\\":{},\\\"methods\\\":{\\\"findByJournal\\\":{\\\"name\\\":\\\"findByJournal\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"journalId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<JournalEntry[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findByAccount\\\":{\\\"name\\\":\\\"findByAccount\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"accountId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<JournalEntry[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getCounterpartyBalances\\\":{\\\"name\\\":\\\"getCounterpartyBalances\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"options\\\",\\\"type\\\":\\\"PostedJournalMovementOptions\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<CounterpartyBalance[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getCounterpartyAging\\\":{\\\"name\\\":\\\"getCounterpartyAging\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"options\\\",\\\"type\\\":\\\"PostedJournalMovementOptions\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"asOf\\\",\\\"type\\\":\\\"Date\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<CounterpartyAgingRow[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getAccountBalance\\\":{\\\"name\\\":\\\"getAccountBalance\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"accountId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"asOfDate\\\",\\\"type\\\":\\\"Date\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<number>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getTrialBalance\\\":{\\\"name\\\":\\\"getTrialBalance\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"asOfDate\\\",\\\"type\\\":\\\"Date\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<TrialBalanceRow[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getTotalsForDateRange\\\":{\\\"name\\\":\\\"getTotalsForDateRange\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"start\\\",\\\"type\\\":\\\"Date\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"end\\\",\\\"type\\\":\\\"Date\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<object>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findByAccounts\\\":{\\\"name\\\":\\\"findByAccounts\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"accountIds\\\",\\\"type\\\":\\\"string[]\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<JournalEntry[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"listPostedMovements\\\":{\\\"name\\\":\\\"listPostedMovements\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"options\\\",\\\"type\\\":\\\"PostedJournalMovementOptions\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<PostedJournalMovement[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getAccountLedger\\\":{\\\"name\\\":\\\"getAccountLedger\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"accountId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Array<object>>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findByTenant\\\":{\\\"name\\\":\\\"findByTenant\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"tenantId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<JournalEntry[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findGlobal\\\":{\\\"name\\\":\\\"findGlobal\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<JournalEntry[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findWithGlobals\\\":{\\\"name\\\":\\\"findWithGlobals\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"tenantId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<JournalEntry[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]}},\\\"extends\\\":\\\"SmrtCollection\\\",\\\"extendsTypeArg\\\":\\\"JournalEntry\\\",\\\"exportName\\\":\\\"JournalEntryCollection\\\",\\\"collectionExportName\\\":\\\"JournalEntryCollectionCollection\\\",\\\"collectionOf\\\":\\\"@happyvertical/smrt-ledgers:JournalEntry\\\",\\\"inheritedExposure\\\":[\\\"api\\\",\\\"mcp\\\"],\\\"schema\\\":{\\\"tableName\\\":\\\"journal_entries\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"journal_entries\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"journal_id\\\\\\\" UUID,\\\\n \\\\\\\"account_id\\\\\\\" UUID,\\\\n \\\\\\\"counterparty_kind\\\\\\\" TEXT,\\\\n \\\\\\\"counterparty_id\\\\\\\" TEXT,\\\\n \\\\\\\"due_date\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"settles_source_ref\\\\\\\" TEXT,\\\\n \\\\\\\"debit\\\\\\\" REAL DEFAULT 0,\\\\n \\\\\\\"credit\\\\\\\" REAL DEFAULT 0,\\\\n \\\\\\\"currency\\\\\\\" TEXT DEFAULT 'USD',\\\\n \\\\\\\"exchange_rate\\\\\\\" REAL DEFAULT 1,\\\\n \\\\\\\"memo\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"metadata\\\\\\\" JSON DEFAULT '{}'\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"journal_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"journals\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"NO ACTION\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"account_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"ledger_accounts\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"NO ACTION\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"counterparty_kind\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"counterparty_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"due_date\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"settles_source_ref\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"debit\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":0},\\\"credit\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":0},\\\"currency\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"USD\\\"},\\\"exchange_rate\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":1},\\\"memo\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"metadata\\\":{\\\"type\\\":\\\"JSON\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":{}}},\\\"indexes\\\":[{\\\"name\\\":\\\"journal_entries_slug_context_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"],\\\"unique\\\":true,\\\"nullsNotDistinct\\\":true},{\\\"name\\\":\\\"journal_entries_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"journal_entries_journal_id_idx\\\",\\\"columns\\\":[\\\"journal_id\\\"]},{\\\"name\\\":\\\"journal_entries_account_id_idx\\\",\\\"columns\\\":[\\\"account_id\\\"]}],\\\"version\\\":\\\"e96b76a2\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-ledgers\\\"},\\\"@happyvertical/smrt-ledgers:JournalCollection\\\":{\\\"name\\\":\\\"journalcollection\\\",\\\"className\\\":\\\"JournalCollection\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-ledgers:JournalCollection\\\",\\\"collection\\\":\\\"journals\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/ledgers/src/collections/Journals.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-ledgers\\\",\\\"fields\\\":{},\\\"methods\\\":{\\\"findByNumber\\\":{\\\"name\\\":\\\"findByNumber\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"number\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Journal | null>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findByDateRange\\\":{\\\"name\\\":\\\"findByDateRange\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"start\\\",\\\"type\\\":\\\"Date\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"end\\\",\\\"type\\\":\\\"Date\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Journal[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findBySource\\\":{\\\"name\\\":\\\"findBySource\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"sourceModule\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Journal[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findByStatus\\\":{\\\"name\\\":\\\"findByStatus\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"status\\\",\\\"type\\\":\\\"JournalStatus\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Journal[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findDrafts\\\":{\\\"name\\\":\\\"findDrafts\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<Journal[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findPosted\\\":{\\\"name\\\":\\\"findPosted\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<Journal[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"createWithEntries\\\":{\\\"name\\\":\\\"createWithEntries\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"data\\\",\\\"type\\\":\\\"CreateJournalData\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Journal>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"post\\\":{\\\"name\\\":\\\"post\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"journalId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Journal>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"void\\\":{\\\"name\\\":\\\"void\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"journalId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"reason\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Journal>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findBySourceRef\\\":{\\\"name\\\":\\\"findBySourceRef\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"sourceRef\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Journal[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findByMonth\\\":{\\\"name\\\":\\\"findByMonth\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"year\\\",\\\"type\\\":\\\"number\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"month\\\",\\\"type\\\":\\\"number\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Journal[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findByTenant\\\":{\\\"name\\\":\\\"findByTenant\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"tenantId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Journal[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findGlobal\\\":{\\\"name\\\":\\\"findGlobal\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<Journal[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findWithGlobals\\\":{\\\"name\\\":\\\"findWithGlobals\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"tenantId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Journal[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\"]}},\\\"extends\\\":\\\"SmrtCollection\\\",\\\"extendsTypeArg\\\":\\\"Journal\\\",\\\"exportName\\\":\\\"JournalCollection\\\",\\\"collectionExportName\\\":\\\"JournalCollectionCollection\\\",\\\"collectionOf\\\":\\\"@happyvertical/smrt-ledgers:Journal\\\",\\\"inheritedExposure\\\":[\\\"api\\\",\\\"mcp\\\"],\\\"schema\\\":{\\\"tableName\\\":\\\"journals\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"journals\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"number\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"date\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"description\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"source_module\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"source_ref\\\\\\\" TEXT,\\\\n \\\\\\\"ledger_id\\\\\\\" UUID,\\\\n \\\\\\\"idempotency_key\\\\\\\" TEXT,\\\\n \\\\\\\"request_digest\\\\\\\" TEXT,\\\\n \\\\\\\"status\\\\\\\" TEXT DEFAULT 'draft',\\\\n \\\\\\\"posted_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"voided_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"void_reason\\\\\\\" TEXT,\\\\n \\\\\\\"metadata\\\\\\\" JSON DEFAULT '{}'\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"number\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"date\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"description\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"source_module\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"source_ref\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"ledger_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"ledgers\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"NO ACTION\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"idempotency_key\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"request_digest\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"status\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"draft\\\"},\\\"posted_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"voided_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"void_reason\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"metadata\\\":{\\\"type\\\":\\\"JSON\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":{}}},\\\"indexes\\\":[{\\\"name\\\":\\\"journals_slug_context_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"],\\\"unique\\\":true,\\\"nullsNotDistinct\\\":true},{\\\"name\\\":\\\"journals_ledger_idempotency_key\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"ledger_id\\\",\\\"idempotency_key\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"journals_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"journals_ledger_id_idx\\\",\\\"columns\\\":[\\\"ledger_id\\\"]}],\\\"version\\\":\\\"1e73dd60\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-ledgers\\\"},\\\"@happyvertical/smrt-ledgers:LedgerCollection\\\":{\\\"name\\\":\\\"ledgercollection\\\",\\\"className\\\":\\\"LedgerCollection\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-ledgers:LedgerCollection\\\",\\\"collection\\\":\\\"ledgers\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/ledgers/src/collections/Ledgers.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-ledgers\\\",\\\"fields\\\":{},\\\"methods\\\":{},\\\"decoratorConfig\\\":{\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\"]}},\\\"extends\\\":\\\"SmrtCollection\\\",\\\"extendsTypeArg\\\":\\\"Ledger\\\",\\\"exportName\\\":\\\"LedgerCollection\\\",\\\"collectionExportName\\\":\\\"LedgerCollectionCollection\\\",\\\"collectionOf\\\":\\\"@happyvertical/smrt-ledgers:Ledger\\\",\\\"inheritedExposure\\\":[\\\"api\\\",\\\"mcp\\\"],\\\"schema\\\":{\\\"tableName\\\":\\\"ledgers\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"ledgers\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"name\\\\\\\" TEXT,\\\\n \\\\\\\"currency\\\\\\\" TEXT,\\\\n \\\\\\\"balance_mode\\\\\\\" TEXT DEFAULT 'tolerant'\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"name\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"currency\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"balance_mode\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"tolerant\\\"}},\\\"indexes\\\":[{\\\"name\\\":\\\"ledgers_slug_context_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"],\\\"unique\\\":true,\\\"nullsNotDistinct\\\":true},{\\\"name\\\":\\\"ledgers_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]}],\\\"version\\\":\\\"be316e4f\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-ledgers\\\"},\\\"@happyvertical/smrt-ledgers:Account\\\":{\\\"name\\\":\\\"account\\\",\\\"className\\\":\\\"Account\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-ledgers:Account\\\",\\\"collection\\\":\\\"accounts\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/ledgers/src/models/Account.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-ledgers\\\",\\\"fields\\\":{\\\"parentId\\\":{\\\"type\\\":\\\"foreignKey\\\",\\\"required\\\":false,\\\"related\\\":\\\"Account\\\",\\\"_meta\\\":{\\\"nullable\\\":true}},\\\"tenantId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"sqlType\\\":\\\"UUID\\\",\\\"nullable\\\":true,\\\"__tenancy\\\":{\\\"isTenantIdField\\\":true,\\\"autoFilter\\\":true,\\\"required\\\":false,\\\"autoPopulate\\\":true,\\\"nullable\\\":true,\\\"mode\\\":\\\"optional\\\",\\\"field\\\":\\\"tenantId\\\",\\\"allowSuperAdminBypass\\\":false}}},\\\"number\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"\\\",\\\"description\\\":\\\"The account number in your chart of accounts.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The account number in your chart of accounts.\\\"}},\\\"name\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"\\\",\\\"description\\\":\\\"What the account is called.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"What the account is called.\\\"}},\\\"description\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"\\\",\\\"description\\\":\\\"What the account is used for.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"What the account is used for.\\\"}},\\\"type\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"asset\\\",\\\"description\\\":\\\"asset, liability, equity, revenue or expense.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"asset, liability, equity, revenue or expense.\\\"},\\\"enum\\\":[\\\"asset\\\",\\\"liability\\\",\\\"equity\\\",\\\"revenue\\\",\\\"expense\\\"]},\\\"ledgerId\\\":{\\\"type\\\":\\\"foreignKey\\\",\\\"required\\\":false,\\\"related\\\":\\\"Ledger\\\",\\\"description\\\":\\\"The ledger policy this account belongs to.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The ledger policy this account belongs to.\\\",\\\"nullable\\\":true}},\\\"active\\\":{\\\"type\\\":\\\"boolean\\\",\\\"required\\\":false,\\\"default\\\":true,\\\"description\\\":\\\"Whether the account is in use; deactivate it instead of deleting it.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"Whether the account is in use; deactivate it instead of deleting it.\\\"}},\\\"metadata\\\":{\\\"type\\\":\\\"json\\\",\\\"required\\\":false,\\\"default\\\":{}}},\\\"methods\\\":{\\\"getParent\\\":{\\\"name\\\":\\\"getParent\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<this | null>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getChildren\\\":{\\\"name\\\":\\\"getChildren\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<this[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getAncestors\\\":{\\\"name\\\":\\\"getAncestors\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<this[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getDescendants\\\":{\\\"name\\\":\\\"getDescendants\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<this[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getHierarchy\\\":{\\\"name\\\":\\\"getHierarchy\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<HierarchyView<this>>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"moveTo\\\":{\\\"name\\\":\\\"moveTo\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"newParent\\\",\\\"type\\\":\\\"this | string | null\\\",\\\"optional\\\":false,\\\"unionBranches\\\":[{\\\"type\\\":\\\"this\\\"},{\\\"type\\\":\\\"string\\\"},{\\\"type\\\":\\\"null\\\"}]}],\\\"returnType\\\":\\\"Promise<void>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"delete\\\":{\\\"name\\\":\\\"delete\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"options\\\",\\\"type\\\":\\\"any\\\",\\\"optional\\\":true,\\\"typeUnresolved\\\":true}],\\\"returnType\\\":\\\"Promise<void>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"isTopLevel\\\":{\\\"name\\\":\\\"isTopLevel\\\",\\\"async\\\":false,\\\"parameters\\\":[],\\\"returnType\\\":\\\"boolean\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"isDebitNormal\\\":{\\\"name\\\":\\\"isDebitNormal\\\",\\\"async\\\":false,\\\"parameters\\\":[],\\\"returnType\\\":\\\"boolean\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"isCreditNormal\\\":{\\\"name\\\":\\\"isCreditNormal\\\",\\\"async\\\":false,\\\"parameters\\\":[],\\\"returnType\\\":\\\"boolean\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getFullPath\\\":{\\\"name\\\":\\\"getFullPath\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<string>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"toTreeNode\\\":{\\\"name\\\":\\\"toTreeNode\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<AccountTreeNode>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getBalance\\\":{\\\"name\\\":\\\"getBalance\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"asOfDate\\\",\\\"type\\\":\\\"Date\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<number>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"createChild\\\":{\\\"name\\\":\\\"createChild\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"options\\\",\\\"type\\\":\\\"Omit<AccountOptions, 'parentId' | 'type'>\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Account>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"ledger_accounts\\\",\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\",\\\"delete\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\"]},\\\"cli\\\":{\\\"skipApiCheck\\\":true},\\\"tenantScoped\\\":{\\\"mode\\\":\\\"optional\\\"},\\\"conflictColumns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"]},\\\"extends\\\":\\\"SmrtHierarchical\\\",\\\"exportName\\\":\\\"Account\\\",\\\"collectionExportName\\\":\\\"AccountCollection\\\",\\\"displayLabelField\\\":\\\"name\\\",\\\"schema\\\":{\\\"tableName\\\":\\\"ledger_accounts\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"ledger_accounts\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"parent_id\\\\\\\" UUID,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"number\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"name\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"description\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"type\\\\\\\" TEXT DEFAULT 'asset',\\\\n \\\\\\\"ledger_id\\\\\\\" UUID,\\\\n \\\\\\\"active\\\\\\\" BOOLEAN DEFAULT TRUE,\\\\n \\\\\\\"metadata\\\\\\\" JSON DEFAULT '{}'\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"parent_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"ledger_accounts\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"NO ACTION\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"number\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"name\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"description\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"type\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"asset\\\"},\\\"ledger_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"ledgers\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"NO ACTION\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"active\\\":{\\\"type\\\":\\\"BOOLEAN\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":true},\\\"metadata\\\":{\\\"type\\\":\\\"JSON\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":{}}},\\\"indexes\\\":[{\\\"name\\\":\\\"ledger_accounts_slug_context_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"],\\\"unique\\\":true,\\\"nullsNotDistinct\\\":true},{\\\"name\\\":\\\"ledger_accounts_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"ledger_accounts_parent_id_idx\\\",\\\"columns\\\":[\\\"parent_id\\\"]},{\\\"name\\\":\\\"ledger_accounts_ledger_id_idx\\\",\\\"columns\\\":[\\\"ledger_id\\\"]}],\\\"version\\\":\\\"caea63eb\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-ledgers\\\"},\\\"@happyvertical/smrt-ledgers:Journal\\\":{\\\"name\\\":\\\"journal\\\",\\\"className\\\":\\\"Journal\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-ledgers:Journal\\\",\\\"collection\\\":\\\"journals\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/ledgers/src/models/Journal.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-ledgers\\\",\\\"fields\\\":{\\\"tenantId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"sqlType\\\":\\\"UUID\\\",\\\"nullable\\\":true,\\\"__tenancy\\\":{\\\"isTenantIdField\\\":true,\\\"autoFilter\\\":true,\\\"required\\\":false,\\\"autoPopulate\\\":true,\\\"nullable\\\":true,\\\"mode\\\":\\\"optional\\\",\\\"field\\\":\\\"tenantId\\\",\\\"allowSuperAdminBypass\\\":false}}},\\\"number\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"\\\",\\\"description\\\":\\\"The journal's reference number.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The journal's reference number.\\\"}},\\\"date\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false,\\\"description\\\":\\\"The date of the transaction.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The date of the transaction.\\\"}},\\\"description\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"\\\",\\\"description\\\":\\\"What the transaction was.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"What the transaction was.\\\"}},\\\"sourceModule\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"\\\"},\\\"sourceRef\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false},\\\"ledgerId\\\":{\\\"type\\\":\\\"foreignKey\\\",\\\"required\\\":false,\\\"related\\\":\\\"Ledger\\\",\\\"description\\\":\\\"The ledger policy that governs this journal.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The ledger policy that governs this journal.\\\",\\\"nullable\\\":true}},\\\"idempotencyKey\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"nullable\\\":true}},\\\"requestDigest\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false},\\\"status\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"draft\\\",\\\"description\\\":\\\"draft until final, then posted, or voided.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"draft until final, then posted, or voided.\\\"},\\\"enum\\\":[\\\"draft\\\",\\\"posted\\\",\\\"voided\\\"]},\\\"postedAt\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false,\\\"description\\\":\\\"When it was posted.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"When it was posted.\\\"}},\\\"voidedAt\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false},\\\"voidReason\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false},\\\"metadata\\\":{\\\"type\\\":\\\"json\\\",\\\"required\\\":false,\\\"default\\\":{}}},\\\"methods\\\":{\\\"isDraft\\\":{\\\"name\\\":\\\"isDraft\\\",\\\"async\\\":false,\\\"parameters\\\":[],\\\"returnType\\\":\\\"boolean\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"isPosted\\\":{\\\"name\\\":\\\"isPosted\\\",\\\"async\\\":false,\\\"parameters\\\":[],\\\"returnType\\\":\\\"boolean\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"isVoided\\\":{\\\"name\\\":\\\"isVoided\\\",\\\"async\\\":false,\\\"parameters\\\":[],\\\"returnType\\\":\\\"boolean\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"isEditable\\\":{\\\"name\\\":\\\"isEditable\\\",\\\"async\\\":false,\\\"parameters\\\":[],\\\"returnType\\\":\\\"boolean\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getEntries\\\":{\\\"name\\\":\\\"getEntries\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"any\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getTotalDebits\\\":{\\\"name\\\":\\\"getTotalDebits\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<number>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getTotalCredits\\\":{\\\"name\\\":\\\"getTotalCredits\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<number>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"isBalanced\\\":{\\\"name\\\":\\\"isBalanced\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<boolean>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getLedger\\\":{\\\"name\\\":\\\"getLedger\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"any\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"addEntry\\\":{\\\"name\\\":\\\"addEntry\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"data\\\",\\\"type\\\":\\\"JournalEntryData\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<void>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"post\\\":{\\\"name\\\":\\\"post\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<void>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"void\\\":{\\\"name\\\":\\\"void\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"reason\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<void>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"save\\\":{\\\"name\\\":\\\"save\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"options\\\",\\\"type\\\":\\\"any\\\",\\\"optional\\\":true,\\\"typeUnresolved\\\":true}],\\\"returnType\\\":\\\"Promise<this>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"delete\\\":{\\\"name\\\":\\\"delete\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"options\\\",\\\"type\\\":\\\"any\\\",\\\"optional\\\":true,\\\"typeUnresolved\\\":true}],\\\"returnType\\\":\\\"Promise<void>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"summarize\\\":{\\\"name\\\":\\\"summarize\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<string>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\"]},\\\"cli\\\":{\\\"skipApiCheck\\\":true},\\\"indexes\\\":[{\\\"name\\\":\\\"journals_ledger_idempotency_key\\\",\\\"columns\\\":[\\\"tenantId\\\",\\\"ledgerId\\\",\\\"idempotencyKey\\\"],\\\"unique\\\":true}],\\\"tenantScoped\\\":{\\\"mode\\\":\\\"optional\\\"},\\\"conflictColumns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"]},\\\"extends\\\":\\\"SmrtObject\\\",\\\"exportName\\\":\\\"Journal\\\",\\\"collectionExportName\\\":\\\"JournalCollection\\\",\\\"schema\\\":{\\\"tableName\\\":\\\"journals\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"journals\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"number\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"date\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"description\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"source_module\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"source_ref\\\\\\\" TEXT,\\\\n \\\\\\\"ledger_id\\\\\\\" UUID,\\\\n \\\\\\\"idempotency_key\\\\\\\" TEXT,\\\\n \\\\\\\"request_digest\\\\\\\" TEXT,\\\\n \\\\\\\"status\\\\\\\" TEXT DEFAULT 'draft',\\\\n \\\\\\\"posted_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"voided_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"void_reason\\\\\\\" TEXT,\\\\n \\\\\\\"metadata\\\\\\\" JSON DEFAULT '{}'\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"number\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"date\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"description\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"source_module\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"source_ref\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"ledger_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"ledgers\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"NO ACTION\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"idempotency_key\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"request_digest\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"status\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"draft\\\"},\\\"posted_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"voided_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"void_reason\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"metadata\\\":{\\\"type\\\":\\\"JSON\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":{}}},\\\"indexes\\\":[{\\\"name\\\":\\\"journals_slug_context_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"],\\\"unique\\\":true,\\\"nullsNotDistinct\\\":true},{\\\"name\\\":\\\"journals_ledger_idempotency_key\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"ledger_id\\\",\\\"idempotency_key\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"journals_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"journals_ledger_id_idx\\\",\\\"columns\\\":[\\\"ledger_id\\\"]}],\\\"version\\\":\\\"1e73dd60\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-ledgers\\\"},\\\"@happyvertical/smrt-ledgers:JournalEntry\\\":{\\\"name\\\":\\\"journalentry\\\",\\\"className\\\":\\\"JournalEntry\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-ledgers:JournalEntry\\\",\\\"collection\\\":\\\"journalentries\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/ledgers/src/models/JournalEntry.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-ledgers\\\",\\\"fields\\\":{\\\"tenantId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"sqlType\\\":\\\"UUID\\\",\\\"nullable\\\":true,\\\"__tenancy\\\":{\\\"isTenantIdField\\\":true,\\\"autoFilter\\\":true,\\\"required\\\":false,\\\"autoPopulate\\\":true,\\\"nullable\\\":true,\\\"mode\\\":\\\"optional\\\",\\\"field\\\":\\\"tenantId\\\",\\\"allowSuperAdminBypass\\\":false}}},\\\"journalId\\\":{\\\"type\\\":\\\"foreignKey\\\",\\\"required\\\":false,\\\"related\\\":\\\"Journal\\\",\\\"description\\\":\\\"The journal this entry belongs to.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The journal this entry belongs to.\\\"}},\\\"accountId\\\":{\\\"type\\\":\\\"foreignKey\\\",\\\"required\\\":false,\\\"related\\\":\\\"Account\\\",\\\"description\\\":\\\"The account this entry changes.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The account this entry changes.\\\"}},\\\"counterpartyKind\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"Generic counterparty type.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"Generic counterparty type.\\\",\\\"nullable\\\":true}},\\\"counterpartyId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"Generic counterparty identifier.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"Generic counterparty identifier.\\\",\\\"nullable\\\":true}},\\\"dueDate\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false,\\\"description\\\":\\\"When this open receivable or payable is due.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"When this open receivable or payable is due.\\\"}},\\\"settlesSourceRef\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false},\\\"debit\\\":{\\\"type\\\":\\\"decimal\\\",\\\"required\\\":false,\\\"default\\\":0,\\\"description\\\":\\\"The amount debited. Zero on a credit entry.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The amount debited. Zero on a credit entry.\\\"}},\\\"credit\\\":{\\\"type\\\":\\\"decimal\\\",\\\"required\\\":false,\\\"default\\\":0,\\\"description\\\":\\\"The amount credited. Zero on a debit entry.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The amount credited. Zero on a debit entry.\\\"}},\\\"currency\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"USD\\\",\\\"description\\\":\\\"The currency of the amounts.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The currency of the amounts.\\\"}},\\\"exchangeRate\\\":{\\\"type\\\":\\\"decimal\\\",\\\"required\\\":false,\\\"default\\\":1},\\\"memo\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"\\\",\\\"description\\\":\\\"A note on this entry.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"A note on this entry.\\\"}},\\\"metadata\\\":{\\\"type\\\":\\\"json\\\",\\\"required\\\":false,\\\"default\\\":{}}},\\\"methods\\\":{\\\"save\\\":{\\\"name\\\":\\\"save\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"options\\\",\\\"type\\\":\\\"any\\\",\\\"optional\\\":true,\\\"typeUnresolved\\\":true}],\\\"returnType\\\":\\\"Promise<this>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"delete\\\":{\\\"name\\\":\\\"delete\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"options\\\",\\\"type\\\":\\\"any\\\",\\\"optional\\\":true,\\\"typeUnresolved\\\":true}],\\\"returnType\\\":\\\"Promise<void>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"isDebit\\\":{\\\"name\\\":\\\"isDebit\\\",\\\"async\\\":false,\\\"parameters\\\":[],\\\"returnType\\\":\\\"boolean\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"isCredit\\\":{\\\"name\\\":\\\"isCredit\\\",\\\"async\\\":false,\\\"parameters\\\":[],\\\"returnType\\\":\\\"boolean\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getAmount\\\":{\\\"name\\\":\\\"getAmount\\\",\\\"async\\\":false,\\\"parameters\\\":[],\\\"returnType\\\":\\\"number\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getBaseAmount\\\":{\\\"name\\\":\\\"getBaseAmount\\\",\\\"async\\\":false,\\\"parameters\\\":[],\\\"returnType\\\":\\\"number\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getJournal\\\":{\\\"name\\\":\\\"getJournal\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"any\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getAccount\\\":{\\\"name\\\":\\\"getAccount\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"any\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getDescription\\\":{\\\"name\\\":\\\"getDescription\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<string>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"cli\\\":{\\\"skipApiCheck\\\":true},\\\"tenantScoped\\\":{\\\"mode\\\":\\\"optional\\\"},\\\"conflictColumns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"]},\\\"extends\\\":\\\"SmrtObject\\\",\\\"exportName\\\":\\\"JournalEntry\\\",\\\"collectionExportName\\\":\\\"JournalEntryCollection\\\",\\\"schema\\\":{\\\"tableName\\\":\\\"journal_entries\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"journal_entries\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"journal_id\\\\\\\" UUID,\\\\n \\\\\\\"account_id\\\\\\\" UUID,\\\\n \\\\\\\"counterparty_kind\\\\\\\" TEXT,\\\\n \\\\\\\"counterparty_id\\\\\\\" TEXT,\\\\n \\\\\\\"due_date\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"settles_source_ref\\\\\\\" TEXT,\\\\n \\\\\\\"debit\\\\\\\" REAL DEFAULT 0,\\\\n \\\\\\\"credit\\\\\\\" REAL DEFAULT 0,\\\\n \\\\\\\"currency\\\\\\\" TEXT DEFAULT 'USD',\\\\n \\\\\\\"exchange_rate\\\\\\\" REAL DEFAULT 1,\\\\n \\\\\\\"memo\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"metadata\\\\\\\" JSON DEFAULT '{}'\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"journal_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"journals\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"NO ACTION\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"account_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"ledger_accounts\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"NO ACTION\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"counterparty_kind\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"counterparty_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"due_date\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"settles_source_ref\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"debit\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":0},\\\"credit\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":0},\\\"currency\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"USD\\\"},\\\"exchange_rate\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":1},\\\"memo\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"metadata\\\":{\\\"type\\\":\\\"JSON\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":{}}},\\\"indexes\\\":[{\\\"name\\\":\\\"journal_entries_slug_context_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"],\\\"unique\\\":true,\\\"nullsNotDistinct\\\":true},{\\\"name\\\":\\\"journal_entries_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"journal_entries_journal_id_idx\\\",\\\"columns\\\":[\\\"journal_id\\\"]},{\\\"name\\\":\\\"journal_entries_account_id_idx\\\",\\\"columns\\\":[\\\"account_id\\\"]}],\\\"version\\\":\\\"e96b76a2\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-ledgers\\\"},\\\"@happyvertical/smrt-ledgers:Ledger\\\":{\\\"name\\\":\\\"ledger\\\",\\\"className\\\":\\\"Ledger\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-ledgers:Ledger\\\",\\\"collection\\\":\\\"ledgers\\\",\\\"description\\\":\\\"A named accounting scope. Exact ledgers store one currency's minor units and reject fractional entries; legacy journals without a ledger retain the tolerant balance rule for backwards compatibility.\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/ledgers/src/models/Ledger.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-ledgers\\\",\\\"fields\\\":{\\\"tenantId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"sqlType\\\":\\\"UUID\\\",\\\"nullable\\\":true,\\\"__tenancy\\\":{\\\"isTenantIdField\\\":true,\\\"autoFilter\\\":true,\\\"required\\\":false,\\\"autoPopulate\\\":true,\\\"nullable\\\":true,\\\"mode\\\":\\\"optional\\\",\\\"field\\\":\\\"tenantId\\\",\\\"allowSuperAdminBypass\\\":false}}},\\\"name\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"The accounting scope name.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The accounting scope name.\\\"}},\\\"currency\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"ISO 4217 currency used by this ledger.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"ISO 4217 currency used by this ledger.\\\"}},\\\"balanceMode\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"tolerant\\\",\\\"description\\\":\\\"tolerant accepts decimal units; exact requires integer minor units.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"tolerant accepts decimal units; exact requires integer minor units.\\\"},\\\"enum\\\":[\\\"tolerant\\\",\\\"exact-integer\\\"]}},\\\"methods\\\":{\\\"delete\\\":{\\\"name\\\":\\\"delete\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<void>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\"]},\\\"cli\\\":{\\\"skipApiCheck\\\":true},\\\"tenantScoped\\\":{\\\"mode\\\":\\\"optional\\\"},\\\"conflictColumns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"]},\\\"extends\\\":\\\"SmrtObject\\\",\\\"exportName\\\":\\\"Ledger\\\",\\\"collectionExportName\\\":\\\"LedgerCollection\\\",\\\"displayLabelField\\\":\\\"name\\\",\\\"schema\\\":{\\\"tableName\\\":\\\"ledgers\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"ledgers\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"name\\\\\\\" TEXT,\\\\n \\\\\\\"currency\\\\\\\" TEXT,\\\\n \\\\\\\"balance_mode\\\\\\\" TEXT DEFAULT 'tolerant'\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"name\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"currency\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"balance_mode\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"tolerant\\\"}},\\\"indexes\\\":[{\\\"name\\\":\\\"ledgers_slug_context_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"],\\\"unique\\\":true,\\\"nullsNotDistinct\\\":true},{\\\"name\\\":\\\"ledgers_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]}],\\\"version\\\":\\\"be316e4f\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-ledgers\\\"}},\\\"moduleType\\\":\\\"smrt\\\",\\\"recipes\\\":[{\\\"id\\\":\\\"ledgers.bookkeeping\\\",\\\"className\\\":\\\"BookkeepingRecipe\\\",\\\"label\\\":\\\"Bookkeeping\\\",\\\"summary\\\":\\\"Keep your books: a chart of accounts and double-entry journals.\\\",\\\"synonyms\\\":[\\\"accounting\\\",\\\"ledger\\\",\\\"general ledger\\\",\\\"journals\\\",\\\"chart of accounts\\\"],\\\"models\\\":[\\\"@happyvertical/smrt-ledgers:Account\\\",\\\"@happyvertical/smrt-ledgers:Journal\\\",\\\"@happyvertical/smrt-ledgers:JournalEntry\\\"],\\\"nav\\\":[{\\\"label\\\":\\\"Accounts\\\",\\\"model\\\":\\\"@happyvertical/smrt-ledgers:Account\\\",\\\"icon\\\":\\\"bank\\\",\\\"description\\\":\\\"The accounts your books are kept in, like sales, rent and bank.\\\"},{\\\"label\\\":\\\"Journals\\\",\\\"model\\\":\\\"@happyvertical/smrt-ledgers:Journal\\\",\\\"icon\\\":\\\"book\\\",\\\"description\\\":\\\"The entries behind your accounts, so every dollar has a trail.\\\"}],\\\"requires\\\":[],\\\"section\\\":{\\\"id\\\":\\\"accounting\\\",\\\"label\\\":\\\"Accounting\\\",\\\"icon\\\":\\\"bank\\\",\\\"description\\\":\\\"Your books: accounts, journals and balances.\\\"},\\\"options\\\":{\\\"@happyvertical/smrt-ledgers:Account\\\":{\\\"fields\\\":{\\\"metadata\\\":{\\\"visibility\\\":\\\"hidden\\\"},\\\"parentId\\\":{\\\"visibility\\\":\\\"hidden\\\"}}},\\\"@happyvertical/smrt-ledgers:Journal\\\":{\\\"fields\\\":{\\\"sourceModule\\\":{\\\"visibility\\\":\\\"hidden\\\"},\\\"sourceRef\\\":{\\\"visibility\\\":\\\"hidden\\\"},\\\"idempotencyKey\\\":{\\\"visibility\\\":\\\"hidden\\\"},\\\"requestDigest\\\":{\\\"visibility\\\":\\\"hidden\\\"},\\\"voidedAt\\\":{\\\"visibility\\\":\\\"hidden\\\"},\\\"voidReason\\\":{\\\"visibility\\\":\\\"hidden\\\"},\\\"metadata\\\":{\\\"visibility\\\":\\\"hidden\\\"}}},\\\"@happyvertical/smrt-ledgers:JournalEntry\\\":{\\\"fields\\\":{\\\"exchangeRate\\\":{\\\"visibility\\\":\\\"hidden\\\"},\\\"settlesSourceRef\\\":{\\\"visibility\\\":\\\"hidden\\\"},\\\"metadata\\\":{\\\"visibility\\\":\\\"hidden\\\"}}}},\\\"help\\\":{\\\"markdown\\\":\\\"## Overview\\\\n\\\\nBookkeeping keeps your accounts. You list the accounts you use (your chart of\\\\naccounts) and record each transaction as a journal whose entries debit and\\\\ncredit those accounts.\\\\n\\\\n## Tasks\\\\n\\\\n### Set up your accounts\\\\n\\\\n1. Create a new account.\\\\n2. Give it a **{field:number}** and a **{field:name}**.\\\\n3. Choose its **{field:type}**: asset, liability, equity, revenue or expense.\\\\n\\\\n### Record a transaction\\\\n\\\\n1. Create a new journal and add a **{field:description}**.\\\\n2. Add entries: pick the account on each and enter a **{field:debit}** or a\\\\n **{field:credit}**. They must add up to the same total.\\\\n3. Set the journal's **{field:status}** to posted when it is final. A posted\\\\n journal is voided, not edited.\\\\n\\\",\\\"fieldRefs\\\":[\\\"credit\\\",\\\"debit\\\",\\\"description\\\",\\\"name\\\",\\\"number\\\",\\\"status\\\",\\\"type\\\"]},\\\"demo\\\":{\\\"mode\\\":\\\"server\\\",\\\"reasons\\\":[\\\"Needs a server because its package does not build for a browser: core migrations (node:os, node:crypto); and its package depends on @happyvertical/smrt-tenancy, which do not build for a browser (#3624, #3626).\\\"]}}],\\\"smrtDependencies\\\":[\\\"@happyvertical/smrt-core\\\",\\\"@happyvertical/smrt-prompts\\\",\\\"@happyvertical/smrt-tenancy\\\"],\\\"browser\\\":{\\\"status\\\":\\\"server-only\\\",\\\"issues\\\":[\\\"#3624\\\",\\\"#3626\\\"],\\\"reason\\\":\\\"core migrations (node:os, node:crypto)\\\",\\\"via\\\":[\\\"@happyvertical/smrt-tenancy\\\"]},\\\"stampsConstructors\\\":true}\"));\n","/**\n * Prompt registrations for the @happyvertical/smrt-ledgers package.\n *\n * Prompts are registered at module-load time via `definePrompt()` so that\n * tenant-aware overrides can be applied at call time via `resolvePrompt()`.\n *\n * Mirrors the pattern used by `@happyvertical/smrt-properties` (see\n * `prompts.ts`) and `@happyvertical/smrt-content` (see `content-prompts.ts`).\n */\n\nimport {\n definePrompt,\n type ResolvedPromptAI,\n} from '@happyvertical/smrt-prompts';\n\n// Journal summarization only uses non-PII journal fields\n// (number, date, description, status, balanced flag) plus aggregate totals\n// and entry count. Internal/foreign-key fields like tenantId, sourceRef,\n// individual entry account IDs, and the extensible `metadata` blob are\n// intentionally NOT passed to the AI provider — they may link to identifying\n// records (customer/vendor IDs via sourceRef) or contain tenant-private\n// configuration. If a downstream tenant needs richer context they can\n// override the template via PromptOverride.\n// Note: smrt-prompts substitutes `{token}` placeholders. The currency prefix\n// is folded into the `journalTotal` variable value (e.g. \"$100.00\") rather\n// than written as a literal `$` in the template — earlier revisions used\n// `\\${journalTotal}` (a template-literal escape that renders as the literal\n// `${journalTotal}` at runtime). That technically worked because the regex\n// still matched the inner `{journalTotal}` and produced `$100.00`, but it\n// confused reviewers; folding the prefix into the value avoids the trap.\nexport const smrtLedgersJournalSummarizePrompt = definePrompt({\n key: 'smrtLedgers.journal.summarize',\n template: `Summarize this accounting journal entry:\nNumber: {journalNumber}\nDate: {journalDate}\nDescription: {journalDescription}\nStatus: {journalStatus}\nTotal: {journalTotal}\nEntries: {entryCount}\nBalanced: {journalBalanced}`,\n editable: {\n template: true,\n profile: true,\n model: true,\n params: true,\n },\n});\n\nexport function promptMessageOptions(ai: ResolvedPromptAI) {\n return {\n ...(ai.params || {}),\n ...(ai.model ? { model: ai.model } : {}),\n ...(typeof ai.temperature === 'number'\n ? { temperature: ai.temperature }\n : {}),\n ...(typeof ai.maxTokens === 'number' ? { maxTokens: ai.maxTokens } : {}),\n };\n}\n","/**\n * AccountCollection - Collection manager for Account objects\n *\n * Provides querying and tree operations for chart of accounts.\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { queryGlobal, queryWithGlobals } from '@happyvertical/smrt-tenancy';\nimport { Account } from '../models/Account';\nimport type { AccountTree, AccountTreeNode, AccountType } from '../types';\n\nexport class AccountCollection extends SmrtCollection<Account> {\n static readonly _itemClass = Account;\n\n /**\n * Find account by number\n *\n * @param number - Account number\n * @returns Account or null\n */\n async findByNumber(number: string): Promise<Account | null> {\n const accounts = await this.list({\n where: { number },\n limit: 1,\n });\n return accounts[0] || null;\n }\n\n /**\n * Find accounts by type\n *\n * @param type - Account type\n * @returns Array of accounts\n */\n async findByType(type: AccountType): Promise<Account[]> {\n return await this.list({\n where: { type },\n orderBy: 'number ASC',\n });\n }\n\n /**\n * Find all active accounts\n *\n * @returns Array of active accounts\n */\n async findActive(): Promise<Account[]> {\n return await this.list({\n where: { active: true },\n orderBy: 'number ASC',\n });\n }\n\n /**\n * Find top-level accounts (no parent)\n *\n * @returns Array of top-level accounts\n */\n async findTopLevel(): Promise<Account[]> {\n return await this.list({\n where: { parentId: null },\n orderBy: 'number ASC',\n });\n }\n\n /**\n * Find direct children of an account\n *\n * @param parentId - Parent account ID\n * @returns Array of child accounts\n */\n async findChildren(parentId: string): Promise<Account[]> {\n return await this.list({\n where: { parentId },\n orderBy: 'number ASC',\n });\n }\n\n /**\n * Get the complete account tree\n *\n * @returns AccountTree structure\n */\n async getTree(): Promise<AccountTree> {\n const allAccounts = await this.list({\n orderBy: 'number ASC',\n });\n\n const accountMap = new Map<string, Account>();\n const childrenMap = new Map<string, Account[]>();\n\n // Build lookup maps\n for (const account of allAccounts) {\n if (account.id) {\n accountMap.set(account.id, account);\n }\n if (!childrenMap.has(account.parentId || '')) {\n childrenMap.set(account.parentId || '', []);\n }\n childrenMap.get(account.parentId || '')?.push(account);\n }\n\n // Build tree nodes recursively\n const buildNode = (account: Account): AccountTreeNode => {\n const children = (account.id ? childrenMap.get(account.id) : []) || [];\n return {\n account,\n children: children.map(buildNode),\n };\n };\n\n // Get root nodes (no parent)\n const roots = childrenMap.get('') || [];\n\n return {\n roots: roots.map(buildNode),\n };\n }\n\n /**\n * Get or create an account by number\n *\n * @param number - Account number\n * @param defaults - Default values if creating\n * @returns Account\n */\n async getOrCreateByNumber(\n number: string,\n defaults: Partial<{\n name: string;\n description: string;\n type: AccountType;\n parentId: string | null;\n }> = {},\n ): Promise<Account> {\n const existing = await this.findByNumber(number);\n if (existing) {\n return existing;\n }\n\n const account = await this.create({\n number,\n name: defaults.name || number,\n description: defaults.description || '',\n type: defaults.type || 'asset',\n parentId: defaults.parentId || null,\n });\n await account.save();\n return account;\n }\n\n /**\n * Find accounts grouped by type\n *\n * @returns Record of type to accounts array\n */\n async groupByType(): Promise<Record<AccountType, Account[]>> {\n const accounts = await this.findActive();\n const grouped: Record<AccountType, Account[]> = {\n asset: [],\n liability: [],\n equity: [],\n revenue: [],\n expense: [],\n };\n\n for (const account of accounts) {\n grouped[account.type].push(account);\n }\n\n return grouped;\n }\n\n /**\n * Get all descendants of an account recursively\n *\n * @param accountId - Account ID\n * @returns Array of all descendant accounts\n */\n async getDescendants(accountId: string): Promise<Account[]> {\n const descendants: Account[] = [];\n const queue: string[] = [accountId];\n\n while (queue.length > 0) {\n const currentId = queue.shift();\n if (!currentId) continue;\n\n const children = await this.findChildren(currentId);\n\n for (const child of children) {\n descendants.push(child);\n if (child.id) {\n queue.push(child.id);\n }\n }\n }\n\n return descendants;\n }\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Tenant Helper Methods\n // ─────────────────────────────────────────────────────────────────────────────\n\n /**\n * Find all accounts belonging to a specific tenant\n *\n * @param tenantId - Tenant ID\n * @returns Array of tenant's accounts\n */\n async findByTenant(tenantId: string): Promise<Account[]> {\n return this.list({ where: { tenantId } });\n }\n\n /**\n * Find all global accounts (no tenant association).\n *\n * Routes through the shared tenant-global helper so it does not throw under\n * an active tenant context (an explicit `tenant_id IS NULL` filter would be\n * flagged as an isolation violation). (#1600)\n *\n * @returns Array of global accounts\n */\n async findGlobal(): Promise<Account[]> {\n return queryGlobal<Account>(this);\n }\n\n /**\n * Find accounts for a tenant plus all global accounts.\n *\n * Fails closed if an active tenant context requests a different tenant's\n * rows; the admin/system path keeps the cross-tenant capability. (#1600)\n *\n * @param tenantId - Tenant ID\n * @returns Array of tenant's accounts and global accounts\n */\n async findWithGlobals(tenantId: string): Promise<Account[]> {\n return queryWithGlobals<Account>(this, tenantId, 'Account.findWithGlobals');\n }\n}\n","/**\n * JournalEntry model - Individual ledger line\n *\n * The atomic unit of double-entry accounting - a single debit or credit.\n * Each entry belongs to a Journal and references an Account.\n */\n\nimport { field, foreignKey, SmrtObject, smrt } from '@happyvertical/smrt-core';\nimport {\n getTenantId,\n isSuperAdminBypass,\n isTenancyEnabled,\n TenantScoped,\n tenantId,\n withTenantGlobalRead,\n} from '@happyvertical/smrt-tenancy';\nimport type { JournalEntryOptions } from '../types';\nimport { Account } from './Account';\n\n@TenantScoped({ mode: 'optional' })\n@smrt({\n api: { include: ['list', 'get'] }, // Created via Journal, not directly\n mcp: { include: ['list', 'get'] },\n cli: { skipApiCheck: true },\n})\nexport class JournalEntry extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-ledgers\";\n /**\n * Tenant ID for multi-tenancy support (nullable for global entries)\n */\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n /**\n * Parent journal ID (required)\n */\n @field({ description: 'The journal this entry belongs to.' })\n @foreignKey('Journal')\n journalId: string = '';\n\n /**\n * Account ID (required)\n */\n // Constructor reference, not the simple name `Account` (also declared by\n // smrt-messages, #3098).\n @field({ description: 'The account this entry changes.' })\n @foreignKey(Account)\n accountId: string = '';\n\n /** Opaque external party dimension, never a product-specific model. */\n @field({ description: 'Generic counterparty type.', nullable: true })\n counterpartyKind: string | null = null;\n\n @field({ description: 'Generic counterparty identifier.', nullable: true })\n counterpartyId: string | null = null;\n\n /** Due date for an AR/AP open item. */\n @field({ description: 'When this open receivable or payable is due.' })\n dueDate: Date | null = null;\n\n /** Source reference of the open item reduced by this settlement line. */\n settlesSourceRef: string | null = null;\n\n /**\n * Debit amount (left side)\n */\n @field({ description: 'The amount debited. Zero on a credit entry.' })\n debit: number = 0.0;\n\n /**\n * Credit amount (right side)\n */\n @field({ description: 'The amount credited. Zero on a debit entry.' })\n credit: number = 0.0;\n\n /**\n * Currency code (e.g., \"USD\", \"CAD\", \"EUR\")\n */\n @field({ description: 'The currency of the amounts.' })\n currency: string = 'USD';\n\n /**\n * Exchange rate to base currency\n */\n exchangeRate: number = 1.0;\n\n /**\n * Line memo/description\n */\n @field({ description: 'A note on this entry.' })\n memo: string = '';\n\n /**\n * Extensible metadata\n */\n metadata: Record<string, unknown> = {};\n\n constructor(options: JournalEntryOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.journalId !== undefined) this.journalId = options.journalId;\n if (options.accountId !== undefined) this.accountId = options.accountId;\n if (options.counterpartyKind !== undefined)\n this.counterpartyKind = options.counterpartyKind;\n if (options.counterpartyId !== undefined)\n this.counterpartyId = options.counterpartyId;\n if (options.dueDate !== undefined) this.dueDate = options.dueDate;\n if (options.settlesSourceRef !== undefined)\n this.settlesSourceRef = options.settlesSourceRef;\n if (options.debit !== undefined) this.debit = options.debit;\n if (options.credit !== undefined) this.credit = options.credit;\n if (options.currency !== undefined) this.currency = options.currency;\n if (options.exchangeRate !== undefined)\n this.exchangeRate = options.exchangeRate;\n if (options.memo !== undefined) this.memo = options.memo;\n if (options.metadata !== undefined) this.metadata = options.metadata;\n }\n\n override async save(\n options: Parameters<SmrtObject['save']>[0] = {},\n ): Promise<this> {\n return this.withTransaction(async () => {\n const journal = await this.getJournal();\n if (!journal)\n throw new Error('Journal entry requires an accessible parent journal');\n if (journal.ledgerId) {\n if (!journal.isDraft() || !journal.updated_at)\n throw new Error('Ledger entries are immutable after posting');\n await journal.claimRevision(journal.updated_at);\n }\n return super.save(options);\n });\n }\n\n /**\n * Validate entry before save\n */\n protected async validateBeforeSave(): Promise<void> {\n await super.validateBeforeSave();\n // A fresh accounting identity must never adopt another row by natural key.\n // Core enforces this with INSERT uniqueness, including concurrent callers.\n this.requireInsertOnSave({ preserveDerivedSlug: true });\n const journal = await this.getJournal();\n // Validation precedes tenancy's beforeSave auto-population. Privileged\n // bypasses do not auto-populate, so those callers must supply the owner.\n const owner =\n this.tenantId ??\n (isTenancyEnabled() && !isSuperAdminBypass()\n ? (getTenantId() ?? null)\n : null);\n if (!journal || journal.tenantId !== owner)\n throw new Error(\n 'Journal entry and parent must belong to the same tenant',\n );\n const account = await this.getAccount();\n if (\n !account ||\n account.ledgerId !== journal.ledgerId ||\n (journal.ledgerId && account.tenantId !== journal.tenantId)\n )\n throw new Error(\n 'Journal entry account must belong to its journal ledger',\n );\n if (journal.ledgerId && !journal.isDraft())\n throw new Error('Ledger entries are immutable after posting');\n if (this.id) {\n const stored = await this.db.get(this.tableName, { id: this.id });\n if (stored && stored.journal_id !== this.journalId)\n throw new Error('Journal entry cannot be moved to another journal');\n if (stored && stored.account_id !== this.accountId) {\n const oldAccount = await this.loadAccount(String(stored.account_id));\n if (!oldAccount || oldAccount.ledgerId !== journal.ledgerId)\n throw new Error(\n 'Stored entry account must belong to its journal ledger',\n );\n }\n }\n if (!Number.isFinite(this.debit) || !Number.isFinite(this.credit))\n throw new Error('Entry amounts must be finite');\n // Validate amounts are non-negative\n if (this.debit < 0) {\n throw new Error('Debit amount cannot be negative');\n }\n if (this.credit < 0) {\n throw new Error('Credit amount cannot be negative');\n }\n\n // Validate that entry has debit OR credit, not both\n if (this.debit > 0 && this.credit > 0) {\n throw new Error('Entry cannot have both debit and credit amounts');\n }\n\n // Validate that entry has at least one amount\n if (this.debit === 0 && this.credit === 0) {\n throw new Error('Entry must have either a debit or credit amount');\n }\n\n // Validate exchange rate is positive\n if (this.exchangeRate <= 0) {\n throw new Error('Exchange rate must be positive');\n }\n if (!!this.counterpartyKind !== !!this.counterpartyId)\n throw new Error('Counterparty kind and ID must be provided together');\n if (this.dueDate && (!this.counterpartyKind || !this.counterpartyId))\n throw new Error('Due date requires a counterparty');\n }\n\n async delete(\n options: Parameters<SmrtObject['delete']>[0] = {},\n ): Promise<void> {\n await this.withTransaction(async () => {\n const stored = this.id\n ? await this.db.get(this.tableName, { id: this.id })\n : null;\n if (stored) {\n const { JournalCollection } = await import('../collections/Journals');\n const journal = await (\n await JournalCollection.create({ db: this.db })\n ).get({ id: String(stored.journal_id) });\n if (!journal || journal.tenantId !== stored.tenant_id)\n throw new Error(\n 'Journal entry requires its accessible same-tenant parent',\n );\n if (journal.ledgerId) {\n if (!journal.isDraft() || !journal.updated_at)\n throw new Error('Ledger entries are immutable after posting');\n await journal.claimRevision(journal.updated_at);\n }\n }\n await super.delete(options);\n });\n }\n\n /**\n * Check if this is a debit entry\n */\n isDebit(): boolean {\n return this.debit > 0;\n }\n\n /**\n * Check if this is a credit entry\n */\n isCredit(): boolean {\n return this.credit > 0;\n }\n\n /**\n * Get the entry amount (positive value regardless of debit/credit)\n */\n getAmount(): number {\n return this.debit > 0 ? this.debit : this.credit;\n }\n\n /**\n * Get the amount in base currency\n */\n getBaseAmount(): number {\n return this.getAmount() * this.exchangeRate;\n }\n\n /**\n * Get the parent journal\n */\n async getJournal(): Promise<import('./Journal').Journal | null> {\n if (!this.journalId) return null;\n const { JournalCollection } = await import('../collections/Journals');\n const collection = await JournalCollection.create(this.options);\n return await collection.get({ id: this.journalId }, { cache: false });\n }\n\n /**\n * Get the account\n */\n async getAccount(): Promise<import('./Account').Account | null> {\n if (!this.accountId) return null;\n return this.loadAccount(this.accountId);\n }\n\n private async loadAccount(\n accountId: string,\n ): Promise<import('./Account').Account | null> {\n const { AccountCollection } = await import('../collections/Accounts');\n const collection = await AccountCollection.create(this.options);\n const account = await collection.get({ id: accountId }, { cache: false });\n if (account) return account;\n const tenant = getTenantId();\n if (!tenant) return null;\n // Legacy charts expose shared, unassigned accounts. The public read scope\n // retains actor authorization and never widens to another tenant's rows.\n return withTenantGlobalRead(tenant, async () => {\n const globals = await collection.list({\n where: { id: accountId, tenantId: null, ledgerId: null },\n limit: 1,\n });\n return globals[0] ?? null;\n });\n }\n\n /**\n * Get a formatted description of this entry\n */\n async getDescription(): Promise<string> {\n const account = await this.getAccount();\n const accountName = account?.name || 'Unknown Account';\n const type = this.isDebit() ? 'DR' : 'CR';\n const amount = this.getAmount().toFixed(2);\n\n return `${type} ${accountName}: $${amount}${this.memo ? ` - ${this.memo}` : ''}`;\n }\n}\n","/**\n * JournalEntryCollection - Collection manager for JournalEntry objects\n *\n * Provides querying and balance calculations for ledger entries.\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport {\n getTenantId,\n queryGlobal,\n queryWithGlobals,\n} from '@happyvertical/smrt-tenancy';\nimport { JournalEntry } from '../models/JournalEntry';\nimport { BALANCE_EPSILON, type TrialBalanceRow } from '../types';\n\n/** One posted ledger movement in its raw stored unit (ledgers are unit-agnostic). */\nexport interface PostedJournalMovement {\n /** Requested owner identity; consumers must retain it at their reporting boundary. */\n tenantId: string;\n entryId: string;\n journalId: string;\n accountId: string;\n journalDate: Date;\n journalNumber: string;\n sourceModule: string;\n sourceRef: string | null;\n currency: string;\n debit: number;\n credit: number;\n /** Credit minus debit, suitable for liability-account reconciliation. */\n creditMinusDebit: number;\n}\n\nexport interface PostedJournalMovementOptions {\n tenantId: string;\n accountIds: readonly string[];\n from: Date;\n to: Date;\n currency: string;\n /** Select credit-normal AP balances; default is debit-normal AR. */\n normalBalance?: 'debit' | 'credit';\n}\n\nexport interface CounterpartyBalance {\n counterpartyKind: string;\n counterpartyId: string;\n currency: string;\n /** Debit minus credit for asset AR accounts; callers choose the account set. */\n balance: number;\n}\n\nexport interface CounterpartyAgingRow extends CounterpartyBalance {\n sourceRef: string;\n dueDate: Date;\n current: number;\n days1To30: number;\n days31To60: number;\n days61To90: number;\n daysOver90: number;\n}\n\nconst MAX_MOVEMENT_ACCOUNTS = 1_000;\n\nfunction storedUnit(value: unknown, label: string): number {\n const number = typeof value === 'number' ? value : Number(value);\n if (!Number.isFinite(number) || Math.abs(number) > Number.MAX_SAFE_INTEGER)\n throw new RangeError(\n `Posted journal ${label} is outside the supported numeric range.`,\n );\n return number;\n}\n\nexport class JournalEntryCollection extends SmrtCollection<JournalEntry> {\n static readonly _itemClass = JournalEntry;\n\n /**\n * Find entries by journal\n *\n * @param journalId - Journal ID\n * @returns Array of entries\n */\n async findByJournal(journalId: string): Promise<JournalEntry[]> {\n return await this.list({\n where: { journalId },\n });\n }\n\n /**\n * Find entries by account\n *\n * @param accountId - Account ID\n * @returns Array of entries\n */\n async findByAccount(accountId: string): Promise<JournalEntry[]> {\n return await this.list({\n where: { accountId },\n });\n }\n\n /** Posted AR/AP net balances by opaque counterparty for selected accounts. */\n async getCounterpartyBalances(\n options: PostedJournalMovementOptions,\n ): Promise<CounterpartyBalance[]> {\n const movements = await this.listPostedMovements(options);\n const result = new Map<string, CounterpartyBalance>();\n for (const movement of movements) {\n const entry = await this.get({ id: movement.entryId });\n if (!entry?.counterpartyKind || !entry.counterpartyId) continue;\n const key = JSON.stringify([\n entry.counterpartyKind,\n entry.counterpartyId,\n movement.currency,\n ]);\n const row = result.get(key) ?? {\n counterpartyKind: entry.counterpartyKind,\n counterpartyId: entry.counterpartyId,\n currency: movement.currency,\n balance: 0,\n };\n row.balance = storedUnit(\n row.balance +\n (movement.debit - movement.credit) *\n (options.normalBalance === 'credit' ? -1 : 1),\n 'counterparty balance',\n );\n result.set(key, row);\n }\n return [...result.values()].filter((row) => row.balance !== 0);\n }\n\n /**\n * Open-item aging. An invoice/allocation line needs a dueDate and sourceRef;\n * a settlement line names that source in settlesSourceRef. This avoids\n * pretending that net counterparty movements are aging.\n */\n async getCounterpartyAging(\n options: PostedJournalMovementOptions,\n asOf: Date,\n ): Promise<CounterpartyAgingRow[]> {\n const movements = await this.listPostedMovements({ ...options, to: asOf });\n const rows = new Map<string, CounterpartyAgingRow>();\n const balances = new Map<string, number>();\n for (const movement of movements) {\n const entry = await this.get({ id: movement.entryId });\n const source = entry?.settlesSourceRef ?? movement.sourceRef;\n if (!entry?.counterpartyKind || !entry.counterpartyId || !source)\n continue;\n const key = JSON.stringify([\n entry.counterpartyKind,\n entry.counterpartyId,\n movement.currency,\n source,\n ]);\n balances.set(\n key,\n storedUnit(\n (balances.get(key) ?? 0) +\n (movement.debit - movement.credit) *\n (options.normalBalance === 'credit' ? -1 : 1),\n 'open item balance',\n ),\n );\n if (!entry.settlesSourceRef && entry.dueDate) {\n const prior = rows.get(key);\n if (prior && prior.dueDate.getTime() !== entry.dueDate.getTime())\n throw new Error('Open item source has conflicting due dates');\n rows.set(key, {\n counterpartyKind: entry.counterpartyKind,\n counterpartyId: entry.counterpartyId,\n currency: movement.currency,\n sourceRef: source,\n dueDate: entry.dueDate,\n balance: 0,\n current: 0,\n days1To30: 0,\n days31To60: 0,\n days61To90: 0,\n daysOver90: 0,\n });\n }\n }\n for (const [key, row] of rows) row.balance = balances.get(key) ?? 0;\n for (const row of rows.values()) {\n if (row.balance <= 0) continue;\n const days = Math.floor(\n (asOf.getTime() - row.dueDate.getTime()) / 86_400_000,\n );\n if (days <= 0) row.current = row.balance;\n else if (days <= 30) row.days1To30 = row.balance;\n else if (days <= 60) row.days31To60 = row.balance;\n else if (days <= 90) row.days61To90 = row.balance;\n else row.daysOver90 = row.balance;\n }\n return [...rows.values()].filter((row) => row.balance > 0);\n }\n\n /**\n * Get account balance\n *\n * For debit-normal accounts (Asset, Expense): balance = debits - credits\n * For credit-normal accounts (Liability, Equity, Revenue): balance = credits - debits\n *\n * @param accountId - Account ID\n * @param asOfDate - Optional date to calculate balance as of\n * @returns Account balance\n */\n async getAccountBalance(accountId: string, asOfDate?: Date): Promise<number> {\n // Get entries for this account from posted journals only\n const { JournalCollection } = await import('./Journals');\n const journalCollection = await JournalCollection.create(this.options);\n const { AccountCollection } = await import('./Accounts');\n const accountCollection = await AccountCollection.create(this.options);\n\n // Get the account to determine if it's debit or credit normal\n const account = await accountCollection.get({ id: accountId });\n if (!account) {\n throw new Error(`Account not found: ${accountId}`);\n }\n\n // Get all entries for this account\n const allEntries = await this.findByAccount(accountId);\n\n let totalDebits = 0;\n let totalCredits = 0;\n\n for (const entry of allEntries) {\n // Get the journal to check status and date\n const journal = await journalCollection.get({ id: entry.journalId });\n if (!journal) continue;\n\n // Only include posted journals\n if (!journal.isPosted()) continue;\n\n // Check date if specified\n if (asOfDate && journal.date > asOfDate) continue;\n\n totalDebits += entry.debit;\n totalCredits += entry.credit;\n }\n\n // Calculate balance based on account type\n if (account.isDebitNormal()) {\n // Asset, Expense: increases with debits\n return totalDebits - totalCredits;\n } else {\n // Liability, Equity, Revenue: increases with credits\n return totalCredits - totalDebits;\n }\n }\n\n /**\n * Get trial balance\n *\n * @param asOfDate - Optional date for trial balance\n * @returns Array of trial balance rows\n */\n async getTrialBalance(asOfDate?: Date): Promise<TrialBalanceRow[]> {\n const { AccountCollection } = await import('./Accounts');\n const accountCollection = await AccountCollection.create(this.options);\n\n const accounts = await accountCollection.findActive();\n const rows: TrialBalanceRow[] = [];\n\n for (const account of accounts) {\n if (!account.id) continue;\n\n const balance = await this.getAccountBalance(account.id, asOfDate);\n\n // Skip zero-balance accounts\n if (Math.abs(balance) < BALANCE_EPSILON) continue;\n\n rows.push({\n accountId: account.id,\n accountNumber: account.number,\n accountName: account.name,\n accountType: account.type,\n debitBalance: account.isDebitNormal() && balance > 0 ? balance : 0,\n creditBalance: account.isCreditNormal() && balance > 0 ? balance : 0,\n });\n }\n\n // Sort by account number\n rows.sort((a, b) => a.accountNumber.localeCompare(b.accountNumber));\n\n return rows;\n }\n\n /**\n * Get total debits and credits for a date range\n *\n * @param start - Start date\n * @param end - End date\n * @returns Object with totalDebits and totalCredits\n */\n async getTotalsForDateRange(\n start: Date,\n end: Date,\n ): Promise<{ totalDebits: number; totalCredits: number }> {\n const { JournalCollection } = await import('./Journals');\n const journalCollection = await JournalCollection.create(this.options);\n\n const journals = await journalCollection.findByDateRange(start, end);\n\n let totalDebits = 0;\n let totalCredits = 0;\n\n for (const journal of journals) {\n if (!journal.isPosted()) continue;\n\n const entries = await this.findByJournal(journal.id!);\n for (const entry of entries) {\n totalDebits += entry.debit;\n totalCredits += entry.credit;\n }\n }\n\n return { totalDebits, totalCredits };\n }\n\n /**\n * Get entries for multiple accounts\n *\n * @param accountIds - Array of account IDs\n * @returns Array of entries\n */\n async findByAccounts(accountIds: string[]): Promise<JournalEntry[]> {\n if (accountIds.length === 0) {\n return [];\n }\n\n // Use single query with IN clause to avoid N+1 problem\n return await this.list({\n where: { accountId: accountIds },\n });\n }\n\n /**\n * Read tenant-owned movements from posted journals only. Amounts deliberately\n * remain raw ledger units; commerce validates its minor-unit convention at\n * the reporting boundary.\n */\n async listPostedMovements(\n options: PostedJournalMovementOptions,\n ): Promise<PostedJournalMovement[]> {\n if (getTenantId() && getTenantId() !== options.tenantId)\n throw new Error('Posted movements tenant differs from active context');\n const accountIds = [...new Set(options.accountIds)];\n if (\n !options.tenantId?.trim() ||\n !options.currency?.trim() ||\n !(options.from instanceof Date) ||\n !(options.to instanceof Date) ||\n !Number.isFinite(options.from.getTime()) ||\n !Number.isFinite(options.to.getTime()) ||\n options.from > options.to\n )\n throw new Error(\n 'Posted movements require tenant, currency and ordered dates.',\n );\n if (accountIds.length === 0) return [];\n if (accountIds.length > MAX_MOVEMENT_ACCOUNTS)\n throw new RangeError(\n `Posted movements allow at most ${MAX_MOVEMENT_ACCOUNTS} accounts per query.`,\n );\n if (\n accountIds.some((id) => typeof id !== 'string' || !id || id.trim() !== id)\n )\n throw new Error('Posted movement account IDs must be nonempty.');\n const placeholders = accountIds.map(() => '?').join(', ');\n const result = await this.db.query(\n `SELECT e.id AS entry_id, e.journal_id, e.account_id, e.currency,\n e.debit, e.credit, j.date AS journal_date, j.number AS journal_number,\n j.source_module, j.source_ref\n FROM journal_entries e\n JOIN journals j ON j.id = e.journal_id AND j.tenant_id = e.tenant_id\n WHERE e.tenant_id = ? AND e.account_id IN (${placeholders})\n AND e.currency = ? AND j.status = 'posted'\n AND j.date >= ? AND j.date <= ?\n ORDER BY j.date ASC, j.id ASC, e.id ASC`,\n options.tenantId,\n ...accountIds,\n options.currency,\n options.from.toISOString(),\n options.to.toISOString(),\n );\n return result.rows.map((row) => {\n const debit = storedUnit(row.debit, 'debit');\n const credit = storedUnit(row.credit, 'credit');\n const movement = credit - debit;\n if (\n !Number.isFinite(movement) ||\n Math.abs(movement) > Number.MAX_SAFE_INTEGER\n )\n throw new RangeError(\n 'Posted journal movement is outside the supported numeric range.',\n );\n return {\n tenantId: options.tenantId,\n entryId: String(row.entry_id),\n journalId: String(row.journal_id),\n accountId: String(row.account_id),\n journalDate: new Date(String(row.journal_date)),\n journalNumber: String(row.journal_number),\n sourceModule: String(row.source_module),\n sourceRef: row.source_ref == null ? null : String(row.source_ref),\n currency: String(row.currency),\n debit,\n credit,\n creditMinusDebit: movement,\n };\n });\n }\n\n /**\n * Get the running balance for an account (list of entries with running total)\n *\n * @param accountId - Account ID\n * @returns Array of entries with running balance\n */\n async getAccountLedger(\n accountId: string,\n ): Promise<Array<{ entry: JournalEntry; runningBalance: number }>> {\n const { JournalCollection } = await import('./Journals');\n const { AccountCollection } = await import('./Accounts');\n const journalCollection = await JournalCollection.create(this.options);\n const accountCollection = await AccountCollection.create(this.options);\n\n const account = await accountCollection.get({ id: accountId });\n if (!account) {\n throw new Error(`Account not found: ${accountId}`);\n }\n\n const entries = await this.findByAccount(accountId);\n const ledger: Array<{ entry: JournalEntry; runningBalance: number }> = [];\n let runningBalance = 0;\n\n // Sort entries by journal date\n const entriesWithJournals = await Promise.all(\n entries.map(async (entry) => ({\n entry,\n journal: await journalCollection.get({ id: entry.journalId }),\n })),\n );\n\n entriesWithJournals.sort((a, b) => {\n if (!a.journal || !b.journal) return 0;\n return a.journal.date.getTime() - b.journal.date.getTime();\n });\n\n for (const { entry, journal } of entriesWithJournals) {\n if (!journal?.isPosted()) continue;\n\n if (account.isDebitNormal()) {\n runningBalance += entry.debit - entry.credit;\n } else {\n runningBalance += entry.credit - entry.debit;\n }\n\n ledger.push({ entry, runningBalance });\n }\n\n return ledger;\n }\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Tenant Helper Methods\n // ─────────────────────────────────────────────────────────────────────────────\n\n /**\n * Find all journal entries belonging to a specific tenant\n *\n * @param tenantId - Tenant ID\n * @returns Array of tenant's journal entries\n */\n async findByTenant(tenantId: string): Promise<JournalEntry[]> {\n return this.list({ where: { tenantId } });\n }\n\n /**\n * Find all global journal entries (no tenant association).\n *\n * Routes through the shared tenant-global helper so it does not throw under\n * an active tenant context. (#1600)\n *\n * @returns Array of global journal entries\n */\n async findGlobal(): Promise<JournalEntry[]> {\n return queryGlobal<JournalEntry>(this);\n }\n\n /**\n * Find journal entries for a tenant plus all global entries.\n *\n * Fails closed if an active tenant context requests a different tenant's\n * rows; the admin/system path keeps the cross-tenant capability. (#1600)\n *\n * @param tenantId - Tenant ID\n * @returns Array of tenant's entries and global entries\n */\n async findWithGlobals(tenantId: string): Promise<JournalEntry[]> {\n return queryWithGlobals<JournalEntry>(\n this,\n tenantId,\n 'JournalEntry.findWithGlobals',\n );\n }\n}\n","/**\n * Journal model - Financial event container\n *\n * Represents a single, discrete financial event.\n * Contains one or more JournalEntry records that must balance (debits = credits).\n */\n\nimport { field, foreignKey, SmrtObject, smrt } from '@happyvertical/smrt-core';\nimport { resolvePrompt } from '@happyvertical/smrt-prompts';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport {\n promptMessageOptions,\n smrtLedgersJournalSummarizePrompt,\n} from '../prompts';\nimport {\n BALANCE_EPSILON,\n type JournalEntryData,\n type JournalOptions,\n type JournalStatus,\n} from '../types';\nimport { Ledger } from './Ledger';\n\n@TenantScoped({ mode: 'optional' })\n@smrt({\n api: { include: ['list', 'get', 'create'] }, // No update/delete - immutable after posting\n mcp: { include: ['list', 'get', 'create'] },\n cli: { skipApiCheck: true },\n indexes: [\n {\n name: 'journals_ledger_idempotency_key',\n columns: ['tenantId', 'ledgerId', 'idempotencyKey'],\n unique: true,\n },\n ],\n})\nexport class Journal extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-ledgers\";\n /**\n * Tenant ID for multi-tenancy support (nullable for global journals)\n */\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n /**\n * Journal number (auto-generated sequence, e.g., \"JNL-0001\")\n */\n @field({ description: \"The journal's reference number.\" })\n number: string = '';\n\n /**\n * Transaction date\n */\n @field({ description: 'The date of the transaction.' })\n date: Date = new Date();\n\n /**\n * Description of the financial event\n */\n @field({ description: 'What the transaction was.' })\n description: string = '';\n\n /**\n * Source module that created this journal (e.g., \"smrt-commerce\", \"manual\")\n */\n sourceModule: string = '';\n\n /**\n * External reference (e.g., order ID, invoice number)\n */\n sourceRef: string | null = null;\n\n /** Optional durable accounting scope; null preserves legacy tolerant journals. */\n @field({\n description: 'The ledger policy that governs this journal.',\n nullable: true,\n })\n @foreignKey(Ledger)\n ledgerId: string | null = null;\n\n @field({ nullable: true })\n idempotencyKey: string | null = null;\n\n requestDigest: string | null = null;\n\n /**\n * Journal status: draft, posted, voided\n */\n @field({\n description: 'draft until final, then posted, or voided.',\n })\n status: JournalStatus = 'draft';\n\n /**\n * When the journal was posted (finalized)\n */\n @field({ description: 'When it was posted.' })\n postedAt: Date | null = null;\n\n /**\n * When the journal was voided\n */\n voidedAt: Date | null = null;\n\n /**\n * Reason for voiding (if voided)\n */\n voidReason: string | null = null;\n\n /**\n * Extensible metadata\n */\n metadata: Record<string, unknown> = {};\n\n constructor(options: JournalOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.number !== undefined) this.number = options.number;\n if (options.date !== undefined) this.date = options.date;\n if (options.description !== undefined)\n this.description = options.description;\n if (options.sourceModule !== undefined)\n this.sourceModule = options.sourceModule;\n if (options.sourceRef !== undefined) this.sourceRef = options.sourceRef;\n if (options.ledgerId !== undefined) this.ledgerId = options.ledgerId;\n if (options.idempotencyKey !== undefined)\n this.idempotencyKey = options.idempotencyKey;\n if (options.requestDigest !== undefined)\n this.requestDigest = options.requestDigest;\n if (options.status !== undefined) this.status = options.status;\n if (options.postedAt !== undefined) this.postedAt = options.postedAt;\n if (options.voidedAt !== undefined) this.voidedAt = options.voidedAt;\n if (options.voidReason !== undefined) this.voidReason = options.voidReason;\n if (options.metadata !== undefined) this.metadata = options.metadata;\n }\n\n /**\n * Check if journal is in draft status\n */\n isDraft(): boolean {\n return this.status === 'draft';\n }\n\n /**\n * Check if journal has been posted\n */\n isPosted(): boolean {\n return this.status === 'posted';\n }\n\n /**\n * Check if journal has been voided\n */\n isVoided(): boolean {\n return this.status === 'voided';\n }\n\n /**\n * Check if journal can be modified\n */\n isEditable(): boolean {\n return this.status === 'draft';\n }\n\n /**\n * Get all entries for this journal\n */\n async getEntries(): Promise<import('./JournalEntry').JournalEntry[]> {\n if (!this.id) return [];\n const { JournalEntryCollection } = await import(\n '../collections/JournalEntries'\n );\n const collection = await JournalEntryCollection.create(this.options);\n return await collection.findByJournal(this.id);\n }\n\n /**\n * Calculate total debits\n */\n async getTotalDebits(): Promise<number> {\n const entries = await this.getEntries();\n return entries.reduce((sum, entry) => sum + entry.debit, 0);\n }\n\n /**\n * Calculate total credits\n */\n async getTotalCredits(): Promise<number> {\n const entries = await this.getEntries();\n return entries.reduce((sum, entry) => sum + entry.credit, 0);\n }\n\n /**\n * Check if journal entries are balanced (debits = credits)\n */\n async isBalanced(): Promise<boolean> {\n const debits = await this.getTotalDebits();\n const credits = await this.getTotalCredits();\n const ledger = await this.getLedger();\n if (!ledger || ledger.balanceMode === 'tolerant')\n return Math.abs(debits - credits) < BALANCE_EPSILON;\n const entries = await this.getEntries();\n return (\n Number.isSafeInteger(debits) &&\n Number.isSafeInteger(credits) &&\n entries.every(\n (entry) =>\n Number.isSafeInteger(entry.debit) &&\n Number.isSafeInteger(entry.credit),\n ) &&\n debits === credits\n );\n }\n\n async getLedger(): Promise<import('./Ledger').Ledger | null> {\n if (!this.ledgerId) return null;\n const { LedgerCollection } = await import('../collections/Ledgers');\n return (await LedgerCollection.create(this.options)).get({\n id: this.ledgerId,\n });\n }\n\n /**\n * Add an entry to this journal (only if draft)\n */\n async addEntry(data: JournalEntryData): Promise<void> {\n if (!this.id) {\n throw new Error('Journal must be saved before adding entries');\n }\n if (!this.isEditable()) {\n throw new Error('Cannot add entries to a posted or voided journal');\n }\n\n const { JournalEntryCollection } = await import(\n '../collections/JournalEntries'\n );\n const collection = await JournalEntryCollection.create(this.options);\n const entry = await collection.create({\n journalId: this.id,\n tenantId: this.tenantId,\n accountId: data.accountId,\n counterpartyKind: data.counterpartyKind ?? null,\n counterpartyId: data.counterpartyId ?? null,\n dueDate: data.dueDate ?? null,\n settlesSourceRef: data.settlesSourceRef ?? null,\n debit: data.debit || 0,\n credit: data.credit || 0,\n currency: data.currency || 'USD',\n exchangeRate: data.exchangeRate || 1.0,\n memo: data.memo || '',\n });\n await entry.save();\n if (this.ledgerId) {\n const parent = await entry.getJournal();\n this.updated_at = parent?.updated_at ?? this.updated_at;\n }\n }\n\n /**\n * Post the journal (finalize and make immutable)\n */\n async post(): Promise<void> {\n if (!this.isDraft()) {\n throw new Error('Only draft journals can be posted');\n }\n\n await this.validatePosting();\n\n this.status = 'posted';\n this.postedAt = new Date();\n await this.save();\n }\n\n /**\n * Void the journal (mark as cancelled with reason)\n */\n async void(reason: string): Promise<void> {\n if (this.isVoided()) {\n throw new Error('Journal is already voided');\n }\n\n this.status = 'voided';\n this.voidedAt = new Date();\n this.voidReason = reason;\n await this.save();\n }\n\n private async validatePosting(): Promise<void> {\n const balanced = await this.isBalanced();\n if (!balanced) {\n const debits = await this.getTotalDebits();\n const credits = await this.getTotalCredits();\n throw new Error(\n `Journal is not balanced. Debits: ${debits}, Credits: ${credits}`,\n );\n }\n\n const entries = await this.getEntries();\n if (entries.length === 0) {\n throw new Error('Journal must have at least one entry');\n }\n const ledger = await this.getLedger();\n if (this.ledgerId && !ledger)\n throw new Error(`Ledger not found: ${this.ledgerId}`);\n if (ledger) {\n if (ledger.tenantId !== this.tenantId)\n throw new Error('Journal and ledger must belong to the same tenant');\n if (entries.some((entry) => entry.currency !== ledger.currency))\n throw new Error(\n `Journal entries must use ledger currency ${ledger.currency}`,\n );\n }\n const { AccountCollection } = await import('../collections/Accounts');\n const accounts = await AccountCollection.create(this.options);\n for (const entry of entries) {\n const account = await accounts.get({ id: entry.accountId });\n if (\n (this.ledgerId || account?.ledgerId) &&\n (!account ||\n !account.active ||\n account.tenantId !== this.tenantId ||\n entry.tenantId !== this.tenantId ||\n account.ledgerId !== this.ledgerId)\n )\n throw new Error(\n 'Journal entries must use active accounts owned by the journal ledger',\n );\n }\n }\n\n override async save(\n options: Parameters<SmrtObject['save']>[0] = {},\n ): Promise<this> {\n return this.withTransaction(async () => {\n if (this.isPersisted && this.updated_at) {\n await this.claimRevision(options.expectedUpdatedAt ?? this.updated_at);\n if (options.expectedUpdatedAt !== undefined)\n options = { ...options, expectedUpdatedAt: this.updated_at };\n }\n return super.save(options);\n });\n }\n\n protected async validateBeforeSave(): Promise<void> {\n await super.validateBeforeSave();\n // A fresh accounting identity must never adopt another row by natural key.\n // Core enforces this with INSERT uniqueness, including concurrent callers.\n this.requireInsertOnSave({ preserveDerivedSlug: true });\n if (this.id) {\n const stored = await this.db.get(this.tableName, { id: this.id });\n if (stored && stored.ledger_id !== this.ledgerId)\n throw new Error('Journal ledger scope is immutable after creation');\n if (stored?.ledger_id && stored.status !== 'draft')\n throw new Error(\n 'Ledger journals are immutable after posting; use a compensating journal',\n );\n }\n if (this.status === 'posted') {\n if (this.ledgerId) await this.validatePosting();\n else {\n for (const entry of await this.getEntries()) {\n if ((await entry.getAccount())?.ledgerId)\n throw new Error('Scoped accounts require their journal ledger');\n }\n }\n }\n }\n\n async delete(\n options: Parameters<SmrtObject['delete']>[0] = {},\n ): Promise<void> {\n await this.withTransaction(async () => {\n if (this.isPersisted && this.updated_at) {\n await this.claimRevision(options.expectedUpdatedAt ?? this.updated_at);\n if (options.expectedUpdatedAt !== undefined)\n options = { ...options, expectedUpdatedAt: this.updated_at };\n }\n const stored = this.id\n ? await this.db.get(this.tableName, { id: this.id })\n : null;\n if (stored?.ledger_id && stored.status !== 'draft')\n throw new Error('Ledger journals are immutable after posting');\n await super.delete(options);\n });\n }\n\n /**\n * AI-powered: Generate a summary of this journal.\n *\n * Uses the `smrtLedgers.journal.summarize` prompt registered via\n * `@happyvertical/smrt-prompts`, allowing tenant- or instance-level\n * overrides of the template, model, and parameters at runtime.\n *\n * Only non-PII journal fields (number, date, description, status, balanced\n * flag) plus aggregate totals and entry count are sent to the AI provider.\n * Internal foreign-key fields (tenantId, sourceRef, individual entry\n * account IDs) and the extensible `metadata` blob are intentionally\n * excluded.\n *\n * @returns Generated summary text\n */\n async summarize(): Promise<string> {\n const entries = await this.getEntries();\n const debits = await this.getTotalDebits();\n const balanced = await this.isBalanced();\n\n // Resolve `db` from either the canonical `db` option or its `persistence`\n // alias. SmrtClass maps `persistence → db` lazily during `initialize()`,\n // so on a freshly-constructed Journal that has not yet been initialized,\n // `this.options.db` may be undefined while `this.options.persistence` is\n // set. Falling back here ensures stored app- and tenant-level prompt\n // overrides in `_smrt_prompt_overrides` are honored on the first call —\n // before `getAiClient()` triggers full initialization further below.\n const db = this.options.db ?? this.options.persistence;\n\n const resolvedPrompt = await resolvePrompt(\n smrtLedgersJournalSummarizePrompt.key,\n {\n db,\n tenantId: this.tenantId,\n variables: {\n journalNumber: this.number || '',\n journalDate: this.date.toISOString().split('T')[0],\n journalDescription: this.description || '',\n journalStatus: this.status || '',\n // Currency prefix folded into the value rather than the template\n // — see the `smrtLedgersJournalSummarizePrompt` comment block.\n journalTotal: `$${debits.toFixed(2)}`,\n entryCount: String(entries.length),\n journalBalanced: balanced ? 'Yes' : 'No',\n },\n },\n );\n\n const ai = await this.getAiClient();\n const response = await ai.message(\n resolvedPrompt.text,\n promptMessageOptions(resolvedPrompt.ai),\n );\n\n return response.trim();\n }\n}\n","/**\n * JournalCollection - Collection manager for Journal objects\n *\n * Provides querying and operations for financial journals.\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { queryGlobal, queryWithGlobals } from '@happyvertical/smrt-tenancy';\nimport { Journal } from '../models/Journal';\nimport {\n BALANCE_EPSILON,\n type CreateJournalData,\n type JournalStatus,\n} from '../types';\n\nexport class JournalCollection extends SmrtCollection<Journal> {\n static readonly _itemClass = Journal;\n\n /**\n * Generate next journal number\n *\n * Uses timestamp and random component to avoid collisions\n * in concurrent environments without relying on shared state.\n */\n private generateJournalNumber(): string {\n const timestamp = Date.now().toString(36);\n const randomPart = Math.random().toString(36).slice(2, 6);\n return `JNL-${timestamp}-${randomPart}`;\n }\n\n /**\n * Find journal by number\n *\n * @param number - Journal number\n * @returns Journal or null\n */\n async findByNumber(number: string): Promise<Journal | null> {\n const journals = await this.list({\n where: { number },\n limit: 1,\n });\n return journals[0] || null;\n }\n\n /**\n * Find journals by date range\n *\n * @param start - Start date\n * @param end - End date\n * @returns Array of journals\n */\n async findByDateRange(start: Date, end: Date): Promise<Journal[]> {\n return await this.list({\n where: {\n 'date >=': start.toISOString(),\n 'date <=': end.toISOString(),\n },\n orderBy: 'date ASC',\n });\n }\n\n /**\n * Find journals by source module\n *\n * @param sourceModule - Source module name\n * @returns Array of journals\n */\n async findBySource(sourceModule: string): Promise<Journal[]> {\n return await this.list({\n where: { sourceModule },\n orderBy: 'date DESC',\n });\n }\n\n /**\n * Find journals by status\n *\n * @param status - Journal status\n * @returns Array of journals\n */\n async findByStatus(status: JournalStatus): Promise<Journal[]> {\n return await this.list({\n where: { status },\n orderBy: 'date DESC',\n });\n }\n\n /**\n * Find draft journals\n *\n * @returns Array of draft journals\n */\n async findDrafts(): Promise<Journal[]> {\n return await this.findByStatus('draft');\n }\n\n /**\n * Find posted journals\n *\n * @returns Array of posted journals\n */\n async findPosted(): Promise<Journal[]> {\n return await this.findByStatus('posted');\n }\n\n /**\n * Create a complete journal with entries\n *\n * @param data - Journal data with entries\n * @returns Created journal\n */\n async createWithEntries(data: CreateJournalData): Promise<Journal> {\n // Validate entries balance\n let totalDebits = 0;\n let totalCredits = 0;\n\n for (const entry of data.entries) {\n totalDebits += entry.debit || 0;\n totalCredits += entry.credit || 0;\n }\n\n if (Math.abs(totalDebits - totalCredits) >= BALANCE_EPSILON) {\n throw new Error(\n `Entries are not balanced. Debits: ${totalDebits}, Credits: ${totalCredits}`,\n );\n }\n\n if (data.entries.length === 0) {\n throw new Error('Journal must have at least one entry');\n }\n\n // Create journal\n const journalNumber = await this.generateJournalNumber();\n const journal = await this.create({\n tenantId: data.tenantId ?? null,\n number: journalNumber,\n date: data.date || new Date(),\n description: data.description,\n sourceModule: data.sourceModule || 'manual',\n sourceRef: data.sourceRef || null,\n ledgerId: data.ledgerId ?? null,\n idempotencyKey: data.idempotencyKey ?? null,\n requestDigest: data.requestDigest ?? null,\n metadata: data.metadata || {},\n });\n await journal.save();\n\n // Create entries\n for (const entryData of data.entries) {\n await journal.addEntry(entryData);\n }\n\n return journal;\n }\n\n /**\n * Post a journal by ID\n *\n * @param journalId - Journal ID\n * @returns Posted journal\n */\n async post(journalId: string): Promise<Journal> {\n const journal = await this.get({ id: journalId });\n if (!journal) {\n throw new Error(`Journal not found: ${journalId}`);\n }\n await journal.post();\n return journal;\n }\n\n /**\n * Void a journal by ID\n *\n * @param journalId - Journal ID\n * @param reason - Reason for voiding\n * @returns Voided journal\n */\n async void(journalId: string, reason: string): Promise<Journal> {\n const journal = await this.get({ id: journalId });\n if (!journal) {\n throw new Error(`Journal not found: ${journalId}`);\n }\n await journal.void(reason);\n return journal;\n }\n\n /**\n * Find journals by source reference\n *\n * @param sourceRef - External reference\n * @returns Array of journals\n */\n async findBySourceRef(sourceRef: string): Promise<Journal[]> {\n return await this.list({\n where: { sourceRef },\n orderBy: 'date DESC',\n });\n }\n\n /**\n * Get journals for a specific month\n *\n * @param year - Year\n * @param month - Month (1-12)\n * @returns Array of journals\n */\n async findByMonth(year: number, month: number): Promise<Journal[]> {\n const start = new Date(year, month - 1, 1);\n const end = new Date(year, month, 0, 23, 59, 59, 999);\n return await this.findByDateRange(start, end);\n }\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Tenant Helper Methods\n // ─────────────────────────────────────────────────────────────────────────────\n\n /**\n * Find all journals belonging to a specific tenant\n *\n * @param tenantId - Tenant ID\n * @returns Array of tenant's journals\n */\n async findByTenant(tenantId: string): Promise<Journal[]> {\n return this.list({ where: { tenantId } });\n }\n\n /**\n * Find all global journals (no tenant association).\n *\n * Routes through the shared tenant-global helper so it does not throw under\n * an active tenant context. (#1600)\n *\n * @returns Array of global journals\n */\n async findGlobal(): Promise<Journal[]> {\n return queryGlobal<Journal>(this);\n }\n\n /**\n * Find journals for a tenant plus all global journals.\n *\n * Fails closed if an active tenant context requests a different tenant's\n * rows; the admin/system path keeps the cross-tenant capability. (#1600)\n *\n * @param tenantId - Tenant ID\n * @returns Array of tenant's journals and global journals\n */\n async findWithGlobals(tenantId: string): Promise<Journal[]> {\n return queryWithGlobals<Journal>(this, tenantId, 'Journal.findWithGlobals');\n }\n}\n","import { SmrtCollection } from '@happyvertical/smrt-core';\nimport { Ledger } from '../models/Ledger';\n\nexport class LedgerCollection extends SmrtCollection<Ledger> {\n static readonly _itemClass = Ledger;\n}\n","/**\n * One-time move of ledger accounts out of the shared `accounts` table (#3098).\n *\n * Until 0.51.24 the ledger `Account` derived the table name `accounts`, which\n * smrt-messages' unrelated `Account` also derives. A database may therefore\n * hold ledger accounts in `accounts` alone (ledgers only), or mixed with\n * messaging accounts in one union table (both packages, after `db:migrate`).\n * The ledger model now owns `ledger_accounts`; this migration moves the\n * existing ledger rows there, detaches the foreign keys that pointed ledger\n * references at `accounts`, and leaves messaging rows where they are.\n *\n * Operator sequence (maintenance window, PostgreSQL):\n * 1. `smrt db:migrate` — creates `ledger_accounts` from the manifest. It\n * reports, and does not apply, the retargeted `journal_entries.account_id`\n * foreign key while the old one still points at `accounts`.\n * 2. `smrt db:migrate-ledger-accounts` — this module.\n * 3. `smrt db:migrate` — adds the foreign keys onto `ledger_accounts`.\n */\n\nimport { detectEngine, ObjectRegistry } from '@happyvertical/smrt-core';\nimport {\n BackfillTracker,\n type DatabaseInterface,\n} from '@happyvertical/smrt-core/migrations';\n\nexport const LEDGER_ACCOUNTS_TABLE = 'ledger_accounts';\nexport const LEGACY_ACCOUNTS_TABLE = 'accounts';\nexport const LEDGER_ACCOUNTS_TABLE_MOVE =\n '@happyvertical/smrt-ledgers:ledger-accounts-table:v1';\n\n/**\n * Columns that only the legacy ledger model put on `accounts`. Their presence\n * identifies a table that may hold ledger rows; this is a fact about the\n * pre-#3098 data being migrated, not a schema definition.\n */\nconst LEGACY_LEDGER_SIGNATURE = ['number', 'type'] as const;\n\n/** The STI discriminator smrt-messages writes on every messaging account. */\nconst STI_DISCRIMINATOR = '_meta_type';\n\n/** Messaging columns that a ledger row never populates. */\nconst MESSAGING_MARKERS = ['provider_type', 'channel_type'] as const;\n\nexport interface LedgerAccountsTableMoveOptions {\n backfillName?: string;\n packageName?: string;\n /** PostgreSQL `lock_timeout`, milliseconds (default 30000). */\n lockTimeout?: number;\n /** PostgreSQL `statement_timeout`, milliseconds (default 60000). */\n statementTimeout?: number;\n}\n\nexport interface LedgerAccountsTableMovePlan {\n /** Whether a legacy `accounts` table with ledger columns exists. */\n legacyTable: boolean;\n /** Ledger rows still in `accounts` that this migration would move. */\n pending: number;\n /** Messaging rows that stay in `accounts`. */\n messagingRows: number;\n}\n\nexport interface LedgerAccountsTableMoveResult {\n ran: boolean;\n moved: number;\n /** Rows (messaging accounts) left in `accounts`. */\n remainingLegacyRows: number;\n /** `table.column` foreign keys detached from `accounts`. */\n detachedForeignKeys: string[];\n}\n\nexport class LedgerAccountsTableMoveError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'LedgerAccountsTableMoveError';\n }\n}\n\ntype Queryable = Pick<DatabaseInterface, 'query'>;\n\ninterface LegacyShape {\n columns: Set<string>;\n hasDiscriminator: boolean;\n}\n\nfunction quote(identifier: string): string {\n return `\"${identifier.replace(/\"/g, '\"\"')}\"`;\n}\n\nfunction timeout(value: number | undefined, fallback: number): string {\n const milliseconds = value ?? fallback;\n if (!Number.isInteger(milliseconds) || milliseconds < 0) {\n throw new LedgerAccountsTableMoveError(\n 'Migration timeout must be a non-negative integer',\n );\n }\n return `${milliseconds}ms`;\n}\n\nfunction assertPostgres(db: DatabaseInterface): void {\n const withConfig = db as DatabaseInterface & {\n type?: string;\n config?: { type?: string; url?: string };\n };\n const engine = detectEngine(\n db.url || withConfig.config?.url || '',\n withConfig.type || withConfig.config?.type,\n );\n if (engine !== 'postgres') {\n throw new LedgerAccountsTableMoveError(\n 'The ledger accounts table move supports PostgreSQL only. For a SQLite database whose `accounts` table holds only ledger accounts, run `ALTER TABLE accounts RENAME TO ledger_accounts` before `db:migrate`; see the smrt-ledgers README.',\n );\n }\n}\n\nasync function readLegacyShape(\n db: DatabaseInterface,\n): Promise<LegacyShape | null> {\n const schema = await db.getTableSchema?.(LEGACY_ACCOUNTS_TABLE);\n if (!schema) return null;\n const columns = new Set(Object.keys(schema.columns));\n if (!LEGACY_LEDGER_SIGNATURE.every((column) => columns.has(column))) {\n return null;\n }\n return { columns, hasDiscriminator: columns.has(STI_DISCRIMINATOR) };\n}\n\n/** SQL predicate selecting the ledger rows of the legacy table. */\nfunction ledgerRowPredicate(shape: LegacyShape): string {\n return shape.hasDiscriminator\n ? `(${quote(STI_DISCRIMINATOR)} IS NULL OR ${quote(STI_DISCRIMINATOR)} = '')`\n : 'TRUE';\n}\n\nasync function count(db: Queryable, where: string): Promise<number> {\n const result = await db.query(\n `SELECT COUNT(*) AS n FROM ${quote(LEGACY_ACCOUNTS_TABLE)} WHERE ${where}`,\n );\n return Number((result.rows[0] as { n: number | string }).n);\n}\n\nasync function classify(\n db: Queryable,\n shape: LegacyShape,\n): Promise<{ pending: number; messagingRows: number }> {\n const ledger = ledgerRowPredicate(shape);\n const pending = await count(db, ledger);\n const messagingRows = shape.hasDiscriminator\n ? await count(db, `NOT ${ledger}`)\n : 0;\n\n // Refuse rows whose owner is not certain rather than guess. A messaging\n // row never carries a ledger account number; a ledger row never carries a\n // messaging provider or channel.\n if (shape.hasDiscriminator) {\n const ledgerLooking = await count(\n db,\n `NOT ${ledger} AND COALESCE(${quote('number')}, '') <> ''`,\n );\n const markers = MESSAGING_MARKERS.filter((column) =>\n shape.columns.has(column),\n );\n const messagingLooking =\n markers.length === 0\n ? 0\n : await count(\n db,\n `${ledger} AND (${markers\n .map((column) => `COALESCE(${quote(column)}, '') <> ''`)\n .join(' OR ')})`,\n );\n if (ledgerLooking > 0 || messagingLooking > 0) {\n throw new LedgerAccountsTableMoveError(\n `Refusing to move ledger accounts: ${ledgerLooking} messaging row(s) carry a ledger account number and ${messagingLooking} ledger row(s) carry a messaging provider or channel in \"${LEGACY_ACCOUNTS_TABLE}\". Resolve their ownership by hand, then rerun.`,\n );\n }\n }\n return { pending, messagingRows };\n}\n\n/**\n * Registered foreign keys by the table they reference: `table.column` keys\n * the manifests point at `ledger_accounts` (the references that pointed at\n * `accounts` before #3098) and at `accounts` (messaging's own references).\n */\nexport function registeredReferenceColumns(): RegisteredReferences {\n const ledger = new Set<string>();\n const accounts = new Set<string>();\n const schemas = ObjectRegistry.getAllSchemasAsDefinitions();\n for (const [tableName, schema] of Object.entries(schemas)) {\n for (const [columnName, column] of Object.entries(schema.columns ?? {})) {\n const target = (column as { foreignKey?: { table?: string } }).foreignKey\n ?.table;\n if (target === LEDGER_ACCOUNTS_TABLE) {\n ledger.add(`${tableName}.${columnName}`);\n } else if (target === LEGACY_ACCOUNTS_TABLE) {\n accounts.add(`${tableName}.${columnName}`);\n }\n }\n }\n return { ledger, accounts };\n}\n\n/** Registered `table.column` references, by the table they point at. */\nexport interface RegisteredReferences {\n ledger: Set<string>;\n accounts: Set<string>;\n}\n\n/** One foreign key into the legacy table (`column` is its first column). */\nexport interface LegacyForeignKey {\n constraint: string;\n table: string;\n column: string;\n arity: number;\n}\n\n/** What the move does with each foreign key into the legacy table. */\nexport interface ForeignKeyDisposition {\n /** Composite keys: never a registered single-column reference. */\n composite: LegacyForeignKey[];\n /** Single-column keys no registered model declares. */\n undeclared: LegacyForeignKey[];\n /** Ledger references: detached, re-added against ledger_accounts. */\n detach: LegacyForeignKey[];\n /** Kept (messaging's and the table's own parent link): must not reference a moving row. */\n keep: LegacyForeignKey[];\n}\n\n/**\n * Sort every foreign key into the legacy table before anything is written.\n * A constraint no registered model declares would keep pointing at accounts\n * after the move (blocking later writes), and a CASCADE or SET NULL action on\n * it would delete or clear rows instead of refusing, so the move refuses\n * `composite` and `undeclared` outright (#3098).\n */\nexport function classifyForeignKeys(\n inbound: readonly LegacyForeignKey[],\n references: RegisteredReferences,\n): ForeignKeyDisposition {\n const disposition: ForeignKeyDisposition = {\n composite: [],\n undeclared: [],\n detach: [],\n keep: [],\n };\n for (const fk of inbound) {\n const key = `${fk.table}.${fk.column}`;\n if (fk.arity > 1) disposition.composite.push(fk);\n else if (references.ledger.has(key)) disposition.detach.push(fk);\n else if (fk.table === LEGACY_ACCOUNTS_TABLE || references.accounts.has(key))\n disposition.keep.push(fk);\n else disposition.undeclared.push(fk);\n }\n return disposition;\n}\n\n/** The refusal for foreign keys the move cannot account for, if any. */\nexport function foreignKeyRefusal(\n disposition: ForeignKeyDisposition,\n): string | undefined {\n if (disposition.composite.length > 0) {\n return `Composite foreign key(s) ${disposition.composite.map((fk) => `${fk.constraint} on ${fk.table} (${fk.arity} columns)`).join(', ')} reference \"${LEGACY_ACCOUNTS_TABLE}\"; no model can declare one, so the move cannot carry it. Nothing was moved. Drop it, or replace it with a single-column reference, then rerun.`;\n }\n if (disposition.undeclared.length > 0) {\n return `Foreign key(s) ${disposition.undeclared.map((fk) => `${fk.table}.${fk.column}`).join(', ')} reference \"${LEGACY_ACCOUNTS_TABLE}\" but no registered model declares them; nothing was moved. Run the move from the application whose models declare them, or retarget each to \"${LEDGER_ACCOUNTS_TABLE}\" (or drop it) by hand, then rerun.`;\n }\n return undefined;\n}\n\n/**\n * The SELECT list copying legacy columns into ledger_accounts: values as they\n * are, converting through text only a column whose legacy type differs from\n * the manifest's (e.g. TEXT ids where ledger_accounts declares UUID).\n */\nexport function copySelectList(\n columns: readonly string[],\n targetTypes: Readonly<Record<string, string | undefined>>,\n legacyTypes: Readonly<Record<string, string | undefined>>,\n): string {\n return columns\n .map((column) => {\n const to = targetTypes[column];\n return sameType(legacyTypes[column], to)\n ? quote(column)\n : `CAST(CAST(${quote(column)} AS TEXT) AS ${targetType(to)})`;\n })\n .join(', ');\n}\n\n/**\n * Every foreign key into the legacy table, composite ones included (`arity`\n * > 1): the move must account for all of them before it writes (#3098).\n */\nasync function legacyForeignKeys(db: Queryable): Promise<LegacyForeignKey[]> {\n const result = await db.query(\n `SELECT con.conname AS constraint_name,\n rel.relname AS table_name,\n att.attname AS column_name,\n array_length(con.conkey, 1) AS arity\n FROM pg_constraint con\n JOIN pg_class rel ON rel.oid = con.conrelid\n JOIN pg_attribute att\n ON att.attrelid = con.conrelid AND att.attnum = con.conkey[1]\n WHERE con.contype = 'f'\n AND con.confrelid = to_regclass(?)\n ORDER BY rel.relname, con.conname`,\n quote(LEGACY_ACCOUNTS_TABLE),\n );\n return (\n result.rows as Array<{\n constraint_name: string;\n table_name: string;\n column_name: string;\n arity: number | string;\n }>\n ).map((row) => ({\n constraint: row.constraint_name,\n table: row.table_name,\n column: row.column_name,\n arity: Number(row.arity),\n }));\n}\n\n/**\n * Inspect the legacy table without changing anything. Read-only portable SQL,\n * so it also reports what a SQLite database would need moved.\n */\nexport async function planLedgerAccountsTableMove(\n db: DatabaseInterface,\n): Promise<LedgerAccountsTableMovePlan> {\n const shape = await readLegacyShape(db);\n if (!shape) return { legacyTable: false, pending: 0, messagingRows: 0 };\n return { legacyTable: true, ...(await classify(db, shape)) };\n}\n\n/**\n * Move ledger accounts from `accounts` into `ledger_accounts` in one\n * transaction under an exclusive lock. Operator-invoked and idempotent: a\n * rerun, or a database that never had ledger rows in `accounts`, is a no-op.\n */\nexport async function migrateLedgerAccountsTable(\n db: DatabaseInterface,\n options: LedgerAccountsTableMoveOptions = {},\n): Promise<LedgerAccountsTableMoveResult> {\n assertPostgres(db);\n if (!db.transaction) {\n throw new LedgerAccountsTableMoveError(\n 'The ledger accounts table move requires a transaction-capable PostgreSQL adapter',\n );\n }\n const noop = (remainingLegacyRows = 0): LedgerAccountsTableMoveResult => ({\n ran: false,\n moved: 0,\n remainingLegacyRows,\n detachedForeignKeys: [],\n });\n\n const shape = await readLegacyShape(db);\n if (!shape) return noop();\n const target = await db.getTableSchema?.(LEDGER_ACCOUNTS_TABLE);\n if (!target) {\n throw new LedgerAccountsTableMoveError(\n `\"${LEDGER_ACCOUNTS_TABLE}\" does not exist; run db:migrate before moving ledger accounts`,\n );\n }\n const legacy = await db.getTableSchema?.(LEGACY_ACCOUNTS_TABLE);\n const copyColumns = Object.keys(target.columns).filter((column) =>\n shape.columns.has(column),\n );\n const references = registeredReferenceColumns();\n\n const tracker = new BackfillTracker({ db });\n await tracker.initialize();\n const backfillName = options.backfillName ?? LEDGER_ACCOUNTS_TABLE_MOVE;\n\n return db.transaction(async (tx) => {\n BackfillTracker.inheritInitialization(tx, db);\n const transactionTracker = new BackfillTracker({ db: tx });\n await tx.query(\n `SET LOCAL lock_timeout = '${timeout(options.lockTimeout, 30_000)}'`,\n );\n await tx.query(\n `SET LOCAL statement_timeout = '${timeout(options.statementTimeout, 60_000)}'`,\n );\n await tx.query(\n `LOCK TABLE ${quote(LEGACY_ACCOUNTS_TABLE)}, ${quote(LEDGER_ACCOUNTS_TABLE)} IN ACCESS EXCLUSIVE MODE`,\n );\n\n const { pending, messagingRows } = await classify(tx, shape);\n if (await transactionTracker.isApplied(backfillName)) {\n if (pending > 0) {\n throw new LedgerAccountsTableMoveError(\n `The ledger accounts table move is recorded as applied but \"${LEGACY_ACCOUNTS_TABLE}\" still holds ${pending} ledger row(s); refusing inconsistent state`,\n );\n }\n return noop(messagingRows);\n }\n\n const ledger = ledgerRowPredicate(shape);\n // Compare through text: a legacy table may still carry TEXT ids where\n // ledger_accounts declares UUID (the copy below converts the same way).\n const clash = await tx.query(\n `SELECT COUNT(*) AS n FROM ${quote(LEGACY_ACCOUNTS_TABLE)} legacy\n WHERE ${ledger}\n AND EXISTS (SELECT 1 FROM ${quote(LEDGER_ACCOUNTS_TABLE)} moved\n WHERE CAST(moved.id AS TEXT) = CAST(legacy.id AS TEXT))`,\n );\n if (Number((clash.rows[0] as { n: number | string }).n) > 0) {\n throw new LedgerAccountsTableMoveError(\n `\"${LEDGER_ACCOUNTS_TABLE}\" already holds ids of ledger rows still in \"${LEGACY_ACCOUNTS_TABLE}\"; refusing to overwrite`,\n );\n }\n\n // Account for every foreign key into accounts before writing anything:\n // refuse what the move cannot carry, and a kept constraint may not\n // reference a row that moves.\n const disposition = classifyForeignKeys(\n await legacyForeignKeys(tx),\n references,\n );\n const refusal = foreignKeyRefusal(disposition);\n if (refusal) throw new LedgerAccountsTableMoveError(refusal);\n for (const fk of disposition.keep) {\n const survivor =\n fk.table === LEGACY_ACCOUNTS_TABLE ? ` AND NOT ${ledger}` : '';\n const pointing = await tx.query(\n `SELECT COUNT(*) AS n FROM ${quote(fk.table)}\n WHERE ${quote(fk.column)} IN\n (SELECT id FROM ${quote(LEGACY_ACCOUNTS_TABLE)} WHERE ${ledger})${survivor}`,\n );\n if (Number((pointing.rows[0] as { n: number | string }).n) > 0) {\n throw new LedgerAccountsTableMoveError(\n `${fk.table}.${fk.column} references ledger accounts in \"${LEGACY_ACCOUNTS_TABLE}\" but is not a ledger reference; nothing was moved. Resolve those rows by hand, then rerun.`,\n );\n }\n }\n\n const selectList = copySelectList(\n copyColumns,\n columnTypes(target),\n columnTypes(legacy),\n );\n await tx.query(\n `INSERT INTO ${quote(LEDGER_ACCOUNTS_TABLE)} (${copyColumns\n .map(quote)\n .join(', ')})\n SELECT ${selectList} FROM ${quote(LEGACY_ACCOUNTS_TABLE)} WHERE ${ledger}`,\n );\n\n // Detach the ledger references (journal entries, and anything else the\n // manifests now point at ledger_accounts) from the legacy table. The\n // next db:migrate adds them against ledger_accounts. References owned by\n // messaging (emails, messages, routes) keep pointing at accounts.\n const detached: string[] = [];\n for (const foreignKey of disposition.detach) {\n await tx.query(\n `ALTER TABLE ${quote(foreignKey.table)} DROP CONSTRAINT ${quote(foreignKey.constraint)}`,\n );\n detached.push(`${foreignKey.table}.${foreignKey.column}`);\n }\n\n // Every remaining constraint was checked above; a violation here is a\n // concurrent change the lock did not cover and rolls the move back.\n await tx.query(\n `DELETE FROM ${quote(LEGACY_ACCOUNTS_TABLE)} WHERE ${ledger}`,\n );\n\n await transactionTracker.recordApplied(backfillName, {\n description:\n 'Moved ledger accounts from the shared accounts table to ledger_accounts (#3098).',\n packageName: options.packageName ?? '@happyvertical/smrt-ledgers',\n });\n return {\n ran: true,\n moved: pending,\n remainingLegacyRows: messagingRows,\n detachedForeignKeys: detached,\n };\n });\n}\n\nconst SQL_TYPE = /^[A-Za-z][A-Za-z0-9 _]*(\\(\\d+(,\\s*\\d+)?\\))?(\\[\\])?$/;\n\nfunction columnTypes(\n schema: { columns: Record<string, { type?: string }> } | null | undefined,\n): Record<string, string | undefined> {\n return Object.fromEntries(\n Object.entries(schema?.columns ?? {}).map(([name, column]) => [\n name,\n column.type,\n ]),\n );\n}\n\nfunction sameType(from: string | undefined, to: string | undefined): boolean {\n return (\n from !== undefined &&\n to !== undefined &&\n from.trim().toLowerCase() === to.trim().toLowerCase()\n );\n}\n\nfunction targetType(declared: string | undefined): string {\n const type = declared?.trim();\n if (!type || !SQL_TYPE.test(type)) {\n throw new LedgerAccountsTableMoveError(\n `Cannot copy into \"${LEDGER_ACCOUNTS_TABLE}\": unsupported live column type ${JSON.stringify(type)}`,\n );\n }\n return type;\n}\n","import { digestRunOnceContent, runOnce } from '@happyvertical/smrt-core';\nimport type { DatabaseInterface } from '@happyvertical/smrt-core/migrations';\nimport { getTenantId, withTenant } from '@happyvertical/smrt-tenancy';\nimport { JournalCollection } from './collections/Journals';\nimport { LedgerCollection } from './collections/Ledgers';\nimport type { Journal } from './models/Journal';\n\nexport type Counterparty = { kind: string; id: string };\n\nexport interface LedgerPostingInput {\n db: DatabaseInterface;\n tenantId: string;\n ledgerId: string;\n idempotencyKey: string;\n sourceModule: string;\n sourceRef: string;\n description: string;\n date?: Date;\n currency: string;\n amountMinor: number;\n counterparty: Counterparty;\n debitAccountId: string;\n creditAccountId: string;\n dueDate?: Date;\n settlesSourceRef?: string;\n}\n\nfunction assertInput(input: LedgerPostingInput): void {\n for (const value of [\n input.tenantId,\n input.ledgerId,\n input.idempotencyKey,\n input.sourceModule,\n input.sourceRef,\n input.currency,\n input.counterparty.kind,\n input.counterparty.id,\n input.debitAccountId,\n input.creditAccountId,\n ...(input.settlesSourceRef === undefined ? [] : [input.settlesSourceRef]),\n ]) {\n if (!value?.trim() || value !== value.trim())\n throw new Error(\n 'Ledger posting identifiers must be nonempty trimmed strings',\n );\n }\n if (!Number.isSafeInteger(input.amountMinor) || input.amountMinor <= 0)\n throw new Error(\n 'Ledger posting amountMinor must be a positive safe integer',\n );\n}\n\nfunction replayMismatchError(): Error {\n return new Error(\n 'Ledger posting idempotency key was replayed with different content',\n );\n}\n\n/**\n * Atomically records an exact-minor-unit double entry. `runOnce` scopes the\n * key by tenant and ledger; its receipt binds the request digest so retries recover the\n * original journal and a changed replay refuses instead of double-posting.\n * Idempotency is permanent: once the receipt is pruned, the journal's unique\n * `(tenantId, ledgerId, idempotencyKey)` row and its `requestDigest` answer the\n * same replay.\n */\nexport async function postLedgerEntry(\n input: LedgerPostingInput,\n): Promise<Journal> {\n // Snapshot caller-owned data before the first await; a caller may reuse or\n // mutate its request object while another posting is waiting for a claim.\n input = {\n ...input,\n counterparty: { ...input.counterparty },\n date: input.date ? new Date(input.date) : undefined,\n dueDate: input.dueDate ? new Date(input.dueDate) : undefined,\n };\n assertInput(input);\n if (getTenantId() && getTenantId() !== input.tenantId)\n throw new Error('Ledger posting tenant differs from active context');\n const content = {\n ledgerId: input.ledgerId,\n sourceModule: input.sourceModule,\n sourceRef: input.sourceRef,\n description: input.description,\n date: input.date?.toISOString() ?? null,\n currency: input.currency,\n amountMinor: input.amountMinor,\n counterparty: input.counterparty,\n debitAccountId: input.debitAccountId,\n creditAccountId: input.creditAccountId,\n dueDate: input.dueDate?.toISOString() ?? null,\n settlesSourceRef: input.settlesSourceRef ?? null,\n };\n const digest = digestRunOnceContent(content);\n const receipt = await withTenant({ tenantId: input.tenantId }, () =>\n runOnce(\n {\n db: input.db,\n tenantId: input.tenantId,\n actor: 'smrt-ledgers.post:v1',\n token: input.idempotencyKey,\n content: { ledgerId: input.ledgerId },\n },\n async (tx) => {\n const ledger = await (await LedgerCollection.create({ db: tx })).get({\n id: input.ledgerId,\n });\n if (\n !ledger ||\n ledger.tenantId !== input.tenantId ||\n ledger.balanceMode !== 'exact-integer'\n )\n throw new Error(\n 'Posting helpers require an owned exact-integer ledger',\n );\n const journals = await JournalCollection.create({ db: tx });\n // The `runOnce` claim is pruned after its retention window (30 days by\n // default), after which an identical retry would re-run this callback\n // and hit `journals_ledger_idempotency_key`. The journal row is the\n // permanent idempotency record, so resolve it before inserting (#4067).\n const [existing] = await journals.list({\n where: {\n tenantId: input.tenantId,\n ledgerId: input.ledgerId,\n idempotencyKey: input.idempotencyKey,\n },\n limit: 1,\n });\n if (existing) {\n if (existing.requestDigest !== digest) throw replayMismatchError();\n if (!existing.isPosted())\n throw new Error(\n 'Ledger posting idempotency key belongs to a journal that is not posted',\n );\n return { journalId: existing.id, requestDigest: digest };\n }\n const journal = await journals.createWithEntries({\n tenantId: input.tenantId,\n ledgerId: input.ledgerId,\n date: input.date ?? new Date(),\n description: input.description,\n sourceModule: input.sourceModule,\n sourceRef: input.sourceRef,\n idempotencyKey: input.idempotencyKey,\n requestDigest: digest,\n metadata: {\n idempotencyKey: input.idempotencyKey,\n requestDigest: digest,\n },\n entries: [\n {\n accountId: input.debitAccountId,\n debit: input.amountMinor,\n currency: input.currency,\n counterpartyKind: input.counterparty.kind,\n counterpartyId: input.counterparty.id,\n dueDate: input.dueDate,\n settlesSourceRef: input.settlesSourceRef,\n },\n {\n accountId: input.creditAccountId,\n credit: input.amountMinor,\n currency: input.currency,\n counterpartyKind: input.counterparty.kind,\n counterpartyId: input.counterparty.id,\n dueDate: input.dueDate,\n settlesSourceRef: input.settlesSourceRef,\n },\n ],\n });\n await journal.post();\n return { journalId: journal.id, requestDigest: digest };\n },\n ),\n );\n if (receipt.requestDigest !== digest) throw replayMismatchError();\n const journal = await withTenant({ tenantId: input.tenantId }, async () => {\n const journals = await JournalCollection.create({ db: input.db });\n return journals.get({ id: String(receipt.journalId) });\n });\n if (!journal?.isPosted())\n throw new Error(\n 'Ledger posting receipt does not resolve to a posted journal',\n );\n if (journal.requestDigest !== digest) throw replayMismatchError();\n return journal;\n}\n\nexport const postReceivable = postLedgerEntry;\nexport const postPayable = postLedgerEntry;\nexport const postSettlement = postLedgerEntry;\n","/**\n * Declared recipes for smrt-ledgers (#3590, #3604): user-facing units of\n * functionality an app or agent can pick instead of the whole package.\n * The scanner reads these statics into the `recipes` array of `manifest.json`\n * and `smrt-knowledge.json`; nothing here runs at that point.\n *\n * @packageDocumentation\n */\n\nimport { SmrtRecipe } from '@happyvertical/smrt-core';\nimport { Account } from './models/Account.js';\nimport { Journal } from './models/Journal.js';\nimport { JournalEntry } from './models/JournalEntry.js';\n\n/** Bookkeeping: Keep your books: a chart of accounts and double-entry journals. */\nexport class BookkeepingRecipe extends SmrtRecipe {\n static id = 'ledgers.bookkeeping';\n static help = './bookkeeping.recipe.md';\n static label = 'Bookkeeping';\n static summary =\n 'Keep your books: a chart of accounts and double-entry journals.';\n static synonyms = [\n 'accounting',\n 'ledger',\n 'general ledger',\n 'journals',\n 'chart of accounts',\n ];\n static section = {\n id: 'accounting',\n label: 'Accounting',\n icon: 'bank',\n description: 'Your books: accounts, journals and balances.',\n };\n static models = [Account, Journal, JournalEntry];\n static nav = [\n {\n label: 'Accounts',\n model: Account,\n icon: 'bank',\n description:\n 'The accounts your books are kept in, like sales, rent and bank.',\n },\n {\n label: 'Journals',\n model: Journal,\n icon: 'book',\n description:\n 'The entries behind your accounts, so every dollar has a trail.',\n },\n ];\n static options = {\n Account: {\n fields: {\n metadata: { visibility: 'hidden' },\n parentId: { visibility: 'hidden' },\n },\n },\n Journal: {\n fields: {\n sourceModule: { visibility: 'hidden' },\n sourceRef: { visibility: 'hidden' },\n idempotencyKey: { visibility: 'hidden' },\n requestDigest: { visibility: 'hidden' },\n voidedAt: { visibility: 'hidden' },\n voidReason: { visibility: 'hidden' },\n metadata: { visibility: 'hidden' },\n },\n },\n JournalEntry: {\n fields: {\n exchangeRate: { visibility: 'hidden' },\n settlesSourceRef: { visibility: 'hidden' },\n metadata: { visibility: 'hidden' },\n },\n },\n } as const;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["journal"],"sources":["../src/__smrt-register__.ts","../src/prompts.ts","../src/collections/Accounts.ts","../src/models/JournalEntry.ts","../src/collections/JournalEntries.ts","../src/models/Journal.ts","../src/collections/Journals.ts","../src/collections/Ledgers.ts","../src/migrations/ledger-accounts-table.ts","../src/postings.ts","../src/recipes.ts"],"sourcesContent":["// Generated by @happyvertical/smrt-core smrtPlugin at library build time.\n// The package manifest is inlined so self-registration cannot miss when a\n// downstream bundler relocates this module away from dist/manifest.json\n// (https://github.com/happyvertical/smrt/issues/1506,\n// https://github.com/happyvertical/smrt/issues/1507).\nimport { ObjectRegistry } from '@happyvertical/smrt-core';\n\nObjectRegistry.registerPackageManifest(JSON.parse(\"{\\\"version\\\":\\\"1.0.0\\\",\\\"timestamp\\\":0,\\\"packageName\\\":\\\"@happyvertical/smrt-ledgers\\\",\\\"packageVersion\\\":\\\"0.60.1\\\",\\\"objects\\\":{\\\"@happyvertical/smrt-ledgers:AccountCollection\\\":{\\\"name\\\":\\\"accountcollection\\\",\\\"className\\\":\\\"AccountCollection\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-ledgers:AccountCollection\\\",\\\"collection\\\":\\\"accounts\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/ledgers/src/collections/Accounts.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-ledgers\\\",\\\"fields\\\":{},\\\"methods\\\":{\\\"findByNumber\\\":{\\\"name\\\":\\\"findByNumber\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"number\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Account | null>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findByType\\\":{\\\"name\\\":\\\"findByType\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"type\\\",\\\"type\\\":\\\"AccountType\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Account[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findActive\\\":{\\\"name\\\":\\\"findActive\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<Account[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findTopLevel\\\":{\\\"name\\\":\\\"findTopLevel\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<Account[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findChildren\\\":{\\\"name\\\":\\\"findChildren\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"parentId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Account[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getTree\\\":{\\\"name\\\":\\\"getTree\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<AccountTree>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getOrCreateByNumber\\\":{\\\"name\\\":\\\"getOrCreateByNumber\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"number\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"defaults\\\",\\\"type\\\":\\\"Partial<object>\\\",\\\"optional\\\":true,\\\"memberTypes\\\":[\\\"string\\\",\\\"AccountType\\\",\\\"string | null\\\"]}],\\\"returnType\\\":\\\"Promise<Account>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"groupByType\\\":{\\\"name\\\":\\\"groupByType\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<Record<AccountType, Account[]>>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getDescendants\\\":{\\\"name\\\":\\\"getDescendants\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"accountId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Account[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findByTenant\\\":{\\\"name\\\":\\\"findByTenant\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"tenantId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Account[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findGlobal\\\":{\\\"name\\\":\\\"findGlobal\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<Account[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findWithGlobals\\\":{\\\"name\\\":\\\"findWithGlobals\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"tenantId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Account[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"ledger_accounts\\\",\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\",\\\"delete\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\"]}},\\\"extends\\\":\\\"SmrtCollection\\\",\\\"extendsTypeArg\\\":\\\"Account\\\",\\\"exportName\\\":\\\"AccountCollection\\\",\\\"collectionExportName\\\":\\\"AccountCollectionCollection\\\",\\\"collectionOf\\\":\\\"@happyvertical/smrt-ledgers:Account\\\",\\\"inheritedExposure\\\":[\\\"api\\\",\\\"mcp\\\"],\\\"schema\\\":{\\\"tableName\\\":\\\"ledger_accounts\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"ledger_accounts\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"parent_id\\\\\\\" UUID,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"number\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"name\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"description\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"type\\\\\\\" TEXT DEFAULT 'asset',\\\\n \\\\\\\"ledger_id\\\\\\\" UUID,\\\\n \\\\\\\"active\\\\\\\" BOOLEAN DEFAULT TRUE,\\\\n \\\\\\\"metadata\\\\\\\" JSON DEFAULT '{}'\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"parent_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"ledger_accounts\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"NO ACTION\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"number\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"name\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"description\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"type\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"asset\\\"},\\\"ledger_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"ledgers\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"NO ACTION\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"active\\\":{\\\"type\\\":\\\"BOOLEAN\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":true},\\\"metadata\\\":{\\\"type\\\":\\\"JSON\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":{}}},\\\"indexes\\\":[{\\\"name\\\":\\\"ledger_accounts_slug_context_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"],\\\"unique\\\":true,\\\"nullsNotDistinct\\\":true},{\\\"name\\\":\\\"ledger_accounts_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"ledger_accounts_parent_id_idx\\\",\\\"columns\\\":[\\\"parent_id\\\"]},{\\\"name\\\":\\\"ledger_accounts_ledger_id_idx\\\",\\\"columns\\\":[\\\"ledger_id\\\"]}],\\\"version\\\":\\\"caea63eb\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-ledgers\\\"},\\\"@happyvertical/smrt-ledgers:JournalEntryCollection\\\":{\\\"name\\\":\\\"journalentrycollection\\\",\\\"className\\\":\\\"JournalEntryCollection\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-ledgers:JournalEntryCollection\\\",\\\"collection\\\":\\\"journalentries\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/ledgers/src/collections/JournalEntries.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-ledgers\\\",\\\"fields\\\":{},\\\"methods\\\":{\\\"findByJournal\\\":{\\\"name\\\":\\\"findByJournal\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"journalId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<JournalEntry[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findByAccount\\\":{\\\"name\\\":\\\"findByAccount\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"accountId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<JournalEntry[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getCounterpartyBalances\\\":{\\\"name\\\":\\\"getCounterpartyBalances\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"options\\\",\\\"type\\\":\\\"PostedJournalMovementOptions\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<CounterpartyBalance[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getCounterpartyAging\\\":{\\\"name\\\":\\\"getCounterpartyAging\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"options\\\",\\\"type\\\":\\\"PostedJournalMovementOptions\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"asOf\\\",\\\"type\\\":\\\"Date\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<CounterpartyAgingRow[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getAccountBalance\\\":{\\\"name\\\":\\\"getAccountBalance\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"accountId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"asOfDate\\\",\\\"type\\\":\\\"Date\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<number>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getTrialBalance\\\":{\\\"name\\\":\\\"getTrialBalance\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"asOfDate\\\",\\\"type\\\":\\\"Date\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<TrialBalanceRow[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getTotalsForDateRange\\\":{\\\"name\\\":\\\"getTotalsForDateRange\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"start\\\",\\\"type\\\":\\\"Date\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"end\\\",\\\"type\\\":\\\"Date\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<object>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findByAccounts\\\":{\\\"name\\\":\\\"findByAccounts\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"accountIds\\\",\\\"type\\\":\\\"string[]\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<JournalEntry[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"listPostedMovements\\\":{\\\"name\\\":\\\"listPostedMovements\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"options\\\",\\\"type\\\":\\\"PostedJournalMovementOptions\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<PostedJournalMovement[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getAccountLedger\\\":{\\\"name\\\":\\\"getAccountLedger\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"accountId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Array<object>>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findByTenant\\\":{\\\"name\\\":\\\"findByTenant\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"tenantId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<JournalEntry[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findGlobal\\\":{\\\"name\\\":\\\"findGlobal\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<JournalEntry[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findWithGlobals\\\":{\\\"name\\\":\\\"findWithGlobals\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"tenantId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<JournalEntry[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]}},\\\"extends\\\":\\\"SmrtCollection\\\",\\\"extendsTypeArg\\\":\\\"JournalEntry\\\",\\\"exportName\\\":\\\"JournalEntryCollection\\\",\\\"collectionExportName\\\":\\\"JournalEntryCollectionCollection\\\",\\\"collectionOf\\\":\\\"@happyvertical/smrt-ledgers:JournalEntry\\\",\\\"inheritedExposure\\\":[\\\"api\\\",\\\"mcp\\\"],\\\"schema\\\":{\\\"tableName\\\":\\\"journal_entries\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"journal_entries\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"journal_id\\\\\\\" UUID,\\\\n \\\\\\\"account_id\\\\\\\" UUID,\\\\n \\\\\\\"counterparty_kind\\\\\\\" TEXT,\\\\n \\\\\\\"counterparty_id\\\\\\\" TEXT,\\\\n \\\\\\\"due_date\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"settles_source_ref\\\\\\\" TEXT,\\\\n \\\\\\\"debit\\\\\\\" REAL DEFAULT 0,\\\\n \\\\\\\"credit\\\\\\\" REAL DEFAULT 0,\\\\n \\\\\\\"currency\\\\\\\" TEXT DEFAULT 'USD',\\\\n \\\\\\\"exchange_rate\\\\\\\" REAL DEFAULT 1,\\\\n \\\\\\\"memo\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"metadata\\\\\\\" JSON DEFAULT '{}'\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"journal_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"journals\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"NO ACTION\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"account_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"ledger_accounts\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"NO ACTION\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"counterparty_kind\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"counterparty_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"due_date\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"settles_source_ref\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"debit\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":0},\\\"credit\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":0},\\\"currency\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"USD\\\"},\\\"exchange_rate\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":1},\\\"memo\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"metadata\\\":{\\\"type\\\":\\\"JSON\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":{}}},\\\"indexes\\\":[{\\\"name\\\":\\\"journal_entries_slug_context_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"],\\\"unique\\\":true,\\\"nullsNotDistinct\\\":true},{\\\"name\\\":\\\"journal_entries_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"journal_entries_journal_id_idx\\\",\\\"columns\\\":[\\\"journal_id\\\"]},{\\\"name\\\":\\\"journal_entries_account_id_idx\\\",\\\"columns\\\":[\\\"account_id\\\"]}],\\\"version\\\":\\\"e96b76a2\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-ledgers\\\"},\\\"@happyvertical/smrt-ledgers:JournalCollection\\\":{\\\"name\\\":\\\"journalcollection\\\",\\\"className\\\":\\\"JournalCollection\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-ledgers:JournalCollection\\\",\\\"collection\\\":\\\"journals\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/ledgers/src/collections/Journals.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-ledgers\\\",\\\"fields\\\":{},\\\"methods\\\":{\\\"findByNumber\\\":{\\\"name\\\":\\\"findByNumber\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"number\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Journal | null>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findByDateRange\\\":{\\\"name\\\":\\\"findByDateRange\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"start\\\",\\\"type\\\":\\\"Date\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"end\\\",\\\"type\\\":\\\"Date\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Journal[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findBySource\\\":{\\\"name\\\":\\\"findBySource\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"sourceModule\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Journal[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findByStatus\\\":{\\\"name\\\":\\\"findByStatus\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"status\\\",\\\"type\\\":\\\"JournalStatus\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Journal[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findDrafts\\\":{\\\"name\\\":\\\"findDrafts\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<Journal[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findPosted\\\":{\\\"name\\\":\\\"findPosted\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<Journal[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"createWithEntries\\\":{\\\"name\\\":\\\"createWithEntries\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"data\\\",\\\"type\\\":\\\"CreateJournalData\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Journal>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"post\\\":{\\\"name\\\":\\\"post\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"journalId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Journal>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"void\\\":{\\\"name\\\":\\\"void\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"journalId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"reason\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Journal>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findBySourceRef\\\":{\\\"name\\\":\\\"findBySourceRef\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"sourceRef\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Journal[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findByMonth\\\":{\\\"name\\\":\\\"findByMonth\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"year\\\",\\\"type\\\":\\\"number\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"month\\\",\\\"type\\\":\\\"number\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Journal[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findByTenant\\\":{\\\"name\\\":\\\"findByTenant\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"tenantId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Journal[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findGlobal\\\":{\\\"name\\\":\\\"findGlobal\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<Journal[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findWithGlobals\\\":{\\\"name\\\":\\\"findWithGlobals\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"tenantId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Journal[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\"]}},\\\"extends\\\":\\\"SmrtCollection\\\",\\\"extendsTypeArg\\\":\\\"Journal\\\",\\\"exportName\\\":\\\"JournalCollection\\\",\\\"collectionExportName\\\":\\\"JournalCollectionCollection\\\",\\\"collectionOf\\\":\\\"@happyvertical/smrt-ledgers:Journal\\\",\\\"inheritedExposure\\\":[\\\"api\\\",\\\"mcp\\\"],\\\"schema\\\":{\\\"tableName\\\":\\\"journals\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"journals\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"number\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"date\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"description\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"source_module\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"source_ref\\\\\\\" TEXT,\\\\n \\\\\\\"ledger_id\\\\\\\" UUID,\\\\n \\\\\\\"idempotency_key\\\\\\\" TEXT,\\\\n \\\\\\\"request_digest\\\\\\\" TEXT,\\\\n \\\\\\\"status\\\\\\\" TEXT DEFAULT 'draft',\\\\n \\\\\\\"posted_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"voided_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"void_reason\\\\\\\" TEXT,\\\\n \\\\\\\"metadata\\\\\\\" JSON DEFAULT '{}'\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"number\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"date\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"description\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"source_module\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"source_ref\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"ledger_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"ledgers\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"NO ACTION\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"idempotency_key\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"request_digest\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"status\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"draft\\\"},\\\"posted_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"voided_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"void_reason\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"metadata\\\":{\\\"type\\\":\\\"JSON\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":{}}},\\\"indexes\\\":[{\\\"name\\\":\\\"journals_slug_context_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"],\\\"unique\\\":true,\\\"nullsNotDistinct\\\":true},{\\\"name\\\":\\\"journals_ledger_idempotency_key\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"ledger_id\\\",\\\"idempotency_key\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"journals_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"journals_ledger_id_idx\\\",\\\"columns\\\":[\\\"ledger_id\\\"]}],\\\"version\\\":\\\"1e73dd60\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-ledgers\\\"},\\\"@happyvertical/smrt-ledgers:LedgerCollection\\\":{\\\"name\\\":\\\"ledgercollection\\\",\\\"className\\\":\\\"LedgerCollection\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-ledgers:LedgerCollection\\\",\\\"collection\\\":\\\"ledgers\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/ledgers/src/collections/Ledgers.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-ledgers\\\",\\\"fields\\\":{},\\\"methods\\\":{},\\\"decoratorConfig\\\":{\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\"]}},\\\"extends\\\":\\\"SmrtCollection\\\",\\\"extendsTypeArg\\\":\\\"Ledger\\\",\\\"exportName\\\":\\\"LedgerCollection\\\",\\\"collectionExportName\\\":\\\"LedgerCollectionCollection\\\",\\\"collectionOf\\\":\\\"@happyvertical/smrt-ledgers:Ledger\\\",\\\"inheritedExposure\\\":[\\\"api\\\",\\\"mcp\\\"],\\\"schema\\\":{\\\"tableName\\\":\\\"ledgers\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"ledgers\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"name\\\\\\\" TEXT,\\\\n \\\\\\\"currency\\\\\\\" TEXT,\\\\n \\\\\\\"balance_mode\\\\\\\" TEXT DEFAULT 'tolerant'\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"name\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"currency\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"balance_mode\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"tolerant\\\"}},\\\"indexes\\\":[{\\\"name\\\":\\\"ledgers_slug_context_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"],\\\"unique\\\":true,\\\"nullsNotDistinct\\\":true},{\\\"name\\\":\\\"ledgers_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]}],\\\"version\\\":\\\"be316e4f\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-ledgers\\\"},\\\"@happyvertical/smrt-ledgers:Account\\\":{\\\"name\\\":\\\"account\\\",\\\"className\\\":\\\"Account\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-ledgers:Account\\\",\\\"collection\\\":\\\"accounts\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/ledgers/src/models/Account.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-ledgers\\\",\\\"fields\\\":{\\\"parentId\\\":{\\\"type\\\":\\\"foreignKey\\\",\\\"required\\\":false,\\\"related\\\":\\\"Account\\\",\\\"_meta\\\":{\\\"nullable\\\":true}},\\\"tenantId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"sqlType\\\":\\\"UUID\\\",\\\"nullable\\\":true,\\\"__tenancy\\\":{\\\"isTenantIdField\\\":true,\\\"autoFilter\\\":true,\\\"required\\\":false,\\\"autoPopulate\\\":true,\\\"nullable\\\":true,\\\"mode\\\":\\\"optional\\\",\\\"field\\\":\\\"tenantId\\\",\\\"allowSuperAdminBypass\\\":false}}},\\\"number\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"\\\",\\\"description\\\":\\\"The account number in your chart of accounts.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The account number in your chart of accounts.\\\"}},\\\"name\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"\\\",\\\"description\\\":\\\"What the account is called.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"What the account is called.\\\"}},\\\"description\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"\\\",\\\"description\\\":\\\"What the account is used for.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"What the account is used for.\\\"}},\\\"type\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"asset\\\",\\\"description\\\":\\\"asset, liability, equity, revenue or expense.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"asset, liability, equity, revenue or expense.\\\"},\\\"enum\\\":[\\\"asset\\\",\\\"liability\\\",\\\"equity\\\",\\\"revenue\\\",\\\"expense\\\"]},\\\"ledgerId\\\":{\\\"type\\\":\\\"foreignKey\\\",\\\"required\\\":false,\\\"related\\\":\\\"Ledger\\\",\\\"description\\\":\\\"The ledger policy this account belongs to.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The ledger policy this account belongs to.\\\",\\\"nullable\\\":true}},\\\"active\\\":{\\\"type\\\":\\\"boolean\\\",\\\"required\\\":false,\\\"default\\\":true,\\\"description\\\":\\\"Whether the account is in use; deactivate it instead of deleting it.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"Whether the account is in use; deactivate it instead of deleting it.\\\"}},\\\"metadata\\\":{\\\"type\\\":\\\"json\\\",\\\"required\\\":false,\\\"default\\\":{}}},\\\"methods\\\":{\\\"getParent\\\":{\\\"name\\\":\\\"getParent\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<this | null>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getChildren\\\":{\\\"name\\\":\\\"getChildren\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<this[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getAncestors\\\":{\\\"name\\\":\\\"getAncestors\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<this[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getDescendants\\\":{\\\"name\\\":\\\"getDescendants\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<this[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getHierarchy\\\":{\\\"name\\\":\\\"getHierarchy\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<HierarchyView<this>>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"moveTo\\\":{\\\"name\\\":\\\"moveTo\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"newParent\\\",\\\"type\\\":\\\"this | string | null\\\",\\\"optional\\\":false,\\\"unionBranches\\\":[{\\\"type\\\":\\\"this\\\"},{\\\"type\\\":\\\"string\\\"},{\\\"type\\\":\\\"null\\\"}]}],\\\"returnType\\\":\\\"Promise<void>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"delete\\\":{\\\"name\\\":\\\"delete\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"options\\\",\\\"type\\\":\\\"any\\\",\\\"optional\\\":true,\\\"typeUnresolved\\\":true}],\\\"returnType\\\":\\\"Promise<void>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"isTopLevel\\\":{\\\"name\\\":\\\"isTopLevel\\\",\\\"async\\\":false,\\\"parameters\\\":[],\\\"returnType\\\":\\\"boolean\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"isDebitNormal\\\":{\\\"name\\\":\\\"isDebitNormal\\\",\\\"async\\\":false,\\\"parameters\\\":[],\\\"returnType\\\":\\\"boolean\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"isCreditNormal\\\":{\\\"name\\\":\\\"isCreditNormal\\\",\\\"async\\\":false,\\\"parameters\\\":[],\\\"returnType\\\":\\\"boolean\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getFullPath\\\":{\\\"name\\\":\\\"getFullPath\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<string>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"toTreeNode\\\":{\\\"name\\\":\\\"toTreeNode\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<AccountTreeNode>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getBalance\\\":{\\\"name\\\":\\\"getBalance\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"asOfDate\\\",\\\"type\\\":\\\"Date\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<number>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"createChild\\\":{\\\"name\\\":\\\"createChild\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"options\\\",\\\"type\\\":\\\"Omit<AccountOptions, 'parentId' | 'type'>\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Account>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"ledger_accounts\\\",\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\",\\\"delete\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\"]},\\\"cli\\\":{\\\"skipApiCheck\\\":true},\\\"tenantScoped\\\":{\\\"mode\\\":\\\"optional\\\"},\\\"conflictColumns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"]},\\\"extends\\\":\\\"SmrtHierarchical\\\",\\\"exportName\\\":\\\"Account\\\",\\\"collectionExportName\\\":\\\"AccountCollection\\\",\\\"displayLabelField\\\":\\\"name\\\",\\\"schema\\\":{\\\"tableName\\\":\\\"ledger_accounts\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"ledger_accounts\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"parent_id\\\\\\\" UUID,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"number\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"name\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"description\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"type\\\\\\\" TEXT DEFAULT 'asset',\\\\n \\\\\\\"ledger_id\\\\\\\" UUID,\\\\n \\\\\\\"active\\\\\\\" BOOLEAN DEFAULT TRUE,\\\\n \\\\\\\"metadata\\\\\\\" JSON DEFAULT '{}'\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"parent_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"ledger_accounts\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"NO ACTION\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"number\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"name\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"description\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"type\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"asset\\\"},\\\"ledger_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"ledgers\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"NO ACTION\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"active\\\":{\\\"type\\\":\\\"BOOLEAN\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":true},\\\"metadata\\\":{\\\"type\\\":\\\"JSON\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":{}}},\\\"indexes\\\":[{\\\"name\\\":\\\"ledger_accounts_slug_context_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"],\\\"unique\\\":true,\\\"nullsNotDistinct\\\":true},{\\\"name\\\":\\\"ledger_accounts_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"ledger_accounts_parent_id_idx\\\",\\\"columns\\\":[\\\"parent_id\\\"]},{\\\"name\\\":\\\"ledger_accounts_ledger_id_idx\\\",\\\"columns\\\":[\\\"ledger_id\\\"]}],\\\"version\\\":\\\"caea63eb\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-ledgers\\\"},\\\"@happyvertical/smrt-ledgers:Journal\\\":{\\\"name\\\":\\\"journal\\\",\\\"className\\\":\\\"Journal\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-ledgers:Journal\\\",\\\"collection\\\":\\\"journals\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/ledgers/src/models/Journal.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-ledgers\\\",\\\"fields\\\":{\\\"tenantId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"sqlType\\\":\\\"UUID\\\",\\\"nullable\\\":true,\\\"__tenancy\\\":{\\\"isTenantIdField\\\":true,\\\"autoFilter\\\":true,\\\"required\\\":false,\\\"autoPopulate\\\":true,\\\"nullable\\\":true,\\\"mode\\\":\\\"optional\\\",\\\"field\\\":\\\"tenantId\\\",\\\"allowSuperAdminBypass\\\":false}}},\\\"number\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"\\\",\\\"description\\\":\\\"The journal's reference number.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The journal's reference number.\\\"}},\\\"date\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false,\\\"description\\\":\\\"The date of the transaction.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The date of the transaction.\\\"}},\\\"description\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"\\\",\\\"description\\\":\\\"What the transaction was.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"What the transaction was.\\\"}},\\\"sourceModule\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"\\\"},\\\"sourceRef\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false},\\\"ledgerId\\\":{\\\"type\\\":\\\"foreignKey\\\",\\\"required\\\":false,\\\"related\\\":\\\"Ledger\\\",\\\"description\\\":\\\"The ledger policy that governs this journal.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The ledger policy that governs this journal.\\\",\\\"nullable\\\":true}},\\\"idempotencyKey\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"nullable\\\":true}},\\\"requestDigest\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false},\\\"status\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"draft\\\",\\\"description\\\":\\\"draft until final, then posted, or voided.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"draft until final, then posted, or voided.\\\"},\\\"enum\\\":[\\\"draft\\\",\\\"posted\\\",\\\"voided\\\"]},\\\"postedAt\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false,\\\"description\\\":\\\"When it was posted.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"When it was posted.\\\"}},\\\"voidedAt\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false},\\\"voidReason\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false},\\\"metadata\\\":{\\\"type\\\":\\\"json\\\",\\\"required\\\":false,\\\"default\\\":{}}},\\\"methods\\\":{\\\"isDraft\\\":{\\\"name\\\":\\\"isDraft\\\",\\\"async\\\":false,\\\"parameters\\\":[],\\\"returnType\\\":\\\"boolean\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"isPosted\\\":{\\\"name\\\":\\\"isPosted\\\",\\\"async\\\":false,\\\"parameters\\\":[],\\\"returnType\\\":\\\"boolean\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"isVoided\\\":{\\\"name\\\":\\\"isVoided\\\",\\\"async\\\":false,\\\"parameters\\\":[],\\\"returnType\\\":\\\"boolean\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"isEditable\\\":{\\\"name\\\":\\\"isEditable\\\",\\\"async\\\":false,\\\"parameters\\\":[],\\\"returnType\\\":\\\"boolean\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getEntries\\\":{\\\"name\\\":\\\"getEntries\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"any\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getTotalDebits\\\":{\\\"name\\\":\\\"getTotalDebits\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<number>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getTotalCredits\\\":{\\\"name\\\":\\\"getTotalCredits\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<number>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"isBalanced\\\":{\\\"name\\\":\\\"isBalanced\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<boolean>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getLedger\\\":{\\\"name\\\":\\\"getLedger\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"any\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"addEntry\\\":{\\\"name\\\":\\\"addEntry\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"data\\\",\\\"type\\\":\\\"JournalEntryData\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<void>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"post\\\":{\\\"name\\\":\\\"post\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<void>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"void\\\":{\\\"name\\\":\\\"void\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"reason\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<void>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"save\\\":{\\\"name\\\":\\\"save\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"options\\\",\\\"type\\\":\\\"any\\\",\\\"optional\\\":true,\\\"typeUnresolved\\\":true}],\\\"returnType\\\":\\\"Promise<this>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"delete\\\":{\\\"name\\\":\\\"delete\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"options\\\",\\\"type\\\":\\\"any\\\",\\\"optional\\\":true,\\\"typeUnresolved\\\":true}],\\\"returnType\\\":\\\"Promise<void>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"summarize\\\":{\\\"name\\\":\\\"summarize\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<string>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\"]},\\\"cli\\\":{\\\"skipApiCheck\\\":true},\\\"indexes\\\":[{\\\"name\\\":\\\"journals_ledger_idempotency_key\\\",\\\"columns\\\":[\\\"tenantId\\\",\\\"ledgerId\\\",\\\"idempotencyKey\\\"],\\\"unique\\\":true}],\\\"tenantScoped\\\":{\\\"mode\\\":\\\"optional\\\"},\\\"conflictColumns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"]},\\\"extends\\\":\\\"SmrtObject\\\",\\\"exportName\\\":\\\"Journal\\\",\\\"collectionExportName\\\":\\\"JournalCollection\\\",\\\"schema\\\":{\\\"tableName\\\":\\\"journals\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"journals\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"number\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"date\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"description\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"source_module\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"source_ref\\\\\\\" TEXT,\\\\n \\\\\\\"ledger_id\\\\\\\" UUID,\\\\n \\\\\\\"idempotency_key\\\\\\\" TEXT,\\\\n \\\\\\\"request_digest\\\\\\\" TEXT,\\\\n \\\\\\\"status\\\\\\\" TEXT DEFAULT 'draft',\\\\n \\\\\\\"posted_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"voided_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"void_reason\\\\\\\" TEXT,\\\\n \\\\\\\"metadata\\\\\\\" JSON DEFAULT '{}'\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"number\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"date\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"description\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"source_module\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"source_ref\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"ledger_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"ledgers\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"NO ACTION\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"idempotency_key\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"request_digest\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"status\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"draft\\\"},\\\"posted_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"voided_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"void_reason\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"metadata\\\":{\\\"type\\\":\\\"JSON\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":{}}},\\\"indexes\\\":[{\\\"name\\\":\\\"journals_slug_context_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"],\\\"unique\\\":true,\\\"nullsNotDistinct\\\":true},{\\\"name\\\":\\\"journals_ledger_idempotency_key\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"ledger_id\\\",\\\"idempotency_key\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"journals_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"journals_ledger_id_idx\\\",\\\"columns\\\":[\\\"ledger_id\\\"]}],\\\"version\\\":\\\"1e73dd60\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-ledgers\\\"},\\\"@happyvertical/smrt-ledgers:JournalEntry\\\":{\\\"name\\\":\\\"journalentry\\\",\\\"className\\\":\\\"JournalEntry\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-ledgers:JournalEntry\\\",\\\"collection\\\":\\\"journalentries\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/ledgers/src/models/JournalEntry.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-ledgers\\\",\\\"fields\\\":{\\\"tenantId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"sqlType\\\":\\\"UUID\\\",\\\"nullable\\\":true,\\\"__tenancy\\\":{\\\"isTenantIdField\\\":true,\\\"autoFilter\\\":true,\\\"required\\\":false,\\\"autoPopulate\\\":true,\\\"nullable\\\":true,\\\"mode\\\":\\\"optional\\\",\\\"field\\\":\\\"tenantId\\\",\\\"allowSuperAdminBypass\\\":false}}},\\\"journalId\\\":{\\\"type\\\":\\\"foreignKey\\\",\\\"required\\\":false,\\\"related\\\":\\\"Journal\\\",\\\"description\\\":\\\"The journal this entry belongs to.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The journal this entry belongs to.\\\"}},\\\"accountId\\\":{\\\"type\\\":\\\"foreignKey\\\",\\\"required\\\":false,\\\"related\\\":\\\"Account\\\",\\\"description\\\":\\\"The account this entry changes.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The account this entry changes.\\\"}},\\\"counterpartyKind\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"Generic counterparty type.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"Generic counterparty type.\\\",\\\"nullable\\\":true}},\\\"counterpartyId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"Generic counterparty identifier.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"Generic counterparty identifier.\\\",\\\"nullable\\\":true}},\\\"dueDate\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false,\\\"description\\\":\\\"When this open receivable or payable is due.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"When this open receivable or payable is due.\\\"}},\\\"settlesSourceRef\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false},\\\"debit\\\":{\\\"type\\\":\\\"decimal\\\",\\\"required\\\":false,\\\"default\\\":0,\\\"description\\\":\\\"The amount debited. Zero on a credit entry.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The amount debited. Zero on a credit entry.\\\"}},\\\"credit\\\":{\\\"type\\\":\\\"decimal\\\",\\\"required\\\":false,\\\"default\\\":0,\\\"description\\\":\\\"The amount credited. Zero on a debit entry.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The amount credited. Zero on a debit entry.\\\"}},\\\"currency\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"USD\\\",\\\"description\\\":\\\"The currency of the amounts.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The currency of the amounts.\\\"}},\\\"exchangeRate\\\":{\\\"type\\\":\\\"decimal\\\",\\\"required\\\":false,\\\"default\\\":1},\\\"memo\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"\\\",\\\"description\\\":\\\"A note on this entry.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"A note on this entry.\\\"}},\\\"metadata\\\":{\\\"type\\\":\\\"json\\\",\\\"required\\\":false,\\\"default\\\":{}}},\\\"methods\\\":{\\\"save\\\":{\\\"name\\\":\\\"save\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"options\\\",\\\"type\\\":\\\"any\\\",\\\"optional\\\":true,\\\"typeUnresolved\\\":true}],\\\"returnType\\\":\\\"Promise<this>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"delete\\\":{\\\"name\\\":\\\"delete\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"options\\\",\\\"type\\\":\\\"any\\\",\\\"optional\\\":true,\\\"typeUnresolved\\\":true}],\\\"returnType\\\":\\\"Promise<void>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"isDebit\\\":{\\\"name\\\":\\\"isDebit\\\",\\\"async\\\":false,\\\"parameters\\\":[],\\\"returnType\\\":\\\"boolean\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"isCredit\\\":{\\\"name\\\":\\\"isCredit\\\",\\\"async\\\":false,\\\"parameters\\\":[],\\\"returnType\\\":\\\"boolean\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getAmount\\\":{\\\"name\\\":\\\"getAmount\\\",\\\"async\\\":false,\\\"parameters\\\":[],\\\"returnType\\\":\\\"number\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getBaseAmount\\\":{\\\"name\\\":\\\"getBaseAmount\\\",\\\"async\\\":false,\\\"parameters\\\":[],\\\"returnType\\\":\\\"number\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getJournal\\\":{\\\"name\\\":\\\"getJournal\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"any\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getAccount\\\":{\\\"name\\\":\\\"getAccount\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"any\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getDescription\\\":{\\\"name\\\":\\\"getDescription\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<string>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\"]},\\\"cli\\\":{\\\"skipApiCheck\\\":true},\\\"tenantScoped\\\":{\\\"mode\\\":\\\"optional\\\"},\\\"conflictColumns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"]},\\\"extends\\\":\\\"SmrtObject\\\",\\\"exportName\\\":\\\"JournalEntry\\\",\\\"collectionExportName\\\":\\\"JournalEntryCollection\\\",\\\"schema\\\":{\\\"tableName\\\":\\\"journal_entries\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"journal_entries\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"journal_id\\\\\\\" UUID,\\\\n \\\\\\\"account_id\\\\\\\" UUID,\\\\n \\\\\\\"counterparty_kind\\\\\\\" TEXT,\\\\n \\\\\\\"counterparty_id\\\\\\\" TEXT,\\\\n \\\\\\\"due_date\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"settles_source_ref\\\\\\\" TEXT,\\\\n \\\\\\\"debit\\\\\\\" REAL DEFAULT 0,\\\\n \\\\\\\"credit\\\\\\\" REAL DEFAULT 0,\\\\n \\\\\\\"currency\\\\\\\" TEXT DEFAULT 'USD',\\\\n \\\\\\\"exchange_rate\\\\\\\" REAL DEFAULT 1,\\\\n \\\\\\\"memo\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"metadata\\\\\\\" JSON DEFAULT '{}'\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"journal_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"journals\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"NO ACTION\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"account_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"ledger_accounts\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"NO ACTION\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"counterparty_kind\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"counterparty_id\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"due_date\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"settles_source_ref\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"debit\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":0},\\\"credit\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":0},\\\"currency\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"USD\\\"},\\\"exchange_rate\\\":{\\\"type\\\":\\\"REAL\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":1},\\\"memo\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"metadata\\\":{\\\"type\\\":\\\"JSON\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":{}}},\\\"indexes\\\":[{\\\"name\\\":\\\"journal_entries_slug_context_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"],\\\"unique\\\":true,\\\"nullsNotDistinct\\\":true},{\\\"name\\\":\\\"journal_entries_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"journal_entries_journal_id_idx\\\",\\\"columns\\\":[\\\"journal_id\\\"]},{\\\"name\\\":\\\"journal_entries_account_id_idx\\\",\\\"columns\\\":[\\\"account_id\\\"]}],\\\"version\\\":\\\"e96b76a2\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-ledgers\\\"},\\\"@happyvertical/smrt-ledgers:Ledger\\\":{\\\"name\\\":\\\"ledger\\\",\\\"className\\\":\\\"Ledger\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-ledgers:Ledger\\\",\\\"collection\\\":\\\"ledgers\\\",\\\"description\\\":\\\"A named accounting scope. Exact ledgers store one currency's minor units and reject fractional entries; legacy journals without a ledger retain the tolerant balance rule for backwards compatibility.\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/ledgers/src/models/Ledger.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-ledgers\\\",\\\"fields\\\":{\\\"tenantId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"sqlType\\\":\\\"UUID\\\",\\\"nullable\\\":true,\\\"__tenancy\\\":{\\\"isTenantIdField\\\":true,\\\"autoFilter\\\":true,\\\"required\\\":false,\\\"autoPopulate\\\":true,\\\"nullable\\\":true,\\\"mode\\\":\\\"optional\\\",\\\"field\\\":\\\"tenantId\\\",\\\"allowSuperAdminBypass\\\":false}}},\\\"name\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"The accounting scope name.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"The accounting scope name.\\\"}},\\\"currency\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"description\\\":\\\"ISO 4217 currency used by this ledger.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"ISO 4217 currency used by this ledger.\\\"}},\\\"balanceMode\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"tolerant\\\",\\\"description\\\":\\\"tolerant accepts decimal units; exact requires integer minor units.\\\",\\\"_meta\\\":{\\\"description\\\":\\\"tolerant accepts decimal units; exact requires integer minor units.\\\"},\\\"enum\\\":[\\\"tolerant\\\",\\\"exact-integer\\\"]}},\\\"methods\\\":{\\\"delete\\\":{\\\"name\\\":\\\"delete\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<void>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\"]},\\\"cli\\\":{\\\"skipApiCheck\\\":true},\\\"tenantScoped\\\":{\\\"mode\\\":\\\"optional\\\"},\\\"conflictColumns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"]},\\\"extends\\\":\\\"SmrtObject\\\",\\\"exportName\\\":\\\"Ledger\\\",\\\"collectionExportName\\\":\\\"LedgerCollection\\\",\\\"displayLabelField\\\":\\\"name\\\",\\\"schema\\\":{\\\"tableName\\\":\\\"ledgers\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"ledgers\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"name\\\\\\\" TEXT,\\\\n \\\\\\\"currency\\\\\\\" TEXT,\\\\n \\\\\\\"balance_mode\\\\\\\" TEXT DEFAULT 'tolerant'\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"name\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"currency\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"balance_mode\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"tolerant\\\"}},\\\"indexes\\\":[{\\\"name\\\":\\\"ledgers_slug_context_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"slug\\\",\\\"context\\\"],\\\"unique\\\":true,\\\"nullsNotDistinct\\\":true},{\\\"name\\\":\\\"ledgers_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]}],\\\"version\\\":\\\"be316e4f\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-ledgers\\\"}},\\\"moduleType\\\":\\\"smrt\\\",\\\"recipes\\\":[{\\\"id\\\":\\\"ledgers.bookkeeping\\\",\\\"className\\\":\\\"BookkeepingRecipe\\\",\\\"label\\\":\\\"Bookkeeping\\\",\\\"summary\\\":\\\"Keep your books: a chart of accounts and double-entry journals.\\\",\\\"synonyms\\\":[\\\"accounting\\\",\\\"ledger\\\",\\\"general ledger\\\",\\\"journals\\\",\\\"chart of accounts\\\"],\\\"models\\\":[\\\"@happyvertical/smrt-ledgers:Account\\\",\\\"@happyvertical/smrt-ledgers:Journal\\\",\\\"@happyvertical/smrt-ledgers:JournalEntry\\\"],\\\"nav\\\":[{\\\"label\\\":\\\"Accounts\\\",\\\"model\\\":\\\"@happyvertical/smrt-ledgers:Account\\\",\\\"icon\\\":\\\"bank\\\",\\\"description\\\":\\\"The accounts your books are kept in, like sales, rent and bank.\\\"},{\\\"label\\\":\\\"Journals\\\",\\\"model\\\":\\\"@happyvertical/smrt-ledgers:Journal\\\",\\\"icon\\\":\\\"book\\\",\\\"description\\\":\\\"The entries behind your accounts, so every dollar has a trail.\\\"}],\\\"requires\\\":[],\\\"section\\\":{\\\"id\\\":\\\"accounting\\\",\\\"label\\\":\\\"Accounting\\\",\\\"icon\\\":\\\"bank\\\",\\\"description\\\":\\\"Your books: accounts, journals and balances.\\\"},\\\"options\\\":{\\\"@happyvertical/smrt-ledgers:Account\\\":{\\\"fields\\\":{\\\"metadata\\\":{\\\"visibility\\\":\\\"hidden\\\"},\\\"parentId\\\":{\\\"visibility\\\":\\\"hidden\\\"}}},\\\"@happyvertical/smrt-ledgers:Journal\\\":{\\\"fields\\\":{\\\"sourceModule\\\":{\\\"visibility\\\":\\\"hidden\\\"},\\\"sourceRef\\\":{\\\"visibility\\\":\\\"hidden\\\"},\\\"idempotencyKey\\\":{\\\"visibility\\\":\\\"hidden\\\"},\\\"requestDigest\\\":{\\\"visibility\\\":\\\"hidden\\\"},\\\"voidedAt\\\":{\\\"visibility\\\":\\\"hidden\\\"},\\\"voidReason\\\":{\\\"visibility\\\":\\\"hidden\\\"},\\\"metadata\\\":{\\\"visibility\\\":\\\"hidden\\\"}}},\\\"@happyvertical/smrt-ledgers:JournalEntry\\\":{\\\"fields\\\":{\\\"exchangeRate\\\":{\\\"visibility\\\":\\\"hidden\\\"},\\\"settlesSourceRef\\\":{\\\"visibility\\\":\\\"hidden\\\"},\\\"metadata\\\":{\\\"visibility\\\":\\\"hidden\\\"}}}},\\\"help\\\":{\\\"markdown\\\":\\\"## Overview\\\\n\\\\nBookkeeping keeps your accounts. You list the accounts you use (your chart of\\\\naccounts) and record each transaction as a journal whose entries debit and\\\\ncredit those accounts.\\\\n\\\\n## Tasks\\\\n\\\\n### Set up your accounts\\\\n\\\\n1. Create a new account.\\\\n2. Give it a **{field:number}** and a **{field:name}**.\\\\n3. Choose its **{field:type}**: asset, liability, equity, revenue or expense.\\\\n\\\\n### Record a transaction\\\\n\\\\n1. Create a new journal and add a **{field:description}**.\\\\n2. Add entries: pick the account on each and enter a **{field:debit}** or a\\\\n **{field:credit}**. They must add up to the same total.\\\\n3. Set the journal's **{field:status}** to posted when it is final. A posted\\\\n journal is voided, not edited.\\\\n\\\",\\\"fieldRefs\\\":[\\\"credit\\\",\\\"debit\\\",\\\"description\\\",\\\"name\\\",\\\"number\\\",\\\"status\\\",\\\"type\\\"]},\\\"demo\\\":{\\\"mode\\\":\\\"server\\\",\\\"reasons\\\":[\\\"Needs a server because its package does not build for a browser: core migrations (node:os, node:crypto); and its package depends on @happyvertical/smrt-tenancy, which do not build for a browser (#3624, #3626).\\\"]}}],\\\"smrtDependencies\\\":[\\\"@happyvertical/smrt-core\\\",\\\"@happyvertical/smrt-prompts\\\",\\\"@happyvertical/smrt-tenancy\\\"],\\\"browser\\\":{\\\"status\\\":\\\"server-only\\\",\\\"issues\\\":[\\\"#3624\\\",\\\"#3626\\\"],\\\"reason\\\":\\\"core migrations (node:os, node:crypto)\\\",\\\"via\\\":[\\\"@happyvertical/smrt-tenancy\\\"]},\\\"stampsConstructors\\\":true}\"));\n","/**\n * Prompt registrations for the @happyvertical/smrt-ledgers package.\n *\n * Prompts are registered at module-load time via `definePrompt()` so that\n * tenant-aware overrides can be applied at call time via `resolvePrompt()`.\n *\n * Mirrors the pattern used by `@happyvertical/smrt-properties` (see\n * `prompts.ts`) and `@happyvertical/smrt-content` (see `content-prompts.ts`).\n */\n\nimport {\n definePrompt,\n type ResolvedPromptAI,\n} from '@happyvertical/smrt-prompts';\n\n// Journal summarization only uses non-PII journal fields\n// (number, date, description, status, balanced flag) plus aggregate totals\n// and entry count. Internal/foreign-key fields like tenantId, sourceRef,\n// individual entry account IDs, and the extensible `metadata` blob are\n// intentionally NOT passed to the AI provider — they may link to identifying\n// records (customer/vendor IDs via sourceRef) or contain tenant-private\n// configuration. If a downstream tenant needs richer context they can\n// override the template via PromptOverride.\n// Note: smrt-prompts substitutes `{token}` placeholders. The currency prefix\n// is folded into the `journalTotal` variable value (e.g. \"$100.00\") rather\n// than written as a literal `$` in the template — earlier revisions used\n// `\\${journalTotal}` (a template-literal escape that renders as the literal\n// `${journalTotal}` at runtime). That technically worked because the regex\n// still matched the inner `{journalTotal}` and produced `$100.00`, but it\n// confused reviewers; folding the prefix into the value avoids the trap.\nexport const smrtLedgersJournalSummarizePrompt = definePrompt({\n key: 'smrtLedgers.journal.summarize',\n template: `Summarize this accounting journal entry:\nNumber: {journalNumber}\nDate: {journalDate}\nDescription: {journalDescription}\nStatus: {journalStatus}\nTotal: {journalTotal}\nEntries: {entryCount}\nBalanced: {journalBalanced}`,\n editable: {\n template: true,\n profile: true,\n model: true,\n params: true,\n },\n});\n\nexport function promptMessageOptions(ai: ResolvedPromptAI) {\n return {\n ...(ai.params || {}),\n ...(ai.model ? { model: ai.model } : {}),\n ...(typeof ai.temperature === 'number'\n ? { temperature: ai.temperature }\n : {}),\n ...(typeof ai.maxTokens === 'number' ? { maxTokens: ai.maxTokens } : {}),\n };\n}\n","/**\n * AccountCollection - Collection manager for Account objects\n *\n * Provides querying and tree operations for chart of accounts.\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { queryGlobal, queryWithGlobals } from '@happyvertical/smrt-tenancy';\nimport { Account } from '../models/Account';\nimport type { AccountTree, AccountTreeNode, AccountType } from '../types';\n\nexport class AccountCollection extends SmrtCollection<Account> {\n static readonly _itemClass = Account;\n\n /**\n * Find account by number\n *\n * @param number - Account number\n * @returns Account or null\n */\n async findByNumber(number: string): Promise<Account | null> {\n const accounts = await this.list({\n where: { number },\n limit: 1,\n });\n return accounts[0] || null;\n }\n\n /**\n * Find accounts by type\n *\n * @param type - Account type\n * @returns Array of accounts\n */\n async findByType(type: AccountType): Promise<Account[]> {\n return await this.list({\n where: { type },\n orderBy: 'number ASC',\n });\n }\n\n /**\n * Find all active accounts\n *\n * @returns Array of active accounts\n */\n async findActive(): Promise<Account[]> {\n return await this.list({\n where: { active: true },\n orderBy: 'number ASC',\n });\n }\n\n /**\n * Find top-level accounts (no parent)\n *\n * @returns Array of top-level accounts\n */\n async findTopLevel(): Promise<Account[]> {\n return await this.list({\n where: { parentId: null },\n orderBy: 'number ASC',\n });\n }\n\n /**\n * Find direct children of an account\n *\n * @param parentId - Parent account ID\n * @returns Array of child accounts\n */\n async findChildren(parentId: string): Promise<Account[]> {\n return await this.list({\n where: { parentId },\n orderBy: 'number ASC',\n });\n }\n\n /**\n * Get the complete account tree\n *\n * @returns AccountTree structure\n */\n async getTree(): Promise<AccountTree> {\n const allAccounts = await this.list({\n orderBy: 'number ASC',\n });\n\n const accountMap = new Map<string, Account>();\n const childrenMap = new Map<string, Account[]>();\n\n // Build lookup maps\n for (const account of allAccounts) {\n if (account.id) {\n accountMap.set(account.id, account);\n }\n if (!childrenMap.has(account.parentId || '')) {\n childrenMap.set(account.parentId || '', []);\n }\n childrenMap.get(account.parentId || '')?.push(account);\n }\n\n // Build tree nodes recursively\n const buildNode = (account: Account): AccountTreeNode => {\n const children = (account.id ? childrenMap.get(account.id) : []) || [];\n return {\n account,\n children: children.map(buildNode),\n };\n };\n\n // Get root nodes (no parent)\n const roots = childrenMap.get('') || [];\n\n return {\n roots: roots.map(buildNode),\n };\n }\n\n /**\n * Get or create an account by number\n *\n * @param number - Account number\n * @param defaults - Default values if creating\n * @returns Account\n */\n async getOrCreateByNumber(\n number: string,\n defaults: Partial<{\n name: string;\n description: string;\n type: AccountType;\n parentId: string | null;\n }> = {},\n ): Promise<Account> {\n const existing = await this.findByNumber(number);\n if (existing) {\n return existing;\n }\n\n const account = await this.create({\n number,\n name: defaults.name || number,\n description: defaults.description || '',\n type: defaults.type || 'asset',\n parentId: defaults.parentId || null,\n });\n await account.save();\n return account;\n }\n\n /**\n * Find accounts grouped by type\n *\n * @returns Record of type to accounts array\n */\n async groupByType(): Promise<Record<AccountType, Account[]>> {\n const accounts = await this.findActive();\n const grouped: Record<AccountType, Account[]> = {\n asset: [],\n liability: [],\n equity: [],\n revenue: [],\n expense: [],\n };\n\n for (const account of accounts) {\n grouped[account.type].push(account);\n }\n\n return grouped;\n }\n\n /**\n * Get all descendants of an account recursively\n *\n * @param accountId - Account ID\n * @returns Array of all descendant accounts\n */\n async getDescendants(accountId: string): Promise<Account[]> {\n const descendants: Account[] = [];\n const queue: string[] = [accountId];\n\n while (queue.length > 0) {\n const currentId = queue.shift();\n if (!currentId) continue;\n\n const children = await this.findChildren(currentId);\n\n for (const child of children) {\n descendants.push(child);\n if (child.id) {\n queue.push(child.id);\n }\n }\n }\n\n return descendants;\n }\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Tenant Helper Methods\n // ─────────────────────────────────────────────────────────────────────────────\n\n /**\n * Find all accounts belonging to a specific tenant\n *\n * @param tenantId - Tenant ID\n * @returns Array of tenant's accounts\n */\n async findByTenant(tenantId: string): Promise<Account[]> {\n return this.list({ where: { tenantId } });\n }\n\n /**\n * Find all global accounts (no tenant association).\n *\n * Routes through the shared tenant-global helper so it does not throw under\n * an active tenant context (an explicit `tenant_id IS NULL` filter would be\n * flagged as an isolation violation). (#1600)\n *\n * @returns Array of global accounts\n */\n async findGlobal(): Promise<Account[]> {\n return queryGlobal<Account>(this);\n }\n\n /**\n * Find accounts for a tenant plus all global accounts.\n *\n * Fails closed if an active tenant context requests a different tenant's\n * rows; the admin/system path keeps the cross-tenant capability. (#1600)\n *\n * @param tenantId - Tenant ID\n * @returns Array of tenant's accounts and global accounts\n */\n async findWithGlobals(tenantId: string): Promise<Account[]> {\n return queryWithGlobals<Account>(this, tenantId, 'Account.findWithGlobals');\n }\n}\n","/**\n * JournalEntry model - Individual ledger line\n *\n * The atomic unit of double-entry accounting - a single debit or credit.\n * Each entry belongs to a Journal and references an Account.\n */\n\nimport { field, foreignKey, SmrtObject, smrt } from '@happyvertical/smrt-core';\nimport {\n getTenantId,\n isSuperAdminBypass,\n isTenancyEnabled,\n TenantScoped,\n tenantId,\n withTenantGlobalRead,\n} from '@happyvertical/smrt-tenancy';\nimport type { JournalEntryOptions } from '../types';\nimport { Account } from './Account';\n\n@TenantScoped({ mode: 'optional' })\n@smrt({\n api: { include: ['list', 'get'] }, // Created via Journal, not directly\n mcp: { include: ['list', 'get'] },\n cli: { skipApiCheck: true },\n})\nexport class JournalEntry extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-ledgers\";\n /**\n * Tenant ID for multi-tenancy support (nullable for global entries)\n */\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n /**\n * Parent journal ID (required)\n */\n @field({ description: 'The journal this entry belongs to.' })\n @foreignKey('Journal')\n journalId: string = '';\n\n /**\n * Account ID (required)\n */\n // Constructor reference, not the simple name `Account` (also declared by\n // smrt-messages, #3098).\n @field({ description: 'The account this entry changes.' })\n @foreignKey(Account)\n accountId: string = '';\n\n /** Opaque external party dimension, never a product-specific model. */\n @field({ description: 'Generic counterparty type.', nullable: true })\n counterpartyKind: string | null = null;\n\n @field({ description: 'Generic counterparty identifier.', nullable: true })\n counterpartyId: string | null = null;\n\n /** Due date for an AR/AP open item. */\n @field({ description: 'When this open receivable or payable is due.' })\n dueDate: Date | null = null;\n\n /** Source reference of the open item reduced by this settlement line. */\n settlesSourceRef: string | null = null;\n\n /**\n * Debit amount (left side)\n */\n @field({ description: 'The amount debited. Zero on a credit entry.' })\n debit: number = 0.0;\n\n /**\n * Credit amount (right side)\n */\n @field({ description: 'The amount credited. Zero on a debit entry.' })\n credit: number = 0.0;\n\n /**\n * Currency code (e.g., \"USD\", \"CAD\", \"EUR\")\n */\n @field({ description: 'The currency of the amounts.' })\n currency: string = 'USD';\n\n /**\n * Exchange rate to base currency\n */\n exchangeRate: number = 1.0;\n\n /**\n * Line memo/description\n */\n @field({ description: 'A note on this entry.' })\n memo: string = '';\n\n /**\n * Extensible metadata\n */\n metadata: Record<string, unknown> = {};\n\n constructor(options: JournalEntryOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.journalId !== undefined) this.journalId = options.journalId;\n if (options.accountId !== undefined) this.accountId = options.accountId;\n if (options.counterpartyKind !== undefined)\n this.counterpartyKind = options.counterpartyKind;\n if (options.counterpartyId !== undefined)\n this.counterpartyId = options.counterpartyId;\n if (options.dueDate !== undefined) this.dueDate = options.dueDate;\n if (options.settlesSourceRef !== undefined)\n this.settlesSourceRef = options.settlesSourceRef;\n if (options.debit !== undefined) this.debit = options.debit;\n if (options.credit !== undefined) this.credit = options.credit;\n if (options.currency !== undefined) this.currency = options.currency;\n if (options.exchangeRate !== undefined)\n this.exchangeRate = options.exchangeRate;\n if (options.memo !== undefined) this.memo = options.memo;\n if (options.metadata !== undefined) this.metadata = options.metadata;\n }\n\n override async save(\n options: Parameters<SmrtObject['save']>[0] = {},\n ): Promise<this> {\n return this.withTransaction(async () => {\n const journal = await this.getJournal();\n if (!journal)\n throw new Error('Journal entry requires an accessible parent journal');\n if (journal.ledgerId) {\n if (!journal.isDraft() || !journal.updated_at)\n throw new Error('Ledger entries are immutable after posting');\n await journal.claimRevision(journal.updated_at);\n }\n return super.save(options);\n });\n }\n\n /**\n * Validate entry before save\n */\n protected async validateBeforeSave(): Promise<void> {\n await super.validateBeforeSave();\n // A fresh accounting identity must never adopt another row by natural key.\n // Core enforces this with INSERT uniqueness, including concurrent callers.\n this.requireInsertOnSave({ preserveDerivedSlug: true });\n const journal = await this.getJournal();\n // Validation precedes tenancy's beforeSave auto-population. Privileged\n // bypasses do not auto-populate, so those callers must supply the owner.\n const owner =\n this.tenantId ??\n (isTenancyEnabled() && !isSuperAdminBypass()\n ? (getTenantId() ?? null)\n : null);\n if (!journal || journal.tenantId !== owner)\n throw new Error(\n 'Journal entry and parent must belong to the same tenant',\n );\n const account = await this.getAccount();\n if (\n !account ||\n account.ledgerId !== journal.ledgerId ||\n (journal.ledgerId && account.tenantId !== journal.tenantId)\n )\n throw new Error(\n 'Journal entry account must belong to its journal ledger',\n );\n if (journal.ledgerId && !journal.isDraft())\n throw new Error('Ledger entries are immutable after posting');\n if (this.id) {\n const stored = await this.db.get(this.tableName, { id: this.id });\n if (stored && stored.journal_id !== this.journalId)\n throw new Error('Journal entry cannot be moved to another journal');\n if (stored && stored.account_id !== this.accountId) {\n const oldAccount = await this.loadAccount(String(stored.account_id));\n if (!oldAccount || oldAccount.ledgerId !== journal.ledgerId)\n throw new Error(\n 'Stored entry account must belong to its journal ledger',\n );\n }\n }\n if (!Number.isFinite(this.debit) || !Number.isFinite(this.credit))\n throw new Error('Entry amounts must be finite');\n // Validate amounts are non-negative\n if (this.debit < 0) {\n throw new Error('Debit amount cannot be negative');\n }\n if (this.credit < 0) {\n throw new Error('Credit amount cannot be negative');\n }\n\n // Validate that entry has debit OR credit, not both\n if (this.debit > 0 && this.credit > 0) {\n throw new Error('Entry cannot have both debit and credit amounts');\n }\n\n // Validate that entry has at least one amount\n if (this.debit === 0 && this.credit === 0) {\n throw new Error('Entry must have either a debit or credit amount');\n }\n\n // Validate exchange rate is positive\n if (this.exchangeRate <= 0) {\n throw new Error('Exchange rate must be positive');\n }\n if (!!this.counterpartyKind !== !!this.counterpartyId)\n throw new Error('Counterparty kind and ID must be provided together');\n if (this.dueDate && (!this.counterpartyKind || !this.counterpartyId))\n throw new Error('Due date requires a counterparty');\n }\n\n async delete(\n options: Parameters<SmrtObject['delete']>[0] = {},\n ): Promise<void> {\n await this.withTransaction(async () => {\n const stored = this.id\n ? await this.db.get(this.tableName, { id: this.id })\n : null;\n if (stored) {\n const { JournalCollection } = await import('../collections/Journals');\n const journal = await (\n await JournalCollection.create({ db: this.db })\n ).get({ id: String(stored.journal_id) });\n if (!journal || journal.tenantId !== stored.tenant_id)\n throw new Error(\n 'Journal entry requires its accessible same-tenant parent',\n );\n if (journal.ledgerId) {\n if (!journal.isDraft() || !journal.updated_at)\n throw new Error('Ledger entries are immutable after posting');\n await journal.claimRevision(journal.updated_at);\n }\n }\n await super.delete(options);\n });\n }\n\n /**\n * Check if this is a debit entry\n */\n isDebit(): boolean {\n return this.debit > 0;\n }\n\n /**\n * Check if this is a credit entry\n */\n isCredit(): boolean {\n return this.credit > 0;\n }\n\n /**\n * Get the entry amount (positive value regardless of debit/credit)\n */\n getAmount(): number {\n return this.debit > 0 ? this.debit : this.credit;\n }\n\n /**\n * Get the amount in base currency\n */\n getBaseAmount(): number {\n return this.getAmount() * this.exchangeRate;\n }\n\n /**\n * Get the parent journal\n */\n async getJournal(): Promise<import('./Journal').Journal | null> {\n if (!this.journalId) return null;\n const { JournalCollection } = await import('../collections/Journals');\n const collection = await JournalCollection.create(this.options);\n return await collection.get({ id: this.journalId }, { cache: false });\n }\n\n /**\n * Get the account\n */\n async getAccount(): Promise<import('./Account').Account | null> {\n if (!this.accountId) return null;\n return this.loadAccount(this.accountId);\n }\n\n private async loadAccount(\n accountId: string,\n ): Promise<import('./Account').Account | null> {\n const { AccountCollection } = await import('../collections/Accounts');\n const collection = await AccountCollection.create(this.options);\n const account = await collection.get({ id: accountId }, { cache: false });\n if (account) return account;\n const tenant = getTenantId();\n if (!tenant) return null;\n // Legacy charts expose shared, unassigned accounts. The public read scope\n // retains actor authorization and never widens to another tenant's rows.\n return withTenantGlobalRead(tenant, async () => {\n const globals = await collection.list({\n where: { id: accountId, tenantId: null, ledgerId: null },\n limit: 1,\n });\n return globals[0] ?? null;\n });\n }\n\n /**\n * Get a formatted description of this entry\n */\n async getDescription(): Promise<string> {\n const account = await this.getAccount();\n const accountName = account?.name || 'Unknown Account';\n const type = this.isDebit() ? 'DR' : 'CR';\n const amount = this.getAmount().toFixed(2);\n\n return `${type} ${accountName}: $${amount}${this.memo ? ` - ${this.memo}` : ''}`;\n }\n}\n","/**\n * JournalEntryCollection - Collection manager for JournalEntry objects\n *\n * Provides querying and balance calculations for ledger entries.\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport {\n getTenantId,\n queryGlobal,\n queryWithGlobals,\n} from '@happyvertical/smrt-tenancy';\nimport { JournalEntry } from '../models/JournalEntry';\nimport { BALANCE_EPSILON, type TrialBalanceRow } from '../types';\n\n/** One posted ledger movement in its raw stored unit (ledgers are unit-agnostic). */\nexport interface PostedJournalMovement {\n /** Requested owner identity; consumers must retain it at their reporting boundary. */\n tenantId: string;\n entryId: string;\n journalId: string;\n accountId: string;\n journalDate: Date;\n journalNumber: string;\n sourceModule: string;\n sourceRef: string | null;\n currency: string;\n debit: number;\n credit: number;\n /** Credit minus debit, suitable for liability-account reconciliation. */\n creditMinusDebit: number;\n}\n\nexport interface PostedJournalMovementOptions {\n tenantId: string;\n accountIds: readonly string[];\n from: Date;\n to: Date;\n currency: string;\n /** Select credit-normal AP balances; default is debit-normal AR. */\n normalBalance?: 'debit' | 'credit';\n}\n\nexport interface CounterpartyBalance {\n counterpartyKind: string;\n counterpartyId: string;\n currency: string;\n /** Debit minus credit for asset AR accounts; callers choose the account set. */\n balance: number;\n}\n\nexport interface CounterpartyAgingRow extends CounterpartyBalance {\n sourceRef: string;\n dueDate: Date;\n current: number;\n days1To30: number;\n days31To60: number;\n days61To90: number;\n daysOver90: number;\n}\n\nconst MAX_MOVEMENT_ACCOUNTS = 1_000;\n\nfunction storedUnit(value: unknown, label: string): number {\n const number = typeof value === 'number' ? value : Number(value);\n if (!Number.isFinite(number) || Math.abs(number) > Number.MAX_SAFE_INTEGER)\n throw new RangeError(\n `Posted journal ${label} is outside the supported numeric range.`,\n );\n return number;\n}\n\nexport class JournalEntryCollection extends SmrtCollection<JournalEntry> {\n static readonly _itemClass = JournalEntry;\n\n /**\n * Find entries by journal\n *\n * @param journalId - Journal ID\n * @returns Array of entries\n */\n async findByJournal(journalId: string): Promise<JournalEntry[]> {\n return await this.list({\n where: { journalId },\n });\n }\n\n /**\n * Find entries by account\n *\n * @param accountId - Account ID\n * @returns Array of entries\n */\n async findByAccount(accountId: string): Promise<JournalEntry[]> {\n return await this.list({\n where: { accountId },\n });\n }\n\n /** Posted AR/AP net balances by opaque counterparty for selected accounts. */\n async getCounterpartyBalances(\n options: PostedJournalMovementOptions,\n ): Promise<CounterpartyBalance[]> {\n const movements = await this.listPostedMovements(options);\n const result = new Map<string, CounterpartyBalance>();\n for (const movement of movements) {\n const entry = await this.get({ id: movement.entryId });\n if (!entry?.counterpartyKind || !entry.counterpartyId) continue;\n const key = JSON.stringify([\n entry.counterpartyKind,\n entry.counterpartyId,\n movement.currency,\n ]);\n const row = result.get(key) ?? {\n counterpartyKind: entry.counterpartyKind,\n counterpartyId: entry.counterpartyId,\n currency: movement.currency,\n balance: 0,\n };\n row.balance = storedUnit(\n row.balance +\n (movement.debit - movement.credit) *\n (options.normalBalance === 'credit' ? -1 : 1),\n 'counterparty balance',\n );\n result.set(key, row);\n }\n return [...result.values()].filter((row) => row.balance !== 0);\n }\n\n /**\n * Open-item aging. An invoice/allocation line needs a dueDate and sourceRef;\n * a settlement line names that source in settlesSourceRef. This avoids\n * pretending that net counterparty movements are aging.\n */\n async getCounterpartyAging(\n options: PostedJournalMovementOptions,\n asOf: Date,\n ): Promise<CounterpartyAgingRow[]> {\n const movements = await this.listPostedMovements({ ...options, to: asOf });\n const rows = new Map<string, CounterpartyAgingRow>();\n const balances = new Map<string, number>();\n for (const movement of movements) {\n const entry = await this.get({ id: movement.entryId });\n const source = entry?.settlesSourceRef ?? movement.sourceRef;\n if (!entry?.counterpartyKind || !entry.counterpartyId || !source)\n continue;\n const key = JSON.stringify([\n entry.counterpartyKind,\n entry.counterpartyId,\n movement.currency,\n source,\n ]);\n balances.set(\n key,\n storedUnit(\n (balances.get(key) ?? 0) +\n (movement.debit - movement.credit) *\n (options.normalBalance === 'credit' ? -1 : 1),\n 'open item balance',\n ),\n );\n if (!entry.settlesSourceRef && entry.dueDate) {\n const prior = rows.get(key);\n if (prior && prior.dueDate.getTime() !== entry.dueDate.getTime())\n throw new Error('Open item source has conflicting due dates');\n rows.set(key, {\n counterpartyKind: entry.counterpartyKind,\n counterpartyId: entry.counterpartyId,\n currency: movement.currency,\n sourceRef: source,\n dueDate: entry.dueDate,\n balance: 0,\n current: 0,\n days1To30: 0,\n days31To60: 0,\n days61To90: 0,\n daysOver90: 0,\n });\n }\n }\n for (const [key, row] of rows) row.balance = balances.get(key) ?? 0;\n for (const row of rows.values()) {\n if (row.balance <= 0) continue;\n const days = Math.floor(\n (asOf.getTime() - row.dueDate.getTime()) / 86_400_000,\n );\n if (days <= 0) row.current = row.balance;\n else if (days <= 30) row.days1To30 = row.balance;\n else if (days <= 60) row.days31To60 = row.balance;\n else if (days <= 90) row.days61To90 = row.balance;\n else row.daysOver90 = row.balance;\n }\n return [...rows.values()].filter((row) => row.balance > 0);\n }\n\n /**\n * Get account balance\n *\n * For debit-normal accounts (Asset, Expense): balance = debits - credits\n * For credit-normal accounts (Liability, Equity, Revenue): balance = credits - debits\n *\n * @param accountId - Account ID\n * @param asOfDate - Optional date to calculate balance as of\n * @returns Account balance\n */\n async getAccountBalance(accountId: string, asOfDate?: Date): Promise<number> {\n // Get entries for this account from posted journals only\n const { JournalCollection } = await import('./Journals');\n const journalCollection = await JournalCollection.create(this.options);\n const { AccountCollection } = await import('./Accounts');\n const accountCollection = await AccountCollection.create(this.options);\n\n // Get the account to determine if it's debit or credit normal\n const account = await accountCollection.get({ id: accountId });\n if (!account) {\n throw new Error(`Account not found: ${accountId}`);\n }\n\n // Get all entries for this account\n const allEntries = await this.findByAccount(accountId);\n\n let totalDebits = 0;\n let totalCredits = 0;\n\n for (const entry of allEntries) {\n // Get the journal to check status and date\n const journal = await journalCollection.get({ id: entry.journalId });\n if (!journal) continue;\n\n // Only include posted journals\n if (!journal.isPosted()) continue;\n\n // Check date if specified\n if (asOfDate && journal.date > asOfDate) continue;\n\n totalDebits += entry.debit;\n totalCredits += entry.credit;\n }\n\n // Calculate balance based on account type\n if (account.isDebitNormal()) {\n // Asset, Expense: increases with debits\n return totalDebits - totalCredits;\n } else {\n // Liability, Equity, Revenue: increases with credits\n return totalCredits - totalDebits;\n }\n }\n\n /**\n * Get trial balance\n *\n * @param asOfDate - Optional date for trial balance\n * @returns Array of trial balance rows\n */\n async getTrialBalance(asOfDate?: Date): Promise<TrialBalanceRow[]> {\n const { AccountCollection } = await import('./Accounts');\n const accountCollection = await AccountCollection.create(this.options);\n\n const accounts = await accountCollection.findActive();\n const rows: TrialBalanceRow[] = [];\n\n for (const account of accounts) {\n if (!account.id) continue;\n\n const balance = await this.getAccountBalance(account.id, asOfDate);\n\n // Skip zero-balance accounts\n if (Math.abs(balance) < BALANCE_EPSILON) continue;\n\n rows.push({\n accountId: account.id,\n accountNumber: account.number,\n accountName: account.name,\n accountType: account.type,\n debitBalance: account.isDebitNormal() && balance > 0 ? balance : 0,\n creditBalance: account.isCreditNormal() && balance > 0 ? balance : 0,\n });\n }\n\n // Sort by account number\n rows.sort((a, b) => a.accountNumber.localeCompare(b.accountNumber));\n\n return rows;\n }\n\n /**\n * Get total debits and credits for a date range\n *\n * @param start - Start date\n * @param end - End date\n * @returns Object with totalDebits and totalCredits\n */\n async getTotalsForDateRange(\n start: Date,\n end: Date,\n ): Promise<{ totalDebits: number; totalCredits: number }> {\n const { JournalCollection } = await import('./Journals');\n const journalCollection = await JournalCollection.create(this.options);\n\n const journals = await journalCollection.findByDateRange(start, end);\n\n let totalDebits = 0;\n let totalCredits = 0;\n\n for (const journal of journals) {\n if (!journal.isPosted()) continue;\n\n const entries = await this.findByJournal(journal.id!);\n for (const entry of entries) {\n totalDebits += entry.debit;\n totalCredits += entry.credit;\n }\n }\n\n return { totalDebits, totalCredits };\n }\n\n /**\n * Get entries for multiple accounts\n *\n * @param accountIds - Array of account IDs\n * @returns Array of entries\n */\n async findByAccounts(accountIds: string[]): Promise<JournalEntry[]> {\n if (accountIds.length === 0) {\n return [];\n }\n\n // Use single query with IN clause to avoid N+1 problem\n return await this.list({\n where: { accountId: accountIds },\n });\n }\n\n /**\n * Read tenant-owned movements from posted journals only. Amounts deliberately\n * remain raw ledger units; commerce validates its minor-unit convention at\n * the reporting boundary.\n */\n async listPostedMovements(\n options: PostedJournalMovementOptions,\n ): Promise<PostedJournalMovement[]> {\n if (getTenantId() && getTenantId() !== options.tenantId)\n throw new Error('Posted movements tenant differs from active context');\n const accountIds = [...new Set(options.accountIds)];\n if (\n !options.tenantId?.trim() ||\n !options.currency?.trim() ||\n !(options.from instanceof Date) ||\n !(options.to instanceof Date) ||\n !Number.isFinite(options.from.getTime()) ||\n !Number.isFinite(options.to.getTime()) ||\n options.from > options.to\n )\n throw new Error(\n 'Posted movements require tenant, currency and ordered dates.',\n );\n if (accountIds.length === 0) return [];\n if (accountIds.length > MAX_MOVEMENT_ACCOUNTS)\n throw new RangeError(\n `Posted movements allow at most ${MAX_MOVEMENT_ACCOUNTS} accounts per query.`,\n );\n if (\n accountIds.some((id) => typeof id !== 'string' || !id || id.trim() !== id)\n )\n throw new Error('Posted movement account IDs must be nonempty.');\n const placeholders = accountIds.map(() => '?').join(', ');\n const result = await this.db.query(\n `SELECT e.id AS entry_id, e.journal_id, e.account_id, e.currency,\n e.debit, e.credit, j.date AS journal_date, j.number AS journal_number,\n j.source_module, j.source_ref\n FROM journal_entries e\n JOIN journals j ON j.id = e.journal_id AND j.tenant_id = e.tenant_id\n WHERE e.tenant_id = ? AND e.account_id IN (${placeholders})\n AND e.currency = ? AND j.status = 'posted'\n AND j.date >= ? AND j.date <= ?\n ORDER BY j.date ASC, j.id ASC, e.id ASC`,\n options.tenantId,\n ...accountIds,\n options.currency,\n options.from.toISOString(),\n options.to.toISOString(),\n );\n return result.rows.map((row) => {\n const debit = storedUnit(row.debit, 'debit');\n const credit = storedUnit(row.credit, 'credit');\n const movement = credit - debit;\n if (\n !Number.isFinite(movement) ||\n Math.abs(movement) > Number.MAX_SAFE_INTEGER\n )\n throw new RangeError(\n 'Posted journal movement is outside the supported numeric range.',\n );\n return {\n tenantId: options.tenantId,\n entryId: String(row.entry_id),\n journalId: String(row.journal_id),\n accountId: String(row.account_id),\n journalDate: new Date(String(row.journal_date)),\n journalNumber: String(row.journal_number),\n sourceModule: String(row.source_module),\n sourceRef: row.source_ref == null ? null : String(row.source_ref),\n currency: String(row.currency),\n debit,\n credit,\n creditMinusDebit: movement,\n };\n });\n }\n\n /**\n * Get the running balance for an account (list of entries with running total)\n *\n * @param accountId - Account ID\n * @returns Array of entries with running balance\n */\n async getAccountLedger(\n accountId: string,\n ): Promise<Array<{ entry: JournalEntry; runningBalance: number }>> {\n const { JournalCollection } = await import('./Journals');\n const { AccountCollection } = await import('./Accounts');\n const journalCollection = await JournalCollection.create(this.options);\n const accountCollection = await AccountCollection.create(this.options);\n\n const account = await accountCollection.get({ id: accountId });\n if (!account) {\n throw new Error(`Account not found: ${accountId}`);\n }\n\n const entries = await this.findByAccount(accountId);\n const ledger: Array<{ entry: JournalEntry; runningBalance: number }> = [];\n let runningBalance = 0;\n\n // Sort entries by journal date\n const entriesWithJournals = await Promise.all(\n entries.map(async (entry) => ({\n entry,\n journal: await journalCollection.get({ id: entry.journalId }),\n })),\n );\n\n entriesWithJournals.sort((a, b) => {\n if (!a.journal || !b.journal) return 0;\n return a.journal.date.getTime() - b.journal.date.getTime();\n });\n\n for (const { entry, journal } of entriesWithJournals) {\n if (!journal?.isPosted()) continue;\n\n if (account.isDebitNormal()) {\n runningBalance += entry.debit - entry.credit;\n } else {\n runningBalance += entry.credit - entry.debit;\n }\n\n ledger.push({ entry, runningBalance });\n }\n\n return ledger;\n }\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Tenant Helper Methods\n // ─────────────────────────────────────────────────────────────────────────────\n\n /**\n * Find all journal entries belonging to a specific tenant\n *\n * @param tenantId - Tenant ID\n * @returns Array of tenant's journal entries\n */\n async findByTenant(tenantId: string): Promise<JournalEntry[]> {\n return this.list({ where: { tenantId } });\n }\n\n /**\n * Find all global journal entries (no tenant association).\n *\n * Routes through the shared tenant-global helper so it does not throw under\n * an active tenant context. (#1600)\n *\n * @returns Array of global journal entries\n */\n async findGlobal(): Promise<JournalEntry[]> {\n return queryGlobal<JournalEntry>(this);\n }\n\n /**\n * Find journal entries for a tenant plus all global entries.\n *\n * Fails closed if an active tenant context requests a different tenant's\n * rows; the admin/system path keeps the cross-tenant capability. (#1600)\n *\n * @param tenantId - Tenant ID\n * @returns Array of tenant's entries and global entries\n */\n async findWithGlobals(tenantId: string): Promise<JournalEntry[]> {\n return queryWithGlobals<JournalEntry>(\n this,\n tenantId,\n 'JournalEntry.findWithGlobals',\n );\n }\n}\n","/**\n * Journal model - Financial event container\n *\n * Represents a single, discrete financial event.\n * Contains one or more JournalEntry records that must balance (debits = credits).\n */\n\nimport { field, foreignKey, SmrtObject, smrt } from '@happyvertical/smrt-core';\nimport { resolvePrompt } from '@happyvertical/smrt-prompts';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport {\n promptMessageOptions,\n smrtLedgersJournalSummarizePrompt,\n} from '../prompts';\nimport {\n BALANCE_EPSILON,\n type JournalEntryData,\n type JournalOptions,\n type JournalStatus,\n} from '../types';\nimport { Ledger } from './Ledger';\n\n@TenantScoped({ mode: 'optional' })\n@smrt({\n api: { include: ['list', 'get', 'create'] }, // No update/delete - immutable after posting\n mcp: { include: ['list', 'get', 'create'] },\n cli: { skipApiCheck: true },\n indexes: [\n {\n name: 'journals_ledger_idempotency_key',\n columns: ['tenantId', 'ledgerId', 'idempotencyKey'],\n unique: true,\n },\n ],\n})\nexport class Journal extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-ledgers\";\n /**\n * Tenant ID for multi-tenancy support (nullable for global journals)\n */\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n /**\n * Journal number (auto-generated sequence, e.g., \"JNL-0001\")\n */\n @field({ description: \"The journal's reference number.\" })\n number: string = '';\n\n /**\n * Transaction date\n */\n @field({ description: 'The date of the transaction.' })\n date: Date = new Date();\n\n /**\n * Description of the financial event\n */\n @field({ description: 'What the transaction was.' })\n description: string = '';\n\n /**\n * Source module that created this journal (e.g., \"smrt-commerce\", \"manual\")\n */\n sourceModule: string = '';\n\n /**\n * External reference (e.g., order ID, invoice number)\n */\n sourceRef: string | null = null;\n\n /** Optional durable accounting scope; null preserves legacy tolerant journals. */\n @field({\n description: 'The ledger policy that governs this journal.',\n nullable: true,\n })\n @foreignKey(Ledger)\n ledgerId: string | null = null;\n\n @field({ nullable: true })\n idempotencyKey: string | null = null;\n\n requestDigest: string | null = null;\n\n /**\n * Journal status: draft, posted, voided\n */\n @field({\n description: 'draft until final, then posted, or voided.',\n })\n status: JournalStatus = 'draft';\n\n /**\n * When the journal was posted (finalized)\n */\n @field({ description: 'When it was posted.' })\n postedAt: Date | null = null;\n\n /**\n * When the journal was voided\n */\n voidedAt: Date | null = null;\n\n /**\n * Reason for voiding (if voided)\n */\n voidReason: string | null = null;\n\n /**\n * Extensible metadata\n */\n metadata: Record<string, unknown> = {};\n\n constructor(options: JournalOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.number !== undefined) this.number = options.number;\n if (options.date !== undefined) this.date = options.date;\n if (options.description !== undefined)\n this.description = options.description;\n if (options.sourceModule !== undefined)\n this.sourceModule = options.sourceModule;\n if (options.sourceRef !== undefined) this.sourceRef = options.sourceRef;\n if (options.ledgerId !== undefined) this.ledgerId = options.ledgerId;\n if (options.idempotencyKey !== undefined)\n this.idempotencyKey = options.idempotencyKey;\n if (options.requestDigest !== undefined)\n this.requestDigest = options.requestDigest;\n if (options.status !== undefined) this.status = options.status;\n if (options.postedAt !== undefined) this.postedAt = options.postedAt;\n if (options.voidedAt !== undefined) this.voidedAt = options.voidedAt;\n if (options.voidReason !== undefined) this.voidReason = options.voidReason;\n if (options.metadata !== undefined) this.metadata = options.metadata;\n }\n\n /**\n * Check if journal is in draft status\n */\n isDraft(): boolean {\n return this.status === 'draft';\n }\n\n /**\n * Check if journal has been posted\n */\n isPosted(): boolean {\n return this.status === 'posted';\n }\n\n /**\n * Check if journal has been voided\n */\n isVoided(): boolean {\n return this.status === 'voided';\n }\n\n /**\n * Check if journal can be modified\n */\n isEditable(): boolean {\n return this.status === 'draft';\n }\n\n /**\n * Get all entries for this journal\n */\n async getEntries(): Promise<import('./JournalEntry').JournalEntry[]> {\n if (!this.id) return [];\n const { JournalEntryCollection } = await import(\n '../collections/JournalEntries'\n );\n const collection = await JournalEntryCollection.create(this.options);\n return await collection.findByJournal(this.id);\n }\n\n /**\n * Calculate total debits\n */\n async getTotalDebits(): Promise<number> {\n const entries = await this.getEntries();\n return entries.reduce((sum, entry) => sum + entry.debit, 0);\n }\n\n /**\n * Calculate total credits\n */\n async getTotalCredits(): Promise<number> {\n const entries = await this.getEntries();\n return entries.reduce((sum, entry) => sum + entry.credit, 0);\n }\n\n /**\n * Check if journal entries are balanced (debits = credits)\n */\n async isBalanced(): Promise<boolean> {\n const debits = await this.getTotalDebits();\n const credits = await this.getTotalCredits();\n const ledger = await this.getLedger();\n if (!ledger || ledger.balanceMode === 'tolerant')\n return Math.abs(debits - credits) < BALANCE_EPSILON;\n const entries = await this.getEntries();\n return (\n Number.isSafeInteger(debits) &&\n Number.isSafeInteger(credits) &&\n entries.every(\n (entry) =>\n Number.isSafeInteger(entry.debit) &&\n Number.isSafeInteger(entry.credit),\n ) &&\n debits === credits\n );\n }\n\n async getLedger(): Promise<import('./Ledger').Ledger | null> {\n if (!this.ledgerId) return null;\n const { LedgerCollection } = await import('../collections/Ledgers');\n return (await LedgerCollection.create(this.options)).get({\n id: this.ledgerId,\n });\n }\n\n /**\n * Add an entry to this journal (only if draft)\n */\n async addEntry(data: JournalEntryData): Promise<void> {\n if (!this.id) {\n throw new Error('Journal must be saved before adding entries');\n }\n if (!this.isEditable()) {\n throw new Error('Cannot add entries to a posted or voided journal');\n }\n\n const { JournalEntryCollection } = await import(\n '../collections/JournalEntries'\n );\n const collection = await JournalEntryCollection.create(this.options);\n const entry = await collection.create({\n journalId: this.id,\n tenantId: this.tenantId,\n accountId: data.accountId,\n counterpartyKind: data.counterpartyKind ?? null,\n counterpartyId: data.counterpartyId ?? null,\n dueDate: data.dueDate ?? null,\n settlesSourceRef: data.settlesSourceRef ?? null,\n debit: data.debit || 0,\n credit: data.credit || 0,\n currency: data.currency || 'USD',\n exchangeRate: data.exchangeRate || 1.0,\n memo: data.memo || '',\n });\n await entry.save();\n if (this.ledgerId) {\n const parent = await entry.getJournal();\n this.updated_at = parent?.updated_at ?? this.updated_at;\n }\n }\n\n /**\n * Post the journal (finalize and make immutable)\n */\n async post(): Promise<void> {\n if (!this.isDraft()) {\n throw new Error('Only draft journals can be posted');\n }\n\n await this.validatePosting();\n\n this.status = 'posted';\n this.postedAt = new Date();\n await this.save();\n }\n\n /**\n * Void the journal (mark as cancelled with reason)\n */\n async void(reason: string): Promise<void> {\n if (this.isVoided()) {\n throw new Error('Journal is already voided');\n }\n\n this.status = 'voided';\n this.voidedAt = new Date();\n this.voidReason = reason;\n await this.save();\n }\n\n private async validatePosting(): Promise<void> {\n const balanced = await this.isBalanced();\n if (!balanced) {\n const debits = await this.getTotalDebits();\n const credits = await this.getTotalCredits();\n throw new Error(\n `Journal is not balanced. Debits: ${debits}, Credits: ${credits}`,\n );\n }\n\n const entries = await this.getEntries();\n if (entries.length === 0) {\n throw new Error('Journal must have at least one entry');\n }\n const ledger = await this.getLedger();\n if (this.ledgerId && !ledger)\n throw new Error(`Ledger not found: ${this.ledgerId}`);\n if (ledger) {\n if (ledger.tenantId !== this.tenantId)\n throw new Error('Journal and ledger must belong to the same tenant');\n if (entries.some((entry) => entry.currency !== ledger.currency))\n throw new Error(\n `Journal entries must use ledger currency ${ledger.currency}`,\n );\n }\n const { AccountCollection } = await import('../collections/Accounts');\n const accounts = await AccountCollection.create(this.options);\n for (const entry of entries) {\n const account = await accounts.get({ id: entry.accountId });\n if (\n (this.ledgerId || account?.ledgerId) &&\n (!account ||\n !account.active ||\n account.tenantId !== this.tenantId ||\n entry.tenantId !== this.tenantId ||\n account.ledgerId !== this.ledgerId)\n )\n throw new Error(\n 'Journal entries must use active accounts owned by the journal ledger',\n );\n }\n }\n\n override async save(\n options: Parameters<SmrtObject['save']>[0] = {},\n ): Promise<this> {\n return this.withTransaction(async () => {\n if (this.isPersisted && this.updated_at) {\n await this.claimRevision(options.expectedUpdatedAt ?? this.updated_at);\n if (options.expectedUpdatedAt !== undefined)\n options = { ...options, expectedUpdatedAt: this.updated_at };\n }\n return super.save(options);\n });\n }\n\n protected async validateBeforeSave(): Promise<void> {\n await super.validateBeforeSave();\n // A fresh accounting identity must never adopt another row by natural key.\n // Core enforces this with INSERT uniqueness, including concurrent callers.\n this.requireInsertOnSave({ preserveDerivedSlug: true });\n if (this.id) {\n const stored = await this.db.get(this.tableName, { id: this.id });\n if (stored && stored.ledger_id !== this.ledgerId)\n throw new Error('Journal ledger scope is immutable after creation');\n if (stored?.ledger_id && stored.status !== 'draft')\n throw new Error(\n 'Ledger journals are immutable after posting; use a compensating journal',\n );\n }\n if (this.status === 'posted') {\n if (this.ledgerId) await this.validatePosting();\n else {\n for (const entry of await this.getEntries()) {\n if ((await entry.getAccount())?.ledgerId)\n throw new Error('Scoped accounts require their journal ledger');\n }\n }\n }\n }\n\n async delete(\n options: Parameters<SmrtObject['delete']>[0] = {},\n ): Promise<void> {\n await this.withTransaction(async () => {\n if (this.isPersisted && this.updated_at) {\n await this.claimRevision(options.expectedUpdatedAt ?? this.updated_at);\n if (options.expectedUpdatedAt !== undefined)\n options = { ...options, expectedUpdatedAt: this.updated_at };\n }\n const stored = this.id\n ? await this.db.get(this.tableName, { id: this.id })\n : null;\n if (stored?.ledger_id && stored.status !== 'draft')\n throw new Error('Ledger journals are immutable after posting');\n await super.delete(options);\n });\n }\n\n /**\n * AI-powered: Generate a summary of this journal.\n *\n * Uses the `smrtLedgers.journal.summarize` prompt registered via\n * `@happyvertical/smrt-prompts`, allowing tenant- or instance-level\n * overrides of the template, model, and parameters at runtime.\n *\n * Only non-PII journal fields (number, date, description, status, balanced\n * flag) plus aggregate totals and entry count are sent to the AI provider.\n * Internal foreign-key fields (tenantId, sourceRef, individual entry\n * account IDs) and the extensible `metadata` blob are intentionally\n * excluded.\n *\n * @returns Generated summary text\n */\n async summarize(): Promise<string> {\n const entries = await this.getEntries();\n const debits = await this.getTotalDebits();\n const balanced = await this.isBalanced();\n\n // Resolve `db` from either the canonical `db` option or its `persistence`\n // alias. SmrtClass maps `persistence → db` lazily during `initialize()`,\n // so on a freshly-constructed Journal that has not yet been initialized,\n // `this.options.db` may be undefined while `this.options.persistence` is\n // set. Falling back here ensures stored app- and tenant-level prompt\n // overrides in `_smrt_prompt_overrides` are honored on the first call —\n // before `getAiClient()` triggers full initialization further below.\n const db = this.options.db ?? this.options.persistence;\n\n const resolvedPrompt = await resolvePrompt(\n smrtLedgersJournalSummarizePrompt.key,\n {\n db,\n tenantId: this.tenantId,\n variables: {\n journalNumber: this.number || '',\n journalDate: this.date.toISOString().split('T')[0],\n journalDescription: this.description || '',\n journalStatus: this.status || '',\n // Currency prefix folded into the value rather than the template\n // — see the `smrtLedgersJournalSummarizePrompt` comment block.\n journalTotal: `$${debits.toFixed(2)}`,\n entryCount: String(entries.length),\n journalBalanced: balanced ? 'Yes' : 'No',\n },\n },\n );\n\n const ai = await this.getAiClient();\n const response = await ai.message(\n resolvedPrompt.text,\n promptMessageOptions(resolvedPrompt.ai),\n );\n\n return response.trim();\n }\n}\n","/**\n * JournalCollection - Collection manager for Journal objects\n *\n * Provides querying and operations for financial journals.\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { queryGlobal, queryWithGlobals } from '@happyvertical/smrt-tenancy';\nimport { Journal } from '../models/Journal';\nimport {\n BALANCE_EPSILON,\n type CreateJournalData,\n type JournalStatus,\n} from '../types';\n\nexport class JournalCollection extends SmrtCollection<Journal> {\n static readonly _itemClass = Journal;\n\n /**\n * Generate next journal number\n *\n * Uses timestamp and random component to avoid collisions\n * in concurrent environments without relying on shared state.\n */\n private generateJournalNumber(): string {\n const timestamp = Date.now().toString(36);\n const randomPart = Math.random().toString(36).slice(2, 6);\n return `JNL-${timestamp}-${randomPart}`;\n }\n\n /**\n * Find journal by number\n *\n * @param number - Journal number\n * @returns Journal or null\n */\n async findByNumber(number: string): Promise<Journal | null> {\n const journals = await this.list({\n where: { number },\n limit: 1,\n });\n return journals[0] || null;\n }\n\n /**\n * Find journals by date range\n *\n * @param start - Start date\n * @param end - End date\n * @returns Array of journals\n */\n async findByDateRange(start: Date, end: Date): Promise<Journal[]> {\n return await this.list({\n where: {\n 'date >=': start.toISOString(),\n 'date <=': end.toISOString(),\n },\n orderBy: 'date ASC',\n });\n }\n\n /**\n * Find journals by source module\n *\n * @param sourceModule - Source module name\n * @returns Array of journals\n */\n async findBySource(sourceModule: string): Promise<Journal[]> {\n return await this.list({\n where: { sourceModule },\n orderBy: 'date DESC',\n });\n }\n\n /**\n * Find journals by status\n *\n * @param status - Journal status\n * @returns Array of journals\n */\n async findByStatus(status: JournalStatus): Promise<Journal[]> {\n return await this.list({\n where: { status },\n orderBy: 'date DESC',\n });\n }\n\n /**\n * Find draft journals\n *\n * @returns Array of draft journals\n */\n async findDrafts(): Promise<Journal[]> {\n return await this.findByStatus('draft');\n }\n\n /**\n * Find posted journals\n *\n * @returns Array of posted journals\n */\n async findPosted(): Promise<Journal[]> {\n return await this.findByStatus('posted');\n }\n\n /**\n * Create a complete journal with entries\n *\n * @param data - Journal data with entries\n * @returns Created journal\n */\n async createWithEntries(data: CreateJournalData): Promise<Journal> {\n // Validate entries balance\n let totalDebits = 0;\n let totalCredits = 0;\n\n for (const entry of data.entries) {\n totalDebits += entry.debit || 0;\n totalCredits += entry.credit || 0;\n }\n\n if (Math.abs(totalDebits - totalCredits) >= BALANCE_EPSILON) {\n throw new Error(\n `Entries are not balanced. Debits: ${totalDebits}, Credits: ${totalCredits}`,\n );\n }\n\n if (data.entries.length === 0) {\n throw new Error('Journal must have at least one entry');\n }\n\n // Create journal\n const journalNumber = await this.generateJournalNumber();\n const journal = await this.create({\n tenantId: data.tenantId ?? null,\n number: journalNumber,\n date: data.date || new Date(),\n description: data.description,\n sourceModule: data.sourceModule || 'manual',\n sourceRef: data.sourceRef || null,\n ledgerId: data.ledgerId ?? null,\n idempotencyKey: data.idempotencyKey ?? null,\n requestDigest: data.requestDigest ?? null,\n metadata: data.metadata || {},\n });\n await journal.save();\n\n // Create entries\n for (const entryData of data.entries) {\n await journal.addEntry(entryData);\n }\n\n return journal;\n }\n\n /**\n * Post a journal by ID\n *\n * @param journalId - Journal ID\n * @returns Posted journal\n */\n async post(journalId: string): Promise<Journal> {\n const journal = await this.get({ id: journalId });\n if (!journal) {\n throw new Error(`Journal not found: ${journalId}`);\n }\n await journal.post();\n return journal;\n }\n\n /**\n * Void a journal by ID\n *\n * @param journalId - Journal ID\n * @param reason - Reason for voiding\n * @returns Voided journal\n */\n async void(journalId: string, reason: string): Promise<Journal> {\n const journal = await this.get({ id: journalId });\n if (!journal) {\n throw new Error(`Journal not found: ${journalId}`);\n }\n await journal.void(reason);\n return journal;\n }\n\n /**\n * Find journals by source reference\n *\n * @param sourceRef - External reference\n * @returns Array of journals\n */\n async findBySourceRef(sourceRef: string): Promise<Journal[]> {\n return await this.list({\n where: { sourceRef },\n orderBy: 'date DESC',\n });\n }\n\n /**\n * Get journals for a specific month\n *\n * @param year - Year\n * @param month - Month (1-12)\n * @returns Array of journals\n */\n async findByMonth(year: number, month: number): Promise<Journal[]> {\n const start = new Date(year, month - 1, 1);\n const end = new Date(year, month, 0, 23, 59, 59, 999);\n return await this.findByDateRange(start, end);\n }\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Tenant Helper Methods\n // ─────────────────────────────────────────────────────────────────────────────\n\n /**\n * Find all journals belonging to a specific tenant\n *\n * @param tenantId - Tenant ID\n * @returns Array of tenant's journals\n */\n async findByTenant(tenantId: string): Promise<Journal[]> {\n return this.list({ where: { tenantId } });\n }\n\n /**\n * Find all global journals (no tenant association).\n *\n * Routes through the shared tenant-global helper so it does not throw under\n * an active tenant context. (#1600)\n *\n * @returns Array of global journals\n */\n async findGlobal(): Promise<Journal[]> {\n return queryGlobal<Journal>(this);\n }\n\n /**\n * Find journals for a tenant plus all global journals.\n *\n * Fails closed if an active tenant context requests a different tenant's\n * rows; the admin/system path keeps the cross-tenant capability. (#1600)\n *\n * @param tenantId - Tenant ID\n * @returns Array of tenant's journals and global journals\n */\n async findWithGlobals(tenantId: string): Promise<Journal[]> {\n return queryWithGlobals<Journal>(this, tenantId, 'Journal.findWithGlobals');\n }\n}\n","import { SmrtCollection } from '@happyvertical/smrt-core';\nimport { Ledger } from '../models/Ledger';\n\nexport class LedgerCollection extends SmrtCollection<Ledger> {\n static readonly _itemClass = Ledger;\n}\n","/**\n * One-time move of ledger accounts out of the shared `accounts` table (#3098).\n *\n * Until 0.51.24 the ledger `Account` derived the table name `accounts`, which\n * smrt-messages' unrelated `Account` also derives. A database may therefore\n * hold ledger accounts in `accounts` alone (ledgers only), or mixed with\n * messaging accounts in one union table (both packages, after `db:migrate`).\n * The ledger model now owns `ledger_accounts`; this migration moves the\n * existing ledger rows there, detaches the foreign keys that pointed ledger\n * references at `accounts`, and leaves messaging rows where they are.\n *\n * Operator sequence (maintenance window, PostgreSQL):\n * 1. `smrt db:migrate` — creates `ledger_accounts` from the manifest. It\n * reports, and does not apply, the retargeted `journal_entries.account_id`\n * foreign key while the old one still points at `accounts`.\n * 2. `smrt db:migrate-ledger-accounts` — this module.\n * 3. `smrt db:migrate` — adds the foreign keys onto `ledger_accounts`.\n */\n\nimport { detectEngine, ObjectRegistry } from '@happyvertical/smrt-core';\nimport {\n BackfillTracker,\n type DatabaseInterface,\n} from '@happyvertical/smrt-core/migrations';\n\nexport const LEDGER_ACCOUNTS_TABLE = 'ledger_accounts';\nexport const LEGACY_ACCOUNTS_TABLE = 'accounts';\nexport const LEDGER_ACCOUNTS_TABLE_MOVE =\n '@happyvertical/smrt-ledgers:ledger-accounts-table:v1';\n\n/**\n * Columns that only the legacy ledger model put on `accounts`. Their presence\n * identifies a table that may hold ledger rows; this is a fact about the\n * pre-#3098 data being migrated, not a schema definition.\n */\nconst LEGACY_LEDGER_SIGNATURE = ['number', 'type'] as const;\n\n/** The STI discriminator smrt-messages writes on every messaging account. */\nconst STI_DISCRIMINATOR = '_meta_type';\n\n/** Messaging columns that a ledger row never populates. */\nconst MESSAGING_MARKERS = ['provider_type', 'channel_type'] as const;\n\nexport interface LedgerAccountsTableMoveOptions {\n backfillName?: string;\n packageName?: string;\n /** PostgreSQL `lock_timeout`, milliseconds (default 30000). */\n lockTimeout?: number;\n /** PostgreSQL `statement_timeout`, milliseconds (default 60000). */\n statementTimeout?: number;\n}\n\nexport interface LedgerAccountsTableMovePlan {\n /** Whether a legacy `accounts` table with ledger columns exists. */\n legacyTable: boolean;\n /** Ledger rows still in `accounts` that this migration would move. */\n pending: number;\n /** Messaging rows that stay in `accounts`. */\n messagingRows: number;\n}\n\nexport interface LedgerAccountsTableMoveResult {\n ran: boolean;\n moved: number;\n /** Rows (messaging accounts) left in `accounts`. */\n remainingLegacyRows: number;\n /** `table.column` foreign keys detached from `accounts`. */\n detachedForeignKeys: string[];\n}\n\nexport class LedgerAccountsTableMoveError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'LedgerAccountsTableMoveError';\n }\n}\n\ntype Queryable = Pick<DatabaseInterface, 'query'>;\n\ninterface LegacyShape {\n columns: Set<string>;\n hasDiscriminator: boolean;\n}\n\nfunction quote(identifier: string): string {\n return `\"${identifier.replace(/\"/g, '\"\"')}\"`;\n}\n\nfunction timeout(value: number | undefined, fallback: number): string {\n const milliseconds = value ?? fallback;\n if (!Number.isInteger(milliseconds) || milliseconds < 0) {\n throw new LedgerAccountsTableMoveError(\n 'Migration timeout must be a non-negative integer',\n );\n }\n return `${milliseconds}ms`;\n}\n\nfunction assertPostgres(db: DatabaseInterface): void {\n const withConfig = db as DatabaseInterface & {\n type?: string;\n config?: { type?: string; url?: string };\n };\n const engine = detectEngine(\n db.url || withConfig.config?.url || '',\n withConfig.type || withConfig.config?.type,\n );\n if (engine !== 'postgres') {\n throw new LedgerAccountsTableMoveError(\n 'The ledger accounts table move supports PostgreSQL only. For a SQLite database whose `accounts` table holds only ledger accounts, run `ALTER TABLE accounts RENAME TO ledger_accounts` before `db:migrate`; see the smrt-ledgers README.',\n );\n }\n}\n\nasync function readLegacyShape(\n db: DatabaseInterface,\n): Promise<LegacyShape | null> {\n const schema = await db.getTableSchema?.(LEGACY_ACCOUNTS_TABLE);\n if (!schema) return null;\n const columns = new Set(Object.keys(schema.columns));\n if (!LEGACY_LEDGER_SIGNATURE.every((column) => columns.has(column))) {\n return null;\n }\n return { columns, hasDiscriminator: columns.has(STI_DISCRIMINATOR) };\n}\n\n/** SQL predicate selecting the ledger rows of the legacy table. */\nfunction ledgerRowPredicate(shape: LegacyShape): string {\n return shape.hasDiscriminator\n ? `(${quote(STI_DISCRIMINATOR)} IS NULL OR ${quote(STI_DISCRIMINATOR)} = '')`\n : 'TRUE';\n}\n\nasync function count(db: Queryable, where: string): Promise<number> {\n const result = await db.query(\n `SELECT COUNT(*) AS n FROM ${quote(LEGACY_ACCOUNTS_TABLE)} WHERE ${where}`,\n );\n return Number((result.rows[0] as { n: number | string }).n);\n}\n\nasync function classify(\n db: Queryable,\n shape: LegacyShape,\n): Promise<{ pending: number; messagingRows: number }> {\n const ledger = ledgerRowPredicate(shape);\n const pending = await count(db, ledger);\n const messagingRows = shape.hasDiscriminator\n ? await count(db, `NOT ${ledger}`)\n : 0;\n\n // Refuse rows whose owner is not certain rather than guess. A messaging\n // row never carries a ledger account number; a ledger row never carries a\n // messaging provider or channel.\n if (shape.hasDiscriminator) {\n const ledgerLooking = await count(\n db,\n `NOT ${ledger} AND COALESCE(${quote('number')}, '') <> ''`,\n );\n const markers = MESSAGING_MARKERS.filter((column) =>\n shape.columns.has(column),\n );\n const messagingLooking =\n markers.length === 0\n ? 0\n : await count(\n db,\n `${ledger} AND (${markers\n .map((column) => `COALESCE(${quote(column)}, '') <> ''`)\n .join(' OR ')})`,\n );\n if (ledgerLooking > 0 || messagingLooking > 0) {\n throw new LedgerAccountsTableMoveError(\n `Refusing to move ledger accounts: ${ledgerLooking} messaging row(s) carry a ledger account number and ${messagingLooking} ledger row(s) carry a messaging provider or channel in \"${LEGACY_ACCOUNTS_TABLE}\". Resolve their ownership by hand, then rerun.`,\n );\n }\n }\n return { pending, messagingRows };\n}\n\n/**\n * Registered foreign keys by the table they reference: `table.column` keys\n * the manifests point at `ledger_accounts` (the references that pointed at\n * `accounts` before #3098) and at `accounts` (messaging's own references).\n */\nexport function registeredReferenceColumns(): RegisteredReferences {\n const ledger = new Set<string>();\n const accounts = new Set<string>();\n const schemas = ObjectRegistry.getAllSchemasAsDefinitions();\n for (const [tableName, schema] of Object.entries(schemas)) {\n for (const [columnName, column] of Object.entries(schema.columns ?? {})) {\n const target = (column as { foreignKey?: { table?: string } }).foreignKey\n ?.table;\n if (target === LEDGER_ACCOUNTS_TABLE) {\n ledger.add(`${tableName}.${columnName}`);\n } else if (target === LEGACY_ACCOUNTS_TABLE) {\n accounts.add(`${tableName}.${columnName}`);\n }\n }\n }\n return { ledger, accounts };\n}\n\n/** Registered `table.column` references, by the table they point at. */\nexport interface RegisteredReferences {\n ledger: Set<string>;\n accounts: Set<string>;\n}\n\n/** One foreign key into the legacy table (`column` is its first column). */\nexport interface LegacyForeignKey {\n constraint: string;\n table: string;\n column: string;\n arity: number;\n}\n\n/** What the move does with each foreign key into the legacy table. */\nexport interface ForeignKeyDisposition {\n /** Composite keys: never a registered single-column reference. */\n composite: LegacyForeignKey[];\n /** Single-column keys no registered model declares. */\n undeclared: LegacyForeignKey[];\n /** Ledger references: detached, re-added against ledger_accounts. */\n detach: LegacyForeignKey[];\n /** Kept (messaging's and the table's own parent link): must not reference a moving row. */\n keep: LegacyForeignKey[];\n}\n\n/**\n * Sort every foreign key into the legacy table before anything is written.\n * A constraint no registered model declares would keep pointing at accounts\n * after the move (blocking later writes), and a CASCADE or SET NULL action on\n * it would delete or clear rows instead of refusing, so the move refuses\n * `composite` and `undeclared` outright (#3098).\n */\nexport function classifyForeignKeys(\n inbound: readonly LegacyForeignKey[],\n references: RegisteredReferences,\n): ForeignKeyDisposition {\n const disposition: ForeignKeyDisposition = {\n composite: [],\n undeclared: [],\n detach: [],\n keep: [],\n };\n for (const fk of inbound) {\n const key = `${fk.table}.${fk.column}`;\n if (fk.arity > 1) disposition.composite.push(fk);\n else if (references.ledger.has(key)) disposition.detach.push(fk);\n else if (fk.table === LEGACY_ACCOUNTS_TABLE || references.accounts.has(key))\n disposition.keep.push(fk);\n else disposition.undeclared.push(fk);\n }\n return disposition;\n}\n\n/** The refusal for foreign keys the move cannot account for, if any. */\nexport function foreignKeyRefusal(\n disposition: ForeignKeyDisposition,\n): string | undefined {\n if (disposition.composite.length > 0) {\n return `Composite foreign key(s) ${disposition.composite.map((fk) => `${fk.constraint} on ${fk.table} (${fk.arity} columns)`).join(', ')} reference \"${LEGACY_ACCOUNTS_TABLE}\"; no model can declare one, so the move cannot carry it. Nothing was moved. Drop it, or replace it with a single-column reference, then rerun.`;\n }\n if (disposition.undeclared.length > 0) {\n return `Foreign key(s) ${disposition.undeclared.map((fk) => `${fk.table}.${fk.column}`).join(', ')} reference \"${LEGACY_ACCOUNTS_TABLE}\" but no registered model declares them; nothing was moved. Run the move from the application whose models declare them, or retarget each to \"${LEDGER_ACCOUNTS_TABLE}\" (or drop it) by hand, then rerun.`;\n }\n return undefined;\n}\n\n/**\n * The SELECT list copying legacy columns into ledger_accounts: values as they\n * are, converting through text only a column whose legacy type differs from\n * the manifest's (e.g. TEXT ids where ledger_accounts declares UUID).\n */\nexport function copySelectList(\n columns: readonly string[],\n targetTypes: Readonly<Record<string, string | undefined>>,\n legacyTypes: Readonly<Record<string, string | undefined>>,\n): string {\n return columns\n .map((column) => {\n const to = targetTypes[column];\n return sameType(legacyTypes[column], to)\n ? quote(column)\n : `CAST(CAST(${quote(column)} AS TEXT) AS ${targetType(to)})`;\n })\n .join(', ');\n}\n\n/**\n * Every foreign key into the legacy table, composite ones included (`arity`\n * > 1): the move must account for all of them before it writes (#3098).\n */\nasync function legacyForeignKeys(db: Queryable): Promise<LegacyForeignKey[]> {\n const result = await db.query(\n `SELECT con.conname AS constraint_name,\n rel.relname AS table_name,\n att.attname AS column_name,\n array_length(con.conkey, 1) AS arity\n FROM pg_constraint con\n JOIN pg_class rel ON rel.oid = con.conrelid\n JOIN pg_attribute att\n ON att.attrelid = con.conrelid AND att.attnum = con.conkey[1]\n WHERE con.contype = 'f'\n AND con.confrelid = to_regclass(?)\n ORDER BY rel.relname, con.conname`,\n quote(LEGACY_ACCOUNTS_TABLE),\n );\n return (\n result.rows as Array<{\n constraint_name: string;\n table_name: string;\n column_name: string;\n arity: number | string;\n }>\n ).map((row) => ({\n constraint: row.constraint_name,\n table: row.table_name,\n column: row.column_name,\n arity: Number(row.arity),\n }));\n}\n\n/**\n * Inspect the legacy table without changing anything. Read-only portable SQL,\n * so it also reports what a SQLite database would need moved.\n */\nexport async function planLedgerAccountsTableMove(\n db: DatabaseInterface,\n): Promise<LedgerAccountsTableMovePlan> {\n const shape = await readLegacyShape(db);\n if (!shape) return { legacyTable: false, pending: 0, messagingRows: 0 };\n return { legacyTable: true, ...(await classify(db, shape)) };\n}\n\n/**\n * Move ledger accounts from `accounts` into `ledger_accounts` in one\n * transaction under an exclusive lock. Operator-invoked and idempotent: a\n * rerun, or a database that never had ledger rows in `accounts`, is a no-op.\n */\nexport async function migrateLedgerAccountsTable(\n db: DatabaseInterface,\n options: LedgerAccountsTableMoveOptions = {},\n): Promise<LedgerAccountsTableMoveResult> {\n assertPostgres(db);\n if (!db.transaction) {\n throw new LedgerAccountsTableMoveError(\n 'The ledger accounts table move requires a transaction-capable PostgreSQL adapter',\n );\n }\n const noop = (remainingLegacyRows = 0): LedgerAccountsTableMoveResult => ({\n ran: false,\n moved: 0,\n remainingLegacyRows,\n detachedForeignKeys: [],\n });\n\n const shape = await readLegacyShape(db);\n if (!shape) return noop();\n const target = await db.getTableSchema?.(LEDGER_ACCOUNTS_TABLE);\n if (!target) {\n throw new LedgerAccountsTableMoveError(\n `\"${LEDGER_ACCOUNTS_TABLE}\" does not exist; run db:migrate before moving ledger accounts`,\n );\n }\n const legacy = await db.getTableSchema?.(LEGACY_ACCOUNTS_TABLE);\n const copyColumns = Object.keys(target.columns).filter((column) =>\n shape.columns.has(column),\n );\n const references = registeredReferenceColumns();\n\n const tracker = new BackfillTracker({ db });\n await tracker.initialize();\n const backfillName = options.backfillName ?? LEDGER_ACCOUNTS_TABLE_MOVE;\n\n return db.transaction(async (tx) => {\n BackfillTracker.inheritInitialization(tx, db);\n const transactionTracker = new BackfillTracker({ db: tx });\n await tx.query(\n `SET LOCAL lock_timeout = '${timeout(options.lockTimeout, 30_000)}'`,\n );\n await tx.query(\n `SET LOCAL statement_timeout = '${timeout(options.statementTimeout, 60_000)}'`,\n );\n await tx.query(\n `LOCK TABLE ${quote(LEGACY_ACCOUNTS_TABLE)}, ${quote(LEDGER_ACCOUNTS_TABLE)} IN ACCESS EXCLUSIVE MODE`,\n );\n\n const { pending, messagingRows } = await classify(tx, shape);\n if (await transactionTracker.isApplied(backfillName)) {\n if (pending > 0) {\n throw new LedgerAccountsTableMoveError(\n `The ledger accounts table move is recorded as applied but \"${LEGACY_ACCOUNTS_TABLE}\" still holds ${pending} ledger row(s); refusing inconsistent state`,\n );\n }\n return noop(messagingRows);\n }\n\n const ledger = ledgerRowPredicate(shape);\n // Compare through text: a legacy table may still carry TEXT ids where\n // ledger_accounts declares UUID (the copy below converts the same way).\n const clash = await tx.query(\n `SELECT COUNT(*) AS n FROM ${quote(LEGACY_ACCOUNTS_TABLE)} legacy\n WHERE ${ledger}\n AND EXISTS (SELECT 1 FROM ${quote(LEDGER_ACCOUNTS_TABLE)} moved\n WHERE CAST(moved.id AS TEXT) = CAST(legacy.id AS TEXT))`,\n );\n if (Number((clash.rows[0] as { n: number | string }).n) > 0) {\n throw new LedgerAccountsTableMoveError(\n `\"${LEDGER_ACCOUNTS_TABLE}\" already holds ids of ledger rows still in \"${LEGACY_ACCOUNTS_TABLE}\"; refusing to overwrite`,\n );\n }\n\n // Account for every foreign key into accounts before writing anything:\n // refuse what the move cannot carry, and a kept constraint may not\n // reference a row that moves.\n const disposition = classifyForeignKeys(\n await legacyForeignKeys(tx),\n references,\n );\n const refusal = foreignKeyRefusal(disposition);\n if (refusal) throw new LedgerAccountsTableMoveError(refusal);\n for (const fk of disposition.keep) {\n const survivor =\n fk.table === LEGACY_ACCOUNTS_TABLE ? ` AND NOT ${ledger}` : '';\n const pointing = await tx.query(\n `SELECT COUNT(*) AS n FROM ${quote(fk.table)}\n WHERE ${quote(fk.column)} IN\n (SELECT id FROM ${quote(LEGACY_ACCOUNTS_TABLE)} WHERE ${ledger})${survivor}`,\n );\n if (Number((pointing.rows[0] as { n: number | string }).n) > 0) {\n throw new LedgerAccountsTableMoveError(\n `${fk.table}.${fk.column} references ledger accounts in \"${LEGACY_ACCOUNTS_TABLE}\" but is not a ledger reference; nothing was moved. Resolve those rows by hand, then rerun.`,\n );\n }\n }\n\n const selectList = copySelectList(\n copyColumns,\n columnTypes(target),\n columnTypes(legacy),\n );\n await tx.query(\n `INSERT INTO ${quote(LEDGER_ACCOUNTS_TABLE)} (${copyColumns\n .map(quote)\n .join(', ')})\n SELECT ${selectList} FROM ${quote(LEGACY_ACCOUNTS_TABLE)} WHERE ${ledger}`,\n );\n\n // Detach the ledger references (journal entries, and anything else the\n // manifests now point at ledger_accounts) from the legacy table. The\n // next db:migrate adds them against ledger_accounts. References owned by\n // messaging (emails, messages, routes) keep pointing at accounts.\n const detached: string[] = [];\n for (const foreignKey of disposition.detach) {\n await tx.query(\n `ALTER TABLE ${quote(foreignKey.table)} DROP CONSTRAINT ${quote(foreignKey.constraint)}`,\n );\n detached.push(`${foreignKey.table}.${foreignKey.column}`);\n }\n\n // Every remaining constraint was checked above; a violation here is a\n // concurrent change the lock did not cover and rolls the move back.\n await tx.query(\n `DELETE FROM ${quote(LEGACY_ACCOUNTS_TABLE)} WHERE ${ledger}`,\n );\n\n await transactionTracker.recordApplied(backfillName, {\n description:\n 'Moved ledger accounts from the shared accounts table to ledger_accounts (#3098).',\n packageName: options.packageName ?? '@happyvertical/smrt-ledgers',\n });\n return {\n ran: true,\n moved: pending,\n remainingLegacyRows: messagingRows,\n detachedForeignKeys: detached,\n };\n });\n}\n\nconst SQL_TYPE = /^[A-Za-z][A-Za-z0-9 _]*(\\(\\d+(,\\s*\\d+)?\\))?(\\[\\])?$/;\n\nfunction columnTypes(\n schema: { columns: Record<string, { type?: string }> } | null | undefined,\n): Record<string, string | undefined> {\n return Object.fromEntries(\n Object.entries(schema?.columns ?? {}).map(([name, column]) => [\n name,\n column.type,\n ]),\n );\n}\n\nfunction sameType(from: string | undefined, to: string | undefined): boolean {\n return (\n from !== undefined &&\n to !== undefined &&\n from.trim().toLowerCase() === to.trim().toLowerCase()\n );\n}\n\nfunction targetType(declared: string | undefined): string {\n const type = declared?.trim();\n if (!type || !SQL_TYPE.test(type)) {\n throw new LedgerAccountsTableMoveError(\n `Cannot copy into \"${LEDGER_ACCOUNTS_TABLE}\": unsupported live column type ${JSON.stringify(type)}`,\n );\n }\n return type;\n}\n","import { digestRunOnceContent, runOnce } from '@happyvertical/smrt-core';\nimport type { DatabaseInterface } from '@happyvertical/smrt-core/migrations';\nimport { getTenantId, withTenant } from '@happyvertical/smrt-tenancy';\nimport { JournalCollection } from './collections/Journals';\nimport { LedgerCollection } from './collections/Ledgers';\nimport type { Journal } from './models/Journal';\n\nexport type Counterparty = { kind: string; id: string };\n\nexport interface LedgerPostingInput {\n db: DatabaseInterface;\n tenantId: string;\n ledgerId: string;\n idempotencyKey: string;\n sourceModule: string;\n sourceRef: string;\n description: string;\n date?: Date;\n currency: string;\n amountMinor: number;\n counterparty: Counterparty;\n debitAccountId: string;\n creditAccountId: string;\n dueDate?: Date;\n settlesSourceRef?: string;\n}\n\nfunction assertInput(input: LedgerPostingInput): void {\n for (const value of [\n input.tenantId,\n input.ledgerId,\n input.idempotencyKey,\n input.sourceModule,\n input.sourceRef,\n input.currency,\n input.counterparty.kind,\n input.counterparty.id,\n input.debitAccountId,\n input.creditAccountId,\n ...(input.settlesSourceRef === undefined ? [] : [input.settlesSourceRef]),\n ]) {\n if (!value?.trim() || value !== value.trim())\n throw new Error(\n 'Ledger posting identifiers must be nonempty trimmed strings',\n );\n }\n if (!Number.isSafeInteger(input.amountMinor) || input.amountMinor <= 0)\n throw new Error(\n 'Ledger posting amountMinor must be a positive safe integer',\n );\n}\n\nfunction replayMismatchError(): Error {\n return new Error(\n 'Ledger posting idempotency key was replayed with different content',\n );\n}\n\n/**\n * Atomically records an exact-minor-unit double entry. `runOnce` scopes the\n * key by tenant and ledger; its receipt binds the request digest so retries recover the\n * original journal and a changed replay refuses instead of double-posting.\n * Idempotency is permanent: once the receipt is pruned, the journal's unique\n * `(tenantId, ledgerId, idempotencyKey)` row and its `requestDigest` answer the\n * same replay.\n */\nexport async function postLedgerEntry(\n input: LedgerPostingInput,\n): Promise<Journal> {\n // Snapshot caller-owned data before the first await; a caller may reuse or\n // mutate its request object while another posting is waiting for a claim.\n input = {\n ...input,\n counterparty: { ...input.counterparty },\n date: input.date ? new Date(input.date) : undefined,\n dueDate: input.dueDate ? new Date(input.dueDate) : undefined,\n };\n assertInput(input);\n if (getTenantId() && getTenantId() !== input.tenantId)\n throw new Error('Ledger posting tenant differs from active context');\n const content = {\n ledgerId: input.ledgerId,\n sourceModule: input.sourceModule,\n sourceRef: input.sourceRef,\n description: input.description,\n date: input.date?.toISOString() ?? null,\n currency: input.currency,\n amountMinor: input.amountMinor,\n counterparty: input.counterparty,\n debitAccountId: input.debitAccountId,\n creditAccountId: input.creditAccountId,\n dueDate: input.dueDate?.toISOString() ?? null,\n settlesSourceRef: input.settlesSourceRef ?? null,\n };\n const digest = digestRunOnceContent(content);\n const receipt = await withTenant({ tenantId: input.tenantId }, () =>\n runOnce(\n {\n db: input.db,\n tenantId: input.tenantId,\n actor: 'smrt-ledgers.post:v1',\n token: input.idempotencyKey,\n content: { ledgerId: input.ledgerId },\n },\n async (tx) => {\n const ledger = await (await LedgerCollection.create({ db: tx })).get({\n id: input.ledgerId,\n });\n if (\n !ledger ||\n ledger.tenantId !== input.tenantId ||\n ledger.balanceMode !== 'exact-integer'\n )\n throw new Error(\n 'Posting helpers require an owned exact-integer ledger',\n );\n const journals = await JournalCollection.create({ db: tx });\n // The `runOnce` claim is pruned after its retention window (30 days by\n // default), after which an identical retry would re-run this callback\n // and hit `journals_ledger_idempotency_key`. The journal row is the\n // permanent idempotency record, so resolve it before inserting (#4067).\n const [existing] = await journals.list({\n where: {\n tenantId: input.tenantId,\n ledgerId: input.ledgerId,\n idempotencyKey: input.idempotencyKey,\n },\n limit: 1,\n });\n if (existing) {\n if (existing.requestDigest !== digest) throw replayMismatchError();\n if (!existing.isPosted())\n throw new Error(\n 'Ledger posting idempotency key belongs to a journal that is not posted',\n );\n return { journalId: existing.id, requestDigest: digest };\n }\n const journal = await journals.createWithEntries({\n tenantId: input.tenantId,\n ledgerId: input.ledgerId,\n date: input.date ?? new Date(),\n description: input.description,\n sourceModule: input.sourceModule,\n sourceRef: input.sourceRef,\n idempotencyKey: input.idempotencyKey,\n requestDigest: digest,\n metadata: {\n idempotencyKey: input.idempotencyKey,\n requestDigest: digest,\n },\n entries: [\n {\n accountId: input.debitAccountId,\n debit: input.amountMinor,\n currency: input.currency,\n counterpartyKind: input.counterparty.kind,\n counterpartyId: input.counterparty.id,\n dueDate: input.dueDate,\n settlesSourceRef: input.settlesSourceRef,\n },\n {\n accountId: input.creditAccountId,\n credit: input.amountMinor,\n currency: input.currency,\n counterpartyKind: input.counterparty.kind,\n counterpartyId: input.counterparty.id,\n dueDate: input.dueDate,\n settlesSourceRef: input.settlesSourceRef,\n },\n ],\n });\n await journal.post();\n return { journalId: journal.id, requestDigest: digest };\n },\n ),\n );\n if (receipt.requestDigest !== digest) throw replayMismatchError();\n const journal = await withTenant({ tenantId: input.tenantId }, async () => {\n const journals = await JournalCollection.create({ db: input.db });\n return journals.get({ id: String(receipt.journalId) });\n });\n if (!journal?.isPosted())\n throw new Error(\n 'Ledger posting receipt does not resolve to a posted journal',\n );\n if (journal.requestDigest !== digest) throw replayMismatchError();\n return journal;\n}\n\nexport const postReceivable = postLedgerEntry;\nexport const postPayable = postLedgerEntry;\nexport const postSettlement = postLedgerEntry;\n","/**\n * Declared recipes for smrt-ledgers (#3590, #3604): user-facing units of\n * functionality an app or agent can pick instead of the whole package.\n * The scanner reads these statics into the `recipes` array of `manifest.json`\n * and `smrt-knowledge.json`; nothing here runs at that point.\n *\n * @packageDocumentation\n */\n\nimport { SmrtRecipe } from '@happyvertical/smrt-core';\nimport { Account } from './models/Account.js';\nimport { Journal } from './models/Journal.js';\nimport { JournalEntry } from './models/JournalEntry.js';\n\n/** Bookkeeping: Keep your books: a chart of accounts and double-entry journals. */\nexport class BookkeepingRecipe extends SmrtRecipe {\n static id = 'ledgers.bookkeeping';\n static help = './bookkeeping.recipe.md';\n static label = 'Bookkeeping';\n static summary =\n 'Keep your books: a chart of accounts and double-entry journals.';\n static synonyms = [\n 'accounting',\n 'ledger',\n 'general ledger',\n 'journals',\n 'chart of accounts',\n ];\n static section = {\n id: 'accounting',\n label: 'Accounting',\n icon: 'bank',\n description: 'Your books: accounts, journals and balances.',\n };\n static models = [Account, Journal, JournalEntry];\n static nav = [\n {\n label: 'Accounts',\n model: Account,\n icon: 'bank',\n description:\n 'The accounts your books are kept in, like sales, rent and bank.',\n },\n {\n label: 'Journals',\n model: Journal,\n icon: 'book',\n description:\n 'The entries behind your accounts, so every dollar has a trail.',\n },\n ];\n static options = {\n Account: {\n fields: {\n metadata: { visibility: 'hidden' },\n parentId: { visibility: 'hidden' },\n },\n },\n Journal: {\n fields: {\n sourceModule: { visibility: 'hidden' },\n sourceRef: { visibility: 'hidden' },\n idempotencyKey: { visibility: 'hidden' },\n requestDigest: { visibility: 'hidden' },\n voidedAt: { visibility: 'hidden' },\n voidReason: { visibility: 'hidden' },\n metadata: { visibility: 'hidden' },\n },\n },\n JournalEntry: {\n fields: {\n exchangeRate: { visibility: 'hidden' },\n settlesSourceRef: { visibility: 'hidden' },\n metadata: { visibility: 'hidden' },\n },\n },\n } as const;\n}\n"],"mappings":"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"}