@classytic/ledger 0.1.5 → 0.3.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/README.md +161 -64
- package/dist/{account.repository-Crf5DGO4.mjs → account.repository-BpkSd6q3.mjs} +190 -41
- package/dist/{categories-BNJBd4ze.mjs → categories-CclX7Q94.mjs} +0 -2
- package/dist/constants/index.d.mts +1 -1
- package/dist/constants/index.mjs +4 -5
- package/dist/{core-Cx0baosR.d.mts → core-8Xfnpn6g.d.mts} +1 -2
- package/dist/country/index.d.mts +2 -105
- package/dist/country/index.mjs +0 -2
- package/dist/{currencies-Bkn3FNkC.d.mts → currencies-4WAbFRlw.d.mts} +2 -3
- package/dist/{currencies-BBk3NwXn.mjs → currencies-W8kQAkm0.mjs} +0 -2
- package/dist/{idempotency.plugin-C6r8RI8d.mjs → date-lock.plugin-eYAJ9h_u.mjs} +50 -13
- package/dist/{engine-Cd73EOT6.d.mts → engine-Cn-9yerQ.d.mts} +38 -8
- package/dist/{errors-CeqRahE-.mjs → errors-B7yC-Jfw.mjs} +0 -2
- package/dist/exports/index.d.mts +2 -2
- package/dist/exports/index.mjs +2 -3
- package/dist/{universal-CMfrZ2hG.mjs → exports-I5Xkq-9_.mjs} +0 -7
- package/dist/{fiscal-close-DuXDgVvb.mjs → fiscal-close-B6LhQ10f.mjs} +742 -32
- package/dist/fiscal-period.schema-BMnlI9H5.d.mts +103 -0
- package/dist/{idempotency.plugin-BESs9YPD.d.mts → idempotency.plugin-B_CNsInz.d.mts} +19 -17
- package/dist/{universal-x33ZJODp.d.mts → index-BPukb3L8.d.mts} +1 -2
- package/dist/index-CxZqRaOU.d.mts +119 -0
- package/dist/index.d.mts +251 -29
- package/dist/index.mjs +124 -27
- package/dist/{journals-CI3Wb4EF.mjs → journals-oH-FK3g8.mjs} +0 -2
- package/dist/{logger-Cv6VVc4r.d.mts → logger-CbHWZl7v.d.mts} +1 -2
- package/dist/money.d.mts +1 -2
- package/dist/money.mjs +3 -3
- package/dist/plugins/index.d.mts +38 -2
- package/dist/plugins/index.mjs +57 -3
- package/dist/reconciliation.repository-CW4-8q90.d.mts +135 -0
- package/dist/{fiscal-period.schema-CbALaaKl.mjs → reconciliation.schema-BuetvZTd.mjs} +218 -30
- package/dist/reports/index.d.mts +2 -2
- package/dist/reports/index.mjs +2 -3
- package/dist/repositories/index.d.mts +2 -2
- package/dist/repositories/index.mjs +2 -3
- package/dist/revaluation-D9x0NE8w.d.mts +530 -0
- package/dist/schemas/index.d.mts +71 -2
- package/dist/schemas/index.mjs +2 -3
- package/dist/tenant-guard-Fm6AID_6.mjs +13 -0
- package/docs/reports.md +1 -1
- package/package.json +3 -3
- package/dist/account.repository-1C2sZvB2.d.mts +0 -29
- package/dist/account.repository-1C2sZvB2.d.mts.map +0 -1
- package/dist/account.repository-Crf5DGO4.mjs.map +0 -1
- package/dist/categories-BNJBd4ze.mjs.map +0 -1
- package/dist/core-Cx0baosR.d.mts.map +0 -1
- package/dist/country/index.d.mts.map +0 -1
- package/dist/country/index.mjs.map +0 -1
- package/dist/currencies-BBk3NwXn.mjs.map +0 -1
- package/dist/currencies-Bkn3FNkC.d.mts.map +0 -1
- package/dist/engine-Cd73EOT6.d.mts.map +0 -1
- package/dist/errors-CeqRahE-.mjs.map +0 -1
- package/dist/fiscal-close-CzUzpnMg.d.mts +0 -270
- package/dist/fiscal-close-CzUzpnMg.d.mts.map +0 -1
- package/dist/fiscal-close-DuXDgVvb.mjs.map +0 -1
- package/dist/fiscal-period.schema-CbALaaKl.mjs.map +0 -1
- package/dist/fiscal-period.schema-DI2scngu.d.mts +0 -38
- package/dist/fiscal-period.schema-DI2scngu.d.mts.map +0 -1
- package/dist/idempotency.plugin-BESs9YPD.d.mts.map +0 -1
- package/dist/idempotency.plugin-C6r8RI8d.mjs.map +0 -1
- package/dist/index.d.mts.map +0 -1
- package/dist/index.mjs.map +0 -1
- package/dist/journals-CI3Wb4EF.mjs.map +0 -1
- package/dist/logger-Cv6VVc4r.d.mts.map +0 -1
- package/dist/money.d.mts.map +0 -1
- package/dist/money.mjs.map +0 -1
- package/dist/session-Dh0s6zG4.mjs +0 -87
- package/dist/session-Dh0s6zG4.mjs.map +0 -1
- package/dist/universal-CMfrZ2hG.mjs.map +0 -1
- package/dist/universal-x33ZJODp.d.mts.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as isValidJournalType, i as getJournalTypeCodes, n as JOURNAL_TYPES, t as JOURNAL_CODES } from "./journals-
|
|
3
|
-
import { a as
|
|
4
|
-
import { n as Errors, t as AccountingError } from "./errors-
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
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";
|
|
7
7
|
import { Money, add, allocate, format, formatPlain, fromDecimal, multiply, parseCents, percentage, splitTaxExclusive, splitTaxInclusive, subtract, toDecimal } from "./money.mjs";
|
|
8
|
-
import { n as
|
|
9
|
-
import { n as
|
|
10
|
-
import { i as isValidCurrency, n as getCurrency, r as getMinorUnit, t as CURRENCIES } from "./currencies-BBk3NwXn.mjs";
|
|
8
|
+
import { i as doubleEntryPlugin, n as idempotencyPlugin, r as fiscalLockPlugin, t as dateLockPlugin } from "./date-lock.plugin-eYAJ9h_u.mjs";
|
|
9
|
+
import { i as isValidCurrency, n as getCurrency, r as getMinorUnit, t as CURRENCIES } from "./currencies-W8kQAkm0.mjs";
|
|
11
10
|
import { defineCountryPack } from "./country/index.mjs";
|
|
12
|
-
import { a as exportToCsv, n as quickbooksFieldMap, r as flattenJournalEntries, t as universalFieldMap } from "./
|
|
13
|
-
|
|
11
|
+
import { a as exportToCsv, n as quickbooksFieldMap, r as flattenJournalEntries, t as universalFieldMap } from "./exports-I5Xkq-9_.mjs";
|
|
12
|
+
import { Schema } from "mongoose";
|
|
14
13
|
//#region src/engine.ts
|
|
15
14
|
var AccountingEngine = class {
|
|
16
15
|
config;
|
|
@@ -31,12 +30,19 @@ var AccountingEngine = class {
|
|
|
31
30
|
createFiscalPeriodSchema(options) {
|
|
32
31
|
return createFiscalPeriodSchema(this.config, options);
|
|
33
32
|
}
|
|
33
|
+
createBudgetSchema(options) {
|
|
34
|
+
return createBudgetSchema(this.config, options);
|
|
35
|
+
}
|
|
36
|
+
createReconciliationSchema(accountModelName, journalEntryModelName, options) {
|
|
37
|
+
return createReconciliationSchema(this.config, accountModelName, journalEntryModelName, options);
|
|
38
|
+
}
|
|
34
39
|
createReports(models) {
|
|
35
|
-
const { Account: AccountModel, JournalEntry: JournalEntryModel } = models;
|
|
40
|
+
const { Account: AccountModel, JournalEntry: JournalEntryModel, Budget: BudgetModel } = models;
|
|
36
41
|
const { country, config } = this;
|
|
37
42
|
const orgField = config.multiTenant?.orgField;
|
|
38
43
|
const fiscalYearStartMonth = config.fiscalYearStartMonth ?? 1;
|
|
39
|
-
const
|
|
44
|
+
const retainedEarningsAccountCode = config.retainedEarningsAccountCode;
|
|
45
|
+
const retainedEarningsDisplayCode = config.retainedEarningsDisplayCode;
|
|
40
46
|
const currentYearEarningsCode = config.currentYearEarningsCode;
|
|
41
47
|
return {
|
|
42
48
|
trialBalance: (params) => generateTrialBalance({
|
|
@@ -52,7 +58,8 @@ var AccountingEngine = class {
|
|
|
52
58
|
country,
|
|
53
59
|
orgField,
|
|
54
60
|
fiscalYearStartMonth,
|
|
55
|
-
|
|
61
|
+
retainedEarningsAccountCode,
|
|
62
|
+
retainedEarningsDisplayCode,
|
|
56
63
|
currentYearEarningsCode
|
|
57
64
|
}, params),
|
|
58
65
|
incomeStatement: (params) => generateIncomeStatement({
|
|
@@ -73,6 +80,35 @@ var AccountingEngine = class {
|
|
|
73
80
|
JournalEntryModel,
|
|
74
81
|
country,
|
|
75
82
|
orgField
|
|
83
|
+
}, params),
|
|
84
|
+
agedBalance: (params) => generateAgedBalance({
|
|
85
|
+
AccountModel,
|
|
86
|
+
JournalEntryModel,
|
|
87
|
+
country,
|
|
88
|
+
orgField
|
|
89
|
+
}, params),
|
|
90
|
+
dimensionBreakdown: (params) => generateDimensionBreakdown({
|
|
91
|
+
AccountModel,
|
|
92
|
+
JournalEntryModel,
|
|
93
|
+
country,
|
|
94
|
+
orgField
|
|
95
|
+
}, params),
|
|
96
|
+
budgetVsActual: (params) => {
|
|
97
|
+
if (!BudgetModel) throw new Error("Budget model required — pass Budget to createReports()");
|
|
98
|
+
return generateBudgetVsActual({
|
|
99
|
+
AccountModel,
|
|
100
|
+
JournalEntryModel,
|
|
101
|
+
BudgetModel,
|
|
102
|
+
country,
|
|
103
|
+
orgField
|
|
104
|
+
}, params);
|
|
105
|
+
},
|
|
106
|
+
revaluation: (params) => generateRevaluation({
|
|
107
|
+
AccountModel,
|
|
108
|
+
JournalEntryModel,
|
|
109
|
+
country,
|
|
110
|
+
orgField,
|
|
111
|
+
baseCurrency: this.currency
|
|
76
112
|
}, params)
|
|
77
113
|
};
|
|
78
114
|
}
|
|
@@ -111,23 +147,22 @@ var AccountingEngine = class {
|
|
|
111
147
|
createJournalEntryRepository(createRepository, models, additionalPlugins = []) {
|
|
112
148
|
const orgField = this.config.multiTenant?.orgField;
|
|
113
149
|
const { JournalEntryModel, AccountModel, FiscalPeriodModel } = models;
|
|
150
|
+
const jeModel = JournalEntryModel;
|
|
114
151
|
const plugins = [...additionalPlugins, doubleEntryPlugin({
|
|
115
|
-
JournalEntryModel,
|
|
152
|
+
JournalEntryModel: jeModel,
|
|
116
153
|
AccountModel,
|
|
117
154
|
orgField
|
|
118
155
|
})];
|
|
119
156
|
if (FiscalPeriodModel) plugins.push(fiscalLockPlugin({
|
|
120
157
|
FiscalPeriodModel,
|
|
121
|
-
JournalEntryModel,
|
|
158
|
+
JournalEntryModel: jeModel,
|
|
122
159
|
orgField
|
|
123
160
|
}));
|
|
124
161
|
if (this.config.idempotency) plugins.push(idempotencyPlugin({
|
|
125
|
-
JournalEntryModel,
|
|
162
|
+
JournalEntryModel: jeModel,
|
|
126
163
|
orgField
|
|
127
164
|
}));
|
|
128
|
-
|
|
129
|
-
wireJournalEntryMethods(repository, JournalEntryModel, orgField, this.config.strictness);
|
|
130
|
-
return repository;
|
|
165
|
+
return wireJournalEntryMethods(createRepository(JournalEntryModel, plugins), JournalEntryModel, orgField, this.config.strictness);
|
|
131
166
|
}
|
|
132
167
|
/**
|
|
133
168
|
* Wire post/reverse domain methods onto a mongokit Repository
|
|
@@ -144,8 +179,7 @@ var AccountingEngine = class {
|
|
|
144
179
|
*/
|
|
145
180
|
wireJournalEntryRepository(repository, JournalEntryModel) {
|
|
146
181
|
const orgField = this.config.multiTenant?.orgField;
|
|
147
|
-
wireJournalEntryMethods(repository, JournalEntryModel, orgField, this.config.strictness);
|
|
148
|
-
return repository;
|
|
182
|
+
return wireJournalEntryMethods(repository, JournalEntryModel, orgField, this.config.strictness);
|
|
149
183
|
}
|
|
150
184
|
/**
|
|
151
185
|
* Wire seedAccounts/bulkCreate and posting-account validation onto a
|
|
@@ -158,14 +192,77 @@ var AccountingEngine = class {
|
|
|
158
192
|
*/
|
|
159
193
|
wireAccountRepository(repository, AccountModel) {
|
|
160
194
|
const orgField = this.config.multiTenant?.orgField;
|
|
161
|
-
wireAccountMethods(repository, AccountModel, this.country, orgField);
|
|
162
|
-
|
|
195
|
+
return wireAccountMethods(repository, AccountModel, this.country, orgField);
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Wire reconcile/unreconcile/getUnreconciled methods onto a mongokit Repository.
|
|
199
|
+
*/
|
|
200
|
+
wireReconciliationRepository(repository, ReconciliationModel, JournalEntryModel) {
|
|
201
|
+
const orgField = this.config.multiTenant?.orgField;
|
|
202
|
+
return wireReconciliationMethods(repository, ReconciliationModel, JournalEntryModel, orgField);
|
|
163
203
|
}
|
|
164
204
|
};
|
|
165
205
|
function createAccountingEngine(config) {
|
|
166
206
|
return new AccountingEngine(config);
|
|
167
207
|
}
|
|
168
|
-
|
|
169
208
|
//#endregion
|
|
170
|
-
|
|
171
|
-
|
|
209
|
+
//#region src/utils/dimensions.ts
|
|
210
|
+
/**
|
|
211
|
+
* Analytic Dimensions — Helpers for defining analytic dimensions
|
|
212
|
+
* (department, project, cost center) on journal items.
|
|
213
|
+
*
|
|
214
|
+
* Generates Mongoose schema fields and indexes for dimension queries.
|
|
215
|
+
*/
|
|
216
|
+
/**
|
|
217
|
+
* Build extraItemFields schema definition for a set of dimensions.
|
|
218
|
+
*
|
|
219
|
+
* Returns a Mongoose schema-compatible object suitable for spreading into
|
|
220
|
+
* `extraItemFields` in JournalSchemaOptions.
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* ```typescript
|
|
224
|
+
* const fields = buildDimensionFields([
|
|
225
|
+
* { field: 'departmentId', label: 'Department', ref: 'Department' },
|
|
226
|
+
* { field: 'projectId', label: 'Project', ref: 'Project' },
|
|
227
|
+
* ]);
|
|
228
|
+
* // => { departmentId: { type: Schema.Types.ObjectId, ref: 'Department', required: false, default: null }, ... }
|
|
229
|
+
* ```
|
|
230
|
+
*/
|
|
231
|
+
function buildDimensionFields(dimensions) {
|
|
232
|
+
const fields = {};
|
|
233
|
+
for (const dim of dimensions) {
|
|
234
|
+
const fieldDef = {
|
|
235
|
+
type: Schema.Types.ObjectId,
|
|
236
|
+
required: dim.required ?? false,
|
|
237
|
+
default: null
|
|
238
|
+
};
|
|
239
|
+
if (dim.ref) fieldDef.ref = dim.ref;
|
|
240
|
+
fields[dim.field] = fieldDef;
|
|
241
|
+
}
|
|
242
|
+
return fields;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Build extra indexes for dimension queries.
|
|
246
|
+
*
|
|
247
|
+
* Each dimension gets a compound index on `journalItems.{field}` + `date`
|
|
248
|
+
* for efficient filtered reporting. When `orgField` is provided, it is
|
|
249
|
+
* prepended to each index for multi-tenant scoping.
|
|
250
|
+
*
|
|
251
|
+
* @param dimensions - Array of dimension definitions
|
|
252
|
+
* @param orgField - Optional org-scoping field name (e.g. 'business')
|
|
253
|
+
* @returns Array of index specifications compatible with `extraIndexes` in JournalSchemaOptions
|
|
254
|
+
*/
|
|
255
|
+
function buildDimensionIndexes(dimensions, orgField) {
|
|
256
|
+
return dimensions.map((dim) => {
|
|
257
|
+
const fields = {};
|
|
258
|
+
if (orgField) fields[orgField] = 1;
|
|
259
|
+
fields[`journalItems.${dim.field}`] = 1;
|
|
260
|
+
fields.date = -1;
|
|
261
|
+
return {
|
|
262
|
+
fields,
|
|
263
|
+
options: {}
|
|
264
|
+
};
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
//#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 };
|
|
@@ -86,7 +86,5 @@ function isValidJournalType(code) {
|
|
|
86
86
|
function getJournalType(code) {
|
|
87
87
|
return JOURNAL_TYPES[code] ?? null;
|
|
88
88
|
}
|
|
89
|
-
|
|
90
89
|
//#endregion
|
|
91
90
|
export { isValidJournalType as a, getJournalTypeCodes as i, JOURNAL_TYPES as n, getJournalType as r, JOURNAL_CODES as t };
|
|
92
|
-
//# sourceMappingURL=journals-CI3Wb4EF.mjs.map
|
package/dist/money.d.mts
CHANGED
|
@@ -125,5 +125,4 @@ declare const Money: {
|
|
|
125
125
|
readonly parseCents: typeof parseCents;
|
|
126
126
|
};
|
|
127
127
|
//#endregion
|
|
128
|
-
export { Money, abs, add, allocate, equals, format, formatPlain, fromDecimal, isNegative, isPositive, isValid, isZero, max, min, multiply, negate, parseCents, percentage, round, splitTaxExclusive, splitTaxInclusive, subtract, toDecimal };
|
|
129
|
-
//# sourceMappingURL=money.d.mts.map
|
|
128
|
+
export { Money, abs, add, allocate, equals, format, formatPlain, fromDecimal, isNegative, isPositive, isValid, isZero, max, min, multiply, negate, parseCents, percentage, round, splitTaxExclusive, splitTaxInclusive, subtract, toDecimal };
|
package/dist/money.mjs
CHANGED
|
@@ -30,7 +30,9 @@ function round(amount) {
|
|
|
30
30
|
/** Convert a decimal dollar amount to integer cents: 10.50 → 1050 */
|
|
31
31
|
function fromDecimal(dollars, minorUnit = 2) {
|
|
32
32
|
const factor = 10 ** minorUnit;
|
|
33
|
-
|
|
33
|
+
const cents = Math.round(dollars * factor);
|
|
34
|
+
if (!Number.isSafeInteger(cents)) throw new Error(`Amount ${dollars} exceeds safe integer limit when converted to minor units. Max safe amount: ${Number.MAX_SAFE_INTEGER / factor}`);
|
|
35
|
+
return cents;
|
|
34
36
|
}
|
|
35
37
|
/** Convert integer cents to a decimal dollar amount: 1050 → 10.50 */
|
|
36
38
|
function toDecimal(cents, minorUnit = 2) {
|
|
@@ -191,7 +193,5 @@ const Money = {
|
|
|
191
193
|
isValid,
|
|
192
194
|
parseCents
|
|
193
195
|
};
|
|
194
|
-
|
|
195
196
|
//#endregion
|
|
196
197
|
export { Money, abs, add, allocate, equals, format, formatPlain, fromDecimal, isNegative, isPositive, isValid, isZero, max, min, multiply, negate, parseCents, percentage, round, splitTaxExclusive, splitTaxInclusive, subtract, toDecimal };
|
|
197
|
-
//# sourceMappingURL=money.mjs.map
|
package/dist/plugins/index.d.mts
CHANGED
|
@@ -1,2 +1,38 @@
|
|
|
1
|
-
import { a as DoubleEntryPluginOptions, i as fiscalLockPlugin, n as idempotencyPlugin, o as doubleEntryPlugin, r as FiscalLockPluginOptions, t as IdempotencyPluginOptions } from "../idempotency.plugin-
|
|
2
|
-
|
|
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";
|
|
2
|
+
import { RepositoryInstance } from "@classytic/mongokit";
|
|
3
|
+
|
|
4
|
+
//#region src/utils/tax-hooks.d.ts
|
|
5
|
+
interface TaxLineInput {
|
|
6
|
+
account: unknown;
|
|
7
|
+
amount: number;
|
|
8
|
+
side: 'debit' | 'credit';
|
|
9
|
+
taxCode?: string;
|
|
10
|
+
extraFields?: Record<string, unknown>;
|
|
11
|
+
}
|
|
12
|
+
interface GeneratedTaxLine {
|
|
13
|
+
account: unknown;
|
|
14
|
+
debit: number;
|
|
15
|
+
credit: number;
|
|
16
|
+
label?: string;
|
|
17
|
+
taxDetails?: Array<{
|
|
18
|
+
taxCode: string;
|
|
19
|
+
taxName?: string;
|
|
20
|
+
}>;
|
|
21
|
+
}
|
|
22
|
+
interface TaxLineGenerator {
|
|
23
|
+
generateTaxLines(input: TaxLineInput): GeneratedTaxLine[];
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
//#region src/plugins/tax-hook.plugin.d.ts
|
|
27
|
+
interface TaxHookPluginOptions {
|
|
28
|
+
/** Tax line generator — implements the tax calculation logic */
|
|
29
|
+
generator: TaxLineGenerator;
|
|
30
|
+
/** Only apply tax hooks on posted entries (default: true) */
|
|
31
|
+
onlyOnPost?: boolean;
|
|
32
|
+
}
|
|
33
|
+
declare function taxHookPlugin(options: TaxHookPluginOptions): {
|
|
34
|
+
name: string;
|
|
35
|
+
apply(repo: RepositoryInstance): void;
|
|
36
|
+
};
|
|
37
|
+
//#endregion
|
|
38
|
+
export { type DateLockPluginOptions, type DoubleEntryPluginOptions, type FiscalLockPluginOptions, type IdempotencyPluginOptions, type TaxHookPluginOptions, dateLockPlugin, doubleEntryPlugin, fiscalLockPlugin, idempotencyPlugin, taxHookPlugin };
|
package/dist/plugins/index.mjs
CHANGED
|
@@ -1,3 +1,57 @@
|
|
|
1
|
-
import { n as
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { i as doubleEntryPlugin, n as idempotencyPlugin, r as fiscalLockPlugin, t as dateLockPlugin } from "../date-lock.plugin-eYAJ9h_u.mjs";
|
|
2
|
+
//#region src/utils/tax-hooks.ts
|
|
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 { dateLockPlugin, doubleEntryPlugin, fiscalLockPlugin, idempotencyPlugin, taxHookPlugin };
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { t as CountryPack } from "./index-CxZqRaOU.mjs";
|
|
2
|
+
import { s as StrictnessConfig } from "./engine-Cn-9yerQ.mjs";
|
|
3
|
+
import { ClientSession, Model } from "mongoose";
|
|
4
|
+
import { Repository } from "@classytic/mongokit";
|
|
5
|
+
|
|
6
|
+
//#region src/types/repositories.d.ts
|
|
7
|
+
interface PostOptions {
|
|
8
|
+
session?: ClientSession | null;
|
|
9
|
+
/** Actor performing this operation (required when strictness.requireActor is enabled) */
|
|
10
|
+
actorId?: unknown;
|
|
11
|
+
}
|
|
12
|
+
interface ReverseOptions extends PostOptions {
|
|
13
|
+
/** Date for the reversal entry (defaults to now) */
|
|
14
|
+
reversalDate?: Date;
|
|
15
|
+
}
|
|
16
|
+
interface SeedOptions {
|
|
17
|
+
session?: ClientSession | null;
|
|
18
|
+
}
|
|
19
|
+
interface SeedResult {
|
|
20
|
+
created: number;
|
|
21
|
+
skipped: number;
|
|
22
|
+
}
|
|
23
|
+
interface BulkCreateInput {
|
|
24
|
+
accountTypeCode?: string;
|
|
25
|
+
accountNumber?: string;
|
|
26
|
+
name?: string;
|
|
27
|
+
active?: boolean;
|
|
28
|
+
isCashAccount?: boolean;
|
|
29
|
+
}
|
|
30
|
+
interface BulkCreateResult {
|
|
31
|
+
summary: {
|
|
32
|
+
total: number;
|
|
33
|
+
created: number;
|
|
34
|
+
skipped: number;
|
|
35
|
+
errors: number;
|
|
36
|
+
};
|
|
37
|
+
created: Array<Record<string, unknown>>;
|
|
38
|
+
skipped: Array<Record<string, unknown>>;
|
|
39
|
+
errors: Array<Record<string, unknown>>;
|
|
40
|
+
}
|
|
41
|
+
interface ReverseResult {
|
|
42
|
+
original: Record<string, unknown>;
|
|
43
|
+
reversal: Record<string, unknown>;
|
|
44
|
+
}
|
|
45
|
+
interface ReconcileParams {
|
|
46
|
+
accountId: unknown;
|
|
47
|
+
journalEntryIds: unknown[];
|
|
48
|
+
organizationId?: unknown;
|
|
49
|
+
note?: string;
|
|
50
|
+
session?: ClientSession;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Journal Entry Repository — extends mongokit Repository with accounting domain methods.
|
|
54
|
+
*
|
|
55
|
+
* Inherits ALL Repository<TDoc> methods: create, getById, getAll, update,
|
|
56
|
+
* delete, count, exists, distinct, aggregate, withTransaction, etc.
|
|
57
|
+
*/
|
|
58
|
+
interface JournalEntryRepository<TDoc = unknown> extends Repository<TDoc> {
|
|
59
|
+
/** Post an entry (draft → posted). Validates items, balance, and accounts. */
|
|
60
|
+
post(id: unknown, orgId?: unknown, options?: PostOptions): Promise<Record<string, unknown>>;
|
|
61
|
+
/** Unpost an entry (posted → draft). Resets state for re-editing. */
|
|
62
|
+
unpost(id: unknown, orgId?: unknown, options?: PostOptions): Promise<Record<string, unknown>>;
|
|
63
|
+
/** Archive a draft entry (draft → archived). Preserves audit trail. */
|
|
64
|
+
archive(id: unknown, orgId?: unknown, options?: PostOptions): Promise<Record<string, unknown>>;
|
|
65
|
+
/** Duplicate an entry as a new draft. Copies items, type, and label. */
|
|
66
|
+
duplicate(id: unknown, orgId?: unknown, options?: PostOptions): Promise<Record<string, unknown>>;
|
|
67
|
+
/** Reverse a posted entry. Creates mirror entry with flipped debits/credits. */
|
|
68
|
+
reverse(id: unknown, orgId?: unknown, options?: ReverseOptions): Promise<ReverseResult>;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Account Repository — extends mongokit Repository with seed and bulk operations.
|
|
72
|
+
*/
|
|
73
|
+
interface AccountRepository<TDoc = unknown> extends Repository<TDoc> {
|
|
74
|
+
/** Seed standard posting accounts for an org from the country pack. */
|
|
75
|
+
seedAccounts(orgId: unknown, options?: SeedOptions): Promise<SeedResult>;
|
|
76
|
+
/** Bulk create accounts with validation and skip-if-exists logic. */
|
|
77
|
+
bulkCreate(accounts: BulkCreateInput[], orgId: unknown): Promise<BulkCreateResult>;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Reconciliation Repository — extends mongokit Repository with bank reconciliation methods.
|
|
81
|
+
*/
|
|
82
|
+
interface ReconciliationRepository<TDoc = unknown> extends Repository<TDoc> {
|
|
83
|
+
/** Reconcile journal entries for a specific account. */
|
|
84
|
+
reconcile(params: ReconcileParams): Promise<Record<string, unknown>>;
|
|
85
|
+
/** Remove a reconciliation record. */
|
|
86
|
+
unreconcile(params: {
|
|
87
|
+
reconciliationId: unknown;
|
|
88
|
+
organizationId?: unknown;
|
|
89
|
+
}): Promise<{
|
|
90
|
+
success: boolean;
|
|
91
|
+
}>;
|
|
92
|
+
/** Get unreconciled journal entries for an account. */
|
|
93
|
+
getUnreconciled(params: {
|
|
94
|
+
accountId: unknown;
|
|
95
|
+
organizationId?: unknown;
|
|
96
|
+
}): Promise<Record<string, unknown>[]>;
|
|
97
|
+
}
|
|
98
|
+
//#endregion
|
|
99
|
+
//#region src/repositories/journal-entry.repository.d.ts
|
|
100
|
+
/**
|
|
101
|
+
* Wire post/reverse onto an existing mongokit Repository.
|
|
102
|
+
*
|
|
103
|
+
* All reads use `repository.getByQuery()` so registered plugins
|
|
104
|
+
* (multi-tenant, audit, cache) fire on every operation.
|
|
105
|
+
*
|
|
106
|
+
* @param repository - A mongokit Repository instance (already created)
|
|
107
|
+
* @param _JournalEntryModel - (Deprecated) The Mongoose model — no longer used internally; kept for API compat
|
|
108
|
+
* @param orgField - The multi-tenant field name (e.g. 'business')
|
|
109
|
+
* @param strictness - Strictness rules (immutable, requireActor, requireApproval)
|
|
110
|
+
*/
|
|
111
|
+
declare function wireJournalEntryMethods<TDoc = unknown>(repository: Repository<TDoc>, _JournalEntryModel: unknown, orgField?: string, strictness?: StrictnessConfig): JournalEntryRepository<TDoc>;
|
|
112
|
+
//#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
|
+
//#region src/repositories/reconciliation.repository.d.ts
|
|
126
|
+
/**
|
|
127
|
+
* Wire reconciliation methods onto an existing mongokit Repository.
|
|
128
|
+
*
|
|
129
|
+
* - reconcile() uses repository.create() so hooks (multi-tenant, audit) fire
|
|
130
|
+
* - unreconcile() uses repository.delete() so hooks fire
|
|
131
|
+
* - Cross-repo reads (JournalEntryModel) use direct Model access (acceptable)
|
|
132
|
+
*/
|
|
133
|
+
declare function wireReconciliationMethods<TDoc = unknown>(repository: Repository<TDoc>, _ReconciliationModel: Model<unknown>, JournalEntryModel: Model<unknown>, orgField?: string): ReconciliationRepository<TDoc>;
|
|
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 };
|