@happyvertical/smrt-ledgers 0.57.2 → 0.57.4

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.
Files changed (38) hide show
  1. package/AGENTS.md +9 -0
  2. package/README.md +73 -0
  3. package/dist/chunks/{Account-b0RgfbjM.js → Account-IFuMKhPt.js} +42 -8
  4. package/dist/chunks/Account-IFuMKhPt.js.map +1 -0
  5. package/dist/chunks/Ledger-DwxK6NRF.js +68 -0
  6. package/dist/chunks/Ledger-DwxK6NRF.js.map +1 -0
  7. package/dist/collections/JournalEntries.d.ts +26 -0
  8. package/dist/collections/JournalEntries.d.ts.map +1 -1
  9. package/dist/collections/Journals.d.ts.map +1 -1
  10. package/dist/collections/Ledgers.d.ts +6 -0
  11. package/dist/collections/Ledgers.d.ts.map +1 -0
  12. package/dist/collections/index.d.ts +1 -0
  13. package/dist/collections/index.d.ts.map +1 -1
  14. package/dist/index.d.ts +5 -2
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +380 -17
  17. package/dist/index.js.map +1 -1
  18. package/dist/manifest.json +639 -13
  19. package/dist/models/Account.d.ts +4 -0
  20. package/dist/models/Account.d.ts.map +1 -1
  21. package/dist/models/Journal.d.ts +9 -0
  22. package/dist/models/Journal.d.ts.map +1 -1
  23. package/dist/models/JournalEntry.d.ts +10 -0
  24. package/dist/models/JournalEntry.d.ts.map +1 -1
  25. package/dist/models/Ledger.d.ts +18 -0
  26. package/dist/models/Ledger.d.ts.map +1 -0
  27. package/dist/models/index.d.ts +1 -0
  28. package/dist/models/index.d.ts.map +1 -1
  29. package/dist/postings.d.ts +33 -0
  30. package/dist/postings.d.ts.map +1 -0
  31. package/dist/recipes.d.ts +9 -0
  32. package/dist/recipes.d.ts.map +1 -1
  33. package/dist/smrt-knowledge.json +475 -9
  34. package/dist/types.d.ts +23 -0
  35. package/dist/types.d.ts.map +1 -1
  36. package/dist/types.js.map +1 -1
  37. package/package.json +5 -5
  38. package/dist/chunks/Account-b0RgfbjM.js.map +0 -1
package/AGENTS.md CHANGED
@@ -24,6 +24,15 @@ PII-conscious variable selection: `tenantId`, `sourceRef` (may reference custome
24
24
 
25
25
  ## Balance Enforcement
26
26
 
27
+ Named `Ledger` scopes freeze owner, currency and balance mode at creation.
28
+ `exact-integer` mode requires safe integer minor units and exact equality; assigned
29
+ accounts freeze scope/owner/type and cannot be deleted. Posted scoped journals and
30
+ lines are immutable, including void/delete; use compensating postings.
31
+ `postReceivable`/`postPayable`/`postSettlement` require exact ledgers and use one
32
+ transactional claim per tenant/ledger/key with payload-digest replay validation.
33
+ See README for ownership, reversal, aging and dialect contracts.
34
+
35
+
27
36
  `journal.post()` validates `Math.abs(totalDebits - totalCredits) < BALANCE_EPSILON` where `BALANCE_EPSILON = 0.01` (float rounding tolerance). Unbalanced journals cannot be posted.
28
37
 
29
38
  **This package is unit-agnostic** — `debit` / `credit` are plain DECIMAL numbers and the balance check only compares the two sides, so it holds for whatever unit the posting module uses. As of #2401, journals posted from `@happyvertical/smrt-commerce` (`Payment.recordPayment()`, `Invoice.recognizeRevenue()`) carry **integer minor units**, which balance exactly rather than merely within the epsilon. A consumer mixing modules that post in different units will get arithmetically balanced but semantically meaningless journals; pick one unit per ledger.
package/README.md CHANGED
@@ -2,6 +2,66 @@
2
2
 
3
3
  Double-entry accounting ledger for the s-m-r-t framework. Hierarchical chart of accounts, journal lifecycle with immutability after posting, and balance enforcement with epsilon tolerance.
4
4
 
5
+ ## Exact ledgers and counterparties
6
+
7
+ Create a `Ledger` with `balanceMode: 'exact-integer'` and an ISO currency when
8
+ the accounting scope stores minor units. Accounts and journals assigned to that
9
+ ledger must share its tenant and currency; posting rejects fractional or unsafe
10
+ amounts and requires exactly equal debit and credit totals. Existing journals
11
+ without a ledger retain the compatible tolerant decimal rule. Direct entry
12
+ writes also require an accessible same-owner journal and matching account/journal
13
+ ledger scope; legacy journals cannot write movements on scoped accounts. An
14
+ existing account cannot change ledger scope, including adoption from an unassigned
15
+ account; create a fresh scoped account instead. Scoped-account creation validates
16
+ the referenced ledger owner. `createChild()` inherits the persisted scoped parent
17
+ ledger and owner and rejects conflicting overrides.
18
+
19
+ `JournalEntry` carries opaque `counterpartyKind` / `counterpartyId` values,
20
+ plus an optional `dueDate`. `JournalEntryCollection.getCounterpartyBalances()`
21
+ reports posted AR/AP movements for caller-selected accounts. Aging is an
22
+ open-item report: the original line needs a source reference and due date, and
23
+ the later settlement uses `settlesSourceRef`; do not infer aging from a net
24
+ counterparty balance.
25
+
26
+ Use `postReceivable`, `postPayable`, or `postSettlement` for exact ledger
27
+ events. They take a tenant-scoped idempotency key and create journal plus lines
28
+ under the framework's atomic retry claim. A replay with changed content is
29
+ refused. Refunds and disputes must post a separate compensating entry with a
30
+ new key; posted ledger journals and their lines cannot be edited, deleted, or
31
+ voided. Reverse the debit/credit accounts and set `settlesSourceRef` to the
32
+ original open item when reducing it. Partial reversals use the partial integer
33
+ amount; full reversals use the remaining amount. Commerce/sales owns deciding
34
+ that amount and retaining the external payment/refund event, including disputes
35
+ after payout; ledgers never initiates a money transfer. Retry the same key after
36
+ a crash between external payout completion and ledger posting. A failed ledger
37
+ transaction rolls back the journal, lines and retry receipt together. Manual
38
+ draft edits and posting claim the parent journal revision in their transaction;
39
+ a concurrent loser fails closed and must reload before retrying.
40
+
41
+ Keys are unique within `(tenantId, ledgerId)` and bind all accounting inputs,
42
+ including an explicitly provided date. Omitted dates use the first successful
43
+ posting time. Caller references must uniquely identify each open item within the
44
+ selected account set. Use `normalBalance: 'credit'` for AP aging/balances (AR is
45
+ debit-normal by default). Balance reports use `from`/`to`; aging uses `from`/`asOf`. Choose a `from`
46
+ that includes the original obligation. An out-of-order settlement is included
47
+ once its source exists; future-dated movements are excluded from historical
48
+ reports. Negative balances/credits remain visible in balances, not aging buckets.
49
+
50
+ Ledger currency, owner and balance mode are immutable. Amounts are safe integer
51
+ minor units with zero epsilon; helpers never round, allocate residuals or convert
52
+ currency. Sales owns deterministic allocation rounding and residual assignment;
53
+ commerce owns original gross/tax/fee amounts. Each boundary must pass reconciled
54
+ integers, e.g. a CAD 100.00 worker co-op invoice posts 10000 debit to receivables
55
+ and 10000 credit to project revenue. A CAD 40.00 settlement reverses 4000 of that
56
+ receivable, leaving 6000. Legacy unassigned journals retain their existing void
57
+ and decimal behavior.
58
+
59
+ The transactional posting and subledger suites cover SQLite and PostgreSQL.
60
+ DuckDB cannot provision this package's existing `JournalEntry` cascading foreign
61
+ keys: the framework explicitly rejects DuckDB's unsupported ON UPDATE CASCADE.
62
+ It is not a supported exact-ledger runtime; no relationship is weakened to make
63
+ that dialect appear compatible.
64
+
5
65
  ## Installation
6
66
 
7
67
  ```bash
@@ -173,3 +233,16 @@ the exported `Account` and `AccountCollection` are unchanged.
173
233
 
174
234
  See [`AGENTS.md`](./AGENTS.md) for package architecture, invariants, validation,
175
235
  and contributor guidance.
236
+
237
+ Accounting identities are insert-only on their first save: an explicit slug/context
238
+ collision cannot replace an existing ledger, account, journal, or line. Load the
239
+ existing object to update it through its lifecycle guards. This also applies to
240
+ legacy unassigned objects; natural-key replacement is not a supported update path.
241
+ Legacy tenant journals may still use shared global accounts that have no ledger;
242
+ scoped journals require accounts owned by their ledger.
243
+
244
+ A journal chooses its ledger scope at creation. Persisted draft journals cannot
245
+ move between ledgers or change between unassigned and scoped, even when empty.
246
+ Create a new journal for another scope; this prevents an in-flight legacy line
247
+ from entering an exact ledger after its validation. Ordinary same-scope draft
248
+ edits and legacy decimal journals retain their existing behavior.
@@ -1,5 +1,6 @@
1
- import { SmrtHierarchical, field, smrt } from "@happyvertical/smrt-core";
2
- import { TenantScoped, tenantId } from "@happyvertical/smrt-tenancy";
1
+ import { t as Ledger } from "./Ledger-DwxK6NRF.js";
2
+ import { SmrtHierarchical, field, foreignKey, smrt } from "@happyvertical/smrt-core";
3
+ import { TenantScoped, getTenantId, isSuperAdminBypass, isTenancyEnabled, tenantId } from "@happyvertical/smrt-tenancy";
3
4
  //#region src/models/Account.ts
4
5
  var __defProp = Object.defineProperty;
5
6
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -22,6 +23,7 @@ var Account = class extends SmrtHierarchical {
22
23
  name = "";
23
24
  description = "";
24
25
  type = "asset";
26
+ ledgerId = null;
25
27
  active = true;
26
28
  /**
27
29
  * Extensible metadata
@@ -29,14 +31,34 @@ var Account = class extends SmrtHierarchical {
29
31
  metadata = {};
30
32
  constructor(options = {}) {
31
33
  super(options);
34
+ if (options.tenantId !== void 0) this.tenantId = options.tenantId;
32
35
  if (options.number !== void 0) this.number = options.number;
33
36
  if (options.name !== void 0) this.name = options.name;
34
37
  if (options.description !== void 0) this.description = options.description;
35
38
  if (options.type !== void 0) this.type = options.type;
39
+ if (options.ledgerId !== void 0) this.ledgerId = options.ledgerId;
36
40
  if (options.parentId !== void 0) this.parentId = options.parentId;
37
41
  if (options.active !== void 0) this.active = options.active;
38
42
  if (options.metadata !== void 0) this.metadata = options.metadata;
39
43
  }
44
+ async validateBeforeSave() {
45
+ await super.validateBeforeSave();
46
+ this.requireInsertOnSave({ preserveDerivedSlug: true });
47
+ if (this.ledgerId) {
48
+ const { LedgerCollection } = await import("../index.js").then((n) => n.t);
49
+ const ledger = await (await LedgerCollection.create(this.options)).get({ id: this.ledgerId }, { cache: false });
50
+ const owner = this.tenantId ?? (isTenancyEnabled() && !isSuperAdminBypass() ? getTenantId() ?? null : null);
51
+ if (!ledger || ledger.tenantId !== owner) throw new Error("Scoped account requires an accessible ledger with the same owner");
52
+ }
53
+ if (this.id) {
54
+ const stored = await this.db.get(this.tableName, { id: this.id });
55
+ if (stored && (stored.ledger_id !== this.ledgerId || stored.ledger_id && (stored.tenant_id !== this.tenantId || stored.type !== this.type))) throw new Error("Ledger account scope, owner and type are immutable");
56
+ }
57
+ }
58
+ async delete(options = {}) {
59
+ if ((this.id ? await this.db.get(this.tableName, { id: this.id }) : null)?.ledger_id) throw new Error("Ledger accounts cannot be deleted; deactivate them instead");
60
+ await super.delete(options);
61
+ }
40
62
  /**
41
63
  * Check if this is a top-level account (no parent)
42
64
  */
@@ -79,7 +101,7 @@ var Account = class extends SmrtHierarchical {
79
101
  */
80
102
  async getBalance(asOfDate) {
81
103
  if (!this.id) return 0;
82
- const { JournalEntryCollection } = await import("../index.js").then((n) => n.t);
104
+ const { JournalEntryCollection } = await import("../index.js").then((n) => n.n);
83
105
  return await (await JournalEntryCollection.create(this.options)).getAccountBalance(this.id, asOfDate);
84
106
  }
85
107
  /**
@@ -87,11 +109,19 @@ var Account = class extends SmrtHierarchical {
87
109
  */
88
110
  async createChild(options) {
89
111
  if (!this.id) throw new Error("Account must be saved before creating children");
90
- const { AccountCollection } = await import("../index.js").then((n) => n.n);
91
- const account = await (await AccountCollection.create(this.options)).create({
112
+ const { AccountCollection } = await import("../index.js").then((n) => n.r);
113
+ const collection = await AccountCollection.create(this.options);
114
+ const parent = await collection.get({ id: this.id }, { cache: false });
115
+ if (!parent) throw new Error("Parent account must be persisted and accessible");
116
+ if (parent.ledgerId && (options.ledgerId !== void 0 && options.ledgerId !== parent.ledgerId || options.tenantId !== void 0 && options.tenantId !== parent.tenantId)) throw new Error("Scoped children must inherit the parent ledger and owner");
117
+ const account = await collection.create({
92
118
  ...options,
93
- parentId: this.id,
94
- type: this.type
119
+ ...parent.ledgerId ? {
120
+ ledgerId: parent.ledgerId,
121
+ tenantId: parent.tenantId
122
+ } : {},
123
+ parentId: parent.id,
124
+ type: parent.type
95
125
  });
96
126
  await account.save();
97
127
  return account;
@@ -103,6 +133,10 @@ __decorateClass([field({ description: "The account number in your chart of accou
103
133
  __decorateClass([field({ description: "What the account is called." })], Account.prototype, "name", 2);
104
134
  __decorateClass([field({ description: "What the account is used for." })], Account.prototype, "description", 2);
105
135
  __decorateClass([field({ description: "asset, liability, equity, revenue or expense." })], Account.prototype, "type", 2);
136
+ __decorateClass([field({
137
+ description: "The ledger policy this account belongs to.",
138
+ nullable: true
139
+ }), foreignKey(Ledger)], Account.prototype, "ledgerId", 2);
106
140
  __decorateClass([field({ description: "Whether the account is in use; deactivate it instead of deleting it." })], Account.prototype, "active", 2);
107
141
  Account = __decorateClass([TenantScoped({ mode: "optional" }), smrt({
108
142
  tableName: "ledger_accounts",
@@ -123,4 +157,4 @@ Account = __decorateClass([TenantScoped({ mode: "optional" }), smrt({
123
157
  //#endregion
124
158
  export { Account as t };
125
159
 
126
- //# sourceMappingURL=Account-b0RgfbjM.js.map
160
+ //# sourceMappingURL=Account-IFuMKhPt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Account-IFuMKhPt.js","names":[],"sources":["../../src/models/Account.ts"],"sourcesContent":["/**\n * Account model - Chart of accounts entry\n *\n * Represents a single account in the chart of accounts.\n * The 5 core types: Asset, Liability, Equity, Revenue, Expense\n */\n\nimport {\n field,\n foreignKey,\n SmrtHierarchical,\n smrt,\n} from '@happyvertical/smrt-core';\nimport {\n getTenantId,\n isSuperAdminBypass,\n isTenancyEnabled,\n TenantScoped,\n tenantId,\n} from '@happyvertical/smrt-tenancy';\nimport type { AccountOptions, AccountTreeNode, AccountType } from '../types';\nimport { Ledger } from './Ledger';\n\n@TenantScoped({ mode: 'optional' })\n@smrt({\n // Own table, never the derived `accounts`: smrt-messages declares an\n // unrelated `Account` on that table (#3098). Existing `accounts`-hosted\n // ledgers move with `smrt db:migrate-ledger-accounts`.\n tableName: 'ledger_accounts',\n api: { include: ['list', 'get', 'create', 'update', 'delete'] },\n mcp: { include: ['list', 'get', 'create'] },\n cli: { skipApiCheck: true },\n})\nexport class Account extends SmrtHierarchical { static __smrtPackage__ = \"@happyvertical/smrt-ledgers\";\n /**\n * Tenant ID for multi-tenancy support (nullable for global accounts)\n */\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n /**\n * Account number (e.g., \"1000\", \"5030\")\n */\n @field({ description: 'The account number in your chart of accounts.' })\n number: string = '';\n\n /**\n * Account name (e.g., \"Cash\", \"Coffee Expense\")\n */\n @field({ description: 'What the account is called.' })\n name: string = '';\n\n /**\n * Account description\n */\n @field({ description: 'What the account is used for.' })\n description: string = '';\n\n /**\n * Account type - one of the 5 core types\n */\n @field({ description: 'asset, liability, equity, revenue or expense.' })\n type: AccountType = 'asset';\n\n /** Accounting scope; null is a legacy account usable only by legacy journals. */\n @field({\n description: 'The ledger policy this account belongs to.',\n nullable: true,\n })\n @foreignKey(Ledger)\n ledgerId: string | null = null;\n\n // parentId inherited from SmrtHierarchical (null = top-level)\n\n /**\n * Whether the account is active\n */\n @field({\n description:\n 'Whether the account is in use; deactivate it instead of deleting it.',\n })\n active: boolean = true;\n\n /**\n * Extensible metadata\n */\n metadata: Record<string, unknown> = {};\n\n constructor(options: AccountOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.number !== undefined) this.number = options.number;\n if (options.name !== undefined) this.name = options.name;\n if (options.description !== undefined)\n this.description = options.description;\n if (options.type !== undefined) this.type = options.type;\n if (options.ledgerId !== undefined) this.ledgerId = options.ledgerId;\n if (options.parentId !== undefined) this.parentId = options.parentId;\n if (options.active !== undefined) this.active = options.active;\n if (options.metadata !== undefined) this.metadata = options.metadata;\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.ledgerId) {\n const { LedgerCollection } = await import('../collections/Ledgers');\n const ledger = await (await LedgerCollection.create(this.options)).get(\n { id: this.ledgerId },\n { cache: false },\n );\n // Model validation precedes optional tenancy auto-population.\n const owner =\n this.tenantId ??\n (isTenancyEnabled() && !isSuperAdminBypass()\n ? (getTenantId() ?? null)\n : null);\n if (!ledger || ledger.tenantId !== owner)\n throw new Error(\n 'Scoped account requires an accessible ledger with the same owner',\n );\n }\n if (this.id) {\n const stored = await this.db.get(this.tableName, { id: this.id });\n if (\n stored &&\n (stored.ledger_id !== this.ledgerId ||\n (stored.ledger_id &&\n (stored.tenant_id !== this.tenantId || stored.type !== this.type)))\n )\n throw new Error('Ledger account scope, owner and type are immutable');\n }\n }\n\n async delete(\n options: Parameters<SmrtHierarchical['delete']>[0] = {},\n ): Promise<void> {\n const stored = this.id\n ? await this.db.get(this.tableName, { id: this.id })\n : null;\n if (stored?.ledger_id)\n throw new Error(\n 'Ledger accounts cannot be deleted; deactivate them instead',\n );\n await super.delete(options);\n }\n\n /**\n * Check if this is a top-level account (no parent)\n */\n isTopLevel(): boolean {\n return this.parentId === null;\n }\n\n /**\n * Check if this is a debit-normal account (Asset, Expense)\n * Debit-normal accounts increase with debits\n */\n isDebitNormal(): boolean {\n return this.type === 'asset' || this.type === 'expense';\n }\n\n /**\n * Check if this is a credit-normal account (Liability, Equity, Revenue)\n * Credit-normal accounts increase with credits\n */\n isCreditNormal(): boolean {\n return (\n this.type === 'liability' ||\n this.type === 'equity' ||\n this.type === 'revenue'\n );\n }\n\n // Hierarchy traversal (getParent / getChildren / getAncestors /\n // getDescendants / getHierarchy / moveTo) provided by SmrtHierarchical.\n // Account-specific helpers (getFullPath / getBalance / createChild /\n // toTreeNode) remain below.\n\n /**\n * Get full account path (e.g., \"Assets > Current > Cash\")\n */\n async getFullPath(): Promise<string> {\n const ancestors = await this.getAncestors();\n const names = [...ancestors.map((a) => a.name), this.name];\n return names.join(' > ');\n }\n\n /**\n * Build tree node for this account and its children\n */\n async toTreeNode(): Promise<AccountTreeNode> {\n const children = await this.getChildren();\n const childNodes = await Promise.all(children.map((c) => c.toTreeNode()));\n return {\n account: this,\n children: childNodes,\n };\n }\n\n /**\n * Get the current balance of this account\n */\n async getBalance(asOfDate?: Date): Promise<number> {\n if (!this.id) return 0;\n const { JournalEntryCollection } = await import(\n '../collections/JournalEntries'\n );\n const collection = await JournalEntryCollection.create(this.options);\n return await collection.getAccountBalance(this.id, asOfDate);\n }\n\n /**\n * Create a sub-account under this account\n */\n async createChild(\n options: Omit<AccountOptions, 'parentId' | 'type'>,\n ): Promise<Account> {\n if (!this.id) {\n throw new Error('Account must be saved before creating children');\n }\n const { AccountCollection } = await import('../collections/Accounts');\n const collection = await AccountCollection.create(this.options);\n const parent = await collection.get({ id: this.id }, { cache: false });\n if (!parent)\n throw new Error('Parent account must be persisted and accessible');\n if (\n parent.ledgerId &&\n ((options.ledgerId !== undefined &&\n options.ledgerId !== parent.ledgerId) ||\n (options.tenantId !== undefined &&\n options.tenantId !== parent.tenantId))\n )\n throw new Error(\n 'Scoped children must inherit the parent ledger and owner',\n );\n const account = await collection.create({\n ...options,\n ...(parent.ledgerId\n ? { ledgerId: parent.ledgerId, tenantId: parent.tenantId }\n : {}),\n parentId: parent.id,\n type: parent.type, // Inherit persisted type from parent\n });\n await account.save();\n return account;\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ import { SmrtObject, field, smrt } from "@happyvertical/smrt-core";
2
+ import { TenantScoped, tenantId } from "@happyvertical/smrt-tenancy";
3
+ //#region src/models/Ledger.ts
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, {
7
+ enumerable: true,
8
+ configurable: true,
9
+ writable: true,
10
+ value
11
+ }) : obj[key] = value;
12
+ var __decorateClass = (decorators, target, key, kind) => {
13
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
14
+ for (var i = decorators.length - 1, decorator; i >= 0; i--) if (decorator = decorators[i]) result = (kind ? decorator(target, key, result) : decorator(result)) || result;
15
+ if (kind && result) __defProp(target, key, result);
16
+ return result;
17
+ };
18
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
19
+ var Ledger = class extends SmrtObject {
20
+ tenantId = null;
21
+ name = "";
22
+ currency = "USD";
23
+ balanceMode = "tolerant";
24
+ constructor(options = {}) {
25
+ super(options);
26
+ if (options.tenantId !== void 0) this.tenantId = options.tenantId;
27
+ if (options.name !== void 0) this.name = options.name;
28
+ if (options.currency !== void 0) this.currency = options.currency;
29
+ if (options.balanceMode !== void 0) this.balanceMode = options.balanceMode;
30
+ }
31
+ async delete() {
32
+ throw new Error("Ledgers cannot be deleted");
33
+ }
34
+ async validateBeforeSave() {
35
+ await super.validateBeforeSave();
36
+ this.requireInsertOnSave({ preserveDerivedSlug: true });
37
+ if (!["tolerant", "exact-integer"].includes(this.balanceMode)) throw new Error("Unknown ledger balance mode");
38
+ if (this.id) {
39
+ const stored = await this.db.get(this.tableName, { id: this.id });
40
+ if (stored && (stored.currency !== this.currency || stored.balance_mode !== this.balanceMode || stored.tenant_id !== this.tenantId)) throw new Error("Ledger currency, balance mode and owner are immutable");
41
+ }
42
+ if (!this.name.trim()) throw new Error("Ledger name is required");
43
+ if (!/^[A-Z]{3}$/.test(this.currency)) throw new Error("Ledger currency must be an uppercase ISO 4217 code");
44
+ }
45
+ };
46
+ __publicField(Ledger, "__smrtPackage__", "@happyvertical/smrt-ledgers");
47
+ __decorateClass([tenantId({ nullable: true })], Ledger.prototype, "tenantId", 2);
48
+ __decorateClass([field({ description: "The accounting scope name." })], Ledger.prototype, "name", 2);
49
+ __decorateClass([field({ description: "ISO 4217 currency used by this ledger." })], Ledger.prototype, "currency", 2);
50
+ __decorateClass([field({ description: "tolerant accepts decimal units; exact requires integer minor units." })], Ledger.prototype, "balanceMode", 2);
51
+ Ledger = __decorateClass([TenantScoped({ mode: "optional" }), smrt({
52
+ api: { include: [
53
+ "list",
54
+ "get",
55
+ "create",
56
+ "update"
57
+ ] },
58
+ mcp: { include: [
59
+ "list",
60
+ "get",
61
+ "create"
62
+ ] },
63
+ cli: { skipApiCheck: true }
64
+ })], Ledger);
65
+ //#endregion
66
+ export { Ledger as t };
67
+
68
+ //# sourceMappingURL=Ledger-DwxK6NRF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Ledger-DwxK6NRF.js","names":[],"sources":["../../src/models/Ledger.ts"],"sourcesContent":["import { field, SmrtObject, smrt } from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type { LedgerOptions } from '../types';\n\n/**\n * A named accounting scope. Exact ledgers store one currency's minor units and\n * reject fractional entries; legacy journals without a ledger retain the\n * tolerant balance rule for backwards compatibility.\n */\n@TenantScoped({ mode: 'optional' })\n@smrt({\n api: { include: ['list', 'get', 'create', 'update'] },\n mcp: { include: ['list', 'get', 'create'] },\n cli: { skipApiCheck: true },\n})\nexport class Ledger extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-ledgers\";\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n @field({ description: 'The accounting scope name.' })\n name = '';\n\n /** ISO 4217 currency for this ledger's entries. */\n @field({ description: 'ISO 4217 currency used by this ledger.' })\n currency = 'USD';\n\n @field({\n description:\n 'tolerant accepts decimal units; exact requires integer minor units.',\n })\n balanceMode: 'tolerant' | 'exact-integer' = 'tolerant';\n\n constructor(options: LedgerOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.name !== undefined) this.name = options.name;\n if (options.currency !== undefined) this.currency = options.currency;\n if (options.balanceMode !== undefined)\n this.balanceMode = options.balanceMode;\n }\n\n async delete(): Promise<void> {\n throw new Error('Ledgers cannot be deleted');\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 (!['tolerant', 'exact-integer'].includes(this.balanceMode))\n throw new Error('Unknown ledger balance mode');\n if (this.id) {\n const stored = await this.db.get(this.tableName, { id: this.id });\n if (\n stored &&\n (stored.currency !== this.currency ||\n stored.balance_mode !== this.balanceMode ||\n stored.tenant_id !== this.tenantId)\n )\n throw new Error(\n 'Ledger currency, balance mode and owner are immutable',\n );\n }\n if (!this.name.trim()) throw new Error('Ledger name is required');\n if (!/^[A-Z]{3}$/.test(this.currency))\n throw new Error('Ledger currency must be an uppercase ISO 4217 code');\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAeO,IAAM,SAAN,cAAqB,WAAW;CAErC,WAA0B;CAG1B,OAAO;CAIP,WAAW;CAMX,cAA4C;CAE5C,YAAY,UAAyB,CAAC,GAAG;EACvC,MAAM,OAAO;EACb,IAAI,QAAQ,aAAa,KAAA,GAAW,KAAK,WAAW,QAAQ;EAC5D,IAAI,QAAQ,SAAS,KAAA,GAAW,KAAK,OAAO,QAAQ;EACpD,IAAI,QAAQ,aAAa,KAAA,GAAW,KAAK,WAAW,QAAQ;EAC5D,IAAI,QAAQ,gBAAgB,KAAA,GAC1B,KAAK,cAAc,QAAQ;CAC/B;CAEA,MAAM,SAAwB;EAC5B,MAAM,IAAI,MAAM,2BAA2B;CAC7C;CAEA,MAAgB,qBAAoC;EAClD,MAAM,MAAM,mBAAmB;EAG/B,KAAK,oBAAoB,EAAE,qBAAqB,KAAK,CAAC;EACtD,IAAI,CAAC,CAAC,YAAY,eAAe,CAAA,CAAE,SAAS,KAAK,WAAW,GAC1D,MAAM,IAAI,MAAM,6BAA6B;EAC/C,IAAI,KAAK,IAAI;GACX,MAAM,SAAS,MAAM,KAAK,GAAG,IAAI,KAAK,WAAW,EAAE,IAAI,KAAK,GAAG,CAAC;GAChE,IACE,WACC,OAAO,aAAa,KAAK,YACxB,OAAO,iBAAiB,KAAK,eAC7B,OAAO,cAAc,KAAK,WAE5B,MAAM,IAAI,MACR,uDACF;EACJ;EACA,IAAI,CAAC,KAAK,KAAK,KAAK,GAAG,MAAM,IAAI,MAAM,yBAAyB;EAChE,IAAI,CAAC,aAAa,KAAK,KAAK,QAAQ,GAClC,MAAM,IAAI,MAAM,oDAAoD;CACxE;AACF;AArDyC,cAA5B,QAAmC,mBAAkB,6BAAA;AAEhE,gBAAA,CADC,SAAS,EAAE,UAAU,KAAK,CAAC,CAAA,GADjB,OAEX,WAAA,YAAA,CAAA;AAGA,gBAAA,CADC,MAAM,EAAE,aAAa,6BAA6B,CAAC,CAAA,GAJzC,OAKX,WAAA,QAAA,CAAA;AAIA,gBAAA,CADC,MAAM,EAAE,aAAa,yCAAyC,CAAC,CAAA,GARrD,OASX,WAAA,YAAA,CAAA;AAMA,gBAAA,CAJC,MAAM,EACL,aACE,sEACJ,CAAC,CAAA,GAdU,OAeX,WAAA,eAAA,CAAA;AAfW,SAAN,gBAAA,CANN,aAAa,EAAE,MAAM,WAAW,CAAC,GACjC,KAAK;CACJ,KAAK,EAAE,SAAS;EAAC;EAAQ;EAAO;EAAU;CAAQ,EAAE;CACpD,KAAK,EAAE,SAAS;EAAC;EAAQ;EAAO;CAAQ,EAAE;CAC1C,KAAK,EAAE,cAAc,KAAK;AAC5B,CAAC,CAAA,GACY,MAAA"}
@@ -29,6 +29,24 @@ export interface PostedJournalMovementOptions {
29
29
  from: Date;
30
30
  to: Date;
31
31
  currency: string;
32
+ /** Select credit-normal AP balances; default is debit-normal AR. */
33
+ normalBalance?: 'debit' | 'credit';
34
+ }
35
+ export interface CounterpartyBalance {
36
+ counterpartyKind: string;
37
+ counterpartyId: string;
38
+ currency: string;
39
+ /** Debit minus credit for asset AR accounts; callers choose the account set. */
40
+ balance: number;
41
+ }
42
+ export interface CounterpartyAgingRow extends CounterpartyBalance {
43
+ sourceRef: string;
44
+ dueDate: Date;
45
+ current: number;
46
+ days1To30: number;
47
+ days31To60: number;
48
+ days61To90: number;
49
+ daysOver90: number;
32
50
  }
33
51
  export declare class JournalEntryCollection extends SmrtCollection<JournalEntry> {
34
52
  static readonly _itemClass: typeof JournalEntry;
@@ -46,6 +64,14 @@ export declare class JournalEntryCollection extends SmrtCollection<JournalEntry>
46
64
  * @returns Array of entries
47
65
  */
48
66
  findByAccount(accountId: string): Promise<JournalEntry[]>;
67
+ /** Posted AR/AP net balances by opaque counterparty for selected accounts. */
68
+ getCounterpartyBalances(options: PostedJournalMovementOptions): Promise<CounterpartyBalance[]>;
69
+ /**
70
+ * Open-item aging. An invoice/allocation line needs a dueDate and sourceRef;
71
+ * a settlement line names that source in settlesSourceRef. This avoids
72
+ * pretending that net counterparty movements are aging.
73
+ */
74
+ getCounterpartyAging(options: PostedJournalMovementOptions, asOf: Date): Promise<CounterpartyAgingRow[]>;
49
75
  /**
50
76
  * Get account balance
51
77
  *
@@ -1 +1 @@
1
- {"version":3,"file":"JournalEntries.d.ts","sourceRoot":"","sources":["../../src/collections/JournalEntries.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D,OAAO,EAAE,YAAY,EAAE,MAAM,2BAAwB,CAAC;AACtD,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,aAAU,CAAC;AAEjE,qFAAqF;AACrF,MAAM,WAAW,qBAAqB;IACpC,sFAAsF;IACtF,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,IAAI,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,IAAI,EAAE,IAAI,CAAC;IACX,EAAE,EAAE,IAAI,CAAC;IACT,QAAQ,EAAE,MAAM,CAAC;CAClB;AAaD,qBAAa,sBAAuB,SAAQ,cAAc,CAAC,YAAY,CAAC;IACtE,MAAM,CAAC,QAAQ,CAAC,UAAU,sBAAgB;IAE1C;;;;;OAKG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAM/D;;;;;OAKG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAM/D;;;;;;;;;OASG;IACG,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC;IA4C5E;;;;;OAKG;IACG,eAAe,CAAC,QAAQ,CAAC,EAAE,IAAI,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IA+BlE;;;;;;OAMG;IACG,qBAAqB,CACzB,KAAK,EAAE,IAAI,EACX,GAAG,EAAE,IAAI,GACR,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC;IAsBzD;;;;;OAKG;IACG,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAWnE;;;;OAIG;IACG,mBAAmB,CACvB,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,qBAAqB,EAAE,CAAC;IAoEnC;;;;;OAKG;IACG,gBAAgB,CACpB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,KAAK,CAAC;QAAE,KAAK,EAAE,YAAY,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IA+ClE;;;;;OAKG;IACG,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAI7D;;;;;;;OAOG;IACG,UAAU,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAI3C;;;;;;;;OAQG;IACG,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;CAOjE"}
1
+ {"version":3,"file":"JournalEntries.d.ts","sourceRoot":"","sources":["../../src/collections/JournalEntries.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"Journals.d.ts","sourceRoot":"","sources":["../../src/collections/Journals.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAmB,CAAC;AAC5C,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,aAAa,EACnB,MAAM,aAAU,CAAC;AAElB,qBAAa,iBAAkB,SAAQ,cAAc,CAAC,OAAO,CAAC;IAC5D,MAAM,CAAC,QAAQ,CAAC,UAAU,iBAAW;IAErC;;;;;OAKG;IACH,OAAO,CAAC,qBAAqB;IAM7B;;;;;OAKG;IACG,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IAQ3D;;;;;;OAMG;IACG,eAAe,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAUjE;;;;;OAKG;IACG,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAO5D;;;;;OAKG;IACG,YAAY,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAO7D;;;;OAIG;IACG,UAAU,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IAItC;;;;OAIG;IACG,UAAU,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IAItC;;;;;OAKG;IACG,iBAAiB,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;IAwClE;;;;;OAKG;IACG,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAS/C;;;;;;OAMG;IACG,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAS/D;;;;;OAKG;IACG,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAO5D;;;;;;OAMG;IACG,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAUlE;;;;;OAKG;IACG,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAIxD;;;;;;;OAOG;IACG,UAAU,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IAItC;;;;;;;;OAQG;IACG,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;CAG5D"}
1
+ {"version":3,"file":"Journals.d.ts","sourceRoot":"","sources":["../../src/collections/Journals.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAmB,CAAC;AAC5C,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,aAAa,EACnB,MAAM,aAAU,CAAC;AAElB,qBAAa,iBAAkB,SAAQ,cAAc,CAAC,OAAO,CAAC;IAC5D,MAAM,CAAC,QAAQ,CAAC,UAAU,iBAAW;IAErC;;;;;OAKG;IACH,OAAO,CAAC,qBAAqB;IAM7B;;;;;OAKG;IACG,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IAQ3D;;;;;;OAMG;IACG,eAAe,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAUjE;;;;;OAKG;IACG,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAO5D;;;;;OAKG;IACG,YAAY,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAO7D;;;;OAIG;IACG,UAAU,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IAItC;;;;OAIG;IACG,UAAU,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IAItC;;;;;OAKG;IACG,iBAAiB,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;IA4ClE;;;;;OAKG;IACG,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAS/C;;;;;;OAMG;IACG,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAS/D;;;;;OAKG;IACG,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAO5D;;;;;;OAMG;IACG,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAUlE;;;;;OAKG;IACG,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAIxD;;;;;;;OAOG;IACG,UAAU,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IAItC;;;;;;;;OAQG;IACG,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;CAG5D"}
@@ -0,0 +1,6 @@
1
+ import { SmrtCollection } from '@happyvertical/smrt-core';
2
+ import { Ledger } from "../models/Ledger.js";
3
+ export declare class LedgerCollection extends SmrtCollection<Ledger> {
4
+ static readonly _itemClass: typeof Ledger;
5
+ }
6
+ //# sourceMappingURL=Ledgers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Ledgers.d.ts","sourceRoot":"","sources":["../../src/collections/Ledgers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAkB,CAAC;AAE1C,qBAAa,gBAAiB,SAAQ,cAAc,CAAC,MAAM,CAAC;IAC1D,MAAM,CAAC,QAAQ,CAAC,UAAU,gBAAU;CACrC"}
@@ -1,4 +1,5 @@
1
1
  export { AccountCollection } from "./Accounts.js";
2
2
  export { JournalEntryCollection } from "./JournalEntries.js";
3
3
  export { JournalCollection } from "./Journals.js";
4
+ export { LedgerCollection } from "./Ledgers.js";
4
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/collections/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAY,CAAC;AAC/C,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAkB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/collections/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAY,CAAC;AAC/C,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAkB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAY,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAW,CAAC"}
package/dist/index.d.ts CHANGED
@@ -62,13 +62,16 @@
62
62
  import './__smrt-register__.js';
63
63
  import './prompts.js';
64
64
  export { AccountCollection } from "./collections/Accounts.js";
65
- export { JournalEntryCollection, type PostedJournalMovement, type PostedJournalMovementOptions, } from "./collections/JournalEntries.js";
65
+ export { type CounterpartyAgingRow, type CounterpartyBalance, JournalEntryCollection, type PostedJournalMovement, type PostedJournalMovementOptions, } from "./collections/JournalEntries.js";
66
66
  export { JournalCollection } from "./collections/Journals.js";
67
+ export { LedgerCollection } from "./collections/Ledgers.js";
67
68
  export { LEDGER_ACCOUNTS_TABLE, LEDGER_ACCOUNTS_TABLE_MOVE, LEGACY_ACCOUNTS_TABLE, LedgerAccountsTableMoveError, type LedgerAccountsTableMoveOptions, type LedgerAccountsTableMovePlan, type LedgerAccountsTableMoveResult, migrateLedgerAccountsTable, planLedgerAccountsTableMove, } from "./migrations/ledger-accounts-table.js";
68
69
  export { Account } from "./models/Account.js";
69
70
  export { Journal } from "./models/Journal.js";
70
71
  export { JournalEntry } from "./models/JournalEntry.js";
72
+ export { Ledger } from "./models/Ledger.js";
73
+ export { type Counterparty, type LedgerPostingInput, postLedgerEntry, postPayable, postReceivable, postSettlement, } from "./postings.js";
71
74
  export { promptMessageOptions, smrtLedgersJournalSummarizePrompt, } from "./prompts.js";
72
75
  export { BookkeepingRecipe } from "./recipes.js";
73
- export type { AccountOptions, AccountTree, AccountTreeNode, AccountType, CreateJournalData, JournalEntryData, JournalEntryOptions, JournalOptions, JournalStatus, TrialBalanceRow, } from "./types.js";
76
+ export type { AccountOptions, AccountTree, AccountTreeNode, AccountType, CreateJournalData, JournalEntryData, JournalEntryOptions, JournalOptions, JournalStatus, LedgerBalanceMode, LedgerOptions, TrialBalanceRow, } from "./types.js";
74
77
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4DG;AAKH,OAAO,wBAAwB,CAAC;AAGhC,OAAO,cAAc,CAAC;AAGtB,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAAwB,CAAC;AAC3D,OAAO,EACL,sBAAsB,EACtB,KAAK,qBAAqB,EAC1B,KAAK,4BAA4B,GAClC,MAAM,iCAA8B,CAAC;AACtC,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAAwB,CAAC;AAE3D,OAAO,EACL,qBAAqB,EACrB,0BAA0B,EAC1B,qBAAqB,EACrB,4BAA4B,EAC5B,KAAK,8BAA8B,EACnC,KAAK,2BAA2B,EAChC,KAAK,6BAA6B,EAClC,0BAA0B,EAC1B,2BAA2B,GAC5B,MAAM,uCAAoC,CAAC;AAE5C,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAkB,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAkB,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,0BAAuB,CAAC;AAIrD,OAAO,EACL,oBAAoB,EACpB,iCAAiC,GAClC,MAAM,cAAW,CAAC;AACnB,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAW,CAAC;AAE9C,YAAY,EACV,cAAc,EACd,WAAW,EACX,eAAe,EACf,WAAW,EACX,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,EACnB,cAAc,EACd,aAAa,EACb,eAAe,GAChB,MAAM,YAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4DG;AAKH,OAAO,wBAAwB,CAAC;AAGhC,OAAO,cAAc,CAAC;AAGtB,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAAwB,CAAC;AAC3D,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,sBAAsB,EACtB,KAAK,qBAAqB,EAC1B,KAAK,4BAA4B,GAClC,MAAM,iCAA8B,CAAC;AACtC,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAAwB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAAuB,CAAC;AAEzD,OAAO,EACL,qBAAqB,EACrB,0BAA0B,EAC1B,qBAAqB,EACrB,4BAA4B,EAC5B,KAAK,8BAA8B,EACnC,KAAK,2BAA2B,EAChC,KAAK,6BAA6B,EAClC,0BAA0B,EAC1B,2BAA2B,GAC5B,MAAM,uCAAoC,CAAC;AAE5C,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAkB,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAkB,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,0BAAuB,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAiB,CAAC;AACzC,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,kBAAkB,EACvB,eAAe,EACf,WAAW,EACX,cAAc,EACd,cAAc,GACf,MAAM,eAAY,CAAC;AAGpB,OAAO,EACL,oBAAoB,EACpB,iCAAiC,GAClC,MAAM,cAAW,CAAC;AACnB,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAW,CAAC;AAE9C,YAAY,EACV,cAAc,EACd,WAAW,EACX,eAAe,EACf,WAAW,EACX,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,EACnB,cAAc,EACd,aAAa,EACb,iBAAiB,EACjB,aAAa,EACb,eAAe,GAChB,MAAM,YAAS,CAAC"}