@fayz-ai/financial 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +34 -2
- package/dist/chunk-2XWEZXFT.js +2805 -0
- package/dist/chunk-2XWEZXFT.js.map +1 -0
- package/dist/chunk-4FWWKKZB.js +49 -0
- package/dist/chunk-4FWWKKZB.js.map +1 -0
- package/dist/chunk-4GXBOEI3.js +50 -0
- package/dist/chunk-4GXBOEI3.js.map +1 -0
- package/dist/chunk-4S5GK776.js +31 -0
- package/dist/chunk-4S5GK776.js.map +1 -0
- package/dist/chunk-56NQHYL7.js +20 -0
- package/dist/chunk-56NQHYL7.js.map +1 -0
- package/dist/chunk-7HISDBUG.js +84 -0
- package/dist/chunk-7HISDBUG.js.map +1 -0
- package/dist/chunk-FNXIAIUZ.js +81 -0
- package/dist/chunk-FNXIAIUZ.js.map +1 -0
- package/dist/chunk-HJPUHTI2.js +77 -0
- package/dist/chunk-HJPUHTI2.js.map +1 -0
- package/dist/chunk-IP5YH4S5.js +14 -0
- package/dist/chunk-IP5YH4S5.js.map +1 -0
- package/dist/chunk-J7BWATQU.js +10 -0
- package/dist/chunk-J7BWATQU.js.map +1 -0
- package/dist/chunk-MCSPCXQK.js +190 -0
- package/dist/chunk-MCSPCXQK.js.map +1 -0
- package/dist/chunk-T7WIM2V7.js +34 -0
- package/dist/chunk-T7WIM2V7.js.map +1 -0
- package/dist/chunk-TZZNVPBY.js +9 -0
- package/dist/chunk-TZZNVPBY.js.map +1 -0
- package/dist/chunk-UERJA7QH.js +893 -0
- package/dist/chunk-UERJA7QH.js.map +1 -0
- package/dist/chunk-XVELDCSL.js +11 -0
- package/dist/chunk-XVELDCSL.js.map +1 -0
- package/dist/chunk-YUNLQYOZ.js +26 -0
- package/dist/chunk-YUNLQYOZ.js.map +1 -0
- package/dist/chunk-ZFUQBYBG.js +124 -0
- package/dist/chunk-ZFUQBYBG.js.map +1 -0
- package/dist/data/fx-auto.d.ts +7 -0
- package/dist/data/fx-auto.d.ts.map +1 -0
- package/dist/data/fx-auto.js +3 -0
- package/dist/data/fx-auto.js.map +1 -0
- package/dist/data/idempotency.d.ts +2 -0
- package/dist/data/idempotency.d.ts.map +1 -0
- package/dist/data/idempotency.js +3 -0
- package/dist/data/idempotency.js.map +1 -0
- package/dist/data/mock.d.ts +29 -0
- package/dist/data/mock.d.ts.map +1 -0
- package/dist/data/mock.js +13 -0
- package/dist/data/mock.js.map +1 -0
- package/dist/data/provider.d.ts +265 -0
- package/dist/data/provider.d.ts.map +1 -0
- package/dist/data/provider.js +3 -0
- package/dist/data/provider.js.map +1 -0
- package/dist/data/reconcile.d.ts +37 -0
- package/dist/data/reconcile.d.ts.map +1 -0
- package/dist/data/reconcile.js +5 -0
- package/dist/data/reconcile.js.map +1 -0
- package/dist/data/supabase.d.ts +3 -0
- package/dist/data/supabase.d.ts.map +1 -0
- package/dist/data/supabase.js +16 -0
- package/dist/data/supabase.js.map +1 -0
- package/dist/data/tables.d.ts +39 -0
- package/dist/data/tables.d.ts.map +1 -0
- package/dist/data/tables.js +3 -0
- package/dist/data/tables.js.map +1 -0
- package/dist/domain/account.d.ts +66 -0
- package/dist/domain/account.d.ts.map +1 -0
- package/dist/domain/account.js +3 -0
- package/dist/domain/account.js.map +1 -0
- package/dist/domain/card.d.ts +33 -0
- package/dist/domain/card.d.ts.map +1 -0
- package/dist/domain/card.js +3 -0
- package/dist/domain/card.js.map +1 -0
- package/dist/domain/cash-session.d.ts +80 -0
- package/dist/domain/cash-session.d.ts.map +1 -0
- package/dist/domain/cash-session.js +4 -0
- package/dist/domain/cash-session.js.map +1 -0
- package/dist/domain/chart-of-accounts.d.ts +57 -0
- package/dist/domain/chart-of-accounts.d.ts.map +1 -0
- package/dist/domain/chart-of-accounts.js +114 -0
- package/dist/domain/chart-of-accounts.js.map +1 -0
- package/dist/domain/client-account.d.ts +28 -0
- package/dist/domain/client-account.d.ts.map +1 -0
- package/dist/domain/client-account.js +3 -0
- package/dist/domain/client-account.js.map +1 -0
- package/dist/domain/cnab240.d.ts +182 -0
- package/dist/domain/cnab240.d.ts.map +1 -0
- package/dist/domain/cnab240.js +265 -0
- package/dist/domain/cnab240.js.map +1 -0
- package/dist/domain/commission.d.ts +142 -0
- package/dist/domain/commission.d.ts.map +1 -0
- package/dist/domain/commission.js +3 -0
- package/dist/domain/commission.js.map +1 -0
- package/dist/domain/counterparty.d.ts +13 -0
- package/dist/domain/counterparty.d.ts.map +1 -0
- package/dist/domain/counterparty.js +48 -0
- package/dist/domain/counterparty.js.map +1 -0
- package/dist/domain/gift-card.d.ts +35 -0
- package/dist/domain/gift-card.d.ts.map +1 -0
- package/dist/domain/gift-card.js +3 -0
- package/dist/domain/gift-card.js.map +1 -0
- package/dist/domain/goal.d.ts +26 -0
- package/dist/domain/goal.d.ts.map +1 -0
- package/dist/domain/goal.js +3 -0
- package/dist/domain/goal.js.map +1 -0
- package/dist/domain/invoice.d.ts +228 -0
- package/dist/domain/invoice.d.ts.map +1 -0
- package/dist/domain/invoice.js +4 -0
- package/dist/domain/invoice.js.map +1 -0
- package/dist/domain/money.d.ts +5 -0
- package/dist/domain/money.d.ts.map +1 -0
- package/dist/domain/money.js +3 -0
- package/dist/domain/money.js.map +1 -0
- package/dist/domain/movement.d.ts +114 -0
- package/dist/domain/movement.d.ts.map +1 -0
- package/dist/domain/movement.js +4 -0
- package/dist/domain/movement.js.map +1 -0
- package/dist/domain/nota-fiscal.d.ts +47 -0
- package/dist/domain/nota-fiscal.d.ts.map +1 -0
- package/dist/domain/nota-fiscal.js +3 -0
- package/dist/domain/nota-fiscal.js.map +1 -0
- package/dist/domain/payment-method.d.ts +54 -0
- package/dist/domain/payment-method.d.ts.map +1 -0
- package/dist/domain/payment-method.js +25 -0
- package/dist/domain/payment-method.js.map +1 -0
- package/dist/domain/query.d.ts +9 -0
- package/dist/domain/query.d.ts.map +1 -0
- package/dist/domain/query.js +3 -0
- package/dist/domain/query.js.map +1 -0
- package/dist/domain/reconciliation.d.ts +277 -0
- package/dist/domain/reconciliation.d.ts.map +1 -0
- package/dist/domain/reconciliation.js +4 -0
- package/dist/domain/reconciliation.js.map +1 -0
- package/dist/domain/recurring-bill.d.ts +42 -0
- package/dist/domain/recurring-bill.d.ts.map +1 -0
- package/dist/domain/recurring-bill.js +3 -0
- package/dist/domain/recurring-bill.js.map +1 -0
- package/dist/domain/report.d.ts +92 -0
- package/dist/domain/report.d.ts.map +1 -0
- package/dist/domain/report.js +6 -0
- package/dist/domain/report.js.map +1 -0
- package/dist/domain/statement-match.d.ts +36 -0
- package/dist/domain/statement-match.d.ts.map +1 -0
- package/dist/domain/statement-match.js +3 -0
- package/dist/domain/statement-match.js.map +1 -0
- package/dist/domain/statement.d.ts +75 -0
- package/dist/domain/statement.d.ts.map +1 -0
- package/dist/domain/statement.js +4 -0
- package/dist/domain/statement.js.map +1 -0
- package/dist/domain/transfer.d.ts +29 -0
- package/dist/domain/transfer.d.ts.map +1 -0
- package/dist/domain/transfer.js +3 -0
- package/dist/domain/transfer.js.map +1 -0
- package/dist/store.d.ts +66 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +287 -0
- package/dist/store.js.map +1 -0
- package/dist/views/zones.d.ts +40 -0
- package/dist/views/zones.d.ts.map +1 -0
- package/dist/views/zones.js +16 -0
- package/dist/views/zones.js.map +1 -0
- package/package.json +49 -3
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { round2 } from './chunk-XVELDCSL.js';
|
|
2
|
+
|
|
3
|
+
// src/domain/reconciliation.ts
|
|
4
|
+
function toReconcileLine(line) {
|
|
5
|
+
return {
|
|
6
|
+
id: line.id,
|
|
7
|
+
amount: line.amount,
|
|
8
|
+
date: line.date,
|
|
9
|
+
direction: line.direction,
|
|
10
|
+
description: line.description,
|
|
11
|
+
bankAccountId: line.bankAccountId,
|
|
12
|
+
externalSource: line.externalSource
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
function statementLinesPage(query) {
|
|
16
|
+
return {
|
|
17
|
+
page: Math.max(1, Math.trunc(query?.page ?? 1)),
|
|
18
|
+
pageSize: Math.min(200, Math.max(1, Math.trunc(query?.pageSize ?? 50)))
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function pageTotals(rows) {
|
|
22
|
+
let credits = 0;
|
|
23
|
+
let debits = 0;
|
|
24
|
+
for (const row of rows) {
|
|
25
|
+
if (row.direction === "credit") credits += row.amount;
|
|
26
|
+
else debits += row.amount;
|
|
27
|
+
}
|
|
28
|
+
return { pageCredits: round2(credits), pageDebits: round2(debits), pageBalance: round2(credits - debits) };
|
|
29
|
+
}
|
|
30
|
+
function candidateTolerance(amount) {
|
|
31
|
+
return Math.max(0.01, round2(amount * 0.02));
|
|
32
|
+
}
|
|
33
|
+
function candidateScore(line, movement) {
|
|
34
|
+
const amount = line.amount;
|
|
35
|
+
const amountScore = amount > 0 ? Math.max(0, 1 - Math.abs((Number(movement.amount) || 0) - amount) / amount) : 0;
|
|
36
|
+
const reference = movement.dueDate ?? movement.paymentDate;
|
|
37
|
+
const days = line.date && reference ? Math.abs((new Date(line.date).getTime() - new Date(reference).getTime()) / 864e5) : 30;
|
|
38
|
+
const dateScore = Math.max(0, 1 - days / 30);
|
|
39
|
+
return round2(0.7 * amountScore + 0.3 * dateScore);
|
|
40
|
+
}
|
|
41
|
+
function transferForStatementLine(line, input) {
|
|
42
|
+
if (!line.bankAccountId) throw new Error("A linha do extrato n\xE3o tem conta vinculada");
|
|
43
|
+
if (line.bankAccountId === input.counterAccountId) throw new Error("Origem e destino n\xE3o podem ser a mesma conta");
|
|
44
|
+
const isOut = line.direction === "debit";
|
|
45
|
+
return {
|
|
46
|
+
fromAccountId: isOut ? line.bankAccountId : input.counterAccountId,
|
|
47
|
+
toAccountId: isOut ? input.counterAccountId : line.bankAccountId,
|
|
48
|
+
amount: line.amount,
|
|
49
|
+
date: line.date,
|
|
50
|
+
notes: input.notes || `Transfer\xEAncia identificada na concilia\xE7\xE3o${line.description ? ` (${line.description})` : ""}`
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function statementLegOf(line, transfer) {
|
|
54
|
+
return line.direction === "debit" ? transfer.debitMovementId : transfer.creditMovementId;
|
|
55
|
+
}
|
|
56
|
+
function sumItems(items) {
|
|
57
|
+
return round2((items ?? []).reduce((total, item) => total + (Number(item.quantity) || 0) * (Number(item.unitPrice) || 0), 0));
|
|
58
|
+
}
|
|
59
|
+
function itemsMismatch(items, lineAmount, fmt) {
|
|
60
|
+
const filled = (items ?? []).filter((i) => i.description.trim());
|
|
61
|
+
if (filled.length === 0) return null;
|
|
62
|
+
const sum = sumItems(filled);
|
|
63
|
+
const diff = round2(sum - round2(lineAmount));
|
|
64
|
+
if (Math.abs(diff) < 0.01) return null;
|
|
65
|
+
return diff > 0 ? `Os itens somam ${fmt(sum)} \u2014 ${fmt(diff)} a MAIS que o extrato (${fmt(lineAmount)}).` : `Os itens somam ${fmt(sum)} \u2014 ${fmt(-diff)} a MENOS que o extrato (${fmt(lineAmount)}).`;
|
|
66
|
+
}
|
|
67
|
+
function buildBillInvoice(line, input) {
|
|
68
|
+
const amount = round2(line.amount);
|
|
69
|
+
const dueDate = input.dueDate || line.date;
|
|
70
|
+
const fallback = input.description?.trim() || line.description || "Lan\xE7amento do extrato";
|
|
71
|
+
const filled = (input.items ?? []).filter((i) => i.description.trim());
|
|
72
|
+
const items = filled.length > 0 ? filled.map((item) => ({
|
|
73
|
+
itemKind: "other",
|
|
74
|
+
description: item.description.trim(),
|
|
75
|
+
quantity: Number(item.quantity) || 1,
|
|
76
|
+
unitPrice: round2(item.unitPrice),
|
|
77
|
+
accountId: item.accountId || input.accountId,
|
|
78
|
+
costCenterId: item.costCenterId || input.costCenterId
|
|
79
|
+
})) : [{
|
|
80
|
+
itemKind: "other",
|
|
81
|
+
description: fallback,
|
|
82
|
+
quantity: 1,
|
|
83
|
+
unitPrice: amount,
|
|
84
|
+
accountId: input.accountId,
|
|
85
|
+
costCenterId: input.costCenterId
|
|
86
|
+
}];
|
|
87
|
+
const sum = sumItems(filled);
|
|
88
|
+
if (filled.length > 0 && Math.abs(sum - amount) >= 0.01) {
|
|
89
|
+
throw new Error(`Os itens somam ${sum.toFixed(2)} e o extrato diz ${amount.toFixed(2)}`);
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
direction: line.direction,
|
|
93
|
+
invoiceDate: line.date,
|
|
94
|
+
contactId: input.contactId,
|
|
95
|
+
contactName: input.contactName,
|
|
96
|
+
observations: `Lan\xE7ado a partir do extrato (${line.externalSource})`,
|
|
97
|
+
metadata: input.receiptUrl ? { receiptUrl: input.receiptUrl } : void 0,
|
|
98
|
+
items,
|
|
99
|
+
installments: [{
|
|
100
|
+
direction: line.direction,
|
|
101
|
+
movementKind: "bill",
|
|
102
|
+
amount,
|
|
103
|
+
dueDate,
|
|
104
|
+
installmentNumber: 1
|
|
105
|
+
}]
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function reconciliationPaymentNote(line) {
|
|
109
|
+
const origin = line.description?.trim();
|
|
110
|
+
return origin ? `Quita\xE7\xE3o via concilia\xE7\xE3o banc\xE1ria \u2014 ${origin}` : "Quita\xE7\xE3o via concilia\xE7\xE3o banc\xE1ria";
|
|
111
|
+
}
|
|
112
|
+
function buildPayment(line, movementId, amount, payment, notes) {
|
|
113
|
+
return {
|
|
114
|
+
movementId,
|
|
115
|
+
amount: round2(amount),
|
|
116
|
+
paymentDate: payment?.paymentDate || line.date,
|
|
117
|
+
paymentMethodId: payment?.paymentMethodId,
|
|
118
|
+
paymentMethodTypeId: payment?.paymentMethodTypeId,
|
|
119
|
+
bankAccountId: payment?.bankAccountId || line.bankAccountId,
|
|
120
|
+
cashSessionId: payment?.cashSessionId,
|
|
121
|
+
cardBrand: payment?.cardBrand,
|
|
122
|
+
cardInstallments: payment?.cardInstallments,
|
|
123
|
+
notes: payment?.notes?.trim() || notes || reconciliationPaymentNote(line)
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
var ADJUSTMENT_LABEL = {
|
|
127
|
+
interest: "Juros",
|
|
128
|
+
fine: "Multa",
|
|
129
|
+
discount: "Desconto"
|
|
130
|
+
};
|
|
131
|
+
function adjustmentDirection(billDirection, type) {
|
|
132
|
+
const costs = type !== "discount";
|
|
133
|
+
if (billDirection === "debit") return costs ? "debit" : "credit";
|
|
134
|
+
return costs ? "credit" : "debit";
|
|
135
|
+
}
|
|
136
|
+
function signedAdjustment(adj) {
|
|
137
|
+
return adj.type === "discount" ? -round2(adj.amount) : round2(adj.amount);
|
|
138
|
+
}
|
|
139
|
+
function adjustmentGap(lineAmount, billOpenAmount) {
|
|
140
|
+
return round2(lineAmount - billOpenAmount);
|
|
141
|
+
}
|
|
142
|
+
function adjustmentsMismatch(adjustments, gap, fmt) {
|
|
143
|
+
const sum = round2((adjustments ?? []).reduce((total, a) => total + signedAdjustment(a), 0));
|
|
144
|
+
const rest = round2(gap - sum);
|
|
145
|
+
if (Math.abs(rest) < 0.01) return null;
|
|
146
|
+
return rest > 0 ? `Faltam ${fmt(rest)} para explicar a diferen\xE7a \u2014 aumente os juros/multa ou reduza o desconto.` : `Sobram ${fmt(-rest)} nos ajustes \u2014 reduza os juros/multa ou aumente o desconto.`;
|
|
147
|
+
}
|
|
148
|
+
function adjustmentDescription(adj) {
|
|
149
|
+
return adj.description?.trim() || ADJUSTMENT_LABEL[adj.type];
|
|
150
|
+
}
|
|
151
|
+
function adjustmentInvoice(line, adj) {
|
|
152
|
+
const direction = adjustmentDirection(line.direction, adj.type);
|
|
153
|
+
return {
|
|
154
|
+
direction,
|
|
155
|
+
invoiceDate: line.date,
|
|
156
|
+
observations: `${ADJUSTMENT_LABEL[adj.type]} da concilia\xE7\xE3o (${line.externalSource})`,
|
|
157
|
+
items: [{
|
|
158
|
+
itemKind: "other",
|
|
159
|
+
description: adjustmentDescription(adj),
|
|
160
|
+
quantity: 1,
|
|
161
|
+
unitPrice: round2(adj.amount),
|
|
162
|
+
accountId: adj.accountId
|
|
163
|
+
}],
|
|
164
|
+
installments: [{
|
|
165
|
+
direction,
|
|
166
|
+
movementKind: "bill",
|
|
167
|
+
amount: round2(adj.amount),
|
|
168
|
+
dueDate: line.date,
|
|
169
|
+
installmentNumber: 1
|
|
170
|
+
}]
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
var isPaid = (m) => m.movementKind === "payment" || m.status === "paid" || round2(m.paidAmount) >= round2(m.amount);
|
|
174
|
+
function resolveCandidates(candidates) {
|
|
175
|
+
const payments = candidates.filter((c) => c.movement.movementKind === "payment");
|
|
176
|
+
const settled = new Set(payments.map((c) => c.movement.settlesMovementId).filter(Boolean));
|
|
177
|
+
return candidates.filter((c) => !(c.movement.movementKind === "bill" && settled.has(c.movement.id))).map((c) => {
|
|
178
|
+
const m = c.movement;
|
|
179
|
+
const paid = isPaid(m);
|
|
180
|
+
return {
|
|
181
|
+
candidate: c,
|
|
182
|
+
mode: paid ? "link_only" : "settle",
|
|
183
|
+
openAmount: paid ? 0 : round2(m.amount - m.paidAmount)
|
|
184
|
+
};
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export { ADJUSTMENT_LABEL, adjustmentDescription, adjustmentDirection, adjustmentGap, adjustmentInvoice, adjustmentsMismatch, buildBillInvoice, buildPayment, candidateScore, candidateTolerance, itemsMismatch, pageTotals, reconciliationPaymentNote, resolveCandidates, signedAdjustment, statementLegOf, statementLinesPage, sumItems, toReconcileLine, transferForStatementLine };
|
|
189
|
+
//# sourceMappingURL=chunk-MCSPCXQK.js.map
|
|
190
|
+
//# sourceMappingURL=chunk-MCSPCXQK.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/domain/reconciliation.ts"],"names":[],"mappings":"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","file":"chunk-MCSPCXQK.js","sourcesContent":["import type { CreateInvoiceInput, Invoice } from './invoice'\nimport { round2 } from './money'\nimport type { FinancialMovement, PayMovementInput, TransactionDirection } from './movement'\nimport type { DateRange } from './query'\nimport type { CreateTransferInput, TransferResult } from './transfer'\n\n/** A normalized bank-statement line, ready to import. */\nexport interface BankStatementLine {\n /** Provider-unique id; with `externalSource`, the idempotency key. */\n externalId: string\n externalSource: string\n /** `credit` is money in, `debit` money out. */\n direction: TransactionDirection\n /** Always positive; the sign is the direction. */\n amount: number\n /** YYYY-MM-DD settlement date. */\n date: string\n description: string\n /** Falls back to the import's account. */\n bankAccountId?: string\n effectiveAt?: string\n /** The bank's balance after this line, what proves the statement adds up. */\n balanceAfter?: number\n counterpartyName?: string\n counterpartyDocument?: string\n document?: string\n code?: string\n category?: string\n transactionType?: string\n rawPayload?: Record<string, unknown>\n}\n\n/**\n * A statement line as stored: evidence, not a ledger entry. A fresh line cannot have two legs\n * because nothing says yet what it posts against; matched, the movement is the economic event.\n */\nexport interface ImportedStatementLine extends BankStatementLine {\n id: string\n tenantId?: string\n unitId?: string\n bankAccountId?: string\n /** The provider withdrew it; it stops showing instead of disappearing. */\n providerDeleted?: boolean\n reconciledAt?: string\n /** Empty with `reconciledAt` set means accepted on its own. */\n matchedMovementId?: string\n createdAt?: string\n updatedAt?: string\n /** Who is on the other side of a reconciled line, read from the matched entry. */\n matchedCounterpartyName?: string\n /** The invoice a reconciled line proves. */\n matchedInvoiceId?: string\n}\n\nexport interface ImportBankTransactionsInput {\n /** Default account for lines that carry none. */\n bankAccountId?: string\n lines: BankStatementLine[]\n}\n\nexport interface ImportBankTransactionsResult {\n imported: number\n /** Lines skipped because they were already imported. */\n duplicates: number\n}\n\nexport interface UnreconciledQuery {\n bankAccountId?: string\n dateRange?: DateRange\n}\n\nexport type StatementLineStatus = 'reconciled' | 'pending'\n\nexport interface StatementLinesQuery {\n bankAccountId?: string\n dateRange?: DateRange\n /** Absent means both. */\n direction?: TransactionDirection\n status?: StatementLineStatus\n /** Matches the description and the provider's identifiers. */\n search?: string\n /** Leaves out investments, auto-investment sweeps and their yields (code-based). */\n hideInvestments?: boolean\n /** 1-based. */\n page?: number\n pageSize?: number\n}\n\nexport interface StatementLinesResult {\n rows: ImportedStatementLine[]\n /** Lines the filter found, not the page's. */\n total: number\n page: number\n pageSize: number\n /** Sums of the page only; the screen labels them so. */\n pageCredits: number\n pageDebits: number\n pageBalance: number\n}\n\n/** An internal movement that may match an imported line. */\nexport interface ReconciliationCandidate {\n movement: FinancialMovement\n invoice?: Invoice\n /** 0..1 confidence from amount and date proximity. */\n score: number\n /** Installments in the bill, for the «1/3» column. */\n installmentCount?: number\n}\n\n/** Free search over the bills a statement line can settle — V1's \"Vincular manualmente\". */\nexport interface ReconciliationTargetQuery {\n /** YYYY-MM-DD, on the due date */\n dueFrom?: string\n dueTo?: string\n /** `all` = open + paid-but-not-yet-reconciled */\n status?: 'all' | 'open' | 'paid'\n /** Counterparty, number or description */\n search?: string\n amountMin?: number\n amountMax?: number\n page?: number\n pageSize?: number\n}\n\nexport interface ReconciliationTargetResult {\n data: ReconciliationCandidate[]\n hasMore: boolean\n}\n\n/** \"Mark as transfer\": the line is money moving between two of the house's accounts. */\nexport interface ReconcileAsTransferInput {\n bankMovementId: string\n /** The other end: destination of an outflow, source of an inflow. */\n counterAccountId: string\n notes?: string\n}\n\n/** \"Post as bill\": nothing matches because the entry never existed, so it is born here. */\nexport interface ReconcileAsBillInput {\n bankMovementId: string\n /** Defaults to the line's direction; the operator may correct it for a refund. */\n direction?: TransactionDirection\n contactId?: string\n contactName?: string\n /** Falls back to the provider's description. */\n description?: string\n /** Chart account; what makes the bill appear classified in the income statement. */\n accountId?: string\n costCenterId?: string\n /** Falls back to the line's date. */\n dueDate?: string\n /** Empty means one line with the statement's description and amount; otherwise they must add up to it. */\n items?: ReconcileBillItemInput[]\n /** Absent settles against the statement's account without naming a method. */\n payment?: ReconcilePaymentInput\n receiptUrl?: string\n}\n\nexport interface ReconcileBillItemInput {\n description: string\n quantity: number\n unitPrice: number\n /** Falls back to the bill's chart account. */\n accountId?: string\n costCenterId?: string\n}\n\n/** How the money moved, in the same shape the invoice payment form speaks. */\nexport interface ReconcilePaymentInput {\n paymentMethodId?: string\n paymentMethodTypeId?: string\n bankAccountId?: string\n cashSessionId?: string\n cardBrand?: string\n cardInstallments?: number\n /** Falls back to the line's date. */\n paymentDate?: string\n notes?: string\n}\n\n/**\n * Interest, fine or discount explaining the gap between a line and the bill it settles. It is its\n * own classified entry, paid the same day against the same account, because the payment RPC\n * refuses to pay more than what is open.\n */\nexport interface ReconcileAdjustment {\n type: 'interest' | 'fine' | 'discount'\n /** Always positive; the type gives the sign. */\n amount: number\n description?: string\n accountId?: string\n}\n\nexport interface ReconcileInput {\n bankMovementId: string\n /** Omit to accept the line on its own. */\n matchedMovementId?: string\n /** `settle` pays an open bill with the line; `link_only` (the default) ties a bill already paid. */\n mode?: 'settle' | 'link_only'\n payment?: ReconcilePaymentInput\n adjustments?: ReconcileAdjustment[]\n /** The line pays only PART of the bill (paid in two transfers): it settles\n * the line's amount and the rest stays open for the next line. */\n partial?: boolean\n}\n\n/**\n * What reading a photographed receipt produced. The statement's amount, date and account stay the\n * source of truth; the receipt adds who, what and where it is classified.\n */\nexport interface ReceiptReading {\n contactName?: string\n /** A chart-account hint, by code or name. */\n accountHint?: string\n items?: ReconcileBillItemInput[]\n document?: string\n /** What the reading had to guess or could not read. */\n warnings?: string[]\n}\n\n/** A statement line reduced to what reconciling needs. */\nexport interface ReconcileLine {\n id: string\n amount: number\n date: string\n direction: TransactionDirection\n description?: string\n bankAccountId?: string\n externalSource: string\n}\n\nexport function toReconcileLine(line: ImportedStatementLine): ReconcileLine {\n return {\n id: line.id,\n amount: line.amount,\n date: line.date,\n direction: line.direction,\n description: line.description,\n bankAccountId: line.bankAccountId,\n externalSource: line.externalSource,\n }\n}\n\n/** The page the screen asked for, clamped: 1-based, 50 by default, never above 200. */\nexport function statementLinesPage(query?: Pick<StatementLinesQuery, 'page' | 'pageSize'>): { page: number; pageSize: number } {\n return {\n page: Math.max(1, Math.trunc(query?.page ?? 1)),\n pageSize: Math.min(200, Math.max(1, Math.trunc(query?.pageSize ?? 50))),\n }\n}\n\nexport function pageTotals(rows: Pick<ImportedStatementLine, 'direction' | 'amount'>[]): Pick<StatementLinesResult, 'pageCredits' | 'pageDebits' | 'pageBalance'> {\n let credits = 0\n let debits = 0\n for (const row of rows) {\n if (row.direction === 'credit') credits += row.amount\n else debits += row.amount\n }\n return { pageCredits: round2(credits), pageDebits: round2(debits), pageBalance: round2(credits - debits) }\n}\n\n/** How far a candidate's amount may be from the line: 2%, at least a cent. */\nexport function candidateTolerance(amount: number): number {\n return Math.max(0.01, round2(amount * 0.02))\n}\n\n/** Confidence that a movement is the line: 70% amount closeness, 30% date within a month. */\nexport function candidateScore(\n line: { amount: number; date?: string },\n movement: { amount: number; dueDate?: string; paymentDate?: string },\n): number {\n const amount = line.amount\n const amountScore = amount > 0 ? Math.max(0, 1 - Math.abs((Number(movement.amount) || 0) - amount) / amount) : 0\n const reference = movement.dueDate ?? movement.paymentDate\n const days = line.date && reference\n ? Math.abs((new Date(line.date).getTime() - new Date(reference).getTime()) / 86400000)\n : 30\n const dateScore = Math.max(0, 1 - days / 30)\n return round2(0.7 * amountScore + 0.3 * dateScore)\n}\n\n/**\n * The transfer a statement line evidences. The statement's account is always one end: an outflow\n * left it, so it is the source; inverting this moves the consolidated balance twice the wrong way.\n */\nexport function transferForStatementLine(line: ReconcileLine, input: ReconcileAsTransferInput): CreateTransferInput {\n if (!line.bankAccountId) throw new Error('A linha do extrato não tem conta vinculada')\n if (line.bankAccountId === input.counterAccountId) throw new Error('Origem e destino não podem ser a mesma conta')\n const isOut = line.direction === 'debit'\n return {\n fromAccountId: isOut ? line.bankAccountId : input.counterAccountId,\n toAccountId: isOut ? input.counterAccountId : line.bankAccountId,\n amount: line.amount,\n date: line.date,\n notes: input.notes || `Transferência identificada na conciliação${line.description ? ` (${line.description})` : ''}`,\n }\n}\n\n/** The leg on the statement's own account: the one the line proves. */\nexport function statementLegOf(line: Pick<ReconcileLine, 'direction'>, transfer: TransferResult): string {\n return line.direction === 'debit' ? transfer.debitMovementId : transfer.creditMovementId\n}\n\nexport function sumItems(items: ReconcileBillItemInput[] | undefined): number {\n return round2((items ?? []).reduce((total, item) =>\n total + (Number(item.quantity) || 0) * (Number(item.unitPrice) || 0), 0))\n}\n\n/** Do the items add up to the line? Returns the blocking message, or null when they do. */\nexport function itemsMismatch(\n items: ReconcileBillItemInput[] | undefined,\n lineAmount: number,\n fmt: (n: number) => string,\n): string | null {\n const filled = (items ?? []).filter((i) => i.description.trim())\n if (filled.length === 0) return null\n const sum = sumItems(filled)\n const diff = round2(sum - round2(lineAmount))\n if (Math.abs(diff) < 0.01) return null\n return diff > 0\n ? `Os itens somam ${fmt(sum)} — ${fmt(diff)} a MAIS que o extrato (${fmt(lineAmount)}).`\n : `Os itens somam ${fmt(sum)} — ${fmt(-diff)} a MENOS que o extrato (${fmt(lineAmount)}).`\n}\n\n/**\n * The bill a statement line evidences. The direction is not a choice: an outflow is a payable and an\n * inflow a receivable. The installment is always the statement's amount.\n */\nexport function buildBillInvoice(line: ReconcileLine, input: ReconcileAsBillInput): CreateInvoiceInput {\n const amount = round2(line.amount)\n const dueDate = input.dueDate || line.date\n const fallback = input.description?.trim() || line.description || 'Lançamento do extrato'\n const filled = (input.items ?? []).filter((i) => i.description.trim())\n\n const items = filled.length > 0\n ? filled.map((item) => ({\n itemKind: 'other' as const,\n description: item.description.trim(),\n quantity: Number(item.quantity) || 1,\n unitPrice: round2(item.unitPrice),\n accountId: item.accountId || input.accountId,\n costCenterId: item.costCenterId || input.costCenterId,\n }))\n : [{\n itemKind: 'other' as const,\n description: fallback,\n quantity: 1,\n unitPrice: amount,\n accountId: input.accountId,\n costCenterId: input.costCenterId,\n }]\n\n const sum = sumItems(filled)\n if (filled.length > 0 && Math.abs(sum - amount) >= 0.01) {\n throw new Error(`Os itens somam ${sum.toFixed(2)} e o extrato diz ${amount.toFixed(2)}`)\n }\n\n return {\n direction: line.direction,\n invoiceDate: line.date,\n contactId: input.contactId,\n contactName: input.contactName,\n observations: `Lançado a partir do extrato (${line.externalSource})`,\n metadata: input.receiptUrl ? { receiptUrl: input.receiptUrl } : undefined,\n items,\n installments: [{\n direction: line.direction,\n movementKind: 'bill',\n amount,\n dueDate,\n installmentNumber: 1,\n }],\n }\n}\n\nexport function reconciliationPaymentNote(line: ReconcileLine): string {\n const origin = line.description?.trim()\n return origin\n ? `Quitação via conciliação bancária — ${origin}`\n : 'Quitação via conciliação bancária'\n}\n\n/**\n * The payment a statement line makes. The line already answers when, where and how much, and the\n * method is the statement itself, so nothing is asked; `payment` exists for callers that pay\n * differently from what the statement says.\n */\nexport function buildPayment(\n line: ReconcileLine,\n movementId: string,\n amount: number,\n payment: ReconcilePaymentInput | undefined,\n notes?: string,\n): PayMovementInput {\n return {\n movementId,\n amount: round2(amount),\n paymentDate: payment?.paymentDate || line.date,\n paymentMethodId: payment?.paymentMethodId,\n paymentMethodTypeId: payment?.paymentMethodTypeId,\n bankAccountId: payment?.bankAccountId || line.bankAccountId,\n cashSessionId: payment?.cashSessionId,\n cardBrand: payment?.cardBrand,\n cardInstallments: payment?.cardInstallments,\n notes: payment?.notes?.trim() || notes || reconciliationPaymentNote(line),\n }\n}\n\nexport const ADJUSTMENT_LABEL: Record<ReconcileAdjustment['type'], string> = {\n interest: 'Juros',\n fine: 'Multa',\n discount: 'Desconto',\n}\n\n/** Interest and fines cost whoever pays the bill; a discount gives back. */\nexport function adjustmentDirection(\n billDirection: TransactionDirection,\n type: ReconcileAdjustment['type'],\n): TransactionDirection {\n const costs = type !== 'discount'\n if (billDirection === 'debit') return costs ? 'debit' : 'credit'\n return costs ? 'credit' : 'debit'\n}\n\n/** How much an adjustment pushes the total up (+) or down (−). */\nexport function signedAdjustment(adj: ReconcileAdjustment): number {\n return adj.type === 'discount' ? -round2(adj.amount) : round2(adj.amount)\n}\n\n/** Positive when the bank took more than the bill asked (interest, fine), negative for a discount. */\nexport function adjustmentGap(lineAmount: number, billOpenAmount: number): number {\n return round2(lineAmount - billOpenAmount)\n}\n\n/** Do the adjustments explain the gap? Returns what is left to explain, or null. */\nexport function adjustmentsMismatch(\n adjustments: ReconcileAdjustment[] | undefined,\n gap: number,\n fmt: (n: number) => string,\n): string | null {\n const sum = round2((adjustments ?? []).reduce((total, a) => total + signedAdjustment(a), 0))\n const rest = round2(gap - sum)\n if (Math.abs(rest) < 0.01) return null\n return rest > 0\n ? `Faltam ${fmt(rest)} para explicar a diferença — aumente os juros/multa ou reduza o desconto.`\n : `Sobram ${fmt(-rest)} nos ajustes — reduza os juros/multa ou aumente o desconto.`\n}\n\nexport function adjustmentDescription(adj: ReconcileAdjustment): string {\n return adj.description?.trim() || ADJUSTMENT_LABEL[adj.type]\n}\n\n/** The entry an adjustment becomes, paid the same day as the line. */\nexport function adjustmentInvoice(line: ReconcileLine, adj: ReconcileAdjustment): CreateInvoiceInput {\n const direction = adjustmentDirection(line.direction, adj.type)\n return {\n direction,\n invoiceDate: line.date,\n observations: `${ADJUSTMENT_LABEL[adj.type]} da conciliação (${line.externalSource})`,\n items: [{\n itemKind: 'other',\n description: adjustmentDescription(adj),\n quantity: 1,\n unitPrice: round2(adj.amount),\n accountId: adj.accountId,\n }],\n installments: [{\n direction,\n movementKind: 'bill',\n amount: round2(adj.amount),\n dueDate: line.date,\n installmentNumber: 1,\n }],\n }\n}\n\n/** A candidate and what reconciling with it does. */\nexport interface ResolvedCandidate {\n candidate: ReconciliationCandidate\n /** `settle` pays an open bill; `link_only` ties one already paid, since paying again doubles the money. */\n mode: 'settle' | 'link_only'\n /** What is still owed (0 on a settled bill). */\n openAmount: number\n}\n\nconst isPaid = (m: FinancialMovement) =>\n m.movementKind === 'payment' || m.status === 'paid' || round2(m.paidAmount) >= round2(m.amount)\n\n/**\n * Says per candidate whether reconciling settles or only links, and drops the bill whose payment is\n * also in the list: a paid bill comes back twice, and two identical rows are two chances to pick wrong.\n */\nexport function resolveCandidates(candidates: ReconciliationCandidate[]): ResolvedCandidate[] {\n const payments = candidates.filter((c) => c.movement.movementKind === 'payment')\n const settled = new Set(payments.map((c) => c.movement.settlesMovementId).filter(Boolean) as string[])\n\n return candidates\n .filter((c) => !(c.movement.movementKind === 'bill' && settled.has(c.movement.id)))\n .map((c) => {\n const m = c.movement\n const paid = isPaid(m)\n return {\n candidate: c,\n mode: paid ? 'link_only' as const : 'settle' as const,\n openAmount: paid ? 0 : round2(m.amount - m.paidAmount),\n }\n })\n}\n"]}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { affectsCash } from './chunk-HJPUHTI2.js';
|
|
2
|
+
import { openAmount } from './chunk-4GXBOEI3.js';
|
|
3
|
+
|
|
4
|
+
// src/domain/report.ts
|
|
5
|
+
function trailingWindow(today, days = 30) {
|
|
6
|
+
const start = /* @__PURE__ */ new Date(`${today}T00:00:00Z`);
|
|
7
|
+
start.setUTCDate(start.getUTCDate() - days);
|
|
8
|
+
return { from: start.toISOString().slice(0, 10), to: today };
|
|
9
|
+
}
|
|
10
|
+
var isOpenBill = (m) => m.movementKind === "bill" && (m.status === "pending" || m.status === "partial");
|
|
11
|
+
function summarizeLedger(input) {
|
|
12
|
+
const receivable = input.movements.filter((m) => m.direction === "credit" && isOpenBill(m));
|
|
13
|
+
const payable = input.movements.filter((m) => m.direction === "debit" && isOpenBill(m));
|
|
14
|
+
const overdueReceivable = receivable.filter((m) => m.dueDate < input.today);
|
|
15
|
+
const overduePayable = payable.filter((m) => m.dueDate < input.today);
|
|
16
|
+
const inWindow = input.movements.filter((m) => affectsCash(m) && m.movementKind === "payment" && (!m.paymentDate || m.paymentDate >= input.window.from && m.paymentDate <= input.window.to));
|
|
17
|
+
const owed = (rows) => rows.reduce((sum, m) => sum + openAmount(m), 0);
|
|
18
|
+
const paid = (rows) => rows.reduce((sum, m) => sum + m.paidAmount, 0);
|
|
19
|
+
return {
|
|
20
|
+
totalBalance: input.accounts.filter((a) => a.isActive).reduce((sum, a) => sum + a.currentBalance, 0),
|
|
21
|
+
totalReceivable: owed(receivable),
|
|
22
|
+
totalPayable: owed(payable),
|
|
23
|
+
monthlyInflow: paid(inWindow.filter((m) => m.direction === "credit")),
|
|
24
|
+
monthlyOutflow: paid(inWindow.filter((m) => m.direction === "debit")),
|
|
25
|
+
overdueReceivableCount: overdueReceivable.length,
|
|
26
|
+
overdueReceivableAmount: owed(overdueReceivable),
|
|
27
|
+
overduePayableCount: overduePayable.length,
|
|
28
|
+
overduePayableAmount: owed(overduePayable)
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export { summarizeLedger, trailingWindow };
|
|
33
|
+
//# sourceMappingURL=chunk-T7WIM2V7.js.map
|
|
34
|
+
//# sourceMappingURL=chunk-T7WIM2V7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/domain/report.ts"],"names":[],"mappings":";;;;AAqFO,SAAS,cAAA,CAAe,KAAA,EAAe,IAAA,GAAO,EAAA,EAAe;AAClE,EAAA,MAAM,KAAA,mBAAQ,IAAI,IAAA,CAAK,CAAA,EAAG,KAAK,CAAA,UAAA,CAAY,CAAA;AAC3C,EAAA,KAAA,CAAM,UAAA,CAAW,KAAA,CAAM,UAAA,EAAW,GAAI,IAAI,CAAA;AAC1C,EAAA,OAAO,EAAE,IAAA,EAAM,KAAA,CAAM,WAAA,EAAY,CAAE,MAAM,CAAA,EAAG,EAAE,CAAA,EAAG,EAAA,EAAI,KAAA,EAAM;AAC7D;AAEA,IAAM,UAAA,GAAa,CAAC,CAAA,KAAyB,CAAA,CAAE,YAAA,KAAiB,WAAW,CAAA,CAAE,MAAA,KAAW,SAAA,IAAa,CAAA,CAAE,MAAA,KAAW,SAAA,CAAA;AAG3G,SAAS,gBAAgB,KAAA,EAKX;AACnB,EAAA,MAAM,UAAA,GAAa,KAAA,CAAM,SAAA,CAAU,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,SAAA,KAAc,QAAA,IAAY,UAAA,CAAW,CAAC,CAAC,CAAA;AAC1F,EAAA,MAAM,OAAA,GAAU,KAAA,CAAM,SAAA,CAAU,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,SAAA,KAAc,OAAA,IAAW,UAAA,CAAW,CAAC,CAAC,CAAA;AACtF,EAAA,MAAM,iBAAA,GAAoB,WAAW,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,OAAA,GAAU,MAAM,KAAK,CAAA;AAC1E,EAAA,MAAM,cAAA,GAAiB,QAAQ,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,OAAA,GAAU,MAAM,KAAK,CAAA;AACpE,EAAA,MAAM,QAAA,GAAW,KAAA,CAAM,SAAA,CAAU,MAAA,CAAO,CAAC,MACvC,WAAA,CAAY,CAAC,CAAA,IAAK,CAAA,CAAE,YAAA,KAAiB,SAAA,KACjC,CAAC,CAAA,CAAE,WAAA,IAAgB,CAAA,CAAE,WAAA,IAAe,KAAA,CAAM,MAAA,CAAO,QAAQ,CAAA,CAAE,WAAA,IAAe,KAAA,CAAM,MAAA,CAAO,EAAA,CAAI,CAAA;AACjG,EAAA,MAAM,IAAA,GAAO,CAAC,IAAA,KAA8B,IAAA,CAAK,MAAA,CAAO,CAAC,GAAA,EAAK,CAAA,KAAM,GAAA,GAAM,UAAA,CAAW,CAAC,CAAA,EAAG,CAAC,CAAA;AAC1F,EAAA,MAAM,IAAA,GAAO,CAAC,IAAA,KAA8B,IAAA,CAAK,MAAA,CAAO,CAAC,GAAA,EAAK,CAAA,KAAM,GAAA,GAAM,CAAA,CAAE,UAAA,EAAY,CAAC,CAAA;AACzF,EAAA,OAAO;AAAA,IACL,cAAc,KAAA,CAAM,QAAA,CAAS,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,QAAQ,CAAA,CAAE,MAAA,CAAO,CAAC,GAAA,EAAK,CAAA,KAAM,GAAA,GAAM,CAAA,CAAE,gBAAgB,CAAC,CAAA;AAAA,IACnG,eAAA,EAAiB,KAAK,UAAU,CAAA;AAAA,IAChC,YAAA,EAAc,KAAK,OAAO,CAAA;AAAA,IAC1B,aAAA,EAAe,KAAK,QAAA,CAAS,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,SAAA,KAAc,QAAQ,CAAC,CAAA;AAAA,IACpE,cAAA,EAAgB,KAAK,QAAA,CAAS,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,SAAA,KAAc,OAAO,CAAC,CAAA;AAAA,IACpE,wBAAwB,iBAAA,CAAkB,MAAA;AAAA,IAC1C,uBAAA,EAAyB,KAAK,iBAAiB,CAAA;AAAA,IAC/C,qBAAqB,cAAA,CAAe,MAAA;AAAA,IACpC,oBAAA,EAAsB,KAAK,cAAc;AAAA,GAC3C;AACF","file":"chunk-T7WIM2V7.js","sourcesContent":["import type { BankAccount } from './account'\nimport { openAmount, type FinancialMovement } from './movement'\nimport type { DateRange } from './query'\nimport { affectsCash } from './statement'\n\nexport interface FinancialSummary {\n totalBalance: number\n totalReceivable: number\n totalPayable: number\n monthlyInflow: number\n monthlyOutflow: number\n overdueReceivableCount: number\n overdueReceivableAmount: number\n overduePayableCount: number\n overduePayableAmount: number\n /**\n * Amounts in a currency with no rate to the house's on file. They are NOT in\n * the totals above (never counted 1:1), so the screen has to say they exist.\n */\n excluded?: Array<{ currency: string; balance: number; receivable: number; payable: number; inflow: number; outflow: number }>\n}\n\nexport interface DreQuery {\n year: number\n unitId?: string\n}\n\n/** One income-statement line: an account's amount in a competence month. */\nexport interface DreRow {\n unitId?: string\n competenceMonth?: string\n accountId?: string\n accountCode?: string\n accountName?: string\n accountType: 'revenue' | 'expense'\n parentAccountId?: string\n statementCode?: string\n statementName?: string\n unclassified: boolean\n amount: number\n discount: number\n lineCount: number\n}\n\n/** A competence month and whether it is closed. */\nexport interface FinancialPeriod {\n id: string\n competenceMonth: string\n status: 'open' | 'closed'\n closedAt?: string | null\n reopenReason?: string | null\n}\n\nexport interface TrialBalanceRow {\n accountId: string\n accountCode?: string | null\n accountName?: string | null\n competenceMonth: string\n totalDebit: number\n totalCredit: number\n balance: number\n}\n\n/** Open balance by how late it is. */\nexport interface AgingRow {\n installmentId: string\n invoiceNumber?: string | null\n counterpartyName?: string | null\n dueDate: string\n balance: number\n daysOverdue: number\n bucket: 'current' | 'd1_15' | 'd16_30' | 'd31_60' | 'd61_90' | 'd90_plus'\n}\n\n/** Revenue minus cost of goods and commission, per month. */\nexport interface MarginRow {\n competenceMonth: string\n revenue: number\n cogs: number\n commission: number\n margin: number\n marginPercent: number\n}\n\n/** The last `days` days up to today: a calendar month-to-date reads empty on the 1st. */\nexport function trailingWindow(today: string, days = 30): DateRange {\n const start = new Date(`${today}T00:00:00Z`)\n start.setUTCDate(start.getUTCDate() - days)\n return { from: start.toISOString().slice(0, 10), to: today }\n}\n\nconst isOpenBill = (m: FinancialMovement) => m.movementKind === 'bill' && (m.status === 'pending' || m.status === 'partial')\n\n/** The nine numbers of the summary card; `financial_summary` computes the same in SQL. */\nexport function summarizeLedger(input: {\n accounts: Pick<BankAccount, 'isActive' | 'currentBalance'>[]\n movements: FinancialMovement[]\n today: string\n window: DateRange\n}): FinancialSummary {\n const receivable = input.movements.filter((m) => m.direction === 'credit' && isOpenBill(m))\n const payable = input.movements.filter((m) => m.direction === 'debit' && isOpenBill(m))\n const overdueReceivable = receivable.filter((m) => m.dueDate < input.today)\n const overduePayable = payable.filter((m) => m.dueDate < input.today)\n const inWindow = input.movements.filter((m) =>\n affectsCash(m) && m.movementKind === 'payment'\n && (!m.paymentDate || (m.paymentDate >= input.window.from && m.paymentDate <= input.window.to)))\n const owed = (rows: FinancialMovement[]) => rows.reduce((sum, m) => sum + openAmount(m), 0)\n const paid = (rows: FinancialMovement[]) => rows.reduce((sum, m) => sum + m.paidAmount, 0)\n return {\n totalBalance: input.accounts.filter((a) => a.isActive).reduce((sum, a) => sum + a.currentBalance, 0),\n totalReceivable: owed(receivable),\n totalPayable: owed(payable),\n monthlyInflow: paid(inWindow.filter((m) => m.direction === 'credit')),\n monthlyOutflow: paid(inWindow.filter((m) => m.direction === 'debit')),\n overdueReceivableCount: overdueReceivable.length,\n overdueReceivableAmount: owed(overdueReceivable),\n overduePayableCount: overduePayable.length,\n overduePayableAmount: owed(overduePayable),\n }\n}\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// src/domain/account.ts
|
|
2
|
+
var NOT_A_HOLDER = /* @__PURE__ */ new Set(["person", "system"]);
|
|
3
|
+
function holdsMoney(account) {
|
|
4
|
+
return !NOT_A_HOLDER.has(account.accountType);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export { holdsMoney };
|
|
8
|
+
//# sourceMappingURL=chunk-TZZNVPBY.js.map
|
|
9
|
+
//# sourceMappingURL=chunk-TZZNVPBY.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/domain/account.ts"],"names":[],"mappings":";AAuEA,IAAM,+BAAe,IAAI,GAAA,CAAqB,CAAC,QAAA,EAAU,QAAQ,CAAC,CAAA;AAG3D,SAAS,WAAW,OAAA,EAAoD;AAC7E,EAAA,OAAO,CAAC,YAAA,CAAa,GAAA,CAAI,OAAA,CAAQ,WAAW,CAAA;AAC9C","file":"chunk-TZZNVPBY.js","sourcesContent":["/**\n * The canonical account vocabulary, `plg_financial_accounts.kind`: what `allowedAccountTypes`\n * compares and the payment RPCs validate.\n */\nexport type BankAccountType =\n | 'bank' | 'cash_physical' | 'cash_session'\n | 'card_receivable_credit' | 'card_receivable_debit'\n | 'card_payable' | 'person' | 'unit' | 'unidentified' | 'system'\n\nexport interface BankAccount {\n id: string\n name: string\n accountType: BankAccountType\n /** COMPE/ISPB number, what boleto, CNAB and PIX use; `bankName` is what people read. */\n bankCode?: string\n bankName?: string\n accountNumber?: string\n agencyNumber?: string\n /** The holder is rarely the tenant: a partner, a holding, the company the account is in. */\n holderName?: string\n holderDocument?: string\n /** Bank-specific CNAB fields, until every bank shares one schema. */\n metadata?: Record<string, unknown>\n currentBalance: number\n initialBalance: number\n creditLimit?: number\n dueDay?: number\n closingDay?: number\n /** The day after closing: a purchase lands on the farthest statement. */\n bestPurchaseDay?: number\n /** Card brand of a card account; it links the account to the per-brand fees. */\n cardBrandId?: string | null\n lastFour?: string | null\n color?: string | null\n isActive: boolean\n unitId?: string\n tenantId: string\n createdAt: string\n updatedAt: string\n}\n\nexport interface CreateBankAccountInput {\n name: string\n accountType: BankAccountType\n bankCode?: string\n bankName?: string\n accountNumber?: string\n agencyNumber?: string\n holderName?: string\n holderDocument?: string\n initialBalance?: number\n creditLimit?: number\n dueDay?: number\n closingDay?: number\n bestPurchaseDay?: number\n cardBrandId?: string | null\n unitId?: string\n}\n\n/** An institution from the central bank catalogue (`public.banks`). */\nexport interface BankCatalogEntry {\n /** Three-digit COMPE, what boleto and CNAB carry; absent for PIX-only institutions. */\n compe?: string\n ispb: string\n name: string\n legalName?: string\n brandColor?: string\n logoUrl?: string\n}\n\n// A person or the system's payables/receivables account is the other leg of an entry, not where it was paid.\nconst NOT_A_HOLDER = new Set<BankAccountType>(['person', 'system'])\n\n/** Can this account be named as where money was paid from or landed? */\nexport function holdsMoney(account: Pick<BankAccount, 'accountType'>): boolean {\n return !NOT_A_HOLDER.has(account.accountType)\n}\n"]}
|