@classytic/ledger 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/country/index.d.mts +2 -2
- package/dist/country/index.mjs +0 -3
- package/dist/{fx-realization.plugin-CgQFDGv2.mjs → fx-realization.plugin-CfYy1tB6.mjs} +1 -37
- package/dist/index-BX8miYdu.d.mts +119 -0
- package/dist/{tax-hooks-BnVenul5.d.mts → index-Bl0_ak5w.d.mts} +17 -66
- package/dist/index.d.mts +18 -70
- package/dist/index.mjs +7 -126
- package/dist/plugins/index.d.mts +2 -16
- package/dist/plugins/index.mjs +2 -57
- package/dist/reports/index.d.mts +1 -1
- package/dist/{trial-balance-s92GEvRR.d.mts → trial-balance-DTc8kzTD.d.mts} +2 -33
- package/package.json +1 -1
- package/dist/index-BthGypsI.d.mts +0 -228
package/dist/country/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { CountryPack, CountryPackInput, JournalTemplate,
|
|
1
|
+
import { i as defineCountryPack, n as CountryPackInput, r as JournalTemplate, t as CountryPack } from "../index-BX8miYdu.mjs";
|
|
2
|
+
export { CountryPack, CountryPackInput, JournalTemplate, defineCountryPack };
|
package/dist/country/index.mjs
CHANGED
|
@@ -15,9 +15,6 @@ function defineCountryPack(input) {
|
|
|
15
15
|
const at = accountMap.get(code);
|
|
16
16
|
return at !== void 0 && !at.isTotal && !at.isGroup;
|
|
17
17
|
},
|
|
18
|
-
getTaxCodesForRegion: (region) => {
|
|
19
|
-
return (input.taxCodesByRegion[region] ?? []).map((c) => input.taxCodes[c]).filter(Boolean);
|
|
20
|
-
},
|
|
21
18
|
flattenAccountTypes: () => input.accountTypes
|
|
22
19
|
};
|
|
23
20
|
}
|
|
@@ -275,42 +275,6 @@ function fiscalLockPlugin(options) {
|
|
|
275
275
|
})
|
|
276
276
|
});
|
|
277
277
|
}
|
|
278
|
-
const defaultTaxSelector = (acc) => acc.taxMetadata != null;
|
|
279
|
-
function taxLockPlugin(options) {
|
|
280
|
-
const { TaxPeriodModel, AccountModel, JournalEntryModel, orgField } = options;
|
|
281
|
-
const isTaxAffecting = options.isTaxAffecting ?? defaultTaxSelector;
|
|
282
|
-
const deriveFilter = options.deriveFilter ?? ((data) => ({
|
|
283
|
-
jurisdiction: data.jurisdiction,
|
|
284
|
-
taxType: data.taxType
|
|
285
|
-
}));
|
|
286
|
-
return createLockPlugin({
|
|
287
|
-
scope: "tax",
|
|
288
|
-
accountSelector: isTaxAffecting,
|
|
289
|
-
AccountModel,
|
|
290
|
-
JournalEntryModel,
|
|
291
|
-
orgField,
|
|
292
|
-
resolve: periodResolver({
|
|
293
|
-
scope: "tax",
|
|
294
|
-
PeriodModel: TaxPeriodModel,
|
|
295
|
-
startField: "periodStart",
|
|
296
|
-
endField: "periodEnd",
|
|
297
|
-
closedField: "status",
|
|
298
|
-
closedValue: { $ne: "open" },
|
|
299
|
-
labelField: "jurisdiction",
|
|
300
|
-
subTypeField: "taxType",
|
|
301
|
-
externalRefField: "returnRef",
|
|
302
|
-
orgField,
|
|
303
|
-
extraQuery: (ctx) => {
|
|
304
|
-
const filter = deriveFilter(ctx.data);
|
|
305
|
-
if (!filter) return void 0;
|
|
306
|
-
const out = {};
|
|
307
|
-
if (filter.jurisdiction) out.jurisdiction = filter.jurisdiction;
|
|
308
|
-
if (filter.taxType) out.taxType = filter.taxType;
|
|
309
|
-
return Object.keys(out).length ? out : void 0;
|
|
310
|
-
}
|
|
311
|
-
})
|
|
312
|
-
});
|
|
313
|
-
}
|
|
314
278
|
function dailyLockPlugin(options) {
|
|
315
279
|
return createLockPlugin({
|
|
316
280
|
scope: "daily",
|
|
@@ -456,4 +420,4 @@ function fxRealizationPlugin(options) {
|
|
|
456
420
|
};
|
|
457
421
|
}
|
|
458
422
|
//#endregion
|
|
459
|
-
export {
|
|
423
|
+
export { watermarkResolver as a, idempotencyPlugin as c, fiscalLockPlugin as i, doubleEntryPlugin as l, creditLimitPlugin as n, periodResolver as o, dailyLockPlugin as r, createLockPlugin as s, fxRealizationPlugin as t };
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { t as AccountType } from "./core-BkGjuVZj.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/country/index.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Declarative template that tells the engine which journals to seed for a
|
|
6
|
+
* new organization. Consumers call
|
|
7
|
+
* `engine.repositories.journals.seedDefaults(orgId)` which reads these from
|
|
8
|
+
* the country pack and creates one Journal document per template.
|
|
9
|
+
*
|
|
10
|
+
* Journals are *optional* — if a consumer never seeds journals, the legacy
|
|
11
|
+
* `journalType` enum on a journal entry still works. Consumers opting in
|
|
12
|
+
* get per-journal sequence prefixes, restricted payment methods, bank
|
|
13
|
+
* statement sources, etc.
|
|
14
|
+
*/
|
|
15
|
+
interface JournalTemplate {
|
|
16
|
+
/** Short stable identifier — e.g. `'SALES'`, `'PURCHASE'`, `'BANK'`. */
|
|
17
|
+
readonly code: string;
|
|
18
|
+
/** Display name. */
|
|
19
|
+
readonly name: string;
|
|
20
|
+
/**
|
|
21
|
+
* One of the registered `JOURNAL_TYPES` codes — connects this journal to
|
|
22
|
+
* the engine's reference-number generator and posting-contract system.
|
|
23
|
+
*/
|
|
24
|
+
readonly journalType: string;
|
|
25
|
+
/** Reference-number prefix — defaults to `code` when omitted. */
|
|
26
|
+
readonly sequencePrefix?: string;
|
|
27
|
+
/** First sequence number — defaults to `1`. */
|
|
28
|
+
readonly sequenceStartNum?: number;
|
|
29
|
+
/**
|
|
30
|
+
* Logical source — pure ledgering (`'general'`), sale-side docs (`'sale'`),
|
|
31
|
+
* purchase-side docs (`'purchase'`), cash/bank movement (`'bank'`, `'cash'`).
|
|
32
|
+
* Drives default locks (sale-lock, purchase-lock) when they're wired.
|
|
33
|
+
*/
|
|
34
|
+
readonly kind?: 'general' | 'sale' | 'purchase' | 'bank' | 'cash' | string;
|
|
35
|
+
/** Optional default debit/credit account roles for quick data entry. */
|
|
36
|
+
readonly defaultDebitAccountRole?: string;
|
|
37
|
+
readonly defaultCreditAccountRole?: string;
|
|
38
|
+
}
|
|
39
|
+
interface CountryPack {
|
|
40
|
+
/** ISO 3166-1 alpha-2 code (e.g., 'CA', 'US', 'GB') */
|
|
41
|
+
readonly code: string;
|
|
42
|
+
/** Country name */
|
|
43
|
+
readonly name: string;
|
|
44
|
+
/** Default currency code */
|
|
45
|
+
readonly defaultCurrency: string;
|
|
46
|
+
/**
|
|
47
|
+
* Full chart of accounts template — flat array of account type definitions.
|
|
48
|
+
* Includes both posting accounts and grouping / total rows.
|
|
49
|
+
*/
|
|
50
|
+
readonly accountTypes: readonly AccountType[];
|
|
51
|
+
/**
|
|
52
|
+
* Optional journal templates seeded per organization. When a consumer
|
|
53
|
+
* calls `engine.repositories.journals.seedDefaults(orgId)`, the engine
|
|
54
|
+
* creates one Journal document per template. See `JournalTemplate`.
|
|
55
|
+
*/
|
|
56
|
+
readonly journalTemplates?: readonly JournalTemplate[];
|
|
57
|
+
/**
|
|
58
|
+
* The retained earnings account code — the account that holds accumulated
|
|
59
|
+
* retained earnings (e.g. '3600' CA, '3310' BD).
|
|
60
|
+
*
|
|
61
|
+
* On the balance sheet, this account is excluded from normal equity grouping
|
|
62
|
+
* and its balance is folded into the computed "Retained Earnings" section
|
|
63
|
+
* (opening RE = RE account balance + prior-year unclosed P&L).
|
|
64
|
+
*
|
|
65
|
+
* Inspired by Odoo's `equity_unaffected` account type.
|
|
66
|
+
*/
|
|
67
|
+
readonly retainedEarningsAccountCode?: string;
|
|
68
|
+
/**
|
|
69
|
+
* Display code for the "Previous Years Retained Earnings" line on the
|
|
70
|
+
* balance sheet (e.g. '3660' for CA GIFI). Defaults to retainedEarningsAccountCode.
|
|
71
|
+
*/
|
|
72
|
+
readonly retainedEarningsDisplayCode?: string;
|
|
73
|
+
/** Display code for current year net income line (e.g. '3680' CA, '3311' BD) */
|
|
74
|
+
readonly currentYearEarningsCode?: string;
|
|
75
|
+
/** Group label code used to identify Cost of Sales in the income statement */
|
|
76
|
+
readonly cogsGroupCode?: string;
|
|
77
|
+
/** Override default English report section names */
|
|
78
|
+
readonly reportLabels?: {
|
|
79
|
+
readonly assets?: string;
|
|
80
|
+
readonly liabilities?: string;
|
|
81
|
+
readonly equity?: string;
|
|
82
|
+
readonly revenue?: string;
|
|
83
|
+
readonly expenses?: string;
|
|
84
|
+
};
|
|
85
|
+
/** Get all account types that can be posted to (not groups, not totals) */
|
|
86
|
+
getPostingAccountTypes(): readonly AccountType[];
|
|
87
|
+
/** Get account type by code */
|
|
88
|
+
getAccountType(code: string): AccountType | undefined;
|
|
89
|
+
/** Validate an account type code exists */
|
|
90
|
+
isValidAccountType(code: string): boolean;
|
|
91
|
+
/** Check if an account type can receive postings */
|
|
92
|
+
isPostingAccount(code: string): boolean;
|
|
93
|
+
/** Flatten hierarchical accounts (if needed) */
|
|
94
|
+
flattenAccountTypes(): readonly AccountType[];
|
|
95
|
+
}
|
|
96
|
+
interface CountryPackInput {
|
|
97
|
+
code: string;
|
|
98
|
+
name: string;
|
|
99
|
+
defaultCurrency: string;
|
|
100
|
+
accountTypes: readonly AccountType[];
|
|
101
|
+
journalTemplates?: readonly JournalTemplate[];
|
|
102
|
+
retainedEarningsAccountCode?: string;
|
|
103
|
+
retainedEarningsDisplayCode?: string;
|
|
104
|
+
currentYearEarningsCode?: string;
|
|
105
|
+
cogsGroupCode?: string;
|
|
106
|
+
reportLabels?: {
|
|
107
|
+
readonly assets?: string;
|
|
108
|
+
readonly liabilities?: string;
|
|
109
|
+
readonly equity?: string;
|
|
110
|
+
readonly revenue?: string;
|
|
111
|
+
readonly expenses?: string;
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Factory to create a CountryPack with auto-generated helper methods.
|
|
116
|
+
*/
|
|
117
|
+
declare function defineCountryPack(input: CountryPackInput): CountryPack;
|
|
118
|
+
//#endregion
|
|
119
|
+
export { defineCountryPack as i, CountryPackInput as n, JournalTemplate as r, CountryPack as t };
|
|
@@ -213,7 +213,22 @@ declare function creditLimitPlugin(options: CreditLimitPluginOptions): {
|
|
|
213
213
|
* This file is side-effect only — importing it anywhere in the package is
|
|
214
214
|
* enough to activate the augmentation. `src/types/index.ts` re-exports it.
|
|
215
215
|
*/
|
|
216
|
-
|
|
216
|
+
/**
|
|
217
|
+
* Internal op tags attached to `repository.update()` / `repository.create()`
|
|
218
|
+
* calls that the ledger itself initiates. Plugins observing the
|
|
219
|
+
* `before:update` / `before:create` hooks can read `context._ledgerInternal`
|
|
220
|
+
* to identify legitimate engine operations and skip guards accordingly.
|
|
221
|
+
*
|
|
222
|
+
* - `post` / `unpost` / `archive` — state transitions on an entry
|
|
223
|
+
* - `reverseMark` — marking an original as reversed
|
|
224
|
+
* (exempt from fiscal/daily locks)
|
|
225
|
+
* - `fxRealize` — FX realization plugin balancing entry
|
|
226
|
+
* (exempt from all locks and credit-limit)
|
|
227
|
+
*
|
|
228
|
+
* Tax-specific internal ops (e.g. cash-basis exigibility realization) live
|
|
229
|
+
* in their respective tax packages and are not part of the ledger core.
|
|
230
|
+
*/
|
|
231
|
+
type LedgerInternalOp = 'post' | 'unpost' | 'archive' | 'reverseMark' | 'fxRealize';
|
|
217
232
|
declare module '@classytic/mongokit' {
|
|
218
233
|
interface RepositoryContext {
|
|
219
234
|
/**
|
|
@@ -414,48 +429,6 @@ declare function fiscalLockPlugin(options: FiscalLockPluginOptions): {
|
|
|
414
429
|
name: string;
|
|
415
430
|
apply(repo: _classytic_mongokit0.RepositoryInstance): void;
|
|
416
431
|
};
|
|
417
|
-
interface TaxLockPluginOptions {
|
|
418
|
-
/**
|
|
419
|
-
* Tax-period model. Expected shape (fields are overridable via the
|
|
420
|
-
* lower-level `createLockPlugin` if your schema differs):
|
|
421
|
-
*
|
|
422
|
-
* {
|
|
423
|
-
* periodStart: Date,
|
|
424
|
-
* periodEnd: Date,
|
|
425
|
-
* status: 'open' | 'filed' | 'amended',
|
|
426
|
-
* jurisdiction?: string,
|
|
427
|
-
* taxType?: string,
|
|
428
|
-
* returnRef?: string,
|
|
429
|
-
* [orgField]?: unknown,
|
|
430
|
-
* }
|
|
431
|
-
*
|
|
432
|
-
* `status !== 'open'` counts as locked.
|
|
433
|
-
*/
|
|
434
|
-
TaxPeriodModel: Model<unknown>;
|
|
435
|
-
AccountModel: Model<unknown>;
|
|
436
|
-
JournalEntryModel?: Model<unknown>;
|
|
437
|
-
orgField?: string;
|
|
438
|
-
/**
|
|
439
|
-
* Predicate deciding which accounts participate in tax returns.
|
|
440
|
-
* Defaults to `acc => acc.taxMetadata != null` — matches the
|
|
441
|
-
* convention used by country packs that populate `taxMetadata` on
|
|
442
|
-
* tax-payable / tax-recoverable account types.
|
|
443
|
-
*/
|
|
444
|
-
isTaxAffecting?: LockAccountSelector;
|
|
445
|
-
/**
|
|
446
|
-
* Derive `{ jurisdiction, taxType }` from the entry payload so each
|
|
447
|
-
* post can look up the right row. Default: use `data.jurisdiction`
|
|
448
|
-
* and `data.taxType` directly when present.
|
|
449
|
-
*/
|
|
450
|
-
deriveFilter?: (data: Record<string, unknown>) => {
|
|
451
|
-
jurisdiction?: string;
|
|
452
|
-
taxType?: string;
|
|
453
|
-
} | undefined;
|
|
454
|
-
}
|
|
455
|
-
declare function taxLockPlugin(options: TaxLockPluginOptions): {
|
|
456
|
-
name: string;
|
|
457
|
-
apply(repo: _classytic_mongokit0.RepositoryInstance): void;
|
|
458
|
-
};
|
|
459
432
|
interface DailyLockPluginOptions {
|
|
460
433
|
/**
|
|
461
434
|
* Return the `lastClosedDate` for the given org/branch — everything
|
|
@@ -488,26 +461,4 @@ interface WatermarkResolverOptions {
|
|
|
488
461
|
}
|
|
489
462
|
declare function watermarkResolver(options: WatermarkResolverOptions): LockResolver;
|
|
490
463
|
//#endregion
|
|
491
|
-
|
|
492
|
-
interface TaxLineInput {
|
|
493
|
-
account: unknown;
|
|
494
|
-
amount: number;
|
|
495
|
-
side: 'debit' | 'credit';
|
|
496
|
-
taxCode?: string;
|
|
497
|
-
extraFields?: Record<string, unknown>;
|
|
498
|
-
}
|
|
499
|
-
interface GeneratedTaxLine {
|
|
500
|
-
account: unknown;
|
|
501
|
-
debit: number;
|
|
502
|
-
credit: number;
|
|
503
|
-
label?: string;
|
|
504
|
-
taxDetails?: Array<{
|
|
505
|
-
taxCode: string;
|
|
506
|
-
taxName?: string;
|
|
507
|
-
}>;
|
|
508
|
-
}
|
|
509
|
-
interface TaxLineGenerator {
|
|
510
|
-
generateTaxLines(input: TaxLineInput): GeneratedTaxLine[];
|
|
511
|
-
}
|
|
512
|
-
//#endregion
|
|
513
|
-
export { JournalEntryRepository as A, SeedResult as B, DoubleEntryPluginOptions as C, AccountRepository as D, creditLimitPlugin as E, PostOptions as F, ReconciliationRepository as I, ReverseOptions as L, JournalRepository as M, MatchInput as N, BulkCreateInput as O, OpenItem as P, ReverseResult as R, fxRealizationPlugin as S, CreditLimitPluginOptions as T, LockResolver as _, DailyLockPluginOptions as a, idempotencyPlugin as b, dailyLockPlugin as c, PeriodResolverOptions as d, periodResolver as f, LockHit as g, LockAccountSelector as h, watermarkResolver as i, JournalItemRef as j, BulkCreateResult as k, fiscalLockPlugin as l, CreateLockPluginOptions as m, TaxLineInput as n, FiscalLockPluginOptions as o, createLockPlugin as p, WatermarkResolverOptions as r, TaxLockPluginOptions as s, TaxLineGenerator as t, taxLockPlugin as u, LockResolverContext as v, doubleEntryPlugin as w, FxRealizationPluginOptions as x, IdempotencyPluginOptions as y, SeedOptions as z };
|
|
464
|
+
export { OpenItem as A, AccountRepository as C, JournalItemRef as D, JournalEntryRepository as E, SeedOptions as F, SeedResult as I, ReconciliationRepository as M, ReverseOptions as N, JournalRepository as O, ReverseResult as P, creditLimitPlugin as S, BulkCreateResult as T, FxRealizationPluginOptions as _, dailyLockPlugin as a, doubleEntryPlugin as b, periodResolver as c, LockAccountSelector as d, LockHit as f, idempotencyPlugin as g, IdempotencyPluginOptions as h, FiscalLockPluginOptions as i, PostOptions as j, MatchInput as k, createLockPlugin as l, LockResolverContext as m, watermarkResolver as n, fiscalLockPlugin as o, LockResolver as p, DailyLockPluginOptions as r, PeriodResolverOptions as s, WatermarkResolverOptions as t, CreateLockPluginOptions as u, fxRealizationPlugin as v, BulkCreateInput as w, CreditLimitPluginOptions as x, DoubleEntryPluginOptions as y };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { _ as TaxMetadata, a as Cents, c as DateRange, d as JournalType, f as MainType, g as TaxDetail, h as StatementType, i as CategoryKey, l as EntryState, m as ObjectId, n as CashFlowCategory, o as Currency, p as NormalBalance, s as DateOption, t as AccountType, u as JournalItem, v as TotalAccountOp } from "./core-BkGjuVZj.mjs";
|
|
2
2
|
import { S as isValidCategory, a as getJournalTypeCodes, b as isBalanceSheet, c as CURRENCIES, d as isValidCurrency, f as CATEGORIES, i as getJournalType, l as getCurrency, n as JOURNAL_TYPES, o as isValidJournalType, p as CATEGORY_KEYS, r as getCustomJournalTypes, s as registerJournalType, t as JOURNAL_CODES, u as getMinorUnit, x as isIncomeStatement, y as getNormalBalance } from "./journals-C50E9mpo.mjs";
|
|
3
|
-
import {
|
|
3
|
+
import { i as defineCountryPack, n as CountryPackInput, r as JournalTemplate, t as CountryPack } from "./index-BX8miYdu.mjs";
|
|
4
4
|
import { _ as PopulatedJournalEntry, a as exportToCsv, h as FlatJournalRow, i as quickbooksFieldMap, m as ExportFieldMap, p as ExportField, r as universalFieldMap, t as flattenJournalEntries } from "./index-D1ZjgVxn.mjs";
|
|
5
5
|
import { Money, abs, add, allocate, equals, format, formatPlain, fromDecimal, isNegative, isPositive, isValid, isZero, max, min, multiply, negate, parseCents, percentage, round, splitTaxExclusive, splitTaxInclusive, subtract, toDecimal } from "./money.mjs";
|
|
6
|
-
import { $ as
|
|
7
|
-
import { A as
|
|
6
|
+
import { $ as AgedBalanceParams, A as generateDimensionBreakdown, B as BalanceSheetReport, D as DimensionBreakdownParams, E as DimensionBreakdownOptions, F as BudgetVsActualReport, G as IncomeStatementReport, H as CashFlowSection, I as BudgetVsActualRow, J as ReportCategory, K as LedgerEntry, L as generateBudgetVsActual, M as generateCashFlow, N as BudgetVsActualOptions, O as DimensionBreakdownReport, P as BudgetVsActualParams, Q as AgedBalanceOptions, T as reopenFiscalPeriod, U as GeneralLedgerAccount, V as CashFlowReport, W as GeneralLedgerReport, X as TrialBalanceReport, Y as ReportGroup, Z as TrialBalanceRow, a as RevaluationReport, at as Logger, b as generateGeneralLedger, c as RevaluationRate, d as computeRevaluation, et as AgedBalanceReport, f as PartnerLedgerLine, g as generatePartnerLedger, h as PartnerLedgerReport, i as RevaluationParams, it as generateAgedBalance, k as DimensionBreakdownRow, l as RevaluationResult, m as PartnerLedgerParams, n as generateTrialBalance, nt as AgedBucketConfig, o as generateRevaluation, ot as defaultLogger, p as PartnerLedgerOptions, q as ReportAccount, r as RevaluationOptions, rt as DEFAULT_BUCKETS, s as AccountForeignBalance, tt as AgedBalanceRow, u as buildRevaluationEntry, v as generateIncomeStatement, w as closeFiscalPeriod, z as generateBalanceSheet } from "./trial-balance-DTc8kzTD.mjs";
|
|
7
|
+
import { A as OpenItem, C as AccountRepository, D as JournalItemRef, E as JournalEntryRepository, F as SeedOptions, I as SeedResult, M as ReconciliationRepository, N as ReverseOptions, O as JournalRepository, P as ReverseResult, S as creditLimitPlugin, T as BulkCreateResult, _ as FxRealizationPluginOptions, a as dailyLockPlugin, b as doubleEntryPlugin, c as periodResolver, d as LockAccountSelector, f as LockHit, g as idempotencyPlugin, i as FiscalLockPluginOptions, j as PostOptions, k as MatchInput, l as createLockPlugin, m as LockResolverContext, n as watermarkResolver, o as fiscalLockPlugin, p as LockResolver, r as DailyLockPluginOptions, s as PeriodResolverOptions, t as WatermarkResolverOptions, u as CreateLockPluginOptions, v as fxRealizationPlugin, w as BulkCreateInput, x as CreditLimitPluginOptions } from "./index-Bl0_ak5w.mjs";
|
|
8
8
|
import { ClientSession, Connection, Model } from "mongoose";
|
|
9
9
|
import { PaginationConfig, PluginType, Repository } from "@classytic/mongokit";
|
|
10
10
|
|
|
@@ -256,23 +256,18 @@ interface IntrospectAPI {
|
|
|
256
256
|
* Agents use this to discover what analytics they can run.
|
|
257
257
|
*/
|
|
258
258
|
reports(): ReadonlyArray<ReportDescriptor>;
|
|
259
|
-
/**
|
|
260
|
-
* List tax codes — all of them, or filtered by region.
|
|
261
|
-
*/
|
|
262
|
-
taxCodes(region?: string): ReadonlyArray<TaxCode>;
|
|
263
259
|
/**
|
|
264
260
|
* List fiscal periods for an organization.
|
|
265
261
|
*/
|
|
266
262
|
fiscalPeriods(organizationId?: unknown, session?: ClientSession | null): Promise<FiscalPeriodSummary[]>;
|
|
267
263
|
/**
|
|
268
264
|
* A one-shot snapshot of everything an agent needs to start working:
|
|
269
|
-
* accounts, journal types, reports,
|
|
265
|
+
* accounts, journal types, reports, fiscal periods.
|
|
270
266
|
*/
|
|
271
267
|
catalog(organizationId?: unknown): Promise<{
|
|
272
268
|
accounts: AccountSummary[];
|
|
273
269
|
journalTypes: ReadonlyArray<JournalType>;
|
|
274
270
|
reports: ReadonlyArray<ReportDescriptor>;
|
|
275
|
-
taxCodes: ReadonlyArray<TaxCode>;
|
|
276
271
|
fiscalPeriods: FiscalPeriodSummary[];
|
|
277
272
|
}>;
|
|
278
273
|
}
|
|
@@ -292,21 +287,6 @@ interface ActorContext {
|
|
|
292
287
|
type AccountCode = string;
|
|
293
288
|
/** Integer-cents amount. */
|
|
294
289
|
type Cents$1 = number;
|
|
295
|
-
interface TaxInput {
|
|
296
|
-
/** Tax code from the country pack (e.g. 'HST', 'GST', 'VAT') */
|
|
297
|
-
readonly code: string;
|
|
298
|
-
/**
|
|
299
|
-
* Account type code where the tax amount posts.
|
|
300
|
-
* For sales: the tax-payable account (e.g. '2300' HST Collected).
|
|
301
|
-
* For expenses: the tax-recoverable (ITC) account (e.g. '2400' HST Paid).
|
|
302
|
-
*/
|
|
303
|
-
readonly account: AccountCode;
|
|
304
|
-
/**
|
|
305
|
-
* If true, `amount` is tax-inclusive and will be split into base + tax.
|
|
306
|
-
* If false (default), `amount` is the tax-exclusive base and tax is added.
|
|
307
|
-
*/
|
|
308
|
-
readonly inclusive?: boolean;
|
|
309
|
-
}
|
|
310
290
|
/**
|
|
311
291
|
* Options passed to every record.* operation. Matches mongokit's
|
|
312
292
|
* RepositoryContext shape so audit/observability plugins pick them up
|
|
@@ -331,14 +311,16 @@ interface RecordOptions {
|
|
|
331
311
|
interface RecordSaleInput {
|
|
332
312
|
/** Transaction date */
|
|
333
313
|
readonly date: Date;
|
|
334
|
-
/**
|
|
314
|
+
/** Sale amount in integer cents. Tax, if any, is the caller's responsibility
|
|
315
|
+
* — compute it with your tax engine (e.g. `@classytic/bd-tax`,
|
|
316
|
+
* `@classytic/ca-tax`) and either pre-add it to `amount` + include a
|
|
317
|
+
* tax journal item via `record.adjustment`, or post the entry directly
|
|
318
|
+
* via `engine.repositories.journalEntries.create`. */
|
|
335
319
|
readonly amount: Cents$1;
|
|
336
320
|
/** Account that receives the money — either Cash or Accounts Receivable */
|
|
337
321
|
readonly receivableAccount: AccountCode;
|
|
338
322
|
/** Revenue account */
|
|
339
323
|
readonly revenueAccount: AccountCode;
|
|
340
|
-
/** Tax info — optional */
|
|
341
|
-
readonly tax?: TaxInput;
|
|
342
324
|
/** Free-text label / memo */
|
|
343
325
|
readonly label?: string;
|
|
344
326
|
/** Optional reference number override (otherwise auto-generated) */
|
|
@@ -350,14 +332,13 @@ interface RecordSaleInput {
|
|
|
350
332
|
}
|
|
351
333
|
interface RecordExpenseInput {
|
|
352
334
|
readonly date: Date;
|
|
353
|
-
/**
|
|
335
|
+
/** Expense amount in integer cents. Tax is caller's responsibility — see
|
|
336
|
+
* `RecordSaleInput.amount` comment. */
|
|
354
337
|
readonly amount: Cents$1;
|
|
355
338
|
/** Expense category account (e.g. '6010' Rent) */
|
|
356
339
|
readonly expenseAccount: AccountCode;
|
|
357
340
|
/** Where the money came from — either Cash or Accounts Payable */
|
|
358
341
|
readonly paidFromAccount: AccountCode;
|
|
359
|
-
/** Tax info (recoverable input tax credit) */
|
|
360
|
-
readonly tax?: TaxInput;
|
|
361
342
|
readonly label?: string;
|
|
362
343
|
readonly reference?: string;
|
|
363
344
|
readonly dimensions?: Record<string, unknown>;
|
|
@@ -402,23 +383,25 @@ interface RecordAdjustmentInput {
|
|
|
402
383
|
}
|
|
403
384
|
interface RecordAPI {
|
|
404
385
|
/**
|
|
405
|
-
* Record a sale. Debits cash/AR, credits revenue
|
|
386
|
+
* Record a sale. Debits cash/AR, credits revenue. Tax lines — if needed —
|
|
387
|
+
* are the consumer's responsibility (compute via your tax engine and
|
|
388
|
+
* either add to `amount` or use `record.adjustment`).
|
|
406
389
|
*
|
|
407
390
|
* @example
|
|
408
391
|
* ```typescript
|
|
409
392
|
* await engine.record.sale(orgId, {
|
|
410
393
|
* date: new Date('2025-04-01'),
|
|
411
|
-
* amount: 10000, // $100.00
|
|
394
|
+
* amount: 10000, // $100.00 total
|
|
412
395
|
* receivableAccount: '1001', // Cash
|
|
413
396
|
* revenueAccount: '4010', // Service Revenue
|
|
414
|
-
* tax: { code: 'HST', account: '2300' }, // 13% HST Collected
|
|
415
397
|
* label: 'Invoice #INV-001',
|
|
416
398
|
* });
|
|
417
399
|
* ```
|
|
418
400
|
*/
|
|
419
401
|
sale(organizationId: unknown, input: RecordSaleInput, options?: RecordOptions): Promise<unknown>;
|
|
420
402
|
/**
|
|
421
|
-
* Record an expense. Debits expense, credits cash/AP
|
|
403
|
+
* Record an expense. Debits expense, credits cash/AP. Tax is caller's
|
|
404
|
+
* responsibility — see `sale()`.
|
|
422
405
|
*/
|
|
423
406
|
expense(organizationId: unknown, input: RecordExpenseInput, options?: RecordOptions): Promise<unknown>;
|
|
424
407
|
/**
|
|
@@ -557,45 +540,10 @@ declare class AccountingEngine {
|
|
|
557
540
|
isValidAccountType(code: string): boolean;
|
|
558
541
|
/** Get account type definition by code */
|
|
559
542
|
getAccountType(code: string): AccountType | undefined;
|
|
560
|
-
/** Get tax codes for a region */
|
|
561
|
-
getTaxCodesForRegion(region: string): TaxCode[];
|
|
562
543
|
private _buildReports;
|
|
563
544
|
}
|
|
564
545
|
declare function createAccountingEngine(config: AccountingEngineConfig): AccountingEngine;
|
|
565
546
|
//#endregion
|
|
566
|
-
//#region src/utils/repartition-tax.d.ts
|
|
567
|
-
/**
|
|
568
|
-
* Resolves an `accountRole` (e.g. `'collected'`, `'recoverable'`,
|
|
569
|
-
* `'transition'`) into the actual account ObjectId for the consumer's
|
|
570
|
-
* chart of accounts. Implementations typically close over an account
|
|
571
|
-
* cache loaded per organization at engine start.
|
|
572
|
-
*/
|
|
573
|
-
type RepartitionAccountResolver = (role: string, taxCode: TaxCode, input: TaxLineInput) => unknown;
|
|
574
|
-
interface RepartitionGeneratorOptions {
|
|
575
|
-
/** Country pack — provides tax codes and optional resolver. */
|
|
576
|
-
country: CountryPack;
|
|
577
|
-
/** Required: resolve role → account id in the consumer's chart. */
|
|
578
|
-
resolveAccount: RepartitionAccountResolver;
|
|
579
|
-
/**
|
|
580
|
-
* Document type — determines which repartition lines apply. A line
|
|
581
|
-
* with `documentTypes: ['invoice']` is skipped when this is `'refund'`.
|
|
582
|
-
* Defaults to `'invoice'`.
|
|
583
|
-
*/
|
|
584
|
-
documentType?: 'invoice' | 'refund' | 'payment';
|
|
585
|
-
}
|
|
586
|
-
/**
|
|
587
|
-
* Build a `TaxLineGenerator` that expands each hit `taxCode` into one
|
|
588
|
-
* journal item per repartition line. Taxes without `repartition` fall
|
|
589
|
-
* back to a single-line generator using the direction-implied account.
|
|
590
|
-
*/
|
|
591
|
-
declare function createRepartitionTaxGenerator(options: RepartitionGeneratorOptions): TaxLineGenerator;
|
|
592
|
-
/**
|
|
593
|
-
* Helper for packs that want the standard "role → account-type code"
|
|
594
|
-
* mapping without writing their own resolver. Returns the function you
|
|
595
|
-
* stuff into `CountryPackInput.resolveTaxRepartitionAccountCode`.
|
|
596
|
-
*/
|
|
597
|
-
declare function defaultResolveTaxRepartitionAccountCode(country: CountryPack): (role: string, tax: TaxCode) => string | undefined;
|
|
598
|
-
//#endregion
|
|
599
547
|
//#region src/utils/account-helpers.d.ts
|
|
600
548
|
/**
|
|
601
549
|
* Check if an account type is a virtual tax sub-account.
|
|
@@ -816,4 +764,4 @@ interface PostingResult {
|
|
|
816
764
|
idempotencyKeys?: string[];
|
|
817
765
|
}
|
|
818
766
|
//#endregion
|
|
819
|
-
export { type AccountCode, type AccountForeignBalance, type AccountRepository, type AccountSummary, type AccountType, AccountingEngine, type AccountingEngineConfig, AccountingError, type ActorContext, type AgedBalanceOptions, type AgedBalanceParams, type AgedBalanceReport, type AgedBalanceRow, type AgedBucketConfig, type AuditConfig, type BalanceSheetReport, type BudgetVsActualOptions, type BudgetVsActualParams, type BudgetVsActualReport, type BudgetVsActualRow, type BulkCreateInput, type BulkCreateResult, CATEGORIES, CATEGORY_KEYS, CURRENCIES, type CashFlowCategory, type CashFlowReport, type CashFlowSection, type CategoryKey, type Cents, type CountryPack, type CountryPackInput, type CreateLockPluginOptions, type CreditLimitPluginOptions, type Currency, DEFAULT_BUCKETS, type DailyLockPluginOptions, type DateOption, type DateRange, type DimensionBreakdownOptions, type DimensionBreakdownParams, type DimensionBreakdownReport, type DimensionBreakdownRow, type DimensionDefinition, type EntryState, Errors, type ExportField, type ExportFieldMap, type FieldError, type FiscalLockPluginOptions, type FiscalPeriodSummary, type FlatJournalRow, type FxRealizationPluginOptions, type GeneralLedgerAccount, type GeneralLedgerReport, type IncomeStatementReport, type IntrospectAPI, JOURNAL_CODES, JOURNAL_TYPES, type JournalEntryRepository, type JournalItem, type JournalItemRef, type JournalRepository, type JournalSchemaOptions, type JournalTemplate, type JournalType, type LedgerEntry, type LedgerModels, type LedgerPaginationConfig, type LedgerRepositories, type LedgerRepositoryPlugins, type LockAccountSelector, type LockHit, type LockResolver, type LockResolverContext, type Logger, type MainType, type MatchInput, type ModelNames, Money, type MultiCurrencyConfig, type MultiTenantConfig, type NormalBalance, type OpenItem, type PartnerLedgerLine, type PartnerLedgerOptions, type PartnerLedgerParams, type PartnerLedgerReport, type PeriodResolverOptions, type PopulatedJournalEntry, type PostOptions, type PostingContract, type PostingResult, type ReconciliationRepository, type RecordAPI, type RecordAdjustmentInput, type RecordAdjustmentLine, type RecordExpenseInput, type RecordOptions, type RecordPaymentInput, type RecordSaleInput, type RecordTransferInput, type
|
|
767
|
+
export { type AccountCode, type AccountForeignBalance, type AccountRepository, type AccountSummary, type AccountType, AccountingEngine, type AccountingEngineConfig, AccountingError, type ActorContext, type AgedBalanceOptions, type AgedBalanceParams, type AgedBalanceReport, type AgedBalanceRow, type AgedBucketConfig, type AuditConfig, type BalanceSheetReport, type BudgetVsActualOptions, type BudgetVsActualParams, type BudgetVsActualReport, type BudgetVsActualRow, type BulkCreateInput, type BulkCreateResult, CATEGORIES, CATEGORY_KEYS, CURRENCIES, type CashFlowCategory, type CashFlowReport, type CashFlowSection, type CategoryKey, type Cents, type CountryPack, type CountryPackInput, type CreateLockPluginOptions, type CreditLimitPluginOptions, type Currency, DEFAULT_BUCKETS, type DailyLockPluginOptions, type DateOption, type DateRange, type DimensionBreakdownOptions, type DimensionBreakdownParams, type DimensionBreakdownReport, type DimensionBreakdownRow, type DimensionDefinition, type EntryState, Errors, type ExportField, type ExportFieldMap, type FieldError, type FiscalLockPluginOptions, type FiscalPeriodSummary, type FlatJournalRow, type FxRealizationPluginOptions, type GeneralLedgerAccount, type GeneralLedgerReport, type IncomeStatementReport, type IntrospectAPI, JOURNAL_CODES, JOURNAL_TYPES, type JournalEntryRepository, type JournalItem, type JournalItemRef, type JournalRepository, type JournalSchemaOptions, type JournalTemplate, type JournalType, type LedgerEntry, type LedgerModels, type LedgerPaginationConfig, type LedgerRepositories, type LedgerRepositoryPlugins, type LockAccountSelector, type LockHit, type LockResolver, type LockResolverContext, type Logger, type MainType, type MatchInput, type ModelNames, Money, type MultiCurrencyConfig, type MultiTenantConfig, type NormalBalance, type OpenItem, type PartnerLedgerLine, type PartnerLedgerOptions, type PartnerLedgerParams, type PartnerLedgerReport, type PeriodResolverOptions, type PopulatedJournalEntry, type PostOptions, type PostingContract, type PostingResult, type ReconciliationRepository, type RecordAPI, type RecordAdjustmentInput, type RecordAdjustmentLine, type RecordExpenseInput, type RecordOptions, type RecordPaymentInput, type RecordSaleInput, type RecordTransferInput, type ReportAccount, type ReportCategory, type ReportDescriptor, type ReportGroup, type ResolvedModelNames, type RevaluationOptions, type RevaluationParams, type RevaluationRate, type RevaluationReport, type RevaluationResult, type ReverseOptions, type ReverseResult, type SchemaOptions, type SeedOptions, type SeedResult, type Cents$1 as SemanticCents, type SessionResult, type StatementType, type StrictnessConfig, type SubledgerJournalItem, type SubledgerPostingInput, type TaxDetail, type TaxMetadata, type TotalAccountOp, type TrialBalanceReport, type TrialBalanceRow, type WatermarkResolverOptions, acquireSession, add, allocate, buildAccountTypeMap, buildDimensionFields, buildDimensionIndexes, buildItemFilters, buildRevaluationEntry, calculateTotal, closeFiscalPeriod, computeEndingBalance, computeRevaluation, createAccountingEngine, createLockPlugin, createModels, createRepositories, creditLimitPlugin, dailyLockPlugin, defaultLogger, defineCountryPack, doubleEntryPlugin, exportToCsv, finalizeSession, fiscalLockPlugin, flattenJournalEntries, format, formatPlain, fromDecimal, fxRealizationPlugin, generateAgedBalance, generateBalanceSheet, generateBudgetVsActual, generateCashFlow, generateDimensionBreakdown, generateGeneralLedger, generateIncomeStatement, generatePartnerLedger, generateRevaluation, generateTrialBalance, getCurrency, getCustomJournalTypes, getDateRange, getFiscalYearStart, getJournalType, getJournalTypeCodes, getMinorUnit, getNormalBalance, idempotencyPlugin, isBalanceSheet, isIncomeStatement, isValidCategory, isValidCurrency, isValidJournalType, isVirtualTaxAccount, multiply, parseCents, percentage, periodResolver, quickbooksFieldMap, registerJournalType, reopenFiscalPeriod, resolveModelNames, splitTaxExclusive, splitTaxInclusive, subtract, toDecimal, universalFieldMap, watermarkResolver };
|
package/dist/index.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import { Money, add, allocate, format, formatPlain, fromDecimal, multiply, parse
|
|
|
3
3
|
import { n as Errors, t as AccountingError } from "./errors-CSDQPNyt.mjs";
|
|
4
4
|
import { C as isVirtualTaxAccount, E as requireOrgScope, S as computeEndingBalance, T as generateAgedBalance, _ as buildItemFilters, a as finalizeSession, b as buildAccountTypeMap, c as generateRevaluation, d as generateIncomeStatement, f as generateGeneralLedger, g as generateBalanceSheet, h as generateBudgetVsActual, i as acquireSession, l as buildRevaluationEntry, m as generateCashFlow, n as closeFiscalPeriod, o as defaultLogger, p as generateDimensionBreakdown, r as reopenFiscalPeriod, s as generateTrialBalance, t as generatePartnerLedger, u as computeRevaluation, v as getDateRange, w as DEFAULT_BUCKETS, x as calculateTotal, y as getFiscalYearStart } from "./partner-ledger-D9H5hegI.mjs";
|
|
5
5
|
import { c as getNormalBalance, d as isValidCategory, l as isBalanceSheet, n as CATEGORY_KEYS, t as CATEGORIES, u as isIncomeStatement } from "./categories-BkKdv16V.mjs";
|
|
6
|
-
import { a as
|
|
6
|
+
import { a as watermarkResolver, c as idempotencyPlugin, i as fiscalLockPlugin, l as doubleEntryPlugin, n as creditLimitPlugin, o as periodResolver, r as dailyLockPlugin, s as createLockPlugin, t as fxRealizationPlugin } from "./fx-realization.plugin-CfYy1tB6.mjs";
|
|
7
7
|
import { defineCountryPack } from "./country/index.mjs";
|
|
8
8
|
import { a as exportToCsv, i as quickbooksFieldMap, r as universalFieldMap, t as flattenJournalEntries } from "./exports-BP-0Ni5W.mjs";
|
|
9
9
|
import mongoose, { Schema } from "mongoose";
|
|
@@ -2055,10 +2055,6 @@ function buildIntrospectAPI({ models, country, config }) {
|
|
|
2055
2055
|
return Object.freeze([...builtIn, ...custom]);
|
|
2056
2056
|
};
|
|
2057
2057
|
const reports = () => REPORT_CATALOG;
|
|
2058
|
-
const taxCodes = (region) => {
|
|
2059
|
-
if (region) return Object.freeze(country.getTaxCodesForRegion(region));
|
|
2060
|
-
return Object.freeze(Object.values(country.taxCodes));
|
|
2061
|
-
};
|
|
2062
2058
|
const fiscalPeriods = async (organizationId, session = null) => {
|
|
2063
2059
|
const filter = {};
|
|
2064
2060
|
if (orgField && organizationId != null) filter[orgField] = organizationId;
|
|
@@ -2076,32 +2072,21 @@ function buildIntrospectAPI({ models, country, config }) {
|
|
|
2076
2072
|
accounts: await accounts(organizationId),
|
|
2077
2073
|
journalTypes: journalTypes(),
|
|
2078
2074
|
reports: reports(),
|
|
2079
|
-
taxCodes: taxCodes(),
|
|
2080
2075
|
fiscalPeriods: await fiscalPeriods(organizationId)
|
|
2081
2076
|
});
|
|
2082
2077
|
return {
|
|
2083
2078
|
accounts,
|
|
2084
2079
|
journalTypes,
|
|
2085
2080
|
reports,
|
|
2086
|
-
taxCodes,
|
|
2087
2081
|
fiscalPeriods,
|
|
2088
2082
|
catalog
|
|
2089
2083
|
};
|
|
2090
2084
|
}
|
|
2091
2085
|
//#endregion
|
|
2092
2086
|
//#region src/semantic/record.ts
|
|
2093
|
-
function buildRecordAPI({ models, repositories,
|
|
2087
|
+
function buildRecordAPI({ models, repositories, config }) {
|
|
2094
2088
|
const AccountModel = models.Account;
|
|
2095
2089
|
const orgField = config.multiTenant?.orgField;
|
|
2096
|
-
const lookupTaxRate = (taxCode) => {
|
|
2097
|
-
const tc = country.taxCodes[taxCode];
|
|
2098
|
-
if (!tc) throw Errors.notFound(`Tax code '${taxCode}' not found in country pack.`, [{
|
|
2099
|
-
path: "tax.code",
|
|
2100
|
-
issue: "unknown tax code",
|
|
2101
|
-
value: taxCode
|
|
2102
|
-
}]);
|
|
2103
|
-
return tc.rate;
|
|
2104
|
-
};
|
|
2105
2090
|
const resolveAccounts = async (organizationId, codes, path, session) => {
|
|
2106
2091
|
const unique = Array.from(new Set(codes));
|
|
2107
2092
|
const filter = { accountTypeCode: { $in: unique } };
|
|
@@ -2155,26 +2140,8 @@ function buildRecordAPI({ models, repositories, country, config }) {
|
|
|
2155
2140
|
});
|
|
2156
2141
|
const sale = async (organizationId, input, options) => {
|
|
2157
2142
|
validateAmount(input.amount, "amount");
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
if (input.tax) {
|
|
2161
|
-
const rate = lookupTaxRate(input.tax.code);
|
|
2162
|
-
if (input.tax.inclusive) {
|
|
2163
|
-
const split = splitTaxInclusive(input.amount, rate);
|
|
2164
|
-
baseAmount = split.base;
|
|
2165
|
-
taxAmount = split.tax;
|
|
2166
|
-
} else {
|
|
2167
|
-
const split = splitTaxExclusive(input.amount, rate);
|
|
2168
|
-
baseAmount = split.base;
|
|
2169
|
-
taxAmount = split.tax;
|
|
2170
|
-
}
|
|
2171
|
-
}
|
|
2172
|
-
const totalCharge = baseAmount + taxAmount;
|
|
2173
|
-
const codes = [input.receivableAccount, input.revenueAccount];
|
|
2174
|
-
if (input.tax) codes.push(input.tax.account);
|
|
2175
|
-
const acctMap = await resolveAccounts(organizationId, codes, "receivableAccount", options?.session ?? null);
|
|
2176
|
-
const items = [buildItem(acctMap.get(input.receivableAccount), totalCharge, 0, input.label, input.dimensions), buildItem(acctMap.get(input.revenueAccount), 0, baseAmount, input.label, input.dimensions)];
|
|
2177
|
-
if (input.tax) items.push(buildItem(acctMap.get(input.tax.account), 0, taxAmount, `${input.label ?? "Sale"} — ${input.tax.code}`, input.dimensions));
|
|
2143
|
+
const acctMap = await resolveAccounts(organizationId, [input.receivableAccount, input.revenueAccount], "receivableAccount", options?.session ?? null);
|
|
2144
|
+
const items = [buildItem(acctMap.get(input.receivableAccount), input.amount, 0, input.label, input.dimensions), buildItem(acctMap.get(input.revenueAccount), 0, input.amount, input.label, input.dimensions)];
|
|
2178
2145
|
return postEntry(organizationId, {
|
|
2179
2146
|
journalType: input.journalType ?? "SALES",
|
|
2180
2147
|
date: input.date,
|
|
@@ -2185,27 +2152,8 @@ function buildRecordAPI({ models, repositories, country, config }) {
|
|
|
2185
2152
|
};
|
|
2186
2153
|
const expense = async (organizationId, input, options) => {
|
|
2187
2154
|
validateAmount(input.amount, "amount");
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
if (input.tax) {
|
|
2191
|
-
const rate = lookupTaxRate(input.tax.code);
|
|
2192
|
-
if (input.tax.inclusive) {
|
|
2193
|
-
const split = splitTaxInclusive(input.amount, rate);
|
|
2194
|
-
baseAmount = split.base;
|
|
2195
|
-
taxAmount = split.tax;
|
|
2196
|
-
} else {
|
|
2197
|
-
const split = splitTaxExclusive(input.amount, rate);
|
|
2198
|
-
baseAmount = split.base;
|
|
2199
|
-
taxAmount = split.tax;
|
|
2200
|
-
}
|
|
2201
|
-
}
|
|
2202
|
-
const totalPaid = baseAmount + taxAmount;
|
|
2203
|
-
const codes = [input.expenseAccount, input.paidFromAccount];
|
|
2204
|
-
if (input.tax) codes.push(input.tax.account);
|
|
2205
|
-
const acctMap = await resolveAccounts(organizationId, codes, "expenseAccount", options?.session ?? null);
|
|
2206
|
-
const items = [buildItem(acctMap.get(input.expenseAccount), baseAmount, 0, input.label, input.dimensions)];
|
|
2207
|
-
if (input.tax) items.push(buildItem(acctMap.get(input.tax.account), taxAmount, 0, `${input.label ?? "Expense"} — ${input.tax.code} ITC`, input.dimensions));
|
|
2208
|
-
items.push(buildItem(acctMap.get(input.paidFromAccount), 0, totalPaid, input.label, input.dimensions));
|
|
2155
|
+
const acctMap = await resolveAccounts(organizationId, [input.expenseAccount, input.paidFromAccount], "expenseAccount", options?.session ?? null);
|
|
2156
|
+
const items = [buildItem(acctMap.get(input.expenseAccount), input.amount, 0, input.label, input.dimensions), buildItem(acctMap.get(input.paidFromAccount), 0, input.amount, input.label, input.dimensions)];
|
|
2209
2157
|
return postEntry(organizationId, {
|
|
2210
2158
|
journalType: input.journalType ?? "PURCHASES",
|
|
2211
2159
|
date: input.date,
|
|
@@ -2337,7 +2285,6 @@ var AccountingEngine = class {
|
|
|
2337
2285
|
this.record = buildRecordAPI({
|
|
2338
2286
|
models: this.models,
|
|
2339
2287
|
repositories: this.repositories,
|
|
2340
|
-
country: this.country,
|
|
2341
2288
|
config: this.config
|
|
2342
2289
|
});
|
|
2343
2290
|
this.introspect = buildIntrospectAPI({
|
|
@@ -2366,10 +2313,6 @@ var AccountingEngine = class {
|
|
|
2366
2313
|
getAccountType(code) {
|
|
2367
2314
|
return this.country.getAccountType(code);
|
|
2368
2315
|
}
|
|
2369
|
-
/** Get tax codes for a region */
|
|
2370
|
-
getTaxCodesForRegion(region) {
|
|
2371
|
-
return this.country.getTaxCodesForRegion(region);
|
|
2372
|
-
}
|
|
2373
2316
|
_buildReports() {
|
|
2374
2317
|
const AccountModel = this.models.Account;
|
|
2375
2318
|
const JournalEntryModel = this.models.JournalEntry;
|
|
@@ -2450,68 +2393,6 @@ function createAccountingEngine(config) {
|
|
|
2450
2393
|
return new AccountingEngine(config);
|
|
2451
2394
|
}
|
|
2452
2395
|
//#endregion
|
|
2453
|
-
//#region src/utils/repartition-tax.ts
|
|
2454
|
-
/**
|
|
2455
|
-
* Default role resolver used when the country pack doesn't override.
|
|
2456
|
-
* Walks `taxCodes` to find a code whose `direction` matches the role.
|
|
2457
|
-
*/
|
|
2458
|
-
function defaultResolveRoleCode(role, _tax, country) {
|
|
2459
|
-
const direction = role === "collected" ? "collected" : role === "recoverable" ? "recoverable" : null;
|
|
2460
|
-
if (!direction) return void 0;
|
|
2461
|
-
for (const tc of Object.values(country.taxCodes)) if (tc.direction === direction) return tc.code;
|
|
2462
|
-
}
|
|
2463
|
-
/**
|
|
2464
|
-
* Build a `TaxLineGenerator` that expands each hit `taxCode` into one
|
|
2465
|
-
* journal item per repartition line. Taxes without `repartition` fall
|
|
2466
|
-
* back to a single-line generator using the direction-implied account.
|
|
2467
|
-
*/
|
|
2468
|
-
function createRepartitionTaxGenerator(options) {
|
|
2469
|
-
const { country, resolveAccount, documentType = "invoice" } = options;
|
|
2470
|
-
return { generateTaxLines(input) {
|
|
2471
|
-
const code = input.taxCode;
|
|
2472
|
-
if (!code) return [];
|
|
2473
|
-
const tax = country.taxCodes[code];
|
|
2474
|
-
if (!tax) return [];
|
|
2475
|
-
const baseTax = Math.round(input.amount * tax.rate / 100);
|
|
2476
|
-
if (baseTax === 0) return [];
|
|
2477
|
-
const lines = tax.repartition && tax.repartition.length > 0 ? tax.repartition.filter((line) => !line.documentTypes || line.documentTypes.includes(documentType)) : [{
|
|
2478
|
-
factor: 1,
|
|
2479
|
-
accountRole: tax.direction === "recoverable" ? "recoverable" : "collected",
|
|
2480
|
-
gridCode: tax.reportLines?.[0]
|
|
2481
|
-
}];
|
|
2482
|
-
const generated = [];
|
|
2483
|
-
for (const rep of lines) {
|
|
2484
|
-
const signed = Math.round(baseTax * rep.factor);
|
|
2485
|
-
if (signed === 0) continue;
|
|
2486
|
-
const account = resolveAccount(rep.accountRole, tax, input);
|
|
2487
|
-
if (!account) throw new Error(`repartitionTax: cannot resolve account for role "${rep.accountRole}" on tax "${tax.code}"`);
|
|
2488
|
-
const absAmount = Math.abs(signed);
|
|
2489
|
-
let onCredit = rep.accountRole === "collected" || rep.accountRole === "transition";
|
|
2490
|
-
if (signed < 0) onCredit = !onCredit;
|
|
2491
|
-
generated.push({
|
|
2492
|
-
account,
|
|
2493
|
-
debit: onCredit ? 0 : absAmount,
|
|
2494
|
-
credit: onCredit ? absAmount : 0,
|
|
2495
|
-
label: rep.label ?? `${tax.name} ${rep.accountRole}`,
|
|
2496
|
-
taxDetails: [{
|
|
2497
|
-
taxCode: tax.code,
|
|
2498
|
-
taxName: tax.name,
|
|
2499
|
-
...rep.gridCode != null ? { gridCode: String(rep.gridCode) } : {}
|
|
2500
|
-
}]
|
|
2501
|
-
});
|
|
2502
|
-
}
|
|
2503
|
-
return generated;
|
|
2504
|
-
} };
|
|
2505
|
-
}
|
|
2506
|
-
/**
|
|
2507
|
-
* Helper for packs that want the standard "role → account-type code"
|
|
2508
|
-
* mapping without writing their own resolver. Returns the function you
|
|
2509
|
-
* stuff into `CountryPackInput.resolveTaxRepartitionAccountCode`.
|
|
2510
|
-
*/
|
|
2511
|
-
function defaultResolveTaxRepartitionAccountCode(country) {
|
|
2512
|
-
return (role, tax) => defaultResolveRoleCode(role, tax, country);
|
|
2513
|
-
}
|
|
2514
|
-
//#endregion
|
|
2515
2396
|
//#region src/utils/dimensions.ts
|
|
2516
2397
|
/**
|
|
2517
2398
|
* Analytic Dimensions — Helpers for defining analytic dimensions
|
|
@@ -2571,4 +2452,4 @@ function buildDimensionIndexes(dimensions, orgField) {
|
|
|
2571
2452
|
});
|
|
2572
2453
|
}
|
|
2573
2454
|
//#endregion
|
|
2574
|
-
export { AccountingEngine, AccountingError, CATEGORIES, CATEGORY_KEYS, CURRENCIES, DEFAULT_BUCKETS, Errors, JOURNAL_CODES, JOURNAL_TYPES, Money, acquireSession, add, allocate, buildAccountTypeMap, buildDimensionFields, buildDimensionIndexes, buildItemFilters, buildRevaluationEntry, calculateTotal, closeFiscalPeriod, computeEndingBalance, computeRevaluation, createAccountingEngine, createLockPlugin, createModels,
|
|
2455
|
+
export { AccountingEngine, AccountingError, CATEGORIES, CATEGORY_KEYS, CURRENCIES, DEFAULT_BUCKETS, Errors, JOURNAL_CODES, JOURNAL_TYPES, Money, acquireSession, add, allocate, buildAccountTypeMap, buildDimensionFields, buildDimensionIndexes, buildItemFilters, buildRevaluationEntry, calculateTotal, closeFiscalPeriod, computeEndingBalance, computeRevaluation, createAccountingEngine, createLockPlugin, createModels, createRepositories, creditLimitPlugin, dailyLockPlugin, defaultLogger, defineCountryPack, doubleEntryPlugin, exportToCsv, finalizeSession, fiscalLockPlugin, flattenJournalEntries, format, formatPlain, fromDecimal, fxRealizationPlugin, generateAgedBalance, generateBalanceSheet, generateBudgetVsActual, generateCashFlow, generateDimensionBreakdown, generateGeneralLedger, generateIncomeStatement, generatePartnerLedger, generateRevaluation, generateTrialBalance, getCurrency, getCustomJournalTypes, getDateRange, getFiscalYearStart, getJournalType, getJournalTypeCodes, getMinorUnit, getNormalBalance, idempotencyPlugin, isBalanceSheet, isIncomeStatement, isValidCategory, isValidCurrency, isValidJournalType, isVirtualTaxAccount, multiply, parseCents, percentage, periodResolver, quickbooksFieldMap, registerJournalType, reopenFiscalPeriod, resolveModelNames, splitTaxExclusive, splitTaxInclusive, subtract, toDecimal, universalFieldMap, watermarkResolver };
|
package/dist/plugins/index.d.mts
CHANGED
|
@@ -1,16 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
//#region src/plugins/tax-hook.plugin.d.ts
|
|
5
|
-
interface TaxHookPluginOptions {
|
|
6
|
-
/** Tax line generator — implements the tax calculation logic */
|
|
7
|
-
generator: TaxLineGenerator;
|
|
8
|
-
/** Only apply tax hooks on posted entries (default: true) */
|
|
9
|
-
onlyOnPost?: boolean;
|
|
10
|
-
}
|
|
11
|
-
declare function taxHookPlugin(options: TaxHookPluginOptions): {
|
|
12
|
-
name: string;
|
|
13
|
-
apply(repo: RepositoryInstance): void;
|
|
14
|
-
};
|
|
15
|
-
//#endregion
|
|
16
|
-
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 TaxHookPluginOptions, type TaxLockPluginOptions, type WatermarkResolverOptions, createLockPlugin, creditLimitPlugin, dailyLockPlugin, doubleEntryPlugin, fiscalLockPlugin, fxRealizationPlugin, idempotencyPlugin, periodResolver, taxHookPlugin, taxLockPlugin, watermarkResolver };
|
|
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-Bl0_ak5w.mjs";
|
|
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/plugins/index.mjs
CHANGED
|
@@ -1,57 +1,2 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Apply a tax hook to journal items.
|
|
5
|
-
*
|
|
6
|
-
* Iterates each item that has a taxCode in taxDetails, calls
|
|
7
|
-
* `generator.generateTaxLines` for each, and appends the generated
|
|
8
|
-
* tax lines as new journal items.
|
|
9
|
-
*
|
|
10
|
-
* @returns The original items + generated tax items
|
|
11
|
-
*/
|
|
12
|
-
function applyTaxHook(items, generator) {
|
|
13
|
-
const taxLines = [];
|
|
14
|
-
for (const item of items) {
|
|
15
|
-
const taxDetails = item.taxDetails;
|
|
16
|
-
if (!taxDetails || taxDetails.length === 0) continue;
|
|
17
|
-
const taxCode = taxDetails.find((td) => td.taxCode != null)?.taxCode;
|
|
18
|
-
if (!taxCode) continue;
|
|
19
|
-
const side = item.debit > 0 ? "debit" : "credit";
|
|
20
|
-
const amount = item.debit > 0 ? item.debit : item.credit;
|
|
21
|
-
const input = {
|
|
22
|
-
account: item.account,
|
|
23
|
-
amount,
|
|
24
|
-
side,
|
|
25
|
-
taxCode
|
|
26
|
-
};
|
|
27
|
-
const generated = generator.generateTaxLines(input);
|
|
28
|
-
for (const line of generated) taxLines.push({
|
|
29
|
-
account: line.account,
|
|
30
|
-
debit: line.debit,
|
|
31
|
-
credit: line.credit,
|
|
32
|
-
label: line.label,
|
|
33
|
-
taxDetails: line.taxDetails
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
return [...items, ...taxLines];
|
|
37
|
-
}
|
|
38
|
-
//#endregion
|
|
39
|
-
//#region src/plugins/tax-hook.plugin.ts
|
|
40
|
-
function taxHookPlugin(options) {
|
|
41
|
-
const { generator, onlyOnPost = true } = options;
|
|
42
|
-
return {
|
|
43
|
-
name: "accounting:tax-hook",
|
|
44
|
-
apply(repo) {
|
|
45
|
-
repo.on("before:create", (context) => {
|
|
46
|
-
const data = context.data;
|
|
47
|
-
if (!data) return;
|
|
48
|
-
if (onlyOnPost && data.state !== "posted") return;
|
|
49
|
-
const items = data.journalItems;
|
|
50
|
-
if (!items || items.length === 0) return;
|
|
51
|
-
data.journalItems = applyTaxHook(items, generator);
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
//#endregion
|
|
57
|
-
export { createLockPlugin, creditLimitPlugin, dailyLockPlugin, doubleEntryPlugin, fiscalLockPlugin, fxRealizationPlugin, idempotencyPlugin, periodResolver, taxHookPlugin, taxLockPlugin, watermarkResolver };
|
|
1
|
+
import { a as watermarkResolver, c as idempotencyPlugin, i as fiscalLockPlugin, l as doubleEntryPlugin, n as creditLimitPlugin, o as periodResolver, r as dailyLockPlugin, s as createLockPlugin, t as fxRealizationPlugin } from "../fx-realization.plugin-CfYy1tB6.mjs";
|
|
2
|
+
export { 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, C as FiscalReopenResult, D as DimensionBreakdownParams, E as DimensionBreakdownOptions, F as BudgetVsActualReport, I as BudgetVsActualRow, L as generateBudgetVsActual, M as generateCashFlow, N as BudgetVsActualOptions, O as DimensionBreakdownReport, P as BudgetVsActualParams, R as BalanceSheetOptions, S as FiscalCloseResult, T as reopenFiscalPeriod, _ as IncomeStatementOptions, a as RevaluationReport,
|
|
1
|
+
import { $ as AgedBalanceParams, A as generateDimensionBreakdown, C as FiscalReopenResult, D as DimensionBreakdownParams, E as DimensionBreakdownOptions, F as BudgetVsActualReport, I as BudgetVsActualRow, L as generateBudgetVsActual, M as generateCashFlow, N as BudgetVsActualOptions, O as DimensionBreakdownReport, P as BudgetVsActualParams, Q as AgedBalanceOptions, R as BalanceSheetOptions, S as FiscalCloseResult, T as reopenFiscalPeriod, _ as IncomeStatementOptions, a as RevaluationReport, b as generateGeneralLedger, et as AgedBalanceReport, f as PartnerLedgerLine, g as generatePartnerLedger, h as PartnerLedgerReport, i as RevaluationParams, it as generateAgedBalance, j as CashFlowOptions, k as DimensionBreakdownRow, m as PartnerLedgerParams, n as generateTrialBalance, nt as AgedBucketConfig, o as generateRevaluation, p as PartnerLedgerOptions, r as RevaluationOptions, rt as DEFAULT_BUCKETS, t as TrialBalanceOptions, tt as AgedBalanceRow, v as generateIncomeStatement, w as closeFiscalPeriod, x as FiscalCloseOptions, y as GeneralLedgerOptions, z as generateBalanceSheet } from "../trial-balance-DTc8kzTD.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 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, generateDimensionBreakdown, generateGeneralLedger, generateIncomeStatement, generatePartnerLedger, generateRevaluation, generateTrialBalance, reopenFiscalPeriod };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { c as DateRange } from "./core-BkGjuVZj.mjs";
|
|
2
|
-
import { t as CountryPack } from "./index-
|
|
2
|
+
import { t as CountryPack } from "./index-BX8miYdu.mjs";
|
|
3
3
|
import { ClientSession, Model } from "mongoose";
|
|
4
4
|
|
|
5
5
|
//#region src/utils/logger.d.ts
|
|
@@ -178,37 +178,6 @@ interface CashFlowReport {
|
|
|
178
178
|
financing: CashFlowSection;
|
|
179
179
|
netCashFlow: number;
|
|
180
180
|
}
|
|
181
|
-
interface TaxAccountBalance {
|
|
182
|
-
code: string;
|
|
183
|
-
name: string;
|
|
184
|
-
balance: number;
|
|
185
|
-
taxMetadata?: unknown;
|
|
186
|
-
}
|
|
187
|
-
interface TaxReturnSummary {
|
|
188
|
-
totalSales: number;
|
|
189
|
-
gstHstCollected: number;
|
|
190
|
-
inputTaxCredits: number;
|
|
191
|
-
netTax: number;
|
|
192
|
-
finalAmount: number;
|
|
193
|
-
isRefund: boolean;
|
|
194
|
-
refundAmount: number;
|
|
195
|
-
paymentAmount: number;
|
|
196
|
-
}
|
|
197
|
-
interface TaxReport {
|
|
198
|
-
period: {
|
|
199
|
-
startDate: string;
|
|
200
|
-
endDate: string;
|
|
201
|
-
province: string;
|
|
202
|
-
};
|
|
203
|
-
accountBalances: {
|
|
204
|
-
collected: Record<string, TaxAccountBalance>;
|
|
205
|
-
itc: Record<string, TaxAccountBalance>;
|
|
206
|
-
instalments: Record<string, TaxAccountBalance>;
|
|
207
|
-
};
|
|
208
|
-
craLines: Record<string | number, number>;
|
|
209
|
-
summary: TaxReturnSummary;
|
|
210
|
-
calculatedAt: string;
|
|
211
|
-
}
|
|
212
181
|
//#endregion
|
|
213
182
|
//#region src/reports/balance-sheet.d.ts
|
|
214
183
|
interface BalanceSheetOptions {
|
|
@@ -612,4 +581,4 @@ declare function generateTrialBalance(opts: TrialBalanceOptions, params: {
|
|
|
612
581
|
filters?: Record<string, unknown>;
|
|
613
582
|
}): Promise<TrialBalanceReport>;
|
|
614
583
|
//#endregion
|
|
615
|
-
export {
|
|
584
|
+
export { AgedBalanceParams as $, generateDimensionBreakdown as A, BalanceSheetReport as B, FiscalReopenResult as C, DimensionBreakdownParams as D, DimensionBreakdownOptions as E, BudgetVsActualReport as F, IncomeStatementReport as G, CashFlowSection as H, BudgetVsActualRow as I, ReportCategory as J, LedgerEntry as K, generateBudgetVsActual as L, generateCashFlow as M, BudgetVsActualOptions as N, DimensionBreakdownReport as O, BudgetVsActualParams as P, AgedBalanceOptions as Q, BalanceSheetOptions as R, FiscalCloseResult as S, reopenFiscalPeriod as T, GeneralLedgerAccount as U, CashFlowReport as V, GeneralLedgerReport as W, TrialBalanceReport as X, ReportGroup as Y, TrialBalanceRow as Z, IncomeStatementOptions as _, RevaluationReport as a, Logger as at, generateGeneralLedger as b, RevaluationRate as c, computeRevaluation as d, AgedBalanceReport as et, PartnerLedgerLine as f, generatePartnerLedger as g, PartnerLedgerReport as h, RevaluationParams as i, generateAgedBalance as it, CashFlowOptions as j, DimensionBreakdownRow as k, RevaluationResult as l, PartnerLedgerParams as m, generateTrialBalance as n, AgedBucketConfig as nt, generateRevaluation as o, defaultLogger as ot, PartnerLedgerOptions as p, ReportAccount as q, RevaluationOptions as r, DEFAULT_BUCKETS as rt, AccountForeignBalance as s, TrialBalanceOptions as t, AgedBalanceRow as tt, buildRevaluationEntry as u, generateIncomeStatement as v, closeFiscalPeriod as w, FiscalCloseOptions as x, GeneralLedgerOptions as y, generateBalanceSheet as z };
|
package/package.json
CHANGED
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
import { t as AccountType } from "./core-BkGjuVZj.mjs";
|
|
2
|
-
|
|
3
|
-
//#region src/country/index.d.ts
|
|
4
|
-
/**
|
|
5
|
-
* A single destination for a fraction of a tax amount. A `TaxCode` can declare
|
|
6
|
-
* multiple repartition lines so that one tax percentage produces multiple
|
|
7
|
-
* journal items (e.g. reverse-charge VAT books +100% to payable AND -100% to
|
|
8
|
-
* recoverable in the same entry). Factors sum across lines and the engine
|
|
9
|
-
* enforces balance inside the existing double-entry plugin.
|
|
10
|
-
*
|
|
11
|
-
* `accountRole` is a logical name looked up against the consumer's chart of
|
|
12
|
-
* accounts via the country pack's `resolveRepartitionAccount` helper — NOT a
|
|
13
|
-
* direct ObjectId, so the same country pack can drive any consumer's accounts.
|
|
14
|
-
* `gridCode` flows through to `taxDetails` for regulatory reporting (CRA
|
|
15
|
-
* schedule lines, HMRC VAT boxes, NBR Mushak grid, etc.).
|
|
16
|
-
*/
|
|
17
|
-
interface TaxRepartitionLine {
|
|
18
|
-
/**
|
|
19
|
-
* Signed multiplier applied to the base tax amount. Use `1` for the
|
|
20
|
-
* "normal" line, `-1` for a mirror (e.g. recoverable reverse-charge).
|
|
21
|
-
* Fractions (e.g. `0.5`) are allowed for split-destination taxes.
|
|
22
|
-
*/
|
|
23
|
-
readonly factor: number;
|
|
24
|
-
/**
|
|
25
|
-
* Logical role resolved against the country pack. Standard roles:
|
|
26
|
-
* - `'collected'` — tax collected from customer (liability)
|
|
27
|
-
* - `'recoverable'` — tax paid to supplier, recoverable (asset)
|
|
28
|
-
* - `'expense'` — tax paid, non-recoverable (expense)
|
|
29
|
-
* - `'transition'` — temporary holding account for cash-basis exigibility
|
|
30
|
-
* Consumers can define custom roles and wire them in their country pack.
|
|
31
|
-
*/
|
|
32
|
-
readonly accountRole: string;
|
|
33
|
-
/** Optional reporting grid code — propagated to `taxDetails` on the item. */
|
|
34
|
-
readonly gridCode?: string | number;
|
|
35
|
-
/** Optional human label surfaced in UI and audit trails. */
|
|
36
|
-
readonly label?: string;
|
|
37
|
-
/** Optional: only apply on these document types. Default: all. */
|
|
38
|
-
readonly documentTypes?: readonly ('invoice' | 'refund' | 'payment')[];
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* When a tax is realized into the books:
|
|
42
|
-
* - `'accrual'` (default) — books at entry time (what 0.5.x did for everything)
|
|
43
|
-
* - `'cash'` — books into a transition account at entry time, moves to the
|
|
44
|
-
* real tax account when the invoice is reconciled against a payment
|
|
45
|
-
*/
|
|
46
|
-
type TaxExigibility = 'accrual' | 'cash';
|
|
47
|
-
interface TaxCode {
|
|
48
|
-
readonly code: string;
|
|
49
|
-
readonly name: string;
|
|
50
|
-
readonly taxType: string;
|
|
51
|
-
readonly rate: number;
|
|
52
|
-
readonly direction: 'collected' | 'recoverable' | 'paid';
|
|
53
|
-
readonly province?: string;
|
|
54
|
-
readonly reportLines?: readonly number[];
|
|
55
|
-
readonly description: string;
|
|
56
|
-
readonly active: boolean;
|
|
57
|
-
/**
|
|
58
|
-
* Multi-line repartition — when present, `createRepartitionTaxGenerator`
|
|
59
|
-
* produces one journal item per line. When absent, the tax behaves as a
|
|
60
|
-
* single-line tax routed to the `direction`-implied account.
|
|
61
|
-
*/
|
|
62
|
-
readonly repartition?: readonly TaxRepartitionLine[];
|
|
63
|
-
/**
|
|
64
|
-
* Accrual (default) or cash-basis exigibility. When `'cash'`, requires
|
|
65
|
-
* a `transition` repartition role in `repartition` OR a country-pack
|
|
66
|
-
* default transition account.
|
|
67
|
-
*/
|
|
68
|
-
readonly exigibility?: TaxExigibility;
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Declarative template that tells the engine which journals to seed for a
|
|
72
|
-
* new organization. Consumers call
|
|
73
|
-
* `engine.repositories.journals.seedDefaults(orgId)` which reads these from
|
|
74
|
-
* the country pack and creates one Journal document per template.
|
|
75
|
-
*
|
|
76
|
-
* Journals are *optional* — if a consumer never seeds journals, the legacy
|
|
77
|
-
* `journalType` enum on a journal entry still works. Consumers opting in
|
|
78
|
-
* get per-journal sequence prefixes, restricted payment methods, bank
|
|
79
|
-
* statement sources, etc.
|
|
80
|
-
*/
|
|
81
|
-
interface JournalTemplate {
|
|
82
|
-
/** Short stable identifier — e.g. `'SALES'`, `'PURCHASE'`, `'BANK'`. */
|
|
83
|
-
readonly code: string;
|
|
84
|
-
/** Display name. */
|
|
85
|
-
readonly name: string;
|
|
86
|
-
/**
|
|
87
|
-
* One of the registered `JOURNAL_TYPES` codes — connects this journal to
|
|
88
|
-
* the engine's reference-number generator and posting-contract system.
|
|
89
|
-
*/
|
|
90
|
-
readonly journalType: string;
|
|
91
|
-
/** Reference-number prefix — defaults to `code` when omitted. */
|
|
92
|
-
readonly sequencePrefix?: string;
|
|
93
|
-
/** First sequence number — defaults to `1`. */
|
|
94
|
-
readonly sequenceStartNum?: number;
|
|
95
|
-
/**
|
|
96
|
-
* Logical source — pure ledgering (`'general'`), sale-side docs (`'sale'`),
|
|
97
|
-
* purchase-side docs (`'purchase'`), cash/bank movement (`'bank'`, `'cash'`).
|
|
98
|
-
* Drives default locks (sale-lock, purchase-lock) when they're wired.
|
|
99
|
-
*/
|
|
100
|
-
readonly kind?: 'general' | 'sale' | 'purchase' | 'bank' | 'cash' | string;
|
|
101
|
-
/** Optional default debit/credit account roles for quick data entry. */
|
|
102
|
-
readonly defaultDebitAccountRole?: string;
|
|
103
|
-
readonly defaultCreditAccountRole?: string;
|
|
104
|
-
}
|
|
105
|
-
interface TaxCodesByRegion {
|
|
106
|
-
readonly [region: string]: readonly string[];
|
|
107
|
-
}
|
|
108
|
-
interface TaxReportLine {
|
|
109
|
-
readonly line: number | string;
|
|
110
|
-
readonly name: string;
|
|
111
|
-
readonly description: string;
|
|
112
|
-
readonly type: 'input' | 'calculated' | 'manual';
|
|
113
|
-
readonly calculate?: (data: Record<string | number, number>) => number;
|
|
114
|
-
readonly section: string;
|
|
115
|
-
}
|
|
116
|
-
interface TaxReportTemplate {
|
|
117
|
-
readonly name: string;
|
|
118
|
-
readonly lines: Readonly<Record<string | number, TaxReportLine>>;
|
|
119
|
-
calculate(inputData: Record<string | number, number>, manualData?: Record<string | number, number>): Record<string | number, number>;
|
|
120
|
-
summarize(calculated: Record<string | number, number>): Record<string, unknown>;
|
|
121
|
-
}
|
|
122
|
-
interface CountryPack {
|
|
123
|
-
/** ISO 3166-1 alpha-2 code (e.g., 'CA', 'US', 'GB') */
|
|
124
|
-
readonly code: string;
|
|
125
|
-
/** Country name */
|
|
126
|
-
readonly name: string;
|
|
127
|
-
/** Default currency code */
|
|
128
|
-
readonly defaultCurrency: string;
|
|
129
|
-
/**
|
|
130
|
-
* Full chart of accounts template — flat array of account type definitions.
|
|
131
|
-
* Includes both regular accounts and virtual tax sub-accounts.
|
|
132
|
-
*/
|
|
133
|
-
readonly accountTypes: readonly AccountType[];
|
|
134
|
-
/** Tax codes indexed by code string */
|
|
135
|
-
readonly taxCodes: Readonly<Record<string, TaxCode>>;
|
|
136
|
-
/** Tax codes grouped by region/province/state */
|
|
137
|
-
readonly taxCodesByRegion: TaxCodesByRegion;
|
|
138
|
-
/** Available regions (provinces/states) */
|
|
139
|
-
readonly regions: readonly string[];
|
|
140
|
-
/** Tax report template (e.g., CRA GST/HST return) */
|
|
141
|
-
readonly taxReport?: TaxReportTemplate;
|
|
142
|
-
/**
|
|
143
|
-
* Optional journal templates seeded per organization. When a consumer
|
|
144
|
-
* calls `engine.repositories.journals.seedDefaults(orgId)`, the engine
|
|
145
|
-
* creates one Journal document per template. See `JournalTemplate`.
|
|
146
|
-
*/
|
|
147
|
-
readonly journalTemplates?: readonly JournalTemplate[];
|
|
148
|
-
/**
|
|
149
|
-
* Map a logical `accountRole` string (e.g. `'collected'`, `'recoverable'`,
|
|
150
|
-
* `'transition'`) to the actual account-type code for this country. The
|
|
151
|
-
* repartition tax generator calls this for each repartition line so the
|
|
152
|
-
* same tax definition can resolve different account codes in BD vs CA.
|
|
153
|
-
*
|
|
154
|
-
* Default behavior when omitted: maps `'collected'` → account with
|
|
155
|
-
* direction='collected' in `taxCodes`, `'recoverable'` →
|
|
156
|
-
* direction='recoverable', etc. Consumers override for custom roles.
|
|
157
|
-
*/
|
|
158
|
-
readonly resolveTaxRepartitionAccountCode?: (role: string, taxCode: TaxCode) => string | undefined;
|
|
159
|
-
/**
|
|
160
|
-
* The retained earnings account code — the account that holds accumulated
|
|
161
|
-
* retained earnings (e.g. '3600' CA, '3310' BD).
|
|
162
|
-
*
|
|
163
|
-
* On the balance sheet, this account is excluded from normal equity grouping
|
|
164
|
-
* and its balance is folded into the computed "Retained Earnings" section
|
|
165
|
-
* (opening RE = RE account balance + prior-year unclosed P&L).
|
|
166
|
-
*
|
|
167
|
-
* Inspired by Odoo's `equity_unaffected` account type.
|
|
168
|
-
*/
|
|
169
|
-
readonly retainedEarningsAccountCode?: string;
|
|
170
|
-
/**
|
|
171
|
-
* Display code for the "Previous Years Retained Earnings" line on the
|
|
172
|
-
* balance sheet (e.g. '3660' for CA GIFI). Defaults to retainedEarningsAccountCode.
|
|
173
|
-
*/
|
|
174
|
-
readonly retainedEarningsDisplayCode?: string;
|
|
175
|
-
/** Display code for current year net income line (e.g. '3680' CA, '3311' BD) */
|
|
176
|
-
readonly currentYearEarningsCode?: string;
|
|
177
|
-
/** Group label code used to identify Cost of Sales in the income statement */
|
|
178
|
-
readonly cogsGroupCode?: string;
|
|
179
|
-
/** Override default English report section names */
|
|
180
|
-
readonly reportLabels?: {
|
|
181
|
-
readonly assets?: string;
|
|
182
|
-
readonly liabilities?: string;
|
|
183
|
-
readonly equity?: string;
|
|
184
|
-
readonly revenue?: string;
|
|
185
|
-
readonly expenses?: string;
|
|
186
|
-
};
|
|
187
|
-
/** Get all account types that can be posted to (not groups, not totals) */
|
|
188
|
-
getPostingAccountTypes(): readonly AccountType[];
|
|
189
|
-
/** Get account type by code */
|
|
190
|
-
getAccountType(code: string): AccountType | undefined;
|
|
191
|
-
/** Validate an account type code exists */
|
|
192
|
-
isValidAccountType(code: string): boolean;
|
|
193
|
-
/** Check if an account type can receive postings */
|
|
194
|
-
isPostingAccount(code: string): boolean;
|
|
195
|
-
/** Get tax codes for a specific region */
|
|
196
|
-
getTaxCodesForRegion(region: string): TaxCode[];
|
|
197
|
-
/** Flatten hierarchical accounts (if needed) */
|
|
198
|
-
flattenAccountTypes(): readonly AccountType[];
|
|
199
|
-
}
|
|
200
|
-
interface CountryPackInput {
|
|
201
|
-
code: string;
|
|
202
|
-
name: string;
|
|
203
|
-
defaultCurrency: string;
|
|
204
|
-
accountTypes: readonly AccountType[];
|
|
205
|
-
taxCodes: Readonly<Record<string, TaxCode>>;
|
|
206
|
-
taxCodesByRegion: TaxCodesByRegion;
|
|
207
|
-
regions: readonly string[];
|
|
208
|
-
taxReport?: TaxReportTemplate;
|
|
209
|
-
journalTemplates?: readonly JournalTemplate[];
|
|
210
|
-
resolveTaxRepartitionAccountCode?: (role: string, taxCode: TaxCode) => string | undefined;
|
|
211
|
-
retainedEarningsAccountCode?: string;
|
|
212
|
-
retainedEarningsDisplayCode?: string;
|
|
213
|
-
currentYearEarningsCode?: string;
|
|
214
|
-
cogsGroupCode?: string;
|
|
215
|
-
reportLabels?: {
|
|
216
|
-
readonly assets?: string;
|
|
217
|
-
readonly liabilities?: string;
|
|
218
|
-
readonly equity?: string;
|
|
219
|
-
readonly revenue?: string;
|
|
220
|
-
readonly expenses?: string;
|
|
221
|
-
};
|
|
222
|
-
}
|
|
223
|
-
/**
|
|
224
|
-
* Factory to create a CountryPack with auto-generated helper methods.
|
|
225
|
-
*/
|
|
226
|
-
declare function defineCountryPack(input: CountryPackInput): CountryPack;
|
|
227
|
-
//#endregion
|
|
228
|
-
export { TaxCodesByRegion as a, TaxReportLine as c, TaxCode as i, TaxReportTemplate as l, CountryPackInput as n, TaxExigibility as o, JournalTemplate as r, TaxRepartitionLine as s, CountryPack as t, defineCountryPack as u };
|