@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.
Files changed (66) hide show
  1. package/README.md +161 -64
  2. package/dist/{account.repository-kDKwDt0I.mjs → account.repository-BpkSd6q3.mjs} +189 -38
  3. package/dist/categories-CclX7Q94.mjs +0 -2
  4. package/dist/core-8Xfnpn6g.d.mts +1 -2
  5. package/dist/country/index.d.mts +1 -1
  6. package/dist/country/index.mjs +0 -2
  7. package/dist/currencies-4WAbFRlw.d.mts +1 -2
  8. package/dist/currencies-W8kQAkm0.mjs +0 -2
  9. package/dist/{idempotency.plugin-v9NQ_ta-.mjs → date-lock.plugin-eYAJ9h_u.mjs} +49 -9
  10. package/dist/{engine-BzBMpWuy.d.mts → engine-Cn-9yerQ.d.mts} +11 -7
  11. package/dist/errors-B7yC-Jfw.mjs +0 -2
  12. package/dist/exports-I5Xkq-9_.mjs +0 -2
  13. package/dist/{fiscal-close-L631E3De.mjs → fiscal-close-B6LhQ10f.mjs} +737 -20
  14. package/dist/fiscal-period.schema-BMnlI9H5.d.mts +103 -0
  15. package/dist/{idempotency.plugin-CPxPt4vX.d.mts → idempotency.plugin-B_CNsInz.d.mts} +19 -17
  16. package/dist/index-BPukb3L8.d.mts +1 -2
  17. package/dist/{index-ZnSiqHYV.d.mts → index-CxZqRaOU.d.mts} +20 -6
  18. package/dist/index.d.mts +248 -26
  19. package/dist/index.mjs +119 -21
  20. package/dist/journals-oH-FK3g8.mjs +0 -2
  21. package/dist/{logger-UbTdBb1x.d.mts → logger-CbHWZl7v.d.mts} +1 -2
  22. package/dist/money.d.mts +1 -2
  23. package/dist/money.mjs +3 -3
  24. package/dist/plugins/index.d.mts +38 -2
  25. package/dist/plugins/index.mjs +57 -2
  26. package/dist/reconciliation.repository-CW4-8q90.d.mts +135 -0
  27. package/dist/{fiscal-period.schema-BQ5wsAq3.mjs → reconciliation.schema-BuetvZTd.mjs} +168 -24
  28. package/dist/reports/index.d.mts +2 -2
  29. package/dist/reports/index.mjs +2 -2
  30. package/dist/repositories/index.d.mts +2 -2
  31. package/dist/repositories/index.mjs +2 -2
  32. package/dist/revaluation-D9x0NE8w.d.mts +530 -0
  33. package/dist/schemas/index.d.mts +71 -2
  34. package/dist/schemas/index.mjs +2 -2
  35. package/dist/tenant-guard-Fm6AID_6.mjs +13 -0
  36. package/docs/reports.md +1 -1
  37. package/package.json +2 -2
  38. package/dist/account.repository-C7gwFLfM.d.mts +0 -29
  39. package/dist/account.repository-C7gwFLfM.d.mts.map +0 -1
  40. package/dist/account.repository-kDKwDt0I.mjs.map +0 -1
  41. package/dist/categories-CclX7Q94.mjs.map +0 -1
  42. package/dist/core-8Xfnpn6g.d.mts.map +0 -1
  43. package/dist/country/index.mjs.map +0 -1
  44. package/dist/currencies-4WAbFRlw.d.mts.map +0 -1
  45. package/dist/currencies-W8kQAkm0.mjs.map +0 -1
  46. package/dist/engine-BzBMpWuy.d.mts.map +0 -1
  47. package/dist/errors-B7yC-Jfw.mjs.map +0 -1
  48. package/dist/exports-I5Xkq-9_.mjs.map +0 -1
  49. package/dist/fiscal-close-L631E3De.mjs.map +0 -1
  50. package/dist/fiscal-close-dNlzB37y.d.mts +0 -270
  51. package/dist/fiscal-close-dNlzB37y.d.mts.map +0 -1
  52. package/dist/fiscal-period.schema-BQ5wsAq3.mjs.map +0 -1
  53. package/dist/fiscal-period.schema-BRdKAjrr.d.mts +0 -38
  54. package/dist/fiscal-period.schema-BRdKAjrr.d.mts.map +0 -1
  55. package/dist/idempotency.plugin-CPxPt4vX.d.mts.map +0 -1
  56. package/dist/idempotency.plugin-v9NQ_ta-.mjs.map +0 -1
  57. package/dist/index-BPukb3L8.d.mts.map +0 -1
  58. package/dist/index-ZnSiqHYV.d.mts.map +0 -1
  59. package/dist/index.d.mts.map +0 -1
  60. package/dist/index.mjs.map +0 -1
  61. package/dist/journals-oH-FK3g8.mjs.map +0 -1
  62. package/dist/logger-UbTdBb1x.d.mts.map +0 -1
  63. package/dist/money.d.mts.map +0 -1
  64. package/dist/money.mjs.map +0 -1
  65. package/dist/session-Ba8E3Ufa.mjs +0 -84
  66. package/dist/session-Ba8E3Ufa.mjs.map +0 -1
@@ -70,9 +70,8 @@ function createAccountSchema(config, options = {}) {
70
70
  };
71
71
  const schema = new mongoose.Schema(fields, { timestamps: true });
72
72
  schema.pre("validate", function() {
73
- const doc = this;
74
- if (!doc.accountNumber && doc.accountTypeCode) doc.accountNumber = doc.accountTypeCode;
75
- if (!doc.name && doc.accountTypeCode) doc.name = country.getAccountType(doc.accountTypeCode)?.name ?? doc.accountTypeCode;
73
+ if (!this.accountNumber && this.accountTypeCode) this.accountNumber = this.accountTypeCode;
74
+ if (!this.name && this.accountTypeCode) this.name = country.getAccountType(this.accountTypeCode)?.name ?? this.accountTypeCode;
76
75
  });
77
76
  if (indexes) if (multiTenant) {
78
77
  const org = multiTenant.orgField;
@@ -275,22 +274,21 @@ function createJournalEntrySchema(config, accountModelName, options = {}) {
275
274
  };
276
275
  const schema = new mongoose.Schema(fields, { timestamps: true });
277
276
  schema.pre("validate", function() {
278
- const doc = this;
279
- for (const item of doc.journalItems) if (!item.date) item.date = doc.date;
280
- for (let i = 0; i < doc.journalItems.length; i++) {
281
- const d = doc.journalItems[i].debit || 0;
282
- const c = doc.journalItems[i].credit || 0;
277
+ for (const item of this.journalItems) if (!item.date) item.date = this.date;
278
+ for (let i = 0; i < this.journalItems.length; i++) {
279
+ const d = this.journalItems[i].debit ?? 0;
280
+ const c = this.journalItems[i].credit ?? 0;
283
281
  if (d > 0 && c > 0) throw new Error(`Journal item at index ${i}: cannot have both debit (${d}) and credit (${c}) greater than zero`);
284
- 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)`);
282
+ if (this.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)`);
285
283
  }
286
- const totalDebit = doc.journalItems.reduce((s, i) => s + (i.debit || 0), 0);
287
- const totalCredit = doc.journalItems.reduce((s, i) => s + (i.credit || 0), 0);
288
- if (doc.state === "posted") {
289
- if (doc.journalItems.length < 2) throw new Error("Posted entries must have at least 2 journal items");
284
+ const totalDebit = this.journalItems.reduce((s, item) => s + (item.debit ?? 0), 0);
285
+ const totalCredit = this.journalItems.reduce((s, item) => s + (item.credit ?? 0), 0);
286
+ if (this.state === "posted") {
287
+ if (this.journalItems.length < 2) throw new Error("Posted entries must have at least 2 journal items");
290
288
  if (totalDebit !== totalCredit) throw new Error("Total debit must equal total credit for posted entries");
291
289
  }
292
- doc.totalDebit = totalDebit;
293
- doc.totalCredit = totalCredit;
290
+ this.totalDebit = totalDebit;
291
+ this.totalCredit = totalCredit;
294
292
  });
295
293
  if (autoReference) {
296
294
  const generateReferenceNumber = async (doc, Model, session) => {
@@ -312,12 +310,11 @@ function createJournalEntrySchema(config, accountModelName, options = {}) {
312
310
  return `${prefix}${String(seq).padStart(4, "0")}`;
313
311
  };
314
312
  schema.pre("save", async function() {
315
- const doc = this;
316
- if (doc.isModified("journalType")) doc.referenceNumber = void 0;
317
- if (!doc.referenceNumber) {
318
- const session = doc.$session?.() ?? null;
319
- const Model = doc.constructor;
320
- doc.referenceNumber = await generateReferenceNumber(doc, Model, session);
313
+ if (this.isModified("journalType")) this.referenceNumber = void 0;
314
+ if (!this.referenceNumber) {
315
+ const session = this.$session?.() ?? null;
316
+ const Model = this.constructor;
317
+ this.referenceNumber = await generateReferenceNumber(this, Model, session);
321
318
  }
322
319
  });
323
320
  const MAX_REF_RETRIES = 3;
@@ -516,6 +513,153 @@ function createFiscalPeriodSchema(config, options = {}) {
516
513
  return schema;
517
514
  }
518
515
  //#endregion
519
- export { createJournalEntrySchema as n, createAccountSchema as r, createFiscalPeriodSchema as t };
520
-
521
- //# sourceMappingURL=fiscal-period.schema-BQ5wsAq3.mjs.map
516
+ //#region src/schemas/budget.schema.ts
517
+ /**
518
+ * Budget Schema Factory
519
+ *
520
+ * Creates a Mongoose schema for budget records.
521
+ * Each record represents a budgeted amount for an account over a specific period.
522
+ * All monetary amounts are in integer cents.
523
+ */
524
+ function createBudgetSchema(config, options = {}) {
525
+ const { multiTenant } = config;
526
+ const { indexes = true, extraFields = {}, extraIndexes = [] } = options;
527
+ const fields = {
528
+ account: {
529
+ type: mongoose.Schema.Types.ObjectId,
530
+ ref: "Account",
531
+ required: true
532
+ },
533
+ periodStart: {
534
+ type: Date,
535
+ required: true
536
+ },
537
+ periodEnd: {
538
+ type: Date,
539
+ required: true
540
+ },
541
+ amount: {
542
+ type: Number,
543
+ required: true,
544
+ validate: {
545
+ validator: (v) => Number.isInteger(v),
546
+ message: "amount must be an integer (cents)."
547
+ }
548
+ },
549
+ label: {
550
+ type: String,
551
+ default: null
552
+ },
553
+ ...extraFields
554
+ };
555
+ if (multiTenant) fields[multiTenant.orgField] = {
556
+ type: mongoose.Schema.Types.ObjectId,
557
+ ref: multiTenant.orgRef,
558
+ required: true
559
+ };
560
+ const schema = new mongoose.Schema(fields, { timestamps: true });
561
+ schema.pre("validate", function() {
562
+ const doc = this;
563
+ if (doc.periodStart && doc.periodEnd && doc.periodEnd <= doc.periodStart) doc.invalidate("periodEnd", "periodEnd must be after periodStart.", doc.periodEnd, "periodEnd");
564
+ });
565
+ if (indexes) if (multiTenant) {
566
+ const org = multiTenant.orgField;
567
+ schema.index({
568
+ [org]: 1,
569
+ account: 1,
570
+ periodStart: 1,
571
+ periodEnd: 1
572
+ }, { unique: true });
573
+ schema.index({
574
+ [org]: 1,
575
+ periodStart: 1,
576
+ periodEnd: 1
577
+ });
578
+ } else {
579
+ schema.index({
580
+ account: 1,
581
+ periodStart: 1,
582
+ periodEnd: 1
583
+ }, { unique: true });
584
+ schema.index({
585
+ periodStart: 1,
586
+ periodEnd: 1
587
+ });
588
+ }
589
+ for (const idx of extraIndexes) schema.index(idx.fields, idx.options);
590
+ return schema;
591
+ }
592
+ //#endregion
593
+ //#region src/schemas/reconciliation.schema.ts
594
+ /**
595
+ * Reconciliation Schema Factory
596
+ *
597
+ * Creates a Mongoose schema for reconciliation records that link matched
598
+ * debit/credit journal items. Used to track which journal entries have been
599
+ * reconciled against each other for a given account.
600
+ */
601
+ function createReconciliationSchema(config, accountModelName, journalEntryModelName, options = {}) {
602
+ const { multiTenant } = config;
603
+ const { indexes = true, extraFields = {}, extraIndexes = [] } = options;
604
+ const fields = {
605
+ account: {
606
+ type: mongoose.Schema.Types.ObjectId,
607
+ ref: accountModelName,
608
+ required: true
609
+ },
610
+ journalEntryIds: {
611
+ type: [{
612
+ type: mongoose.Schema.Types.ObjectId,
613
+ ref: journalEntryModelName
614
+ }],
615
+ required: true,
616
+ validate: {
617
+ validator: (v) => Array.isArray(v) && v.length > 0,
618
+ message: "journalEntryIds must contain at least one entry."
619
+ }
620
+ },
621
+ debitTotal: {
622
+ type: Number,
623
+ required: true
624
+ },
625
+ creditTotal: {
626
+ type: Number,
627
+ required: true
628
+ },
629
+ difference: {
630
+ type: Number,
631
+ default: 0
632
+ },
633
+ note: { type: String },
634
+ reconciledBy: { type: String },
635
+ reconciledAt: {
636
+ type: Date,
637
+ default: Date.now
638
+ },
639
+ ...extraFields
640
+ };
641
+ if (multiTenant) fields[multiTenant.orgField] = {
642
+ type: mongoose.Schema.Types.ObjectId,
643
+ ref: multiTenant.orgRef,
644
+ required: true
645
+ };
646
+ const schema = new mongoose.Schema(fields, { timestamps: true });
647
+ if (indexes) {
648
+ if (multiTenant) {
649
+ const org = multiTenant.orgField;
650
+ schema.index({
651
+ [org]: 1,
652
+ account: 1,
653
+ reconciledAt: 1
654
+ });
655
+ } else schema.index({
656
+ account: 1,
657
+ reconciledAt: 1
658
+ });
659
+ schema.index({ journalEntryIds: 1 });
660
+ }
661
+ for (const idx of extraIndexes) schema.index(idx.fields, idx.options);
662
+ return schema;
663
+ }
664
+ //#endregion
665
+ export { createAccountSchema as a, createJournalEntrySchema as i, createBudgetSchema as n, createFiscalPeriodSchema as r, createReconciliationSchema as t };
@@ -1,2 +1,2 @@
1
- import { a as reopenFiscalPeriod, c as GeneralLedgerOptions, d as generateIncomeStatement, f as BalanceSheetOptions, h as generateTrialBalance, i as closeFiscalPeriod, l as generateGeneralLedger, m as TrialBalanceOptions, n as FiscalCloseResult, o as CashFlowOptions, p as generateBalanceSheet, r as FiscalReopenResult, s as generateCashFlow, t as FiscalCloseOptions, u as IncomeStatementOptions } from "../fiscal-close-dNlzB37y.mjs";
2
- export { type BalanceSheetOptions, type CashFlowOptions, type FiscalCloseOptions, type FiscalCloseResult, type FiscalReopenResult, type GeneralLedgerOptions, type IncomeStatementOptions, type TrialBalanceOptions, closeFiscalPeriod, generateBalanceSheet, generateCashFlow, generateGeneralLedger, generateIncomeStatement, generateTrialBalance, reopenFiscalPeriod };
1
+ import { $ as BudgetVsActualReport, A as generateGeneralLedger, C as FiscalCloseResult, D as CashFlowOptions, E as reopenFiscalPeriod, F as TrialBalanceOptions, I as generateTrialBalance, M as generateIncomeStatement, N as BalanceSheetOptions, O as generateCashFlow, P as generateBalanceSheet, Q as BudgetVsActualParams, S as FiscalCloseOptions, T as closeFiscalPeriod, Z as BudgetVsActualOptions, _ as DimensionBreakdownOptions, b as DimensionBreakdownRow, d as AgedBalanceParams, et as BudgetVsActualRow, f as AgedBalanceReport, g as generateAgedBalance, h as DEFAULT_BUCKETS, i as generateRevaluation, j as IncomeStatementOptions, k as GeneralLedgerOptions, m as AgedBucketConfig, n as RevaluationParams, p as AgedBalanceRow, r as RevaluationReport, t as RevaluationOptions, tt as generateBudgetVsActual, u as AgedBalanceOptions, v as DimensionBreakdownParams, w as FiscalReopenResult, x as generateDimensionBreakdown, y as DimensionBreakdownReport } from "../revaluation-D9x0NE8w.mjs";
2
+ export { type AgedBalanceOptions, type AgedBalanceParams, type AgedBalanceReport, type AgedBalanceRow, type AgedBucketConfig, type BalanceSheetOptions, type BudgetVsActualOptions, type BudgetVsActualParams, type BudgetVsActualReport, type BudgetVsActualRow, type CashFlowOptions, DEFAULT_BUCKETS, type DimensionBreakdownOptions, type DimensionBreakdownParams, type DimensionBreakdownReport, type DimensionBreakdownRow, type FiscalCloseOptions, type FiscalCloseResult, type FiscalReopenResult, type GeneralLedgerOptions, type IncomeStatementOptions, type RevaluationOptions, type RevaluationParams, type RevaluationReport, type TrialBalanceOptions, closeFiscalPeriod, generateAgedBalance, generateBalanceSheet, generateBudgetVsActual, generateCashFlow, generateDimensionBreakdown, generateGeneralLedger, generateIncomeStatement, generateRevaluation, generateTrialBalance, reopenFiscalPeriod };
@@ -1,2 +1,2 @@
1
- import { a as generateIncomeStatement, d as generateTrialBalance, i as generateGeneralLedger, n as reopenFiscalPeriod, o as generateBalanceSheet, r as generateCashFlow, t as closeFiscalPeriod } from "../fiscal-close-L631E3De.mjs";
2
- export { closeFiscalPeriod, generateBalanceSheet, generateCashFlow, generateGeneralLedger, generateIncomeStatement, generateTrialBalance, reopenFiscalPeriod };
1
+ import { d as DEFAULT_BUCKETS, f as generateAgedBalance, g as generateBalanceSheet, h as generateIncomeStatement, l as generateBudgetVsActual, m as generateGeneralLedger, n as reopenFiscalPeriod, o as generateRevaluation, p as generateCashFlow, t as closeFiscalPeriod, u as generateDimensionBreakdown, x as generateTrialBalance } from "../fiscal-close-B6LhQ10f.mjs";
2
+ export { DEFAULT_BUCKETS, closeFiscalPeriod, generateAgedBalance, generateBalanceSheet, generateBudgetVsActual, generateCashFlow, generateDimensionBreakdown, generateGeneralLedger, generateIncomeStatement, generateRevaluation, generateTrialBalance, reopenFiscalPeriod };
@@ -1,2 +1,2 @@
1
- import { n as wireJournalEntryMethods, t as wireAccountMethods } from "../account.repository-C7gwFLfM.mjs";
2
- export { wireAccountMethods, wireJournalEntryMethods };
1
+ import { n as wireAccountMethods, r as wireJournalEntryMethods, t as wireReconciliationMethods } from "../reconciliation.repository-CW4-8q90.mjs";
2
+ export { wireAccountMethods, wireJournalEntryMethods, wireReconciliationMethods };
@@ -1,2 +1,2 @@
1
- import { n as wireJournalEntryMethods, t as wireAccountMethods } from "../account.repository-kDKwDt0I.mjs";
2
- export { wireAccountMethods, wireJournalEntryMethods };
1
+ import { n as wireJournalEntryMethods, r as wireReconciliationMethods, t as wireAccountMethods } from "../account.repository-BpkSd6q3.mjs";
2
+ export { wireAccountMethods, wireJournalEntryMethods, wireReconciliationMethods };