@classytic/ledger 0.12.2 → 0.12.3
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 +32 -0
- package/dist/bridges/index.d.mts +2 -1
- package/dist/constants/index.d.mts +1 -1
- package/dist/country/index.d.mts +1 -1
- package/dist/events/index.d.mts +1 -1
- package/dist/exports/index.d.mts +1 -1
- package/dist/{index-pRW5cZhF.d.mts → index-CMyOuKd3.d.mts} +10 -8
- package/dist/{index-Cr57UKD-.d.mts → index-DmRItmfZ.d.mts} +1 -1
- package/dist/{index-DygMrab0.d.mts → index-Dq3Kt1IG.d.mts} +3 -45
- package/dist/index.d.mts +50 -9
- package/dist/index.mjs +47 -6
- package/dist/{journals-B1CePayM.d.mts → journals-DCsI2nFX.d.mts} +1 -1
- package/dist/plugins/index.d.mts +1 -1
- package/dist/reports/index.d.mts +1 -1
- package/dist/source.bridge-CqqsPWfn.d.mts +74 -0
- package/dist/{trial-balance-Dy_fAeJV.d.mts → trial-balance-BS7F7-Xe.d.mts} +2 -2
- package/docs/sync.md +56 -302
- package/package.json +9 -9
- /package/dist/{core-B90x0Abq.d.mts → core-D-2qfAJF.d.mts} +0 -0
- /package/dist/{index-BFPFihTF.d.mts → index-DkM0S1kQ.d.mts} +0 -0
- /package/dist/{outbox-store-CPLeocPg.d.mts → outbox-store-BcCiHMPw.d.mts} +0 -0
package/README.md
CHANGED
|
@@ -121,6 +121,38 @@ const engine = createAccountingEngine({
|
|
|
121
121
|
});
|
|
122
122
|
```
|
|
123
123
|
|
|
124
|
+
### Source provenance — `JournalEntry.sourceRef` (0.13.0+)
|
|
125
|
+
|
|
126
|
+
Every JE carries a typed `sourceRef: { sourceModel, sourceId, label?, kind? }`
|
|
127
|
+
slot for "what produced this whole JE". Per-line back-references live on
|
|
128
|
+
`journalItems[].sourceRef` (settles which document) and
|
|
129
|
+
`journalItems[].linkedRefs[]` (additional docs touched).
|
|
130
|
+
|
|
131
|
+
Add the index for fast source → JEs drill-down:
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
import { createAccountingEngine, ENTRY_SOURCE_INDEX } from '@classytic/ledger';
|
|
135
|
+
|
|
136
|
+
createAccountingEngine({
|
|
137
|
+
schemaOptions: {
|
|
138
|
+
journalEntry: { extraIndexes: [ENTRY_SOURCE_INDEX] },
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
// After import — stamp the back-reference, then query by it.
|
|
143
|
+
await JE.updateMany({ _importRunId: docId }, { $set: { sourceRef: {
|
|
144
|
+
sourceModel: 'SourceDocument', sourceId: docId,
|
|
145
|
+
label: 'INV-2026-001 — Acme Corp', kind: 'xero-invoice',
|
|
146
|
+
}}});
|
|
147
|
+
|
|
148
|
+
// Drill-down. Include `sourceModel` in the predicate so the query
|
|
149
|
+
// planner reliably picks `sourceRef_idx` (the partial index only
|
|
150
|
+
// contains stamped docs; the planner prefers it when both fields are
|
|
151
|
+
// constrained). The sourceId-only form returns identical results but
|
|
152
|
+
// may COLLSCAN on small collections.
|
|
153
|
+
await JE.find({ 'sourceRef.sourceModel': 'SourceDocument', 'sourceRef.sourceId': docId });
|
|
154
|
+
```
|
|
155
|
+
|
|
124
156
|
## Plugins
|
|
125
157
|
|
|
126
158
|
```ts
|
package/dist/bridges/index.d.mts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as PeriodLockedNotification, i as NotificationBridgeContext, n as EntryReversedNotification, o as ReconciliationMismatchNotification, r as NotificationBridge, s as ExchangeRateBridge, t as LedgerBridges } from "../index-Dq3Kt1IG.mjs";
|
|
2
|
+
import { n as SourceBridgeContext, r as SourceRef, t as SourceBridge } from "../source.bridge-CqqsPWfn.mjs";
|
|
2
3
|
export { EntryReversedNotification, ExchangeRateBridge, LedgerBridges, NotificationBridge, NotificationBridgeContext, PeriodLockedNotification, ReconciliationMismatchNotification, SourceBridge, SourceBridgeContext, SourceRef };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { S as isValidCategory, _ as getCategoryMainType, a as getJournalTypeCodes, b as isBalanceSheet, c as CURRENCIES, d as isValidCurrency, f as CATEGORIES, g as extractStatementType, h as extractMainType, i as getJournalType, l as getCurrency, m as categoryKey, n as JOURNAL_TYPES, o as isValidJournalType, p as CATEGORY_KEYS, r as getCustomJournalTypes, s as registerJournalType, t as JOURNAL_CODES, u as getMinorUnit, v as getCategoryStatementType, x as isIncomeStatement, y as getNormalBalance } from "../journals-
|
|
1
|
+
import { S as isValidCategory, _ as getCategoryMainType, a as getJournalTypeCodes, b as isBalanceSheet, c as CURRENCIES, d as isValidCurrency, f as CATEGORIES, g as extractStatementType, h as extractMainType, i as getJournalType, l as getCurrency, m as categoryKey, n as JOURNAL_TYPES, o as isValidJournalType, p as CATEGORY_KEYS, r as getCustomJournalTypes, s as registerJournalType, t as JOURNAL_CODES, u as getMinorUnit, v as getCategoryStatementType, x as isIncomeStatement, y as getNormalBalance } from "../journals-DCsI2nFX.mjs";
|
|
2
2
|
export { CATEGORIES, CATEGORY_KEYS, CURRENCIES, JOURNAL_CODES, JOURNAL_TYPES, categoryKey, extractMainType, extractStatementType, getCategoryMainType, getCategoryStatementType, getCurrency, getCustomJournalTypes, getJournalType, getJournalTypeCodes, getMinorUnit, getNormalBalance, isBalanceSheet, isIncomeStatement, isValidCategory, isValidCurrency, isValidJournalType, registerJournalType };
|
package/dist/country/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as defineCountryPack, n as CountryPackInput, r as JournalTemplate, t as CountryPack } from "../index-
|
|
1
|
+
import { i as defineCountryPack, n as CountryPackInput, r as JournalTemplate, t as CountryPack } from "../index-DmRItmfZ.mjs";
|
|
2
2
|
export { CountryPack, CountryPackInput, JournalTemplate, defineCountryPack };
|
package/dist/events/index.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { $ as ReconciliationUnmatchedPayload, A as LedgerEventDefinition, B as InProcessLedgerBusOptions, C as EntryPostedPayloadSchema, D as EntryUnpostedPayloadSchema, E as EntryUnposted, F as ReconciliationUnmatched, G as EntryArchivedPayload, H as createEvent, I as ReconciliationUnmatchedPayloadSchema, J as EntryPostedPayload, K as EntryCreatedPayload, L as ledgerEventDefinitions, M as LedgerEventSchema, N as ReconciliationMatched, O as JournalSeeded, P as ReconciliationMatchedPayloadSchema, Q as ReconciliationMatchedPayload, R as EventLogger, S as EntryPosted, T as EntryReversedPayloadSchema, U as AccountBulkCreatedPayload, V as EventContext, W as AccountSeededPayload, X as EntryUnpostedPayload, Y as EntryReversedPayload, Z as JournalSeededPayload, _ as EntryArchivedPayloadSchema, a as OutboxFailOptions, b as EntryDuplicated, c as OutboxFailurePolicy, d as OutboxWriteOptions, et as LEDGER_EVENTS, f as AccountBulkCreated, g as EntryArchived, h as AccountSeededPayloadSchema, i as OutboxErrorInfo, j as LedgerEventPayloadOf, k as JournalSeededPayloadSchema, l as OutboxOwnershipError, m as AccountSeeded, n as OutboxAcknowledgeOptions, o as OutboxFailureContext, p as AccountBulkCreatedPayloadSchema, q as EntryDuplicatedPayload, r as OutboxClaimOptions, s as OutboxFailureDecision, t as InvalidOutboxEventError, tt as LedgerEventName, u as OutboxStore, v as EntryCreated, w as EntryReversed, x as EntryDuplicatedPayloadSchema, y as EntryCreatedPayloadSchema, z as InProcessLedgerBus } from "../outbox-store-
|
|
1
|
+
import { $ as ReconciliationUnmatchedPayload, A as LedgerEventDefinition, B as InProcessLedgerBusOptions, C as EntryPostedPayloadSchema, D as EntryUnpostedPayloadSchema, E as EntryUnposted, F as ReconciliationUnmatched, G as EntryArchivedPayload, H as createEvent, I as ReconciliationUnmatchedPayloadSchema, J as EntryPostedPayload, K as EntryCreatedPayload, L as ledgerEventDefinitions, M as LedgerEventSchema, N as ReconciliationMatched, O as JournalSeeded, P as ReconciliationMatchedPayloadSchema, Q as ReconciliationMatchedPayload, R as EventLogger, S as EntryPosted, T as EntryReversedPayloadSchema, U as AccountBulkCreatedPayload, V as EventContext, W as AccountSeededPayload, X as EntryUnpostedPayload, Y as EntryReversedPayload, Z as JournalSeededPayload, _ as EntryArchivedPayloadSchema, a as OutboxFailOptions, b as EntryDuplicated, c as OutboxFailurePolicy, d as OutboxWriteOptions, et as LEDGER_EVENTS, f as AccountBulkCreated, g as EntryArchived, h as AccountSeededPayloadSchema, i as OutboxErrorInfo, j as LedgerEventPayloadOf, k as JournalSeededPayloadSchema, l as OutboxOwnershipError, m as AccountSeeded, n as OutboxAcknowledgeOptions, o as OutboxFailureContext, p as AccountBulkCreatedPayloadSchema, q as EntryDuplicatedPayload, r as OutboxClaimOptions, s as OutboxFailureDecision, t as InvalidOutboxEventError, tt as LedgerEventName, u as OutboxStore, v as EntryCreated, w as EntryReversed, x as EntryDuplicatedPayloadSchema, y as EntryCreatedPayloadSchema, z as InProcessLedgerBus } from "../outbox-store-BcCiHMPw.mjs";
|
|
2
2
|
import { DomainEvent, EventHandler, EventTransport, PublishManyResult } from "@classytic/primitives/events";
|
|
3
3
|
export { AccountBulkCreated, type AccountBulkCreatedPayload, type AccountBulkCreatedPayloadSchema, AccountSeeded, type AccountSeededPayload, type AccountSeededPayloadSchema, type DomainEvent, EntryArchived, type EntryArchivedPayload, type EntryArchivedPayloadSchema, EntryCreated, type EntryCreatedPayload, type EntryCreatedPayloadSchema, EntryDuplicated, type EntryDuplicatedPayload, type EntryDuplicatedPayloadSchema, EntryPosted, type EntryPostedPayload, type EntryPostedPayloadSchema, EntryReversed, type EntryReversedPayload, type EntryReversedPayloadSchema, EntryUnposted, type EntryUnpostedPayload, type EntryUnpostedPayloadSchema, type EventContext, type EventHandler, type EventLogger, type EventTransport, InProcessLedgerBus, type InProcessLedgerBusOptions, InvalidOutboxEventError, JournalSeeded, type JournalSeededPayload, type JournalSeededPayloadSchema, LEDGER_EVENTS, type LedgerEventDefinition, type LedgerEventName, type LedgerEventPayloadOf, type LedgerEventSchema, type OutboxAcknowledgeOptions, type OutboxClaimOptions, type OutboxErrorInfo, type OutboxFailOptions, type OutboxFailureContext, type OutboxFailureDecision, type OutboxFailurePolicy, OutboxOwnershipError, type OutboxStore, type OutboxWriteOptions, type PublishManyResult, ReconciliationMatched, type ReconciliationMatchedPayload, type ReconciliationMatchedPayloadSchema, ReconciliationUnmatched, type ReconciliationUnmatchedPayload, type ReconciliationUnmatchedPayloadSchema, createEvent, ledgerEventDefinitions };
|
package/dist/exports/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { _ as PopulatedJournalEntry, a as exportToCsv, c as getHeaders, d as serializeCsv, f as CsvOptions, g as PopulatedAccount, h as FlatJournalRow, i as quickbooksFieldMap, l as buildCsv, m as ExportFieldMap, n as flattenJournalEntry, o as extractAllRows, p as ExportField, r as universalFieldMap, s as extractRow, t as flattenJournalEntries, u as escapeCell, v as PopulatedJournalItem } from "../index-
|
|
1
|
+
import { _ as PopulatedJournalEntry, a as exportToCsv, c as getHeaders, d as serializeCsv, f as CsvOptions, g as PopulatedAccount, h as FlatJournalRow, i as quickbooksFieldMap, l as buildCsv, m as ExportFieldMap, n as flattenJournalEntry, o as extractAllRows, p as ExportField, r as universalFieldMap, s as extractRow, t as flattenJournalEntries, u as escapeCell, v as PopulatedJournalItem } from "../index-CMyOuKd3.mjs";
|
|
2
2
|
export { CsvOptions, ExportField, ExportFieldMap, FlatJournalRow, PopulatedAccount, PopulatedJournalEntry, PopulatedJournalItem, buildCsv, escapeCell, exportToCsv, extractAllRows, extractRow, flattenJournalEntries, flattenJournalEntry, getHeaders, quickbooksFieldMap, serializeCsv, universalFieldMap };
|
|
@@ -1,12 +1,6 @@
|
|
|
1
|
+
import { r as SourceRef } from "./source.bridge-CqqsPWfn.mjs";
|
|
2
|
+
|
|
1
3
|
//#region src/exports/types.d.ts
|
|
2
|
-
/**
|
|
3
|
-
* Export Types — Field maps, flat rows, and CSV builder configuration.
|
|
4
|
-
*
|
|
5
|
-
* All monetary values are in integer minor units (cents). For example,
|
|
6
|
-
* 10050 represents $100.50. Field maps convert to dollar strings at CSV output.
|
|
7
|
-
*
|
|
8
|
-
* @module @classytic/ledger/exports
|
|
9
|
-
*/
|
|
10
4
|
/**
|
|
11
5
|
* A populated account object (the shape after .populate('journalItems.account')).
|
|
12
6
|
* Only the fields the export module reads. Extra fields are ignored.
|
|
@@ -31,6 +25,12 @@ interface PopulatedJournalItem {
|
|
|
31
25
|
taxCode?: string;
|
|
32
26
|
taxName?: string;
|
|
33
27
|
}>;
|
|
28
|
+
/** Per-line source back-ref (0.13.0). Null defaults when unstamped. */
|
|
29
|
+
sourceRef?: SourceRef;
|
|
30
|
+
/** Additional docs this line touches (QBO `LinkedTxn[]` shape). */
|
|
31
|
+
linkedRefs?: SourceRef[];
|
|
32
|
+
/** Free-form per-line provenance. */
|
|
33
|
+
meta?: Record<string, unknown> | null;
|
|
34
34
|
/** Extra dimension fields from extraItemFields */
|
|
35
35
|
[key: string]: unknown;
|
|
36
36
|
}
|
|
@@ -49,6 +49,8 @@ interface PopulatedJournalEntry {
|
|
|
49
49
|
totalCredit: number;
|
|
50
50
|
state: 'draft' | 'posted' | 'archived';
|
|
51
51
|
reversed?: boolean;
|
|
52
|
+
/** Entry-level source back-ref (0.13.0). Null defaults when unstamped. */
|
|
53
|
+
sourceRef?: SourceRef;
|
|
52
54
|
createdAt?: Date | string;
|
|
53
55
|
updatedAt?: Date | string;
|
|
54
56
|
[key: string]: unknown;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { t as SourceBridge } from "./source.bridge-CqqsPWfn.mjs";
|
|
2
|
+
|
|
1
3
|
//#region src/bridges/exchange-rate.bridge.d.ts
|
|
2
4
|
/**
|
|
3
5
|
* Exchange Rate Bridge — host-injected rate sourcing.
|
|
@@ -114,50 +116,6 @@ interface NotificationBridge {
|
|
|
114
116
|
onReconciliationMismatch?(payload: ReconciliationMismatchNotification, ctx: NotificationBridgeContext): Promise<void>;
|
|
115
117
|
}
|
|
116
118
|
//#endregion
|
|
117
|
-
//#region src/bridges/source.bridge.d.ts
|
|
118
|
-
/**
|
|
119
|
-
* SourceBridge — host-implemented resolver for polymorphic external references.
|
|
120
|
-
*
|
|
121
|
-
* Ledger journal entries commonly carry a `reference`/`externalRef` pointing
|
|
122
|
-
* at a source document that lives outside the ledger package — an Invoice,
|
|
123
|
-
* Payment, Payroll Run, Stripe Charge, ERP voucher, etc. Storing these as
|
|
124
|
-
* opaque `String + sourceModel` (per PACKAGE_RULES §7) keeps the ledger
|
|
125
|
-
* transport-agnostic: the same schema works whether the source lives in the
|
|
126
|
-
* same Mongo, a different Mongo, Postgres, or an external REST API.
|
|
127
|
-
*
|
|
128
|
-
* Hosts implement `SourceBridge` to hydrate those refs when building
|
|
129
|
-
* enriched views (partner ledger with invoice details, audit trail with
|
|
130
|
-
* payment metadata, reconciliation UI with source documents, etc.).
|
|
131
|
-
*
|
|
132
|
-
* All methods are optional. Features that need resolution degrade gracefully
|
|
133
|
-
* when a bridge is not provided.
|
|
134
|
-
*/
|
|
135
|
-
interface SourceRef {
|
|
136
|
-
sourceId: string;
|
|
137
|
-
sourceModel: string;
|
|
138
|
-
}
|
|
139
|
-
interface SourceBridgeContext {
|
|
140
|
-
organizationId?: unknown;
|
|
141
|
-
actorId?: unknown;
|
|
142
|
-
[key: string]: unknown;
|
|
143
|
-
}
|
|
144
|
-
interface SourceBridge {
|
|
145
|
-
/**
|
|
146
|
-
* Resolve a single external reference.
|
|
147
|
-
*
|
|
148
|
-
* Return `null` when the source cannot be found (deleted, permission
|
|
149
|
-
* denied, wrong model). Do not throw for missing sources — callers
|
|
150
|
-
* expect `null` for graceful degradation.
|
|
151
|
-
*/
|
|
152
|
-
resolve?(sourceId: string, sourceModel: string, ctx: SourceBridgeContext): Promise<unknown | null>;
|
|
153
|
-
/**
|
|
154
|
-
* Batch resolver — avoids N+1 round-trips when enriching a list.
|
|
155
|
-
* Key the returned map by `sourceId`. Missing sources may be omitted or
|
|
156
|
-
* mapped to `null` at the implementer's discretion.
|
|
157
|
-
*/
|
|
158
|
-
resolveMany?(refs: ReadonlyArray<SourceRef>, ctx: SourceBridgeContext): Promise<Map<string, unknown>>;
|
|
159
|
-
}
|
|
160
|
-
//#endregion
|
|
161
119
|
//#region src/bridges/index.d.ts
|
|
162
120
|
/** Collected bridges exposed as `engine.bridges`. All optional per PACKAGE_RULES §23. */
|
|
163
121
|
interface LedgerBridges {
|
|
@@ -166,4 +124,4 @@ interface LedgerBridges {
|
|
|
166
124
|
exchangeRate?: ExchangeRateBridge | undefined;
|
|
167
125
|
}
|
|
168
126
|
//#endregion
|
|
169
|
-
export {
|
|
127
|
+
export { PeriodLockedNotification as a, NotificationBridgeContext as i, EntryReversedNotification as n, ReconciliationMismatchNotification as o, NotificationBridge as r, ExchangeRateBridge as s, LedgerBridges as t };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { i as
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
1
|
+
import { a as PeriodLockedNotification, i as NotificationBridgeContext, n as EntryReversedNotification, o as ReconciliationMismatchNotification, r as NotificationBridge, s as ExchangeRateBridge, t as LedgerBridges } from "./index-Dq3Kt1IG.mjs";
|
|
2
|
+
import { n as SourceBridgeContext, r as SourceRef, t as SourceBridge } from "./source.bridge-CqqsPWfn.mjs";
|
|
3
|
+
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-D-2qfAJF.mjs";
|
|
4
|
+
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-DCsI2nFX.mjs";
|
|
5
|
+
import { i as defineCountryPack, n as CountryPackInput, r as JournalTemplate, t as CountryPack } from "./index-DmRItmfZ.mjs";
|
|
6
|
+
import { $ as ReconciliationUnmatchedPayload, A as LedgerEventDefinition, B as InProcessLedgerBusOptions, E as EntryUnposted, F as ReconciliationUnmatched, G as EntryArchivedPayload, H as createEvent, J as EntryPostedPayload, K as EntryCreatedPayload, L as ledgerEventDefinitions, M as LedgerEventSchema, N as ReconciliationMatched, O as JournalSeeded, Q as ReconciliationMatchedPayload, R as EventLogger, S as EntryPosted, U as AccountBulkCreatedPayload, V as EventContext, W as AccountSeededPayload, X as EntryUnpostedPayload, Y as EntryReversedPayload, Z as JournalSeededPayload, a as OutboxFailOptions, b as EntryDuplicated, c as OutboxFailurePolicy, d as OutboxWriteOptions, et as LEDGER_EVENTS, f as AccountBulkCreated, g as EntryArchived, i as OutboxErrorInfo, j as LedgerEventPayloadOf, l as OutboxOwnershipError, m as AccountSeeded, n as OutboxAcknowledgeOptions, o as OutboxFailureContext, q as EntryDuplicatedPayload, r as OutboxClaimOptions, s as OutboxFailureDecision, t as InvalidOutboxEventError, tt as LedgerEventName, u as OutboxStore, v as EntryCreated, w as EntryReversed, z as InProcessLedgerBus } from "./outbox-store-BcCiHMPw.mjs";
|
|
7
|
+
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-CMyOuKd3.mjs";
|
|
7
8
|
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
|
-
import { $ as GeneralLedgerAccount, A as generateDimensionBreakdown, B as AgedBalanceOptions, D as DimensionBreakdownParams, E as DimensionBreakdownOptions, F as BudgetVsActualReport, G as DEFAULT_BUCKETS, H as AgedBalanceReport, I as BudgetVsActualRow, J as BalanceSheetReport, K as generateAgedBalance, L as generateBudgetVsActual, M as generateCashFlow, N as BudgetVsActualOptions, O as DimensionBreakdownReport, P as BudgetVsActualParams, Q as ComparativeMode, T as reopenFiscalPeriod, U as AgedBalanceRow, V as AgedBalanceParams, W as AgedBucketConfig, X as CashFlowReport, Y as BalanceSheetSection, Z as CashFlowSection, a as RevaluationReport, at as PeriodColumn, b as generateGeneralLedger, c as RevaluationRate, ct as ReportGroup, d as computeRevaluation, dt as TrialBalanceColumnRow, et as GeneralLedgerReport, f as PartnerLedgerLine, ft as TrialBalanceReport, g as generatePartnerLedger, h as PartnerLedgerReport, ht as defaultLogger, i as RevaluationParams, it as LedgerEntry, k as DimensionBreakdownRow, l as RevaluationResult, lt as ReportLine, m as PartnerLedgerParams, mt as Logger, n as generateTrialBalance, nt as IncomeStatementReport, o as generateRevaluation, ot as ReportAccount, p as PartnerLedgerOptions, pt as TrialBalanceRow, q as BalanceSheetLineSource, r as RevaluationOptions, rt as IncomeStatementSection, s as AccountForeignBalance, st as ReportCategory, tt as IncomeStatementLineSource, u as buildRevaluationEntry, ut as ReportSection, v as generateIncomeStatement, vt as DaybookParams, w as closeFiscalPeriod, yt as DaybookReport, z as generateBalanceSheet } from "./trial-balance-
|
|
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 { $ as GeneralLedgerAccount, A as generateDimensionBreakdown, B as AgedBalanceOptions, D as DimensionBreakdownParams, E as DimensionBreakdownOptions, F as BudgetVsActualReport, G as DEFAULT_BUCKETS, H as AgedBalanceReport, I as BudgetVsActualRow, J as BalanceSheetReport, K as generateAgedBalance, L as generateBudgetVsActual, M as generateCashFlow, N as BudgetVsActualOptions, O as DimensionBreakdownReport, P as BudgetVsActualParams, Q as ComparativeMode, T as reopenFiscalPeriod, U as AgedBalanceRow, V as AgedBalanceParams, W as AgedBucketConfig, X as CashFlowReport, Y as BalanceSheetSection, Z as CashFlowSection, a as RevaluationReport, at as PeriodColumn, b as generateGeneralLedger, c as RevaluationRate, ct as ReportGroup, d as computeRevaluation, dt as TrialBalanceColumnRow, et as GeneralLedgerReport, f as PartnerLedgerLine, ft as TrialBalanceReport, g as generatePartnerLedger, h as PartnerLedgerReport, ht as defaultLogger, i as RevaluationParams, it as LedgerEntry, k as DimensionBreakdownRow, l as RevaluationResult, lt as ReportLine, m as PartnerLedgerParams, mt as Logger, n as generateTrialBalance, nt as IncomeStatementReport, o as generateRevaluation, ot as ReportAccount, p as PartnerLedgerOptions, pt as TrialBalanceRow, q as BalanceSheetLineSource, r as RevaluationOptions, rt as IncomeStatementSection, s as AccountForeignBalance, st as ReportCategory, tt as IncomeStatementLineSource, u as buildRevaluationEntry, ut as ReportSection, v as generateIncomeStatement, vt as DaybookParams, w as closeFiscalPeriod, yt as DaybookReport, z as generateBalanceSheet } from "./trial-balance-BS7F7-Xe.mjs";
|
|
10
|
+
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-DkM0S1kQ.mjs";
|
|
10
11
|
import { DomainEvent, EventHandler, EventTransport, EventTransport as EventTransport$1, PublishManyResult } from "@classytic/primitives/events";
|
|
11
12
|
import { PaginationConfig, PluginFunction, PluginType, QueryParser, QueryParserOptions, Repository } from "@classytic/mongokit";
|
|
12
13
|
import mongoose, { ClientSession, Connection, Model } from "mongoose";
|
|
@@ -887,6 +888,16 @@ interface JournalEntryInput {
|
|
|
887
888
|
label?: string;
|
|
888
889
|
date: Date;
|
|
889
890
|
journalItems: JournalItemInput[];
|
|
891
|
+
/**
|
|
892
|
+
* Entry-level source back-reference (0.13.0+). Set at create time to stamp
|
|
893
|
+
* "what produced this whole JE". Most ingestion paths set this *after*
|
|
894
|
+
* insert via `repo.updateMany({ _importRunId }, { $set: { sourceRef } })`
|
|
895
|
+
* (because the source doc id is known only after the batch lands), but
|
|
896
|
+
* single-shot creators can pass it inline here. Drill-down: query
|
|
897
|
+
* `find({ 'sourceRef.sourceId': id })` — add `ENTRY_SOURCE_INDEX` to
|
|
898
|
+
* `schemaOptions.journalEntry.extraIndexes` for the index.
|
|
899
|
+
*/
|
|
900
|
+
sourceRef?: SourceRef;
|
|
890
901
|
/** Extra fields injected into the entry doc (dimension fields, tags, etc.). */
|
|
891
902
|
extra?: Record<string, unknown>;
|
|
892
903
|
}
|
|
@@ -901,6 +912,12 @@ interface JournalItemInput {
|
|
|
901
912
|
originalCredit?: Cents;
|
|
902
913
|
matchingNumber?: string;
|
|
903
914
|
maturityDate?: Date;
|
|
915
|
+
/** "The document this line settles" — primary per-line back-reference. */
|
|
916
|
+
sourceRef?: SourceRef;
|
|
917
|
+
/** Additional docs this line touches (QBO `LinkedTxn[]` shape). */
|
|
918
|
+
linkedRefs?: SourceRef[];
|
|
919
|
+
/** Free-form per-line provenance (cost-center, project code, etc). */
|
|
920
|
+
meta?: Record<string, unknown> | null;
|
|
904
921
|
}
|
|
905
922
|
//#endregion
|
|
906
923
|
//#region src/builders/opening-balance.d.ts
|
|
@@ -972,6 +989,30 @@ declare function buildOpeningBalanceEntry(input: OpeningBalanceInput): OpeningBa
|
|
|
972
989
|
* },
|
|
973
990
|
* });
|
|
974
991
|
*/
|
|
992
|
+
/**
|
|
993
|
+
* Recommended opt-in index for the entry-level `sourceRef` field (0.13.0+).
|
|
994
|
+
*
|
|
995
|
+
* Spread into `schemaOptions.journalEntry.extraIndexes` to enable fast
|
|
996
|
+
* "list every JE produced by source document X" lookups — the canonical
|
|
997
|
+
* bookkeeping-UI drill-down from a source document (invoice, bill, bank
|
|
998
|
+
* statement) into its derived journal entries.
|
|
999
|
+
*
|
|
1000
|
+
* Sparse + partial: only JEs where `sourceRef.sourceModel` is a string get
|
|
1001
|
+
* indexed. Unstamped JEs (the default `{ sourceModel: null, sourceId: null }`)
|
|
1002
|
+
* cost zero index storage.
|
|
1003
|
+
*
|
|
1004
|
+
* @example
|
|
1005
|
+
* import { createAccountingEngine, ENTRY_SOURCE_INDEX } from '@classytic/ledger';
|
|
1006
|
+
* createAccountingEngine({
|
|
1007
|
+
* schemaOptions: {
|
|
1008
|
+
* journalEntry: { extraIndexes: [ENTRY_SOURCE_INDEX] },
|
|
1009
|
+
* },
|
|
1010
|
+
* });
|
|
1011
|
+
*/
|
|
1012
|
+
declare const ENTRY_SOURCE_INDEX: {
|
|
1013
|
+
fields: Record<string, 1 | -1>;
|
|
1014
|
+
options: Record<string, unknown>;
|
|
1015
|
+
};
|
|
975
1016
|
declare const LINE_SOURCE_INDEXES: ReadonlyArray<{
|
|
976
1017
|
fields: Record<string, 1 | -1>;
|
|
977
1018
|
options: Record<string, unknown>;
|
|
@@ -1198,4 +1239,4 @@ interface PostingResult {
|
|
|
1198
1239
|
idempotencyKeys?: string[];
|
|
1199
1240
|
}
|
|
1200
1241
|
//#endregion
|
|
1201
|
-
export { AccountBulkCreated, type AccountBulkCreatedPayload, type AccountCode, type AccountForeignBalance, type AccountRepository, AccountSeeded, 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 BalanceSheetLineSource, type BalanceSheetReport, type BalanceSheetSection, type BudgetVsActualOptions, type BudgetVsActualParams, type BudgetVsActualReport, type BudgetVsActualRow, type BulkCreateInput, type BulkCreateResult, CATEGORIES, CATEGORY_KEYS, CURRENCIES, type CashFlowCategory, type CashFlowReport, type CashFlowSection, type CategoryKey, type Cents, type ComparativeMode, 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, EntryArchived, type EntryArchivedPayload, EntryCreated, type EntryCreatedPayload, EntryDuplicated, type EntryDuplicatedPayload, EntryPosted, type EntryPostedPayload, EntryReversed, type EntryReversedNotification, type EntryReversedPayload, type EntryState, EntryUnposted, 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 IncomeStatementLineSource, type IncomeStatementReport, type IncomeStatementSection, type IntrospectAPI, InvalidOutboxEventError, JOURNAL_CODES, JOURNAL_TYPES, type JournalEntryInput, type JournalEntryRepository, type JournalItem, type JournalItemInput, type JournalItemRef, type JournalRepository, type JournalSchemaOptions, JournalSeeded, type JournalSeededPayload, type JournalTemplate, type JournalType, LEDGER_EVENTS, LINE_SOURCE_INDEXES, type LedgerBridges, type LedgerEntry, type LedgerEventDefinition, type LedgerEventName, type LedgerEventPayloadOf, type LedgerEventSchema, 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 OpeningBalanceInput, type OpeningBalanceResult, type OutboxAcknowledgeOptions, type OutboxClaimOptions, type OutboxErrorInfo, type OutboxFailOptions, type OutboxFailureContext, type OutboxFailureDecision, type OutboxFailurePolicy, OutboxOwnershipError, type OutboxStore, type OutboxWriteOptions, type PartnerLedgerLine, type PartnerLedgerOptions, type PartnerLedgerParams, type PartnerLedgerReport, type PeriodColumn, type PeriodLockedNotification, type PeriodResolverOptions, type PopulatedJournalEntry, type PostOptions, type PostingContract, type PostingResult, type PublishManyResult, ReconciliationMatched, type ReconciliationMatchedPayload, type ReconciliationMismatchNotification, type ReconciliationRepository, ReconciliationUnmatched, 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 ReportLine, type ReportSection, 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 TrialBalanceColumnRow, type TrialBalanceReport, type TrialBalanceRow, type UnmatchHookContext, type WatermarkResolverOptions, acquireSession, add, allocate, buildAccountTypeMap, buildDimensionFields, buildDimensionIndexes, buildItemFilters, buildOpeningBalanceEntry, 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, ledgerEventDefinitions, multiply, parseCents, percentage, periodResolver, quickbooksFieldMap, registerJournalType, reopenFiscalPeriod, resolveModelNames, splitTaxExclusive, splitTaxInclusive, subtract, toDecimal, universalFieldMap, watermarkResolver };
|
|
1242
|
+
export { AccountBulkCreated, type AccountBulkCreatedPayload, type AccountCode, type AccountForeignBalance, type AccountRepository, AccountSeeded, 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 BalanceSheetLineSource, type BalanceSheetReport, type BalanceSheetSection, type BudgetVsActualOptions, type BudgetVsActualParams, type BudgetVsActualReport, type BudgetVsActualRow, type BulkCreateInput, type BulkCreateResult, CATEGORIES, CATEGORY_KEYS, CURRENCIES, type CashFlowCategory, type CashFlowReport, type CashFlowSection, type CategoryKey, type Cents, type ComparativeMode, 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, ENTRY_SOURCE_INDEX, EntryArchived, type EntryArchivedPayload, EntryCreated, type EntryCreatedPayload, EntryDuplicated, type EntryDuplicatedPayload, EntryPosted, type EntryPostedPayload, EntryReversed, type EntryReversedNotification, type EntryReversedPayload, type EntryState, EntryUnposted, 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 IncomeStatementLineSource, type IncomeStatementReport, type IncomeStatementSection, type IntrospectAPI, InvalidOutboxEventError, JOURNAL_CODES, JOURNAL_TYPES, type JournalEntryInput, type JournalEntryRepository, type JournalItem, type JournalItemInput, type JournalItemRef, type JournalRepository, type JournalSchemaOptions, JournalSeeded, type JournalSeededPayload, type JournalTemplate, type JournalType, LEDGER_EVENTS, LINE_SOURCE_INDEXES, type LedgerBridges, type LedgerEntry, type LedgerEventDefinition, type LedgerEventName, type LedgerEventPayloadOf, type LedgerEventSchema, 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 OpeningBalanceInput, type OpeningBalanceResult, type OutboxAcknowledgeOptions, type OutboxClaimOptions, type OutboxErrorInfo, type OutboxFailOptions, type OutboxFailureContext, type OutboxFailureDecision, type OutboxFailurePolicy, OutboxOwnershipError, type OutboxStore, type OutboxWriteOptions, type PartnerLedgerLine, type PartnerLedgerOptions, type PartnerLedgerParams, type PartnerLedgerReport, type PeriodColumn, type PeriodLockedNotification, type PeriodResolverOptions, type PopulatedJournalEntry, type PostOptions, type PostingContract, type PostingResult, type PublishManyResult, ReconciliationMatched, type ReconciliationMatchedPayload, type ReconciliationMismatchNotification, type ReconciliationRepository, ReconciliationUnmatched, 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 ReportLine, type ReportSection, 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 TrialBalanceColumnRow, type TrialBalanceReport, type TrialBalanceRow, type UnmatchHookContext, type WatermarkResolverOptions, acquireSession, add, allocate, buildAccountTypeMap, buildDimensionFields, buildDimensionIndexes, buildItemFilters, buildOpeningBalanceEntry, 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, ledgerEventDefinitions, multiply, parseCents, percentage, periodResolver, quickbooksFieldMap, registerJournalType, reopenFiscalPeriod, resolveModelNames, splitTaxExclusive, splitTaxInclusive, subtract, toDecimal, universalFieldMap, watermarkResolver };
|
package/dist/index.mjs
CHANGED
|
@@ -497,13 +497,42 @@ function createJournalSchema(config, accountModelName, options = {}) {
|
|
|
497
497
|
* },
|
|
498
498
|
* });
|
|
499
499
|
*/
|
|
500
|
+
/**
|
|
501
|
+
* Recommended opt-in index for the entry-level `sourceRef` field (0.13.0+).
|
|
502
|
+
*
|
|
503
|
+
* Spread into `schemaOptions.journalEntry.extraIndexes` to enable fast
|
|
504
|
+
* "list every JE produced by source document X" lookups — the canonical
|
|
505
|
+
* bookkeeping-UI drill-down from a source document (invoice, bill, bank
|
|
506
|
+
* statement) into its derived journal entries.
|
|
507
|
+
*
|
|
508
|
+
* Sparse + partial: only JEs where `sourceRef.sourceModel` is a string get
|
|
509
|
+
* indexed. Unstamped JEs (the default `{ sourceModel: null, sourceId: null }`)
|
|
510
|
+
* cost zero index storage.
|
|
511
|
+
*
|
|
512
|
+
* @example
|
|
513
|
+
* import { createAccountingEngine, ENTRY_SOURCE_INDEX } from '@classytic/ledger';
|
|
514
|
+
* createAccountingEngine({
|
|
515
|
+
* schemaOptions: {
|
|
516
|
+
* journalEntry: { extraIndexes: [ENTRY_SOURCE_INDEX] },
|
|
517
|
+
* },
|
|
518
|
+
* });
|
|
519
|
+
*/
|
|
520
|
+
const ENTRY_SOURCE_INDEX = {
|
|
521
|
+
fields: {
|
|
522
|
+
"sourceRef.sourceModel": 1,
|
|
523
|
+
"sourceRef.sourceId": 1
|
|
524
|
+
},
|
|
525
|
+
options: {
|
|
526
|
+
partialFilterExpression: { "sourceRef.sourceModel": { $type: "string" } },
|
|
527
|
+
name: "sourceRef_idx"
|
|
528
|
+
}
|
|
529
|
+
};
|
|
500
530
|
const LINE_SOURCE_INDEXES = [{
|
|
501
531
|
fields: {
|
|
502
532
|
"journalItems.sourceRef.sourceModel": 1,
|
|
503
533
|
"journalItems.sourceRef.sourceId": 1
|
|
504
534
|
},
|
|
505
535
|
options: {
|
|
506
|
-
sparse: true,
|
|
507
536
|
partialFilterExpression: { "journalItems.sourceRef.sourceModel": { $type: "string" } },
|
|
508
537
|
name: "journalItems_sourceRef_idx"
|
|
509
538
|
}
|
|
@@ -525,7 +554,7 @@ function createJournalEntrySchema(config, accountModelName, options = {}) {
|
|
|
525
554
|
taxCode: { type: String },
|
|
526
555
|
taxName: { type: String }
|
|
527
556
|
}, { _id: false });
|
|
528
|
-
const
|
|
557
|
+
const SourceRefSchema = new mongoose.Schema({
|
|
529
558
|
sourceModel: {
|
|
530
559
|
type: String,
|
|
531
560
|
default: null
|
|
@@ -533,6 +562,14 @@ function createJournalEntrySchema(config, accountModelName, options = {}) {
|
|
|
533
562
|
sourceId: {
|
|
534
563
|
type: String,
|
|
535
564
|
default: null
|
|
565
|
+
},
|
|
566
|
+
label: {
|
|
567
|
+
type: String,
|
|
568
|
+
default: null
|
|
569
|
+
},
|
|
570
|
+
kind: {
|
|
571
|
+
type: String,
|
|
572
|
+
default: null
|
|
536
573
|
}
|
|
537
574
|
}, { _id: false });
|
|
538
575
|
const amountValidator = {
|
|
@@ -603,11 +640,11 @@ function createJournalEntrySchema(config, accountModelName, options = {}) {
|
|
|
603
640
|
default: null
|
|
604
641
|
},
|
|
605
642
|
sourceRef: {
|
|
606
|
-
type:
|
|
643
|
+
type: SourceRefSchema,
|
|
607
644
|
default: () => ({})
|
|
608
645
|
},
|
|
609
646
|
linkedRefs: {
|
|
610
|
-
type: [
|
|
647
|
+
type: [SourceRefSchema],
|
|
611
648
|
default: void 0
|
|
612
649
|
},
|
|
613
650
|
...currencyItemFields,
|
|
@@ -688,6 +725,10 @@ function createJournalEntrySchema(config, accountModelName, options = {}) {
|
|
|
688
725
|
type: mongoose.Schema.Types.Mixed,
|
|
689
726
|
default: null
|
|
690
727
|
},
|
|
728
|
+
sourceRef: {
|
|
729
|
+
type: SourceRefSchema,
|
|
730
|
+
default: () => ({})
|
|
731
|
+
},
|
|
691
732
|
...extraFields
|
|
692
733
|
};
|
|
693
734
|
if (config.audit?.trackActor) {
|
|
@@ -783,6 +824,7 @@ function createJournalEntrySchema(config, accountModelName, options = {}) {
|
|
|
783
824
|
partialFilterExpression: { idempotencyKey: { $type: "string" } }
|
|
784
825
|
});
|
|
785
826
|
}
|
|
827
|
+
for (const idx of extraIndexes) schema.index(idx.fields, idx.options);
|
|
786
828
|
injectTenantField(schema, scope);
|
|
787
829
|
if (indexes) {
|
|
788
830
|
schema.index({
|
|
@@ -801,7 +843,6 @@ function createJournalEntrySchema(config, accountModelName, options = {}) {
|
|
|
801
843
|
},
|
|
802
844
|
name: "journal_text_idx"
|
|
803
845
|
});
|
|
804
|
-
for (const idx of extraIndexes) schema.index(idx.fields, idx.options);
|
|
805
846
|
return schema;
|
|
806
847
|
}
|
|
807
848
|
//#endregion
|
|
@@ -3129,4 +3170,4 @@ function buildDimensionIndexes(dimensions, orgField) {
|
|
|
3129
3170
|
});
|
|
3130
3171
|
}
|
|
3131
3172
|
//#endregion
|
|
3132
|
-
export { AccountBulkCreated, AccountSeeded, AccountingEngine, AccountingError, CATEGORIES, CATEGORY_KEYS, CURRENCIES, ConcurrencyError, DEFAULT_BUCKETS, DuplicateReferenceError, EntryArchived, EntryCreated, EntryDuplicated, EntryPosted, EntryReversed, EntryUnposted, Errors, IdempotencyConflictError, ImmutableViolationError, InProcessLedgerBus, InvalidOutboxEventError, JOURNAL_CODES, JOURNAL_TYPES, JournalSeeded, LEDGER_EVENTS, LINE_SOURCE_INDEXES, Money, OutboxOwnershipError, ReconciliationMatched, ReconciliationUnmatched, acquireSession, add, allocate, buildAccountTypeMap, buildDimensionFields, buildDimensionIndexes, buildItemFilters, buildOpeningBalanceEntry, 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, ledgerEventDefinitions, multiply, parseCents, percentage, periodResolver, quickbooksFieldMap, registerJournalType, reopenFiscalPeriod, resolveModelNames, splitTaxExclusive, splitTaxInclusive, subtract, toDecimal, universalFieldMap, watermarkResolver };
|
|
3173
|
+
export { AccountBulkCreated, AccountSeeded, AccountingEngine, AccountingError, CATEGORIES, CATEGORY_KEYS, CURRENCIES, ConcurrencyError, DEFAULT_BUCKETS, DuplicateReferenceError, ENTRY_SOURCE_INDEX, EntryArchived, EntryCreated, EntryDuplicated, EntryPosted, EntryReversed, EntryUnposted, Errors, IdempotencyConflictError, ImmutableViolationError, InProcessLedgerBus, InvalidOutboxEventError, JOURNAL_CODES, JOURNAL_TYPES, JournalSeeded, LEDGER_EVENTS, LINE_SOURCE_INDEXES, Money, OutboxOwnershipError, ReconciliationMatched, ReconciliationUnmatched, acquireSession, add, allocate, buildAccountTypeMap, buildDimensionFields, buildDimensionIndexes, buildItemFilters, buildOpeningBalanceEntry, 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, ledgerEventDefinitions, multiply, parseCents, percentage, periodResolver, quickbooksFieldMap, registerJournalType, reopenFiscalPeriod, resolveModelNames, splitTaxExclusive, splitTaxInclusive, subtract, toDecimal, universalFieldMap, watermarkResolver };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { d as JournalType, f as MainType, h as StatementType, i as CategoryKey, o as Currency, r as Category } from "./core-
|
|
1
|
+
import { d as JournalType, f as MainType, h as StatementType, i as CategoryKey, o as Currency, r as Category } from "./core-D-2qfAJF.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/constants/categories.d.ts
|
|
4
4
|
/** All valid categories */
|
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-DkM0S1kQ.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/dist/reports/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { A as generateDimensionBreakdown, B as AgedBalanceOptions, C as FiscalReopenResult, D as DimensionBreakdownParams, E as DimensionBreakdownOptions, F as BudgetVsActualReport, G as DEFAULT_BUCKETS, H as AgedBalanceReport, I as BudgetVsActualRow, K as generateAgedBalance, L as generateBudgetVsActual, M as generateCashFlow, N as BudgetVsActualOptions, O as DimensionBreakdownReport, P as BudgetVsActualParams, R as BalanceSheetOptions, S as FiscalCloseResult, T as reopenFiscalPeriod, U as AgedBalanceRow, V as AgedBalanceParams, W as AgedBucketConfig, _ as IncomeStatementOptions, _t as DaybookOptions, a as RevaluationReport, b as generateGeneralLedger, bt as generateDaybook, f as PartnerLedgerLine, g as generatePartnerLedger, gt as DaybookLine, h as PartnerLedgerReport, i as RevaluationParams, j as CashFlowOptions, k as DimensionBreakdownRow, m as PartnerLedgerParams, n as generateTrialBalance, o as generateRevaluation, p as PartnerLedgerOptions, r as RevaluationOptions, t as TrialBalanceOptions, v as generateIncomeStatement, vt as DaybookParams, w as closeFiscalPeriod, x as FiscalCloseOptions, y as GeneralLedgerOptions, yt as DaybookReport, z as generateBalanceSheet } from "../trial-balance-
|
|
1
|
+
import { A as generateDimensionBreakdown, B as AgedBalanceOptions, C as FiscalReopenResult, D as DimensionBreakdownParams, E as DimensionBreakdownOptions, F as BudgetVsActualReport, G as DEFAULT_BUCKETS, H as AgedBalanceReport, I as BudgetVsActualRow, K as generateAgedBalance, L as generateBudgetVsActual, M as generateCashFlow, N as BudgetVsActualOptions, O as DimensionBreakdownReport, P as BudgetVsActualParams, R as BalanceSheetOptions, S as FiscalCloseResult, T as reopenFiscalPeriod, U as AgedBalanceRow, V as AgedBalanceParams, W as AgedBucketConfig, _ as IncomeStatementOptions, _t as DaybookOptions, a as RevaluationReport, b as generateGeneralLedger, bt as generateDaybook, f as PartnerLedgerLine, g as generatePartnerLedger, gt as DaybookLine, h as PartnerLedgerReport, i as RevaluationParams, j as CashFlowOptions, k as DimensionBreakdownRow, m as PartnerLedgerParams, n as generateTrialBalance, o as generateRevaluation, p as PartnerLedgerOptions, r as RevaluationOptions, t as TrialBalanceOptions, v as generateIncomeStatement, vt as DaybookParams, w as closeFiscalPeriod, x as FiscalCloseOptions, y as GeneralLedgerOptions, yt as DaybookReport, z as generateBalanceSheet } from "../trial-balance-BS7F7-Xe.mjs";
|
|
2
2
|
export { type AgedBalanceOptions, type AgedBalanceParams, type AgedBalanceReport, type AgedBalanceRow, type AgedBucketConfig, type BalanceSheetOptions, type BudgetVsActualOptions, type BudgetVsActualParams, type BudgetVsActualReport, type BudgetVsActualRow, type CashFlowOptions, DEFAULT_BUCKETS, type DaybookLine, type DaybookOptions, type DaybookParams, type DaybookReport, type DimensionBreakdownOptions, type DimensionBreakdownParams, type DimensionBreakdownReport, type DimensionBreakdownRow, type FiscalCloseOptions, type FiscalCloseResult, type FiscalReopenResult, type GeneralLedgerOptions, type IncomeStatementOptions, type PartnerLedgerLine, type PartnerLedgerOptions, type PartnerLedgerParams, type PartnerLedgerReport, type RevaluationOptions, type RevaluationParams, type RevaluationReport, type TrialBalanceOptions, closeFiscalPeriod, generateAgedBalance, generateBalanceSheet, generateBudgetVsActual, generateCashFlow, generateDaybook, generateDimensionBreakdown, generateGeneralLedger, generateIncomeStatement, generatePartnerLedger, generateRevaluation, generateTrialBalance, reopenFiscalPeriod };
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
//#region src/bridges/source.bridge.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* SourceBridge — host-implemented resolver for polymorphic external references.
|
|
4
|
+
*
|
|
5
|
+
* Ledger journal entries commonly carry a `reference`/`externalRef` pointing
|
|
6
|
+
* at a source document that lives outside the ledger package — an Invoice,
|
|
7
|
+
* Payment, Payroll Run, Stripe Charge, ERP voucher, etc. Storing these as
|
|
8
|
+
* opaque `String + sourceModel` (per PACKAGE_RULES §7) keeps the ledger
|
|
9
|
+
* transport-agnostic: the same schema works whether the source lives in the
|
|
10
|
+
* same Mongo, a different Mongo, Postgres, or an external REST API.
|
|
11
|
+
*
|
|
12
|
+
* Hosts implement `SourceBridge` to hydrate those refs when building
|
|
13
|
+
* enriched views (partner ledger with invoice details, audit trail with
|
|
14
|
+
* payment metadata, reconciliation UI with source documents, etc.).
|
|
15
|
+
*
|
|
16
|
+
* All methods are optional. Features that need resolution degrade gracefully
|
|
17
|
+
* when a bridge is not provided.
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Polymorphic back-reference to a host source document — the universal
|
|
21
|
+
* "what produced this entry" pointer used by both the entry-level
|
|
22
|
+
* `JournalEntry.sourceRef` slot and the line-level
|
|
23
|
+
* `JournalEntry.journalItems[].sourceRef` slot.
|
|
24
|
+
*
|
|
25
|
+
* Required:
|
|
26
|
+
* - `sourceModel` — host model namespace (`"SourceDocument"`,
|
|
27
|
+
* `"BankStatement"`, `"Invoice"`, `"PayrollRun"`, …).
|
|
28
|
+
* - `sourceId` — opaque string identifier (ObjectId hex, ULID, or a
|
|
29
|
+
* human-readable number like `INV-2026-04-001`). String — not ObjectId —
|
|
30
|
+
* because the ledger has no knowledge of consumer model namespaces.
|
|
31
|
+
*
|
|
32
|
+
* Optional denormalization (0.13.0+):
|
|
33
|
+
* - `label` — human-readable name of the source (statement label,
|
|
34
|
+
* invoice number with party). Renders "From: <label>" in audit / drill-down
|
|
35
|
+
* UIs without a follow-up `SourceBridge.resolve()` call.
|
|
36
|
+
* - `kind` — sub-classifier of `sourceModel` (e.g. `"xero-invoice"`,
|
|
37
|
+
* `"qbo-bill"`, `"bank-statement"`). Lets the UI route to the correct
|
|
38
|
+
* detail page without re-querying the source.
|
|
39
|
+
*
|
|
40
|
+
* Both optional fields are denormalized — labels rarely change, and if they
|
|
41
|
+
* do, a one-shot `updateMany({ 'sourceRef.sourceId': id }, { $set: ... })`
|
|
42
|
+
* refreshes stale copies. The tradeoff buys the bookkeeping UI a fast path
|
|
43
|
+
* for "show me every JE produced by this document" without N+1 source-doc
|
|
44
|
+
* fetches.
|
|
45
|
+
*/
|
|
46
|
+
interface SourceRef {
|
|
47
|
+
sourceId: string;
|
|
48
|
+
sourceModel: string;
|
|
49
|
+
label?: string | null;
|
|
50
|
+
kind?: string | null;
|
|
51
|
+
}
|
|
52
|
+
interface SourceBridgeContext {
|
|
53
|
+
organizationId?: unknown;
|
|
54
|
+
actorId?: unknown;
|
|
55
|
+
[key: string]: unknown;
|
|
56
|
+
}
|
|
57
|
+
interface SourceBridge {
|
|
58
|
+
/**
|
|
59
|
+
* Resolve a single external reference.
|
|
60
|
+
*
|
|
61
|
+
* Return `null` when the source cannot be found (deleted, permission
|
|
62
|
+
* denied, wrong model). Do not throw for missing sources — callers
|
|
63
|
+
* expect `null` for graceful degradation.
|
|
64
|
+
*/
|
|
65
|
+
resolve?(sourceId: string, sourceModel: string, ctx: SourceBridgeContext): Promise<unknown | null>;
|
|
66
|
+
/**
|
|
67
|
+
* Batch resolver — avoids N+1 round-trips when enriching a list.
|
|
68
|
+
* Key the returned map by `sourceId`. Missing sources may be omitted or
|
|
69
|
+
* mapped to `null` at the implementer's discretion.
|
|
70
|
+
*/
|
|
71
|
+
resolveMany?(refs: ReadonlyArray<SourceRef>, ctx: SourceBridgeContext): Promise<Map<string, unknown>>;
|
|
72
|
+
}
|
|
73
|
+
//#endregion
|
|
74
|
+
export { SourceBridgeContext as n, SourceRef as r, SourceBridge as t };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { c as DateRange } from "./core-
|
|
2
|
-
import { t as CountryPack } from "./index-
|
|
1
|
+
import { c as DateRange } from "./core-D-2qfAJF.mjs";
|
|
2
|
+
import { t as CountryPack } from "./index-DmRItmfZ.mjs";
|
|
3
3
|
import { ClientSession, Model } from "mongoose";
|
|
4
4
|
|
|
5
5
|
//#region src/reports/daybook.d.ts
|
package/docs/sync.md
CHANGED
|
@@ -1,330 +1,84 @@
|
|
|
1
|
-
# Sync —
|
|
1
|
+
# Sync — Removed in 0.11.0
|
|
2
2
|
|
|
3
|
-
`@classytic/ledger/sync`
|
|
3
|
+
> **The `@classytic/ledger/sync` subpath was removed in `@classytic/ledger@0.11.0`.**
|
|
4
|
+
> Sync orchestration is now host responsibility. This doc page is preserved
|
|
5
|
+
> so links from older releases still resolve to a useful migration pointer
|
|
6
|
+
> instead of a 404.
|
|
4
7
|
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
// Invoice engine bridge (recommended)
|
|
8
|
-
createLedgerBridge,
|
|
8
|
+
## What used to live here
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
wireImport,
|
|
12
|
-
wireExport,
|
|
10
|
+
The `/sync` subpath shipped with three concerns bundled together:
|
|
13
11
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
journalEntryMapper,
|
|
18
|
-
openingBalanceMapper,
|
|
19
|
-
} from '@classytic/ledger/sync';
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
---
|
|
23
|
-
|
|
24
|
-
## Invoice Engine Integration
|
|
25
|
-
|
|
26
|
-
### Recommended: `createLedgerBridge()`
|
|
27
|
-
|
|
28
|
-
Wire `@classytic/invoice` to `@classytic/ledger` with one call. The bridge handles account mapping, tax lines, credit notes, payments, and reversals — no manual journal wiring needed.
|
|
29
|
-
|
|
30
|
-
```typescript
|
|
31
|
-
import { createAccountingEngine } from '@classytic/ledger';
|
|
32
|
-
import { createLedgerBridge } from '@classytic/ledger/sync';
|
|
33
|
-
import { createInvoiceEngine } from '@classytic/invoice';
|
|
34
|
-
import { canadaPack } from '@classytic/ledger-ca';
|
|
35
|
-
|
|
36
|
-
// 1. Create the accounting engine
|
|
37
|
-
const accounting = createAccountingEngine({
|
|
38
|
-
mongoose: connection,
|
|
39
|
-
country: canadaPack,
|
|
40
|
-
currency: 'CAD',
|
|
41
|
-
multiTenant: { orgField: 'organizationId', orgRef: 'Organization' },
|
|
42
|
-
idempotency: true,
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
// 2. Create the bridge — map your chart of accounts once
|
|
46
|
-
const bridge = createLedgerBridge(accounting, {
|
|
47
|
-
accounts: {
|
|
48
|
-
receivable: '1200', // Accounts Receivable
|
|
49
|
-
payable: '2000', // Accounts Payable
|
|
50
|
-
revenue: '4000', // Revenue
|
|
51
|
-
expense: '5000', // Cost of Goods Sold / Expenses
|
|
52
|
-
taxPayable: '2100', // HST/GST/VAT Payable
|
|
53
|
-
taxReceivable: '1150', // HST/GST/VAT Receivable (Input Tax Credit)
|
|
54
|
-
cash: '1000', // Cash / Bank
|
|
55
|
-
},
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
// 3. Pass the bridge to the invoice engine — done
|
|
59
|
-
const invoicing = createInvoiceEngine({
|
|
60
|
-
mongoose: connection,
|
|
61
|
-
ledger: bridge,
|
|
62
|
-
// ... other invoice config
|
|
63
|
-
});
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
From this point, every invoice lifecycle operation automatically posts to the ledger:
|
|
67
|
-
|
|
68
|
-
- **`invoicing.services.posting.post(id)`** → creates a balanced journal entry
|
|
69
|
-
- **`invoicing.services.payment.recordPayment(input)`** → posts a payment entry (DR Cash, CR AR)
|
|
70
|
-
- **`invoicing.services.posting.cancel(id, reason)`** → reverses the journal entry
|
|
71
|
-
- **`invoicing.services.posting.void(id, reason)`** → reverses the journal entry (even if partially paid)
|
|
72
|
-
|
|
73
|
-
### How the bridge maps each move type
|
|
74
|
-
|
|
75
|
-
| Invoice Move Type | Journal Lines | Journal Type |
|
|
76
|
-
|---|---|---|
|
|
77
|
-
| `out_invoice` (Customer Invoice) | DR Receivable (total), CR Revenue (per line), CR Tax Payable | `SALES` |
|
|
78
|
-
| `in_invoice` (Vendor Bill) | DR Expense (per line), DR Tax Receivable, CR Payable (total) | `PURCHASES` |
|
|
79
|
-
| `out_refund` (Customer Credit Note) | CR Receivable, DR Revenue (per line), DR Tax Payable | `SALES` |
|
|
80
|
-
| `in_refund` (Vendor Credit Note) | DR Payable, CR Expense (per line), CR Tax Receivable | `PURCHASES` |
|
|
81
|
-
| `receipt` (POS Receipt) | DR Receivable/Cash, CR Revenue (per line), CR Tax Payable | `CASH_RECEIPTS` |
|
|
82
|
-
|
|
83
|
-
All amounts are integer cents. Tax lines are only added when `taxAmount > 0`.
|
|
84
|
-
|
|
85
|
-
### Payment recording
|
|
86
|
-
|
|
87
|
-
When the invoice engine records a payment, the bridge calls `engine.record.payment()`:
|
|
88
|
-
|
|
89
|
-
```
|
|
90
|
-
DR Cash (1000) $500.00
|
|
91
|
-
CR Receivable (1200) $500.00
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
An idempotency key is automatically derived from the payment ID (`payment:{paymentId}`), preventing duplicate journal entries on retry.
|
|
95
|
-
|
|
96
|
-
### Reversal
|
|
97
|
-
|
|
98
|
-
When an invoice is cancelled or voided, the bridge calls `engine.repositories.journalEntries.reverse()`, which creates a mirror entry with debits and credits swapped and links both entries bidirectionally.
|
|
99
|
-
|
|
100
|
-
### Bridge configuration options
|
|
101
|
-
|
|
102
|
-
#### `receiptAccount`
|
|
103
|
-
|
|
104
|
-
Override the debit account for POS receipts. By default, receipts debit the `receivable` account. If your receipts are immediately paid (no A/R), point this at cash:
|
|
105
|
-
|
|
106
|
-
```typescript
|
|
107
|
-
createLedgerBridge(accounting, {
|
|
108
|
-
accounts: { ... },
|
|
109
|
-
receiptAccount: '1000', // Receipts debit Cash directly
|
|
110
|
-
});
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
#### `resolvePaymentAccounts`
|
|
114
|
-
|
|
115
|
-
Custom resolver for payment accounts. Use when you need to determine AR vs AP based on context (e.g., vendor bill payments should clear AP, not AR):
|
|
12
|
+
1. **`createLedgerBridge(accounting, config)`** — `@classytic/invoice` `LedgerBridge` adapter.
|
|
13
|
+
2. **`wireImport` / `wireExport`** — generic batch importer/exporter pipeline.
|
|
14
|
+
3. **Mapper factories** — `bankStatementMapper`, `invoiceMapper`, `journalEntryMapper`, `openingBalanceMapper` (fin-io canonical shapes → `JournalEntryInput`).
|
|
116
15
|
|
|
117
|
-
|
|
118
|
-
createLedgerBridge(accounting, {
|
|
119
|
-
accounts: { ... },
|
|
120
|
-
resolvePaymentAccounts: (input) => {
|
|
121
|
-
const isVendor = vendorInvoiceIds.has(input.invoiceId);
|
|
122
|
-
return {
|
|
123
|
-
receivableOrPayable: isVendor ? '2000' : '1200',
|
|
124
|
-
cash: '1000',
|
|
125
|
-
};
|
|
126
|
-
},
|
|
127
|
-
});
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
### Double-entry guarantee
|
|
131
|
-
|
|
132
|
-
The bridge uses `engine.record.adjustment()` internally. This routes through the ledger's double-entry plugin, which validates `sum(debits) === sum(credits)` before persisting. If the invoice engine sends unbalanced data, the ledger rejects it with a structured validation error.
|
|
133
|
-
|
|
134
|
-
---
|
|
135
|
-
|
|
136
|
-
### Alternative: Manual wiring (without `createLedgerBridge`)
|
|
16
|
+
All three were moved out of `@classytic/ledger` because:
|
|
137
17
|
|
|
138
|
-
|
|
18
|
+
- They forced **`@classytic/fin-io`** as an optional peer on every consumer, even when no fin-io shape was ever read.
|
|
19
|
+
- The invoice-bridge adapter imported `@classytic/invoice` types — a cross-package import that violates [`PACKAGE_RULES` P1](../PACKAGE_RULES.md) (no inter-package imports beyond `mongokit` + `primitives`).
|
|
20
|
+
- Only one host ever consumed the subpath, so the cost wasn't worth keeping in a shared library.
|
|
139
21
|
|
|
140
|
-
|
|
141
|
-
import type { LedgerBridge } from '@classytic/ledger/sync';
|
|
22
|
+
## What stayed (still on the main entry)
|
|
142
23
|
|
|
143
|
-
|
|
144
|
-
async createJournalEntry(input) {
|
|
145
|
-
// Use record.adjustment() for multi-line entries with tax
|
|
146
|
-
const entry = await accounting.record.adjustment(input.organizationId, {
|
|
147
|
-
date: input.date,
|
|
148
|
-
label: `Invoice ${input.invoiceId}`,
|
|
149
|
-
journalType: 'SALES',
|
|
150
|
-
lines: [
|
|
151
|
-
{ account: '1200', debit: input.totalAmount },
|
|
152
|
-
...input.lines.map(line => ({
|
|
153
|
-
account: '4000',
|
|
154
|
-
credit: line.amount,
|
|
155
|
-
label: line.description,
|
|
156
|
-
})),
|
|
157
|
-
...(input.taxAmount > 0
|
|
158
|
-
? [{ account: '2100', credit: input.taxAmount, label: 'Tax' }]
|
|
159
|
-
: []),
|
|
160
|
-
],
|
|
161
|
-
}, {
|
|
162
|
-
idempotencyKey: input.idempotencyKey,
|
|
163
|
-
});
|
|
164
|
-
return String((entry as any)._id);
|
|
165
|
-
},
|
|
24
|
+
The pure ledger-side primitives that don't pull in fin-io OR invoice types are kept:
|
|
166
25
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
return String((reversal as any)._id);
|
|
171
|
-
},
|
|
26
|
+
- `buildOpeningBalanceEntry(input)` — pure helper, re-exported from `@classytic/ledger`.
|
|
27
|
+
- `OpeningBalanceInput`, `OpeningBalanceResult` — re-exported from `@classytic/ledger`.
|
|
28
|
+
- `JournalEntryInput`, `JournalItemInput` — describe the `journalEntries.create()` input; inherent to the engine, not a sync concern.
|
|
172
29
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
amount: input.amount,
|
|
177
|
-
fromReceivableAccount: '1200',
|
|
178
|
-
toCashAccount: '1000',
|
|
179
|
-
label: `Payment ${input.paymentId} for ${input.invoiceId}`,
|
|
180
|
-
}, {
|
|
181
|
-
idempotencyKey: `payment:${input.paymentId}`,
|
|
182
|
-
});
|
|
183
|
-
return String((entry as any)._id);
|
|
184
|
-
},
|
|
185
|
-
};
|
|
186
|
-
|
|
187
|
-
// Then pass to the invoice engine
|
|
188
|
-
const invoicing = createInvoiceEngine({
|
|
189
|
-
mongoose: connection,
|
|
190
|
-
ledger: ledgerBridge,
|
|
191
|
-
});
|
|
30
|
+
```ts
|
|
31
|
+
import { buildOpeningBalanceEntry } from '@classytic/ledger';
|
|
32
|
+
import type { JournalEntryInput, JournalItemInput } from '@classytic/ledger';
|
|
192
33
|
```
|
|
193
34
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
### Using `LedgerBridge` without `@classytic/invoice`
|
|
35
|
+
## How to wire an invoice engine today
|
|
197
36
|
|
|
198
|
-
|
|
37
|
+
Pick one of two paths:
|
|
199
38
|
|
|
200
|
-
|
|
201
|
-
import type { LedgerBridge, LedgerPostInput, LedgerPaymentInput } from '@classytic/ledger/sync';
|
|
39
|
+
### Option A — Copy the canonical reference implementation
|
|
202
40
|
|
|
203
|
-
|
|
204
|
-
|
|
41
|
+
`fajr-be-arc` carries the production-grade implementation at
|
|
42
|
+
`src/shared/ledger-sync/`. The relevant files are:
|
|
205
43
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
partnerId: 'customer-123',
|
|
212
|
-
date: new Date(),
|
|
213
|
-
currency: 'USD',
|
|
214
|
-
lines: [
|
|
215
|
-
{ description: 'Consulting', amount: 100000, taxAmount: 13000, taxCode: 'HST' },
|
|
216
|
-
],
|
|
217
|
-
totalAmount: 113000,
|
|
218
|
-
taxAmount: 13000,
|
|
219
|
-
});
|
|
44
|
+
- `ledger-bridge.ts` — implements `@classytic/invoice`'s `LedgerBridge`
|
|
45
|
+
contract on top of an `AccountingEngine`. Includes multi-tenant scope,
|
|
46
|
+
multi-currency, withholding tax, refunds, and an opt-in
|
|
47
|
+
`resolvePaymentAccounts({ debit, credit })` callback for AR/AP-aware
|
|
48
|
+
hosts (clears AR-shape for `out_invoice`, AP-shape for `in_invoice`).
|
|
220
49
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
organizationId: 'org_1',
|
|
224
|
-
invoiceId: 'INV-001',
|
|
225
|
-
paymentId: 'PAY-001',
|
|
226
|
-
amount: 113000,
|
|
227
|
-
currency: 'USD',
|
|
228
|
-
date: new Date(),
|
|
229
|
-
method: 'bank_transfer',
|
|
230
|
-
});
|
|
50
|
+
Drop the files into your repo, adjust the import paths, done. The
|
|
51
|
+
implementation is < 600 lines total and stable.
|
|
231
52
|
|
|
232
|
-
|
|
233
|
-
await bridge.reverseJournalEntry(jeId, 'Invoice cancelled');
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
---
|
|
237
|
-
|
|
238
|
-
## Bank Statement Import
|
|
53
|
+
### Option B — Implement `LedgerBridge` yourself
|
|
239
54
|
|
|
240
|
-
|
|
55
|
+
Implement the three-method interface against your accounting engine
|
|
56
|
+
directly. The contract lives in `@classytic/invoice/dist/domain/contracts/ledger-bridge.d.ts`:
|
|
241
57
|
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
const report = await wireImport({
|
|
250
|
-
source: parsed.data.flatMap(s => s.transactions),
|
|
251
|
-
mapper: bankStatementMapper({
|
|
252
|
-
bankAccountId: bankAccount._id,
|
|
253
|
-
suspenseAccountId: suspenseAccount._id,
|
|
254
|
-
categorize: (txn) => knownVendors[txn.counterparty?.name]?.accountId,
|
|
255
|
-
}),
|
|
256
|
-
journalEntries: engine.repositories.journalEntries,
|
|
257
|
-
context: { organizationId },
|
|
258
|
-
}).run();
|
|
259
|
-
|
|
260
|
-
console.log(`Imported ${report.inserted}, skipped ${report.skipped} duplicates`);
|
|
58
|
+
```ts
|
|
59
|
+
export interface LedgerBridge {
|
|
60
|
+
createJournalEntry(input: LedgerPostInput): Promise<string>;
|
|
61
|
+
reverseJournalEntry(jeId: string, reason: string, ctx: LedgerReverseContext): Promise<string>;
|
|
62
|
+
recordPayment(input: LedgerPaymentInput): Promise<string>;
|
|
63
|
+
}
|
|
261
64
|
```
|
|
262
65
|
|
|
263
|
-
|
|
66
|
+
A bare-minimum implementation is ~80 lines (one tax line, no withholding,
|
|
67
|
+
no FX). Useful when your COA is small and stable enough that the
|
|
68
|
+
`createLedgerBridge` config map's flexibility is overkill.
|
|
264
69
|
|
|
265
|
-
|
|
266
|
-
|---|---|---|
|
|
267
|
-
| `bankStatementMapper` | `CanonicalTransaction` (OFX, CAMT, MT940, CSV, Plaid) | 2-line JE: Cash ↔ Suspense |
|
|
268
|
-
| `invoiceMapper` | `CanonicalInvoice` (QBO, Xero JSON) | Multi-line JE: AR/AP ↔ Revenue/Expense ↔ Tax |
|
|
269
|
-
| `journalEntryMapper` | `CanonicalJournalEntry` (QBO, Xero manual journals) | 1:1 mapping |
|
|
270
|
-
| `openingBalanceMapper` | `TrialBalanceInput` | Multi-line opening balance entry |
|
|
70
|
+
## How to wire fin-io imports today
|
|
271
71
|
|
|
272
|
-
|
|
72
|
+
The mapper helpers (`bankStatementMapper`, `invoiceMapper`, etc.) and the
|
|
73
|
+
`wireImport`/`wireExport` pipeline moved to host code along with the
|
|
74
|
+
bridge. The canonical implementation lives in `fajr-be-arc` under
|
|
75
|
+
`src/workflows/ai-bank-import.workflow.ts` (for AI-extracted bank
|
|
76
|
+
statements) and `src/resources/integrations/` (for QBO / Xero sync).
|
|
273
77
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
For best performance, provide a `findExisting` callback and add a partial index on `{ organizationId: 1, _externalId: 1 }`.
|
|
277
|
-
|
|
278
|
-
---
|
|
279
|
-
|
|
280
|
-
## Export
|
|
281
|
-
|
|
282
|
-
Stream ledger data to external formats:
|
|
283
|
-
|
|
284
|
-
```typescript
|
|
285
|
-
import { wireExport } from '@classytic/ledger/sync';
|
|
286
|
-
|
|
287
|
-
const report = await wireExport({
|
|
288
|
-
query: { organizationId: 'org_1', state: 'posted' },
|
|
289
|
-
sink: {
|
|
290
|
-
fromJournalEntry: (entry) => transformToCSVRow(entry),
|
|
291
|
-
emit: async (rows) => csvStream.write(rows),
|
|
292
|
-
flush: async () => csvStream.end(),
|
|
293
|
-
},
|
|
294
|
-
journalEntries: engine.repositories.journalEntries,
|
|
295
|
-
options: { batchSize: 500 },
|
|
296
|
-
}).run();
|
|
297
|
-
```
|
|
78
|
+
`@classytic/fin-io` is a normal direct dependency in fajr — not a peer
|
|
79
|
+
of ledger. Hosts that don't need fin-io shapes don't pull it in.
|
|
298
80
|
|
|
299
81
|
---
|
|
300
82
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
Implement `ImportMapper<TRaw>` for any data source:
|
|
304
|
-
|
|
305
|
-
```typescript
|
|
306
|
-
import type { ImportMapper } from '@classytic/ledger/sync';
|
|
307
|
-
|
|
308
|
-
interface MyPayrollRecord {
|
|
309
|
-
id: string;
|
|
310
|
-
employeeName: string;
|
|
311
|
-
grossPay: number;
|
|
312
|
-
taxWithheld: number;
|
|
313
|
-
netPay: number;
|
|
314
|
-
date: Date;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
const payrollMapper: ImportMapper<MyPayrollRecord> = {
|
|
318
|
-
externalId: (record) => `payroll:${record.id}`,
|
|
319
|
-
|
|
320
|
-
toJournalEntry: (record, ctx) => ({
|
|
321
|
-
date: record.date,
|
|
322
|
-
label: `Payroll — ${record.employeeName}`,
|
|
323
|
-
journalItems: [
|
|
324
|
-
{ account: salaryExpenseId, debit: record.grossPay, credit: 0 },
|
|
325
|
-
{ account: taxPayableId, debit: 0, credit: record.taxWithheld },
|
|
326
|
-
{ account: cashId, debit: 0, credit: record.netPay },
|
|
327
|
-
],
|
|
328
|
-
}),
|
|
329
|
-
};
|
|
330
|
-
```
|
|
83
|
+
For the architectural rationale + full migration list, see
|
|
84
|
+
[`CHANGELOG.md` → 0.11.0](../CHANGELOG.md).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@classytic/ledger",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.3",
|
|
4
4
|
"description": "Production-grade double-entry accounting engine for MongoDB — schemas, reports, tax, multi-tenant",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -88,23 +88,23 @@
|
|
|
88
88
|
"url": "git+https://github.com/classytic/ledger.git"
|
|
89
89
|
},
|
|
90
90
|
"peerDependencies": {
|
|
91
|
-
"@classytic/mongokit": ">=3.
|
|
92
|
-
"@classytic/primitives": ">=0.
|
|
93
|
-
"@classytic/repo-core": ">=0.
|
|
94
|
-
"mongoose": ">=9.
|
|
91
|
+
"@classytic/mongokit": ">=3.14.0",
|
|
92
|
+
"@classytic/primitives": ">=0.6.0",
|
|
93
|
+
"@classytic/repo-core": ">=0.5.0",
|
|
94
|
+
"mongoose": ">=9.6.2",
|
|
95
95
|
"zod": ">=4.0.0"
|
|
96
96
|
},
|
|
97
97
|
"devDependencies": {
|
|
98
98
|
"@biomejs/biome": "^2.4.12",
|
|
99
99
|
"@classytic/dev-tools": "^0.2.0",
|
|
100
|
-
"@classytic/mongokit": "
|
|
101
|
-
"@classytic/primitives": "
|
|
102
|
-
"@classytic/repo-core": "
|
|
100
|
+
"@classytic/mongokit": "^3.14.0",
|
|
101
|
+
"@classytic/primitives": "^0.6.0",
|
|
102
|
+
"@classytic/repo-core": "^0.5.0",
|
|
103
103
|
"@types/node": "^25.5.0",
|
|
104
104
|
"@vitest/coverage-v8": "^4.1.4",
|
|
105
105
|
"knip": "^6.4.1",
|
|
106
106
|
"mongodb-memory-server": "^11.0.1",
|
|
107
|
-
"mongoose": "^9.
|
|
107
|
+
"mongoose": "^9.6.2",
|
|
108
108
|
"tsdown": "^0.21.8",
|
|
109
109
|
"typescript": "^5.7.0",
|
|
110
110
|
"vitest": "^4.1.4",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|