@classytic/ledger 0.2.0 → 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-kDKwDt0I.mjs → account.repository-BpkSd6q3.mjs} +189 -38
- package/dist/categories-CclX7Q94.mjs +0 -2
- package/dist/core-8Xfnpn6g.d.mts +1 -2
- package/dist/country/index.d.mts +1 -1
- package/dist/country/index.mjs +0 -2
- package/dist/currencies-4WAbFRlw.d.mts +1 -2
- package/dist/currencies-W8kQAkm0.mjs +0 -2
- package/dist/{idempotency.plugin-v9NQ_ta-.mjs → date-lock.plugin-eYAJ9h_u.mjs} +49 -9
- package/dist/{engine-BzBMpWuy.d.mts → engine-Cn-9yerQ.d.mts} +11 -7
- package/dist/errors-B7yC-Jfw.mjs +0 -2
- package/dist/exports-I5Xkq-9_.mjs +0 -2
- package/dist/{fiscal-close-L631E3De.mjs → fiscal-close-B6LhQ10f.mjs} +737 -20
- package/dist/fiscal-period.schema-BMnlI9H5.d.mts +103 -0
- package/dist/{idempotency.plugin-CPxPt4vX.d.mts → idempotency.plugin-B_CNsInz.d.mts} +19 -17
- package/dist/index-BPukb3L8.d.mts +1 -2
- package/dist/{index-ZnSiqHYV.d.mts → index-CxZqRaOU.d.mts} +20 -6
- package/dist/index.d.mts +248 -26
- package/dist/index.mjs +119 -21
- package/dist/journals-oH-FK3g8.mjs +0 -2
- package/dist/{logger-UbTdBb1x.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 -2
- package/dist/reconciliation.repository-CW4-8q90.d.mts +135 -0
- package/dist/{fiscal-period.schema-BQ5wsAq3.mjs → reconciliation.schema-BuetvZTd.mjs} +168 -24
- package/dist/reports/index.d.mts +2 -2
- package/dist/reports/index.mjs +2 -2
- package/dist/repositories/index.d.mts +2 -2
- package/dist/repositories/index.mjs +2 -2
- package/dist/revaluation-D9x0NE8w.d.mts +530 -0
- package/dist/schemas/index.d.mts +71 -2
- package/dist/schemas/index.mjs +2 -2
- package/dist/tenant-guard-Fm6AID_6.mjs +13 -0
- package/docs/reports.md +1 -1
- package/package.json +2 -2
- package/dist/account.repository-C7gwFLfM.d.mts +0 -29
- package/dist/account.repository-C7gwFLfM.d.mts.map +0 -1
- package/dist/account.repository-kDKwDt0I.mjs.map +0 -1
- package/dist/categories-CclX7Q94.mjs.map +0 -1
- package/dist/core-8Xfnpn6g.d.mts.map +0 -1
- package/dist/country/index.mjs.map +0 -1
- package/dist/currencies-4WAbFRlw.d.mts.map +0 -1
- package/dist/currencies-W8kQAkm0.mjs.map +0 -1
- package/dist/engine-BzBMpWuy.d.mts.map +0 -1
- package/dist/errors-B7yC-Jfw.mjs.map +0 -1
- package/dist/exports-I5Xkq-9_.mjs.map +0 -1
- package/dist/fiscal-close-L631E3De.mjs.map +0 -1
- package/dist/fiscal-close-dNlzB37y.d.mts +0 -270
- package/dist/fiscal-close-dNlzB37y.d.mts.map +0 -1
- package/dist/fiscal-period.schema-BQ5wsAq3.mjs.map +0 -1
- package/dist/fiscal-period.schema-BRdKAjrr.d.mts +0 -38
- package/dist/fiscal-period.schema-BRdKAjrr.d.mts.map +0 -1
- package/dist/idempotency.plugin-CPxPt4vX.d.mts.map +0 -1
- package/dist/idempotency.plugin-v9NQ_ta-.mjs.map +0 -1
- package/dist/index-BPukb3L8.d.mts.map +0 -1
- package/dist/index-ZnSiqHYV.d.mts.map +0 -1
- package/dist/index.d.mts.map +0 -1
- package/dist/index.mjs.map +0 -1
- package/dist/journals-oH-FK3g8.mjs.map +0 -1
- package/dist/logger-UbTdBb1x.d.mts.map +0 -1
- package/dist/money.d.mts.map +0 -1
- package/dist/money.mjs.map +0 -1
- package/dist/session-Ba8E3Ufa.mjs +0 -84
- package/dist/session-Ba8E3Ufa.mjs.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as createAccountSchema, i as createJournalEntrySchema, n as createBudgetSchema, r as createFiscalPeriodSchema, t as createReconciliationSchema } from "./reconciliation.schema-BuetvZTd.mjs";
|
|
2
2
|
import { a as isValidJournalType, i as getJournalTypeCodes, n as JOURNAL_TYPES, t as JOURNAL_CODES } from "./journals-oH-FK3g8.mjs";
|
|
3
|
-
import { a as
|
|
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
4
|
import { n as Errors, t as AccountingError } from "./errors-B7yC-Jfw.mjs";
|
|
5
|
-
import { n as finalizeSession, r as defaultLogger, t as acquireSession } from "./session-Ba8E3Ufa.mjs";
|
|
6
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 fiscalLockPlugin, r as doubleEntryPlugin, t as idempotencyPlugin } from "./idempotency.plugin-v9NQ_ta-.mjs";
|
|
8
|
+
import { i as doubleEntryPlugin, n as idempotencyPlugin, r as fiscalLockPlugin, t as dateLockPlugin } from "./date-lock.plugin-eYAJ9h_u.mjs";
|
|
10
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
11
|
import { a as exportToCsv, n as quickbooksFieldMap, r as flattenJournalEntries, t as universalFieldMap } from "./exports-I5Xkq-9_.mjs";
|
|
12
|
+
import { Schema } from "mongoose";
|
|
13
13
|
//#region src/engine.ts
|
|
14
14
|
var AccountingEngine = class {
|
|
15
15
|
config;
|
|
@@ -30,12 +30,19 @@ var AccountingEngine = class {
|
|
|
30
30
|
createFiscalPeriodSchema(options) {
|
|
31
31
|
return createFiscalPeriodSchema(this.config, options);
|
|
32
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
|
+
}
|
|
33
39
|
createReports(models) {
|
|
34
|
-
const { Account: AccountModel, JournalEntry: JournalEntryModel } = models;
|
|
40
|
+
const { Account: AccountModel, JournalEntry: JournalEntryModel, Budget: BudgetModel } = models;
|
|
35
41
|
const { country, config } = this;
|
|
36
42
|
const orgField = config.multiTenant?.orgField;
|
|
37
43
|
const fiscalYearStartMonth = config.fiscalYearStartMonth ?? 1;
|
|
38
|
-
const
|
|
44
|
+
const retainedEarningsAccountCode = config.retainedEarningsAccountCode;
|
|
45
|
+
const retainedEarningsDisplayCode = config.retainedEarningsDisplayCode;
|
|
39
46
|
const currentYearEarningsCode = config.currentYearEarningsCode;
|
|
40
47
|
return {
|
|
41
48
|
trialBalance: (params) => generateTrialBalance({
|
|
@@ -51,7 +58,8 @@ var AccountingEngine = class {
|
|
|
51
58
|
country,
|
|
52
59
|
orgField,
|
|
53
60
|
fiscalYearStartMonth,
|
|
54
|
-
|
|
61
|
+
retainedEarningsAccountCode,
|
|
62
|
+
retainedEarningsDisplayCode,
|
|
55
63
|
currentYearEarningsCode
|
|
56
64
|
}, params),
|
|
57
65
|
incomeStatement: (params) => generateIncomeStatement({
|
|
@@ -72,6 +80,35 @@ var AccountingEngine = class {
|
|
|
72
80
|
JournalEntryModel,
|
|
73
81
|
country,
|
|
74
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
|
|
75
112
|
}, params)
|
|
76
113
|
};
|
|
77
114
|
}
|
|
@@ -110,23 +147,22 @@ var AccountingEngine = class {
|
|
|
110
147
|
createJournalEntryRepository(createRepository, models, additionalPlugins = []) {
|
|
111
148
|
const orgField = this.config.multiTenant?.orgField;
|
|
112
149
|
const { JournalEntryModel, AccountModel, FiscalPeriodModel } = models;
|
|
150
|
+
const jeModel = JournalEntryModel;
|
|
113
151
|
const plugins = [...additionalPlugins, doubleEntryPlugin({
|
|
114
|
-
JournalEntryModel,
|
|
152
|
+
JournalEntryModel: jeModel,
|
|
115
153
|
AccountModel,
|
|
116
154
|
orgField
|
|
117
155
|
})];
|
|
118
156
|
if (FiscalPeriodModel) plugins.push(fiscalLockPlugin({
|
|
119
157
|
FiscalPeriodModel,
|
|
120
|
-
JournalEntryModel,
|
|
158
|
+
JournalEntryModel: jeModel,
|
|
121
159
|
orgField
|
|
122
160
|
}));
|
|
123
161
|
if (this.config.idempotency) plugins.push(idempotencyPlugin({
|
|
124
|
-
JournalEntryModel,
|
|
162
|
+
JournalEntryModel: jeModel,
|
|
125
163
|
orgField
|
|
126
164
|
}));
|
|
127
|
-
|
|
128
|
-
wireJournalEntryMethods(repository, JournalEntryModel, orgField, this.config.strictness);
|
|
129
|
-
return repository;
|
|
165
|
+
return wireJournalEntryMethods(createRepository(JournalEntryModel, plugins), JournalEntryModel, orgField, this.config.strictness);
|
|
130
166
|
}
|
|
131
167
|
/**
|
|
132
168
|
* Wire post/reverse domain methods onto a mongokit Repository
|
|
@@ -143,8 +179,7 @@ var AccountingEngine = class {
|
|
|
143
179
|
*/
|
|
144
180
|
wireJournalEntryRepository(repository, JournalEntryModel) {
|
|
145
181
|
const orgField = this.config.multiTenant?.orgField;
|
|
146
|
-
wireJournalEntryMethods(repository, JournalEntryModel, orgField, this.config.strictness);
|
|
147
|
-
return repository;
|
|
182
|
+
return wireJournalEntryMethods(repository, JournalEntryModel, orgField, this.config.strictness);
|
|
148
183
|
}
|
|
149
184
|
/**
|
|
150
185
|
* Wire seedAccounts/bulkCreate and posting-account validation onto a
|
|
@@ -157,14 +192,77 @@ var AccountingEngine = class {
|
|
|
157
192
|
*/
|
|
158
193
|
wireAccountRepository(repository, AccountModel) {
|
|
159
194
|
const orgField = this.config.multiTenant?.orgField;
|
|
160
|
-
wireAccountMethods(repository, AccountModel, this.country, orgField);
|
|
161
|
-
|
|
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);
|
|
162
203
|
}
|
|
163
204
|
};
|
|
164
205
|
function createAccountingEngine(config) {
|
|
165
206
|
return new AccountingEngine(config);
|
|
166
207
|
}
|
|
167
208
|
//#endregion
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
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 };
|
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) {
|
|
@@ -193,5 +195,3 @@ const Money = {
|
|
|
193
195
|
};
|
|
194
196
|
//#endregion
|
|
195
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 };
|
|
196
|
-
|
|
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,2 +1,57 @@
|
|
|
1
|
-
import { n as
|
|
2
|
-
|
|
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 };
|