@classytic/ledger 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +108 -0
- package/dist/account.repository-1C2sZvB2.d.mts +29 -0
- package/dist/account.repository-1C2sZvB2.d.mts.map +1 -0
- package/dist/account.repository-Crf5DGO4.mjs +393 -0
- package/dist/account.repository-Crf5DGO4.mjs.map +1 -0
- package/dist/categories-BNJBd4ze.mjs +70 -0
- package/dist/categories-BNJBd4ze.mjs.map +1 -0
- package/dist/constants/index.d.mts +2 -0
- package/dist/constants/index.mjs +5 -0
- package/dist/core-Cx0baosR.d.mts +104 -0
- package/dist/core-Cx0baosR.d.mts.map +1 -0
- package/dist/country/index.d.mts +105 -0
- package/dist/country/index.d.mts.map +1 -0
- package/dist/country/index.mjs +27 -0
- package/dist/country/index.mjs.map +1 -0
- package/dist/currencies-BBk3NwXn.mjs +82 -0
- package/dist/currencies-BBk3NwXn.mjs.map +1 -0
- package/dist/currencies-Bkn3FNkC.d.mts +38 -0
- package/dist/currencies-Bkn3FNkC.d.mts.map +1 -0
- package/dist/engine-Cd73EOT6.d.mts +72 -0
- package/dist/engine-Cd73EOT6.d.mts.map +1 -0
- package/dist/errors-CeqRahE-.mjs +28 -0
- package/dist/errors-CeqRahE-.mjs.map +1 -0
- package/dist/exports/index.d.mts +2 -0
- package/dist/exports/index.mjs +3 -0
- package/dist/fiscal-close-CNOwv_ud.mjs +934 -0
- package/dist/fiscal-close-CNOwv_ud.mjs.map +1 -0
- package/dist/fiscal-close-CzUzpnMg.d.mts +270 -0
- package/dist/fiscal-close-CzUzpnMg.d.mts.map +1 -0
- package/dist/fiscal-period.schema-CbALaaKl.mjs +477 -0
- package/dist/fiscal-period.schema-CbALaaKl.mjs.map +1 -0
- package/dist/fiscal-period.schema-DI2scngu.d.mts +38 -0
- package/dist/fiscal-period.schema-DI2scngu.d.mts.map +1 -0
- package/dist/idempotency.plugin-BESs9YPD.d.mts +58 -0
- package/dist/idempotency.plugin-BESs9YPD.d.mts.map +1 -0
- package/dist/idempotency.plugin-C6r8RI8d.mjs +165 -0
- package/dist/idempotency.plugin-C6r8RI8d.mjs.map +1 -0
- package/dist/index.d.mts +308 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +171 -0
- package/dist/index.mjs.map +1 -0
- package/dist/journals-CI3Wb4EF.mjs +92 -0
- package/dist/journals-CI3Wb4EF.mjs.map +1 -0
- package/dist/logger-Cv6VVc4r.d.mts +15 -0
- package/dist/logger-Cv6VVc4r.d.mts.map +1 -0
- package/dist/money.d.mts +129 -0
- package/dist/money.d.mts.map +1 -0
- package/dist/money.mjs +197 -0
- package/dist/money.mjs.map +1 -0
- package/dist/plugins/index.d.mts +2 -0
- package/dist/plugins/index.mjs +3 -0
- package/dist/reports/index.d.mts +2 -0
- package/dist/reports/index.mjs +3 -0
- package/dist/repositories/index.d.mts +2 -0
- package/dist/repositories/index.mjs +3 -0
- package/dist/schemas/index.d.mts +2 -0
- package/dist/schemas/index.mjs +3 -0
- package/dist/session-Dh0s6zG4.mjs +87 -0
- package/dist/session-Dh0s6zG4.mjs.map +1 -0
- package/dist/universal-CMfrZ2hG.mjs +257 -0
- package/dist/universal-CMfrZ2hG.mjs.map +1 -0
- package/dist/universal-x33ZJODp.d.mts +137 -0
- package/dist/universal-x33ZJODp.d.mts.map +1 -0
- package/docs/country-packs.md +117 -0
- package/docs/engine.md +147 -0
- package/docs/exports.md +81 -0
- package/docs/money.md +81 -0
- package/docs/plugins.md +136 -0
- package/docs/reports.md +154 -0
- package/docs/repositories.md +239 -0
- package/docs/schemas.md +146 -0
- package/docs/subledger-integration.md +287 -0
- package/package.json +116 -0
|
@@ -0,0 +1,477 @@
|
|
|
1
|
+
import { i as getJournalTypeCodes, t as JOURNAL_CODES } from "./journals-CI3Wb4EF.mjs";
|
|
2
|
+
import mongoose from "mongoose";
|
|
3
|
+
|
|
4
|
+
//#region src/schemas/account.schema.ts
|
|
5
|
+
/**
|
|
6
|
+
* Account Schema Factory
|
|
7
|
+
*
|
|
8
|
+
* Creates a Mongoose schema for Chart of Accounts that is:
|
|
9
|
+
* - Multi-tenant aware (adds org field + compound indexes when configured)
|
|
10
|
+
* - Validates accountTypeCode against the country pack
|
|
11
|
+
* - Supports accountNumber (unique per org) and name (user-facing display)
|
|
12
|
+
* - Lean: no cached balances — always computed from journal entries
|
|
13
|
+
*/
|
|
14
|
+
function createAccountSchema(config, options = {}) {
|
|
15
|
+
const { multiTenant, country } = config;
|
|
16
|
+
const { indexes = true, extraFields = {}, extraIndexes = [] } = options;
|
|
17
|
+
const fields = {
|
|
18
|
+
accountTypeCode: {
|
|
19
|
+
type: String,
|
|
20
|
+
required: true,
|
|
21
|
+
validate: {
|
|
22
|
+
validator: (code) => country.isValidAccountType(code),
|
|
23
|
+
message: (props) => `"${props.value}" is not a valid account type code for ${country.name}.`
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
accountNumber: {
|
|
27
|
+
type: String,
|
|
28
|
+
required: true,
|
|
29
|
+
trim: true
|
|
30
|
+
},
|
|
31
|
+
name: {
|
|
32
|
+
type: String,
|
|
33
|
+
required: true,
|
|
34
|
+
trim: true
|
|
35
|
+
},
|
|
36
|
+
active: {
|
|
37
|
+
type: Boolean,
|
|
38
|
+
default: true
|
|
39
|
+
},
|
|
40
|
+
isCashAccount: {
|
|
41
|
+
type: Boolean,
|
|
42
|
+
default: false
|
|
43
|
+
},
|
|
44
|
+
...extraFields
|
|
45
|
+
};
|
|
46
|
+
if (multiTenant) fields[multiTenant.orgField] = {
|
|
47
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
48
|
+
ref: multiTenant.orgRef,
|
|
49
|
+
required: true
|
|
50
|
+
};
|
|
51
|
+
const schema = new mongoose.Schema(fields, { timestamps: true });
|
|
52
|
+
schema.pre("validate", function() {
|
|
53
|
+
const doc = this;
|
|
54
|
+
if (!doc.accountNumber && doc.accountTypeCode) doc.accountNumber = doc.accountTypeCode;
|
|
55
|
+
if (!doc.name && doc.accountTypeCode) doc.name = country.getAccountType(doc.accountTypeCode)?.name ?? doc.accountTypeCode;
|
|
56
|
+
});
|
|
57
|
+
if (indexes) if (multiTenant) {
|
|
58
|
+
const org = multiTenant.orgField;
|
|
59
|
+
schema.index({
|
|
60
|
+
[org]: 1,
|
|
61
|
+
active: 1
|
|
62
|
+
});
|
|
63
|
+
schema.index({
|
|
64
|
+
[org]: 1,
|
|
65
|
+
accountNumber: 1
|
|
66
|
+
}, { unique: true });
|
|
67
|
+
schema.index({
|
|
68
|
+
[org]: 1,
|
|
69
|
+
accountTypeCode: 1
|
|
70
|
+
});
|
|
71
|
+
} else {
|
|
72
|
+
schema.index({ active: 1 });
|
|
73
|
+
schema.index({ accountNumber: 1 }, { unique: true });
|
|
74
|
+
schema.index({ accountTypeCode: 1 });
|
|
75
|
+
}
|
|
76
|
+
for (const idx of extraIndexes) schema.index(idx.fields, idx.options);
|
|
77
|
+
return schema;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
//#endregion
|
|
81
|
+
//#region src/schemas/journal-entry.schema.ts
|
|
82
|
+
/**
|
|
83
|
+
* Journal Entry Schema Factory
|
|
84
|
+
*
|
|
85
|
+
* Creates a Mongoose schema for double-entry journal entries.
|
|
86
|
+
* - Multi-tenant aware
|
|
87
|
+
* - Embedded journal items with account refs
|
|
88
|
+
* - State machine: draft → posted, draft → archived
|
|
89
|
+
* - Auto-generated reference numbers
|
|
90
|
+
* - Double-entry validation on post
|
|
91
|
+
* - Optimized indexes for high-load reporting
|
|
92
|
+
*/
|
|
93
|
+
function createJournalEntrySchema(config, accountModelName, options = {}) {
|
|
94
|
+
const { multiTenant } = config;
|
|
95
|
+
const { indexes = true, autoReference = true, textSearch = true, extraFields = {}, extraIndexes = [], extraItemFields = {} } = options;
|
|
96
|
+
const TaxDetailSchema = new mongoose.Schema({
|
|
97
|
+
taxCode: { type: String },
|
|
98
|
+
taxName: { type: String }
|
|
99
|
+
}, { _id: false });
|
|
100
|
+
const amountValidator = {
|
|
101
|
+
validator: (v) => Number.isInteger(v) && v >= 0,
|
|
102
|
+
message: "{PATH} must be a non-negative integer (cents), got {VALUE}"
|
|
103
|
+
};
|
|
104
|
+
const JournalItemSchema = new mongoose.Schema({
|
|
105
|
+
account: {
|
|
106
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
107
|
+
ref: accountModelName,
|
|
108
|
+
required: true
|
|
109
|
+
},
|
|
110
|
+
label: { type: String },
|
|
111
|
+
date: { type: Date },
|
|
112
|
+
debit: {
|
|
113
|
+
type: Number,
|
|
114
|
+
default: 0,
|
|
115
|
+
min: 0,
|
|
116
|
+
validate: amountValidator
|
|
117
|
+
},
|
|
118
|
+
credit: {
|
|
119
|
+
type: Number,
|
|
120
|
+
default: 0,
|
|
121
|
+
min: 0,
|
|
122
|
+
validate: amountValidator
|
|
123
|
+
},
|
|
124
|
+
taxDetails: {
|
|
125
|
+
type: [TaxDetailSchema],
|
|
126
|
+
default: []
|
|
127
|
+
},
|
|
128
|
+
...extraItemFields
|
|
129
|
+
}, { _id: false });
|
|
130
|
+
const fields = {
|
|
131
|
+
journalType: {
|
|
132
|
+
type: String,
|
|
133
|
+
enum: getJournalTypeCodes(),
|
|
134
|
+
default: JOURNAL_CODES["MISC"],
|
|
135
|
+
required: true
|
|
136
|
+
},
|
|
137
|
+
referenceNumber: { type: String },
|
|
138
|
+
label: { type: String },
|
|
139
|
+
date: {
|
|
140
|
+
type: Date,
|
|
141
|
+
default: Date.now,
|
|
142
|
+
required: function() {
|
|
143
|
+
return this.state !== "draft";
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
journalItems: {
|
|
147
|
+
type: [JournalItemSchema],
|
|
148
|
+
default: []
|
|
149
|
+
},
|
|
150
|
+
totalDebit: {
|
|
151
|
+
type: Number,
|
|
152
|
+
required: true,
|
|
153
|
+
min: 0,
|
|
154
|
+
validate: {
|
|
155
|
+
validator: Number.isInteger,
|
|
156
|
+
message: "totalDebit must be an integer (cents)"
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
totalCredit: {
|
|
160
|
+
type: Number,
|
|
161
|
+
required: true,
|
|
162
|
+
min: 0,
|
|
163
|
+
validate: {
|
|
164
|
+
validator: Number.isInteger,
|
|
165
|
+
message: "totalCredit must be an integer (cents)"
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
state: {
|
|
169
|
+
type: String,
|
|
170
|
+
enum: [
|
|
171
|
+
"draft",
|
|
172
|
+
"posted",
|
|
173
|
+
"archived"
|
|
174
|
+
],
|
|
175
|
+
default: "draft",
|
|
176
|
+
required: true
|
|
177
|
+
},
|
|
178
|
+
stateChangedAt: {
|
|
179
|
+
type: Date,
|
|
180
|
+
default: Date.now
|
|
181
|
+
},
|
|
182
|
+
reversed: {
|
|
183
|
+
type: Boolean,
|
|
184
|
+
default: false
|
|
185
|
+
},
|
|
186
|
+
reversedBy: {
|
|
187
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
188
|
+
ref: "JournalEntry",
|
|
189
|
+
default: null
|
|
190
|
+
},
|
|
191
|
+
reversalOf: {
|
|
192
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
193
|
+
ref: "JournalEntry",
|
|
194
|
+
default: null
|
|
195
|
+
},
|
|
196
|
+
...extraFields
|
|
197
|
+
};
|
|
198
|
+
if (config.audit?.trackActor) {
|
|
199
|
+
fields.createdBy = {
|
|
200
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
201
|
+
default: null
|
|
202
|
+
};
|
|
203
|
+
fields.postedBy = {
|
|
204
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
205
|
+
default: null
|
|
206
|
+
};
|
|
207
|
+
fields.reversedByUser = {
|
|
208
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
209
|
+
default: null
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
if (config.strictness?.requireApproval || config.audit?.trackActor) {
|
|
213
|
+
fields.approvedBy = {
|
|
214
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
215
|
+
default: null
|
|
216
|
+
};
|
|
217
|
+
fields.approvedAt = {
|
|
218
|
+
type: Date,
|
|
219
|
+
default: null
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
if (config.idempotency) fields.idempotencyKey = {
|
|
223
|
+
type: String,
|
|
224
|
+
default: null
|
|
225
|
+
};
|
|
226
|
+
if (multiTenant) fields[multiTenant.orgField] = {
|
|
227
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
228
|
+
ref: multiTenant.orgRef,
|
|
229
|
+
required: true
|
|
230
|
+
};
|
|
231
|
+
const schema = new mongoose.Schema(fields, { timestamps: true });
|
|
232
|
+
schema.pre("validate", function() {
|
|
233
|
+
const doc = this;
|
|
234
|
+
for (const item of doc.journalItems) if (!item.date) item.date = doc.date;
|
|
235
|
+
for (let i = 0; i < doc.journalItems.length; i++) {
|
|
236
|
+
const d = doc.journalItems[i].debit || 0;
|
|
237
|
+
const c = doc.journalItems[i].credit || 0;
|
|
238
|
+
if (d > 0 && c > 0) throw new Error(`Journal item at index ${i}: cannot have both debit (${d}) and credit (${c}) greater than zero`);
|
|
239
|
+
if (doc.state === "posted" && d === 0 && c === 0) throw new Error(`Journal item at index ${i}: posted entries cannot have zero-value lines (both debit and credit are 0)`);
|
|
240
|
+
}
|
|
241
|
+
const totalDebit = doc.journalItems.reduce((s, i) => s + (i.debit || 0), 0);
|
|
242
|
+
const totalCredit = doc.journalItems.reduce((s, i) => s + (i.credit || 0), 0);
|
|
243
|
+
if (doc.state === "posted") {
|
|
244
|
+
if (doc.journalItems.length < 2) throw new Error("Posted entries must have at least 2 journal items");
|
|
245
|
+
if (totalDebit !== totalCredit) throw new Error("Total debit must equal total credit for posted entries");
|
|
246
|
+
}
|
|
247
|
+
doc.totalDebit = totalDebit;
|
|
248
|
+
doc.totalCredit = totalCredit;
|
|
249
|
+
});
|
|
250
|
+
if (autoReference) {
|
|
251
|
+
const generateReferenceNumber = async (doc, Model, session) => {
|
|
252
|
+
const jt = doc.journalType || "MISC";
|
|
253
|
+
const d = new Date(doc.date);
|
|
254
|
+
const prefix = `${jt}/${d.getFullYear()}/${String(d.getMonth() + 1).padStart(2, "0")}/`;
|
|
255
|
+
const matchFilter = { referenceNumber: { $regex: `^${prefix.replace(/\//g, "\\/")}` } };
|
|
256
|
+
if (multiTenant) matchFilter[multiTenant.orgField] = doc[multiTenant.orgField];
|
|
257
|
+
const pipeline = [
|
|
258
|
+
{ $match: matchFilter },
|
|
259
|
+
{ $addFields: { _refSeq: { $toInt: { $arrayElemAt: [{ $split: ["$referenceNumber", "/"] }, -1] } } } },
|
|
260
|
+
{ $sort: { _refSeq: -1 } },
|
|
261
|
+
{ $limit: 1 },
|
|
262
|
+
{ $project: { _refSeq: 1 } }
|
|
263
|
+
];
|
|
264
|
+
const results = await Model.aggregate(pipeline).session(session);
|
|
265
|
+
let seq = 1;
|
|
266
|
+
if (results.length > 0 && typeof results[0]._refSeq === "number") seq = results[0]._refSeq + 1;
|
|
267
|
+
return `${prefix}${String(seq).padStart(4, "0")}`;
|
|
268
|
+
};
|
|
269
|
+
schema.pre("save", async function() {
|
|
270
|
+
const doc = this;
|
|
271
|
+
if (doc.isModified("journalType")) doc.referenceNumber = void 0;
|
|
272
|
+
if (!doc.referenceNumber) {
|
|
273
|
+
const session = doc.$session?.() ?? null;
|
|
274
|
+
const Model = doc.constructor;
|
|
275
|
+
doc.referenceNumber = await generateReferenceNumber(doc, Model, session);
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
const MAX_REF_RETRIES = 3;
|
|
279
|
+
schema.post("save", async function(error, doc, next) {
|
|
280
|
+
const mongoError = error;
|
|
281
|
+
if (mongoError.code === 11e3 && mongoError.keyPattern?.referenceNumber) {
|
|
282
|
+
const entry = doc;
|
|
283
|
+
const retryCount = entry.__refRetries ?? 0;
|
|
284
|
+
if (retryCount >= MAX_REF_RETRIES) {
|
|
285
|
+
next(/* @__PURE__ */ new Error(`Failed to generate unique reference number after ${MAX_REF_RETRIES} retries. Too many concurrent inserts for this period.`));
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
entry.__refRetries = retryCount + 1;
|
|
289
|
+
const session = entry.$session?.() ?? null;
|
|
290
|
+
const Model = entry.constructor;
|
|
291
|
+
entry.referenceNumber = await generateReferenceNumber(entry, Model, session);
|
|
292
|
+
try {
|
|
293
|
+
await entry.save({ session });
|
|
294
|
+
next();
|
|
295
|
+
} catch (retryError) {
|
|
296
|
+
next(retryError);
|
|
297
|
+
}
|
|
298
|
+
} else next(error);
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
if (indexes) {
|
|
302
|
+
const org = multiTenant?.orgField;
|
|
303
|
+
const refPartial = { partialFilterExpression: { referenceNumber: {
|
|
304
|
+
$exists: true,
|
|
305
|
+
$type: "string"
|
|
306
|
+
} } };
|
|
307
|
+
if (org) {
|
|
308
|
+
schema.index({
|
|
309
|
+
[org]: 1,
|
|
310
|
+
referenceNumber: 1
|
|
311
|
+
}, {
|
|
312
|
+
unique: true,
|
|
313
|
+
...refPartial
|
|
314
|
+
});
|
|
315
|
+
schema.index({
|
|
316
|
+
[org]: 1,
|
|
317
|
+
state: 1,
|
|
318
|
+
date: 1
|
|
319
|
+
});
|
|
320
|
+
schema.index({
|
|
321
|
+
[org]: 1,
|
|
322
|
+
date: -1
|
|
323
|
+
});
|
|
324
|
+
schema.index({
|
|
325
|
+
[org]: 1,
|
|
326
|
+
journalType: 1
|
|
327
|
+
});
|
|
328
|
+
schema.index({
|
|
329
|
+
"journalItems.account": 1,
|
|
330
|
+
state: 1
|
|
331
|
+
});
|
|
332
|
+
schema.index({
|
|
333
|
+
[org]: 1,
|
|
334
|
+
"journalItems.account": 1,
|
|
335
|
+
date: 1,
|
|
336
|
+
state: 1
|
|
337
|
+
});
|
|
338
|
+
} else {
|
|
339
|
+
schema.index({ referenceNumber: 1 }, {
|
|
340
|
+
unique: true,
|
|
341
|
+
...refPartial
|
|
342
|
+
});
|
|
343
|
+
schema.index({
|
|
344
|
+
state: 1,
|
|
345
|
+
date: 1
|
|
346
|
+
});
|
|
347
|
+
schema.index({ date: -1 });
|
|
348
|
+
schema.index({ journalType: 1 });
|
|
349
|
+
schema.index({
|
|
350
|
+
"journalItems.account": 1,
|
|
351
|
+
state: 1
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
schema.index({ reversed: 1 });
|
|
355
|
+
if (config.idempotency) {
|
|
356
|
+
const idempotencyIdx = {};
|
|
357
|
+
if (org) idempotencyIdx[org] = 1;
|
|
358
|
+
idempotencyIdx.idempotencyKey = 1;
|
|
359
|
+
schema.index(idempotencyIdx, {
|
|
360
|
+
unique: true,
|
|
361
|
+
partialFilterExpression: { idempotencyKey: {
|
|
362
|
+
$exists: true,
|
|
363
|
+
$ne: null
|
|
364
|
+
} }
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
if (textSearch) schema.index({
|
|
369
|
+
referenceNumber: "text",
|
|
370
|
+
label: "text"
|
|
371
|
+
}, {
|
|
372
|
+
weights: {
|
|
373
|
+
referenceNumber: 10,
|
|
374
|
+
label: 5
|
|
375
|
+
},
|
|
376
|
+
name: "journal_text_idx"
|
|
377
|
+
});
|
|
378
|
+
for (const idx of extraIndexes) schema.index(idx.fields, idx.options);
|
|
379
|
+
return schema;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
//#endregion
|
|
383
|
+
//#region src/schemas/fiscal-period.schema.ts
|
|
384
|
+
/**
|
|
385
|
+
* Fiscal Period Schema Factory
|
|
386
|
+
*
|
|
387
|
+
* Creates a Mongoose schema for tracking fiscal periods (months, quarters, years).
|
|
388
|
+
* Supports closing periods to lock entries.
|
|
389
|
+
*/
|
|
390
|
+
function createFiscalPeriodSchema(config, options = {}) {
|
|
391
|
+
const { multiTenant } = config;
|
|
392
|
+
const { indexes = true, extraFields = {}, extraIndexes = [] } = options;
|
|
393
|
+
const fields = {
|
|
394
|
+
name: {
|
|
395
|
+
type: String,
|
|
396
|
+
required: true
|
|
397
|
+
},
|
|
398
|
+
startDate: {
|
|
399
|
+
type: Date,
|
|
400
|
+
required: true
|
|
401
|
+
},
|
|
402
|
+
endDate: {
|
|
403
|
+
type: Date,
|
|
404
|
+
required: true
|
|
405
|
+
},
|
|
406
|
+
closed: {
|
|
407
|
+
type: Boolean,
|
|
408
|
+
default: false
|
|
409
|
+
},
|
|
410
|
+
closedAt: {
|
|
411
|
+
type: Date,
|
|
412
|
+
default: null
|
|
413
|
+
},
|
|
414
|
+
closedBy: {
|
|
415
|
+
type: String,
|
|
416
|
+
default: null
|
|
417
|
+
},
|
|
418
|
+
closingEntryId: {
|
|
419
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
420
|
+
default: null
|
|
421
|
+
},
|
|
422
|
+
reopenedAt: {
|
|
423
|
+
type: Date,
|
|
424
|
+
default: null
|
|
425
|
+
},
|
|
426
|
+
reopenedBy: {
|
|
427
|
+
type: String,
|
|
428
|
+
default: null
|
|
429
|
+
},
|
|
430
|
+
...extraFields
|
|
431
|
+
};
|
|
432
|
+
if (multiTenant) fields[multiTenant.orgField] = {
|
|
433
|
+
type: mongoose.Schema.Types.ObjectId,
|
|
434
|
+
ref: multiTenant.orgRef,
|
|
435
|
+
required: true
|
|
436
|
+
};
|
|
437
|
+
const schema = new mongoose.Schema(fields, { timestamps: true });
|
|
438
|
+
if (indexes) if (multiTenant) {
|
|
439
|
+
const org = multiTenant.orgField;
|
|
440
|
+
schema.index({
|
|
441
|
+
[org]: 1,
|
|
442
|
+
startDate: 1,
|
|
443
|
+
endDate: 1
|
|
444
|
+
}, { unique: true });
|
|
445
|
+
schema.index({
|
|
446
|
+
[org]: 1,
|
|
447
|
+
closed: 1
|
|
448
|
+
});
|
|
449
|
+
} else {
|
|
450
|
+
schema.index({
|
|
451
|
+
startDate: 1,
|
|
452
|
+
endDate: 1
|
|
453
|
+
}, { unique: true });
|
|
454
|
+
schema.index({ closed: 1 });
|
|
455
|
+
}
|
|
456
|
+
for (const idx of extraIndexes) schema.index(idx.fields, idx.options);
|
|
457
|
+
schema.pre("validate", async function() {
|
|
458
|
+
const doc = this;
|
|
459
|
+
if (!doc.startDate || !doc.endDate) return;
|
|
460
|
+
const overlapQuery = {
|
|
461
|
+
_id: { $ne: doc._id },
|
|
462
|
+
startDate: { $lt: doc.endDate },
|
|
463
|
+
endDate: { $gt: doc.startDate }
|
|
464
|
+
};
|
|
465
|
+
if (multiTenant) overlapQuery[multiTenant.orgField] = doc[multiTenant.orgField];
|
|
466
|
+
const overlap = await doc.collection.findOne(overlapQuery);
|
|
467
|
+
if (overlap) {
|
|
468
|
+
const msg = `Fiscal period overlaps with existing period "${overlap.name}" (${new Date(overlap.startDate).toISOString().split("T")[0]} – ${new Date(overlap.endDate).toISOString().split("T")[0]}).`;
|
|
469
|
+
doc.invalidate("startDate", msg, doc.startDate, "overlap");
|
|
470
|
+
}
|
|
471
|
+
});
|
|
472
|
+
return schema;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
//#endregion
|
|
476
|
+
export { createJournalEntrySchema as n, createAccountSchema as r, createFiscalPeriodSchema as t };
|
|
477
|
+
//# sourceMappingURL=fiscal-period.schema-CbALaaKl.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fiscal-period.schema-CbALaaKl.mjs","names":[],"sources":["../src/schemas/account.schema.ts","../src/schemas/journal-entry.schema.ts","../src/schemas/fiscal-period.schema.ts"],"sourcesContent":["/**\r\n * Account Schema Factory\r\n *\r\n * Creates a Mongoose schema for Chart of Accounts that is:\r\n * - Multi-tenant aware (adds org field + compound indexes when configured)\r\n * - Validates accountTypeCode against the country pack\r\n * - Supports accountNumber (unique per org) and name (user-facing display)\r\n * - Lean: no cached balances — always computed from journal entries\r\n */\r\n\r\nimport mongoose from 'mongoose';\r\nimport type { AccountingEngineConfig, SchemaOptions } from '../types/engine.js';\r\n\r\nexport function createAccountSchema(\r\n config: AccountingEngineConfig,\r\n options: SchemaOptions = {},\r\n) {\r\n const { multiTenant, country } = config;\r\n const { indexes = true, extraFields = {}, extraIndexes = [] } = options;\r\n\r\n // ── Base fields ──────────────────────────────────────────────────────────\r\n\r\n const fields: Record<string, unknown> = {\r\n accountTypeCode: {\r\n type: String,\r\n required: true,\r\n validate: {\r\n validator: (code: string) => country.isValidAccountType(code),\r\n message: (props: { value: string }) =>\r\n `\"${props.value}\" is not a valid account type code for ${country.name}.`,\r\n },\r\n },\r\n accountNumber: {\r\n type: String,\r\n required: true,\r\n trim: true,\r\n },\r\n name: {\r\n type: String,\r\n required: true,\r\n trim: true,\r\n },\r\n active: { type: Boolean, default: true },\r\n isCashAccount: { type: Boolean, default: false },\r\n ...extraFields,\r\n };\r\n\r\n // ── Multi-tenant field ───────────────────────────────────────────────────\r\n\r\n if (multiTenant) {\r\n fields[multiTenant.orgField] = {\r\n type: mongoose.Schema.Types.ObjectId,\r\n ref: multiTenant.orgRef,\r\n required: true,\r\n };\r\n }\r\n\r\n // ── Schema ───────────────────────────────────────────────────────────────\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const schema = new mongoose.Schema(fields as any, { timestamps: true });\r\n\r\n // ── Pre-validate: auto-default accountNumber and name ──────────────────\r\n\r\n schema.pre('validate', function () {\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const doc = this as any;\r\n if (!doc.accountNumber && doc.accountTypeCode) {\r\n doc.accountNumber = doc.accountTypeCode;\r\n }\r\n if (!doc.name && doc.accountTypeCode) {\r\n const at = country.getAccountType(doc.accountTypeCode);\r\n doc.name = at?.name ?? doc.accountTypeCode;\r\n }\r\n });\r\n\r\n // ── Indexes ──────────────────────────────────────────────────────────────\r\n\r\n if (indexes) {\r\n if (multiTenant) {\r\n const org = multiTenant.orgField;\r\n schema.index({ [org]: 1, active: 1 });\r\n // accountNumber is the unique identity per org\r\n schema.index({ [org]: 1, accountNumber: 1 }, { unique: true });\r\n // accountTypeCode is non-unique — multiple accounts can share a classification\r\n schema.index({ [org]: 1, accountTypeCode: 1 });\r\n } else {\r\n schema.index({ active: 1 });\r\n schema.index({ accountNumber: 1 }, { unique: true });\r\n schema.index({ accountTypeCode: 1 });\r\n }\r\n }\r\n\r\n for (const idx of extraIndexes) {\r\n schema.index(idx.fields, idx.options);\r\n }\r\n\r\n return schema;\r\n}\r\n","/**\r\n * Journal Entry Schema Factory\r\n *\r\n * Creates a Mongoose schema for double-entry journal entries.\r\n * - Multi-tenant aware\r\n * - Embedded journal items with account refs\r\n * - State machine: draft → posted, draft → archived\r\n * - Auto-generated reference numbers\r\n * - Double-entry validation on post\r\n * - Optimized indexes for high-load reporting\r\n */\r\n\r\nimport mongoose from 'mongoose';\r\nimport type { AccountingEngineConfig, JournalSchemaOptions } from '../types/engine.js';\r\nimport { getJournalTypeCodes, JOURNAL_CODES } from '../constants/journals.js';\r\n\r\nexport function createJournalEntrySchema(\r\n config: AccountingEngineConfig,\r\n accountModelName: string,\r\n options: JournalSchemaOptions = {},\r\n) {\r\n const { multiTenant } = config;\r\n const {\r\n indexes = true,\r\n autoReference = true,\r\n textSearch = true,\r\n extraFields = {},\r\n extraIndexes = [],\r\n extraItemFields = {},\r\n } = options;\r\n\r\n // ── Tax Detail (audit reference only) ────────────────────────────────────\r\n\r\n const TaxDetailSchema = new mongoose.Schema(\r\n {\r\n taxCode: { type: String },\r\n taxName: { type: String },\r\n },\r\n { _id: false },\r\n );\r\n\r\n // ── Journal Item ─────────────────────────────────────────────────────────\r\n\r\n const amountValidator = {\r\n validator: (v: number) => Number.isInteger(v) && v >= 0,\r\n message: '{PATH} must be a non-negative integer (cents), got {VALUE}',\r\n };\r\n\r\n const JournalItemSchema = new mongoose.Schema(\r\n {\r\n account: {\r\n type: mongoose.Schema.Types.ObjectId,\r\n ref: accountModelName,\r\n required: true,\r\n },\r\n label: { type: String },\r\n date: { type: Date },\r\n debit: { type: Number, default: 0, min: 0, validate: amountValidator },\r\n credit: { type: Number, default: 0, min: 0, validate: amountValidator },\r\n taxDetails: { type: [TaxDetailSchema], default: [] },\r\n ...extraItemFields,\r\n },\r\n { _id: false },\r\n );\r\n\r\n // ── Main fields ──────────────────────────────────────────────────────────\r\n\r\n const fields: Record<string, unknown> = {\r\n journalType: {\r\n type: String,\r\n enum: getJournalTypeCodes(),\r\n default: JOURNAL_CODES['MISC'],\r\n required: true,\r\n },\r\n referenceNumber: { type: String },\r\n label: { type: String },\r\n date: {\r\n type: Date,\r\n default: Date.now,\r\n required: function (this: { state?: string }) {\r\n return this.state !== 'draft';\r\n },\r\n },\r\n journalItems: { type: [JournalItemSchema], default: [] },\r\n totalDebit: { type: Number, required: true, min: 0, validate: { validator: Number.isInteger, message: 'totalDebit must be an integer (cents)' } },\r\n totalCredit: { type: Number, required: true, min: 0, validate: { validator: Number.isInteger, message: 'totalCredit must be an integer (cents)' } },\r\n state: {\r\n type: String,\r\n enum: ['draft', 'posted', 'archived'],\r\n default: 'draft',\r\n required: true,\r\n },\r\n stateChangedAt: { type: Date, default: Date.now },\r\n reversed: { type: Boolean, default: false },\r\n reversedBy: {\r\n type: mongoose.Schema.Types.ObjectId,\r\n ref: 'JournalEntry',\r\n default: null,\r\n },\r\n reversalOf: {\r\n type: mongoose.Schema.Types.ObjectId,\r\n ref: 'JournalEntry',\r\n default: null,\r\n },\r\n ...extraFields,\r\n };\r\n\r\n // ── Audit fields (conditional) ─────────────────────────────────────────\r\n\r\n if (config.audit?.trackActor) {\r\n fields.createdBy = { type: mongoose.Schema.Types.ObjectId, default: null };\r\n fields.postedBy = { type: mongoose.Schema.Types.ObjectId, default: null };\r\n fields.reversedByUser = { type: mongoose.Schema.Types.ObjectId, default: null };\r\n }\r\n\r\n // ── Approval fields (conditional) ──────────────────────────────────────\r\n\r\n if (config.strictness?.requireApproval || config.audit?.trackActor) {\r\n fields.approvedBy = { type: mongoose.Schema.Types.ObjectId, default: null };\r\n fields.approvedAt = { type: Date, default: null };\r\n }\r\n\r\n // ── Idempotency key (conditional) ──────────────────────────────────────\r\n\r\n if (config.idempotency) {\r\n fields.idempotencyKey = { type: String, default: null };\r\n }\r\n\r\n // ── Multi-tenant field ───────────────────────────────────────────────────\r\n\r\n if (multiTenant) {\r\n fields[multiTenant.orgField] = {\r\n type: mongoose.Schema.Types.ObjectId,\r\n ref: multiTenant.orgRef,\r\n required: true,\r\n };\r\n }\r\n\r\n // ── Schema ───────────────────────────────────────────────────────────────\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const schema = new mongoose.Schema(fields as any, { timestamps: true });\r\n\r\n // ── Pre-validate: double-entry enforcement ───────────────────────────────\r\n\r\n schema.pre('validate', function () {\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const doc = this as any;\r\n\r\n // Propagate entry date to items without a date\r\n for (const item of doc.journalItems) {\r\n if (!item.date) item.date = doc.date;\r\n }\r\n\r\n // Each line must be debit OR credit (not both), and posted entries cannot have zero-value lines\r\n for (let i = 0; i < doc.journalItems.length; i++) {\r\n const d = doc.journalItems[i].debit || 0;\r\n const c = doc.journalItems[i].credit || 0;\r\n if (d > 0 && c > 0) {\r\n throw new Error(\r\n `Journal item at index ${i}: cannot have both debit (${d}) and credit (${c}) greater than zero`,\r\n );\r\n }\r\n if (doc.state === 'posted' && d === 0 && c === 0) {\r\n throw new Error(\r\n `Journal item at index ${i}: posted entries cannot have zero-value lines (both debit and credit are 0)`,\r\n );\r\n }\r\n }\r\n\r\n // Calculate totals\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const totalDebit = doc.journalItems.reduce((s: number, i: any) => s + (i.debit || 0), 0);\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const totalCredit = doc.journalItems.reduce((s: number, i: any) => s + (i.credit || 0), 0);\r\n\r\n // Enforce minimum items and balance for posted entries\r\n if (doc.state === 'posted') {\r\n if (doc.journalItems.length < 2) {\r\n throw new Error('Posted entries must have at least 2 journal items');\r\n }\r\n if (totalDebit !== totalCredit) {\r\n throw new Error('Total debit must equal total credit for posted entries');\r\n }\r\n }\r\n\r\n doc.totalDebit = totalDebit;\r\n doc.totalCredit = totalCredit;\r\n });\r\n\r\n // ── Pre-save: auto-generate reference number ─────────────────────────────\r\n\r\n if (autoReference) {\r\n // Helper: compute next reference number from DB\r\n // Uses aggregation pipeline to extract & sort the numeric suffix,\r\n // avoiding lexicographic sort issues beyond sequence 9999.\r\n const generateReferenceNumber = async (doc: Record<string, unknown>, Model: mongoose.Model<unknown>, session: unknown) => {\r\n const jt = (doc.journalType as string) || 'MISC';\r\n const d = new Date(doc.date as string | number | Date);\r\n const year = d.getFullYear();\r\n const month = String(d.getMonth() + 1).padStart(2, '0');\r\n const prefix = `${jt}/${year}/${month}/`;\r\n\r\n // Build match filter\r\n const matchFilter: Record<string, unknown> = {\r\n referenceNumber: { $regex: `^${prefix.replace(/\\//g, '\\\\/')}` },\r\n };\r\n\r\n // Add org field to query for multi-tenant\r\n if (multiTenant) {\r\n matchFilter[multiTenant.orgField] = doc[multiTenant.orgField];\r\n }\r\n\r\n // Extract numeric suffix via $split and sort numerically\r\n const pipeline: mongoose.PipelineStage[] = [\r\n { $match: matchFilter },\r\n {\r\n $addFields: {\r\n _refSeq: {\r\n $toInt: {\r\n $arrayElemAt: [{ $split: ['$referenceNumber', '/'] }, -1],\r\n },\r\n },\r\n },\r\n },\r\n { $sort: { _refSeq: -1 as const } },\r\n { $limit: 1 },\r\n { $project: { _refSeq: 1 } },\r\n ];\r\n\r\n const results = await Model.aggregate(pipeline)\r\n .session(session as mongoose.mongo.ClientSession | null);\r\n\r\n let seq = 1;\r\n if (results.length > 0 && typeof results[0]._refSeq === 'number') {\r\n seq = results[0]._refSeq + 1;\r\n }\r\n\r\n return `${prefix}${String(seq).padStart(4, '0')}`;\r\n };\r\n\r\n schema.pre('save', async function () {\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const doc = this as any;\r\n\r\n if (doc.isModified('journalType')) {\r\n doc.referenceNumber = undefined;\r\n }\r\n\r\n if (!doc.referenceNumber) {\r\n const session = doc.$session?.() ?? null;\r\n const Model = doc.constructor as mongoose.Model<unknown>;\r\n doc.referenceNumber = await generateReferenceNumber(doc, Model, session);\r\n }\r\n });\r\n\r\n // Retry on duplicate key error (race condition between concurrent inserts)\r\n const MAX_REF_RETRIES = 3;\r\n schema.post('save', async function (error: Error, doc: unknown, next: (err?: Error) => void) {\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const mongoError = error as any;\r\n // 11000 = MongoDB duplicate key error\r\n if (mongoError.code === 11000 && mongoError.keyPattern?.referenceNumber) {\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const entry = doc as any;\r\n const retryCount: number = entry.__refRetries ?? 0;\r\n if (retryCount >= MAX_REF_RETRIES) {\r\n next(new Error(\r\n `Failed to generate unique reference number after ${MAX_REF_RETRIES} retries. ` +\r\n 'Too many concurrent inserts for this period.',\r\n ));\r\n return;\r\n }\r\n entry.__refRetries = retryCount + 1;\r\n const session = entry.$session?.() ?? null;\r\n const Model = entry.constructor as mongoose.Model<unknown>;\r\n entry.referenceNumber = await generateReferenceNumber(entry, Model, session);\r\n try {\r\n await entry.save({ session });\r\n next();\r\n } catch (retryError) {\r\n next(retryError as Error);\r\n }\r\n } else {\r\n next(error);\r\n }\r\n });\r\n }\r\n\r\n // ── Indexes ──────────────────────────────────────────────────────────────\r\n\r\n if (indexes) {\r\n const org = multiTenant?.orgField;\r\n\r\n // Partial filter: unique constraint only applies to docs with a string\r\n // referenceNumber — allows multiple entries without a ref when autoReference is off.\r\n const refPartial = { partialFilterExpression: { referenceNumber: { $exists: true, $type: 'string' } } };\r\n\r\n if (org) {\r\n schema.index({ [org]: 1, referenceNumber: 1 }, { unique: true, ...refPartial });\r\n schema.index({ [org]: 1, state: 1, date: 1 });\r\n schema.index({ [org]: 1, date: -1 });\r\n schema.index({ [org]: 1, journalType: 1 });\r\n schema.index({ 'journalItems.account': 1, state: 1 });\r\n schema.index({ [org]: 1, 'journalItems.account': 1, date: 1, state: 1 });\r\n } else {\r\n schema.index({ referenceNumber: 1 }, { unique: true, ...refPartial });\r\n schema.index({ state: 1, date: 1 });\r\n schema.index({ date: -1 });\r\n schema.index({ journalType: 1 });\r\n schema.index({ 'journalItems.account': 1, state: 1 });\r\n }\r\n\r\n schema.index({ reversed: 1 });\r\n\r\n // Idempotency key: unique sparse index (only when enabled)\r\n if (config.idempotency) {\r\n const idempotencyIdx: Record<string, 1 | -1> = {};\r\n if (org) idempotencyIdx[org] = 1;\r\n idempotencyIdx.idempotencyKey = 1;\r\n schema.index(idempotencyIdx, {\r\n unique: true,\r\n partialFilterExpression: { idempotencyKey: { $exists: true, $ne: null } },\r\n });\r\n }\r\n }\r\n\r\n if (textSearch) {\r\n schema.index(\r\n { referenceNumber: 'text', label: 'text' },\r\n { weights: { referenceNumber: 10, label: 5 }, name: 'journal_text_idx' },\r\n );\r\n }\r\n\r\n for (const idx of extraIndexes) {\r\n schema.index(idx.fields, idx.options);\r\n }\r\n\r\n return schema;\r\n}\r\n","/**\r\n * Fiscal Period Schema Factory\r\n *\r\n * Creates a Mongoose schema for tracking fiscal periods (months, quarters, years).\r\n * Supports closing periods to lock entries.\r\n */\r\n\r\nimport mongoose from 'mongoose';\r\nimport type { AccountingEngineConfig, SchemaOptions } from '../types/engine.js';\r\n\r\nexport function createFiscalPeriodSchema(\r\n config: AccountingEngineConfig,\r\n options: SchemaOptions = {},\r\n) {\r\n const { multiTenant } = config;\r\n const { indexes = true, extraFields = {}, extraIndexes = [] } = options;\r\n\r\n const fields: Record<string, unknown> = {\r\n name: { type: String, required: true },\r\n startDate: { type: Date, required: true },\r\n endDate: { type: Date, required: true },\r\n closed: { type: Boolean, default: false },\r\n closedAt: { type: Date, default: null },\r\n closedBy: { type: String, default: null },\r\n closingEntryId: { type: mongoose.Schema.Types.ObjectId, default: null },\r\n reopenedAt: { type: Date, default: null },\r\n reopenedBy: { type: String, default: null },\r\n ...extraFields,\r\n };\r\n\r\n if (multiTenant) {\r\n fields[multiTenant.orgField] = {\r\n type: mongoose.Schema.Types.ObjectId,\r\n ref: multiTenant.orgRef,\r\n required: true,\r\n };\r\n }\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const schema = new mongoose.Schema(fields as any, { timestamps: true });\r\n\r\n if (indexes) {\r\n if (multiTenant) {\r\n const org = multiTenant.orgField;\r\n schema.index({ [org]: 1, startDate: 1, endDate: 1 }, { unique: true });\r\n schema.index({ [org]: 1, closed: 1 });\r\n } else {\r\n schema.index({ startDate: 1, endDate: 1 }, { unique: true });\r\n schema.index({ closed: 1 });\r\n }\r\n }\r\n\r\n for (const idx of extraIndexes) {\r\n schema.index(idx.fields, idx.options);\r\n }\r\n\r\n // ── Overlap guard: prevent overlapping date ranges within a tenant ─────\r\n schema.pre('validate', async function () {\r\n const doc = this as mongoose.Document & { startDate: Date; endDate: Date; [key: string]: unknown };\r\n if (!doc.startDate || !doc.endDate) return;\r\n\r\n // A period overlaps if: existing.startDate < this.endDate AND existing.endDate > this.startDate\r\n const overlapQuery: Record<string, unknown> = {\r\n _id: { $ne: doc._id },\r\n startDate: { $lt: doc.endDate },\r\n endDate: { $gt: doc.startDate },\r\n };\r\n\r\n if (multiTenant) {\r\n overlapQuery[multiTenant.orgField] = doc[multiTenant.orgField];\r\n }\r\n\r\n const overlap = await doc.collection.findOne(overlapQuery);\r\n if (overlap) {\r\n const msg = `Fiscal period overlaps with existing period \"${overlap.name}\" (${new Date(overlap.startDate).toISOString().split('T')[0]} – ${new Date(overlap.endDate).toISOString().split('T')[0]}).`;\r\n doc.invalidate('startDate', msg, doc.startDate, 'overlap');\r\n }\r\n });\r\n\r\n return schema;\r\n}\r\n"],"mappings":";;;;;;;;;;;;;AAaA,SAAgB,oBACd,QACA,UAAyB,EAAE,EAC3B;CACA,MAAM,EAAE,aAAa,YAAY;CACjC,MAAM,EAAE,UAAU,MAAM,cAAc,EAAE,EAAE,eAAe,EAAE,KAAK;CAIhE,MAAM,SAAkC;EACtC,iBAAiB;GACf,MAAM;GACN,UAAU;GACV,UAAU;IACR,YAAY,SAAiB,QAAQ,mBAAmB,KAAK;IAC7D,UAAU,UACR,IAAI,MAAM,MAAM,yCAAyC,QAAQ,KAAK;IACzE;GACF;EACD,eAAe;GACb,MAAM;GACN,UAAU;GACV,MAAM;GACP;EACD,MAAM;GACJ,MAAM;GACN,UAAU;GACV,MAAM;GACP;EACD,QAAQ;GAAE,MAAM;GAAS,SAAS;GAAM;EACxC,eAAe;GAAE,MAAM;GAAS,SAAS;GAAO;EAChD,GAAG;EACJ;AAID,KAAI,YACF,QAAO,YAAY,YAAY;EAC7B,MAAM,SAAS,OAAO,MAAM;EAC5B,KAAK,YAAY;EACjB,UAAU;EACX;CAMH,MAAM,SAAS,IAAI,SAAS,OAAO,QAAe,EAAE,YAAY,MAAM,CAAC;AAIvE,QAAO,IAAI,YAAY,WAAY;EAEjC,MAAM,MAAM;AACZ,MAAI,CAAC,IAAI,iBAAiB,IAAI,gBAC5B,KAAI,gBAAgB,IAAI;AAE1B,MAAI,CAAC,IAAI,QAAQ,IAAI,gBAEnB,KAAI,OADO,QAAQ,eAAe,IAAI,gBAAgB,EACvC,QAAQ,IAAI;GAE7B;AAIF,KAAI,QACF,KAAI,aAAa;EACf,MAAM,MAAM,YAAY;AACxB,SAAO,MAAM;IAAG,MAAM;GAAG,QAAQ;GAAG,CAAC;AAErC,SAAO,MAAM;IAAG,MAAM;GAAG,eAAe;GAAG,EAAE,EAAE,QAAQ,MAAM,CAAC;AAE9D,SAAO,MAAM;IAAG,MAAM;GAAG,iBAAiB;GAAG,CAAC;QACzC;AACL,SAAO,MAAM,EAAE,QAAQ,GAAG,CAAC;AAC3B,SAAO,MAAM,EAAE,eAAe,GAAG,EAAE,EAAE,QAAQ,MAAM,CAAC;AACpD,SAAO,MAAM,EAAE,iBAAiB,GAAG,CAAC;;AAIxC,MAAK,MAAM,OAAO,aAChB,QAAO,MAAM,IAAI,QAAQ,IAAI,QAAQ;AAGvC,QAAO;;;;;;;;;;;;;;;;ACjFT,SAAgB,yBACd,QACA,kBACA,UAAgC,EAAE,EAClC;CACA,MAAM,EAAE,gBAAgB;CACxB,MAAM,EACJ,UAAU,MACV,gBAAgB,MAChB,aAAa,MACb,cAAc,EAAE,EAChB,eAAe,EAAE,EACjB,kBAAkB,EAAE,KAClB;CAIJ,MAAM,kBAAkB,IAAI,SAAS,OACnC;EACE,SAAS,EAAE,MAAM,QAAQ;EACzB,SAAS,EAAE,MAAM,QAAQ;EAC1B,EACD,EAAE,KAAK,OAAO,CACf;CAID,MAAM,kBAAkB;EACtB,YAAY,MAAc,OAAO,UAAU,EAAE,IAAI,KAAK;EACtD,SAAS;EACV;CAED,MAAM,oBAAoB,IAAI,SAAS,OACrC;EACE,SAAS;GACP,MAAM,SAAS,OAAO,MAAM;GAC5B,KAAK;GACL,UAAU;GACX;EACD,OAAO,EAAE,MAAM,QAAQ;EACvB,MAAM,EAAE,MAAM,MAAM;EACpB,OAAO;GAAE,MAAM;GAAQ,SAAS;GAAG,KAAK;GAAG,UAAU;GAAiB;EACtE,QAAQ;GAAE,MAAM;GAAQ,SAAS;GAAG,KAAK;GAAG,UAAU;GAAiB;EACvE,YAAY;GAAE,MAAM,CAAC,gBAAgB;GAAE,SAAS,EAAE;GAAE;EACpD,GAAG;EACJ,EACD,EAAE,KAAK,OAAO,CACf;CAID,MAAM,SAAkC;EACtC,aAAa;GACX,MAAM;GACN,MAAM,qBAAqB;GAC3B,SAAS,cAAc;GACvB,UAAU;GACX;EACD,iBAAiB,EAAE,MAAM,QAAQ;EACjC,OAAO,EAAE,MAAM,QAAQ;EACvB,MAAM;GACJ,MAAM;GACN,SAAS,KAAK;GACd,UAAU,WAAoC;AAC5C,WAAO,KAAK,UAAU;;GAEzB;EACD,cAAc;GAAE,MAAM,CAAC,kBAAkB;GAAE,SAAS,EAAE;GAAE;EACxD,YAAY;GAAE,MAAM;GAAQ,UAAU;GAAM,KAAK;GAAG,UAAU;IAAE,WAAW,OAAO;IAAW,SAAS;IAAyC;GAAE;EACjJ,aAAa;GAAE,MAAM;GAAQ,UAAU;GAAM,KAAK;GAAG,UAAU;IAAE,WAAW,OAAO;IAAW,SAAS;IAA0C;GAAE;EACnJ,OAAO;GACL,MAAM;GACN,MAAM;IAAC;IAAS;IAAU;IAAW;GACrC,SAAS;GACT,UAAU;GACX;EACD,gBAAgB;GAAE,MAAM;GAAM,SAAS,KAAK;GAAK;EACjD,UAAU;GAAE,MAAM;GAAS,SAAS;GAAO;EAC3C,YAAY;GACV,MAAM,SAAS,OAAO,MAAM;GAC5B,KAAK;GACL,SAAS;GACV;EACD,YAAY;GACV,MAAM,SAAS,OAAO,MAAM;GAC5B,KAAK;GACL,SAAS;GACV;EACD,GAAG;EACJ;AAID,KAAI,OAAO,OAAO,YAAY;AAC5B,SAAO,YAAY;GAAE,MAAM,SAAS,OAAO,MAAM;GAAU,SAAS;GAAM;AAC1E,SAAO,WAAW;GAAE,MAAM,SAAS,OAAO,MAAM;GAAU,SAAS;GAAM;AACzE,SAAO,iBAAiB;GAAE,MAAM,SAAS,OAAO,MAAM;GAAU,SAAS;GAAM;;AAKjF,KAAI,OAAO,YAAY,mBAAmB,OAAO,OAAO,YAAY;AAClE,SAAO,aAAa;GAAE,MAAM,SAAS,OAAO,MAAM;GAAU,SAAS;GAAM;AAC3E,SAAO,aAAa;GAAE,MAAM;GAAM,SAAS;GAAM;;AAKnD,KAAI,OAAO,YACT,QAAO,iBAAiB;EAAE,MAAM;EAAQ,SAAS;EAAM;AAKzD,KAAI,YACF,QAAO,YAAY,YAAY;EAC7B,MAAM,SAAS,OAAO,MAAM;EAC5B,KAAK,YAAY;EACjB,UAAU;EACX;CAMH,MAAM,SAAS,IAAI,SAAS,OAAO,QAAe,EAAE,YAAY,MAAM,CAAC;AAIvE,QAAO,IAAI,YAAY,WAAY;EAEjC,MAAM,MAAM;AAGZ,OAAK,MAAM,QAAQ,IAAI,aACrB,KAAI,CAAC,KAAK,KAAM,MAAK,OAAO,IAAI;AAIlC,OAAK,IAAI,IAAI,GAAG,IAAI,IAAI,aAAa,QAAQ,KAAK;GAChD,MAAM,IAAI,IAAI,aAAa,GAAG,SAAS;GACvC,MAAM,IAAI,IAAI,aAAa,GAAG,UAAU;AACxC,OAAI,IAAI,KAAK,IAAI,EACf,OAAM,IAAI,MACR,yBAAyB,EAAE,4BAA4B,EAAE,gBAAgB,EAAE,qBAC5E;AAEH,OAAI,IAAI,UAAU,YAAY,MAAM,KAAK,MAAM,EAC7C,OAAM,IAAI,MACR,yBAAyB,EAAE,6EAC5B;;EAML,MAAM,aAAa,IAAI,aAAa,QAAQ,GAAW,MAAW,KAAK,EAAE,SAAS,IAAI,EAAE;EAExF,MAAM,cAAc,IAAI,aAAa,QAAQ,GAAW,MAAW,KAAK,EAAE,UAAU,IAAI,EAAE;AAG1F,MAAI,IAAI,UAAU,UAAU;AAC1B,OAAI,IAAI,aAAa,SAAS,EAC5B,OAAM,IAAI,MAAM,oDAAoD;AAEtE,OAAI,eAAe,YACjB,OAAM,IAAI,MAAM,yDAAyD;;AAI7E,MAAI,aAAa;AACjB,MAAI,cAAc;GAClB;AAIF,KAAI,eAAe;EAIjB,MAAM,0BAA0B,OAAO,KAA8B,OAAgC,YAAqB;GACxH,MAAM,KAAM,IAAI,eAA0B;GAC1C,MAAM,IAAI,IAAI,KAAK,IAAI,KAA+B;GAGtD,MAAM,SAAS,GAAG,GAAG,GAFR,EAAE,aAAa,CAEC,GADf,OAAO,EAAE,UAAU,GAAG,EAAE,CAAC,SAAS,GAAG,IAAI,CACjB;GAGtC,MAAM,cAAuC,EAC3C,iBAAiB,EAAE,QAAQ,IAAI,OAAO,QAAQ,OAAO,MAAM,IAAI,EAChE;AAGD,OAAI,YACF,aAAY,YAAY,YAAY,IAAI,YAAY;GAItD,MAAM,WAAqC;IACzC,EAAE,QAAQ,aAAa;IACvB,EACE,YAAY,EACV,SAAS,EACP,QAAQ,EACN,cAAc,CAAC,EAAE,QAAQ,CAAC,oBAAoB,IAAI,EAAE,EAAE,GAAG,EAC1D,EACF,EACF,EACF;IACD,EAAE,OAAO,EAAE,SAAS,IAAa,EAAE;IACnC,EAAE,QAAQ,GAAG;IACb,EAAE,UAAU,EAAE,SAAS,GAAG,EAAE;IAC7B;GAED,MAAM,UAAU,MAAM,MAAM,UAAU,SAAS,CAC5C,QAAQ,QAA+C;GAE1D,IAAI,MAAM;AACV,OAAI,QAAQ,SAAS,KAAK,OAAO,QAAQ,GAAG,YAAY,SACtD,OAAM,QAAQ,GAAG,UAAU;AAG7B,UAAO,GAAG,SAAS,OAAO,IAAI,CAAC,SAAS,GAAG,IAAI;;AAGjD,SAAO,IAAI,QAAQ,iBAAkB;GAEnC,MAAM,MAAM;AAEZ,OAAI,IAAI,WAAW,cAAc,CAC/B,KAAI,kBAAkB;AAGxB,OAAI,CAAC,IAAI,iBAAiB;IACxB,MAAM,UAAU,IAAI,YAAY,IAAI;IACpC,MAAM,QAAQ,IAAI;AAClB,QAAI,kBAAkB,MAAM,wBAAwB,KAAK,OAAO,QAAQ;;IAE1E;EAGF,MAAM,kBAAkB;AACxB,SAAO,KAAK,QAAQ,eAAgB,OAAc,KAAc,MAA6B;GAE3F,MAAM,aAAa;AAEnB,OAAI,WAAW,SAAS,QAAS,WAAW,YAAY,iBAAiB;IAEvE,MAAM,QAAQ;IACd,MAAM,aAAqB,MAAM,gBAAgB;AACjD,QAAI,cAAc,iBAAiB;AACjC,0BAAK,IAAI,MACP,oDAAoD,gBAAgB,wDAErE,CAAC;AACF;;AAEF,UAAM,eAAe,aAAa;IAClC,MAAM,UAAU,MAAM,YAAY,IAAI;IACtC,MAAM,QAAQ,MAAM;AACpB,UAAM,kBAAkB,MAAM,wBAAwB,OAAO,OAAO,QAAQ;AAC5E,QAAI;AACF,WAAM,MAAM,KAAK,EAAE,SAAS,CAAC;AAC7B,WAAM;aACC,YAAY;AACnB,UAAK,WAAoB;;SAG3B,MAAK,MAAM;IAEb;;AAKJ,KAAI,SAAS;EACX,MAAM,MAAM,aAAa;EAIzB,MAAM,aAAa,EAAE,yBAAyB,EAAE,iBAAiB;GAAE,SAAS;GAAM,OAAO;GAAU,EAAE,EAAE;AAEvG,MAAI,KAAK;AACP,UAAO,MAAM;KAAG,MAAM;IAAG,iBAAiB;IAAG,EAAE;IAAE,QAAQ;IAAM,GAAG;IAAY,CAAC;AAC/E,UAAO,MAAM;KAAG,MAAM;IAAG,OAAO;IAAG,MAAM;IAAG,CAAC;AAC7C,UAAO,MAAM;KAAG,MAAM;IAAG,MAAM;IAAI,CAAC;AACpC,UAAO,MAAM;KAAG,MAAM;IAAG,aAAa;IAAG,CAAC;AAC1C,UAAO,MAAM;IAAE,wBAAwB;IAAG,OAAO;IAAG,CAAC;AACrD,UAAO,MAAM;KAAG,MAAM;IAAG,wBAAwB;IAAG,MAAM;IAAG,OAAO;IAAG,CAAC;SACnE;AACL,UAAO,MAAM,EAAE,iBAAiB,GAAG,EAAE;IAAE,QAAQ;IAAM,GAAG;IAAY,CAAC;AACrE,UAAO,MAAM;IAAE,OAAO;IAAG,MAAM;IAAG,CAAC;AACnC,UAAO,MAAM,EAAE,MAAM,IAAI,CAAC;AAC1B,UAAO,MAAM,EAAE,aAAa,GAAG,CAAC;AAChC,UAAO,MAAM;IAAE,wBAAwB;IAAG,OAAO;IAAG,CAAC;;AAGvD,SAAO,MAAM,EAAE,UAAU,GAAG,CAAC;AAG7B,MAAI,OAAO,aAAa;GACtB,MAAM,iBAAyC,EAAE;AACjD,OAAI,IAAK,gBAAe,OAAO;AAC/B,kBAAe,iBAAiB;AAChC,UAAO,MAAM,gBAAgB;IAC3B,QAAQ;IACR,yBAAyB,EAAE,gBAAgB;KAAE,SAAS;KAAM,KAAK;KAAM,EAAE;IAC1E,CAAC;;;AAIN,KAAI,WACF,QAAO,MACL;EAAE,iBAAiB;EAAQ,OAAO;EAAQ,EAC1C;EAAE,SAAS;GAAE,iBAAiB;GAAI,OAAO;GAAG;EAAE,MAAM;EAAoB,CACzE;AAGH,MAAK,MAAM,OAAO,aAChB,QAAO,MAAM,IAAI,QAAQ,IAAI,QAAQ;AAGvC,QAAO;;;;;;;;;;;ACxUT,SAAgB,yBACd,QACA,UAAyB,EAAE,EAC3B;CACA,MAAM,EAAE,gBAAgB;CACxB,MAAM,EAAE,UAAU,MAAM,cAAc,EAAE,EAAE,eAAe,EAAE,KAAK;CAEhE,MAAM,SAAkC;EACtC,MAAM;GAAE,MAAM;GAAQ,UAAU;GAAM;EACtC,WAAW;GAAE,MAAM;GAAM,UAAU;GAAM;EACzC,SAAS;GAAE,MAAM;GAAM,UAAU;GAAM;EACvC,QAAQ;GAAE,MAAM;GAAS,SAAS;GAAO;EACzC,UAAU;GAAE,MAAM;GAAM,SAAS;GAAM;EACvC,UAAU;GAAE,MAAM;GAAQ,SAAS;GAAM;EACzC,gBAAgB;GAAE,MAAM,SAAS,OAAO,MAAM;GAAU,SAAS;GAAM;EACvE,YAAY;GAAE,MAAM;GAAM,SAAS;GAAM;EACzC,YAAY;GAAE,MAAM;GAAQ,SAAS;GAAM;EAC3C,GAAG;EACJ;AAED,KAAI,YACF,QAAO,YAAY,YAAY;EAC7B,MAAM,SAAS,OAAO,MAAM;EAC5B,KAAK,YAAY;EACjB,UAAU;EACX;CAIH,MAAM,SAAS,IAAI,SAAS,OAAO,QAAe,EAAE,YAAY,MAAM,CAAC;AAEvE,KAAI,QACF,KAAI,aAAa;EACf,MAAM,MAAM,YAAY;AACxB,SAAO,MAAM;IAAG,MAAM;GAAG,WAAW;GAAG,SAAS;GAAG,EAAE,EAAE,QAAQ,MAAM,CAAC;AACtE,SAAO,MAAM;IAAG,MAAM;GAAG,QAAQ;GAAG,CAAC;QAChC;AACL,SAAO,MAAM;GAAE,WAAW;GAAG,SAAS;GAAG,EAAE,EAAE,QAAQ,MAAM,CAAC;AAC5D,SAAO,MAAM,EAAE,QAAQ,GAAG,CAAC;;AAI/B,MAAK,MAAM,OAAO,aAChB,QAAO,MAAM,IAAI,QAAQ,IAAI,QAAQ;AAIvC,QAAO,IAAI,YAAY,iBAAkB;EACvC,MAAM,MAAM;AACZ,MAAI,CAAC,IAAI,aAAa,CAAC,IAAI,QAAS;EAGpC,MAAM,eAAwC;GAC5C,KAAK,EAAE,KAAK,IAAI,KAAK;GACrB,WAAW,EAAE,KAAK,IAAI,SAAS;GAC/B,SAAS,EAAE,KAAK,IAAI,WAAW;GAChC;AAED,MAAI,YACF,cAAa,YAAY,YAAY,IAAI,YAAY;EAGvD,MAAM,UAAU,MAAM,IAAI,WAAW,QAAQ,aAAa;AAC1D,MAAI,SAAS;GACX,MAAM,MAAM,gDAAgD,QAAQ,KAAK,KAAK,IAAI,KAAK,QAAQ,UAAU,CAAC,aAAa,CAAC,MAAM,IAAI,CAAC,GAAG,KAAK,IAAI,KAAK,QAAQ,QAAQ,CAAC,aAAa,CAAC,MAAM,IAAI,CAAC,GAAG;AACjM,OAAI,WAAW,aAAa,KAAK,IAAI,WAAW,UAAU;;GAE5D;AAEF,QAAO"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { a as SchemaOptions, r as JournalSchemaOptions, t as AccountingEngineConfig } from "./engine-Cd73EOT6.mjs";
|
|
2
|
+
import mongoose from "mongoose";
|
|
3
|
+
|
|
4
|
+
//#region src/schemas/account.schema.d.ts
|
|
5
|
+
declare function createAccountSchema(config: AccountingEngineConfig, options?: SchemaOptions): mongoose.Schema<any, mongoose.Model<any, any, any, any, any, any, any>, {}, {}, {}, {}, {
|
|
6
|
+
timestamps: true;
|
|
7
|
+
}, any, any, unknown, {
|
|
8
|
+
[x: string]: any;
|
|
9
|
+
} & Required<{
|
|
10
|
+
_id: unknown;
|
|
11
|
+
}> & {
|
|
12
|
+
__v: number;
|
|
13
|
+
}>;
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region src/schemas/journal-entry.schema.d.ts
|
|
16
|
+
declare function createJournalEntrySchema(config: AccountingEngineConfig, accountModelName: string, options?: JournalSchemaOptions): mongoose.Schema<any, mongoose.Model<any, any, any, any, any, any, any>, {}, {}, {}, {}, {
|
|
17
|
+
timestamps: true;
|
|
18
|
+
}, any, any, unknown, {
|
|
19
|
+
[x: string]: any;
|
|
20
|
+
} & Required<{
|
|
21
|
+
_id: unknown;
|
|
22
|
+
}> & {
|
|
23
|
+
__v: number;
|
|
24
|
+
}>;
|
|
25
|
+
//#endregion
|
|
26
|
+
//#region src/schemas/fiscal-period.schema.d.ts
|
|
27
|
+
declare function createFiscalPeriodSchema(config: AccountingEngineConfig, options?: SchemaOptions): mongoose.Schema<any, mongoose.Model<any, any, any, any, any, any, any>, {}, {}, {}, {}, {
|
|
28
|
+
timestamps: true;
|
|
29
|
+
}, any, any, unknown, {
|
|
30
|
+
[x: string]: any;
|
|
31
|
+
} & Required<{
|
|
32
|
+
_id: unknown;
|
|
33
|
+
}> & {
|
|
34
|
+
__v: number;
|
|
35
|
+
}>;
|
|
36
|
+
//#endregion
|
|
37
|
+
export { createJournalEntrySchema as n, createAccountSchema as r, createFiscalPeriodSchema as t };
|
|
38
|
+
//# sourceMappingURL=fiscal-period.schema-DI2scngu.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fiscal-period.schema-DI2scngu.d.mts","names":[],"sources":["../src/schemas/account.schema.ts","../src/schemas/journal-entry.schema.ts","../src/schemas/fiscal-period.schema.ts"],"mappings":";;;;iBAagB,mBAAA,CACd,MAAA,EAAQ,sBAAA,EACR,OAAA,GAAS,aAAA,GAAkB,QAAA,CAAA,MAAA,MAAA,QAAA,CAAA,KAAA;;;;;;;;;;;iBCCb,wBAAA,CACd,MAAA,EAAQ,sBAAA,EACR,gBAAA,UACA,OAAA,GAAS,oBAAA,GAAyB,QAAA,CAAA,MAAA,MAAA,QAAA,CAAA,KAAA;;;;;;;;;;;iBCTpB,wBAAA,CACd,MAAA,EAAQ,sBAAA,EACR,OAAA,GAAS,aAAA,GAAkB,QAAA,CAAA,MAAA,MAAA,QAAA,CAAA,KAAA"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Model } from "mongoose";
|
|
2
|
+
|
|
3
|
+
//#region src/plugins/double-entry.plugin.d.ts
|
|
4
|
+
/** Minimal interface matching @classytic/mongokit RepositoryInstance */
|
|
5
|
+
interface RepositoryInstance$2 {
|
|
6
|
+
on(event: string, listener: (data: unknown) => void | Promise<void>): unknown;
|
|
7
|
+
}
|
|
8
|
+
interface DoubleEntryPluginOptions {
|
|
9
|
+
/** Only enforce on posted entries (default: true) */
|
|
10
|
+
onlyOnPost?: boolean;
|
|
11
|
+
/** Mongoose model — required to validate partial updates that only set state */
|
|
12
|
+
JournalEntryModel?: Model<unknown>;
|
|
13
|
+
/** Account model — when provided, posted creates verify account existence + tenant scoping */
|
|
14
|
+
AccountModel?: Model<unknown>;
|
|
15
|
+
/** Multi-tenant org field name (e.g. 'business'). Required for tenant-account integrity checks. */
|
|
16
|
+
orgField?: string;
|
|
17
|
+
}
|
|
18
|
+
declare function doubleEntryPlugin(options?: DoubleEntryPluginOptions): {
|
|
19
|
+
name: string;
|
|
20
|
+
apply(repo: RepositoryInstance$2): void;
|
|
21
|
+
};
|
|
22
|
+
//#endregion
|
|
23
|
+
//#region src/plugins/fiscal-lock.plugin.d.ts
|
|
24
|
+
/** Minimal interface matching @classytic/mongokit RepositoryInstance */
|
|
25
|
+
interface RepositoryInstance$1 {
|
|
26
|
+
on(event: string, listener: (data: unknown) => void | Promise<void>): unknown;
|
|
27
|
+
}
|
|
28
|
+
interface FiscalLockPluginOptions {
|
|
29
|
+
/** Mongoose model for fiscal periods */
|
|
30
|
+
FiscalPeriodModel: Model<unknown>;
|
|
31
|
+
/** Mongoose model for journal entries — needed to look up persisted date on partial updates */
|
|
32
|
+
JournalEntryModel?: Model<unknown>;
|
|
33
|
+
/** Organization field name (for multi-tenant) */
|
|
34
|
+
orgField?: string;
|
|
35
|
+
}
|
|
36
|
+
declare function fiscalLockPlugin(options: FiscalLockPluginOptions): {
|
|
37
|
+
name: string;
|
|
38
|
+
apply(repo: RepositoryInstance$1): void;
|
|
39
|
+
};
|
|
40
|
+
//#endregion
|
|
41
|
+
//#region src/plugins/idempotency.plugin.d.ts
|
|
42
|
+
/** Minimal interface matching @classytic/mongokit RepositoryInstance */
|
|
43
|
+
interface RepositoryInstance {
|
|
44
|
+
on(event: string, listener: (data: unknown) => void | Promise<void>): unknown;
|
|
45
|
+
}
|
|
46
|
+
interface IdempotencyPluginOptions {
|
|
47
|
+
/** Mongoose model for journal entries */
|
|
48
|
+
JournalEntryModel: Model<unknown>;
|
|
49
|
+
/** Multi-tenant org field name */
|
|
50
|
+
orgField?: string;
|
|
51
|
+
}
|
|
52
|
+
declare function idempotencyPlugin(options: IdempotencyPluginOptions): {
|
|
53
|
+
name: string;
|
|
54
|
+
apply(repo: RepositoryInstance): void;
|
|
55
|
+
};
|
|
56
|
+
//#endregion
|
|
57
|
+
export { DoubleEntryPluginOptions as a, fiscalLockPlugin as i, idempotencyPlugin as n, doubleEntryPlugin as o, FiscalLockPluginOptions as r, IdempotencyPluginOptions as t };
|
|
58
|
+
//# sourceMappingURL=idempotency.plugin-BESs9YPD.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"idempotency.plugin-BESs9YPD.d.mts","names":[],"sources":["../src/plugins/double-entry.plugin.ts","../src/plugins/fiscal-lock.plugin.ts","../src/plugins/idempotency.plugin.ts"],"mappings":";;;;UAaU,oBAAA;EACR,EAAA,CAAG,KAAA,UAAe,QAAA,GAAW,IAAA,qBAAyB,OAAA;AAAA;AAAA,UAGvC,wBAAA;EAAA;EAEf,UAAA;;EAEA,iBAAA,GAAoB,KAAA;EAFpB;EAIA,YAAA,GAAe,KAAA;EAFK;EAIpB,QAAA;AAAA;AAAA,iBAGc,iBAAA,CAAkB,OAAA,GAAS,wBAAA;;cAyC3B,oBAAA;AAAA;;;;UCxDN,oBAAA;EACR,EAAA,CAAG,KAAA,UAAe,QAAA,GAAW,IAAA,qBAAyB,OAAA;AAAA;AAAA,UAGvC,uBAAA;EDAA;ECEf,iBAAA,EAAmB,KAAA;;EAEnB,iBAAA,GAAoB,KAAA;EDFpB;ECIA,QAAA;AAAA;AAAA,iBAGc,gBAAA,CAAiB,OAAA,EAAS,uBAAA;;cAK1B,oBAAA;AAAA;;;;UCpBN,kBAAA;EACR,EAAA,CAAG,KAAA,UAAe,QAAA,GAAW,IAAA,qBAAyB,OAAA;AAAA;AAAA,UAGvC,wBAAA;EFDoD;EEGnE,iBAAA,EAAmB,KAAA;EFAJ;EEEf,QAAA;AAAA;AAAA,iBAGc,iBAAA,CAAkB,OAAA,EAAS,wBAAA;;cAK3B,kBAAA;AAAA"}
|