@classytic/ledger 0.6.0 → 0.8.0

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.
@@ -1,6 +1,6 @@
1
- import { ClientSession, Model } from "mongoose";
2
1
  import * as _classytic_mongokit0 from "@classytic/mongokit";
3
2
  import { Repository, RepositoryContext, RepositoryInstance } from "@classytic/mongokit";
3
+ import { ClientSession, Model } from "mongoose";
4
4
 
5
5
  //#region src/types/repositories.d.ts
6
6
  interface PostOptions {
@@ -213,7 +213,22 @@ declare function creditLimitPlugin(options: CreditLimitPluginOptions): {
213
213
  * This file is side-effect only — importing it anywhere in the package is
214
214
  * enough to activate the augmentation. `src/types/index.ts` re-exports it.
215
215
  */
216
- type LedgerInternalOp = 'post' | 'unpost' | 'archive' | 'reverseMark' | 'fxRealize' | 'cashBasisRealize';
216
+ /**
217
+ * Internal op tags attached to `repository.update()` / `repository.create()`
218
+ * calls that the ledger itself initiates. Plugins observing the
219
+ * `before:update` / `before:create` hooks can read `context._ledgerInternal`
220
+ * to identify legitimate engine operations and skip guards accordingly.
221
+ *
222
+ * - `post` / `unpost` / `archive` — state transitions on an entry
223
+ * - `reverseMark` — marking an original as reversed
224
+ * (exempt from fiscal/daily locks)
225
+ * - `fxRealize` — FX realization plugin balancing entry
226
+ * (exempt from all locks and credit-limit)
227
+ *
228
+ * Tax-specific internal ops (e.g. cash-basis exigibility realization) live
229
+ * in their respective tax packages and are not part of the ledger core.
230
+ */
231
+ type LedgerInternalOp = 'post' | 'unpost' | 'archive' | 'reverseMark' | 'fxRealize';
217
232
  declare module '@classytic/mongokit' {
218
233
  interface RepositoryContext {
219
234
  /**
@@ -414,48 +429,6 @@ declare function fiscalLockPlugin(options: FiscalLockPluginOptions): {
414
429
  name: string;
415
430
  apply(repo: _classytic_mongokit0.RepositoryInstance): void;
416
431
  };
417
- interface TaxLockPluginOptions {
418
- /**
419
- * Tax-period model. Expected shape (fields are overridable via the
420
- * lower-level `createLockPlugin` if your schema differs):
421
- *
422
- * {
423
- * periodStart: Date,
424
- * periodEnd: Date,
425
- * status: 'open' | 'filed' | 'amended',
426
- * jurisdiction?: string,
427
- * taxType?: string,
428
- * returnRef?: string,
429
- * [orgField]?: unknown,
430
- * }
431
- *
432
- * `status !== 'open'` counts as locked.
433
- */
434
- TaxPeriodModel: Model<unknown>;
435
- AccountModel: Model<unknown>;
436
- JournalEntryModel?: Model<unknown>;
437
- orgField?: string;
438
- /**
439
- * Predicate deciding which accounts participate in tax returns.
440
- * Defaults to `acc => acc.taxMetadata != null` — matches the
441
- * convention used by country packs that populate `taxMetadata` on
442
- * tax-payable / tax-recoverable account types.
443
- */
444
- isTaxAffecting?: LockAccountSelector;
445
- /**
446
- * Derive `{ jurisdiction, taxType }` from the entry payload so each
447
- * post can look up the right row. Default: use `data.jurisdiction`
448
- * and `data.taxType` directly when present.
449
- */
450
- deriveFilter?: (data: Record<string, unknown>) => {
451
- jurisdiction?: string;
452
- taxType?: string;
453
- } | undefined;
454
- }
455
- declare function taxLockPlugin(options: TaxLockPluginOptions): {
456
- name: string;
457
- apply(repo: _classytic_mongokit0.RepositoryInstance): void;
458
- };
459
432
  interface DailyLockPluginOptions {
460
433
  /**
461
434
  * Return the `lastClosedDate` for the given org/branch — everything
@@ -488,26 +461,4 @@ interface WatermarkResolverOptions {
488
461
  }
489
462
  declare function watermarkResolver(options: WatermarkResolverOptions): LockResolver;
490
463
  //#endregion
491
- //#region src/utils/tax-hooks.d.ts
492
- interface TaxLineInput {
493
- account: unknown;
494
- amount: number;
495
- side: 'debit' | 'credit';
496
- taxCode?: string;
497
- extraFields?: Record<string, unknown>;
498
- }
499
- interface GeneratedTaxLine {
500
- account: unknown;
501
- debit: number;
502
- credit: number;
503
- label?: string;
504
- taxDetails?: Array<{
505
- taxCode: string;
506
- taxName?: string;
507
- }>;
508
- }
509
- interface TaxLineGenerator {
510
- generateTaxLines(input: TaxLineInput): GeneratedTaxLine[];
511
- }
512
- //#endregion
513
- export { JournalEntryRepository as A, SeedResult as B, DoubleEntryPluginOptions as C, AccountRepository as D, creditLimitPlugin as E, PostOptions as F, ReconciliationRepository as I, ReverseOptions as L, JournalRepository as M, MatchInput as N, BulkCreateInput as O, OpenItem as P, ReverseResult as R, fxRealizationPlugin as S, CreditLimitPluginOptions as T, LockResolver as _, DailyLockPluginOptions as a, idempotencyPlugin as b, dailyLockPlugin as c, PeriodResolverOptions as d, periodResolver as f, LockHit as g, LockAccountSelector as h, watermarkResolver as i, JournalItemRef as j, BulkCreateResult as k, fiscalLockPlugin as l, CreateLockPluginOptions as m, TaxLineInput as n, FiscalLockPluginOptions as o, createLockPlugin as p, WatermarkResolverOptions as r, TaxLockPluginOptions as s, TaxLineGenerator as t, taxLockPlugin as u, LockResolverContext as v, doubleEntryPlugin as w, FxRealizationPluginOptions as x, IdempotencyPluginOptions as y, SeedOptions as z };
464
+ export { OpenItem as A, AccountRepository as C, JournalItemRef as D, JournalEntryRepository as E, SeedOptions as F, SeedResult as I, ReconciliationRepository as M, ReverseOptions as N, JournalRepository as O, ReverseResult as P, creditLimitPlugin as S, BulkCreateResult as T, FxRealizationPluginOptions as _, dailyLockPlugin as a, doubleEntryPlugin as b, periodResolver as c, LockAccountSelector as d, LockHit as f, idempotencyPlugin as g, IdempotencyPluginOptions as h, FiscalLockPluginOptions as i, PostOptions as j, MatchInput as k, createLockPlugin as l, LockResolverContext as m, watermarkResolver as n, fiscalLockPlugin as o, LockResolver as p, DailyLockPluginOptions as r, PeriodResolverOptions as s, WatermarkResolverOptions as t, CreateLockPluginOptions as u, fxRealizationPlugin as v, BulkCreateInput as w, CreditLimitPluginOptions as x, DoubleEntryPluginOptions as y };
@@ -0,0 +1,130 @@
1
+ import { t as AccountType } from "./core-MpgjCqK0.mjs";
2
+
3
+ //#region src/country/index.d.ts
4
+ /**
5
+ * Declarative template that tells the engine which journals to seed for a
6
+ * new organization. Consumers call
7
+ * `engine.repositories.journals.seedDefaults(orgId)` which reads these from
8
+ * the country pack and creates one Journal document per template.
9
+ *
10
+ * Journals are *optional* — if a consumer never seeds journals, the legacy
11
+ * `journalType` enum on a journal entry still works. Consumers opting in
12
+ * get per-journal sequence prefixes, restricted payment methods, bank
13
+ * statement sources, etc.
14
+ */
15
+ interface JournalTemplate {
16
+ /** Short stable identifier — e.g. `'SALES'`, `'PURCHASE'`, `'BANK'`. */
17
+ readonly code: string;
18
+ /** Display name. */
19
+ readonly name: string;
20
+ /**
21
+ * One of the registered `JOURNAL_TYPES` codes — connects this journal to
22
+ * the engine's reference-number generator and posting-contract system.
23
+ */
24
+ readonly journalType: string;
25
+ /** Reference-number prefix — defaults to `code` when omitted. */
26
+ readonly sequencePrefix?: string;
27
+ /** First sequence number — defaults to `1`. */
28
+ readonly sequenceStartNum?: number;
29
+ /**
30
+ * Logical source — pure ledgering (`'general'`), sale-side docs (`'sale'`),
31
+ * purchase-side docs (`'purchase'`), cash/bank movement (`'bank'`, `'cash'`).
32
+ * Drives default locks (sale-lock, purchase-lock) when they're wired.
33
+ */
34
+ readonly kind?: 'general' | 'sale' | 'purchase' | 'bank' | 'cash' | string;
35
+ /** Optional default debit/credit account roles for quick data entry. */
36
+ readonly defaultDebitAccountRole?: string;
37
+ readonly defaultCreditAccountRole?: string;
38
+ }
39
+ interface CountryPack {
40
+ /** ISO 3166-1 alpha-2 code (e.g., 'CA', 'US', 'GB') */
41
+ readonly code: string;
42
+ /** Country name */
43
+ readonly name: string;
44
+ /** Default currency code */
45
+ readonly defaultCurrency: string;
46
+ /**
47
+ * Full chart of accounts template — flat array of account type definitions.
48
+ * Includes both posting accounts and grouping / total rows.
49
+ */
50
+ readonly accountTypes: readonly AccountType[];
51
+ /**
52
+ * Optional journal templates seeded per organization. When a consumer
53
+ * calls `engine.repositories.journals.seedDefaults(orgId)`, the engine
54
+ * creates one Journal document per template. See `JournalTemplate`.
55
+ */
56
+ readonly journalTemplates?: readonly JournalTemplate[];
57
+ /**
58
+ * The retained earnings account code — the account that holds accumulated
59
+ * retained earnings (e.g. '3600' CA, '3310' BD).
60
+ *
61
+ * On the balance sheet, this account is excluded from normal equity grouping
62
+ * and its balance is folded into the computed "Retained Earnings" section
63
+ * (opening RE = RE account balance + prior-year unclosed P&L).
64
+ *
65
+ * Inspired by Odoo's `equity_unaffected` account type.
66
+ */
67
+ readonly retainedEarningsAccountCode?: string;
68
+ /**
69
+ * Display code for the "Previous Years Retained Earnings" line on the
70
+ * balance sheet (e.g. '3660' for CA GIFI). Defaults to retainedEarningsAccountCode.
71
+ */
72
+ readonly retainedEarningsDisplayCode?: string;
73
+ /** Display code for current year net income line (e.g. '3680' CA, '3311' BD) */
74
+ readonly currentYearEarningsCode?: string;
75
+ /**
76
+ * Account code used as the equity contra for opening balance entries.
77
+ * Defaults to `retainedEarningsAccountCode` when not set.
78
+ *
79
+ * Following Odoo convention, this is typically the retained earnings
80
+ * account itself (not a temporary "Opening Balance Equity" account).
81
+ * Country packs that prefer a separate temporary account (like ERPNext)
82
+ * can override this.
83
+ */
84
+ readonly openingBalanceEquityCode?: string;
85
+ /** Group label code used to identify Cost of Sales in the income statement */
86
+ readonly cogsGroupCode?: string;
87
+ /** Override default English report section names */
88
+ readonly reportLabels?: {
89
+ readonly assets?: string;
90
+ readonly liabilities?: string;
91
+ readonly equity?: string;
92
+ readonly revenue?: string;
93
+ readonly expenses?: string;
94
+ };
95
+ /** Get all account types that can be posted to (not groups, not totals) */
96
+ getPostingAccountTypes(): readonly AccountType[];
97
+ /** Get account type by code */
98
+ getAccountType(code: string): AccountType | undefined;
99
+ /** Validate an account type code exists */
100
+ isValidAccountType(code: string): boolean;
101
+ /** Check if an account type can receive postings */
102
+ isPostingAccount(code: string): boolean;
103
+ /** Flatten hierarchical accounts (if needed) */
104
+ flattenAccountTypes(): readonly AccountType[];
105
+ }
106
+ interface CountryPackInput {
107
+ code: string;
108
+ name: string;
109
+ defaultCurrency: string;
110
+ accountTypes: readonly AccountType[];
111
+ journalTemplates?: readonly JournalTemplate[];
112
+ retainedEarningsAccountCode?: string;
113
+ retainedEarningsDisplayCode?: string;
114
+ currentYearEarningsCode?: string;
115
+ openingBalanceEquityCode?: string;
116
+ cogsGroupCode?: string;
117
+ reportLabels?: {
118
+ readonly assets?: string;
119
+ readonly liabilities?: string;
120
+ readonly equity?: string;
121
+ readonly revenue?: string;
122
+ readonly expenses?: string;
123
+ };
124
+ }
125
+ /**
126
+ * Factory to create a CountryPack with auto-generated helper methods.
127
+ */
128
+ declare function defineCountryPack(input: CountryPackInput): CountryPack;
129
+ //#endregion
130
+ export { defineCountryPack as i, CountryPackInput as n, JournalTemplate as r, CountryPack as t };
package/dist/index.d.mts CHANGED
@@ -1,12 +1,12 @@
1
- import { _ as TaxMetadata, a as Cents, c as DateRange, d as JournalType, f as MainType, g as TaxDetail, h as StatementType, i as CategoryKey, l as EntryState, m as ObjectId, n as CashFlowCategory, o as Currency, p as NormalBalance, s as DateOption, t as AccountType, u as JournalItem, v as TotalAccountOp } from "./core-BkGjuVZj.mjs";
2
- import { S as isValidCategory, a as getJournalTypeCodes, b as isBalanceSheet, c as CURRENCIES, d as isValidCurrency, f as CATEGORIES, i as getJournalType, l as getCurrency, n as JOURNAL_TYPES, o as isValidJournalType, p as CATEGORY_KEYS, r as getCustomJournalTypes, s as registerJournalType, t as JOURNAL_CODES, u as getMinorUnit, x as isIncomeStatement, y as getNormalBalance } from "./journals-C50E9mpo.mjs";
3
- import { a as TaxCodesByRegion, c as TaxReportLine, i as TaxCode, l as TaxReportTemplate, n as CountryPackInput, o as TaxExigibility, r as JournalTemplate, s as TaxRepartitionLine, t as CountryPack, u as defineCountryPack } from "./index-BthGypsI.mjs";
4
- import { _ as PopulatedJournalEntry, a as exportToCsv, h as FlatJournalRow, i as quickbooksFieldMap, m as ExportFieldMap, p as ExportField, r as universalFieldMap, t as flattenJournalEntries } from "./index-D1ZjgVxn.mjs";
1
+ import { _ as TaxMetadata, a as Cents, c as DateRange, d as JournalType, f as MainType, g as TaxDetail, h as StatementType, i as CategoryKey, l as EntryState, m as ObjectId, n as CashFlowCategory, o as Currency, p as NormalBalance, s as DateOption, t as AccountType, u as JournalItem, v as TotalAccountOp } from "./core-MpgjCqK0.mjs";
2
+ import { S as isValidCategory, a as getJournalTypeCodes, b as isBalanceSheet, c as CURRENCIES, d as isValidCurrency, f as CATEGORIES, i as getJournalType, l as getCurrency, n as JOURNAL_TYPES, o as isValidJournalType, p as CATEGORY_KEYS, r as getCustomJournalTypes, s as registerJournalType, t as JOURNAL_CODES, u as getMinorUnit, x as isIncomeStatement, y as getNormalBalance } from "./journals-Dd4A9TN3.mjs";
3
+ import { i as defineCountryPack, n as CountryPackInput, r as JournalTemplate, t as CountryPack } from "./index-RNZsX0Yo.mjs";
4
+ import { _ as PopulatedJournalEntry, a as exportToCsv, h as FlatJournalRow, i as quickbooksFieldMap, m as ExportFieldMap, p as ExportField, r as universalFieldMap, t as flattenJournalEntries } from "./index-bCEeSzdO.mjs";
5
5
  import { Money, abs, add, allocate, equals, format, formatPlain, fromDecimal, isNegative, isPositive, isValid, isZero, max, min, multiply, negate, parseCents, percentage, round, splitTaxExclusive, splitTaxInclusive, subtract, toDecimal } from "./money.mjs";
6
- import { $ as TrialBalanceRow, A as generateDimensionBreakdown, B as BalanceSheetReport, D as DimensionBreakdownParams, E as DimensionBreakdownOptions, F as BudgetVsActualReport, G as IncomeStatementReport, H as CashFlowSection, I as BudgetVsActualRow, J as ReportCategory, K as LedgerEntry, L as generateBudgetVsActual, M as generateCashFlow, N as BudgetVsActualOptions, O as DimensionBreakdownReport, P as BudgetVsActualParams, Q as TrialBalanceReport, T as reopenFiscalPeriod, U as GeneralLedgerAccount, V as CashFlowReport, W as GeneralLedgerReport, X as TaxReport, Y as ReportGroup, Z as TaxReturnSummary, a as RevaluationReport, at as DEFAULT_BUCKETS, b as generateGeneralLedger, c as RevaluationRate, ct as defaultLogger, d as computeRevaluation, et as AgedBalanceOptions, f as PartnerLedgerLine, g as generatePartnerLedger, h as PartnerLedgerReport, i as RevaluationParams, it as AgedBucketConfig, k as DimensionBreakdownRow, l as RevaluationResult, m as PartnerLedgerParams, n as generateTrialBalance, nt as AgedBalanceReport, o as generateRevaluation, ot as generateAgedBalance, p as PartnerLedgerOptions, q as ReportAccount, r as RevaluationOptions, rt as AgedBalanceRow, s as AccountForeignBalance, st as Logger, tt as AgedBalanceParams, u as buildRevaluationEntry, v as generateIncomeStatement, w as closeFiscalPeriod, z as generateBalanceSheet } from "./trial-balance-s92GEvRR.mjs";
7
- import { A as JournalEntryRepository, B as SeedResult, D as AccountRepository, E as creditLimitPlugin, F as PostOptions, I as ReconciliationRepository, L as ReverseOptions, M as JournalRepository, N as MatchInput, O as BulkCreateInput, P as OpenItem, R as ReverseResult, S as fxRealizationPlugin, T as CreditLimitPluginOptions, _ as LockResolver, a as DailyLockPluginOptions, b as idempotencyPlugin, c as dailyLockPlugin, d as PeriodResolverOptions, f as periodResolver, g as LockHit, h as LockAccountSelector, i as watermarkResolver, j as JournalItemRef, k as BulkCreateResult, l as fiscalLockPlugin, m as CreateLockPluginOptions, n as TaxLineInput, o as FiscalLockPluginOptions, p as createLockPlugin, r as WatermarkResolverOptions, s as TaxLockPluginOptions, t as TaxLineGenerator, u as taxLockPlugin, v as LockResolverContext, w as doubleEntryPlugin, x as FxRealizationPluginOptions, z as SeedOptions } from "./tax-hooks-BnVenul5.mjs";
6
+ import { $ as AgedBalanceParams, A as generateDimensionBreakdown, B as BalanceSheetReport, D as DimensionBreakdownParams, E as DimensionBreakdownOptions, F as BudgetVsActualReport, G as IncomeStatementReport, H as CashFlowSection, I as BudgetVsActualRow, J as ReportCategory, K as LedgerEntry, L as generateBudgetVsActual, M as generateCashFlow, N as BudgetVsActualOptions, O as DimensionBreakdownReport, P as BudgetVsActualParams, Q as AgedBalanceOptions, T as reopenFiscalPeriod, U as GeneralLedgerAccount, V as CashFlowReport, W as GeneralLedgerReport, X as TrialBalanceReport, Y as ReportGroup, Z as TrialBalanceRow, a as RevaluationReport, at as Logger, b as generateGeneralLedger, c as RevaluationRate, d as computeRevaluation, et as AgedBalanceReport, f as PartnerLedgerLine, g as generatePartnerLedger, h as PartnerLedgerReport, i as RevaluationParams, it as generateAgedBalance, k as DimensionBreakdownRow, l as RevaluationResult, m as PartnerLedgerParams, n as generateTrialBalance, nt as AgedBucketConfig, o as generateRevaluation, ot as defaultLogger, p as PartnerLedgerOptions, q as ReportAccount, r as RevaluationOptions, rt as DEFAULT_BUCKETS, s as AccountForeignBalance, tt as AgedBalanceRow, u as buildRevaluationEntry, v as generateIncomeStatement, w as closeFiscalPeriod, z as generateBalanceSheet } from "./trial-balance-DTj-c21f.mjs";
7
+ import { A as OpenItem, C as AccountRepository, D as JournalItemRef, E as JournalEntryRepository, F as SeedOptions, I as SeedResult, M as ReconciliationRepository, N as ReverseOptions, O as JournalRepository, P as ReverseResult, S as creditLimitPlugin, T as BulkCreateResult, _ as FxRealizationPluginOptions, a as dailyLockPlugin, b as doubleEntryPlugin, c as periodResolver, d as LockAccountSelector, f as LockHit, g as idempotencyPlugin, i as FiscalLockPluginOptions, j as PostOptions, k as MatchInput, l as createLockPlugin, m as LockResolverContext, n as watermarkResolver, o as fiscalLockPlugin, p as LockResolver, r as DailyLockPluginOptions, s as PeriodResolverOptions, t as WatermarkResolverOptions, u as CreateLockPluginOptions, v as fxRealizationPlugin, w as BulkCreateInput, x as CreditLimitPluginOptions } from "./index-BSsvrf3m.mjs";
8
+ import { PaginationConfig, PluginType, QueryParser, QueryParserOptions, Repository } from "@classytic/mongokit";
8
9
  import { ClientSession, Connection, Model } from "mongoose";
9
- import { PaginationConfig, PluginType, Repository } from "@classytic/mongokit";
10
10
 
11
11
  //#region src/types/engine.d.ts
12
12
  /** Mongokit plugins to install per repository (composes with engine built-ins). */
@@ -256,23 +256,18 @@ interface IntrospectAPI {
256
256
  * Agents use this to discover what analytics they can run.
257
257
  */
258
258
  reports(): ReadonlyArray<ReportDescriptor>;
259
- /**
260
- * List tax codes — all of them, or filtered by region.
261
- */
262
- taxCodes(region?: string): ReadonlyArray<TaxCode>;
263
259
  /**
264
260
  * List fiscal periods for an organization.
265
261
  */
266
262
  fiscalPeriods(organizationId?: unknown, session?: ClientSession | null): Promise<FiscalPeriodSummary[]>;
267
263
  /**
268
264
  * A one-shot snapshot of everything an agent needs to start working:
269
- * accounts, journal types, reports, tax codes, fiscal periods.
265
+ * accounts, journal types, reports, fiscal periods.
270
266
  */
271
267
  catalog(organizationId?: unknown): Promise<{
272
268
  accounts: AccountSummary[];
273
269
  journalTypes: ReadonlyArray<JournalType>;
274
270
  reports: ReadonlyArray<ReportDescriptor>;
275
- taxCodes: ReadonlyArray<TaxCode>;
276
271
  fiscalPeriods: FiscalPeriodSummary[];
277
272
  }>;
278
273
  }
@@ -292,21 +287,6 @@ interface ActorContext {
292
287
  type AccountCode = string;
293
288
  /** Integer-cents amount. */
294
289
  type Cents$1 = number;
295
- interface TaxInput {
296
- /** Tax code from the country pack (e.g. 'HST', 'GST', 'VAT') */
297
- readonly code: string;
298
- /**
299
- * Account type code where the tax amount posts.
300
- * For sales: the tax-payable account (e.g. '2300' HST Collected).
301
- * For expenses: the tax-recoverable (ITC) account (e.g. '2400' HST Paid).
302
- */
303
- readonly account: AccountCode;
304
- /**
305
- * If true, `amount` is tax-inclusive and will be split into base + tax.
306
- * If false (default), `amount` is the tax-exclusive base and tax is added.
307
- */
308
- readonly inclusive?: boolean;
309
- }
310
290
  /**
311
291
  * Options passed to every record.* operation. Matches mongokit's
312
292
  * RepositoryContext shape so audit/observability plugins pick them up
@@ -331,14 +311,16 @@ interface RecordOptions {
331
311
  interface RecordSaleInput {
332
312
  /** Transaction date */
333
313
  readonly date: Date;
334
- /** Tax-exclusive sale amount in integer cents (unless `tax.inclusive` is true) */
314
+ /** Sale amount in integer cents. Tax, if any, is the caller's responsibility
315
+ * — compute it with your tax engine (e.g. `@classytic/bd-tax`,
316
+ * `@classytic/ca-tax`) and either pre-add it to `amount` + include a
317
+ * tax journal item via `record.adjustment`, or post the entry directly
318
+ * via `engine.repositories.journalEntries.create`. */
335
319
  readonly amount: Cents$1;
336
320
  /** Account that receives the money — either Cash or Accounts Receivable */
337
321
  readonly receivableAccount: AccountCode;
338
322
  /** Revenue account */
339
323
  readonly revenueAccount: AccountCode;
340
- /** Tax info — optional */
341
- readonly tax?: TaxInput;
342
324
  /** Free-text label / memo */
343
325
  readonly label?: string;
344
326
  /** Optional reference number override (otherwise auto-generated) */
@@ -350,14 +332,13 @@ interface RecordSaleInput {
350
332
  }
351
333
  interface RecordExpenseInput {
352
334
  readonly date: Date;
353
- /** Tax-exclusive expense amount in cents (unless `tax.inclusive` is true) */
335
+ /** Expense amount in integer cents. Tax is caller's responsibility — see
336
+ * `RecordSaleInput.amount` comment. */
354
337
  readonly amount: Cents$1;
355
338
  /** Expense category account (e.g. '6010' Rent) */
356
339
  readonly expenseAccount: AccountCode;
357
340
  /** Where the money came from — either Cash or Accounts Payable */
358
341
  readonly paidFromAccount: AccountCode;
359
- /** Tax info (recoverable input tax credit) */
360
- readonly tax?: TaxInput;
361
342
  readonly label?: string;
362
343
  readonly reference?: string;
363
344
  readonly dimensions?: Record<string, unknown>;
@@ -400,25 +381,49 @@ interface RecordAdjustmentInput {
400
381
  readonly dimensions?: Record<string, unknown>;
401
382
  readonly journalType?: string;
402
383
  }
384
+ interface RecordOpeningBalanceInput {
385
+ /** Cutover date — typically start of fiscal year. */
386
+ readonly cutoverDate: Date;
387
+ /**
388
+ * Account balances in integer cents, signed:
389
+ * - Positive = normal debit balance (assets)
390
+ * - Negative = normal credit balance (liabilities, equity)
391
+ *
392
+ * Should only contain balance sheet accounts. P&L cumulative effect
393
+ * belongs in retained earnings (the equity account).
394
+ */
395
+ readonly balances: ReadonlyArray<{
396
+ readonly account: AccountCode;
397
+ readonly balance: Cents$1;
398
+ }>;
399
+ /**
400
+ * Equity contra account code. Defaults to the country pack's
401
+ * `retainedEarningsAccountCode` (e.g. '3600' for CA, '3310' for BD).
402
+ */
403
+ readonly equityAccount?: AccountCode;
404
+ readonly label?: string;
405
+ }
403
406
  interface RecordAPI {
404
407
  /**
405
- * Record a sale. Debits cash/AR, credits revenue, splits tax if provided.
408
+ * Record a sale. Debits cash/AR, credits revenue. Tax lines if needed —
409
+ * are the consumer's responsibility (compute via your tax engine and
410
+ * either add to `amount` or use `record.adjustment`).
406
411
  *
407
412
  * @example
408
413
  * ```typescript
409
414
  * await engine.record.sale(orgId, {
410
415
  * date: new Date('2025-04-01'),
411
- * amount: 10000, // $100.00 base
416
+ * amount: 10000, // $100.00 total
412
417
  * receivableAccount: '1001', // Cash
413
418
  * revenueAccount: '4010', // Service Revenue
414
- * tax: { code: 'HST', account: '2300' }, // 13% HST Collected
415
419
  * label: 'Invoice #INV-001',
416
420
  * });
417
421
  * ```
418
422
  */
419
423
  sale(organizationId: unknown, input: RecordSaleInput, options?: RecordOptions): Promise<unknown>;
420
424
  /**
421
- * Record an expense. Debits expense, credits cash/AP, splits input tax credit if provided.
425
+ * Record an expense. Debits expense, credits cash/AP. Tax is caller's
426
+ * responsibility — see `sale()`.
422
427
  */
423
428
  expense(organizationId: unknown, input: RecordExpenseInput, options?: RecordOptions): Promise<unknown>;
424
429
  /**
@@ -435,6 +440,31 @@ interface RecordAPI {
435
440
  * the other verbs. Amounts must balance (debits = credits).
436
441
  */
437
442
  adjustment(organizationId: unknown, input: RecordAdjustmentInput, options?: RecordOptions): Promise<unknown>;
443
+ /**
444
+ * Record opening balances for a cutover migration. Creates a single
445
+ * multi-line journal entry with each account's balance, contra'd against
446
+ * an equity account (retained earnings by default).
447
+ *
448
+ * Follows the Odoo convention: regular JE, not a special type. Only
449
+ * balance sheet accounts should be passed — P&L cumulative effect belongs
450
+ * in the equity contra account.
451
+ *
452
+ * Idempotent: uses `_externalId: 'opening-balance:{date}'` so re-calling
453
+ * with the same cutover date fails cleanly (duplicate key error).
454
+ *
455
+ * @example
456
+ * ```typescript
457
+ * await engine.record.openingBalance(orgId, {
458
+ * cutoverDate: new Date('2025-01-01'),
459
+ * balances: [
460
+ * { account: '1000', balance: 5000000 }, // $50k cash
461
+ * { account: '2620', balance: -1875000 }, // $18.75k AP
462
+ * { account: '3600', balance: -3125000 }, // $31.25k RE
463
+ * ],
464
+ * });
465
+ * ```
466
+ */
467
+ openingBalance(organizationId: unknown, input: RecordOpeningBalanceInput, options?: RecordOptions): Promise<unknown>;
438
468
  }
439
469
  //#endregion
440
470
  //#region src/engine.d.ts
@@ -557,44 +587,79 @@ declare class AccountingEngine {
557
587
  isValidAccountType(code: string): boolean;
558
588
  /** Get account type definition by code */
559
589
  getAccountType(code: string): AccountType | undefined;
560
- /** Get tax codes for a region */
561
- getTaxCodesForRegion(region: string): TaxCode[];
590
+ /**
591
+ * Create a pre-configured QueryParser for URL-driven queries against
592
+ * ledger repositories. Returns a mongokit QueryParser with the correct
593
+ * schema and pagination limits for the specified model.
594
+ *
595
+ * @param model - Which ledger model to parse queries for
596
+ * @param overrides - Additional QueryParserOptions to merge
597
+ *
598
+ * @example
599
+ * ```typescript
600
+ * const parser = engine.createQueryParser('journalEntry');
601
+ * const parsed = parser.parse(req.query);
602
+ * const result = await engine.repositories.journalEntries.getAll({
603
+ * ...parsed,
604
+ * filters: { ...parsed.filters, organizationId },
605
+ * });
606
+ * ```
607
+ */
608
+ createQueryParser(model: 'account' | 'journalEntry' | 'fiscalPeriod' | 'budget' | 'reconciliation' | 'journal', overrides?: Partial<QueryParserOptions>): QueryParser;
562
609
  private _buildReports;
563
610
  }
564
611
  declare function createAccountingEngine(config: AccountingEngineConfig): AccountingEngine;
565
612
  //#endregion
566
- //#region src/utils/repartition-tax.d.ts
567
- /**
568
- * Resolves an `accountRole` (e.g. `'collected'`, `'recoverable'`,
569
- * `'transition'`) into the actual account ObjectId for the consumer's
570
- * chart of accounts. Implementations typically close over an account
571
- * cache loaded per organization at engine start.
572
- */
573
- type RepartitionAccountResolver = (role: string, taxCode: TaxCode, input: TaxLineInput) => unknown;
574
- interface RepartitionGeneratorOptions {
575
- /** Country pack — provides tax codes and optional resolver. */
576
- country: CountryPack;
577
- /** Required: resolve role → account id in the consumer's chart. */
578
- resolveAccount: RepartitionAccountResolver;
579
- /**
580
- * Document type — determines which repartition lines apply. A line
581
- * with `documentTypes: ['invoice']` is skipped when this is `'refund'`.
582
- * Defaults to `'invoice'`.
583
- */
584
- documentType?: 'invoice' | 'refund' | 'payment';
613
+ //#region src/repositories/reconciliation.repository.d.ts
614
+ interface MatchHookItem {
615
+ entry: unknown;
616
+ itemIndex: number;
617
+ debit: number;
618
+ credit: number;
619
+ amountCurrency: number | null;
620
+ exchangeRate: number | null;
585
621
  }
586
622
  /**
587
- * Build a `TaxLineGenerator` that expands each hit `taxCode` into one
588
- * journal item per repartition line. Taxes without `repartition` fall
589
- * back to a single-line generator using the direction-implied account.
623
+ * Context passed to `before:match` and `after:match` hooks.
624
+ *
625
+ * - `before:match`: fired after validation but before the matchingNumber is
626
+ * stamped and the reconciliation doc is created. Throw to abort.
627
+ * - `after:match`: fired after the reconciliation doc is persisted. Used by
628
+ * fxRealizationPlugin, and can be used by invoice packages to update
629
+ * payment state.
590
630
  */
591
- declare function createRepartitionTaxGenerator(options: RepartitionGeneratorOptions): TaxLineGenerator;
631
+ interface MatchHookContext {
632
+ /** The input that was passed to match(). */
633
+ input: MatchInput;
634
+ /** Validated + enriched item snapshots with debit/credit/currency info. */
635
+ items: MatchHookItem[];
636
+ /** Shared currency across all items, or null if mixed. */
637
+ sharedCurrency: string | null;
638
+ /** The matching number (auto-generated or caller-provided). */
639
+ matchingNumber: string;
640
+ /** Totals for the matched set. */
641
+ debitTotal: number;
642
+ creditTotal: number;
643
+ isFullReconcile: boolean;
644
+ /** The created reconciliation document (only in after:match). */
645
+ reconciliation?: unknown;
646
+ session: ClientSession | null;
647
+ }
592
648
  /**
593
- * Helper for packs that want the standard "role → account-type code"
594
- * mapping without writing their own resolver. Returns the function you
595
- * stuff into `CountryPackInput.resolveTaxRepartitionAccountCode`.
649
+ * Context passed to `before:unmatch` and `after:unmatch` hooks.
596
650
  */
597
- declare function defaultResolveTaxRepartitionAccountCode(country: CountryPack): (role: string, tax: TaxCode) => string | undefined;
651
+ interface UnmatchHookContext {
652
+ matchingNumber: string;
653
+ /** The reconciliation document being removed. */
654
+ reconciliation: Record<string, unknown>;
655
+ /** The items that will be / were unmatched. */
656
+ items: Array<{
657
+ entry: unknown;
658
+ itemIndex: number;
659
+ }>;
660
+ organizationId?: unknown;
661
+ session: ClientSession | null;
662
+ }
598
663
  //#endregion
599
664
  //#region src/utils/account-helpers.d.ts
600
665
  /**
@@ -816,4 +881,4 @@ interface PostingResult {
816
881
  idempotencyKeys?: string[];
817
882
  }
818
883
  //#endregion
819
- export { type AccountCode, type AccountForeignBalance, type AccountRepository, type AccountSummary, type AccountType, AccountingEngine, type AccountingEngineConfig, AccountingError, type ActorContext, type AgedBalanceOptions, type AgedBalanceParams, type AgedBalanceReport, type AgedBalanceRow, type AgedBucketConfig, type AuditConfig, type BalanceSheetReport, type BudgetVsActualOptions, type BudgetVsActualParams, type BudgetVsActualReport, type BudgetVsActualRow, type BulkCreateInput, type BulkCreateResult, CATEGORIES, CATEGORY_KEYS, CURRENCIES, type CashFlowCategory, type CashFlowReport, type CashFlowSection, type CategoryKey, type Cents, type CountryPack, type CountryPackInput, type CreateLockPluginOptions, type CreditLimitPluginOptions, type Currency, DEFAULT_BUCKETS, type DailyLockPluginOptions, type DateOption, type DateRange, type DimensionBreakdownOptions, type DimensionBreakdownParams, type DimensionBreakdownReport, type DimensionBreakdownRow, type DimensionDefinition, type EntryState, Errors, type ExportField, type ExportFieldMap, type FieldError, type FiscalLockPluginOptions, type FiscalPeriodSummary, type FlatJournalRow, type FxRealizationPluginOptions, type GeneralLedgerAccount, type GeneralLedgerReport, type IncomeStatementReport, type IntrospectAPI, JOURNAL_CODES, JOURNAL_TYPES, type JournalEntryRepository, type JournalItem, type JournalItemRef, type JournalRepository, type JournalSchemaOptions, type JournalTemplate, type JournalType, type LedgerEntry, type LedgerModels, type LedgerPaginationConfig, type LedgerRepositories, type LedgerRepositoryPlugins, type LockAccountSelector, type LockHit, type LockResolver, type LockResolverContext, type Logger, type MainType, type MatchInput, type ModelNames, Money, type MultiCurrencyConfig, type MultiTenantConfig, type NormalBalance, type OpenItem, type PartnerLedgerLine, type PartnerLedgerOptions, type PartnerLedgerParams, type PartnerLedgerReport, type PeriodResolverOptions, type PopulatedJournalEntry, type PostOptions, type PostingContract, type PostingResult, type ReconciliationRepository, type RecordAPI, type RecordAdjustmentInput, type RecordAdjustmentLine, type RecordExpenseInput, type RecordOptions, type RecordPaymentInput, type RecordSaleInput, type RecordTransferInput, type RepartitionAccountResolver, type RepartitionGeneratorOptions, type ReportAccount, type ReportCategory, type ReportDescriptor, type ReportGroup, type ResolvedModelNames, type RevaluationOptions, type RevaluationParams, type RevaluationRate, type RevaluationReport, type RevaluationResult, type ReverseOptions, type ReverseResult, type SchemaOptions, type SeedOptions, type SeedResult, type Cents$1 as SemanticCents, type SessionResult, type StatementType, type StrictnessConfig, type SubledgerJournalItem, type SubledgerPostingInput, type TaxCode, type TaxCodesByRegion, type TaxDetail, type TaxExigibility, type TaxInput, type TaxLockPluginOptions, type TaxMetadata, type TaxRepartitionLine, type TaxReport, type TaxReportLine, type TaxReportTemplate, type TaxReturnSummary, type TotalAccountOp, type TrialBalanceReport, type TrialBalanceRow, type WatermarkResolverOptions, acquireSession, add, allocate, buildAccountTypeMap, buildDimensionFields, buildDimensionIndexes, buildItemFilters, buildRevaluationEntry, calculateTotal, closeFiscalPeriod, computeEndingBalance, computeRevaluation, createAccountingEngine, createLockPlugin, createModels, createRepartitionTaxGenerator, createRepositories, creditLimitPlugin, dailyLockPlugin, defaultLogger, defaultResolveTaxRepartitionAccountCode, defineCountryPack, doubleEntryPlugin, exportToCsv, finalizeSession, fiscalLockPlugin, flattenJournalEntries, format, formatPlain, fromDecimal, fxRealizationPlugin, generateAgedBalance, generateBalanceSheet, generateBudgetVsActual, generateCashFlow, generateDimensionBreakdown, generateGeneralLedger, generateIncomeStatement, generatePartnerLedger, generateRevaluation, generateTrialBalance, getCurrency, getCustomJournalTypes, getDateRange, getFiscalYearStart, getJournalType, getJournalTypeCodes, getMinorUnit, getNormalBalance, idempotencyPlugin, isBalanceSheet, isIncomeStatement, isValidCategory, isValidCurrency, isValidJournalType, isVirtualTaxAccount, multiply, parseCents, percentage, periodResolver, quickbooksFieldMap, registerJournalType, reopenFiscalPeriod, resolveModelNames, splitTaxExclusive, splitTaxInclusive, subtract, taxLockPlugin, toDecimal, universalFieldMap, watermarkResolver };
884
+ export { type AccountCode, type AccountForeignBalance, type AccountRepository, type AccountSummary, type AccountType, AccountingEngine, type AccountingEngineConfig, AccountingError, type ActorContext, type AgedBalanceOptions, type AgedBalanceParams, type AgedBalanceReport, type AgedBalanceRow, type AgedBucketConfig, type AuditConfig, type BalanceSheetReport, type BudgetVsActualOptions, type BudgetVsActualParams, type BudgetVsActualReport, type BudgetVsActualRow, type BulkCreateInput, type BulkCreateResult, CATEGORIES, CATEGORY_KEYS, CURRENCIES, type CashFlowCategory, type CashFlowReport, type CashFlowSection, type CategoryKey, type Cents, type CountryPack, type CountryPackInput, type CreateLockPluginOptions, type CreditLimitPluginOptions, type Currency, DEFAULT_BUCKETS, type DailyLockPluginOptions, type DateOption, type DateRange, type DimensionBreakdownOptions, type DimensionBreakdownParams, type DimensionBreakdownReport, type DimensionBreakdownRow, type DimensionDefinition, type EntryState, Errors, type ExportField, type ExportFieldMap, type FieldError, type FiscalLockPluginOptions, type FiscalPeriodSummary, type FlatJournalRow, type FxRealizationPluginOptions, type GeneralLedgerAccount, type GeneralLedgerReport, type IncomeStatementReport, type IntrospectAPI, JOURNAL_CODES, JOURNAL_TYPES, type JournalEntryRepository, type JournalItem, type JournalItemRef, type JournalRepository, type JournalSchemaOptions, type JournalTemplate, type JournalType, type LedgerEntry, type LedgerModels, type LedgerPaginationConfig, type LedgerRepositories, type LedgerRepositoryPlugins, type LockAccountSelector, type LockHit, type LockResolver, type LockResolverContext, type Logger, type MainType, type MatchHookContext, type MatchHookItem, type MatchInput, type ModelNames, Money, type MultiCurrencyConfig, type MultiTenantConfig, type NormalBalance, type OpenItem, type PartnerLedgerLine, type PartnerLedgerOptions, type PartnerLedgerParams, type PartnerLedgerReport, type PeriodResolverOptions, type PopulatedJournalEntry, type PostOptions, type PostingContract, type PostingResult, type ReconciliationRepository, type RecordAPI, type RecordAdjustmentInput, type RecordAdjustmentLine, type RecordExpenseInput, type RecordOptions, type RecordPaymentInput, type RecordSaleInput, type RecordTransferInput, type ReportAccount, type ReportCategory, type ReportDescriptor, type ReportGroup, type ResolvedModelNames, type RevaluationOptions, type RevaluationParams, type RevaluationRate, type RevaluationReport, type RevaluationResult, type ReverseOptions, type ReverseResult, type SchemaOptions, type SeedOptions, type SeedResult, type Cents$1 as SemanticCents, type SessionResult, type StatementType, type StrictnessConfig, type SubledgerJournalItem, type SubledgerPostingInput, type TaxDetail, type TaxMetadata, type TotalAccountOp, type TrialBalanceReport, type TrialBalanceRow, type UnmatchHookContext, type WatermarkResolverOptions, acquireSession, add, allocate, buildAccountTypeMap, buildDimensionFields, buildDimensionIndexes, buildItemFilters, buildRevaluationEntry, calculateTotal, closeFiscalPeriod, computeEndingBalance, computeRevaluation, createAccountingEngine, createLockPlugin, createModels, createRepositories, creditLimitPlugin, dailyLockPlugin, defaultLogger, defineCountryPack, doubleEntryPlugin, exportToCsv, finalizeSession, fiscalLockPlugin, flattenJournalEntries, format, formatPlain, fromDecimal, fxRealizationPlugin, generateAgedBalance, generateBalanceSheet, generateBudgetVsActual, generateCashFlow, generateDimensionBreakdown, generateGeneralLedger, generateIncomeStatement, generatePartnerLedger, generateRevaluation, generateTrialBalance, getCurrency, getCustomJournalTypes, getDateRange, getFiscalYearStart, getJournalType, getJournalTypeCodes, getMinorUnit, getNormalBalance, idempotencyPlugin, isBalanceSheet, isIncomeStatement, isValidCategory, isValidCurrency, isValidJournalType, isVirtualTaxAccount, multiply, parseCents, percentage, periodResolver, quickbooksFieldMap, registerJournalType, reopenFiscalPeriod, resolveModelNames, splitTaxExclusive, splitTaxInclusive, subtract, toDecimal, universalFieldMap, watermarkResolver };