@classytic/ledger 0.9.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +94 -348
- package/dist/bridges/index.d.mts +2 -2
- package/dist/{index-Db0n_6Z8.d.mts → index-ClLwzNRF.d.mts} +3 -3
- package/dist/{index-dqkjgpII.d.mts → index-Dih0lM65.d.mts} +67 -2
- package/dist/index.d.mts +9 -3
- package/dist/index.mjs +15 -0
- package/dist/plugins/index.d.mts +1 -1
- package/package.json +14 -11
package/README.md
CHANGED
|
@@ -1,412 +1,158 @@
|
|
|
1
1
|
# @classytic/ledger
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
> **0.7.0 (BREAKING)** — `@classytic/ledger` is now a **pure double-entry accounting engine**. Tax computation, return templates, repartition, and exigibility have been removed from the core and country-pack contracts and now live in dedicated tax packages (`@classytic/bd-tax` is the existing reference; `@classytic/ca-tax` will follow). Country packs `@classytic/ledger-bd@0.2.0` and `@classytic/ledger-ca@0.2.0` ship the chart of accounts + journal templates only — they re-export the raw tax data tables as named constants for tax engines to lift. The 0.6.x A/P + A/R primitives (item-level matching, partner ledger, credit limit, FX realization, journal resource, open-item queries) are unchanged. See [CHANGELOG.md](CHANGELOG.md).
|
|
3
|
+
Double-entry accounting engine for MongoDB. Integer-cents arithmetic, plugin-based, country-agnostic, multi-tenant. Framework-agnostic — works with Fastify, Express, Nest, or plain Mongoose.
|
|
6
4
|
|
|
7
5
|
## Install
|
|
8
6
|
|
|
9
7
|
```bash
|
|
10
8
|
npm install @classytic/ledger @classytic/mongokit mongoose
|
|
11
|
-
npm install @classytic/ledger-ca # Canada (GIFI chart of accounts)
|
|
12
9
|
npm install @classytic/ledger-bd # Bangladesh (BFRS chart of accounts)
|
|
13
10
|
```
|
|
14
11
|
|
|
15
12
|
## Quick Start
|
|
16
13
|
|
|
17
14
|
```ts
|
|
18
|
-
import mongoose from
|
|
19
|
-
import { createAccountingEngine } from
|
|
20
|
-
import {
|
|
15
|
+
import mongoose from 'mongoose';
|
|
16
|
+
import { createAccountingEngine } from '@classytic/ledger';
|
|
17
|
+
import { bangladeshPack } from '@classytic/ledger-bd';
|
|
21
18
|
|
|
22
19
|
const engine = createAccountingEngine({
|
|
23
20
|
mongoose: mongoose.connection,
|
|
24
|
-
country:
|
|
25
|
-
currency:
|
|
26
|
-
multiTenant: { orgField:
|
|
21
|
+
country: bangladeshPack,
|
|
22
|
+
currency: 'BDT',
|
|
23
|
+
multiTenant: { orgField: 'organizationId', orgRef: 'organization' },
|
|
27
24
|
});
|
|
28
25
|
|
|
26
|
+
// Seed chart of accounts for a branch
|
|
29
27
|
await engine.repositories.accounts.seedAccounts(orgId);
|
|
30
28
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const bs = await engine.reports.balanceSheet({
|
|
40
|
-
organizationId: orgId,
|
|
41
|
-
dateOption: "year",
|
|
42
|
-
dateValue: 2025,
|
|
43
|
-
});
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
The engine owns the models. After `createAccountingEngine` you have:
|
|
47
|
-
|
|
48
|
-
| Property | What it gives you |
|
|
49
|
-
| --- | --- |
|
|
50
|
-
| `engine.models.{Account,JournalEntry,FiscalPeriod,Budget,Reconciliation,Journal}` | Mongoose models |
|
|
51
|
-
| `engine.repositories.accounts` | `seedAccounts()`, `bulkCreate()` + plugins |
|
|
52
|
-
| `engine.repositories.journalEntries` | `post()`, `unpost()`, `reverse()`, `duplicate()` + double-entry, fiscal-lock, idempotency |
|
|
53
|
-
| `engine.repositories.journals` | First-class posting channels — `seedDefaults()`, `nextSequenceNumber()` |
|
|
54
|
-
| `engine.repositories.reconciliations` | Item-level matching — `match()`, `unmatch()`, `getOpenItems()` |
|
|
55
|
-
| `engine.repositories.{fiscalPeriods,budgets}` | Plain CRUD |
|
|
56
|
-
| `engine.record.*` | Domain verbs (`sale`, `expense`, `transfer`, `payment`, `adjustment`) |
|
|
57
|
-
| `engine.introspect.*` | Runtime catalog of accounts, journal types, reports, fiscal periods |
|
|
58
|
-
| `engine.reports.*` | All 12 reports, bound to owned models |
|
|
59
|
-
|
|
60
|
-
## Semantic Record API
|
|
61
|
-
|
|
62
|
-
Record business operations as domain verbs. The engine resolves account codes and produces a balanced journal entry — you never touch debits/credits.
|
|
63
|
-
|
|
64
|
-
```ts
|
|
65
|
-
await engine.record.sale(orgId, {
|
|
66
|
-
date, amount: 10000,
|
|
67
|
-
receivableAccount: "1001", revenueAccount: "4010",
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
await engine.record.expense(orgId, {
|
|
71
|
-
date, amount: 3000,
|
|
72
|
-
expenseAccount: "6010", paidFromAccount: "2001",
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
await engine.record.transfer(orgId, { date, amount: 5000, fromAccount: "1001", toAccount: "1002" });
|
|
76
|
-
|
|
77
|
-
await engine.record.payment(orgId, {
|
|
78
|
-
date, amount: 11300,
|
|
79
|
-
fromReceivableAccount: "1200", toCashAccount: "1001",
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
// Multi-line adjustment (depreciation, accruals, corrections)
|
|
83
|
-
await engine.record.adjustment(orgId, {
|
|
84
|
-
date, label: "Monthly depreciation",
|
|
85
|
-
lines: [
|
|
86
|
-
{ account: "6030", debit: 1000 },
|
|
87
|
-
{ account: "1500", credit: 1000 },
|
|
29
|
+
// Post a journal entry
|
|
30
|
+
const entry = await engine.repositories.journalEntries.create({
|
|
31
|
+
journalType: 'GENERAL',
|
|
32
|
+
date: new Date(),
|
|
33
|
+
label: 'Office supplies',
|
|
34
|
+
journalItems: [
|
|
35
|
+
{ account: expenseAccountId, debit: 500_00, credit: 0 },
|
|
36
|
+
{ account: cashAccountId, debit: 0, credit: 500_00 },
|
|
88
37
|
],
|
|
89
38
|
});
|
|
39
|
+
await engine.repositories.journalEntries.post(entry._id, orgId);
|
|
90
40
|
```
|
|
91
41
|
|
|
92
|
-
|
|
42
|
+
## Multi-Currency (0.9.0+)
|
|
93
43
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
## Accounts Payable & Receivable
|
|
97
|
-
|
|
98
|
-
The 0.6.x A/P + A/R primitives are the foundation for any ERP workflow on top of the ledger.
|
|
44
|
+
GL stays in base currency (BDT). Foreign currency is audit metadata.
|
|
99
45
|
|
|
100
46
|
```ts
|
|
101
|
-
// Tag every journal item with a partnerId via extraItemFields (one-time setup)
|
|
102
47
|
const engine = createAccountingEngine({
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
},
|
|
109
|
-
},
|
|
48
|
+
country: bangladeshPack,
|
|
49
|
+
currency: 'BDT',
|
|
50
|
+
multiCurrency: { enabled: true, currencies: ['USD', 'EUR', 'GBP'] },
|
|
51
|
+
bridges: {
|
|
52
|
+
exchangeRate: myRateBridge, // host-injected rate source
|
|
110
53
|
},
|
|
111
54
|
});
|
|
112
55
|
|
|
113
|
-
// Post
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
date: new Date(
|
|
56
|
+
// Post with foreign currency metadata
|
|
57
|
+
await engine.repositories.journalEntries.create({
|
|
58
|
+
journalType: 'PURCHASES',
|
|
59
|
+
date: new Date(),
|
|
60
|
+
label: 'Import from China',
|
|
117
61
|
journalItems: [
|
|
118
|
-
{
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
journalItems: [
|
|
128
|
-
{ account: cashId, debit: 40_000 },
|
|
129
|
-
{ account: arId, credit: 40_000, partnerId: "wholesale-1" },
|
|
130
|
-
],
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
// Match the AR sides — partial settlement
|
|
134
|
-
await engine.repositories.reconciliations.match({
|
|
135
|
-
account: arId,
|
|
136
|
-
items: [
|
|
137
|
-
{ entry: invoice._id, itemIndex: 0 },
|
|
138
|
-
{ entry: payment._id, itemIndex: 1 },
|
|
62
|
+
{
|
|
63
|
+
account: inventoryId,
|
|
64
|
+
debit: 120_500_00, // BDT (base currency, always)
|
|
65
|
+
credit: 0,
|
|
66
|
+
currency: 'USD',
|
|
67
|
+
originalDebit: 1_000_00, // USD 1,000.00
|
|
68
|
+
exchangeRate: 120.50,
|
|
69
|
+
},
|
|
70
|
+
{ account: apId, debit: 0, credit: 120_500_00 },
|
|
139
71
|
],
|
|
140
72
|
});
|
|
141
|
-
|
|
142
|
-
// Open items for this partner (subsidiary ledger)
|
|
143
|
-
await engine.repositories.reconciliations.getOpenItems({
|
|
144
|
-
accountId: arId,
|
|
145
|
-
filter: { partnerId: "wholesale-1" },
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
// Customer statement with running balance + aged buckets
|
|
149
|
-
import { generatePartnerLedger } from "@classytic/ledger";
|
|
150
|
-
await generatePartnerLedger(
|
|
151
|
-
{ AccountModel: engine.models.Account, JournalEntryModel: engine.models.JournalEntry },
|
|
152
|
-
{
|
|
153
|
-
controlAccountId: arId,
|
|
154
|
-
partnerId: "wholesale-1",
|
|
155
|
-
startDate: new Date("2026-01-01"),
|
|
156
|
-
endDate: new Date("2026-03-31"),
|
|
157
|
-
},
|
|
158
|
-
);
|
|
159
|
-
|
|
160
|
-
// Cross-partner aged A/R buckets
|
|
161
|
-
import { generateAgedBalance } from "@classytic/ledger";
|
|
162
|
-
await generateAgedBalance(
|
|
163
|
-
{ AccountModel, JournalEntryModel, country: canadaPack },
|
|
164
|
-
{ type: "receivable", contactField: "journalItems.partnerId" },
|
|
165
|
-
);
|
|
166
|
-
|
|
167
|
-
// Enforce per-customer credit limits
|
|
168
|
-
import { creditLimitPlugin } from "@classytic/ledger/plugins";
|
|
169
|
-
creditLimitPlugin({
|
|
170
|
-
arControlAccountId: arId,
|
|
171
|
-
JournalEntryModel: engine.models.JournalEntry,
|
|
172
|
-
getCreditLimit: async (partnerId) => Customer.findById(partnerId).then(c => c?.creditLimit ?? null),
|
|
173
|
-
}).apply(engine.repositories.journalEntries);
|
|
174
73
|
```
|
|
175
74
|
|
|
176
|
-
##
|
|
75
|
+
## Features
|
|
177
76
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
try {
|
|
190
|
-
await engine.record.sale(orgId, { ... });
|
|
191
|
-
} catch (err) {
|
|
192
|
-
if (err instanceof AccountingError) {
|
|
193
|
-
err.status // 400 | 402 | 403 | 404 | 409
|
|
194
|
-
err.code // 'VALIDATION_ERROR' | 'NOT_FOUND' | 'CREDIT_LIMIT_EXCEEDED' | 'PERIOD_LOCKED_FISCAL' | ...
|
|
195
|
-
err.fields // [{ path, issue, value }, ...]
|
|
196
|
-
err.toJSON();
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
## Audit, Observability & Framework Integration
|
|
202
|
-
|
|
203
|
-
Every operation flows through mongokit's `RepositoryContext`. Custom plugins can hook `before:create` / `after:create` / `before:update` / `after:update` / `after:match` to add audit trails, metrics, webhooks, or business rules — none of it is hardcoded into the core.
|
|
204
|
-
|
|
205
|
-
The `_ledgerInternal` context flag (`'post' | 'unpost' | 'archive' | 'reverseMark' | 'fxRealize'`) tells plugins which engine operation is in flight, so guards (locks, credit limit, immutability) can exempt legitimate engine writes without affecting consumer code.
|
|
77
|
+
| Feature | What it does |
|
|
78
|
+
|---------|-------------|
|
|
79
|
+
| **Double-entry** | `doubleEntryPlugin` validates debit = credit on every post |
|
|
80
|
+
| **Integer cents** | All amounts in minor units (paisa/cents). No float errors. |
|
|
81
|
+
| **Multi-tenant** | `organizationId` scoping via mongokit plugin |
|
|
82
|
+
| **Multi-currency** | Optional foreign currency fields + FX realization + revaluation |
|
|
83
|
+
| **Idempotency** | `idempotencyPlugin` prevents duplicate postings |
|
|
84
|
+
| **Period locking** | `createLockPlugin` blocks edits to closed periods |
|
|
85
|
+
| **Credit limits** | `creditLimitPlugin` enforces per-partner credit caps |
|
|
86
|
+
| **Immutable guard** | `immutableGuardPlugin` prevents posted entry edits |
|
|
87
|
+
| **Country packs** | Pluggable chart of accounts (BD, CA, custom) |
|
|
206
88
|
|
|
207
89
|
## Reports
|
|
208
90
|
|
|
209
|
-
12 typed reports, all multi-tenant scoped, all returning structured JSON ready for any UI:
|
|
210
|
-
|
|
211
|
-
| Report | Purpose |
|
|
212
|
-
| --- | --- |
|
|
213
|
-
| `trialBalance` | Debits/credits per account with running balances |
|
|
214
|
-
| `balanceSheet` | Assets, liabilities, equity at a date with computed retained earnings |
|
|
215
|
-
| `incomeStatement` | Revenue, COGS, expenses, net income for a period |
|
|
216
|
-
| `generalLedger` | Per-account transaction detail with running balance |
|
|
217
|
-
| `cashFlow` | Operating / investing / financing breakdown |
|
|
218
|
-
| `agedBalance` | A/R or A/P bucketed by age, optionally per partner |
|
|
219
|
-
| `partnerLedger` | Supplier/customer statement with opening + running balance + aged buckets |
|
|
220
|
-
| `dimensionBreakdown` | Group by department/project/cost center |
|
|
221
|
-
| `budgetVsActual` | Variance vs budget per account/period |
|
|
222
|
-
| `revaluation` | Foreign-currency unrealized FX gain/loss at a date |
|
|
223
|
-
| `closeFiscalPeriod` / `reopenFiscalPeriod` | Year-end close pipeline |
|
|
224
|
-
|
|
225
|
-
## Engine Configuration
|
|
226
|
-
|
|
227
|
-
```ts
|
|
228
|
-
const engine = createAccountingEngine({
|
|
229
|
-
mongoose: mongoose.connection,
|
|
230
|
-
country: canadaPack,
|
|
231
|
-
currency: "CAD",
|
|
232
|
-
multiTenant: { orgField: "organizationId", orgRef: "Organization" },
|
|
233
|
-
multiCurrency: { enabled: true, currencies: ["USD", "EUR"] },
|
|
234
|
-
fiscalYearStartMonth: 1,
|
|
235
|
-
idempotency: true,
|
|
236
|
-
strictness: { immutable: true, requireActor: true },
|
|
237
|
-
schemaOptions: {
|
|
238
|
-
journalEntry: {
|
|
239
|
-
extraItemFields: {
|
|
240
|
-
partnerId: { type: String, index: true },
|
|
241
|
-
departmentId: { type: mongoose.Schema.Types.ObjectId },
|
|
242
|
-
},
|
|
243
|
-
},
|
|
244
|
-
},
|
|
245
|
-
});
|
|
246
|
-
```
|
|
247
|
-
|
|
248
|
-
## Built-in Plugins
|
|
249
|
-
|
|
250
|
-
| Plugin | Purpose |
|
|
251
|
-
| --- | --- |
|
|
252
|
-
| `doubleEntryPlugin` | Validates debits = credits, account existence, tenant integrity, posted-entry immutability |
|
|
253
|
-
| `fiscalLockPlugin` | Prevents posting into closed fiscal periods (auto-wired) |
|
|
254
|
-
| `dailyLockPlugin` | Per-branch `lastClosedDate` watermark for daily POS close |
|
|
255
|
-
| `createLockPlugin` | Generic lock factory — compose your own scopes (bank recon, payroll, tax filings) |
|
|
256
|
-
| `idempotencyPlugin` | Prevents duplicate entries by key (auto-wired when `idempotency: true`) |
|
|
257
|
-
| `creditLimitPlugin` | Per-partner A/R credit limit enforcement |
|
|
258
|
-
| `fxRealizationPlugin` | Books realized FX gain/loss when matched items have different exchange rates |
|
|
259
|
-
|
|
260
|
-
`doubleEntryPlugin`, `fiscalLockPlugin`, and `idempotencyPlugin` (when enabled) are wired automatically by the engine. The others are opt-in via `.apply(engine.repositories.journalEntries)` or `.apply(engine.repositories.reconciliations)`.
|
|
261
|
-
|
|
262
|
-
## Custom Journal Types
|
|
263
|
-
|
|
264
|
-
The 15 built-in journal types (SALES, PURCHASES, GENERAL, PAYROLL, …) cover standard accounting. Register custom types **before** the first engine call:
|
|
265
|
-
|
|
266
|
-
```ts
|
|
267
|
-
import { registerJournalType } from "@classytic/ledger";
|
|
268
|
-
|
|
269
|
-
registerJournalType("POS_SALES", { code: "POS_SALES", name: "POS Sales Journal" });
|
|
270
|
-
registerJournalType("ECOM_SALES", { code: "ECOM_SALES", name: "E-Commerce Sales" });
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
Reference numbers use the type prefix (`POS_SALES/2025/03/0001`). The registry freezes after the first schema is created.
|
|
274
|
-
|
|
275
|
-
## Country Packs
|
|
276
|
-
|
|
277
|
-
A country pack ships the **chart of accounts** + accounting conventions for a jurisdiction. Tax (VAT/GST/HST/income-tax) lives in separate tax packages — see "Tax" below.
|
|
278
|
-
|
|
279
91
|
```ts
|
|
280
|
-
import {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
],
|
|
292
|
-
});
|
|
92
|
+
import {
|
|
93
|
+
generateTrialBalance,
|
|
94
|
+
generateBalanceSheet,
|
|
95
|
+
generateIncomeStatement,
|
|
96
|
+
generateCashFlow,
|
|
97
|
+
generateGeneralLedger,
|
|
98
|
+
generateAgedBalance,
|
|
99
|
+
generateBudgetVsActual,
|
|
100
|
+
generatePartnerLedger,
|
|
101
|
+
generateRevaluation,
|
|
102
|
+
} from '@classytic/ledger';
|
|
293
103
|
```
|
|
294
104
|
|
|
295
|
-
|
|
105
|
+
All reports accept `{ startDate, endDate, organizationId }` and return typed result objects.
|
|
296
106
|
|
|
297
|
-
##
|
|
107
|
+
## Bridges
|
|
298
108
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
For tax computation, return generation, and repartition:
|
|
302
|
-
|
|
303
|
-
- **`@classytic/bd-tax`** — Bangladesh income tax + VAT compute, IT-11GA forms, Mushak 9.1 returns, deduction optimizer, depreciation
|
|
304
|
-
- **`@classytic/ca-tax`** *(planned)* — Canadian GST/HST/PST/QST compute, CRA GST34 form, ITC tracking
|
|
305
|
-
- **Or your own** — tax engines just call `engine.repositories.journalEntries.create()` with the tax line items they want posted
|
|
306
|
-
|
|
307
|
-
The country packs (`ledger-bd`, `ledger-ca`) still re-export their raw tax data tables (`TAX_CODES`, `TAX_CODES_BY_REGION`, `mushakReturnTemplate`, `craReturnTemplate`) as named exports so tax packages can lift them — they're just no longer wired into the `CountryPack` contract.
|
|
308
|
-
|
|
309
|
-
## Invoice Engine Integration
|
|
310
|
-
|
|
311
|
-
Wire `@classytic/invoice` to the ledger with one call — no manual journal wiring needed:
|
|
109
|
+
All optional. All methods optional. Features degrade gracefully.
|
|
312
110
|
|
|
313
111
|
```ts
|
|
314
|
-
import {
|
|
315
|
-
import { createLedgerBridge } from "@classytic/ledger/sync";
|
|
316
|
-
import { createInvoiceEngine } from "@classytic/invoice";
|
|
317
|
-
import { canadaPack } from "@classytic/ledger-ca";
|
|
318
|
-
|
|
319
|
-
const accounting = createAccountingEngine({
|
|
320
|
-
mongoose: mongoose.connection,
|
|
321
|
-
country: canadaPack,
|
|
322
|
-
currency: "CAD",
|
|
323
|
-
multiTenant: { orgField: "organizationId", orgRef: "Organization" },
|
|
324
|
-
idempotency: true,
|
|
325
|
-
});
|
|
112
|
+
import type { ExchangeRateBridge, SourceBridge, NotificationBridge } from '@classytic/ledger';
|
|
326
113
|
|
|
327
|
-
const
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
expense: "5000", // Expenses
|
|
335
|
-
taxPayable: "2100", // Tax Payable
|
|
336
|
-
taxReceivable: "1150", // Tax Receivable
|
|
337
|
-
cash: "1000", // Cash / Bank
|
|
338
|
-
},
|
|
339
|
-
}),
|
|
114
|
+
const engine = createAccountingEngine({
|
|
115
|
+
// ...
|
|
116
|
+
bridges: {
|
|
117
|
+
exchangeRate: myRateBridge, // FX rate lookup
|
|
118
|
+
source: mySourceBridge, // resolve external doc refs
|
|
119
|
+
notification: myNotifBridge, // alert on reversals, period locks
|
|
120
|
+
},
|
|
340
121
|
});
|
|
341
122
|
```
|
|
342
123
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
For custom subledgers (inventory, payroll, etc.) that don't use `@classytic/invoice`, see [docs/subledger-integration.md](docs/subledger-integration.md) for the manual `PostingContract` pattern.
|
|
346
|
-
|
|
347
|
-
## URL-Driven Queries
|
|
348
|
-
|
|
349
|
-
Parse URL query parameters directly into paginated repository queries via mongokit's `QueryParser`:
|
|
124
|
+
## Plugins
|
|
350
125
|
|
|
351
126
|
```ts
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
}
|
|
127
|
+
import {
|
|
128
|
+
doubleEntryPlugin,
|
|
129
|
+
idempotencyPlugin,
|
|
130
|
+
creditLimitPlugin,
|
|
131
|
+
fxRealizationPlugin,
|
|
132
|
+
immutableGuardPlugin,
|
|
133
|
+
createLockPlugin,
|
|
134
|
+
} from '@classytic/ledger';
|
|
360
135
|
```
|
|
361
136
|
|
|
362
|
-
|
|
137
|
+
Plugins attach to mongokit repository hooks. They run at POLICY priority before any query.
|
|
363
138
|
|
|
364
139
|
## Subpath Exports
|
|
365
140
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
| `@classytic/ledger/reports` | Standalone report generators |
|
|
372
|
-
| `@classytic/ledger/plugins` | All plugins |
|
|
373
|
-
| `@classytic/ledger/exports` | CSV export + QuickBooks field maps |
|
|
374
|
-
| `@classytic/ledger/country` | `defineCountryPack`, `CountryPack` |
|
|
375
|
-
| `@classytic/ledger/constants` | Categories, journal types, currencies |
|
|
376
|
-
|
|
377
|
-
## Testing
|
|
378
|
-
|
|
379
|
-
```bash
|
|
380
|
-
npm test # 1327 tests, 77 files
|
|
381
|
-
npm run smoke # full pipeline against published dist/
|
|
382
|
-
npx vitest run tests/e2e/ # end-to-end scenarios
|
|
383
|
-
npx vitest run tests/scenarios/ # multi-step business scenarios
|
|
384
|
-
npx vitest run tests/hardening/ # edge cases & invariants
|
|
141
|
+
```ts
|
|
142
|
+
import { Money } from '@classytic/ledger/money';
|
|
143
|
+
import { CATEGORIES, CURRENCIES } from '@classytic/ledger/constants';
|
|
144
|
+
import { defineCountryPack } from '@classytic/ledger/country';
|
|
145
|
+
import { exportToCsv, quickbooksFieldMap } from '@classytic/ledger/exports';
|
|
385
146
|
```
|
|
386
147
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
- Canadian small-business full-year lifecycle (open → post → close → reopen)
|
|
390
|
-
- Multi-year fiscal cycles with retained-earnings rollover
|
|
391
|
-
- Multi-currency trading with realized + unrealized FX
|
|
392
|
-
- Multi-tenant report isolation (org A cannot see org B)
|
|
393
|
-
- All 12 reports with month / quarter / year / custom date ranges
|
|
394
|
-
- Reversal and correction workflows
|
|
395
|
-
- Custom journal type registry → schema → posting pipeline
|
|
396
|
-
- Item-level matching: 1-to-1, 1-to-many, partial settlement, unmatch
|
|
397
|
-
- Per-partner credit limit enforcement + reversal exemption
|
|
398
|
-
- FX realization plugin auto-booking gain/loss on cross-rate match
|
|
399
|
-
- Full ERP A/P + A/R cycle (bill receipt → match → supplier statement → aged balance)
|
|
400
|
-
- Double-entry conservation across all entries
|
|
401
|
-
- Money arithmetic hardening (overflow, penny-leak, float traps)
|
|
402
|
-
- O-Level / A-Level / university textbook accounting problems
|
|
403
|
-
|
|
404
|
-
## Requirements
|
|
148
|
+
## Architecture
|
|
405
149
|
|
|
406
|
-
-
|
|
407
|
-
-
|
|
408
|
-
-
|
|
409
|
-
-
|
|
150
|
+
- Repositories extend `@classytic/mongokit` Repository directly
|
|
151
|
+
- No service layer — domain verbs live on the repository
|
|
152
|
+
- No barrel re-exports — import from source paths
|
|
153
|
+
- Events: arc-compatible `DomainEvent` / `EventTransport` shapes
|
|
154
|
+
- Country packs: pluggable chart of accounts + journal type seeds
|
|
155
|
+
- Tax: NOT in ledger. Use `@classytic/bd-tax` for Bangladesh tax calculations.
|
|
410
156
|
|
|
411
157
|
## License
|
|
412
158
|
|
package/dist/bridges/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as EntryReversedNotification, c as PeriodLockedNotification, i as SourceRef, l as ReconciliationMismatchNotification, n as SourceBridge, o as NotificationBridge, r as SourceBridgeContext, s as NotificationBridgeContext, t as LedgerBridges } from "../index-
|
|
2
|
-
export { EntryReversedNotification, LedgerBridges, NotificationBridge, NotificationBridgeContext, PeriodLockedNotification, ReconciliationMismatchNotification, SourceBridge, SourceBridgeContext, SourceRef };
|
|
1
|
+
import { a as EntryReversedNotification, c as PeriodLockedNotification, i as SourceRef, l as ReconciliationMismatchNotification, n as SourceBridge, o as NotificationBridge, r as SourceBridgeContext, s as NotificationBridgeContext, t as LedgerBridges, u as ExchangeRateBridge } from "../index-Dih0lM65.mjs";
|
|
2
|
+
export { EntryReversedNotification, ExchangeRateBridge, LedgerBridges, NotificationBridge, NotificationBridgeContext, PeriodLockedNotification, ReconciliationMismatchNotification, SourceBridge, SourceBridgeContext, SourceRef };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as _classytic_mongokit0 from "@classytic/mongokit";
|
|
1
|
+
import * as _$_classytic_mongokit0 from "@classytic/mongokit";
|
|
2
2
|
import { Repository, RepositoryContext, RepositoryInstance } from "@classytic/mongokit";
|
|
3
3
|
import { ClientSession, Model } from "mongoose";
|
|
4
4
|
|
|
@@ -427,7 +427,7 @@ interface FiscalLockPluginOptions {
|
|
|
427
427
|
}
|
|
428
428
|
declare function fiscalLockPlugin(options: FiscalLockPluginOptions): {
|
|
429
429
|
name: string;
|
|
430
|
-
apply(repo: _classytic_mongokit0.RepositoryInstance): void;
|
|
430
|
+
apply(repo: _$_classytic_mongokit0.RepositoryInstance): void;
|
|
431
431
|
};
|
|
432
432
|
interface DailyLockPluginOptions {
|
|
433
433
|
/**
|
|
@@ -441,7 +441,7 @@ interface DailyLockPluginOptions {
|
|
|
441
441
|
}
|
|
442
442
|
declare function dailyLockPlugin(options: DailyLockPluginOptions): {
|
|
443
443
|
name: string;
|
|
444
|
-
apply(repo: _classytic_mongokit0.RepositoryInstance): void;
|
|
444
|
+
apply(repo: _$_classytic_mongokit0.RepositoryInstance): void;
|
|
445
445
|
};
|
|
446
446
|
//#endregion
|
|
447
447
|
//#region src/plugins/lock/watermark-resolver.d.ts
|
|
@@ -1,3 +1,67 @@
|
|
|
1
|
+
//#region src/bridges/exchange-rate.bridge.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Exchange Rate Bridge — host-injected rate sourcing.
|
|
4
|
+
*
|
|
5
|
+
* The ledger never hardcodes where exchange rates come from. The host
|
|
6
|
+
* provides an implementation at engine init time:
|
|
7
|
+
*
|
|
8
|
+
* - ManualRateBridge: user-entered Currency Exchange records
|
|
9
|
+
* - BangladeshBankRateBridge: BB daily rate API
|
|
10
|
+
* - FixedRateBridge: hardcoded for testing
|
|
11
|
+
* - ProviderRateBridge: third-party rate API (Wise, Open Exchange Rates)
|
|
12
|
+
*
|
|
13
|
+
* When no bridge is provided, the caller must supply the exchange rate
|
|
14
|
+
* explicitly on every journal item (the existing behavior). The bridge
|
|
15
|
+
* is a convenience for hosts that want automatic rate lookup.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* const engine = createAccountingEngine({
|
|
20
|
+
* country: bdPack,
|
|
21
|
+
* currency: 'BDT',
|
|
22
|
+
* multiCurrency: { enabled: true, currencies: ['USD', 'EUR'] },
|
|
23
|
+
* bridges: {
|
|
24
|
+
* exchangeRate: {
|
|
25
|
+
* async getRate(from, to, date) {
|
|
26
|
+
* const row = await CurrencyExchange.findOne({ from, to, date });
|
|
27
|
+
* if (!row) throw new Error(`No rate for ${from}→${to} on ${date}`);
|
|
28
|
+
* return row.rate;
|
|
29
|
+
* },
|
|
30
|
+
* },
|
|
31
|
+
* },
|
|
32
|
+
* });
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
interface ExchangeRateBridge {
|
|
36
|
+
/**
|
|
37
|
+
* Get the exchange rate for converting `fromCurrency` to `toCurrency`
|
|
38
|
+
* on a given date.
|
|
39
|
+
*
|
|
40
|
+
* @param fromCurrency ISO 4217 code (e.g., 'USD')
|
|
41
|
+
* @param toCurrency ISO 4217 code (e.g., 'BDT')
|
|
42
|
+
* @param date Transaction date (rate as of this date)
|
|
43
|
+
* @param purpose Optional: 'buying' or 'selling' rate (some central
|
|
44
|
+
* banks publish separate rates)
|
|
45
|
+
* @returns The rate as a positive decimal. Example: 120.50 means
|
|
46
|
+
* 1 USD = 120.50 BDT.
|
|
47
|
+
* @throws When no rate is available for the requested pair + date.
|
|
48
|
+
*/
|
|
49
|
+
getRate(fromCurrency: string, toCurrency: string, date: Date, purpose?: 'buying' | 'selling'): Promise<number>;
|
|
50
|
+
/**
|
|
51
|
+
* Optional batch lookup — avoids N+1 when posting multi-line entries
|
|
52
|
+
* with different currencies. Host implementations that cache rates
|
|
53
|
+
* benefit from a single DB round-trip.
|
|
54
|
+
*
|
|
55
|
+
* When absent, the engine falls back to calling `getRate()` per item.
|
|
56
|
+
*/
|
|
57
|
+
getRates?(requests: Array<{
|
|
58
|
+
fromCurrency: string;
|
|
59
|
+
toCurrency: string;
|
|
60
|
+
date: Date;
|
|
61
|
+
purpose?: 'buying' | 'selling';
|
|
62
|
+
}>): Promise<Map<string, number>>;
|
|
63
|
+
}
|
|
64
|
+
//#endregion
|
|
1
65
|
//#region src/bridges/notification.bridge.d.ts
|
|
2
66
|
/**
|
|
3
67
|
* NotificationBridge — host-implemented delivery for ledger-originated alerts.
|
|
@@ -95,10 +159,11 @@ interface SourceBridge {
|
|
|
95
159
|
}
|
|
96
160
|
//#endregion
|
|
97
161
|
//#region src/bridges/index.d.ts
|
|
98
|
-
/** Collected bridges exposed as `engine.bridges`. */
|
|
162
|
+
/** Collected bridges exposed as `engine.bridges`. All optional per PACKAGE_RULES §23. */
|
|
99
163
|
interface LedgerBridges {
|
|
100
164
|
source?: SourceBridge;
|
|
101
165
|
notification?: NotificationBridge;
|
|
166
|
+
exchangeRate?: ExchangeRateBridge;
|
|
102
167
|
}
|
|
103
168
|
//#endregion
|
|
104
|
-
export { EntryReversedNotification as a, PeriodLockedNotification as c, SourceRef as i, ReconciliationMismatchNotification as l, SourceBridge as n, NotificationBridge as o, SourceBridgeContext as r, NotificationBridgeContext as s, LedgerBridges as t };
|
|
169
|
+
export { EntryReversedNotification as a, PeriodLockedNotification as c, SourceRef as i, ReconciliationMismatchNotification as l, SourceBridge as n, NotificationBridge as o, SourceBridgeContext as r, NotificationBridgeContext as s, LedgerBridges as t, ExchangeRateBridge as u };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as EntryReversedNotification, c as PeriodLockedNotification, i as SourceRef, l as ReconciliationMismatchNotification, n as SourceBridge, o as NotificationBridge, r as SourceBridgeContext, s as NotificationBridgeContext, t as LedgerBridges } from "./index-
|
|
1
|
+
import { a as EntryReversedNotification, c as PeriodLockedNotification, i as SourceRef, l as ReconciliationMismatchNotification, n as SourceBridge, o as NotificationBridge, r as SourceBridgeContext, s as NotificationBridgeContext, t as LedgerBridges, u as ExchangeRateBridge } from "./index-Dih0lM65.mjs";
|
|
2
2
|
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-DwjkrRkJ.mjs";
|
|
3
3
|
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-DUpWwFt1.mjs";
|
|
4
4
|
import { i as defineCountryPack, n as CountryPackInput, r as JournalTemplate, t as CountryPack } from "./index-08IpHhrU.mjs";
|
|
@@ -6,7 +6,7 @@ import { C as EntryReversedPayload, D as ReconciliationUnmatchedPayload, E as Re
|
|
|
6
6
|
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-J-XIbXH-.mjs";
|
|
7
7
|
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";
|
|
8
8
|
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-DyNm5bFu.mjs";
|
|
9
|
-
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-
|
|
9
|
+
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-ClLwzNRF.mjs";
|
|
10
10
|
import { PaginationConfig, PluginFunction, PluginType, QueryParser, QueryParserOptions, Repository } from "@classytic/mongokit";
|
|
11
11
|
import { ClientSession, Connection, Model } from "mongoose";
|
|
12
12
|
|
|
@@ -714,6 +714,12 @@ declare class AccountingEngine {
|
|
|
714
714
|
readonly outboxStore: OutboxStore | undefined;
|
|
715
715
|
private _reports?;
|
|
716
716
|
constructor(config: AccountingEngineConfig);
|
|
717
|
+
/**
|
|
718
|
+
* Explicitly sync indexes on all managed models.
|
|
719
|
+
* Call this in deploy-time scripts — NOT on every boot.
|
|
720
|
+
* See PACKAGE_RULES section 32.
|
|
721
|
+
*/
|
|
722
|
+
syncIndexes(): Promise<void>;
|
|
717
723
|
/**
|
|
718
724
|
* Pre-built reports bound to the engine's owned models.
|
|
719
725
|
* Lazy-initialized on first access.
|
|
@@ -1043,4 +1049,4 @@ interface PostingResult {
|
|
|
1043
1049
|
idempotencyKeys?: string[];
|
|
1044
1050
|
}
|
|
1045
1051
|
//#endregion
|
|
1046
|
-
export { type AccountBulkCreatedPayload, type AccountCode, type AccountForeignBalance, type AccountRepository, type AccountSeededPayload, 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, ConcurrencyError, 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 DomainEvent, DuplicateReferenceError, type EntryArchivedPayload, type EntryCreatedPayload, type EntryDuplicatedPayload, type EntryPostedPayload, type EntryReversedNotification, type EntryReversedPayload, type EntryState, type EntryUnpostedPayload, Errors, type EventContext, type EventHandler, type EventLogger, type EventTransport, type ExportField, type ExportFieldMap, type FieldError, type FiscalLockPluginOptions, type FiscalPeriodSummary, type FlatJournalRow, type FxRealizationPluginOptions, type GeneralLedgerAccount, type GeneralLedgerReport, IdempotencyConflictError, type ImmutableGuardOptions, ImmutableViolationError, InProcessLedgerBus, type InProcessLedgerBusOptions, type IncomeStatementReport, type IntrospectAPI, JOURNAL_CODES, JOURNAL_TYPES, type JournalEntryRepository, type JournalItem, type JournalItemRef, type JournalRepository, type JournalSchemaOptions, type JournalSeededPayload, type JournalTemplate, type JournalType, LEDGER_EVENTS, type LedgerBridges, type LedgerEntry, type LedgerEventName, 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 NotificationBridge, type NotificationBridgeContext, type OpenItem, type OutboxAcknowledgeOptions, type OutboxClaimOptions, type OutboxErrorInfo, type OutboxFailOptions, OutboxOwnershipError, type OutboxStore, type OutboxWriteOptions, type PartnerLedgerLine, type PartnerLedgerOptions, type PartnerLedgerParams, type PartnerLedgerReport, type PeriodLockedNotification, type PeriodResolverOptions, type PopulatedJournalEntry, type PostOptions, type PostingContract, type PostingResult, type PublishManyResult, type ReconciliationMatchedPayload, type ReconciliationMismatchNotification, type ReconciliationRepository, type ReconciliationUnmatchedPayload, 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 SourceBridge, type SourceBridgeContext, type SourceRef, 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, classifyDuplicateKey, closeFiscalPeriod, computeEndingBalance, computeRevaluation, createAccountingEngine, createEvent, 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, immutableGuardPlugin, isBalanceSheet, isIncomeStatement, isValidCategory, isValidCurrency, isValidJournalType, isVirtualTaxAccount, multiply, parseCents, percentage, periodResolver, quickbooksFieldMap, registerJournalType, reopenFiscalPeriod, resolveModelNames, splitTaxExclusive, splitTaxInclusive, subtract, toDecimal, universalFieldMap, watermarkResolver };
|
|
1052
|
+
export { type AccountBulkCreatedPayload, type AccountCode, type AccountForeignBalance, type AccountRepository, type AccountSeededPayload, 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, ConcurrencyError, 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 DomainEvent, DuplicateReferenceError, type EntryArchivedPayload, type EntryCreatedPayload, type EntryDuplicatedPayload, type EntryPostedPayload, type EntryReversedNotification, type EntryReversedPayload, type EntryState, type EntryUnpostedPayload, Errors, type EventContext, type EventHandler, type EventLogger, type EventTransport, type ExchangeRateBridge, type ExportField, type ExportFieldMap, type FieldError, type FiscalLockPluginOptions, type FiscalPeriodSummary, type FlatJournalRow, type FxRealizationPluginOptions, type GeneralLedgerAccount, type GeneralLedgerReport, IdempotencyConflictError, type ImmutableGuardOptions, ImmutableViolationError, InProcessLedgerBus, type InProcessLedgerBusOptions, type IncomeStatementReport, type IntrospectAPI, JOURNAL_CODES, JOURNAL_TYPES, type JournalEntryRepository, type JournalItem, type JournalItemRef, type JournalRepository, type JournalSchemaOptions, type JournalSeededPayload, type JournalTemplate, type JournalType, LEDGER_EVENTS, type LedgerBridges, type LedgerEntry, type LedgerEventName, 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 NotificationBridge, type NotificationBridgeContext, type OpenItem, type OutboxAcknowledgeOptions, type OutboxClaimOptions, type OutboxErrorInfo, type OutboxFailOptions, OutboxOwnershipError, type OutboxStore, type OutboxWriteOptions, type PartnerLedgerLine, type PartnerLedgerOptions, type PartnerLedgerParams, type PartnerLedgerReport, type PeriodLockedNotification, type PeriodResolverOptions, type PopulatedJournalEntry, type PostOptions, type PostingContract, type PostingResult, type PublishManyResult, type ReconciliationMatchedPayload, type ReconciliationMismatchNotification, type ReconciliationRepository, type ReconciliationUnmatchedPayload, 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 SourceBridge, type SourceBridgeContext, type SourceRef, 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, classifyDuplicateKey, closeFiscalPeriod, computeEndingBalance, computeRevaluation, createAccountingEngine, createEvent, 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, immutableGuardPlugin, isBalanceSheet, isIncomeStatement, isValidCategory, isValidCurrency, isValidJournalType, isVirtualTaxAccount, multiply, parseCents, percentage, periodResolver, quickbooksFieldMap, registerJournalType, reopenFiscalPeriod, resolveModelNames, splitTaxExclusive, splitTaxInclusive, subtract, toDecimal, universalFieldMap, watermarkResolver };
|
package/dist/index.mjs
CHANGED
|
@@ -2669,6 +2669,21 @@ var AccountingEngine = class {
|
|
|
2669
2669
|
});
|
|
2670
2670
|
}
|
|
2671
2671
|
/**
|
|
2672
|
+
* Explicitly sync indexes on all managed models.
|
|
2673
|
+
* Call this in deploy-time scripts — NOT on every boot.
|
|
2674
|
+
* See PACKAGE_RULES section 32.
|
|
2675
|
+
*/
|
|
2676
|
+
async syncIndexes() {
|
|
2677
|
+
await Promise.all([
|
|
2678
|
+
this.models.Account.syncIndexes(),
|
|
2679
|
+
this.models.JournalEntry.syncIndexes(),
|
|
2680
|
+
this.models.FiscalPeriod.syncIndexes(),
|
|
2681
|
+
this.models.Budget.syncIndexes(),
|
|
2682
|
+
this.models.Reconciliation.syncIndexes(),
|
|
2683
|
+
this.models.Journal.syncIndexes()
|
|
2684
|
+
]);
|
|
2685
|
+
}
|
|
2686
|
+
/**
|
|
2672
2687
|
* Pre-built reports bound to the engine's owned models.
|
|
2673
2688
|
* Lazy-initialized on first access.
|
|
2674
2689
|
*/
|
package/dist/plugins/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { S as creditLimitPlugin, _ as FxRealizationPluginOptions, a as dailyLockPlugin, b as doubleEntryPlugin, c as periodResolver, d as LockAccountSelector, f as LockHit, g as idempotencyPlugin, h as IdempotencyPluginOptions, i as FiscalLockPluginOptions, 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, x as CreditLimitPluginOptions, y as DoubleEntryPluginOptions } from "../index-
|
|
1
|
+
import { S as creditLimitPlugin, _ as FxRealizationPluginOptions, a as dailyLockPlugin, b as doubleEntryPlugin, c as periodResolver, d as LockAccountSelector, f as LockHit, g as idempotencyPlugin, h as IdempotencyPluginOptions, i as FiscalLockPluginOptions, 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, x as CreditLimitPluginOptions, y as DoubleEntryPluginOptions } from "../index-ClLwzNRF.mjs";
|
|
2
2
|
export { type CreateLockPluginOptions, type CreditLimitPluginOptions, type DailyLockPluginOptions, type DoubleEntryPluginOptions, type FiscalLockPluginOptions, type FxRealizationPluginOptions, type IdempotencyPluginOptions, type LockAccountSelector, type LockHit, type LockResolver, type LockResolverContext, type PeriodResolverOptions, type WatermarkResolverOptions, createLockPlugin, creditLimitPlugin, dailyLockPlugin, doubleEntryPlugin, fiscalLockPlugin, fxRealizationPlugin, idempotencyPlugin, periodResolver, watermarkResolver };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@classytic/ledger",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"description": "Production-grade double-entry accounting engine for MongoDB — schemas, reports, tax, multi-tenant",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -90,7 +90,7 @@
|
|
|
90
90
|
"license": "MIT",
|
|
91
91
|
"repository": {
|
|
92
92
|
"type": "git",
|
|
93
|
-
"url": "git+https://github.com/classytic/
|
|
93
|
+
"url": "git+https://github.com/classytic/ledger.git"
|
|
94
94
|
},
|
|
95
95
|
"peerDependencies": {
|
|
96
96
|
"@classytic/fin-io": ">=0.1.0",
|
|
@@ -103,17 +103,17 @@
|
|
|
103
103
|
}
|
|
104
104
|
},
|
|
105
105
|
"devDependencies": {
|
|
106
|
-
"@biomejs/biome": "^2.4.
|
|
107
|
-
"@classytic/fin-io": "
|
|
106
|
+
"@biomejs/biome": "^2.4.12",
|
|
107
|
+
"@classytic/fin-io": "^0.1.0",
|
|
108
108
|
"@classytic/mongokit": "^3.6.4",
|
|
109
109
|
"@types/node": "^25.5.0",
|
|
110
|
-
"@vitest/coverage-v8": "^
|
|
111
|
-
"knip": "^6.
|
|
112
|
-
"mongodb-memory-server": "^
|
|
110
|
+
"@vitest/coverage-v8": "^4.1.4",
|
|
111
|
+
"knip": "^6.4.1",
|
|
112
|
+
"mongodb-memory-server": "^11.0.1",
|
|
113
113
|
"mongoose": "^9.4.1",
|
|
114
|
-
"tsdown": "^0.21.
|
|
114
|
+
"tsdown": "^0.21.8",
|
|
115
115
|
"typescript": "^5.7.0",
|
|
116
|
-
"vitest": "^
|
|
116
|
+
"vitest": "^4.1.4"
|
|
117
117
|
},
|
|
118
118
|
"engines": {
|
|
119
119
|
"node": ">=22"
|
|
@@ -121,8 +121,11 @@
|
|
|
121
121
|
"scripts": {
|
|
122
122
|
"build": "tsdown",
|
|
123
123
|
"dev": "tsdown --watch",
|
|
124
|
-
"test": "vitest run",
|
|
125
|
-
"test:
|
|
124
|
+
"test": "vitest run --project unit --project integration",
|
|
125
|
+
"test:unit": "vitest run --project unit",
|
|
126
|
+
"test:integration": "vitest run --project integration",
|
|
127
|
+
"test:all": "vitest run",
|
|
128
|
+
"test:watch": "vitest --project unit --project integration",
|
|
126
129
|
"test:coverage": "vitest run --coverage",
|
|
127
130
|
"typecheck": "tsc --noEmit",
|
|
128
131
|
"lint": "biome check src/",
|