@classytic/ledger 0.3.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/README.md +82 -20
  2. package/dist/constants/index.d.mts +2 -2
  3. package/dist/constants/index.mjs +3 -3
  4. package/dist/{date-lock.plugin-eYAJ9h_u.mjs → date-lock.plugin-DL6pe24p.mjs} +2 -2
  5. package/dist/{engine-Cn-9yerQ.d.mts → engine-scgOvxHJ.d.mts} +30 -2
  6. package/dist/exports/index.d.mts +1 -1
  7. package/dist/exports/index.mjs +1 -1
  8. package/dist/{exports-I5Xkq-9_.mjs → exports-DoGQQtMQ.mjs} +96 -75
  9. package/dist/{fiscal-close-B6LhQ10f.mjs → fiscal-close-B2_7WMTe.mjs} +748 -751
  10. package/dist/{index-BPukb3L8.d.mts → index-J-XIbXH-.d.mts} +7 -7
  11. package/dist/index.d.mts +239 -87
  12. package/dist/index.mjs +149 -12
  13. package/dist/{fiscal-period.schema-BMnlI9H5.d.mts → journal-entry.schema-JqrfbvB4.d.mts} +12 -12
  14. package/dist/{journals-oH-FK3g8.mjs → journals-BfwnCFam.mjs} +27 -4
  15. package/dist/{currencies-4WAbFRlw.d.mts → journals-DTipb_rz.d.mts} +16 -7
  16. package/dist/money.mjs +2 -2
  17. package/dist/plugins/index.d.mts +1 -1
  18. package/dist/plugins/index.mjs +1 -1
  19. package/dist/{reconciliation.repository-CW4-8q90.d.mts → reconciliation.repository-D-D_ITL-.d.mts} +14 -14
  20. package/dist/{account.repository-BpkSd6q3.mjs → reconciliation.repository-fPwFKvrk.mjs} +255 -255
  21. package/dist/{reconciliation.schema-BuetvZTd.mjs → reconciliation.schema-BA1lPv4t.mjs} +174 -173
  22. package/dist/reports/index.d.mts +1 -1
  23. package/dist/reports/index.mjs +1 -1
  24. package/dist/repositories/index.d.mts +1 -1
  25. package/dist/repositories/index.mjs +1 -1
  26. package/dist/schemas/index.d.mts +6 -6
  27. package/dist/schemas/index.mjs +1 -1
  28. package/dist/{tenant-guard-Fm6AID_6.mjs → tenant-guard-r17Se3Bb.mjs} +1 -1
  29. package/dist/{revaluation-D9x0NE8w.d.mts → trial-balance-DcQ0xj_4.d.mts} +124 -124
  30. package/docs/schemas.md +2 -2
  31. package/package.json +14 -6
  32. /package/dist/{categories-CclX7Q94.mjs → categories-DWogBUgQ.mjs} +0 -0
  33. /package/dist/{errors-B7yC-Jfw.mjs → errors-B_dyYZc_.mjs} +0 -0
  34. /package/dist/{idempotency.plugin-B_CNsInz.d.mts → idempotency.plugin-zU-GKJ0-.d.mts} +0 -0
  35. /package/dist/{logger-CbHWZl7v.d.mts → logger-UbTdBb1x.d.mts} +0 -0
package/dist/index.mjs CHANGED
@@ -1,25 +1,154 @@
1
- import { a as createAccountSchema, i as createJournalEntrySchema, n as createBudgetSchema, r as createFiscalPeriodSchema, t as createReconciliationSchema } from "./reconciliation.schema-BuetvZTd.mjs";
2
- import { a as isValidJournalType, i as getJournalTypeCodes, n as JOURNAL_TYPES, t as JOURNAL_CODES } from "./journals-oH-FK3g8.mjs";
3
- import { C as getDateRange, S as buildItemFilters, _ as buildAccountTypeMap, a as defaultLogger, b as isVirtualTaxAccount, c as computeRevaluation, d as DEFAULT_BUCKETS, f as generateAgedBalance, g as generateBalanceSheet, h as generateIncomeStatement, i as finalizeSession, l as generateBudgetVsActual, m as generateGeneralLedger, n as reopenFiscalPeriod, o as generateRevaluation, p as generateCashFlow, r as acquireSession, s as buildRevaluationEntry, t as closeFiscalPeriod, u as generateDimensionBreakdown, v as calculateTotal, w as getFiscalYearStart, x as generateTrialBalance, y as computeEndingBalance } from "./fiscal-close-B6LhQ10f.mjs";
4
- import { n as Errors, t as AccountingError } from "./errors-B7yC-Jfw.mjs";
5
- import { c as getNormalBalance, d as isValidCategory, l as isBalanceSheet, n as CATEGORY_KEYS, t as CATEGORIES, u as isIncomeStatement } from "./categories-CclX7Q94.mjs";
6
- import { n as wireJournalEntryMethods, r as wireReconciliationMethods, t as wireAccountMethods } from "./account.repository-BpkSd6q3.mjs";
1
+ import { a as createAccountSchema, i as createBudgetSchema, n as createJournalEntrySchema, r as createFiscalPeriodSchema, t as createReconciliationSchema } from "./reconciliation.schema-BA1lPv4t.mjs";
2
+ import { a as getJournalType, c as registerJournalType, i as getCustomJournalTypes, n as JOURNAL_TYPES, o as getJournalTypeCodes, s as isValidJournalType, t as JOURNAL_CODES } from "./journals-BfwnCFam.mjs";
7
3
  import { Money, add, allocate, format, formatPlain, fromDecimal, multiply, parseCents, percentage, splitTaxExclusive, splitTaxInclusive, subtract, toDecimal } from "./money.mjs";
8
- import { i as doubleEntryPlugin, n as idempotencyPlugin, r as fiscalLockPlugin, t as dateLockPlugin } from "./date-lock.plugin-eYAJ9h_u.mjs";
4
+ import { n as Errors, t as AccountingError } from "./errors-B_dyYZc_.mjs";
5
+ import { i as doubleEntryPlugin, n as idempotencyPlugin, r as fiscalLockPlugin, t as dateLockPlugin } from "./date-lock.plugin-DL6pe24p.mjs";
6
+ import { C as DEFAULT_BUCKETS, S as isVirtualTaxAccount, _ as getDateRange, a as defaultLogger, b as calculateTotal, c as buildRevaluationEntry, d as generateGeneralLedger, f as generateDimensionBreakdown, g as buildItemFilters, h as generateBalanceSheet, i as finalizeSession, l as computeRevaluation, m as generateBudgetVsActual, n as reopenFiscalPeriod, o as generateTrialBalance, p as generateCashFlow, r as acquireSession, s as generateRevaluation, t as closeFiscalPeriod, u as generateIncomeStatement, v as getFiscalYearStart, w as generateAgedBalance, x as computeEndingBalance, y as buildAccountTypeMap } from "./fiscal-close-B2_7WMTe.mjs";
7
+ import { c as getNormalBalance, d as isValidCategory, l as isBalanceSheet, n as CATEGORY_KEYS, t as CATEGORIES, u as isIncomeStatement } from "./categories-DWogBUgQ.mjs";
8
+ import { n as wireJournalEntryMethods, r as wireAccountMethods, t as wireReconciliationMethods } from "./reconciliation.repository-fPwFKvrk.mjs";
9
9
  import { i as isValidCurrency, n as getCurrency, r as getMinorUnit, t as CURRENCIES } from "./currencies-W8kQAkm0.mjs";
10
10
  import { defineCountryPack } from "./country/index.mjs";
11
- import { a as exportToCsv, n as quickbooksFieldMap, r as flattenJournalEntries, t as universalFieldMap } from "./exports-I5Xkq-9_.mjs";
11
+ import { a as exportToCsv, i as quickbooksFieldMap, r as universalFieldMap, t as flattenJournalEntries } from "./exports-DoGQQtMQ.mjs";
12
12
  import { Schema } from "mongoose";
13
+ import { Repository } from "@classytic/mongokit";
14
+ //#region src/models/factory.ts
15
+ function resolveModelNames(overrides) {
16
+ return {
17
+ account: overrides?.account ?? "Account",
18
+ journalEntry: overrides?.journalEntry ?? "JournalEntry",
19
+ fiscalPeriod: overrides?.fiscalPeriod ?? "FiscalPeriod",
20
+ budget: overrides?.budget ?? "Budget",
21
+ reconciliation: overrides?.reconciliation ?? "Reconciliation"
22
+ };
23
+ }
24
+ /**
25
+ * Create (or reuse) all ledger models on the given connection.
26
+ *
27
+ * If a model with the same name is already registered on the connection,
28
+ * the existing model is reused — this allows multiple engine instances
29
+ * to share models and prevents "OverwriteModelError".
30
+ */
31
+ function createModels(connection, config) {
32
+ const names = resolveModelNames(config.modelNames);
33
+ const so = config.schemaOptions ?? {};
34
+ const existing = connection.models;
35
+ if (existing[names.account] && existing[names.journalEntry] && existing[names.fiscalPeriod] && existing[names.budget] && existing[names.reconciliation]) return {
36
+ Account: existing[names.account],
37
+ JournalEntry: existing[names.journalEntry],
38
+ FiscalPeriod: existing[names.fiscalPeriod],
39
+ Budget: existing[names.budget],
40
+ Reconciliation: existing[names.reconciliation]
41
+ };
42
+ return {
43
+ Account: existing[names.account] ?? connection.model(names.account, createAccountSchema(config, so.account)),
44
+ JournalEntry: existing[names.journalEntry] ?? connection.model(names.journalEntry, createJournalEntrySchema(config, names.account, so.journalEntry)),
45
+ FiscalPeriod: existing[names.fiscalPeriod] ?? connection.model(names.fiscalPeriod, createFiscalPeriodSchema(config, so.fiscalPeriod)),
46
+ Budget: existing[names.budget] ?? connection.model(names.budget, createBudgetSchema(config, so.budget)),
47
+ Reconciliation: existing[names.reconciliation] ?? connection.model(names.reconciliation, createReconciliationSchema(config, names.account, names.journalEntry, so.reconciliation))
48
+ };
49
+ }
50
+ //#endregion
51
+ //#region src/repositories/factory.ts
52
+ /**
53
+ * Repositories Factory — wires fully-configured repositories.
54
+ *
55
+ * Matches the flow/promo pattern: engine owns the repositories with all
56
+ * plugins (double-entry, fiscal-lock, idempotency) pre-wired.
57
+ *
58
+ * Consumer never constructs Repository, never calls wireXxx methods.
59
+ * Just uses `engine.repositories.accounts.seedAccounts(orgId)`.
60
+ */
61
+ /**
62
+ * Build all ledger repositories with plugins + domain methods pre-wired.
63
+ *
64
+ * - `accounts` — has seedAccounts(), bulkCreate()
65
+ * - `journalEntries` — has post(), unpost(), reverse(), duplicate() + double-entry + fiscal-lock (+ idempotency if enabled)
66
+ * - `fiscalPeriods` — plain CRUD
67
+ * - `budgets` — plain CRUD
68
+ * - `reconciliations` — has reconcile(), unreconcile(), getUnreconciled()
69
+ */
70
+ function createRepositories(models, config, plugins = {}) {
71
+ const orgField = config.multiTenant?.orgField;
72
+ const strictness = config.strictness;
73
+ const country = config.country;
74
+ const accounts = wireAccountMethods(new Repository(models.Account, plugins.account ?? []), models.Account, country, orgField);
75
+ const jePlugins = [
76
+ ...plugins.journalEntry ?? [],
77
+ doubleEntryPlugin({
78
+ JournalEntryModel: models.JournalEntry,
79
+ AccountModel: models.Account,
80
+ orgField
81
+ }),
82
+ fiscalLockPlugin({
83
+ FiscalPeriodModel: models.FiscalPeriod,
84
+ JournalEntryModel: models.JournalEntry,
85
+ orgField
86
+ })
87
+ ];
88
+ if (config.idempotency) jePlugins.push(idempotencyPlugin({
89
+ JournalEntryModel: models.JournalEntry,
90
+ orgField
91
+ }));
92
+ return {
93
+ accounts,
94
+ journalEntries: wireJournalEntryMethods(new Repository(models.JournalEntry, jePlugins), models.JournalEntry, orgField, strictness),
95
+ fiscalPeriods: new Repository(models.FiscalPeriod, plugins.fiscalPeriod ?? []),
96
+ budgets: new Repository(models.Budget, plugins.budget ?? []),
97
+ reconciliations: wireReconciliationMethods(new Repository(models.Reconciliation, plugins.reconciliation ?? []), models.Reconciliation, models.JournalEntry, orgField)
98
+ };
99
+ }
100
+ //#endregion
13
101
  //#region src/engine.ts
14
102
  var AccountingEngine = class {
15
103
  config;
16
104
  country;
17
105
  currency;
18
106
  money = Money;
19
- constructor(config) {
107
+ _models;
108
+ _repositories;
109
+ _reports;
110
+ constructor(config, plugins = {}) {
20
111
  this.config = config;
21
112
  this.country = config.country;
22
113
  this.currency = config.currency;
114
+ if (config.mongoose) {
115
+ this._models = createModels(config.mongoose, config);
116
+ this._repositories = createRepositories(this._models, config, plugins);
117
+ }
118
+ }
119
+ /**
120
+ * Auto-created Mongoose models. Requires `mongoose` in config.
121
+ *
122
+ * @throws if `mongoose` was not provided in config
123
+ */
124
+ get models() {
125
+ if (!this._models) throw new Error("engine.models requires a Mongoose connection. Pass `mongoose: connection` in createAccountingEngine config.");
126
+ return this._models;
127
+ }
128
+ /**
129
+ * Auto-wired repositories with plugins + domain methods (post, reverse, etc.).
130
+ * Requires `mongoose` in config.
131
+ *
132
+ * @throws if `mongoose` was not provided in config
133
+ */
134
+ get repositories() {
135
+ if (!this._repositories) throw new Error("engine.repositories requires a Mongoose connection. Pass `mongoose: connection` in createAccountingEngine config.");
136
+ return this._repositories;
137
+ }
138
+ /**
139
+ * Pre-built reports bound to auto-created models. Requires `mongoose` in config.
140
+ * For custom models, use `engine.createReports({ Account, JournalEntry, Budget })`.
141
+ */
142
+ get reports() {
143
+ if (!this._reports) {
144
+ if (!this._models) throw new Error("engine.reports requires a Mongoose connection. Pass `mongoose: connection` in createAccountingEngine config, or use engine.createReports({ Account, JournalEntry }) for manual models.");
145
+ this._reports = this._buildReports({
146
+ Account: this._models.Account,
147
+ JournalEntry: this._models.JournalEntry,
148
+ Budget: this._models.Budget
149
+ });
150
+ }
151
+ return this._reports;
23
152
  }
24
153
  createAccountSchema(options) {
25
154
  return createAccountSchema(this.config, options);
@@ -36,7 +165,15 @@ var AccountingEngine = class {
36
165
  createReconciliationSchema(accountModelName, journalEntryModelName, options) {
37
166
  return createReconciliationSchema(this.config, accountModelName, journalEntryModelName, options);
38
167
  }
168
+ /**
169
+ * Build a reports object bound to the given models. Use this when you
170
+ * need custom/external models. Prefer `engine.reports` when the engine
171
+ * owns the models (via `mongoose` in config).
172
+ */
39
173
  createReports(models) {
174
+ return this._buildReports(models);
175
+ }
176
+ _buildReports(models) {
40
177
  const { Account: AccountModel, JournalEntry: JournalEntryModel, Budget: BudgetModel } = models;
41
178
  const { country, config } = this;
42
179
  const orgField = config.multiTenant?.orgField;
@@ -202,8 +339,8 @@ var AccountingEngine = class {
202
339
  return wireReconciliationMethods(repository, ReconciliationModel, JournalEntryModel, orgField);
203
340
  }
204
341
  };
205
- function createAccountingEngine(config) {
206
- return new AccountingEngine(config);
342
+ function createAccountingEngine(config, plugins = {}) {
343
+ return new AccountingEngine(config, plugins);
207
344
  }
208
345
  //#endregion
209
346
  //#region src/utils/dimensions.ts
@@ -265,4 +402,4 @@ function buildDimensionIndexes(dimensions, orgField) {
265
402
  });
266
403
  }
267
404
  //#endregion
268
- 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, createAccountSchema, createAccountingEngine, createFiscalPeriodSchema, createJournalEntrySchema, dateLockPlugin, defaultLogger, defineCountryPack, doubleEntryPlugin, exportToCsv, finalizeSession, fiscalLockPlugin, flattenJournalEntries, format, formatPlain, fromDecimal, generateAgedBalance, generateBalanceSheet, generateCashFlow, generateDimensionBreakdown, generateGeneralLedger, generateIncomeStatement, generateRevaluation, generateTrialBalance, getCurrency, getDateRange, getFiscalYearStart, getJournalTypeCodes, getMinorUnit, getNormalBalance, idempotencyPlugin, isBalanceSheet, isIncomeStatement, isValidCategory, isValidCurrency, isValidJournalType, isVirtualTaxAccount, multiply, parseCents, percentage, quickbooksFieldMap, reopenFiscalPeriod, splitTaxExclusive, splitTaxInclusive, subtract, toDecimal, universalFieldMap, wireAccountMethods, wireJournalEntryMethods, wireReconciliationMethods };
405
+ 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, createAccountSchema, createAccountingEngine, createFiscalPeriodSchema, createJournalEntrySchema, createModels, createRepositories, dateLockPlugin, defaultLogger, defineCountryPack, doubleEntryPlugin, exportToCsv, finalizeSession, fiscalLockPlugin, flattenJournalEntries, format, formatPlain, fromDecimal, generateAgedBalance, generateBalanceSheet, generateBudgetVsActual, generateCashFlow, generateDimensionBreakdown, generateGeneralLedger, generateIncomeStatement, generateRevaluation, generateTrialBalance, getCurrency, getCustomJournalTypes, getDateRange, getFiscalYearStart, getJournalType, getJournalTypeCodes, getMinorUnit, getNormalBalance, idempotencyPlugin, isBalanceSheet, isIncomeStatement, isValidCategory, isValidCurrency, isValidJournalType, isVirtualTaxAccount, multiply, parseCents, percentage, quickbooksFieldMap, registerJournalType, reopenFiscalPeriod, resolveModelNames, splitTaxExclusive, splitTaxInclusive, subtract, toDecimal, universalFieldMap, wireAccountMethods, wireJournalEntryMethods, wireReconciliationMethods };
@@ -1,4 +1,4 @@
1
- import { o as SchemaOptions, r as JournalSchemaOptions, t as AccountingEngineConfig } from "./engine-Cn-9yerQ.mjs";
1
+ import { r as JournalSchemaOptions, s as SchemaOptions, t as AccountingEngineConfig } from "./engine-scgOvxHJ.mjs";
2
2
  import mongoose from "mongoose";
3
3
 
4
4
  //#region src/schemas/account.schema.d.ts
@@ -12,9 +12,9 @@ declare function createAccountSchema(config: AccountingEngineConfig, options?: S
12
12
  [x: string]: any;
13
13
  } & mongoose.DefaultTimestampProps, {
14
14
  id: string;
15
- }, mongoose.MergeType<mongoose.DefaultSchemaOptions, {
15
+ }, Omit<mongoose.DefaultSchemaOptions, "timestamps"> & {
16
16
  timestamps: true;
17
- }>> & Omit<{
17
+ }> & Omit<{
18
18
  [x: number]: any;
19
19
  [x: string]: any;
20
20
  } & mongoose.DefaultTimestampProps & {
@@ -34,8 +34,8 @@ declare function createAccountSchema(config: AccountingEngineConfig, options?: S
34
34
  __v: number;
35
35
  }>;
36
36
  //#endregion
37
- //#region src/schemas/journal-entry.schema.d.ts
38
- declare function createJournalEntrySchema(config: AccountingEngineConfig, accountModelName: string, options?: JournalSchemaOptions): mongoose.Schema<any, mongoose.Model<any, any, any, any, any, any, any>, {}, {}, {}, {}, {
37
+ //#region src/schemas/fiscal-period.schema.d.ts
38
+ declare function createFiscalPeriodSchema(config: AccountingEngineConfig, options?: SchemaOptions): mongoose.Schema<any, mongoose.Model<any, any, any, any, any, any, any>, {}, {}, {}, {}, {
39
39
  timestamps: true;
40
40
  }, {
41
41
  [x: number]: any;
@@ -45,9 +45,9 @@ declare function createJournalEntrySchema(config: AccountingEngineConfig, accoun
45
45
  [x: string]: any;
46
46
  } & mongoose.DefaultTimestampProps, {
47
47
  id: string;
48
- }, mongoose.MergeType<mongoose.DefaultSchemaOptions, {
48
+ }, Omit<mongoose.DefaultSchemaOptions, "timestamps"> & {
49
49
  timestamps: true;
50
- }>> & Omit<{
50
+ }> & Omit<{
51
51
  [x: number]: any;
52
52
  [x: string]: any;
53
53
  } & mongoose.DefaultTimestampProps & {
@@ -67,8 +67,8 @@ declare function createJournalEntrySchema(config: AccountingEngineConfig, accoun
67
67
  __v: number;
68
68
  }>;
69
69
  //#endregion
70
- //#region src/schemas/fiscal-period.schema.d.ts
71
- declare function createFiscalPeriodSchema(config: AccountingEngineConfig, options?: SchemaOptions): mongoose.Schema<any, mongoose.Model<any, any, any, any, any, any, any>, {}, {}, {}, {}, {
70
+ //#region src/schemas/journal-entry.schema.d.ts
71
+ declare function createJournalEntrySchema(config: AccountingEngineConfig, accountModelName: string, options?: JournalSchemaOptions): mongoose.Schema<any, mongoose.Model<any, any, any, any, any, any, any>, {}, {}, {}, {}, {
72
72
  timestamps: true;
73
73
  }, {
74
74
  [x: number]: any;
@@ -78,9 +78,9 @@ declare function createFiscalPeriodSchema(config: AccountingEngineConfig, option
78
78
  [x: string]: any;
79
79
  } & mongoose.DefaultTimestampProps, {
80
80
  id: string;
81
- }, mongoose.MergeType<mongoose.DefaultSchemaOptions, {
81
+ }, Omit<mongoose.DefaultSchemaOptions, "timestamps"> & {
82
82
  timestamps: true;
83
- }>> & Omit<{
83
+ }> & Omit<{
84
84
  [x: number]: any;
85
85
  [x: string]: any;
86
86
  } & mongoose.DefaultTimestampProps & {
@@ -100,4 +100,4 @@ declare function createFiscalPeriodSchema(config: AccountingEngineConfig, option
100
100
  __v: number;
101
101
  }>;
102
102
  //#endregion
103
- export { createJournalEntrySchema as n, createAccountSchema as r, createFiscalPeriodSchema as t };
103
+ export { createFiscalPeriodSchema as n, createAccountSchema as r, createJournalEntrySchema as t };
@@ -77,14 +77,37 @@ const JOURNAL_TYPES = Object.freeze({
77
77
  }
78
78
  });
79
79
  const JOURNAL_CODES = Object.freeze(Object.fromEntries(Object.keys(JOURNAL_TYPES).map((k) => [k, k])));
80
+ const _customTypes = {};
81
+ let _frozen = false;
82
+ /**
83
+ * Register a custom journal type. Must be called **before** schema
84
+ * initialization (`createJournalEntrySchema`). Custom types are
85
+ * automatically included in Mongoose enum validation and all lookup
86
+ * functions.
87
+ */
88
+ function registerJournalType(code, def) {
89
+ if (_frozen) throw new Error("Cannot register journal types after schema initialization");
90
+ if (code in JOURNAL_TYPES) throw new Error(`Cannot override built-in journal type: ${code}`);
91
+ if (def.code !== code) throw new Error(`Journal type code mismatch: key="${code}" but def.code="${def.code}"`);
92
+ if (!def.name || !def.description) throw new Error(`Journal type "${code}" requires non-empty name and description`);
93
+ _customTypes[code] = def;
94
+ }
95
+ /** Returns all custom (non-built-in) journal types. */
96
+ function getCustomJournalTypes() {
97
+ return Object.values(_customTypes);
98
+ }
99
+ /** @internal Lock the registry — called by `createJournalEntrySchema`. */
100
+ function _freezeJournalTypes() {
101
+ _frozen = true;
102
+ }
80
103
  function getJournalTypeCodes() {
81
- return Object.keys(JOURNAL_TYPES);
104
+ return [...Object.keys(JOURNAL_TYPES), ...Object.keys(_customTypes)];
82
105
  }
83
106
  function isValidJournalType(code) {
84
- return code in JOURNAL_TYPES;
107
+ return code in JOURNAL_TYPES || code in _customTypes;
85
108
  }
86
109
  function getJournalType(code) {
87
- return JOURNAL_TYPES[code] ?? null;
110
+ return JOURNAL_TYPES[code] ?? _customTypes[code] ?? null;
88
111
  }
89
112
  //#endregion
90
- export { isValidJournalType as a, getJournalTypeCodes as i, JOURNAL_TYPES as n, getJournalType as r, JOURNAL_CODES as t };
113
+ export { getJournalType as a, registerJournalType as c, getCustomJournalTypes as i, JOURNAL_TYPES as n, getJournalTypeCodes as o, _freezeJournalTypes as r, isValidJournalType as s, JOURNAL_CODES as t };
@@ -21,17 +21,26 @@ declare function extractMainType(key: string): MainType | null;
21
21
  /** Extract statement type from a category key string */
22
22
  declare function extractStatementType(key: string): StatementType | null;
23
23
  //#endregion
24
+ //#region src/constants/currencies.d.ts
25
+ declare const CURRENCIES: Readonly<Record<string, Currency>>;
26
+ declare function getCurrency(code: string): Currency | null;
27
+ declare function isValidCurrency(code: string): boolean;
28
+ declare function getMinorUnit(code: string): number;
29
+ //#endregion
24
30
  //#region src/constants/journals.d.ts
25
31
  declare const JOURNAL_TYPES: Readonly<Record<string, JournalType>>;
26
32
  declare const JOURNAL_CODES: Readonly<Record<string, string>>;
33
+ /**
34
+ * Register a custom journal type. Must be called **before** schema
35
+ * initialization (`createJournalEntrySchema`). Custom types are
36
+ * automatically included in Mongoose enum validation and all lookup
37
+ * functions.
38
+ */
39
+ declare function registerJournalType(code: string, def: JournalType): void;
40
+ /** Returns all custom (non-built-in) journal types. */
41
+ declare function getCustomJournalTypes(): JournalType[];
27
42
  declare function getJournalTypeCodes(): string[];
28
43
  declare function isValidJournalType(code: string): boolean;
29
44
  declare function getJournalType(code: string): JournalType | null;
30
45
  //#endregion
31
- //#region src/constants/currencies.d.ts
32
- declare const CURRENCIES: Readonly<Record<string, Currency>>;
33
- declare function getCurrency(code: string): Currency | null;
34
- declare function isValidCurrency(code: string): boolean;
35
- declare function getMinorUnit(code: string): number;
36
- //#endregion
37
- export { getNormalBalance as _, JOURNAL_CODES as a, isValidCategory as b, getJournalTypeCodes as c, CATEGORY_KEYS as d, categoryKey as f, getCategoryStatementType as g, getCategoryMainType as h, isValidCurrency as i, isValidJournalType as l, extractStatementType as m, getCurrency as n, JOURNAL_TYPES as o, extractMainType as p, getMinorUnit as r, getJournalType as s, CURRENCIES as t, CATEGORIES as u, isBalanceSheet as v, isIncomeStatement as y };
46
+ export { isValidCategory as S, getCategoryMainType as _, getJournalTypeCodes as a, isBalanceSheet as b, CURRENCIES as c, isValidCurrency as d, CATEGORIES as f, extractStatementType as g, extractMainType as h, getJournalType as i, getCurrency as l, categoryKey as m, JOURNAL_TYPES as n, isValidJournalType as o, CATEGORY_KEYS as p, getCustomJournalTypes as r, registerJournalType as s, JOURNAL_CODES as t, getMinorUnit as u, getCategoryStatementType as v, isIncomeStatement as x, getNormalBalance as y };
package/dist/money.mjs CHANGED
@@ -93,7 +93,7 @@ function allocate(totalCents, ratios) {
93
93
  const ratioSum = ratios.reduce((s, r) => s + r, 0);
94
94
  if (ratioSum === 0) throw new Error("Sum of ratios must be > 0");
95
95
  const allocations = ratios.map((r) => Math.floor(totalCents * r / ratioSum));
96
- let remainder = totalCents - allocations.reduce((s, a) => s + a, 0);
96
+ const remainder = totalCents - allocations.reduce((s, a) => s + a, 0);
97
97
  const fractions = ratios.map((r, i) => ({
98
98
  index: i,
99
99
  frac: totalCents * r / ratioSum - allocations[i]
@@ -166,7 +166,7 @@ function parseCents(input, minorUnit = 2) {
166
166
  if (typeof input === "number") return fromDecimal(input, minorUnit);
167
167
  const cleaned = input.replace(/[$,\s]/g, "");
168
168
  const parsed = parseFloat(cleaned);
169
- if (isNaN(parsed)) throw new Error(`Cannot parse "${input}" as money`);
169
+ if (Number.isNaN(parsed)) throw new Error(`Cannot parse "${input}" as money`);
170
170
  return fromDecimal(parsed, minorUnit);
171
171
  }
172
172
  const Money = {
@@ -1,4 +1,4 @@
1
- import { a as DoubleEntryPluginOptions, c as dateLockPlugin, i as fiscalLockPlugin, n as idempotencyPlugin, o as doubleEntryPlugin, r as FiscalLockPluginOptions, s as DateLockPluginOptions, t as IdempotencyPluginOptions } from "../idempotency.plugin-B_CNsInz.mjs";
1
+ import { a as DoubleEntryPluginOptions, c as dateLockPlugin, i as fiscalLockPlugin, n as idempotencyPlugin, o as doubleEntryPlugin, r as FiscalLockPluginOptions, s as DateLockPluginOptions, t as IdempotencyPluginOptions } from "../idempotency.plugin-zU-GKJ0-.mjs";
2
2
  import { RepositoryInstance } from "@classytic/mongokit";
3
3
 
4
4
  //#region src/utils/tax-hooks.d.ts
@@ -1,4 +1,4 @@
1
- import { i as doubleEntryPlugin, n as idempotencyPlugin, r as fiscalLockPlugin, t as dateLockPlugin } from "../date-lock.plugin-eYAJ9h_u.mjs";
1
+ import { i as doubleEntryPlugin, n as idempotencyPlugin, r as fiscalLockPlugin, t as dateLockPlugin } from "../date-lock.plugin-DL6pe24p.mjs";
2
2
  //#region src/utils/tax-hooks.ts
3
3
  /**
4
4
  * Apply a tax hook to journal items.
@@ -1,5 +1,5 @@
1
1
  import { t as CountryPack } from "./index-CxZqRaOU.mjs";
2
- import { s as StrictnessConfig } from "./engine-Cn-9yerQ.mjs";
2
+ import { c as StrictnessConfig } from "./engine-scgOvxHJ.mjs";
3
3
  import { ClientSession, Model } from "mongoose";
4
4
  import { Repository } from "@classytic/mongokit";
5
5
 
@@ -96,6 +96,18 @@ interface ReconciliationRepository<TDoc = unknown> extends Repository<TDoc> {
96
96
  }): Promise<Record<string, unknown>[]>;
97
97
  }
98
98
  //#endregion
99
+ //#region src/repositories/account.repository.d.ts
100
+ /**
101
+ * Wire seedAccounts, bulkCreate and posting-account validation
102
+ * onto an existing mongokit Repository.
103
+ *
104
+ * @param repository - A mongokit Repository instance (already created)
105
+ * @param AccountModel - The Mongoose model for accounts
106
+ * @param country - The CountryPack for account type lookups
107
+ * @param orgField - The multi-tenant field name (e.g. 'business')
108
+ */
109
+ declare function wireAccountMethods<TDoc = unknown>(repository: Repository<TDoc>, AccountModel: Model<unknown>, country: CountryPack, orgField?: string): AccountRepository<TDoc>;
110
+ //#endregion
99
111
  //#region src/repositories/journal-entry.repository.d.ts
100
112
  /**
101
113
  * Wire post/reverse onto an existing mongokit Repository.
@@ -110,18 +122,6 @@ interface ReconciliationRepository<TDoc = unknown> extends Repository<TDoc> {
110
122
  */
111
123
  declare function wireJournalEntryMethods<TDoc = unknown>(repository: Repository<TDoc>, _JournalEntryModel: unknown, orgField?: string, strictness?: StrictnessConfig): JournalEntryRepository<TDoc>;
112
124
  //#endregion
113
- //#region src/repositories/account.repository.d.ts
114
- /**
115
- * Wire seedAccounts, bulkCreate and posting-account validation
116
- * onto an existing mongokit Repository.
117
- *
118
- * @param repository - A mongokit Repository instance (already created)
119
- * @param AccountModel - The Mongoose model for accounts
120
- * @param country - The CountryPack for account type lookups
121
- * @param orgField - The multi-tenant field name (e.g. 'business')
122
- */
123
- declare function wireAccountMethods<TDoc = unknown>(repository: Repository<TDoc>, AccountModel: Model<unknown>, country: CountryPack, orgField?: string): AccountRepository<TDoc>;
124
- //#endregion
125
125
  //#region src/repositories/reconciliation.repository.d.ts
126
126
  /**
127
127
  * Wire reconciliation methods onto an existing mongokit Repository.
@@ -132,4 +132,4 @@ declare function wireAccountMethods<TDoc = unknown>(repository: Repository<TDoc>
132
132
  */
133
133
  declare function wireReconciliationMethods<TDoc = unknown>(repository: Repository<TDoc>, _ReconciliationModel: Model<unknown>, JournalEntryModel: Model<unknown>, orgField?: string): ReconciliationRepository<TDoc>;
134
134
  //#endregion
135
- export { BulkCreateInput as a, PostOptions as c, ReverseOptions as d, ReverseResult as f, AccountRepository as i, ReconcileParams as l, SeedResult as m, wireAccountMethods as n, BulkCreateResult as o, SeedOptions as p, wireJournalEntryMethods as r, JournalEntryRepository as s, wireReconciliationMethods as t, ReconciliationRepository as u };
135
+ export { BulkCreateInput as a, PostOptions as c, ReverseOptions as d, ReverseResult as f, AccountRepository as i, ReconcileParams as l, SeedResult as m, wireJournalEntryMethods as n, BulkCreateResult as o, SeedOptions as p, wireAccountMethods as r, JournalEntryRepository as s, wireReconciliationMethods as t, ReconciliationRepository as u };