@classytic/ledger 0.5.1 → 0.6.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.
@@ -1,4 +1,4 @@
1
- import { n as Errors } from "./errors-BmRjW38t.mjs";
1
+ import { n as Errors } from "./errors-CSDQPNyt.mjs";
2
2
  import { i as extractMainType } from "./categories-BkKdv16V.mjs";
3
3
  import mongoose from "mongoose";
4
4
  //#region src/utils/tenant-guard.ts
@@ -1519,7 +1519,7 @@ async function closeFiscalPeriod(opts, params) {
1519
1519
  if (orgField && organizationId) periodQuery[orgField] = organizationId;
1520
1520
  const period = await FiscalPeriodModel.findOne(periodQuery, null, queryOpts).lean();
1521
1521
  if (!period) throw Errors.notFound("Fiscal period not found");
1522
- if (period.closed) throw Errors.fiscal("Fiscal period is already closed");
1522
+ if (period.closed) throw Errors.locked("fiscal", "Fiscal period is already closed");
1523
1523
  const startDate = period.startDate;
1524
1524
  const endDate = period.endDate;
1525
1525
  const accountQuery = { active: true };
@@ -1538,7 +1538,7 @@ async function closeFiscalPeriod(opts, params) {
1538
1538
  isIncome: at.category === "Income Statement-Income"
1539
1539
  });
1540
1540
  }
1541
- if (!retainedEarningsId) throw Errors.fiscal(`Retained earnings account (code: ${retainedEarningsAccountCode}) not found. Create this account before closing the fiscal period.`);
1541
+ if (!retainedEarningsId) throw Errors.locked("fiscal", `Retained earnings account (code: ${retainedEarningsAccountCode}) not found. Create this account before closing the fiscal period.`);
1542
1542
  const baseMatch = {
1543
1543
  state: "posted",
1544
1544
  date: {
@@ -1630,13 +1630,13 @@ async function reopenFiscalPeriod(opts, params) {
1630
1630
  if (orgField && organizationId) periodQuery[orgField] = organizationId;
1631
1631
  const period = await FiscalPeriodModel.findOne(periodQuery, null, queryOpts).lean();
1632
1632
  if (!period) throw Errors.notFound("Fiscal period not found");
1633
- if (!period.closed) throw Errors.fiscal("Fiscal period is not closed");
1633
+ if (!period.closed) throw Errors.locked("fiscal", "Fiscal period is not closed");
1634
1634
  const laterQuery = {
1635
1635
  closed: true,
1636
1636
  startDate: { $gt: period.endDate }
1637
1637
  };
1638
1638
  if (orgField && organizationId) laterQuery[orgField] = organizationId;
1639
- if (await FiscalPeriodModel.findOne(laterQuery, null, queryOpts).lean()) throw Errors.fiscal("Cannot reopen: a later fiscal period is already closed. Reopen later periods first.");
1639
+ if (await FiscalPeriodModel.findOne(laterQuery, null, queryOpts).lean()) throw Errors.locked("fiscal", "Cannot reopen: a later fiscal period is already closed. Reopen later periods first.");
1640
1640
  const closingEntryId = period.closingEntryId ?? null;
1641
1641
  if (closingEntryId) await JournalEntryModel.findByIdAndDelete(closingEntryId, queryOpts);
1642
1642
  const reopenedAt = /* @__PURE__ */ new Date();
@@ -1660,4 +1660,141 @@ async function reopenFiscalPeriod(opts, params) {
1660
1660
  }
1661
1661
  }
1662
1662
  //#endregion
1663
- export { DEFAULT_BUCKETS as C, isVirtualTaxAccount as S, requireOrgScope as T, getDateRange as _, defaultLogger as a, calculateTotal as b, buildRevaluationEntry as c, generateGeneralLedger as d, generateDimensionBreakdown as f, buildItemFilters as g, generateBalanceSheet as h, finalizeSession as i, computeRevaluation as l, generateBudgetVsActual as m, reopenFiscalPeriod as n, generateTrialBalance as o, generateCashFlow as p, acquireSession as r, generateRevaluation as s, closeFiscalPeriod as t, generateIncomeStatement as u, getFiscalYearStart as v, generateAgedBalance as w, computeEndingBalance as x, buildAccountTypeMap as y };
1663
+ //#region src/reports/partner-ledger.ts
1664
+ async function generatePartnerLedger(opts, params) {
1665
+ const { AccountModel, JournalEntryModel, orgField } = opts;
1666
+ const { controlAccountId, partnerField = "partnerId", partnerId, startDate, endDate, includeMatched = true, buckets = DEFAULT_BUCKETS } = params;
1667
+ requireOrgScope(orgField, params.organizationId);
1668
+ const accountDoc = await AccountModel.findById(controlAccountId).lean();
1669
+ const openingMatch = {
1670
+ state: "posted",
1671
+ date: { $lt: startDate }
1672
+ };
1673
+ if (orgField && params.organizationId) openingMatch[orgField] = params.organizationId;
1674
+ const openingPipeline = [
1675
+ { $match: openingMatch },
1676
+ { $unwind: "$journalItems" },
1677
+ { $match: {
1678
+ "journalItems.account": controlAccountId,
1679
+ [`journalItems.${partnerField}`]: partnerId
1680
+ } },
1681
+ { $group: {
1682
+ _id: null,
1683
+ debit: { $sum: { $ifNull: ["$journalItems.debit", 0] } },
1684
+ credit: { $sum: { $ifNull: ["$journalItems.credit", 0] } }
1685
+ } }
1686
+ ];
1687
+ const openingResult = await JournalEntryModel.aggregate(openingPipeline);
1688
+ const openingBalance = (openingResult[0]?.debit ?? 0) - (openingResult[0]?.credit ?? 0);
1689
+ const periodMatch = {
1690
+ state: "posted",
1691
+ date: {
1692
+ $gte: startDate,
1693
+ $lte: endDate
1694
+ }
1695
+ };
1696
+ if (orgField && params.organizationId) periodMatch[orgField] = params.organizationId;
1697
+ const itemMatch = {
1698
+ "journalItems.account": controlAccountId,
1699
+ [`journalItems.${partnerField}`]: partnerId
1700
+ };
1701
+ if (!includeMatched) itemMatch.$or = [{ "journalItems.matchingNumber": null }, { "journalItems.matchingNumber": { $exists: false } }];
1702
+ const linePipeline = [
1703
+ { $match: periodMatch },
1704
+ { $addFields: { journalItems: { $map: {
1705
+ input: { $range: [0, { $size: "$journalItems" }] },
1706
+ as: "idx",
1707
+ in: { $mergeObjects: [{ $arrayElemAt: ["$journalItems", "$$idx"] }, { _itemIndex: "$$idx" }] }
1708
+ } } } },
1709
+ { $unwind: "$journalItems" },
1710
+ { $match: itemMatch },
1711
+ { $project: {
1712
+ _id: 0,
1713
+ entry: "$_id",
1714
+ itemIndex: "$journalItems._itemIndex",
1715
+ date: { $ifNull: ["$journalItems.date", "$date"] },
1716
+ referenceNumber: 1,
1717
+ label: "$journalItems.label",
1718
+ debit: { $ifNull: ["$journalItems.debit", 0] },
1719
+ credit: { $ifNull: ["$journalItems.credit", 0] },
1720
+ signedDelta: { $subtract: [{ $ifNull: ["$journalItems.debit", 0] }, { $ifNull: ["$journalItems.credit", 0] }] },
1721
+ matchingNumber: "$journalItems.matchingNumber",
1722
+ maturityDate: "$journalItems.maturityDate"
1723
+ } },
1724
+ { $sort: {
1725
+ date: 1,
1726
+ entry: 1,
1727
+ itemIndex: 1
1728
+ } },
1729
+ { $setWindowFields: {
1730
+ sortBy: {
1731
+ date: 1,
1732
+ entry: 1,
1733
+ itemIndex: 1
1734
+ },
1735
+ output: { runningDelta: {
1736
+ $sum: "$signedDelta",
1737
+ window: { documents: ["unbounded", "current"] }
1738
+ } }
1739
+ } }
1740
+ ];
1741
+ const rawLines = await JournalEntryModel.aggregate(linePipeline);
1742
+ const endMs = endDate.getTime();
1743
+ const lines = rawLines.map((r) => {
1744
+ const matchingNumber = r.matchingNumber ?? null;
1745
+ const maturityDate = r.maturityDate ?? null;
1746
+ const daysPastDue = maturityDate ? Math.max(0, Math.floor((endMs - new Date(maturityDate).getTime()) / 864e5)) : null;
1747
+ return {
1748
+ date: r.date,
1749
+ entry: r.entry,
1750
+ itemIndex: r.itemIndex,
1751
+ referenceNumber: r.referenceNumber,
1752
+ label: r.label,
1753
+ debit: r.debit,
1754
+ credit: r.credit,
1755
+ balance: openingBalance + r.runningDelta,
1756
+ matchingNumber,
1757
+ maturityDate,
1758
+ daysPastDue,
1759
+ isMatched: matchingNumber != null
1760
+ };
1761
+ });
1762
+ const closingBalance = lines.length > 0 ? lines[lines.length - 1].balance : openingBalance;
1763
+ let openItemsTotal = 0;
1764
+ let matchedTotal = 0;
1765
+ for (const l of lines) {
1766
+ const delta = l.debit - l.credit;
1767
+ if (l.isMatched) matchedTotal += delta;
1768
+ else openItemsTotal += delta;
1769
+ }
1770
+ const agedBuckets = Object.fromEntries(buckets.map((b) => [b.label, 0]));
1771
+ for (const l of lines) {
1772
+ if (l.isMatched) continue;
1773
+ const days = l.daysPastDue ?? 0;
1774
+ const bucket = buckets.find((b) => days >= b.minDays && days < b.maxDays);
1775
+ if (bucket) agedBuckets[bucket.label] += l.debit - l.credit;
1776
+ }
1777
+ return {
1778
+ metadata: {
1779
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
1780
+ partnerId,
1781
+ controlAccount: {
1782
+ id: controlAccountId,
1783
+ name: accountDoc?.name,
1784
+ code: accountDoc?.accountNumber
1785
+ },
1786
+ period: {
1787
+ startDate: startDate.toISOString().split("T")[0],
1788
+ endDate: endDate.toISOString().split("T")[0]
1789
+ }
1790
+ },
1791
+ openingBalance,
1792
+ closingBalance,
1793
+ openItemsTotal,
1794
+ matchedTotal,
1795
+ lines,
1796
+ agedBuckets
1797
+ };
1798
+ }
1799
+ //#endregion
1800
+ export { isVirtualTaxAccount as C, requireOrgScope as E, computeEndingBalance as S, generateAgedBalance as T, buildItemFilters as _, finalizeSession as a, buildAccountTypeMap as b, generateRevaluation as c, generateIncomeStatement as d, generateGeneralLedger as f, generateBalanceSheet as g, generateBudgetVsActual as h, acquireSession as i, buildRevaluationEntry as l, generateCashFlow as m, closeFiscalPeriod as n, defaultLogger as o, generateDimensionBreakdown as p, reopenFiscalPeriod as r, generateTrialBalance as s, generatePartnerLedger as t, computeRevaluation as u, getDateRange as v, DEFAULT_BUCKETS as w, calculateTotal as x, getFiscalYearStart as y };
@@ -1,28 +1,6 @@
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-WcQLZU9n.mjs";
1
+ import { C as DoubleEntryPluginOptions, E as creditLimitPlugin, S as fxRealizationPlugin, T as CreditLimitPluginOptions, _ as LockResolver, a as DailyLockPluginOptions, b as idempotencyPlugin, c as dailyLockPlugin, d as PeriodResolverOptions, f as periodResolver, g as LockHit, h as LockAccountSelector, i as watermarkResolver, l as fiscalLockPlugin, m as CreateLockPluginOptions, o as FiscalLockPluginOptions, p as createLockPlugin, r as WatermarkResolverOptions, s as TaxLockPluginOptions, t as TaxLineGenerator, u as taxLockPlugin, v as LockResolverContext, w as doubleEntryPlugin, x as FxRealizationPluginOptions, y as IdempotencyPluginOptions } from "../tax-hooks-BnVenul5.mjs";
2
2
  import { RepositoryInstance } from "@classytic/mongokit";
3
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
4
  //#region src/plugins/tax-hook.plugin.d.ts
27
5
  interface TaxHookPluginOptions {
28
6
  /** Tax line generator — implements the tax calculation logic */
@@ -35,4 +13,4 @@ declare function taxHookPlugin(options: TaxHookPluginOptions): {
35
13
  apply(repo: RepositoryInstance): void;
36
14
  };
37
15
  //#endregion
38
- export { type DateLockPluginOptions, type DoubleEntryPluginOptions, type FiscalLockPluginOptions, type IdempotencyPluginOptions, type TaxHookPluginOptions, dateLockPlugin, doubleEntryPlugin, fiscalLockPlugin, idempotencyPlugin, taxHookPlugin };
16
+ export { type CreateLockPluginOptions, type CreditLimitPluginOptions, type DailyLockPluginOptions, type DoubleEntryPluginOptions, type FiscalLockPluginOptions, type FxRealizationPluginOptions, type IdempotencyPluginOptions, type LockAccountSelector, type LockHit, type LockResolver, type LockResolverContext, type PeriodResolverOptions, type TaxHookPluginOptions, type TaxLockPluginOptions, type WatermarkResolverOptions, createLockPlugin, creditLimitPlugin, dailyLockPlugin, doubleEntryPlugin, fiscalLockPlugin, fxRealizationPlugin, idempotencyPlugin, periodResolver, taxHookPlugin, taxLockPlugin, watermarkResolver };
@@ -1,4 +1,4 @@
1
- import { i as doubleEntryPlugin, n as idempotencyPlugin, r as fiscalLockPlugin, t as dateLockPlugin } from "../date-lock.plugin-B6WyvqNG.mjs";
1
+ import { a as taxLockPlugin, c as createLockPlugin, i as fiscalLockPlugin, l as idempotencyPlugin, n as creditLimitPlugin, o as watermarkResolver, r as dailyLockPlugin, s as periodResolver, t as fxRealizationPlugin, u as doubleEntryPlugin } from "../fx-realization.plugin-CgQFDGv2.mjs";
2
2
  //#region src/utils/tax-hooks.ts
3
3
  /**
4
4
  * Apply a tax hook to journal items.
@@ -54,4 +54,4 @@ function taxHookPlugin(options) {
54
54
  };
55
55
  }
56
56
  //#endregion
57
- export { dateLockPlugin, doubleEntryPlugin, fiscalLockPlugin, idempotencyPlugin, taxHookPlugin };
57
+ export { createLockPlugin, creditLimitPlugin, dailyLockPlugin, doubleEntryPlugin, fiscalLockPlugin, fxRealizationPlugin, idempotencyPlugin, periodResolver, taxHookPlugin, taxLockPlugin, watermarkResolver };
@@ -1,2 +1,2 @@
1
- import { $ as AgedBucketConfig, A as BudgetVsActualReport, C as DimensionBreakdownReport, D as generateCashFlow, E as CashFlowOptions, M as generateBudgetVsActual, N as BalanceSheetOptions, O as BudgetVsActualOptions, P as generateBalanceSheet, Q as AgedBalanceRow, S as DimensionBreakdownParams, T as generateDimensionBreakdown, X as AgedBalanceParams, Y as AgedBalanceOptions, Z as AgedBalanceReport, _ as FiscalCloseResult, a as RevaluationReport, b as reopenFiscalPeriod, et as DEFAULT_BUCKETS, f as IncomeStatementOptions, g as FiscalCloseOptions, h as generateGeneralLedger, i as RevaluationParams, j as BudgetVsActualRow, k as BudgetVsActualParams, m as GeneralLedgerOptions, n as generateTrialBalance, o as generateRevaluation, p as generateIncomeStatement, r as RevaluationOptions, t as TrialBalanceOptions, tt as generateAgedBalance, v as FiscalReopenResult, w as DimensionBreakdownRow, x as DimensionBreakdownOptions, y as closeFiscalPeriod } from "../trial-balance-BZ7yOOFD.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
+ import { A as generateDimensionBreakdown, C as FiscalReopenResult, D as DimensionBreakdownParams, E as DimensionBreakdownOptions, F as BudgetVsActualReport, I as BudgetVsActualRow, L as generateBudgetVsActual, M as generateCashFlow, N as BudgetVsActualOptions, O as DimensionBreakdownReport, P as BudgetVsActualParams, R as BalanceSheetOptions, S as FiscalCloseResult, T as reopenFiscalPeriod, _ as IncomeStatementOptions, a as RevaluationReport, at as DEFAULT_BUCKETS, b as generateGeneralLedger, et as AgedBalanceOptions, f as PartnerLedgerLine, g as generatePartnerLedger, h as PartnerLedgerReport, i as RevaluationParams, it as AgedBucketConfig, j as CashFlowOptions, k as DimensionBreakdownRow, m as PartnerLedgerParams, n as generateTrialBalance, nt as AgedBalanceReport, o as generateRevaluation, ot as generateAgedBalance, p as PartnerLedgerOptions, r as RevaluationOptions, rt as AgedBalanceRow, t as TrialBalanceOptions, tt as AgedBalanceParams, v as generateIncomeStatement, w as closeFiscalPeriod, x as FiscalCloseOptions, y as GeneralLedgerOptions, z as generateBalanceSheet } from "../trial-balance-s92GEvRR.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 PartnerLedgerLine, type PartnerLedgerOptions, type PartnerLedgerParams, type PartnerLedgerReport, type RevaluationOptions, type RevaluationParams, type RevaluationReport, type TrialBalanceOptions, closeFiscalPeriod, generateAgedBalance, generateBalanceSheet, generateBudgetVsActual, generateCashFlow, generateDimensionBreakdown, generateGeneralLedger, generateIncomeStatement, generatePartnerLedger, generateRevaluation, generateTrialBalance, reopenFiscalPeriod };
@@ -1,2 +1,2 @@
1
- import { C as DEFAULT_BUCKETS, d as generateGeneralLedger, f as generateDimensionBreakdown, h as generateBalanceSheet, m as generateBudgetVsActual, n as reopenFiscalPeriod, o as generateTrialBalance, p as generateCashFlow, s as generateRevaluation, t as closeFiscalPeriod, u as generateIncomeStatement, w as generateAgedBalance } from "../fiscal-close-Dk3yRT9i.mjs";
2
- export { DEFAULT_BUCKETS, closeFiscalPeriod, generateAgedBalance, generateBalanceSheet, generateBudgetVsActual, generateCashFlow, generateDimensionBreakdown, generateGeneralLedger, generateIncomeStatement, generateRevaluation, generateTrialBalance, reopenFiscalPeriod };
1
+ import { T as generateAgedBalance, c as generateRevaluation, d as generateIncomeStatement, f as generateGeneralLedger, g as generateBalanceSheet, h as generateBudgetVsActual, m as generateCashFlow, n as closeFiscalPeriod, p as generateDimensionBreakdown, r as reopenFiscalPeriod, s as generateTrialBalance, t as generatePartnerLedger, w as DEFAULT_BUCKETS } from "../partner-ledger-D9H5hegI.mjs";
2
+ export { DEFAULT_BUCKETS, closeFiscalPeriod, generateAgedBalance, generateBalanceSheet, generateBudgetVsActual, generateCashFlow, generateDimensionBreakdown, generateGeneralLedger, generateIncomeStatement, generatePartnerLedger, generateRevaluation, generateTrialBalance, reopenFiscalPeriod };