@happyvertical/smrt-ledgers 0.30.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.
- package/AGENTS.md +36 -0
- package/CLAUDE.md +1 -0
- package/LICENSE +7 -0
- package/README.md +124 -0
- package/dist/index.d.ts +647 -0
- package/dist/index.js +1172 -0
- package/dist/index.js.map +1 -0
- package/dist/manifest.json +1561 -0
- package/dist/smrt-knowledge.json +871 -0
- package/dist/types.d.ts +179 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +59 -0
package/AGENTS.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# @happyvertical/smrt-ledgers
|
|
2
|
+
|
|
3
|
+
Double-entry accounting with chart of accounts, journal lifecycle, and balance enforcement.
|
|
4
|
+
|
|
5
|
+
## Models
|
|
6
|
+
|
|
7
|
+
- **Account**: 5 types (asset/liability/equity/revenue/expense). Hierarchical via `parentId`. Debit-normal (asset, expense) vs credit-normal (liability, equity, revenue). Methods: `getAncestors()`, `getFullPath()`, `toTreeNode()`, `getBalance(asOfDate?)`.
|
|
8
|
+
- **Journal**: lifecycle `draft → posted → voided`. **Immutable after posting** (can only void, not edit). `sourceModule`/`sourceRef` for cross-package attribution. Auto-numbered (e.g., "JNL-0001"). `summarize()` is AI-powered via the smrt-prompts registry (see Prompt Registry below).
|
|
9
|
+
- **JournalEntry**: debit XOR credit (not both, validated on save). Multi-currency via `exchangeRate`. Non-negative amounts required.
|
|
10
|
+
|
|
11
|
+
## Key Methods
|
|
12
|
+
|
|
13
|
+
- **`Journal.summarize()`**: Generates a natural-language summary via the registered `smrtLedgers.journal.summarize` prompt, resolved through `@happyvertical/smrt-prompts`. Tenants can override the template, model, temperature, or other params via `_smrt_prompt_overrides` without code changes. Only non-PII fields (number, date, description, status, aggregate total, entry count, balanced flag) reach the AI provider.
|
|
14
|
+
|
|
15
|
+
## Prompt Registry
|
|
16
|
+
|
|
17
|
+
Registered at module-load time via `definePrompt()` in `src/prompts.ts`. Side-effect imported from `src/index.ts` so consumers automatically see the prompts after importing any export from this package.
|
|
18
|
+
|
|
19
|
+
| Key | Method | Variables |
|
|
20
|
+
|-----|--------|-----------|
|
|
21
|
+
| `smrtLedgers.journal.summarize` | `Journal.summarize()` | `journalNumber`, `journalDate`, `journalDescription`, `journalStatus`, `journalTotal`, `entryCount`, `journalBalanced` |
|
|
22
|
+
|
|
23
|
+
PII-conscious variable selection: `tenantId`, `sourceRef` (may reference customer/vendor identifiers), per-entry `accountId`/`id`, and the extensible `metadata` blob are intentionally NOT exposed as prompt variables. Tenants who need richer context should override the template via `PromptOverride` and supply their own variables through a custom call site.
|
|
24
|
+
|
|
25
|
+
## Balance Enforcement
|
|
26
|
+
|
|
27
|
+
`journal.post()` validates `Math.abs(totalDebits - totalCredits) < BALANCE_EPSILON` where `BALANCE_EPSILON = 0.01` (float rounding tolerance). Unbalanced journals cannot be posted.
|
|
28
|
+
|
|
29
|
+
## Gotchas
|
|
30
|
+
|
|
31
|
+
- **Float tolerance**: 0.01 epsilon for balance check — not exact equality
|
|
32
|
+
- **Entry requires journalId**: save Journal first, then add entries
|
|
33
|
+
- **Posted journals cannot be modified**: only voided (`voidReason`, `voidedAt`)
|
|
34
|
+
- **Account types inherited by children**: child cannot differ from parent type
|
|
35
|
+
- **getBalance() is async**: requires JournalEntryCollection query (not stored on Account)
|
|
36
|
+
- **Optional tenancy** on all models
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@AGENTS.md
|
package/LICENSE
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Copyright <2025> <Happy Vertical Corporation>
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
+
|
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# @happyvertical/smrt-ledgers
|
|
2
|
+
|
|
3
|
+
Double-entry accounting ledger for the SMRT framework. Hierarchical chart of accounts, journal lifecycle with immutability after posting, and balance enforcement with epsilon tolerance.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @happyvertical/smrt-ledgers
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import {
|
|
15
|
+
Account, AccountCollection,
|
|
16
|
+
Journal, JournalCollection,
|
|
17
|
+
JournalEntry, JournalEntryCollection
|
|
18
|
+
} from '@happyvertical/smrt-ledgers';
|
|
19
|
+
|
|
20
|
+
// Set up chart of accounts
|
|
21
|
+
const accounts = new AccountCollection(db);
|
|
22
|
+
const cash = await accounts.create({
|
|
23
|
+
number: '1000',
|
|
24
|
+
name: 'Cash',
|
|
25
|
+
type: 'asset',
|
|
26
|
+
});
|
|
27
|
+
await cash.save();
|
|
28
|
+
|
|
29
|
+
const revenue = await accounts.create({
|
|
30
|
+
number: '4000',
|
|
31
|
+
name: 'Sales Revenue',
|
|
32
|
+
type: 'revenue',
|
|
33
|
+
});
|
|
34
|
+
await revenue.save();
|
|
35
|
+
|
|
36
|
+
// Create a sub-account under Cash
|
|
37
|
+
const checking = await cash.createChild({
|
|
38
|
+
number: '1010',
|
|
39
|
+
name: 'Checking Account',
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// Create a balanced journal with entries
|
|
43
|
+
const journals = new JournalCollection(db);
|
|
44
|
+
const journal = await journals.createWithEntries({
|
|
45
|
+
description: 'Cash sale',
|
|
46
|
+
sourceModule: 'manual',
|
|
47
|
+
entries: [
|
|
48
|
+
{ accountId: cash.id, debit: 100.00 },
|
|
49
|
+
{ accountId: revenue.id, credit: 100.00 },
|
|
50
|
+
],
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Post the journal (validates balance, then immutable)
|
|
54
|
+
await journal.post();
|
|
55
|
+
|
|
56
|
+
// Query balances
|
|
57
|
+
const cashBalance = await cash.getBalance();
|
|
58
|
+
|
|
59
|
+
// Get trial balance across all active accounts
|
|
60
|
+
const entries = new JournalEntryCollection(db);
|
|
61
|
+
const trialBalance = await entries.getTrialBalance();
|
|
62
|
+
|
|
63
|
+
// Void a journal (cannot edit after posting, only void)
|
|
64
|
+
await journal.void('Duplicate entry');
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Double-Entry Accounting
|
|
68
|
+
|
|
69
|
+
Every journal must balance before it can be posted. The balance check uses `BALANCE_EPSILON = 0.001` to handle floating-point rounding:
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
Math.abs(totalDebits - totalCredits) < 0.001
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Account types follow standard accounting rules:
|
|
76
|
+
- **Debit-normal** (Asset, Expense): balance = debits - credits
|
|
77
|
+
- **Credit-normal** (Liability, Equity, Revenue): balance = credits - debits
|
|
78
|
+
|
|
79
|
+
### Journal Lifecycle
|
|
80
|
+
|
|
81
|
+
Journals follow a strict `draft -> posted -> voided` lifecycle:
|
|
82
|
+
- **Draft**: editable, entries can be added via `journal.addEntry()`
|
|
83
|
+
- **Posted**: immutable, balance validated, `postedAt` timestamp set
|
|
84
|
+
- **Voided**: marked with `voidReason` and `voidedAt`, cannot be edited or re-posted
|
|
85
|
+
|
|
86
|
+
Each JournalEntry must have either a debit or a credit (not both, not zero). Amounts must be non-negative. Multi-currency is supported via `exchangeRate` on each entry.
|
|
87
|
+
|
|
88
|
+
## API
|
|
89
|
+
|
|
90
|
+
### Models
|
|
91
|
+
|
|
92
|
+
| Export | Description |
|
|
93
|
+
|--------|------------|
|
|
94
|
+
| `Account` | Chart of accounts entry with type, number, hierarchical parent, and balance queries |
|
|
95
|
+
| `Journal` | Transaction journal with status lifecycle, auto-numbered (JNL-*), sourceModule/sourceRef for cross-package attribution |
|
|
96
|
+
| `JournalEntry` | Individual debit or credit line within a journal, with currency and exchange rate |
|
|
97
|
+
|
|
98
|
+
### Collections
|
|
99
|
+
|
|
100
|
+
| Export | Key Methods |
|
|
101
|
+
|--------|------------|
|
|
102
|
+
| `AccountCollection` | `findChildren()`, `findActive()` |
|
|
103
|
+
| `JournalCollection` | `createWithEntries()`, `findByNumber()`, `findByDateRange()`, `findBySource()`, `findByStatus()`, `findDrafts()`, `findPosted()` |
|
|
104
|
+
| `JournalEntryCollection` | `findByJournal()`, `findByAccount()`, `getAccountBalance()`, `getTrialBalance()`, `getAccountLedger()`, `getTotalsForDateRange()` |
|
|
105
|
+
|
|
106
|
+
### Types
|
|
107
|
+
|
|
108
|
+
| Export | Description |
|
|
109
|
+
|--------|------------|
|
|
110
|
+
| `AccountType` | `'asset'`, `'liability'`, `'equity'`, `'revenue'`, `'expense'` |
|
|
111
|
+
| `JournalStatus` | `'draft'`, `'posted'`, `'voided'` |
|
|
112
|
+
| `AccountOptions` | Options for creating an Account |
|
|
113
|
+
| `JournalOptions` | Options for creating a Journal |
|
|
114
|
+
| `JournalEntryOptions` | Options for creating a JournalEntry |
|
|
115
|
+
| `JournalEntryData` | Entry data for `addEntry()` / `createWithEntries()` |
|
|
116
|
+
| `CreateJournalData` | Full journal + entries creation payload |
|
|
117
|
+
| `TrialBalanceRow` | Row in trial balance report (accountId, number, name, type, debit/credit balances) |
|
|
118
|
+
| `AccountTree` | Tree of account nodes (roots array) |
|
|
119
|
+
| `AccountTreeNode` | Single node in account tree (account + children) |
|
|
120
|
+
|
|
121
|
+
## Dependencies
|
|
122
|
+
|
|
123
|
+
- `@happyvertical/smrt-core` -- ORM and code generation
|
|
124
|
+
- `@happyvertical/smrt-tenancy` -- multi-tenant scoping
|