@fayz-ai/plugin-financial 0.1.7 → 0.8.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 (72) hide show
  1. package/README.md +2 -0
  2. package/dist/FinancialContext.d.ts +2 -0
  3. package/dist/FinancialContext.d.ts.map +1 -1
  4. package/dist/FinancialPage.d.ts.map +1 -1
  5. package/dist/data/index.d.ts +1 -0
  6. package/dist/data/index.d.ts.map +1 -1
  7. package/dist/data/mock.d.ts +15 -0
  8. package/dist/data/mock.d.ts.map +1 -1
  9. package/dist/data/supabase.d.ts.map +1 -1
  10. package/dist/data/tables.d.ts +11 -0
  11. package/dist/data/tables.d.ts.map +1 -0
  12. package/dist/data/types.d.ts +2 -1
  13. package/dist/data/types.d.ts.map +1 -1
  14. package/dist/index.cjs +1594 -252
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.ts +13 -1
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +1456 -131
  19. package/dist/index.js.map +1 -1
  20. package/dist/locales/en.d.ts.map +1 -1
  21. package/dist/locales/pt-BR.d.ts.map +1 -1
  22. package/dist/migrations/index.d.ts +16 -0
  23. package/dist/migrations/index.d.ts.map +1 -0
  24. package/dist/quick-add.d.ts +13 -0
  25. package/dist/quick-add.d.ts.map +1 -0
  26. package/dist/registries.d.ts.map +1 -1
  27. package/dist/store.d.ts +3 -1
  28. package/dist/store.d.ts.map +1 -1
  29. package/dist/types.d.ts +42 -0
  30. package/dist/types.d.ts.map +1 -1
  31. package/dist/views/CardsView.d.ts.map +1 -1
  32. package/dist/views/InvoiceListView.d.ts.map +1 -1
  33. package/dist/views/QuickTransactionForm.d.ts +16 -0
  34. package/dist/views/QuickTransactionForm.d.ts.map +1 -0
  35. package/dist/views/SummaryView.d.ts +5 -4
  36. package/dist/views/SummaryView.d.ts.map +1 -1
  37. package/dist/views/dashboardWidgets.d.ts.map +1 -1
  38. package/package.json +7 -4
  39. package/src/FinancialContext.tsx +2 -0
  40. package/src/FinancialPage.tsx +86 -7
  41. package/src/README.md +5 -5
  42. package/src/contract.test.ts +1 -1
  43. package/src/data/capability.test.ts +45 -0
  44. package/src/data/index.ts +1 -0
  45. package/src/data/mock.ts +50 -10
  46. package/src/data/supabase.ts +95 -49
  47. package/src/data/tables.ts +12 -0
  48. package/src/data/types.ts +2 -1
  49. package/src/index.ts +24 -4
  50. package/src/locales/en.ts +75 -0
  51. package/src/locales/pt-BR.ts +75 -0
  52. package/src/migrations/000_plg_rename.sql +30 -0
  53. package/src/migrations/001_financial_base.sql +30 -30
  54. package/src/migrations/002_chart_of_accounts.sql +10 -10
  55. package/src/migrations/003_card_brands.sql +4 -4
  56. package/src/migrations/004_order_to_cash.sql +28 -28
  57. package/src/migrations/005_seed_defaults.sql +6 -6
  58. package/src/migrations/006_rls_policies.sql +5 -5
  59. package/src/migrations/{006_extract_fee_amount.sql → 006b_extract_fee_amount.sql} +4 -4
  60. package/src/migrations/007_reconciliation.sql +9 -9
  61. package/src/migrations/007b_movement_payment_method_type.sql +6 -0
  62. package/src/migrations/008_split_payment_movements.sql +5 -5
  63. package/src/migrations/index.ts +544 -0
  64. package/src/quick-add.ts +58 -0
  65. package/src/registries.ts +8 -7
  66. package/src/store.ts +88 -0
  67. package/src/types.ts +45 -0
  68. package/src/views/CardsView.tsx +186 -50
  69. package/src/views/InvoiceListView.tsx +60 -3
  70. package/src/views/QuickTransactionForm.tsx +537 -0
  71. package/src/views/SummaryView.tsx +197 -6
  72. package/src/views/dashboardWidgets.tsx +251 -5
package/dist/index.cjs CHANGED
@@ -1,17 +1,33 @@
1
1
  'use strict';
2
2
 
3
- var React14 = require('react');
3
+ var React17 = require('react');
4
4
  var core = require('@fayz-ai/core');
5
5
  var ui = require('@fayz-ai/ui');
6
6
  var saas = require('@fayz-ai/saas');
7
- var jsxRuntime = require('react/jsx-runtime');
8
7
  var lucideReact = require('lucide-react');
8
+ var jsxRuntime = require('react/jsx-runtime');
9
9
  var reactDom = require('react-dom');
10
10
  var vanilla = require('zustand/vanilla');
11
11
 
12
- function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
12
+ function _interopNamespace(e) {
13
+ if (e && e.__esModule) return e;
14
+ var n = Object.create(null);
15
+ if (e) {
16
+ Object.keys(e).forEach(function (k) {
17
+ if (k !== 'default') {
18
+ var d = Object.getOwnPropertyDescriptor(e, k);
19
+ Object.defineProperty(n, k, d.get ? d : {
20
+ enumerable: true,
21
+ get: function () { return e[k]; }
22
+ });
23
+ }
24
+ });
25
+ }
26
+ n.default = e;
27
+ return Object.freeze(n);
28
+ }
13
29
 
14
- var React14__default = /*#__PURE__*/_interopDefault(React14);
30
+ var React17__namespace = /*#__PURE__*/_interopNamespace(React17);
15
31
 
16
32
  // src/index.ts
17
33
  var ctx = saas.createPluginContext("FinancialPage");
@@ -20,7 +36,628 @@ var useFinancialConfig = ctx.useConfig;
20
36
  var useFinancialProvider = ctx.useProvider;
21
37
  var useFinancialStore = ctx.useStore;
22
38
  function SummaryView() {
23
- return /* @__PURE__ */ jsxRuntime.jsx(ui.DashboardCanvas, { surface: "plugin-home", domain: "financial", showHeader: false, className: "space-y-6" });
39
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
40
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "md:hidden", children: /* @__PURE__ */ jsxRuntime.jsx(MobileSummary, {}) }),
41
+ /* @__PURE__ */ jsxRuntime.jsx(
42
+ ui.DashboardCanvas,
43
+ {
44
+ surface: "plugin-home",
45
+ domain: "financial",
46
+ showHeader: false,
47
+ className: "hidden space-y-6 md:block"
48
+ }
49
+ )
50
+ ] });
51
+ }
52
+ function categoryIcon(label) {
53
+ const s = label.toLowerCase();
54
+ if (/(mercado|super|padaria|extra|p[aã]o|hortifr)/.test(s)) return lucideReact.ShoppingCart;
55
+ if (/(uber|99|posto|shell|gasol|combust|carro)/.test(s)) return lucideReact.Car;
56
+ if (/(aluguel|casa|condom|im[oó]vel)/.test(s)) return lucideReact.Home;
57
+ if (/(ifood|restaurante|outback|lanche|food|bar\b)/.test(s)) return lucideReact.Utensils;
58
+ if (/(luz|energia|enel|internet|vivo|conta de|[aá]gua)/.test(s)) return lucideReact.Zap;
59
+ if (/(cinema|netflix|cinemark|filme|disney|prime)/.test(s)) return lucideReact.Film;
60
+ if (/(farm|drogasil|sa[uú]de|plano|hospital|m[eé]dic)/.test(s)) return lucideReact.HeartPulse;
61
+ if (/(academia|smartfit|gym|treino)/.test(s)) return lucideReact.Dumbbell;
62
+ if (/(spotify|music|deezer)/.test(s)) return lucideReact.Music;
63
+ if (/(amazon|shopping|loja|magaz|americanas|mercado livre)/.test(s)) return lucideReact.ShoppingBag;
64
+ if (/(fatura|cart[aã]o|nubank|banco|boleto)/.test(s)) return lucideReact.Landmark;
65
+ if (/(sal[aá]rio|freel|pix|reembolso|receb|renda|d[ií]vidend)/.test(s)) return lucideReact.Wallet;
66
+ return lucideReact.CircleDollarSign;
67
+ }
68
+ function useDateLabel() {
69
+ const t2 = core.useTranslation();
70
+ const { currency } = useFinancialConfig();
71
+ return React17.useMemo(() => {
72
+ const todayStr = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
73
+ const y = /* @__PURE__ */ new Date();
74
+ y.setDate(y.getDate() - 1);
75
+ const yesterdayStr = y.toISOString().slice(0, 10);
76
+ return (dateStr) => {
77
+ if (dateStr === todayStr) return t2("financial.summary.today");
78
+ if (dateStr === yesterdayStr) return t2("financial.summary.yesterday");
79
+ try {
80
+ return (/* @__PURE__ */ new Date(`${dateStr}T00:00:00`)).toLocaleDateString(currency.locale, {
81
+ weekday: "short",
82
+ day: "2-digit",
83
+ month: "short"
84
+ });
85
+ } catch {
86
+ return dateStr;
87
+ }
88
+ };
89
+ }, [t2, currency.locale]);
90
+ }
91
+ function MobileSummary() {
92
+ const t2 = core.useTranslation();
93
+ const { currency } = useFinancialConfig();
94
+ const summary = useFinancialStore((s) => s.summary);
95
+ const statement = useFinancialStore((s) => s.statement);
96
+ const bankAccounts = useFinancialStore((s) => s.bankAccounts);
97
+ const fetchSummary = useFinancialStore((s) => s.fetchSummary);
98
+ const fetchBankAccounts = useFinancialStore((s) => s.fetchBankAccounts);
99
+ const fetchStatement = useFinancialStore((s) => s.fetchStatement);
100
+ const dateLabel = useDateLabel();
101
+ React17.useEffect(() => {
102
+ void fetchSummary();
103
+ void fetchBankAccounts();
104
+ const to = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
105
+ const from = /* @__PURE__ */ new Date();
106
+ from.setDate(from.getDate() - 90);
107
+ void fetchStatement({ dateRange: { from: from.toISOString().slice(0, 10), to } });
108
+ }, []);
109
+ const fmt = (n) => saas.formatCurrency(n, currency);
110
+ const inflow = summary?.monthlyInflow ?? 0;
111
+ const outflow = summary?.monthlyOutflow ?? 0;
112
+ const accountName = React17.useMemo(() => {
113
+ const map = new Map(bankAccounts.map((a) => [a.id, a.name]));
114
+ return (id) => id ? map.get(id) ?? "" : "";
115
+ }, [bankAccounts]);
116
+ const groups = React17.useMemo(() => {
117
+ const entries = (statement?.entries ?? []).filter((e) => e.entryKind === "movement");
118
+ const byDate = /* @__PURE__ */ new Map();
119
+ for (const e of entries) {
120
+ const d = e.movement.paymentDate ?? e.movement.dueDate;
121
+ const bucket = byDate.get(d);
122
+ if (bucket) bucket.push(e);
123
+ else byDate.set(d, [e]);
124
+ }
125
+ return [...byDate.entries()].sort((a, b) => b[0].localeCompare(a[0]));
126
+ }, [statement]);
127
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
128
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-2", children: [
129
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "col-span-2 rounded-xl border bg-card p-4", children: [
130
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: t2("financial.summary.totalBalance") }),
131
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-0.5 text-2xl font-semibold", children: fmt(summary?.totalBalance ?? 0) })
132
+ ] }),
133
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border bg-card p-3", children: [
134
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[11px] text-muted-foreground", children: t2("financial.summary.income") }),
135
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-0.5 text-base font-semibold text-success", children: fmt(inflow) })
136
+ ] }),
137
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border bg-card p-3", children: [
138
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[11px] text-muted-foreground", children: t2("financial.summary.expenses") }),
139
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-0.5 text-base font-semibold text-destructive", children: fmt(outflow) })
140
+ ] })
141
+ ] }),
142
+ groups.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-xl border border-dashed py-12 text-center text-sm text-muted-foreground", children: t2("financial.summary.noTransactions") }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-4", children: groups.map(([date, rows]) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
143
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-1 text-xs font-medium uppercase tracking-wide text-muted-foreground", children: dateLabel(date) }),
144
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y overflow-hidden rounded-xl border bg-card", children: rows.map((e) => {
145
+ const isCredit = e.movement.direction === "credit";
146
+ const title = e.invoice?.contactName || e.movement.notes || t2("financial.summary.transactionsTitle");
147
+ const Icon = categoryIcon(title);
148
+ const category = isCredit ? t2("financial.summary.income") : t2("financial.summary.expenses");
149
+ const acct = accountName(e.movement.bankAccountId);
150
+ const subtitle = acct ? `${category} \xB7 ${acct}` : category;
151
+ const receiptUrl = e.invoice?.metadata?.receiptUrl;
152
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 px-3 py-2.5", children: [
153
+ /* @__PURE__ */ jsxRuntime.jsx(
154
+ "span",
155
+ {
156
+ className: `flex h-9 w-9 shrink-0 items-center justify-center rounded-full ${isCredit ? "bg-success-soft text-success-soft-foreground" : "bg-destructive-soft text-destructive-soft-foreground"}`,
157
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "h-4 w-4" })
158
+ }
159
+ ),
160
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
161
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "flex items-center gap-1.5 truncate text-sm font-medium", children: [
162
+ title,
163
+ receiptUrl && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Paperclip, { className: "h-3 w-3 shrink-0 text-muted-foreground", "aria-label": t2("financial.quickTx.receiptAttached") })
164
+ ] }),
165
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "truncate text-xs text-muted-foreground", children: subtitle })
166
+ ] }),
167
+ receiptUrl && /* @__PURE__ */ jsxRuntime.jsx(
168
+ "img",
169
+ {
170
+ src: receiptUrl,
171
+ alt: t2("financial.quickTx.receiptAttached"),
172
+ className: "h-9 w-9 shrink-0 rounded-md border object-cover"
173
+ }
174
+ ),
175
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: `shrink-0 text-sm font-semibold ${isCredit ? "text-success" : "text-destructive"}`, children: [
176
+ isCredit ? "+" : "-",
177
+ fmt(e.net)
178
+ ] })
179
+ ] }, e.movement.id);
180
+ }) })
181
+ ] }, date)) })
182
+ ] });
183
+ }
184
+ function typeTheme(type) {
185
+ switch (type) {
186
+ case "income":
187
+ return { header: "bg-success text-success-foreground", ring: "ring-success", icon: lucideReact.ArrowDownCircle };
188
+ case "transfer":
189
+ return { header: "bg-muted text-foreground", ring: "ring-ring", icon: lucideReact.ArrowLeftRight };
190
+ case "expense":
191
+ default:
192
+ return { header: "bg-destructive text-destructive-foreground", ring: "ring-destructive", icon: lucideReact.ArrowUpCircle };
193
+ }
194
+ }
195
+ function ChipSelect({ icon: Icon, label, value, options, onChange, emptyLabel }) {
196
+ const [open, setOpen] = React17.useState(false);
197
+ const ref = React17.useRef(null);
198
+ React17.useEffect(() => {
199
+ if (!open) return;
200
+ function onDoc(e) {
201
+ if (ref.current && !ref.current.contains(e.target)) setOpen(false);
202
+ }
203
+ document.addEventListener("mousedown", onDoc);
204
+ return () => document.removeEventListener("mousedown", onDoc);
205
+ }, [open]);
206
+ const selected = options.find((o) => o.id === value);
207
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref, className: "relative", children: [
208
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-muted-foreground", children: label }),
209
+ /* @__PURE__ */ jsxRuntime.jsxs(
210
+ "button",
211
+ {
212
+ type: "button",
213
+ onClick: () => setOpen((v) => !v),
214
+ className: "mt-1 flex w-full items-center gap-2 rounded-input border border-input bg-card px-3 py-2.5 text-left text-sm shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] transition-colors hover:bg-muted/30",
215
+ children: [
216
+ /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
217
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: `flex-1 truncate ${selected ? "" : "text-muted-foreground"}`, children: selected?.name ?? emptyLabel }),
218
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: `h-3.5 w-3.5 shrink-0 text-muted-foreground transition-transform ${open ? "rotate-180" : ""}` })
219
+ ]
220
+ }
221
+ ),
222
+ open && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "fayz-glass-surface absolute bottom-full left-0 right-0 z-50 mb-1 max-h-56 overflow-auto rounded-lg border bg-popover py-1 shadow-lg", children: options.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-3 py-4 text-center text-xs text-muted-foreground", children: emptyLabel }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
223
+ value != null && /* @__PURE__ */ jsxRuntime.jsxs(
224
+ "button",
225
+ {
226
+ onClick: () => {
227
+ onChange(void 0);
228
+ setOpen(false);
229
+ },
230
+ className: "flex w-full items-center gap-2 px-3 py-2.5 text-left text-xs text-muted-foreground hover:bg-muted/50",
231
+ children: [
232
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-3.5 w-3.5" }),
233
+ " ",
234
+ emptyLabel
235
+ ]
236
+ }
237
+ ),
238
+ options.map((o) => /* @__PURE__ */ jsxRuntime.jsxs(
239
+ "button",
240
+ {
241
+ onClick: () => {
242
+ onChange(o.id);
243
+ setOpen(false);
244
+ },
245
+ className: `flex w-full items-center gap-2 px-3 py-2.5 text-left text-sm hover:bg-muted/50 ${o.id === value ? "bg-muted/30" : ""}`,
246
+ children: [
247
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 truncate", children: o.name }),
248
+ o.hint && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground", children: o.hint }),
249
+ o.id === value && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-3.5 w-3.5 text-primary" })
250
+ ]
251
+ },
252
+ o.id
253
+ ))
254
+ ] }) })
255
+ ] });
256
+ }
257
+ function TogglePill({ icon: Icon, label, checked, onChange, accent }) {
258
+ return /* @__PURE__ */ jsxRuntime.jsxs(
259
+ "button",
260
+ {
261
+ type: "button",
262
+ onClick: () => onChange(!checked),
263
+ className: `flex items-center gap-2 rounded-full border px-3 py-2 text-xs font-medium transition-colors ${checked ? `border-transparent ${accent ?? "bg-primary text-primary-foreground"}` : "border-input bg-card text-muted-foreground hover:bg-muted/40"}`,
264
+ children: [
265
+ /* @__PURE__ */ jsxRuntime.jsx(Icon, { className: "h-3.5 w-3.5" }),
266
+ label
267
+ ]
268
+ }
269
+ );
270
+ }
271
+ function QuickTransactionForm({ open, onOpenChange, defaultType = "expense", defaultAccountId, focusReceipt = false }) {
272
+ const t2 = core.useTranslation();
273
+ const { currency } = useFinancialConfig();
274
+ const provider = useFinancialProvider();
275
+ const createQuickTransaction = useFinancialStore((s) => s.createQuickTransaction);
276
+ const [type, setType] = React17.useState(defaultType);
277
+ const [amount, setAmount] = React17.useState(0);
278
+ const [amountStr, setAmountStr] = React17.useState("");
279
+ const [paid, setPaid] = React17.useState(true);
280
+ const [date, setDate] = React17.useState(() => (/* @__PURE__ */ new Date()).toISOString().slice(0, 10));
281
+ const [description, setDescription] = React17.useState("");
282
+ const [categoryId, setCategoryId] = React17.useState();
283
+ const [accountId, setAccountId] = React17.useState();
284
+ const [toAccountId, setToAccountId] = React17.useState();
285
+ const [recurring, setRecurring] = React17.useState(false);
286
+ const [saving, setSaving] = React17.useState(false);
287
+ const [receiptUrl, setReceiptUrl] = React17.useState();
288
+ const fileInputRef = React17.useRef(null);
289
+ const [accounts, setAccounts] = React17.useState([]);
290
+ const [categories, setCategories] = React17.useState([]);
291
+ React17.useEffect(() => {
292
+ if (!open) return;
293
+ setType(defaultType);
294
+ setAmount(0);
295
+ setAmountStr("");
296
+ setPaid(true);
297
+ setDate((/* @__PURE__ */ new Date()).toISOString().slice(0, 10));
298
+ setDescription("");
299
+ setCategoryId(void 0);
300
+ setAccountId(defaultAccountId);
301
+ setToAccountId(void 0);
302
+ setRecurring(false);
303
+ setReceiptUrl(void 0);
304
+ }, [open, defaultType, defaultAccountId]);
305
+ React17.useEffect(() => {
306
+ if (open && focusReceipt) {
307
+ const id = window.setTimeout(() => fileInputRef.current?.click(), 250);
308
+ return () => window.clearTimeout(id);
309
+ }
310
+ }, [open, focusReceipt]);
311
+ function onPickReceipt(e) {
312
+ const file = e.target.files?.[0];
313
+ e.target.value = "";
314
+ if (!file) return;
315
+ if (!file.type.startsWith("image/")) {
316
+ ui.toast.error(t2("financial.quickTx.receiptInvalid"));
317
+ return;
318
+ }
319
+ const reader = new FileReader();
320
+ reader.onload = () => {
321
+ setReceiptUrl(typeof reader.result === "string" ? reader.result : void 0);
322
+ };
323
+ reader.onerror = () => ui.toast.error(t2("financial.quickTx.receiptInvalid"));
324
+ reader.readAsDataURL(file);
325
+ }
326
+ React17.useEffect(() => {
327
+ if (!open) return;
328
+ let cancelled = false;
329
+ void (async () => {
330
+ const [accs, coa] = await Promise.all([
331
+ provider.getBankAccounts(),
332
+ provider.getChartOfAccounts().catch(() => [])
333
+ ]);
334
+ if (cancelled) return;
335
+ setAccounts(accs);
336
+ setCategories(coa);
337
+ setAccountId((prev) => prev ?? accs[0]?.id);
338
+ })();
339
+ return () => {
340
+ cancelled = true;
341
+ };
342
+ }, [open, provider]);
343
+ const theme = typeTheme(type);
344
+ const HeaderIcon = theme.icon;
345
+ const accountOptions = React17.useMemo(
346
+ () => accounts.map((a) => ({ id: a.id, name: a.name, hint: a.accountType === "credit_card" ? t2("financial.quickTx.card") : void 0 })),
347
+ [accounts, t2]
348
+ );
349
+ const categoryOptions = React17.useMemo(
350
+ () => categories.filter((c) => c.isActive).map((c) => ({ id: c.id, name: c.name, hint: c.code })),
351
+ [categories]
352
+ );
353
+ function onAmountChange(raw) {
354
+ const cleaned = raw.replace(/[^\d.,]/g, "").replace(",", ".");
355
+ setAmountStr(raw.replace(/[^\d.,]/g, ""));
356
+ const n = Number.parseFloat(cleaned);
357
+ setAmount(Number.isFinite(n) ? n : 0);
358
+ }
359
+ const canSave = amount > 0 && !saving && (type === "transfer" ? !!accountId && !!toAccountId && accountId !== toAccountId : true);
360
+ async function handleSave() {
361
+ if (!canSave) {
362
+ if (type === "transfer" && accountId && accountId === toAccountId) {
363
+ ui.toast.error(t2("financial.transfer.sameAccount"));
364
+ }
365
+ return;
366
+ }
367
+ setSaving(true);
368
+ try {
369
+ await createQuickTransaction({
370
+ type,
371
+ amount,
372
+ date,
373
+ paid: type === "transfer" ? true : paid,
374
+ description: description || void 0,
375
+ categoryId: type === "transfer" ? void 0 : categoryId,
376
+ bankAccountId: accountId,
377
+ toAccountId: type === "transfer" ? toAccountId : void 0,
378
+ recurring: type === "transfer" ? false : recurring,
379
+ receiptUrl: type === "transfer" ? void 0 : receiptUrl
380
+ });
381
+ onOpenChange(false);
382
+ } catch {
383
+ } finally {
384
+ setSaving(false);
385
+ }
386
+ }
387
+ const TYPES = [
388
+ { id: "expense", label: t2("financial.quickTx.expense") },
389
+ { id: "income", label: t2("financial.quickTx.income") },
390
+ { id: "transfer", label: t2("financial.quickTx.transfer") }
391
+ ];
392
+ return /* @__PURE__ */ jsxRuntime.jsx(ui.Modal, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.ModalContent, { size: "md", noPadding: true, hideClose: true, className: "overflow-hidden", children: [
393
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${theme.header} shrink-0 px-5 pb-5 pt-5`, children: [
394
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
395
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
396
+ /* @__PURE__ */ jsxRuntime.jsx(HeaderIcon, { className: "h-5 w-5" }),
397
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-sm font-semibold", children: t2("financial.quickTx.title") })
398
+ ] }),
399
+ /* @__PURE__ */ jsxRuntime.jsx(
400
+ "button",
401
+ {
402
+ onClick: () => onOpenChange(false),
403
+ className: "flex h-7 w-7 items-center justify-center rounded-full opacity-80 transition-colors hover:bg-black/10 hover:opacity-100",
404
+ "aria-label": t2("financial.quickTx.close"),
405
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-4 w-4" })
406
+ }
407
+ )
408
+ ] }),
409
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-4 flex gap-1 rounded-full bg-black/15 p-1", children: TYPES.map((ty) => /* @__PURE__ */ jsxRuntime.jsx(
410
+ "button",
411
+ {
412
+ onClick: () => setType(ty.id),
413
+ className: `flex-1 rounded-full px-2 py-1.5 text-xs font-medium transition-colors ${type === ty.id ? "bg-white/90 text-foreground shadow-sm" : "opacity-90 hover:bg-white/10"}`,
414
+ children: ty.label
415
+ },
416
+ ty.id
417
+ )) }),
418
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-5 flex items-baseline justify-center gap-2", children: [
419
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xl font-medium opacity-90", children: currency.symbol }),
420
+ /* @__PURE__ */ jsxRuntime.jsx(
421
+ "input",
422
+ {
423
+ type: "text",
424
+ inputMode: "decimal",
425
+ autoFocus: true,
426
+ value: amountStr,
427
+ onChange: (e) => onAmountChange(e.target.value),
428
+ onKeyDown: (e) => {
429
+ if (e.key === "Enter") void handleSave();
430
+ },
431
+ placeholder: "0,00",
432
+ className: "w-full max-w-[220px] bg-transparent text-center text-4xl font-bold tracking-tight outline-none placeholder:opacity-40"
433
+ }
434
+ )
435
+ ] })
436
+ ] }),
437
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 space-y-4 overflow-y-auto px-5 py-5", children: [
438
+ type !== "transfer" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between rounded-input border border-input bg-card px-3 py-2.5 shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)]", children: [
439
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium", children: type === "income" ? t2("financial.quickTx.received") : t2("financial.quickTx.paid") }),
440
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-1", children: [
441
+ /* @__PURE__ */ jsxRuntime.jsx(
442
+ "button",
443
+ {
444
+ onClick: () => setPaid(true),
445
+ className: `rounded-full px-3 py-1 text-xs font-medium transition-colors ${paid ? "bg-success text-success-foreground" : "bg-muted text-muted-foreground"}`,
446
+ children: t2("financial.quickTx.yes")
447
+ }
448
+ ),
449
+ /* @__PURE__ */ jsxRuntime.jsx(
450
+ "button",
451
+ {
452
+ onClick: () => setPaid(false),
453
+ className: `rounded-full px-3 py-1 text-xs font-medium transition-colors ${!paid ? "bg-warning text-warning-foreground" : "bg-muted text-muted-foreground"}`,
454
+ children: t2("financial.quickTx.no")
455
+ }
456
+ )
457
+ ] })
458
+ ] }),
459
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
460
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "mb-1 flex items-center gap-1.5 text-xs font-medium text-muted-foreground", children: [
461
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CalendarDays, { className: "h-3.5 w-3.5" }),
462
+ " ",
463
+ t2("financial.invoiceForm.date")
464
+ ] }),
465
+ /* @__PURE__ */ jsxRuntime.jsx(ui.DatePicker, { value: date, onChange: setDate })
466
+ ] }),
467
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
468
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-muted-foreground", children: t2("financial.invoiceForm.description") }),
469
+ /* @__PURE__ */ jsxRuntime.jsx(
470
+ "input",
471
+ {
472
+ type: "text",
473
+ value: description,
474
+ onChange: (e) => setDescription(e.target.value),
475
+ onKeyDown: (e) => {
476
+ if (e.key === "Enter") void handleSave();
477
+ },
478
+ placeholder: t2("financial.quickTx.descriptionPlaceholder"),
479
+ className: "mt-1 w-full rounded-input border border-input bg-card px-3 py-2.5 text-sm shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] outline-none focus:ring-2 focus:ring-ring"
480
+ }
481
+ )
482
+ ] }),
483
+ type !== "transfer" && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
484
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "mb-1 flex items-center gap-1.5 text-xs font-medium text-muted-foreground", children: [
485
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Paperclip, { className: "h-3.5 w-3.5" }),
486
+ " ",
487
+ t2("financial.quickTx.receipt")
488
+ ] }),
489
+ /* @__PURE__ */ jsxRuntime.jsx(
490
+ "input",
491
+ {
492
+ ref: fileInputRef,
493
+ type: "file",
494
+ accept: "image/*",
495
+ capture: "environment",
496
+ className: "hidden",
497
+ onChange: onPickReceipt
498
+ }
499
+ ),
500
+ receiptUrl ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 rounded-input border border-input bg-card p-2 shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)]", children: [
501
+ /* @__PURE__ */ jsxRuntime.jsx(
502
+ "img",
503
+ {
504
+ src: receiptUrl,
505
+ alt: t2("financial.quickTx.receipt"),
506
+ className: "h-16 w-16 shrink-0 rounded-md border object-cover"
507
+ }
508
+ ),
509
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
510
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "truncate text-sm font-medium", children: t2("financial.quickTx.receiptAttached") }),
511
+ /* @__PURE__ */ jsxRuntime.jsx(
512
+ "button",
513
+ {
514
+ type: "button",
515
+ onClick: () => fileInputRef.current?.click(),
516
+ className: "text-xs text-primary hover:underline",
517
+ children: t2("financial.quickTx.receiptReplace")
518
+ }
519
+ )
520
+ ] }),
521
+ /* @__PURE__ */ jsxRuntime.jsx(
522
+ "button",
523
+ {
524
+ type: "button",
525
+ onClick: () => setReceiptUrl(void 0),
526
+ "aria-label": t2("financial.quickTx.receiptRemove"),
527
+ className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-muted",
528
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-4 w-4" })
529
+ }
530
+ )
531
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(
532
+ "button",
533
+ {
534
+ type: "button",
535
+ onClick: () => fileInputRef.current?.click(),
536
+ className: `flex w-full items-center justify-center gap-2 rounded-input border border-dashed px-3 py-3 text-sm font-medium transition-colors hover:bg-muted/30 ${focusReceipt ? "border-primary text-primary ring-1 ring-primary/30" : "border-input text-muted-foreground"}`,
537
+ children: [
538
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Camera, { className: "h-4 w-4" }),
539
+ " ",
540
+ t2("financial.quickTx.receiptCapture")
541
+ ]
542
+ }
543
+ )
544
+ ] }),
545
+ type === "transfer" ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 gap-3", children: [
546
+ /* @__PURE__ */ jsxRuntime.jsx(
547
+ ChipSelect,
548
+ {
549
+ icon: lucideReact.Wallet,
550
+ label: t2("financial.quickTx.fromAccount"),
551
+ value: accountId,
552
+ options: accountOptions,
553
+ onChange: setAccountId,
554
+ emptyLabel: t2("financial.quickTx.selectAccount")
555
+ }
556
+ ),
557
+ /* @__PURE__ */ jsxRuntime.jsx(
558
+ ChipSelect,
559
+ {
560
+ icon: lucideReact.Wallet,
561
+ label: t2("financial.quickTx.toAccount"),
562
+ value: toAccountId,
563
+ options: accountOptions.filter((o) => o.id !== accountId),
564
+ onChange: setToAccountId,
565
+ emptyLabel: t2("financial.quickTx.selectAccount")
566
+ }
567
+ )
568
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 gap-3", children: [
569
+ /* @__PURE__ */ jsxRuntime.jsx(
570
+ ChipSelect,
571
+ {
572
+ icon: lucideReact.Tag,
573
+ label: t2("financial.quickTx.category"),
574
+ value: categoryId,
575
+ options: categoryOptions,
576
+ onChange: setCategoryId,
577
+ emptyLabel: t2("financial.quickTx.selectCategory")
578
+ }
579
+ ),
580
+ /* @__PURE__ */ jsxRuntime.jsx(
581
+ ChipSelect,
582
+ {
583
+ icon: lucideReact.Wallet,
584
+ label: t2("financial.quickTx.account"),
585
+ value: accountId,
586
+ options: accountOptions,
587
+ onChange: setAccountId,
588
+ emptyLabel: t2("financial.quickTx.selectAccount")
589
+ }
590
+ )
591
+ ] }),
592
+ type !== "transfer" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-2", children: [
593
+ /* @__PURE__ */ jsxRuntime.jsx(
594
+ TogglePill,
595
+ {
596
+ icon: lucideReact.Repeat,
597
+ label: t2("financial.quickTx.recurring"),
598
+ checked: recurring,
599
+ onChange: setRecurring
600
+ }
601
+ ),
602
+ /* @__PURE__ */ jsxRuntime.jsxs(
603
+ "button",
604
+ {
605
+ type: "button",
606
+ onClick: () => fileInputRef.current?.click(),
607
+ title: t2("financial.quickTx.attachment"),
608
+ className: `flex items-center gap-2 rounded-full border px-3 py-2 text-xs font-medium transition-colors ${receiptUrl ? "border-transparent bg-primary text-primary-foreground" : "border-input bg-card text-muted-foreground hover:bg-muted/40"}`,
609
+ children: [
610
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Paperclip, { className: "h-3.5 w-3.5" }),
611
+ " ",
612
+ t2("financial.quickTx.attachment"),
613
+ receiptUrl && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-3.5 w-3.5" })
614
+ ]
615
+ }
616
+ )
617
+ ] })
618
+ ] }),
619
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 items-center gap-3 border-t px-5 py-3", children: [
620
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: amount > 0 ? saas.formatCurrency(amount, currency) : t2("financial.quickTx.enterAmount") }),
621
+ /* @__PURE__ */ jsxRuntime.jsxs(
622
+ ui.Button,
623
+ {
624
+ className: "ml-auto",
625
+ onClick: () => void handleSave(),
626
+ disabled: !canSave,
627
+ children: [
628
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-4 w-4" }),
629
+ saving ? t2("financial.quickTx.saving") : t2("financial.quickTx.save")
630
+ ]
631
+ }
632
+ )
633
+ ] })
634
+ ] }) });
635
+ }
636
+ var pending = null;
637
+ var listeners = /* @__PURE__ */ new Set();
638
+ function emit() {
639
+ for (const l of listeners) l();
640
+ }
641
+ function openQuickAdd(type = "expense", receipt = false) {
642
+ pending = { type, receipt };
643
+ emit();
644
+ }
645
+ function consumeQuickAdd() {
646
+ const req = pending;
647
+ pending = null;
648
+ return req;
649
+ }
650
+ function subscribe(cb) {
651
+ listeners.add(cb);
652
+ return () => {
653
+ listeners.delete(cb);
654
+ };
655
+ }
656
+ function getSnapshot() {
657
+ return pending;
658
+ }
659
+ function usePendingQuickAdd() {
660
+ return React17__namespace.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
24
661
  }
25
662
  var STATUS_OPTIONS = [
26
663
  { value: "open", labelKey: "financial.invoice.statusOpen", color: "bg-info-soft text-info-soft-foreground", icon: lucideReact.CircleDashed },
@@ -41,7 +678,7 @@ function StatusBadge({ status }) {
41
678
  }
42
679
  function useInvoiceColumns(currency) {
43
680
  const t2 = core.useTranslation();
44
- return React14.useMemo(() => [
681
+ return React17.useMemo(() => [
45
682
  {
46
683
  accessorKey: "fiscalNumber",
47
684
  header: "#",
@@ -93,27 +730,49 @@ function useInvoiceColumns(currency) {
93
730
  function InvoiceListView({ direction, onNew, onEdit }) {
94
731
  const t2 = core.useTranslation();
95
732
  const { currency } = useFinancialConfig();
733
+ const provider = useFinancialProvider();
96
734
  const invoices = useFinancialStore((s) => s.invoices);
97
735
  useFinancialStore((s) => s.invoicesTotal);
98
736
  const invoicesLoading = useFinancialStore((s) => s.invoicesLoading);
99
737
  const fetchInvoices = useFinancialStore((s) => s.fetchInvoices);
100
- const [search, setSearch] = React14.useState("");
101
- const [statusFilter, setStatusFilter] = React14.useState([]);
102
- React14.useEffect(() => {
738
+ const [search, setSearch] = React17.useState("");
739
+ const [statusFilter, setStatusFilter] = React17.useState([]);
740
+ const [accountId, setAccountId] = React17.useState("");
741
+ const [costCenterId, setCostCenterId] = React17.useState("");
742
+ const [accounts, setAccounts] = React17.useState([]);
743
+ const [costCenters, setCostCenters] = React17.useState([]);
744
+ React17.useEffect(() => {
745
+ let active = true;
746
+ Promise.all([provider.getChartOfAccounts(), provider.getCostCenters()]).then(([accountRows, costCenterRows]) => {
747
+ if (!active) return;
748
+ setAccounts(accountRows.filter((account) => account.nodeType === "leaf"));
749
+ setCostCenters(costCenterRows);
750
+ }).catch(() => {
751
+ if (!active) return;
752
+ setAccounts([]);
753
+ setCostCenters([]);
754
+ });
755
+ return () => {
756
+ active = false;
757
+ };
758
+ }, [provider]);
759
+ React17.useEffect(() => {
103
760
  fetchInvoices({
104
761
  direction,
105
762
  status: statusFilter.length > 0 ? statusFilter : void 0,
106
- search: search || void 0
763
+ search: search || void 0,
764
+ accountId: accountId || void 0,
765
+ costCenterId: costCenterId || void 0
107
766
  });
108
- }, [direction, statusFilter, search]);
767
+ }, [direction, statusFilter, search, accountId, costCenterId]);
109
768
  const filtered = invoices.filter((inv) => inv.direction === direction);
110
769
  const listTitle = direction === "debit" ? t2("financial.invoice.accountsPayable") : t2("financial.invoice.accountsReceivable");
111
770
  const columns = useInvoiceColumns(currency);
112
- const tags = React14.useMemo(
771
+ const tags = React17.useMemo(
113
772
  () => STATUS_OPTIONS.filter((o) => o.value !== "cancelled").map((o) => ({ value: o.value, label: t2(o.labelKey) })),
114
773
  [t2]
115
774
  );
116
- const summary = React14.useMemo(() => {
775
+ const summary = React17.useMemo(() => {
117
776
  let totalAmount = 0;
118
777
  let paidAmount = 0;
119
778
  let openAmount = 0;
@@ -135,6 +794,46 @@ function InvoiceListView({ direction, onNew, onEdit }) {
135
794
  subtitle: t2("financial.invoice.invoices", { count: filtered.length })
136
795
  }
137
796
  ),
797
+ (accounts.length > 0 || costCenters.length > 0) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-end gap-3 rounded-lg border bg-muted/20 px-4 py-3", children: [
798
+ accounts.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex min-w-[220px] flex-col gap-1 text-xs font-medium text-muted-foreground", children: [
799
+ t2("financial.invoice.filterAccount"),
800
+ /* @__PURE__ */ jsxRuntime.jsxs(
801
+ "select",
802
+ {
803
+ className: "h-9 rounded-md border bg-background px-3 text-sm text-foreground",
804
+ value: accountId,
805
+ onChange: (event) => setAccountId(event.target.value),
806
+ children: [
807
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: t2("financial.invoice.filterAllAccounts") }),
808
+ accounts.map((account) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: account.id, children: [
809
+ account.code,
810
+ " - ",
811
+ account.name
812
+ ] }, account.id))
813
+ ]
814
+ }
815
+ )
816
+ ] }),
817
+ costCenters.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex min-w-[220px] flex-col gap-1 text-xs font-medium text-muted-foreground", children: [
818
+ t2("financial.invoice.filterCostCenter"),
819
+ /* @__PURE__ */ jsxRuntime.jsxs(
820
+ "select",
821
+ {
822
+ className: "h-9 rounded-md border bg-background px-3 text-sm text-foreground",
823
+ value: costCenterId,
824
+ onChange: (event) => setCostCenterId(event.target.value),
825
+ children: [
826
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: t2("financial.invoice.filterAllCostCenters") }),
827
+ costCenters.map((costCenter) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: costCenter.id, children: [
828
+ costCenter.code,
829
+ " - ",
830
+ costCenter.name
831
+ ] }, costCenter.id))
832
+ ]
833
+ }
834
+ )
835
+ ] })
836
+ ] }),
138
837
  /* @__PURE__ */ jsxRuntime.jsx(
139
838
  ui.ListView,
140
839
  {
@@ -177,10 +876,10 @@ function InvoiceListView({ direction, onNew, onEdit }) {
177
876
  }
178
877
  function LocationSelector({ locations, value, onChange }) {
179
878
  const t2 = core.useTranslation();
180
- const [open, setOpen] = React14.useState(false);
181
- const [search, setSearch] = React14.useState("");
182
- const ref = React14.useRef(null);
183
- React14.useEffect(() => {
879
+ const [open, setOpen] = React17.useState(false);
880
+ const [search, setSearch] = React17.useState("");
881
+ const ref = React17.useRef(null);
882
+ React17.useEffect(() => {
184
883
  function handler(e) {
185
884
  if (ref.current && !ref.current.contains(e.target)) setOpen(false);
186
885
  }
@@ -260,7 +959,7 @@ function ItemRow({ item, index, itemTypes, currency, expanded, onToggle, onUpdat
260
959
  const total = item.quantity * item.unitPrice - (item.discount ?? 0) + (item.surcharge ?? 0);
261
960
  const kindLabel = itemTypes.find((tp) => tp.value === item.itemKind)?.label ?? item.itemKind;
262
961
  const hasAdjustments = (item.discount ?? 0) > 0 || (item.surcharge ?? 0) > 0;
263
- const [showAdjustments, setShowAdjustments] = React14.useState(hasAdjustments);
962
+ const [showAdjustments, setShowAdjustments] = React17.useState(hasAdjustments);
264
963
  function handleFieldKeyDown(e) {
265
964
  if (e.key === "Enter" && !e.shiftKey) {
266
965
  e.preventDefault();
@@ -496,25 +1195,25 @@ function InvoiceFormView({ direction, editId, onSaved }) {
496
1195
  const createInvoice = useFinancialStore((s) => s.createInvoice);
497
1196
  const hasLocations = locations.length > 0;
498
1197
  const isEdit = !!editId;
499
- const [loaded, setLoaded] = React14.useState(!editId);
500
- const [loading, setLoading] = React14.useState(!!editId);
501
- const [contactName, setContactName] = React14.useState("");
502
- const [contactId, setContactId] = React14.useState();
503
- const [unitId, setUnitId] = React14.useState(locations[0]?.id ?? "");
504
- const [invoiceDate, setInvoiceDate] = React14.useState((/* @__PURE__ */ new Date()).toISOString().slice(0, 10));
505
- const [fiscalNumber, setFiscalNumber] = React14.useState("");
506
- const [observations, setObservations] = React14.useState("");
507
- const [items, setItems] = React14.useState([]);
508
- const [expandedItemId, setExpandedItemId] = React14.useState(null);
509
- const [addingItem, setAddingItem] = React14.useState(false);
510
- const [installments, setInstallments] = React14.useState([]);
511
- const [saving, setSaving] = React14.useState(false);
512
- const [menuOpen, setMenuOpen] = React14.useState(false);
513
- const [confirmCancel, setConfirmCancel] = React14.useState(false);
514
- const [cancelling, setCancelling] = React14.useState(false);
515
- const menuRef = React14.useRef(null);
1198
+ const [loaded, setLoaded] = React17.useState(!editId);
1199
+ const [loading, setLoading] = React17.useState(!!editId);
1200
+ const [contactName, setContactName] = React17.useState("");
1201
+ const [contactId, setContactId] = React17.useState();
1202
+ const [unitId, setUnitId] = React17.useState(locations[0]?.id ?? "");
1203
+ const [invoiceDate, setInvoiceDate] = React17.useState((/* @__PURE__ */ new Date()).toISOString().slice(0, 10));
1204
+ const [fiscalNumber, setFiscalNumber] = React17.useState("");
1205
+ const [observations, setObservations] = React17.useState("");
1206
+ const [items, setItems] = React17.useState([]);
1207
+ const [expandedItemId, setExpandedItemId] = React17.useState(null);
1208
+ const [addingItem, setAddingItem] = React17.useState(false);
1209
+ const [installments, setInstallments] = React17.useState([]);
1210
+ const [saving, setSaving] = React17.useState(false);
1211
+ const [menuOpen, setMenuOpen] = React17.useState(false);
1212
+ const [confirmCancel, setConfirmCancel] = React17.useState(false);
1213
+ const [cancelling, setCancelling] = React17.useState(false);
1214
+ const menuRef = React17.useRef(null);
516
1215
  const cancelInvoice = useFinancialStore((s) => s.cancelInvoice);
517
- React14.useEffect(() => {
1216
+ React17.useEffect(() => {
518
1217
  if (!menuOpen) return;
519
1218
  function handleClick(e) {
520
1219
  if (menuRef.current && !menuRef.current.contains(e.target)) setMenuOpen(false);
@@ -533,7 +1232,7 @@ function InvoiceFormView({ direction, editId, onSaved }) {
533
1232
  setCancelling(false);
534
1233
  }
535
1234
  }
536
- React14.useEffect(() => {
1235
+ React17.useEffect(() => {
537
1236
  if (!editId || loaded) return;
538
1237
  setLoading(true);
539
1238
  (async () => {
@@ -570,8 +1269,8 @@ function InvoiceFormView({ direction, editId, onSaved }) {
570
1269
  const totalAmount = items.reduce((sum, it) => {
571
1270
  return sum + it.quantity * it.unitPrice - (it.discount ?? 0) + (it.surcharge ?? 0);
572
1271
  }, 0);
573
- const prevItemCount = React14.useRef(items.length);
574
- React14.useEffect(() => {
1272
+ const prevItemCount = React17.useRef(items.length);
1273
+ React17.useEffect(() => {
575
1274
  if (items.length > 0 && prevItemCount.current === 0 && installments.length === 0 && !isEdit) {
576
1275
  const total = items.reduce((sum, it) => sum + it.quantity * it.unitPrice - (it.discount ?? 0) + (it.surcharge ?? 0), 0);
577
1276
  if (total > 0) {
@@ -580,7 +1279,7 @@ function InvoiceFormView({ direction, editId, onSaved }) {
580
1279
  }
581
1280
  prevItemCount.current = items.length;
582
1281
  }, [items.length]);
583
- React14.useEffect(() => {
1282
+ React17.useEffect(() => {
584
1283
  if (installments.length > 0 && totalAmount > 0 && !isEdit) {
585
1284
  const count = installments.length;
586
1285
  const perInstallment = Math.floor(totalAmount * 100 / count) / 100;
@@ -692,8 +1391,8 @@ function InvoiceFormView({ direction, editId, onSaved }) {
692
1391
  items: items.map(({ _id, ...rest }) => rest),
693
1392
  installments: installments.map(({ _id, ...rest }) => rest)
694
1393
  };
695
- const snapshot = React14.useRef(null);
696
- React14.useEffect(() => {
1394
+ const snapshot = React17.useRef(null);
1395
+ React17.useEffect(() => {
697
1396
  if (loaded && snapshot.current === null) snapshot.current = JSON.stringify(fields);
698
1397
  }, [loaded]);
699
1398
  const dirty = snapshot.current !== null && JSON.stringify(fields) !== snapshot.current;
@@ -1003,40 +1702,40 @@ function PaymentModal({ movement, onClose, onPaid }) {
1003
1702
  const fetchBankAccounts = useFinancialStore((s) => s.fetchBankAccounts);
1004
1703
  const fetchPaymentMethods = useFinancialStore((s) => s.fetchPaymentMethods);
1005
1704
  const remaining = movement.amount - movement.paidAmount;
1006
- const [amount, setAmount] = React14.useState(remaining);
1007
- const [paymentDate, setPaymentDate] = React14.useState((/* @__PURE__ */ new Date()).toISOString().slice(0, 10));
1008
- const [selectedTypeId, setSelectedTypeId] = React14.useState("");
1009
- const [paymentMethodId, setPaymentMethodId] = React14.useState("");
1010
- const [bankAccountId, setBankAccountId] = React14.useState("");
1011
- const [cardBrand, setCardBrand] = React14.useState("");
1012
- const [cardInstallments, setCardInstallments] = React14.useState(1);
1013
- const [notes, setNotes] = React14.useState("");
1014
- const [saving, setSaving] = React14.useState(false);
1015
- const [visible, setVisible] = React14.useState(false);
1016
- const [expandMethodPicker, setExpandMethodPicker] = React14.useState(true);
1017
- React14.useEffect(() => {
1705
+ const [amount, setAmount] = React17.useState(remaining);
1706
+ const [paymentDate, setPaymentDate] = React17.useState((/* @__PURE__ */ new Date()).toISOString().slice(0, 10));
1707
+ const [selectedTypeId, setSelectedTypeId] = React17.useState("");
1708
+ const [paymentMethodId, setPaymentMethodId] = React17.useState("");
1709
+ const [bankAccountId, setBankAccountId] = React17.useState("");
1710
+ const [cardBrand, setCardBrand] = React17.useState("");
1711
+ const [cardInstallments, setCardInstallments] = React17.useState(1);
1712
+ const [notes, setNotes] = React17.useState("");
1713
+ const [saving, setSaving] = React17.useState(false);
1714
+ const [visible, setVisible] = React17.useState(false);
1715
+ const [expandMethodPicker, setExpandMethodPicker] = React17.useState(true);
1716
+ React17.useEffect(() => {
1018
1717
  fetchBankAccounts();
1019
1718
  fetchPaymentMethods();
1020
1719
  requestAnimationFrame(() => setVisible(true));
1021
1720
  }, []);
1022
- const selectedType = React14.useMemo(
1721
+ const selectedType = React17.useMemo(
1023
1722
  () => paymentMethodTypes.find((tp) => tp.id === selectedTypeId),
1024
1723
  [paymentMethodTypes, selectedTypeId]
1025
1724
  );
1026
1725
  const txType = selectedType?.transactionType ?? "";
1027
- const filteredMethods = React14.useMemo(
1726
+ const filteredMethods = React17.useMemo(
1028
1727
  () => paymentMethods.filter((m) => m.paymentMethodTypeId === selectedTypeId),
1029
1728
  [paymentMethods, selectedTypeId]
1030
1729
  );
1031
1730
  const needsCard = txType === "credit_card" || txType === "debit_card";
1032
1731
  const needsCardInstallments = txType === "credit_card";
1033
- const eligibleAccounts = React14.useMemo(() => {
1732
+ const eligibleAccounts = React17.useMemo(() => {
1034
1733
  const allowed = selectedType?.allowedAccountTypes && selectedType.allowedAccountTypes.length ? selectedType.allowedAccountTypes : ACCOUNT_TYPES_FOR_TX[txType];
1035
1734
  if (!allowed || !allowed.length) return bankAccounts;
1036
1735
  const filtered = bankAccounts.filter((a) => allowed.includes(a.accountType));
1037
1736
  return filtered.length ? filtered : bankAccounts;
1038
1737
  }, [bankAccounts, selectedType, txType]);
1039
- React14.useEffect(() => {
1738
+ React17.useEffect(() => {
1040
1739
  if (selectedTypeId && !bankAccountId && eligibleAccounts.length) {
1041
1740
  setBankAccountId(eligibleAccounts[0].id);
1042
1741
  }
@@ -1280,19 +1979,19 @@ function InvoiceDetailView({ invoiceId, direction, onBack, onEdit, backLabel })
1280
1979
  const bankAccounts = useFinancialStore((s) => s.bankAccounts);
1281
1980
  const fetchPaymentMethods = useFinancialStore((s) => s.fetchPaymentMethods);
1282
1981
  const fetchBankAccounts = useFinancialStore((s) => s.fetchBankAccounts);
1283
- const [detailsLoaded, setDetailsLoaded] = React14.useState(false);
1284
- const [detailsLoading, setDetailsLoading] = React14.useState(false);
1285
- const [invoice, setInvoice] = React14.useState(null);
1286
- const [items, setItems] = React14.useState([]);
1287
- const [movements, setMovements] = React14.useState([]);
1288
- const [payments, setPayments] = React14.useState([]);
1289
- const [loading, setLoading] = React14.useState(true);
1290
- const [payingMovement, setPayingMovement] = React14.useState(null);
1291
- const [expandedMovId, setExpandedMovId] = React14.useState(null);
1292
- const [menuOpen, setMenuOpen] = React14.useState(false);
1293
- const [confirmCancel, setConfirmCancel] = React14.useState(false);
1294
- const [cancelling, setCancelling] = React14.useState(false);
1295
- const menuRef = React14.useRef(null);
1982
+ const [detailsLoaded, setDetailsLoaded] = React17.useState(false);
1983
+ const [detailsLoading, setDetailsLoading] = React17.useState(false);
1984
+ const [invoice, setInvoice] = React17.useState(null);
1985
+ const [items, setItems] = React17.useState([]);
1986
+ const [movements, setMovements] = React17.useState([]);
1987
+ const [payments, setPayments] = React17.useState([]);
1988
+ const [loading, setLoading] = React17.useState(true);
1989
+ const [payingMovement, setPayingMovement] = React17.useState(null);
1990
+ const [expandedMovId, setExpandedMovId] = React17.useState(null);
1991
+ const [menuOpen, setMenuOpen] = React17.useState(false);
1992
+ const [confirmCancel, setConfirmCancel] = React17.useState(false);
1993
+ const [cancelling, setCancelling] = React17.useState(false);
1994
+ const menuRef = React17.useRef(null);
1296
1995
  const cancelInvoice = useFinancialStore((s) => s.cancelInvoice);
1297
1996
  async function loadData() {
1298
1997
  setLoading(true);
@@ -1311,10 +2010,10 @@ function InvoiceDetailView({ invoiceId, direction, onBack, onEdit, backLabel })
1311
2010
  );
1312
2011
  setLoading(false);
1313
2012
  }
1314
- React14.useEffect(() => {
2013
+ React17.useEffect(() => {
1315
2014
  loadData();
1316
2015
  }, [invoiceId]);
1317
- React14.useEffect(() => {
2016
+ React17.useEffect(() => {
1318
2017
  if (!menuOpen) return;
1319
2018
  function handleClick(e) {
1320
2019
  if (menuRef.current && !menuRef.current.contains(e.target)) setMenuOpen(false);
@@ -1915,16 +2614,16 @@ function CashOpeningPanel({
1915
2614
  currency,
1916
2615
  onOpen
1917
2616
  }) {
1918
- const [selectedAccountId, setSelectedAccountId] = React14.useState(cashAccounts[0]?.id ?? "");
1919
- const [mode, setMode] = React14.useState("quick");
1920
- const [quickBalance, setQuickBalance] = React14.useState(0);
1921
- const [counts, setCounts] = React14.useState({});
1922
- const [notes, setNotes] = React14.useState("");
1923
- const [showNotes, setShowNotes] = React14.useState(false);
1924
- const [confirming, setConfirming] = React14.useState(false);
1925
- const [submitting, setSubmitting] = React14.useState(false);
2617
+ const [selectedAccountId, setSelectedAccountId] = React17.useState(cashAccounts[0]?.id ?? "");
2618
+ const [mode, setMode] = React17.useState("quick");
2619
+ const [quickBalance, setQuickBalance] = React17.useState(0);
2620
+ const [counts, setCounts] = React17.useState({});
2621
+ const [notes, setNotes] = React17.useState("");
2622
+ const [showNotes, setShowNotes] = React17.useState(false);
2623
+ const [confirming, setConfirming] = React17.useState(false);
2624
+ const [submitting, setSubmitting] = React17.useState(false);
1926
2625
  const t2 = core.useTranslation();
1927
- const countedTotal = React14.useMemo(() => {
2626
+ const countedTotal = React17.useMemo(() => {
1928
2627
  return BRL_DENOMINATIONS.reduce((sum, d) => sum + (counts[d.value] ?? 0) * d.value, 0);
1929
2628
  }, [counts]);
1930
2629
  const effectiveBalance = mode === "count" ? countedTotal : quickBalance;
@@ -2100,13 +2799,13 @@ function CashClosingPanel({
2100
2799
  currency,
2101
2800
  onClose
2102
2801
  }) {
2103
- const [mode, setMode] = React14.useState("quick");
2104
- const [quickBalance, setQuickBalance] = React14.useState(0);
2105
- const [counts, setCounts] = React14.useState({});
2106
- const [notes, setNotes] = React14.useState("");
2107
- const [submitting, setSubmitting] = React14.useState(false);
2802
+ const [mode, setMode] = React17.useState("quick");
2803
+ const [quickBalance, setQuickBalance] = React17.useState(0);
2804
+ const [counts, setCounts] = React17.useState({});
2805
+ const [notes, setNotes] = React17.useState("");
2806
+ const [submitting, setSubmitting] = React17.useState(false);
2108
2807
  const t2 = core.useTranslation();
2109
- const countedTotal = React14.useMemo(() => {
2808
+ const countedTotal = React17.useMemo(() => {
2110
2809
  return BRL_DENOMINATIONS.reduce((sum, d) => sum + (counts[d.value] ?? 0) * d.value, 0);
2111
2810
  }, [counts]);
2112
2811
  const effectiveBalance = mode === "count" ? countedTotal : quickBalance;
@@ -2211,8 +2910,8 @@ function CashRegistersView() {
2211
2910
  const fetchCashSessions = useFinancialStore((s) => s.fetchCashSessions);
2212
2911
  const openCashSession = useFinancialStore((s) => s.openCashSession);
2213
2912
  const closeCashSession = useFinancialStore((s) => s.closeCashSession);
2214
- const [expandedClosing, setExpandedClosing] = React14.useState(null);
2215
- React14.useEffect(() => {
2913
+ const [expandedClosing, setExpandedClosing] = React17.useState(null);
2914
+ React17.useEffect(() => {
2216
2915
  fetchBankAccounts();
2217
2916
  fetchCashSessions();
2218
2917
  }, []);
@@ -2316,7 +3015,7 @@ function OpenAnotherCollapsible({
2316
3015
  onOpen
2317
3016
  }) {
2318
3017
  const t2 = core.useTranslation();
2319
- const [expanded, setExpanded] = React14.useState(false);
3018
+ const [expanded, setExpanded] = React17.useState(false);
2320
3019
  const availableAccounts = cashAccounts.filter((a) => !openSessions.some((s) => s.bankAccountId === a.id));
2321
3020
  if (availableAccounts.length === 0) return null;
2322
3021
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border bg-card shadow-sm", children: [
@@ -2343,14 +3042,14 @@ function TransferModal({ onClose, onDone, defaultFromId }) {
2343
3042
  const bankAccounts = useFinancialStore((s) => s.bankAccounts);
2344
3043
  const createTransfer = useFinancialStore((s) => s.createTransfer);
2345
3044
  const fetchBankAccounts = useFinancialStore((s) => s.fetchBankAccounts);
2346
- const [fromAccountId, setFromAccountId] = React14.useState(defaultFromId ?? "");
2347
- const [toAccountId, setToAccountId] = React14.useState("");
2348
- const [amount, setAmount] = React14.useState(0);
2349
- const [date, setDate] = React14.useState((/* @__PURE__ */ new Date()).toISOString().slice(0, 10));
2350
- const [notes, setNotes] = React14.useState("");
2351
- const [saving, setSaving] = React14.useState(false);
2352
- const [visible, setVisible] = React14.useState(false);
2353
- React14.useEffect(() => {
3045
+ const [fromAccountId, setFromAccountId] = React17.useState(defaultFromId ?? "");
3046
+ const [toAccountId, setToAccountId] = React17.useState("");
3047
+ const [amount, setAmount] = React17.useState(0);
3048
+ const [date, setDate] = React17.useState((/* @__PURE__ */ new Date()).toISOString().slice(0, 10));
3049
+ const [notes, setNotes] = React17.useState("");
3050
+ const [saving, setSaving] = React17.useState(false);
3051
+ const [visible, setVisible] = React17.useState(false);
3052
+ React17.useEffect(() => {
2354
3053
  fetchBankAccounts();
2355
3054
  requestAnimationFrame(() => setVisible(true));
2356
3055
  }, []);
@@ -2493,19 +3192,19 @@ function StatementsView({ onNavigate }) {
2493
3192
  const fetchBankAccounts = useFinancialStore((s) => s.fetchBankAccounts);
2494
3193
  const fetchPaymentMethods = useFinancialStore((s) => s.fetchPaymentMethods);
2495
3194
  const fetchStatement = useFinancialStore((s) => s.fetchStatement);
2496
- const [accountId, setAccountId] = React14.useState("");
2497
- const [dateFrom, setDateFrom] = React14.useState(() => {
3195
+ const [accountId, setAccountId] = React17.useState("");
3196
+ const [dateFrom, setDateFrom] = React17.useState(() => {
2498
3197
  const d = /* @__PURE__ */ new Date();
2499
3198
  d.setMonth(d.getMonth() - 3);
2500
3199
  return d.toISOString().slice(0, 10);
2501
3200
  });
2502
- const [dateTo, setDateTo] = React14.useState(() => (/* @__PURE__ */ new Date()).toISOString().slice(0, 10));
2503
- const [showTransfer, setShowTransfer] = React14.useState(false);
2504
- React14.useEffect(() => {
3201
+ const [dateTo, setDateTo] = React17.useState(() => (/* @__PURE__ */ new Date()).toISOString().slice(0, 10));
3202
+ const [showTransfer, setShowTransfer] = React17.useState(false);
3203
+ React17.useEffect(() => {
2505
3204
  fetchBankAccounts();
2506
3205
  fetchPaymentMethods();
2507
3206
  }, []);
2508
- const methodName = React14.useMemo(() => {
3207
+ const methodName = React17.useMemo(() => {
2509
3208
  const byId = new Map(paymentMethods.map((m) => [m.id, m.name]));
2510
3209
  const typeById = new Map(paymentMethodTypes.map((tp) => [tp.id, tp.name]));
2511
3210
  return (mov) => {
@@ -2520,7 +3219,7 @@ function StatementsView({ onNavigate }) {
2520
3219
  const base = e.movement.direction === "credit" ? "receivables" : "payables";
2521
3220
  onNavigate(`${base}-detail:${e.movement.invoiceId}`);
2522
3221
  }
2523
- React14.useEffect(() => {
3222
+ React17.useEffect(() => {
2524
3223
  if (accountId) {
2525
3224
  fetchStatement({
2526
3225
  bankAccountId: accountId === ALL ? void 0 : accountId,
@@ -2528,11 +3227,11 @@ function StatementsView({ onNavigate }) {
2528
3227
  });
2529
3228
  }
2530
3229
  }, [accountId, dateFrom, dateTo]);
2531
- React14.useEffect(() => {
3230
+ React17.useEffect(() => {
2532
3231
  if (!accountId) setAccountId(ALL);
2533
3232
  }, []);
2534
3233
  const fmt = (n) => saas.formatCurrency(n, currency);
2535
- const columns = React14.useMemo(() => [
3234
+ const columns = React17.useMemo(() => [
2536
3235
  {
2537
3236
  id: "date",
2538
3237
  header: t2("financial.statements.columnDate"),
@@ -2707,59 +3406,141 @@ function CommissionsView() {
2707
3406
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center rounded-lg border-2 border-dashed border-muted p-12", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: t2("financial.commissions.comingSoon") }) })
2708
3407
  ] });
2709
3408
  }
3409
+ function cardMath(acc) {
3410
+ const limit = acc.creditLimit ?? 0;
3411
+ const used = Math.max(0, -acc.currentBalance);
3412
+ const available = Math.max(0, limit - used);
3413
+ const pct = limit > 0 ? Math.min(100, used / limit * 100) : 0;
3414
+ return { limit, used, available, pct };
3415
+ }
2710
3416
  function CardsView() {
2711
3417
  const t2 = core.useTranslation();
2712
- const { currency, labels } = useFinancialConfig();
2713
- const cardTransactions = useFinancialStore((s) => s.cardTransactions);
2714
- const cardsLoading = useFinancialStore((s) => s.cardsLoading);
2715
- const fetchCardTransactions = useFinancialStore((s) => s.fetchCardTransactions);
2716
- React14.useEffect(() => {
2717
- fetchCardTransactions();
3418
+ const { currency } = useFinancialConfig();
3419
+ const bankAccounts = useFinancialStore((s) => s.bankAccounts);
3420
+ const bankAccountsLoading = useFinancialStore((s) => s.bankAccountsLoading);
3421
+ const fetchBankAccounts = useFinancialStore((s) => s.fetchBankAccounts);
3422
+ const [tab, setTab] = React17.useState("open");
3423
+ const [addOpen, setAddOpen] = React17.useState(false);
3424
+ const [addCardId, setAddCardId] = React17.useState();
3425
+ React17.useEffect(() => {
3426
+ fetchBankAccounts();
2718
3427
  }, []);
2719
- const byBrand = {};
2720
- for (const tx of cardTransactions) {
2721
- const brand = tx.cardBrand || "Other";
2722
- if (!byBrand[brand]) byBrand[brand] = [];
2723
- byBrand[brand].push(tx);
3428
+ const cards = React17.useMemo(
3429
+ () => bankAccounts.filter((a) => a.accountType === "credit_card"),
3430
+ [bankAccounts]
3431
+ );
3432
+ const openCards = React17.useMemo(() => cards.filter((c) => c.isActive), [cards]);
3433
+ const closedCards = React17.useMemo(() => cards.filter((c) => !c.isActive), [cards]);
3434
+ const visibleCards = tab === "open" ? openCards : closedCards;
3435
+ const summary = React17.useMemo(() => {
3436
+ let totalAvailable = 0;
3437
+ let totalBills = 0;
3438
+ for (const c of openCards) {
3439
+ const { available, used } = cardMath(c);
3440
+ totalAvailable += available;
3441
+ totalBills += used;
3442
+ }
3443
+ return { totalAvailable, totalBills };
3444
+ }, [openCards]);
3445
+ function openAddExpense(cardId) {
3446
+ setAddCardId(cardId);
3447
+ setAddOpen(true);
2724
3448
  }
2725
3449
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
2726
3450
  /* @__PURE__ */ jsxRuntime.jsx(ui.SubpageHeader, { title: t2("financial.cards.title"), subtitle: t2("financial.cards.subtitle") }),
2727
- cardsLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center py-12 text-sm text-muted-foreground", children: "Loading..." }) : cardTransactions.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center py-12 text-center rounded-lg border-2 border-dashed border-muted", children: [
2728
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-10 w-10 items-center justify-center rounded-lg bg-indigo-50 dark:bg-indigo-500/20 mb-2", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CreditCard, { className: "h-5 w-5 text-indigo-500" }) }),
2729
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: t2("financial.cards.noTransactions") }),
2730
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground mt-0.5", children: t2("financial.cards.transactionsAppear") })
2731
- ] }) : Object.entries(byBrand).map(([brand, txs]) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border bg-card shadow-sm", children: [
2732
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 px-4 py-3 border-b", children: [
2733
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CreditCard, { className: "h-4 w-4 text-indigo-500" }),
2734
- /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-sm font-semibold", children: brand }),
2735
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground", children: [
2736
- "(",
2737
- txs.length,
2738
- " transactions)"
3451
+ bankAccountsLoading && cards.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center py-12 text-sm text-muted-foreground", children: "Loading..." }) : cards.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center py-12 text-center rounded-2xl border-2 border-dashed border-muted", children: [
3452
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-12 w-12 items-center justify-center rounded-xl bg-gradient-to-br from-amber-300 to-yellow-600 mb-3 text-white shadow-sm", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CreditCard, { className: "h-6 w-6" }) }),
3453
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium", children: t2("financial.cards.noCards") }),
3454
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground mt-0.5 max-w-xs", children: t2("financial.cards.noCardsHint") })
3455
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3456
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-px overflow-hidden rounded-2xl border bg-border shadow-sm", children: [
3457
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-card px-4 py-3", children: [
3458
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: t2("financial.cards.availableLimit") }),
3459
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-0.5 text-lg font-bold tabular-nums text-success", children: saas.formatCurrency(summary.totalAvailable, currency) })
3460
+ ] }),
3461
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-card px-4 py-3", children: [
3462
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: t2("financial.cards.allBillsValue") }),
3463
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-0.5 text-lg font-bold tabular-nums", children: saas.formatCurrency(summary.totalBills, currency) })
2739
3464
  ] })
2740
3465
  ] }),
2741
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y", children: txs.map((tx) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-4 py-3 flex items-center justify-between", children: [
2742
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2743
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm font-medium", children: [
2744
- "Installment ",
2745
- tx.currentInstallment,
2746
- "/",
2747
- tx.installmentCount
3466
+ closedCards.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-1 rounded-full bg-muted p-1 w-full max-w-xs", children: ["open", "closed"].map((k) => /* @__PURE__ */ jsxRuntime.jsx(
3467
+ "button",
3468
+ {
3469
+ onClick: () => setTab(k),
3470
+ className: `flex-1 rounded-full px-3 py-1.5 text-xs font-medium transition-colors ${tab === k ? "bg-card text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"}`,
3471
+ children: k === "open" ? t2("financial.cards.tabOpen") : t2("financial.cards.tabClosed")
3472
+ },
3473
+ k
3474
+ )) }),
3475
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3", children: visibleCards.map((card) => {
3476
+ const { limit, used, available, pct } = cardMath(card);
3477
+ const over = pct >= 90;
3478
+ const brand = `${card.bankName ?? ""} ${card.name ?? ""}`.toLowerCase();
3479
+ const headerGrad = brand.includes("nubank") || brand.includes("nu ") ? "from-purple-500 via-purple-600 to-indigo-700" : brand.includes("ita") ? "from-orange-400 via-orange-500 to-amber-600" : brand.includes("inter") ? "from-orange-500 via-orange-600 to-orange-700" : "from-indigo-500 via-indigo-600 to-violet-700";
3480
+ const barGrad = brand.includes("nubank") || brand.includes("nu ") ? "from-purple-500 to-indigo-600" : brand.includes("ita") ? "from-orange-400 to-amber-500" : brand.includes("inter") ? "from-orange-500 to-orange-600" : "from-indigo-500 to-violet-600";
3481
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "overflow-hidden rounded-2xl border bg-card shadow-sm", children: [
3482
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `bg-gradient-to-br ${headerGrad} px-4 py-4 text-white`, children: [
3483
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between", children: [
3484
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
3485
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CreditCard, { className: "h-5 w-5" }),
3486
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold", children: card.name })
3487
+ ] }),
3488
+ card.bankName && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[11px] font-medium uppercase tracking-wide opacity-80", children: card.bankName })
3489
+ ] }),
3490
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4", children: [
3491
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[11px] uppercase tracking-wide opacity-80", children: t2("financial.cards.currentBill") }),
3492
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-2xl font-bold tabular-nums leading-tight", children: saas.formatCurrency(used, currency) })
3493
+ ] })
2748
3494
  ] }),
2749
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-muted-foreground", children: [
2750
- "Due: ",
2751
- tx.expectedDate
3495
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3 px-4 py-3", children: [
3496
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3497
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between text-[11px] text-muted-foreground", children: [
3498
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: t2("financial.cards.usedOfLimit", { percent: String(Math.round(pct)) }) }),
3499
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "tabular-nums", children: saas.formatCurrency(limit, currency) })
3500
+ ] }),
3501
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 h-2 overflow-hidden rounded-full bg-muted", children: /* @__PURE__ */ jsxRuntime.jsx(
3502
+ "div",
3503
+ {
3504
+ className: `h-full rounded-full ${over ? "bg-destructive" : `bg-gradient-to-r ${barGrad}`}`,
3505
+ style: { width: `${pct}%` }
3506
+ }
3507
+ ) })
3508
+ ] }),
3509
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
3510
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3511
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[11px] text-muted-foreground", children: t2("financial.cards.availableLimit") }),
3512
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold tabular-nums", children: saas.formatCurrency(available, currency) })
3513
+ ] }),
3514
+ card.dueDay != null && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 text-right text-xs text-muted-foreground", children: [
3515
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CalendarClock, { className: "h-3.5 w-3.5" }),
3516
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: t2("financial.cards.dueOn", { day: String(card.dueDay) }) })
3517
+ ] })
3518
+ ] }),
3519
+ /* @__PURE__ */ jsxRuntime.jsxs(
3520
+ "button",
3521
+ {
3522
+ type: "button",
3523
+ onClick: () => openAddExpense(card.id),
3524
+ className: "flex w-full items-center justify-center gap-1.5 rounded-input border border-input bg-card px-3 py-2 text-xs font-medium text-foreground transition-colors hover:bg-muted/40",
3525
+ children: [
3526
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "h-3.5 w-3.5" }),
3527
+ t2("financial.cards.addExpense")
3528
+ ]
3529
+ }
3530
+ )
2752
3531
  ] })
2753
- ] }),
2754
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
2755
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium", children: saas.formatCurrency(tx.installmentAmount, currency) }),
2756
- tx.status === "received" ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 rounded-full bg-success/15 px-2 py-0.5 text-[10px] font-medium text-success dark:bg-success/20", children: [
2757
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "h-2.5 w-2.5" }),
2758
- " Received"
2759
- ] }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex items-center rounded-full bg-warning/15 px-2 py-0.5 text-[10px] font-medium text-warning dark:bg-warning/20", children: "Pending" })
2760
- ] })
2761
- ] }, tx.id)) })
2762
- ] }, brand))
3532
+ ] }, card.id);
3533
+ }) })
3534
+ ] }),
3535
+ /* @__PURE__ */ jsxRuntime.jsx(
3536
+ QuickTransactionForm,
3537
+ {
3538
+ open: addOpen,
3539
+ onOpenChange: setAddOpen,
3540
+ defaultType: "expense",
3541
+ defaultAccountId: addCardId
3542
+ }
3543
+ )
2763
3544
  ] });
2764
3545
  }
2765
3546
  function ReconciliationView() {
@@ -2767,14 +3548,14 @@ function ReconciliationView() {
2767
3548
  const { currency } = useFinancialConfig();
2768
3549
  const provider = useFinancialProvider();
2769
3550
  const fmt = (n) => saas.formatCurrency(n, currency);
2770
- const [lines, setLines] = React14.useState([]);
2771
- const [loading, setLoading] = React14.useState(true);
2772
- const [selectedId, setSelectedId] = React14.useState(null);
2773
- const [candidates, setCandidates] = React14.useState([]);
2774
- const [candidatesLoading, setCandidatesLoading] = React14.useState(false);
2775
- const [busy, setBusy] = React14.useState(false);
3551
+ const [lines, setLines] = React17.useState([]);
3552
+ const [loading, setLoading] = React17.useState(true);
3553
+ const [selectedId, setSelectedId] = React17.useState(null);
3554
+ const [candidates, setCandidates] = React17.useState([]);
3555
+ const [candidatesLoading, setCandidatesLoading] = React17.useState(false);
3556
+ const [busy, setBusy] = React17.useState(false);
2776
3557
  const supported = typeof provider.getUnreconciled === "function";
2777
- const load = React14.useCallback(async () => {
3558
+ const load = React17.useCallback(async () => {
2778
3559
  if (!provider.getUnreconciled) return;
2779
3560
  setLoading(true);
2780
3561
  try {
@@ -2785,10 +3566,10 @@ function ReconciliationView() {
2785
3566
  setLoading(false);
2786
3567
  }
2787
3568
  }, [provider]);
2788
- React14.useEffect(() => {
3569
+ React17.useEffect(() => {
2789
3570
  void load();
2790
3571
  }, [load]);
2791
- React14.useEffect(() => {
3572
+ React17.useEffect(() => {
2792
3573
  if (!selectedId || !provider.suggestReconciliation) {
2793
3574
  setCandidates([]);
2794
3575
  return;
@@ -2940,7 +3721,7 @@ var STEPS = [
2940
3721
  ];
2941
3722
  function FinancialOnboarding({ onComplete }) {
2942
3723
  const t2 = core.useTranslation();
2943
- const [step, setStep] = React14.useState(0);
3724
+ const [step, setStep] = React17.useState(0);
2944
3725
  const current = STEPS[step];
2945
3726
  const isLast = step === STEPS.length - 1;
2946
3727
  const Icon = current.icon;
@@ -3085,18 +3866,47 @@ function FinancialPage({ config, provider, store, registries }) {
3085
3866
  cards: 0,
3086
3867
  settings: 1
3087
3868
  });
3088
- const [onboardingComplete, setOnboardingComplete] = React14.useState(() => {
3869
+ const [onboardingComplete, setOnboardingComplete] = React17.useState(() => {
3089
3870
  try {
3090
3871
  return localStorage.getItem("saas-core:financial-onboarded") === "true";
3091
3872
  } catch {
3092
3873
  return false;
3093
3874
  }
3094
3875
  });
3876
+ React17.useEffect(() => {
3877
+ if (onboardingComplete) return;
3878
+ let cancelled = false;
3879
+ void provider.getMovements({ pageSize: 1 }).then((res) => {
3880
+ if (!cancelled && res.total > 0) setOnboardingComplete(true);
3881
+ }).catch(() => {
3882
+ });
3883
+ return () => {
3884
+ cancelled = true;
3885
+ };
3886
+ }, [onboardingComplete, provider]);
3095
3887
  const t2 = core.useTranslation();
3096
3888
  const intent = parseIntent(view);
3097
3889
  const isSettings = view === "settings";
3098
3890
  const nav = buildNav(config, view, navigate, t2);
3099
- const quickActions = React14.useMemo(() => {
3891
+ const [quickAddOpen, setQuickAddOpen] = React17.useState(false);
3892
+ const [quickAddType, setQuickAddType] = React17.useState("expense");
3893
+ const [quickAddReceipt, setQuickAddReceipt] = React17.useState(false);
3894
+ const openQuickAdd2 = React17.useCallback((type = "expense") => {
3895
+ setQuickAddType(type);
3896
+ setQuickAddReceipt(false);
3897
+ setQuickAddOpen(true);
3898
+ }, []);
3899
+ const pendingQuickAdd = usePendingQuickAdd();
3900
+ React17.useEffect(() => {
3901
+ if (!pendingQuickAdd) return;
3902
+ const req = consumeQuickAdd();
3903
+ if (!req) return;
3904
+ setQuickAddType(req.type);
3905
+ setQuickAddReceipt(req.receipt);
3906
+ setQuickAddOpen(true);
3907
+ }, [pendingQuickAdd]);
3908
+ const quickActions = React17.useMemo(() => {
3909
+ if (config.quickAdd) return [];
3100
3910
  const actions = [];
3101
3911
  if (config.modules.payables) {
3102
3912
  actions.push({
@@ -3126,7 +3936,7 @@ function FinancialPage({ config, provider, store, registries }) {
3126
3936
  });
3127
3937
  }
3128
3938
  return actions;
3129
- }, [config.modules]);
3939
+ }, [config.modules, config.quickAdd]);
3130
3940
  function handleOnboardingComplete() {
3131
3941
  setOnboardingComplete(true);
3132
3942
  try {
@@ -3170,7 +3980,7 @@ function FinancialPage({ config, provider, store, registries }) {
3170
3980
  return /* @__PURE__ */ jsxRuntime.jsx(SummaryView, {});
3171
3981
  }
3172
3982
  }
3173
- return /* @__PURE__ */ jsxRuntime.jsx(FinancialContextProvider, { config, provider, store, children: /* @__PURE__ */ jsxRuntime.jsx(
3983
+ return /* @__PURE__ */ jsxRuntime.jsx(FinancialContextProvider, { config, provider, store, children: /* @__PURE__ */ jsxRuntime.jsxs(
3174
3984
  ui.ModulePage,
3175
3985
  {
3176
3986
  title: config.labels.pageTitle,
@@ -3179,21 +3989,50 @@ function FinancialPage({ config, provider, store, registries }) {
3179
3989
  showHeader: intent.view === "summary" || view === "summary",
3180
3990
  viewKey: view,
3181
3991
  direction,
3182
- headerAction: /* @__PURE__ */ jsxRuntime.jsx(
3183
- saas.ModuleActionBar,
3184
- {
3185
- quickActions,
3186
- settingsPath: registries && registries.length > 0 ? "/settings/financial" : void 0,
3187
- settingsLabel: t2("financial.settingsPage.title")
3188
- }
3189
- ),
3190
- children: renderView()
3992
+ headerAction: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
3993
+ config.quickAdd && // One-primary-action rule (FAY-1247): quick-add is the single primary
3994
+ // add affordance in B2C mode. The receipt entry point lives inside the
3995
+ // sheet's "Fotografar ou anexar recibo" attachment step, so no separate
3996
+ // "Enviar recibo" button is needed here.
3997
+ /* @__PURE__ */ jsxRuntime.jsxs(
3998
+ ui.Button,
3999
+ {
4000
+ size: "sm",
4001
+ className: "hidden md:inline-flex",
4002
+ onClick: () => openQuickAdd2("expense"),
4003
+ children: [
4004
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "h-4 w-4" }),
4005
+ t2("financial.quickTx.newTransaction")
4006
+ ]
4007
+ }
4008
+ ),
4009
+ /* @__PURE__ */ jsxRuntime.jsx(
4010
+ saas.ModuleActionBar,
4011
+ {
4012
+ quickActions,
4013
+ settingsPath: registries && registries.length > 0 ? "/settings/financial" : void 0,
4014
+ settingsLabel: t2("financial.settingsPage.title")
4015
+ }
4016
+ )
4017
+ ] }),
4018
+ children: [
4019
+ renderView(),
4020
+ /* @__PURE__ */ jsxRuntime.jsx(
4021
+ QuickTransactionForm,
4022
+ {
4023
+ open: quickAddOpen,
4024
+ onOpenChange: setQuickAddOpen,
4025
+ defaultType: quickAddType,
4026
+ focusReceipt: quickAddReceipt
4027
+ }
4028
+ )
4029
+ ]
3191
4030
  }
3192
4031
  ) });
3193
4032
  }
3194
4033
  function useEnsureSummary() {
3195
4034
  const fetchSummary = useFinancialStore((s) => s.fetchSummary);
3196
- React14.useEffect(() => {
4035
+ React17.useEffect(() => {
3197
4036
  void fetchSummary();
3198
4037
  }, []);
3199
4038
  }
@@ -3317,7 +4156,7 @@ function RecentTransactions() {
3317
4156
  const { currency } = useFinancialConfig();
3318
4157
  const invoices = useFinancialStore((s) => s.invoices);
3319
4158
  const fetchInvoices = useFinancialStore((s) => s.fetchInvoices);
3320
- React14.useEffect(() => {
4159
+ React17.useEffect(() => {
3321
4160
  void fetchInvoices({ pageSize: 5 });
3322
4161
  }, []);
3323
4162
  const columns = [
@@ -3334,6 +4173,202 @@ function RecentTransactions() {
3334
4173
  ];
3335
4174
  return /* @__PURE__ */ jsxRuntime.jsx(ui.TableWidget, { title: t2("financial.summary.recentTransactions"), icon: "CircleDollarSign", columns, data: invoices.slice(0, 5), emptyMessage: t2("financial.summary.noTransactions") });
3336
4175
  }
4176
+ function useDueLabel() {
4177
+ const t2 = core.useTranslation();
4178
+ return (dueDate) => {
4179
+ const today2 = /* @__PURE__ */ new Date();
4180
+ today2.setHours(0, 0, 0, 0);
4181
+ const due = /* @__PURE__ */ new Date(`${dueDate}T00:00:00`);
4182
+ const days = Math.round((due.getTime() - today2.getTime()) / 864e5);
4183
+ if (days < 0) return t2("financial.home.overdueDays", { count: String(Math.abs(days)) });
4184
+ if (days === 0) return t2("financial.home.dueToday");
4185
+ if (days === 1) return t2("financial.home.dueTomorrow");
4186
+ return t2("financial.home.dueInDays", { count: String(days) });
4187
+ };
4188
+ }
4189
+ function BalanceHero() {
4190
+ const t2 = core.useTranslation();
4191
+ const { currency } = useFinancialConfig();
4192
+ const summary = useFinancialStore((s) => s.summary);
4193
+ const navigate = ui.useDashboardNavigate();
4194
+ useEnsureSummary();
4195
+ const [hidden, setHidden] = React17__namespace.default.useState(false);
4196
+ const money = (v) => hidden ? "\u2022\u2022\u2022\u2022\u2022\u2022" : saas.formatCurrency(v ?? 0, currency);
4197
+ const inflow = summary?.monthlyInflow ?? 0;
4198
+ const outflow = summary?.monthlyOutflow ?? 0;
4199
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.GoldCard, { branded: true, className: "px-5 py-4 text-center md:px-8 md:py-5", children: [
4200
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-medium uppercase tracking-wide opacity-75", children: t2("financial.home.balance") }),
4201
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-0.5 flex items-center justify-center gap-2.5", children: [
4202
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-3xl font-bold tracking-tight tabular-nums md:text-4xl", children: money(summary?.totalBalance) }),
4203
+ /* @__PURE__ */ jsxRuntime.jsx(
4204
+ "button",
4205
+ {
4206
+ type: "button",
4207
+ onClick: () => setHidden((h) => !h),
4208
+ "aria-label": hidden ? t2("financial.home.showBalance") : t2("financial.home.hideBalance"),
4209
+ className: "rounded-full p-1.5 text-primary-foreground/80 transition-colors hover:bg-white/10",
4210
+ children: hidden ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.EyeOff, { className: "h-5 w-5" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Eye, { className: "h-5 w-5" })
4211
+ }
4212
+ )
4213
+ ] }),
4214
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mx-auto mt-3 grid max-w-lg grid-cols-2 gap-3", children: [
4215
+ /* @__PURE__ */ jsxRuntime.jsxs(
4216
+ "button",
4217
+ {
4218
+ type: "button",
4219
+ onClick: () => navigate("/financial/receivables-list"),
4220
+ "aria-label": t2("financial.home.inflow"),
4221
+ className: "flex cursor-pointer items-center gap-2 rounded-2xl bg-white/10 px-3 py-2 text-left transition-colors hover:bg-white/20",
4222
+ children: [
4223
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-emerald-500/90", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUpRight, { className: "h-4 w-4 text-white" }) }),
4224
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "min-w-0", children: [
4225
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block text-[11px] uppercase tracking-wide opacity-70", children: t2("financial.home.inflow") }),
4226
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block truncate text-sm font-semibold tabular-nums", children: money(inflow) })
4227
+ ] })
4228
+ ]
4229
+ }
4230
+ ),
4231
+ /* @__PURE__ */ jsxRuntime.jsxs(
4232
+ "button",
4233
+ {
4234
+ type: "button",
4235
+ onClick: () => navigate("/financial/payables-list"),
4236
+ "aria-label": t2("financial.home.outflow"),
4237
+ className: "flex cursor-pointer items-center gap-2 rounded-2xl bg-white/10 px-3 py-2 text-left transition-colors hover:bg-white/20",
4238
+ children: [
4239
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-rose-500/90", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDownRight, { className: "h-4 w-4 text-white" }) }),
4240
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "min-w-0", children: [
4241
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block text-[11px] uppercase tracking-wide opacity-70", children: t2("financial.home.outflow") }),
4242
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block truncate text-sm font-semibold tabular-nums", children: money(outflow) })
4243
+ ] })
4244
+ ]
4245
+ }
4246
+ )
4247
+ ] })
4248
+ ] });
4249
+ }
4250
+ var SPEND_CATEGORIES = [
4251
+ { key: "subscriptions", keywords: ["netflix", "spotify", "prime video", "disney", "hbo", " max", "youtube", "apple", "assinatura", "subscription"] },
4252
+ { key: "groceries", keywords: ["supermercado", "mercado", "padaria", "hortifruti", "feira", "a\xE7ougue", "grocery", "market"] },
4253
+ { key: "transport", keywords: ["uber", "99", "taxi", "posto", "shell", "ipiranga", "combust\xEDvel", "gasolina", "metr\xF4", "\xF4nibus", "transport", "fuel"] },
4254
+ { key: "dining", keywords: ["ifood", "rappi", "restaurante", "outback", "lanchonete", "pizzaria", "caf\xE9", "cafeteria", "mcdonald", "burger", "food"] },
4255
+ { key: "home", keywords: ["aluguel", "condom\xEDnio", "luz", "enel", "\xE1gua", "sabesp", "internet", "vivo", "claro", "g\xE1s", "iptu", "rent", "utilit"] },
4256
+ { key: "health", keywords: ["farm\xE1cia", "farmacia", "drogasil", "drogaria", "academia", "smartfit", "cl\xEDnica", "hospital", "m\xE9dico", "sa\xFAde", "gym", "fitness", "health", "pharmac"] },
4257
+ { key: "leisure", keywords: ["cinema", "cinemark", "ingresso", "show", "teatro", "viagem", "hotel", "steam", "leisure"] },
4258
+ { key: "shopping", keywords: ["amazon", "magalu", "shopee", "aliexpress", "loja", "shopping", "zara", "renner", "store"] }
4259
+ ];
4260
+ function categorizeSpend(notes) {
4261
+ const s = (notes ?? "").toLowerCase();
4262
+ for (const c of SPEND_CATEGORIES) if (c.keywords.some((k) => s.includes(k))) return c.key;
4263
+ return "other";
4264
+ }
4265
+ function SpendByCategoryChart() {
4266
+ const t2 = core.useTranslation();
4267
+ const provider = useFinancialProvider();
4268
+ const [rows, setRows] = React17__namespace.default.useState([]);
4269
+ React17.useEffect(() => {
4270
+ let alive = true;
4271
+ void (async () => {
4272
+ const res = await provider.getMovements({ status: "paid", direction: "debit" });
4273
+ if (!alive) return;
4274
+ const totals = /* @__PURE__ */ new Map();
4275
+ for (const m of res.data) {
4276
+ if (m.movementKind === "transfer") continue;
4277
+ const key = categorizeSpend(m.notes);
4278
+ totals.set(key, (totals.get(key) ?? 0) + (m.paidAmount || m.amount));
4279
+ }
4280
+ setRows(
4281
+ [...totals.entries()].sort((a, b) => b[1] - a[1]).map(([key, value]) => ({ name: t2(`financial.home.category.${key}`), value: Math.round(value * 100) / 100 }))
4282
+ );
4283
+ })();
4284
+ return () => {
4285
+ alive = false;
4286
+ };
4287
+ }, [provider]);
4288
+ if (rows.length === 0) {
4289
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.Card, { children: [
4290
+ /* @__PURE__ */ jsxRuntime.jsx(ui.CardHeader, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.CardTitle, { children: t2("financial.home.spendByCategory") }) }),
4291
+ /* @__PURE__ */ jsxRuntime.jsx(ui.CardContent, { className: "flex h-[200px] items-center justify-center text-sm text-muted-foreground", children: t2("financial.home.noSpend") })
4292
+ ] });
4293
+ }
4294
+ return /* @__PURE__ */ jsxRuntime.jsx(
4295
+ ui.ChartWidget,
4296
+ {
4297
+ type: "pie",
4298
+ title: t2("financial.home.spendByCategory"),
4299
+ icon: "PieChart",
4300
+ categoryKey: "name",
4301
+ data: rows,
4302
+ series: [{ dataKey: "value", label: t2("financial.home.spendByCategory") }]
4303
+ }
4304
+ );
4305
+ }
4306
+ function UpcomingBills() {
4307
+ const t2 = core.useTranslation();
4308
+ const { currency } = useFinancialConfig();
4309
+ const provider = useFinancialProvider();
4310
+ const dueLabel = useDueLabel();
4311
+ const [bills, setBills] = React17__namespace.default.useState([]);
4312
+ React17.useEffect(() => {
4313
+ let alive = true;
4314
+ void (async () => {
4315
+ const pending2 = await provider.getMovements({ status: "pending" });
4316
+ if (!alive) return;
4317
+ setBills(
4318
+ pending2.data.filter((m) => m.direction === "debit" && m.movementKind === "bill").sort((a, b) => a.dueDate.localeCompare(b.dueDate))
4319
+ );
4320
+ })();
4321
+ return () => {
4322
+ alive = false;
4323
+ };
4324
+ }, [provider]);
4325
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.GoldCard, { className: "p-0 overflow-hidden", children: [
4326
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-between px-4 pt-4", children: /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-sm font-semibold text-foreground", children: t2("financial.home.upcomingBills") }) }),
4327
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3", children: bills.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-4 py-6 text-center text-xs text-muted-foreground", children: t2("financial.home.noBills") }) : bills.map((bill, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4 py-3.5" + (i > 0 ? " border-t border-border" : ""), children: [
4328
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [
4329
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "truncate text-sm font-medium text-foreground", children: bill.notes ?? t2("financial.home.bill") }),
4330
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: dueLabel(bill.dueDate) })
4331
+ ] }),
4332
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-sm font-semibold tabular-nums text-foreground", children: saas.formatCurrency(bill.amount - bill.paidAmount, currency) })
4333
+ ] }, bill.id)) })
4334
+ ] });
4335
+ }
4336
+ function CreditCards() {
4337
+ const t2 = core.useTranslation();
4338
+ const { currency } = useFinancialConfig();
4339
+ const bankAccounts = useFinancialStore((s) => s.bankAccounts);
4340
+ const fetchBankAccounts = useFinancialStore((s) => s.fetchBankAccounts);
4341
+ React17.useEffect(() => {
4342
+ void fetchBankAccounts();
4343
+ }, []);
4344
+ const cards = bankAccounts.filter((a) => a.accountType === "credit_card");
4345
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.GoldCard, { className: "bg-transparent border-0 p-0 shadow-none", children: [
4346
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "mb-3 text-sm font-semibold text-foreground", children: t2("financial.home.cards") }),
4347
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
4348
+ cards.map((card) => {
4349
+ const fatura = Math.abs(Math.min(0, card.currentBalance));
4350
+ const limite = Math.max(0, (card.creditLimit ?? 0) - fatura);
4351
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-2xl bg-gradient-to-br from-violet-600 to-indigo-700 p-4 text-white shadow-md", children: [
4352
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
4353
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold", children: card.bankName ?? card.name }),
4354
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CreditCard, { className: "h-5 w-5 opacity-80" })
4355
+ ] }),
4356
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-6 text-[11px] uppercase tracking-wide opacity-70", children: t2("financial.home.currentBill") }),
4357
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xl font-bold tabular-nums", children: saas.formatCurrency(fatura, currency) }),
4358
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mt-2 text-[11px] opacity-70", children: [
4359
+ t2("financial.home.availableLimit"),
4360
+ " ",
4361
+ saas.formatCurrency(limite, currency)
4362
+ ] })
4363
+ ] }, card.id);
4364
+ }),
4365
+ cards.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center rounded-2xl border border-dashed border-border py-6 text-sm font-medium text-muted-foreground", children: [
4366
+ "+ ",
4367
+ t2("financial.home.addCard")
4368
+ ] }) : null
4369
+ ] })
4370
+ ] });
4371
+ }
3337
4372
  function createFinancialDashboardWidgets(ctx2) {
3338
4373
  const withCtx = (Inner) => {
3339
4374
  const Wrapped = () => /* @__PURE__ */ jsxRuntime.jsx(FinancialContextProvider, { config: ctx2.config, provider: ctx2.provider, store: ctx2.store, children: /* @__PURE__ */ jsxRuntime.jsx(Inner, {}) });
@@ -3350,7 +4385,19 @@ function createFinancialDashboardWidgets(ctx2) {
3350
4385
  ui.defineChartWidget({ id: "financial.chart.cash-flow", title: "financial.summary.cashFlow", domain: "financial", span: 2, defaultOrder: 10, surfaces: ["plugin-home"], component: withCtx(CashFlowChart) }),
3351
4386
  ui.defineCustomWidget({ id: "financial.panel.breakdown", title: "financial.summary.cashFlowBreakdown", domain: "financial", span: 1, defaultOrder: 11, surfaces: ["plugin-home"], component: withCtx(CashFlowBreakdown) }),
3352
4387
  ui.defineCustomWidget({ id: "financial.panel.overdue", title: "financial.summary.overdueTitle", domain: "financial", span: 1, defaultOrder: 12, surfaces: ["plugin-home"], component: withCtx(OverdueAlerts) }),
3353
- ui.defineTableWidget({ id: "financial.table.recent", title: "financial.summary.recentTransactions", domain: "financial", span: 4, defaultOrder: 20, surfaces: ["plugin-home"], component: withCtx(RecentTransactions) })
4388
+ ui.defineTableWidget({ id: "financial.table.recent", title: "financial.summary.recentTransactions", domain: "financial", span: 4, defaultOrder: 20, surfaces: ["plugin-home"], component: withCtx(RecentTransactions) }),
4389
+ // FINANCE-HOME surface (B2C phone-first dashboard) — a compact analytical
4390
+ // layout: hero band → charts row (spend-by-category + cash-flow) → bills +
4391
+ // cards. This is a dedicated consumer surface (norman-ai's money screen), NOT
4392
+ // the universal B2B 'home': a full-bleed balance hero and credit-card tiles
4393
+ // are personal-finance chrome that would leak into every app that merely
4394
+ // enables plugin-financial (e.g. the beauty-saas Painel). Apps that want them
4395
+ // opt in explicitly by rendering <DashboardCanvas surface="finance-home">.
4396
+ ui.defineCustomWidget({ id: "financial.hero.balance", title: "financial.home.balance", domain: "financial", span: 4, defaultOrder: 0, surfaces: ["finance-home"], component: withCtx(BalanceHero) }),
4397
+ ui.defineChartWidget({ id: "financial.chart.spend-by-category", title: "financial.home.spendByCategory", domain: "financial", span: 2, defaultOrder: 1, surfaces: ["finance-home"], component: withCtx(SpendByCategoryChart) }),
4398
+ ui.defineChartWidget({ id: "financial.chart.cash-flow-home", title: "financial.summary.cashFlow", domain: "financial", span: 2, defaultOrder: 2, surfaces: ["finance-home"], component: withCtx(CashFlowChart) }),
4399
+ ui.defineCustomWidget({ id: "financial.list.upcoming-bills", title: "financial.home.upcomingBills", domain: "financial", span: 2, defaultOrder: 3, surfaces: ["finance-home"], component: withCtx(UpcomingBills) }),
4400
+ ui.defineCustomWidget({ id: "financial.cards", title: "financial.home.cards", domain: "financial", span: 2, defaultOrder: 4, surfaces: ["finance-home"], component: withCtx(CreditCards) })
3354
4401
  ];
3355
4402
  }
3356
4403
 
@@ -3383,9 +4430,10 @@ function paginate(items, page, pageSize) {
3383
4430
  const start = (p - 1) * ps;
3384
4431
  return { data: items.slice(start, start + ps), total: items.length };
3385
4432
  }
3386
- function createStore(seedPaymentMethodTypes) {
4433
+ function createStore(options) {
3387
4434
  const tenantId = "mock-tenant";
3388
- const defaultPMTypes = ([
4435
+ const seed = options?.seed;
4436
+ const defaultPMTypes = (options?.paymentMethodTypes ?? [
3389
4437
  { name: "Cash", transactionType: "cash" },
3390
4438
  { name: "Credit Card", transactionType: "credit_card" },
3391
4439
  { name: "Debit Card", transactionType: "debit_card" },
@@ -3423,19 +4471,23 @@ function createStore(seedPaymentMethodTypes) {
3423
4471
  updatedAt: now()
3424
4472
  };
3425
4473
  return {
3426
- invoices: [],
3427
- invoiceItems: [],
3428
- movements: [],
3429
- bankAccounts: [cashAccount, bankAccount],
4474
+ // Seeded data (when provided) makes the module render as if the user already
4475
+ // has accounts + transactions — a populated Summary/Statements instead of the
4476
+ // empty onboarding state. Seed arrays are copied so the caller's data is not mutated.
4477
+ invoices: seed?.invoices ? [...seed.invoices] : [],
4478
+ invoiceItems: seed?.invoiceItems ? [...seed.invoiceItems] : [],
4479
+ movements: seed?.movements ? [...seed.movements] : [],
4480
+ bankAccounts: seed?.bankAccounts ? [...seed.bankAccounts] : [cashAccount, bankAccount],
3430
4481
  cashSessions: [],
3431
- paymentMethods: [],
4482
+ paymentMethods: seed?.paymentMethods ? [...seed.paymentMethods] : [],
3432
4483
  paymentMethodTypes: defaultPMTypes,
3433
4484
  chartOfAccounts: [],
4485
+ costCenters: [],
3434
4486
  cardTransactions: []
3435
4487
  };
3436
4488
  }
3437
4489
  function createMockFinancialProvider(options) {
3438
- const store = createStore();
4490
+ const store = createStore(options);
3439
4491
  const tenantId = "mock-tenant";
3440
4492
  function recalcInvoiceStatus(invoice) {
3441
4493
  if (invoice.paidAmount >= invoice.totalAmount) {
@@ -3456,6 +4508,14 @@ function createMockFinancialProvider(options) {
3456
4508
  if (query.direction) results = results.filter((i) => i.direction === query.direction);
3457
4509
  if (query.status) results = results.filter((i) => matchesStatus(i.status, query.status));
3458
4510
  if (query.contactId) results = results.filter((i) => i.contactId === query.contactId);
4511
+ if (query.accountId) {
4512
+ const invoiceIds = new Set(store.invoiceItems.filter((item) => item.accountId === query.accountId).map((item) => item.invoiceId));
4513
+ results = results.filter((invoice) => invoiceIds.has(invoice.id));
4514
+ }
4515
+ if (query.costCenterId) {
4516
+ const invoiceIds = new Set(store.invoiceItems.filter((item) => item.costCenterId === query.costCenterId).map((item) => item.invoiceId));
4517
+ results = results.filter((invoice) => invoiceIds.has(invoice.id));
4518
+ }
3459
4519
  if (query.dateRange) results = results.filter((i) => matchesDateRange(i.invoiceDate, query.dateRange));
3460
4520
  if (query.search) {
3461
4521
  const s = query.search.toLowerCase();
@@ -3778,6 +4838,9 @@ function createMockFinancialProvider(options) {
3778
4838
  async getChartOfAccounts() {
3779
4839
  return store.chartOfAccounts.filter((n) => n.isActive);
3780
4840
  },
4841
+ async getCostCenters() {
4842
+ return store.costCenters.filter((c) => c.isActive);
4843
+ },
3781
4844
  // --- Card Transactions ---
3782
4845
  async getCardTransactions(dateRange) {
3783
4846
  let results = [...store.cardTransactions];
@@ -3865,7 +4928,9 @@ function createMockFinancialProvider(options) {
3865
4928
  (m) => m.direction === "debit" && m.movementKind === "bill" && ["pending", "partial"].includes(m.status)
3866
4929
  );
3867
4930
  const todayStr = today();
3868
- const monthStart = todayStr.slice(0, 7) + "-01";
4931
+ const monthAgo = /* @__PURE__ */ new Date();
4932
+ monthAgo.setDate(monthAgo.getDate() - 30);
4933
+ const monthStart = monthAgo.toISOString().slice(0, 10);
3869
4934
  const monthEnd = todayStr;
3870
4935
  const monthMovements = store.movements.filter(
3871
4936
  (m) => m.movementKind === "payment" && matchesDateRange(m.paymentDate, dateRange ?? { from: monthStart, to: monthEnd })
@@ -3972,6 +5037,18 @@ function createMockFinancialProvider(options) {
3972
5037
  return provider;
3973
5038
  }
3974
5039
 
5040
+ // src/data/tables.ts
5041
+ var T = {
5042
+ movements: "plg_financial_movements",
5043
+ chartOfAccounts: "plg_financial_chart_of_accounts",
5044
+ bankAccounts: "plg_financial_bank_accounts",
5045
+ cardBrands: "plg_financial_card_brands",
5046
+ costCenters: "plg_financial_cost_centers",
5047
+ cashRegisterSessions: "plg_financial_cash_register_sessions",
5048
+ paymentMethods: "plg_financial_payment_methods",
5049
+ paymentMethodTypes: "plg_financial_payment_method_types"
5050
+ };
5051
+
3975
5052
  // src/data/supabase.ts
3976
5053
  function getTenantId() {
3977
5054
  return core.getActiveTenantId();
@@ -3994,7 +5071,7 @@ function camelToSnake(obj) {
3994
5071
  function getClients() {
3995
5072
  const supabase = core.getSupabaseClientOptional();
3996
5073
  if (!supabase) throw new Error("Supabase not initialized");
3997
- return { core: supabase.schema("saas_core"), pub: supabase };
5074
+ return { core: supabase, pub: supabase };
3998
5075
  }
3999
5076
  function mapStageToInvoiceStatus(stage) {
4000
5077
  switch (stage) {
@@ -4021,11 +5098,11 @@ async function sweepOverdue() {
4021
5098
  try {
4022
5099
  const { core, pub } = getClients();
4023
5100
  const today2 = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
4024
- const { data: overdueMovs } = await pub.from("financial_movements").update({ status: "overdue" }).in("status", ["pending", "partial"]).lt("due_date", today2).select("invoice_id");
5101
+ const { data: overdueMovs } = await pub.from(T.movements).update({ status: "overdue" }).in("status", ["pending", "partial"]).lt("due_date", today2).select("invoice_id");
4025
5102
  if (overdueMovs && overdueMovs.length > 0) {
4026
5103
  const invoiceIds = [...new Set(overdueMovs.map((m) => m.invoice_id).filter(Boolean))];
4027
5104
  for (const invId of invoiceIds) {
4028
- const { data: allMovs } = await pub.from("financial_movements").select("status").eq("invoice_id", invId).eq("movement_kind", "bill");
5105
+ const { data: allMovs } = await pub.from(T.movements).select("status").eq("invoice_id", invId).eq("movement_kind", "bill");
4029
5106
  const movs = allMovs ?? [];
4030
5107
  const hasOverdue = movs.some((m) => m.status === "overdue");
4031
5108
  const allPaid = movs.every((m) => m.status === "paid");
@@ -4049,9 +5126,21 @@ async function fetchInvoiceBalances(pub, ids) {
4049
5126
  function round22(n) {
4050
5127
  return Math.round(n * 100) / 100;
4051
5128
  }
5129
+ async function findOrderIdsByItemMetadata(core, filters) {
5130
+ if (!filters.accountId && !filters.costCenterId) return void 0;
5131
+ let qb = core.from("order_items").select("order_id");
5132
+ if (filters.accountId) qb = qb.filter("metadata->>accountId", "eq", filters.accountId);
5133
+ if (filters.costCenterId) qb = qb.filter("metadata->>costCenterId", "eq", filters.costCenterId);
5134
+ const { data } = await qb;
5135
+ const ids = [];
5136
+ for (const row of data ?? []) {
5137
+ if (typeof row.order_id === "string" && row.order_id.length > 0) ids.push(row.order_id);
5138
+ }
5139
+ return Array.from(new Set(ids));
5140
+ }
4052
5141
  async function getMethodFeePct(pub, paymentMethodId) {
4053
5142
  if (!paymentMethodId) return 0;
4054
- const { data } = await pub.from("payment_methods").select("discount_value").eq("id", paymentMethodId).single();
5143
+ const { data } = await pub.from(T.paymentMethods).select("discount_value").eq("id", paymentMethodId).single();
4055
5144
  return Number(data?.discount_value) || 0;
4056
5145
  }
4057
5146
  function genId() {
@@ -4076,6 +5165,14 @@ function createSupabaseFinancialProvider() {
4076
5165
  const statuses = Array.isArray(query.status) ? query.status : [query.status];
4077
5166
  qb = qb.in("status", statuses);
4078
5167
  }
5168
+ const itemScopedOrderIds = await findOrderIdsByItemMetadata(core, {
5169
+ accountId: query.accountId,
5170
+ costCenterId: query.costCenterId
5171
+ });
5172
+ if (itemScopedOrderIds) {
5173
+ if (itemScopedOrderIds.length === 0) return { data: [], total: 0 };
5174
+ qb = qb.in("id", itemScopedOrderIds);
5175
+ }
4079
5176
  if (query.contactId) qb = qb.eq("party_id", query.contactId);
4080
5177
  if (query.search) qb = qb.ilike("notes", `%${query.search}%`);
4081
5178
  if (query.dateRange) qb = qb.gte("created_at", query.dateRange.from).lte("created_at", query.dateRange.to);
@@ -4115,7 +5212,7 @@ function createSupabaseFinancialProvider() {
4115
5212
  const o = snakeToCamel(data);
4116
5213
  const meta = data.metadata ?? {};
4117
5214
  const balance = (await fetchInvoiceBalances(pub, [id])).get(id);
4118
- const { data: movs } = await pub.from("financial_movements").select("paid_amount").eq("invoice_id", id).eq("movement_kind", "bill");
5215
+ const { data: movs } = await pub.from(T.movements).select("paid_amount").eq("invoice_id", id).eq("movement_kind", "bill");
4119
5216
  return {
4120
5217
  id: o.id,
4121
5218
  direction: o.direction ?? (o.kind === "invoice_payable" ? "debit" : "credit"),
@@ -4151,6 +5248,8 @@ function createSupabaseFinancialProvider() {
4151
5248
  discount: i.discount ?? 0,
4152
5249
  surcharge: 0,
4153
5250
  referenceId: i.productId ?? i.serviceId,
5251
+ accountId: i.metadata?.accountId,
5252
+ costCenterId: i.metadata?.costCenterId,
4154
5253
  createdAt: i.createdAt
4155
5254
  };
4156
5255
  });
@@ -4190,12 +5289,17 @@ function createSupabaseFinancialProvider() {
4190
5289
  discount: item.discount ?? 0,
4191
5290
  total: item.quantity * item.unitPrice - (item.discount ?? 0) + (item.surcharge ?? 0),
4192
5291
  sort_order: i,
4193
- metadata: { itemKind: item.itemKind, referenceId: item.referenceId }
5292
+ metadata: {
5293
+ itemKind: item.itemKind,
5294
+ referenceId: item.referenceId,
5295
+ accountId: item.accountId,
5296
+ costCenterId: item.costCenterId
5297
+ }
4194
5298
  }))
4195
5299
  );
4196
5300
  }
4197
5301
  if (order && input.installments.length > 0) {
4198
- await pub.from("financial_movements").insert(
5302
+ await pub.from(T.movements).insert(
4199
5303
  input.installments.map((inst, i) => ({
4200
5304
  tenant_id: tenantId,
4201
5305
  invoice_id: order.id,
@@ -4237,12 +5341,12 @@ function createSupabaseFinancialProvider() {
4237
5341
  async cancelInvoice(id) {
4238
5342
  const { core, pub } = getClients();
4239
5343
  await core.from("orders").update({ status: "cancelled" }).eq("id", id);
4240
- await pub.from("financial_movements").update({ status: "cancelled" }).eq("invoice_id", id).eq("status", "pending");
5344
+ await pub.from(T.movements).update({ status: "cancelled" }).eq("invoice_id", id).eq("status", "pending");
4241
5345
  },
4242
5346
  // --- Movements (public.financial_movements) ---
4243
5347
  async getMovements(query) {
4244
5348
  const { pub } = getClients();
4245
- let qb = pub.from("financial_movements").select("*", { count: "exact" });
5349
+ let qb = pub.from(T.movements).select("*", { count: "exact" });
4246
5350
  if (query.direction) qb = qb.eq("direction", query.direction);
4247
5351
  if (query.status) {
4248
5352
  const statuses = Array.isArray(query.status) ? query.status : [query.status];
@@ -4259,7 +5363,7 @@ function createSupabaseFinancialProvider() {
4259
5363
  },
4260
5364
  async payMovement(input) {
4261
5365
  const { core, pub } = getClients();
4262
- const { data: mov } = await pub.from("financial_movements").select("*").eq("id", input.movementId).single();
5366
+ const { data: mov } = await pub.from(T.movements).select("*").eq("id", input.movementId).single();
4263
5367
  if (!mov) throw new Error("Movement not found");
4264
5368
  const tenantId = mov.tenant_id ?? getTenantId();
4265
5369
  const feePct = mov.direction === "credit" ? await getMethodFeePct(pub, input.paymentMethodId) : 0;
@@ -4284,17 +5388,17 @@ function createSupabaseFinancialProvider() {
4284
5388
  card_installments: input.cardInstallments ?? null,
4285
5389
  notes: input.notes ?? null
4286
5390
  };
4287
- let { data, error } = await pub.from("financial_movements").insert(paymentRow).select().single();
5391
+ let { data, error } = await pub.from(T.movements).insert(paymentRow).select().single();
4288
5392
  if (error && /fee_amount/i.test(error.message ?? "")) {
4289
5393
  const { fee_amount, ...rest } = paymentRow;
4290
- ({ data, error } = await pub.from("financial_movements").insert(rest).select().single());
5394
+ ({ data, error } = await pub.from(T.movements).insert(rest).select().single());
4291
5395
  }
4292
5396
  if (error) throw error;
4293
5397
  const newPaid = round22((mov.paid_amount ?? 0) + input.amount);
4294
5398
  const billStatus = newPaid >= mov.amount ? "paid" : "partial";
4295
- await pub.from("financial_movements").update({ paid_amount: newPaid, status: billStatus, payment_date: null, bank_account_id: null }).eq("id", mov.id);
5399
+ await pub.from(T.movements).update({ paid_amount: newPaid, status: billStatus, payment_date: null, bank_account_id: null }).eq("id", mov.id);
4296
5400
  if (mov.invoice_id) {
4297
- const { data: allMovs } = await pub.from("financial_movements").select("status, amount, paid_amount").eq("invoice_id", mov.invoice_id).eq("movement_kind", "bill");
5401
+ const { data: allMovs } = await pub.from(T.movements).select("status, amount, paid_amount").eq("invoice_id", mov.invoice_id).eq("movement_kind", "bill");
4298
5402
  const movs = allMovs ?? [];
4299
5403
  const allPaid = movs.length > 0 && movs.every((m) => m.status === "paid");
4300
5404
  const anyPaid = movs.some((m) => m.status === "paid" || m.status === "partial");
@@ -4311,7 +5415,7 @@ function createSupabaseFinancialProvider() {
4311
5415
  },
4312
5416
  async cancelMovement(id) {
4313
5417
  const { pub } = getClients();
4314
- await pub.from("financial_movements").update({ status: "cancelled" }).eq("id", id);
5418
+ await pub.from(T.movements).update({ status: "cancelled" }).eq("id", id);
4315
5419
  },
4316
5420
  // --- Transfers (between accounts) ---
4317
5421
  async createTransfer(input) {
@@ -4347,10 +5451,10 @@ function createSupabaseFinancialProvider() {
4347
5451
  metadata: { transferId, transferRole: "in", counterAccountId: input.fromAccountId }
4348
5452
  }
4349
5453
  ];
4350
- let { data, error } = await pub.from("financial_movements").insert(rowsToInsert).select("id, direction");
5454
+ let { data, error } = await pub.from(T.movements).insert(rowsToInsert).select("id, direction");
4351
5455
  if (error && /fee_amount/i.test(error.message ?? "")) {
4352
5456
  const stripped = rowsToInsert.map(({ fee_amount, ...rest }) => rest);
4353
- ({ data, error } = await pub.from("financial_movements").insert(stripped).select("id, direction"));
5457
+ ({ data, error } = await pub.from(T.movements).insert(stripped).select("id, direction"));
4354
5458
  }
4355
5459
  if (error) throw error;
4356
5460
  const rows = data ?? [];
@@ -4361,13 +5465,13 @@ function createSupabaseFinancialProvider() {
4361
5465
  // --- Bank Accounts ---
4362
5466
  async getBankAccounts() {
4363
5467
  const { pub } = getClients();
4364
- const { data } = await pub.from("bank_accounts").select("*").eq("is_active", true).order("name");
5468
+ const { data } = await pub.from(T.bankAccounts).select("*").eq("is_active", true).order("name");
4365
5469
  return (data ?? []).map((r) => snakeToCamel(r));
4366
5470
  },
4367
5471
  async createBankAccount(input) {
4368
5472
  const { pub } = getClients();
4369
5473
  const tenantId = getTenantId();
4370
- const { data } = await pub.from("bank_accounts").insert({
5474
+ const { data } = await pub.from(T.bankAccounts).insert({
4371
5475
  ...camelToSnake(input),
4372
5476
  tenant_id: tenantId,
4373
5477
  current_balance: input.initialBalance ?? 0
@@ -4379,26 +5483,26 @@ function createSupabaseFinancialProvider() {
4379
5483
  const row = camelToSnake(partial);
4380
5484
  delete row.id;
4381
5485
  delete row.tenant_id;
4382
- const { data } = await pub.from("bank_accounts").update(row).eq("id", id).select().single();
5486
+ const { data } = await pub.from(T.bankAccounts).update(row).eq("id", id).select().single();
4383
5487
  return snakeToCamel(data);
4384
5488
  },
4385
5489
  // --- Cash Sessions ---
4386
5490
  async getCashSessions(bankAccountId) {
4387
5491
  const { pub } = getClients();
4388
- let qb = pub.from("cash_register_sessions").select("*");
5492
+ let qb = pub.from(T.cashRegisterSessions).select("*");
4389
5493
  if (bankAccountId) qb = qb.eq("bank_account_id", bankAccountId);
4390
5494
  const { data } = await qb.order("opened_at", { ascending: false });
4391
5495
  return (data ?? []).map((r) => snakeToCamel(r));
4392
5496
  },
4393
5497
  async getOpenSession(bankAccountId) {
4394
5498
  const { pub } = getClients();
4395
- const { data } = await pub.from("cash_register_sessions").select("*").eq("bank_account_id", bankAccountId).eq("status", "open").single();
5499
+ const { data } = await pub.from(T.cashRegisterSessions).select("*").eq("bank_account_id", bankAccountId).eq("status", "open").single();
4396
5500
  return data ? snakeToCamel(data) : null;
4397
5501
  },
4398
5502
  async openCashSession(input) {
4399
5503
  const { pub } = getClients();
4400
5504
  const tenantId = getTenantId();
4401
- const { data } = await pub.from("cash_register_sessions").insert({
5505
+ const { data } = await pub.from(T.cashRegisterSessions).insert({
4402
5506
  tenant_id: tenantId,
4403
5507
  bank_account_id: input.bankAccountId,
4404
5508
  status: "open",
@@ -4411,7 +5515,7 @@ function createSupabaseFinancialProvider() {
4411
5515
  },
4412
5516
  async closeCashSession(input) {
4413
5517
  const { pub } = getClients();
4414
- const { data } = await pub.from("cash_register_sessions").update({
5518
+ const { data } = await pub.from(T.cashRegisterSessions).update({
4415
5519
  status: "closed",
4416
5520
  closing_balance: input.closingBalance,
4417
5521
  closed_at: (/* @__PURE__ */ new Date()).toISOString(),
@@ -4423,8 +5527,8 @@ function createSupabaseFinancialProvider() {
4423
5527
  },
4424
5528
  async getCashSessionSummary(sessionId) {
4425
5529
  const { pub } = getClients();
4426
- const session = (await pub.from("cash_register_sessions").select("*").eq("id", sessionId).single()).data;
4427
- const { data: movs } = await pub.from("financial_movements").select("direction, paid_amount").eq("cash_session_id", sessionId).eq("status", "paid");
5530
+ const session = (await pub.from(T.cashRegisterSessions).select("*").eq("id", sessionId).single()).data;
5531
+ const { data: movs } = await pub.from(T.movements).select("direction, paid_amount").eq("cash_session_id", sessionId).eq("status", "paid");
4428
5532
  const movements = movs ?? [];
4429
5533
  return {
4430
5534
  session: snakeToCamel(session),
@@ -4436,18 +5540,23 @@ function createSupabaseFinancialProvider() {
4436
5540
  // --- Payment Methods ---
4437
5541
  async getPaymentMethods() {
4438
5542
  const { pub } = getClients();
4439
- const { data } = await pub.from("payment_methods").select("*").eq("is_active", true).order("name");
5543
+ const { data } = await pub.from(T.paymentMethods).select("*").eq("is_active", true).order("name");
4440
5544
  return (data ?? []).map((r) => snakeToCamel(r));
4441
5545
  },
4442
5546
  async getPaymentMethodTypes() {
4443
5547
  const { pub } = getClients();
4444
- const { data } = await pub.from("payment_method_types").select("*").eq("is_active", true).order("name");
5548
+ const { data } = await pub.from(T.paymentMethodTypes).select("*").eq("is_active", true).order("name");
4445
5549
  return (data ?? []).map((r) => snakeToCamel(r));
4446
5550
  },
4447
5551
  // --- Chart of Accounts ---
4448
5552
  async getChartOfAccounts() {
4449
5553
  const { pub } = getClients();
4450
- const { data } = await pub.from("chart_of_accounts").select("*").eq("is_active", true).order("code");
5554
+ const { data } = await pub.from(T.chartOfAccounts).select("*").eq("is_active", true).order("code");
5555
+ return (data ?? []).map((r) => snakeToCamel(r));
5556
+ },
5557
+ async getCostCenters() {
5558
+ const { pub } = getClients();
5559
+ const { data } = await pub.from(T.costCenters).select("*").eq("is_active", true).order("code");
4451
5560
  return (data ?? []).map((r) => snakeToCamel(r));
4452
5561
  },
4453
5562
  // --- Card Transactions ---
@@ -4459,7 +5568,7 @@ function createSupabaseFinancialProvider() {
4459
5568
  async getStatement(query) {
4460
5569
  const { core, pub } = getClients();
4461
5570
  const today2 = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
4462
- const { data: acctRows } = await pub.from("bank_accounts").select("id, name, initial_balance, is_active");
5571
+ const { data: acctRows } = await pub.from(T.bankAccounts).select("id, name, initial_balance, is_active");
4463
5572
  const allAccounts = acctRows ?? [];
4464
5573
  const consolidated = !query.bankAccountId;
4465
5574
  const scopeAccounts = consolidated ? allAccounts.filter((a) => a.is_active) : allAccounts.filter((a) => a.id === query.bankAccountId);
@@ -4471,10 +5580,10 @@ function createSupabaseFinancialProvider() {
4471
5580
  }
4472
5581
  const scopeFilter = (qb) => consolidated ? qb : qb.in("bank_account_id", accountIds);
4473
5582
  const netOf = (r) => r.direction === "credit" ? (Number(r.paid_amount) || 0) - (Number(r.fee_amount) || 0) : -(Number(r.paid_amount) || 0);
4474
- const { data: priorRows } = await scopeFilter(pub.from("financial_movements").select("*").neq("status", "cancelled").lt("payment_date", query.dateRange.from));
5583
+ const { data: priorRows } = await scopeFilter(pub.from(T.movements).select("*").neq("status", "cancelled").lt("payment_date", query.dateRange.from));
4475
5584
  const priorNet = (priorRows ?? []).reduce((s, r) => s + netOf(r), 0);
4476
5585
  const openingBalance = round22(initialSum + priorNet);
4477
- const { data: movs } = await scopeFilter(pub.from("financial_movements").select("*").neq("status", "cancelled").gte("payment_date", query.dateRange.from).lte("payment_date", query.dateRange.to).order("payment_date").order("created_at"));
5586
+ const { data: movs } = await scopeFilter(pub.from(T.movements).select("*").neq("status", "cancelled").gte("payment_date", query.dateRange.from).lte("payment_date", query.dateRange.to).order("payment_date").order("created_at"));
4478
5587
  const invoiceIds = [...new Set((movs ?? []).map((r) => r.invoice_id).filter(Boolean))];
4479
5588
  const invoiceById = /* @__PURE__ */ new Map();
4480
5589
  if (invoiceIds.length) {
@@ -4516,7 +5625,7 @@ function createSupabaseFinancialProvider() {
4516
5625
  });
4517
5626
  const matchedIds = [...new Set(entries.map((e) => e.movement.matchedMovementId).filter(Boolean))];
4518
5627
  if (matchedIds.length) {
4519
- const { data: matched } = await pub.from("financial_movements").select("id, invoice_id, notes").in("id", matchedIds);
5628
+ const { data: matched } = await pub.from(T.movements).select("id, invoice_id, notes").in("id", matchedIds);
4520
5629
  const matchedById = new Map((matched ?? []).map((m) => [m.id, m]));
4521
5630
  const matchedInvoiceIds = [...new Set((matched ?? []).map((m) => m.invoice_id).filter(Boolean))];
4522
5631
  const invById = /* @__PURE__ */ new Map();
@@ -4538,7 +5647,7 @@ function createSupabaseFinancialProvider() {
4538
5647
  };
4539
5648
  }
4540
5649
  }
4541
- const { data: todayRows } = await scopeFilter(pub.from("financial_movements").select("*").neq("status", "cancelled").lte("payment_date", today2));
5650
+ const { data: todayRows } = await scopeFilter(pub.from(T.movements).select("*").neq("status", "cancelled").lte("payment_date", today2));
4542
5651
  const accountCurrentBalance = round22(initialSum + (todayRows ?? []).reduce((s, r) => s + netOf(r), 0));
4543
5652
  return {
4544
5653
  entries,
@@ -4556,9 +5665,9 @@ function createSupabaseFinancialProvider() {
4556
5665
  async getSummary(dateRange) {
4557
5666
  sweepOverdue();
4558
5667
  const { pub } = getClients();
4559
- const { data: accounts } = await pub.from("bank_accounts").select("current_balance").eq("is_active", true);
5668
+ const { data: accounts } = await pub.from(T.bankAccounts).select("current_balance").eq("is_active", true);
4560
5669
  const totalBalance = (accounts ?? []).reduce((s, a) => s + (a.current_balance ?? 0), 0);
4561
- const { data: movs } = await pub.from("financial_movements").select("direction, movement_kind, amount, paid_amount, status, due_date, payment_date");
5670
+ const { data: movs } = await pub.from(T.movements).select("direction, movement_kind, amount, paid_amount, status, due_date, payment_date");
4562
5671
  const allMovs = movs ?? [];
4563
5672
  const unpaid = allMovs.filter((m) => ["pending", "partial", "overdue"].includes(m.status));
4564
5673
  const today2 = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
@@ -4566,7 +5675,9 @@ function createSupabaseFinancialProvider() {
4566
5675
  const unpaidDebit = unpaid.filter((m) => m.direction === "debit");
4567
5676
  const overdueCredit = unpaidCredit.filter((m) => m.status === "overdue" || m.due_date < today2);
4568
5677
  const overdueDebit = unpaidDebit.filter((m) => m.status === "overdue" || m.due_date < today2);
4569
- const monthStart = today2.slice(0, 7) + "-01";
5678
+ const monthAgo = /* @__PURE__ */ new Date();
5679
+ monthAgo.setDate(monthAgo.getDate() - 30);
5680
+ const monthStart = monthAgo.toISOString().slice(0, 10);
4570
5681
  const monthPaid = allMovs.filter((m) => m.movement_kind === "payment" && m.payment_date >= monthStart);
4571
5682
  return {
4572
5683
  totalBalance,
@@ -4589,7 +5700,7 @@ function createSupabaseFinancialProvider() {
4589
5700
  const tenantId = getTenantId();
4590
5701
  let imported = 0, duplicates = 0;
4591
5702
  for (const line of input.lines) {
4592
- const { error } = await pub.from("financial_movements").insert({
5703
+ const { error } = await pub.from(T.movements).insert({
4593
5704
  tenant_id: tenantId,
4594
5705
  direction: line.direction,
4595
5706
  movement_kind: "payment",
@@ -4612,7 +5723,7 @@ function createSupabaseFinancialProvider() {
4612
5723
  },
4613
5724
  async getUnreconciled(query) {
4614
5725
  const { pub } = getClients();
4615
- let qb = pub.from("financial_movements").select("*").not("external_source", "is", null).is("reconciled_at", null);
5726
+ let qb = pub.from(T.movements).select("*").not("external_source", "is", null).is("reconciled_at", null);
4616
5727
  if (query?.bankAccountId) qb = qb.eq("bank_account_id", query.bankAccountId);
4617
5728
  if (query?.dateRange) qb = qb.gte("payment_date", query.dateRange.from).lte("payment_date", query.dateRange.to);
4618
5729
  const { data } = await qb.order("payment_date", { ascending: false });
@@ -4620,12 +5731,12 @@ function createSupabaseFinancialProvider() {
4620
5731
  },
4621
5732
  async suggestReconciliation(bankMovementId) {
4622
5733
  const { core, pub } = getClients();
4623
- const { data: line } = await pub.from("financial_movements").select("*").eq("id", bankMovementId).single();
5734
+ const { data: line } = await pub.from(T.movements).select("*").eq("id", bankMovementId).single();
4624
5735
  if (!line) return [];
4625
5736
  const amount = Number(line.amount) || 0;
4626
5737
  const lineDate = line.payment_date ?? line.due_date;
4627
5738
  const tol = Math.max(0.01, round22(amount * 0.02));
4628
- const { data } = await pub.from("financial_movements").select("*").is("external_source", null).is("reconciled_at", null).eq("direction", line.direction).gte("amount", round22(amount - tol)).lte("amount", round22(amount + tol)).neq("id", bankMovementId).limit(25);
5739
+ const { data } = await pub.from(T.movements).select("*").is("external_source", null).is("reconciled_at", null).eq("direction", line.direction).gte("amount", round22(amount - tol)).lte("amount", round22(amount + tol)).neq("id", bankMovementId).limit(25);
4629
5740
  const candidates = (data ?? []).map((r) => {
4630
5741
  const amtDiff = Math.abs((Number(r.amount) || 0) - amount);
4631
5742
  const amtScore = amount > 0 ? Math.max(0, 1 - amtDiff / amount) : 0;
@@ -4651,20 +5762,20 @@ function createSupabaseFinancialProvider() {
4651
5762
  async reconcileMovement(input) {
4652
5763
  const { pub } = getClients();
4653
5764
  const now2 = (/* @__PURE__ */ new Date()).toISOString();
4654
- await pub.from("financial_movements").update({
5765
+ await pub.from(T.movements).update({
4655
5766
  reconciled_at: now2,
4656
5767
  matched_movement_id: input.matchedMovementId ?? null
4657
5768
  }).eq("id", input.bankMovementId);
4658
5769
  if (input.matchedMovementId) {
4659
- await pub.from("financial_movements").update({ reconciled_at: now2 }).eq("id", input.matchedMovementId);
5770
+ await pub.from(T.movements).update({ reconciled_at: now2 }).eq("id", input.matchedMovementId);
4660
5771
  }
4661
5772
  },
4662
5773
  async unreconcileMovement(bankMovementId) {
4663
5774
  const { pub } = getClients();
4664
- const { data: line } = await pub.from("financial_movements").select("matched_movement_id").eq("id", bankMovementId).single();
4665
- await pub.from("financial_movements").update({ reconciled_at: null, matched_movement_id: null }).eq("id", bankMovementId);
5775
+ const { data: line } = await pub.from(T.movements).select("matched_movement_id").eq("id", bankMovementId).single();
5776
+ await pub.from(T.movements).update({ reconciled_at: null, matched_movement_id: null }).eq("id", bankMovementId);
4666
5777
  if (line?.matched_movement_id) {
4667
- await pub.from("financial_movements").update({ reconciled_at: null }).eq("id", line.matched_movement_id);
5778
+ await pub.from(T.movements).update({ reconciled_at: null }).eq("id", line.matched_movement_id);
4668
5779
  }
4669
5780
  }
4670
5781
  };
@@ -4757,6 +5868,82 @@ function createFinancialStore(provider) {
4757
5868
  throw err;
4758
5869
  }
4759
5870
  },
5871
+ async createQuickTransaction(input) {
5872
+ try {
5873
+ if (input.type === "transfer") {
5874
+ if (!input.bankAccountId || !input.toAccountId) {
5875
+ throw new Error("Select source and destination accounts");
5876
+ }
5877
+ await provider.createTransfer({
5878
+ fromAccountId: input.bankAccountId,
5879
+ toAccountId: input.toAccountId,
5880
+ amount: input.amount,
5881
+ date: input.date,
5882
+ notes: input.description?.trim() || void 0
5883
+ });
5884
+ } else {
5885
+ const direction = input.type === "income" ? "credit" : "debit";
5886
+ const desc = input.description?.trim() || (input.type === "income" ? "Receita" : "Despesa");
5887
+ const invoiceMeta = {};
5888
+ if (input.recurring) invoiceMeta.recurring = true;
5889
+ if (input.receiptUrl) invoiceMeta.receiptUrl = input.receiptUrl;
5890
+ const invoice = await provider.createInvoice({
5891
+ direction,
5892
+ invoiceDate: input.date,
5893
+ contactName: desc,
5894
+ metadata: Object.keys(invoiceMeta).length > 0 ? invoiceMeta : void 0,
5895
+ items: [{
5896
+ itemKind: "other",
5897
+ description: desc,
5898
+ quantity: 1,
5899
+ unitPrice: input.amount,
5900
+ accountId: input.categoryId
5901
+ }],
5902
+ installments: [{
5903
+ direction,
5904
+ movementKind: "bill",
5905
+ amount: input.amount,
5906
+ dueDate: input.date,
5907
+ installmentNumber: 1,
5908
+ bankAccountId: input.bankAccountId,
5909
+ notes: desc
5910
+ }]
5911
+ });
5912
+ if (input.paid) {
5913
+ const movements = await provider.getMovements({ direction, status: "pending" });
5914
+ const bill = movements.data.find((m) => m.invoiceId === invoice.id && m.movementKind === "bill");
5915
+ if (bill) {
5916
+ await provider.payMovement({
5917
+ movementId: bill.id,
5918
+ amount: input.amount,
5919
+ paymentDate: input.date,
5920
+ bankAccountId: input.bankAccountId,
5921
+ notes: desc
5922
+ });
5923
+ }
5924
+ }
5925
+ }
5926
+ const invoiceQuery = get().invoiceQuery;
5927
+ const statementQuery = get().statementQuery;
5928
+ const [summary, bankAccounts, invoicesRes, statement] = await Promise.all([
5929
+ provider.getSummary(),
5930
+ provider.getBankAccounts(),
5931
+ provider.getInvoices(invoiceQuery),
5932
+ statementQuery ? provider.getStatement(statementQuery) : Promise.resolve(get().statement)
5933
+ ]);
5934
+ set({
5935
+ summary,
5936
+ bankAccounts,
5937
+ invoices: invoicesRes.data,
5938
+ invoicesTotal: invoicesRes.total,
5939
+ statement
5940
+ });
5941
+ ui.toast.success("Transaction saved");
5942
+ } catch (err) {
5943
+ ui.toast.error("Failed to save transaction", { description: err?.message });
5944
+ throw err;
5945
+ }
5946
+ },
4760
5947
  async payMovement(input) {
4761
5948
  try {
4762
5949
  await provider.payMovement(input);
@@ -4836,7 +6023,7 @@ var paymentMethodTypeEntity = {
4836
6023
  { key: "transactionType", label: "Transaction Type", type: "select", options: ["cash", "credit_card", "debit_card", "pix", "bank_transfer", "check", "voucher"], showInTable: true, required: true },
4837
6024
  { key: "isActive", label: "Active", type: "boolean", showInTable: true, defaultValue: true }
4838
6025
  ],
4839
- data: { table: "payment_method_types", tenantScoped: true }
6026
+ data: { table: T.paymentMethodTypes, tenantScoped: true }
4840
6027
  };
4841
6028
  var paymentMethodEntity = {
4842
6029
  name: "Payment Method",
@@ -4848,14 +6035,14 @@ var paymentMethodEntity = {
4848
6035
  { key: "name", label: "Name", type: "text", required: true, showInTable: true },
4849
6036
  // FK to the seeded payment_method_types catalog — load real ids at runtime
4850
6037
  // (a static enum select would write the string into the uuid column).
4851
- { key: "paymentMethodTypeId", label: "Type", type: "relation", relation: { table: "payment_method_types", labelField: "name" }, showInTable: true, required: true },
6038
+ { key: "paymentMethodTypeId", label: "Type", type: "relation", relation: { table: T.paymentMethodTypes, labelField: "name" }, showInTable: true, required: true },
4852
6039
  { key: "discountValue", label: "Discount %", type: "number", showInTable: true },
4853
6040
  { key: "interestValue", label: "Interest %", type: "number", showInTable: true },
4854
6041
  { key: "minInstallments", label: "Min Installments", type: "number", defaultValue: 1 },
4855
6042
  { key: "maxInstallments", label: "Max Installments", type: "number", defaultValue: 1, showInTable: true },
4856
6043
  { key: "isActive", label: "Active", type: "boolean", showInTable: true, defaultValue: true }
4857
6044
  ],
4858
- data: { table: "payment_methods", tenantScoped: true }
6045
+ data: { table: T.paymentMethods, tenantScoped: true }
4859
6046
  };
4860
6047
  var chartOfAccountsEntity = {
4861
6048
  name: "Ledger Account",
@@ -4870,7 +6057,7 @@ var chartOfAccountsEntity = {
4870
6057
  { key: "parentId", label: "Parent", type: "text", showInTable: false },
4871
6058
  { key: "isActive", label: "Active", type: "boolean", showInTable: true, defaultValue: true }
4872
6059
  ],
4873
- data: { table: "chart_of_accounts", tenantScoped: true }
6060
+ data: { table: T.chartOfAccounts, tenantScoped: true }
4874
6061
  };
4875
6062
  var costCenterEntity = {
4876
6063
  name: "Cost Center",
@@ -4883,7 +6070,7 @@ var costCenterEntity = {
4883
6070
  { key: "name", label: "Name", type: "text", required: true, showInTable: true },
4884
6071
  { key: "isActive", label: "Active", type: "boolean", showInTable: true, defaultValue: true }
4885
6072
  ],
4886
- data: { table: "cost_centers", tenantScoped: true }
6073
+ data: { table: T.costCenters, tenantScoped: true }
4887
6074
  };
4888
6075
  var bankAccountEntity = {
4889
6076
  name: "Bank Account",
@@ -4908,7 +6095,7 @@ var bankAccountEntity = {
4908
6095
  { key: "dueDay", label: "Due Day", type: "number" },
4909
6096
  { key: "isActive", label: "Active", type: "boolean", showInTable: true, defaultValue: true }
4910
6097
  ],
4911
- data: { table: "bank_accounts", tenantScoped: true }
6098
+ data: { table: T.bankAccounts, tenantScoped: true }
4912
6099
  };
4913
6100
  var cardBrandEntity = {
4914
6101
  name: "Card Brand",
@@ -4920,7 +6107,7 @@ var cardBrandEntity = {
4920
6107
  { key: "name", label: "Name", type: "text", required: true, showInTable: true },
4921
6108
  { key: "isActive", label: "Active", type: "boolean", showInTable: true, defaultValue: true }
4922
6109
  ],
4923
- data: { table: "card_brands", tenantScoped: true }
6110
+ data: { table: T.cardBrands, tenantScoped: true }
4924
6111
  };
4925
6112
  var commissionRuleEntity = {
4926
6113
  name: "Commission Rule",
@@ -5083,8 +6270,18 @@ var financialRegistries = [
5083
6270
 
5084
6271
  // src/locales/en.ts
5085
6272
  var en = {
6273
+ "financial.cards.addExpense": "Add expense",
6274
+ "financial.cards.allBillsValue": "All bills value",
6275
+ "financial.cards.availableLimit": "Available limit",
6276
+ "financial.cards.currentBill": "Current bill",
6277
+ "financial.cards.dueOn": "Due on the {{day}}",
5086
6278
  "financial.cards.installment": "Installment {{current}}/{{total}}",
6279
+ "financial.cards.noCards": "No cards yet",
6280
+ "financial.cards.noCardsHint": "Add a credit card in settings to track your bills here",
5087
6281
  "financial.cards.noTransactions": "No card transactions",
6282
+ "financial.cards.tabClosed": "Closed",
6283
+ "financial.cards.tabOpen": "Open",
6284
+ "financial.cards.usedOfLimit": "{{percent}}% of limit used",
5088
6285
  "financial.cards.pending": "Pending",
5089
6286
  "financial.cards.received": "Received",
5090
6287
  "financial.cards.subtitle": "Credit and debit card transactions",
@@ -5211,6 +6408,10 @@ var en = {
5211
6408
  "financial.nav.rules": "Rules",
5212
6409
  "financial.nav.statements": "Statements",
5213
6410
  "financial.nav.summary": "Summary",
6411
+ "financial.invoice.filterAccount": "Chart account",
6412
+ "financial.invoice.filterAllAccounts": "All accounts",
6413
+ "financial.invoice.filterCostCenter": "Cost center",
6414
+ "financial.invoice.filterAllCostCenters": "All cost centers",
5214
6415
  "financial.reconciliation.title": "Reconciliation",
5215
6416
  "financial.reconciliation.subtitle": "Match imported bank lines to your movements",
5216
6417
  "financial.reconciliation.pending": "{{count}} to reconcile",
@@ -5325,6 +6526,36 @@ var en = {
5325
6526
  "financial.summary.totalBalance": "Total Balance",
5326
6527
  "financial.summary.transactionsAppear": "Transactions will appear here once recorded",
5327
6528
  "financial.summary.viewAll": "View all",
6529
+ "financial.summary.today": "Today",
6530
+ "financial.summary.yesterday": "Yesterday",
6531
+ "financial.summary.transactionsTitle": "Transactions",
6532
+ "financial.home.balance": "Balance",
6533
+ "financial.home.inflow": "Income",
6534
+ "financial.home.outflow": "Expenses",
6535
+ "financial.home.showBalance": "Show balance",
6536
+ "financial.home.hideBalance": "Hide balance",
6537
+ "financial.home.upcomingBills": "Upcoming bills",
6538
+ "financial.home.noBills": "No upcoming bills.",
6539
+ "financial.home.dueToday": "Due today",
6540
+ "financial.home.dueTomorrow": "Due tomorrow",
6541
+ "financial.home.dueInDays": "Due in {{count}} days",
6542
+ "financial.home.overdueDays": "Overdue by {{count}} days",
6543
+ "financial.home.cards": "Cards",
6544
+ "financial.home.currentBill": "Current bill",
6545
+ "financial.home.availableLimit": "Available limit",
6546
+ "financial.home.addCard": "New card",
6547
+ "financial.home.bill": "Bill",
6548
+ "financial.home.spendByCategory": "Spending by category",
6549
+ "financial.home.noSpend": "No spending this month.",
6550
+ "financial.home.category.groceries": "Groceries",
6551
+ "financial.home.category.transport": "Transport",
6552
+ "financial.home.category.subscriptions": "Subscriptions",
6553
+ "financial.home.category.dining": "Dining",
6554
+ "financial.home.category.home": "Home",
6555
+ "financial.home.category.health": "Health",
6556
+ "financial.home.category.leisure": "Leisure",
6557
+ "financial.home.category.shopping": "Shopping",
6558
+ "financial.home.category.other": "Other",
5328
6559
  "financial.quickActions.newPayable": "New Payable",
5329
6560
  "financial.quickActions.newPayableDesc": "Record an expense or bill to pay",
5330
6561
  "financial.quickActions.newReceivable": "New Receivable",
@@ -5486,13 +6717,54 @@ var en = {
5486
6717
  "financial.transfer.created": "Transfer recorded",
5487
6718
  "financial.transfer.failed": "Failed to record transfer",
5488
6719
  "financial.transfer.sameAccount": "Source and destination must differ",
5489
- "financial.transfer.invalidAmount": "Amount must be greater than zero"
6720
+ "financial.transfer.invalidAmount": "Amount must be greater than zero",
6721
+ "financial.quickTx.title": "New transaction",
6722
+ "financial.quickTx.close": "Close",
6723
+ "financial.quickTx.newTransaction": "New transaction",
6724
+ "financial.quickTx.expense": "Expense",
6725
+ "financial.quickTx.income": "Income",
6726
+ "financial.quickTx.transfer": "Transfer",
6727
+ "financial.quickTx.paid": "Paid",
6728
+ "financial.quickTx.received": "Received",
6729
+ "financial.quickTx.yes": "Yes",
6730
+ "financial.quickTx.no": "No",
6731
+ "financial.quickTx.category": "Category",
6732
+ "financial.quickTx.selectCategory": "No category",
6733
+ "financial.quickTx.account": "Account",
6734
+ "financial.quickTx.selectAccount": "Select account",
6735
+ "financial.quickTx.fromAccount": "From account",
6736
+ "financial.quickTx.toAccount": "To account",
6737
+ "financial.quickTx.card": "Card",
6738
+ "financial.quickTx.recurring": "Recurring",
6739
+ "financial.quickTx.attachment": "Attachment",
6740
+ "financial.quickTx.attachmentSoon": "Attachments coming soon",
6741
+ "financial.quickTx.receipt": "Receipt",
6742
+ "financial.quickTx.receiptCapture": "Snap or attach a receipt",
6743
+ "financial.quickTx.receiptAttached": "Receipt attached",
6744
+ "financial.quickTx.receiptReplace": "Replace",
6745
+ "financial.quickTx.receiptRemove": "Remove receipt",
6746
+ "financial.quickTx.receiptInvalid": "Please choose an image file",
6747
+ "financial.quickTx.sendReceipt": "Send receipt",
6748
+ "financial.quickTx.descriptionPlaceholder": "e.g. Groceries, Salary\u2026",
6749
+ "financial.quickTx.enterAmount": "Enter an amount",
6750
+ "financial.quickTx.save": "Save",
6751
+ "financial.quickTx.saving": "Saving\u2026"
5490
6752
  };
5491
6753
 
5492
6754
  // src/locales/pt-BR.ts
5493
6755
  var ptBR = {
6756
+ "financial.cards.addExpense": "Adicionar despesa",
6757
+ "financial.cards.allBillsValue": "Total das faturas",
6758
+ "financial.cards.availableLimit": "Limite dispon\xEDvel",
6759
+ "financial.cards.currentBill": "Fatura atual",
6760
+ "financial.cards.dueOn": "Vence dia {{day}}",
5494
6761
  "financial.cards.installment": "Parcela {{current}}/{{total}}",
6762
+ "financial.cards.noCards": "Nenhum cart\xE3o cadastrado",
6763
+ "financial.cards.noCardsHint": "Adicione um cart\xE3o de cr\xE9dito nas configura\xE7\xF5es para acompanhar suas faturas aqui",
5495
6764
  "financial.cards.noTransactions": "Nenhuma transa\xE7\xE3o com cart\xE3o",
6765
+ "financial.cards.tabClosed": "Fechados",
6766
+ "financial.cards.tabOpen": "Abertos",
6767
+ "financial.cards.usedOfLimit": "{{percent}}% do limite usado",
5496
6768
  "financial.cards.pending": "Pendente",
5497
6769
  "financial.cards.received": "Recebido",
5498
6770
  "financial.cards.subtitle": "Transa\xE7\xF5es de cart\xE3o de cr\xE9dito e d\xE9bito",
@@ -5619,6 +6891,10 @@ var ptBR = {
5619
6891
  "financial.nav.rules": "Regras",
5620
6892
  "financial.nav.statements": "Extratos",
5621
6893
  "financial.nav.summary": "Resumo",
6894
+ "financial.invoice.filterAccount": "Plano de contas",
6895
+ "financial.invoice.filterAllAccounts": "Todos os planos",
6896
+ "financial.invoice.filterCostCenter": "Centro de custo",
6897
+ "financial.invoice.filterAllCostCenters": "Todos os centros",
5622
6898
  "financial.reconciliation.title": "Concilia\xE7\xE3o",
5623
6899
  "financial.reconciliation.subtitle": "Concilie as linhas importadas do banco com seus lan\xE7amentos",
5624
6900
  "financial.reconciliation.pending": "{{count}} para conciliar",
@@ -5733,6 +7009,36 @@ var ptBR = {
5733
7009
  "financial.summary.totalBalance": "Saldo Total",
5734
7010
  "financial.summary.transactionsAppear": "As transa\xE7\xF5es aparecer\xE3o aqui ap\xF3s serem registradas",
5735
7011
  "financial.summary.viewAll": "Ver todos",
7012
+ "financial.summary.today": "Hoje",
7013
+ "financial.summary.yesterday": "Ontem",
7014
+ "financial.summary.transactionsTitle": "Transa\xE7\xF5es",
7015
+ "financial.home.balance": "Saldo",
7016
+ "financial.home.inflow": "Entradas",
7017
+ "financial.home.outflow": "Sa\xEDdas",
7018
+ "financial.home.showBalance": "Mostrar saldo",
7019
+ "financial.home.hideBalance": "Ocultar saldo",
7020
+ "financial.home.upcomingBills": "Pr\xF3ximas contas",
7021
+ "financial.home.noBills": "Nenhuma conta a vencer.",
7022
+ "financial.home.dueToday": "Vence hoje",
7023
+ "financial.home.dueTomorrow": "Vence amanh\xE3",
7024
+ "financial.home.dueInDays": "Vence em {{count}} dias",
7025
+ "financial.home.overdueDays": "Venceu h\xE1 {{count}} dias",
7026
+ "financial.home.cards": "Cart\xF5es",
7027
+ "financial.home.currentBill": "Fatura atual",
7028
+ "financial.home.availableLimit": "Limite dispon\xEDvel",
7029
+ "financial.home.addCard": "Novo cart\xE3o",
7030
+ "financial.home.bill": "Conta",
7031
+ "financial.home.spendByCategory": "Gastos por categoria",
7032
+ "financial.home.noSpend": "Sem gastos neste m\xEAs.",
7033
+ "financial.home.category.groceries": "Mercado",
7034
+ "financial.home.category.transport": "Transporte",
7035
+ "financial.home.category.subscriptions": "Assinaturas",
7036
+ "financial.home.category.dining": "Alimenta\xE7\xE3o",
7037
+ "financial.home.category.home": "Casa",
7038
+ "financial.home.category.health": "Sa\xFAde",
7039
+ "financial.home.category.leisure": "Lazer",
7040
+ "financial.home.category.shopping": "Compras",
7041
+ "financial.home.category.other": "Outros",
5736
7042
  "financial.quickActions.newPayable": "Nova Conta a Pagar",
5737
7043
  "financial.quickActions.newPayableDesc": "Registrar uma despesa ou conta a pagar",
5738
7044
  "financial.quickActions.newReceivable": "Nova Conta a Receber",
@@ -5894,7 +7200,38 @@ var ptBR = {
5894
7200
  "financial.transfer.created": "Transfer\xEAncia registrada",
5895
7201
  "financial.transfer.failed": "Falha ao registrar transfer\xEAncia",
5896
7202
  "financial.transfer.sameAccount": "Origem e destino devem ser diferentes",
5897
- "financial.transfer.invalidAmount": "O valor deve ser maior que zero"
7203
+ "financial.transfer.invalidAmount": "O valor deve ser maior que zero",
7204
+ "financial.quickTx.title": "Nova transa\xE7\xE3o",
7205
+ "financial.quickTx.close": "Fechar",
7206
+ "financial.quickTx.newTransaction": "Nova transa\xE7\xE3o",
7207
+ "financial.quickTx.expense": "Despesa",
7208
+ "financial.quickTx.income": "Receita",
7209
+ "financial.quickTx.transfer": "Transfer\xEAncia",
7210
+ "financial.quickTx.paid": "Pago",
7211
+ "financial.quickTx.received": "Recebido",
7212
+ "financial.quickTx.yes": "Sim",
7213
+ "financial.quickTx.no": "N\xE3o",
7214
+ "financial.quickTx.category": "Categoria",
7215
+ "financial.quickTx.selectCategory": "Sem categoria",
7216
+ "financial.quickTx.account": "Conta",
7217
+ "financial.quickTx.selectAccount": "Selecione a conta",
7218
+ "financial.quickTx.fromAccount": "Conta de origem",
7219
+ "financial.quickTx.toAccount": "Conta de destino",
7220
+ "financial.quickTx.card": "Cart\xE3o",
7221
+ "financial.quickTx.recurring": "Recorrente",
7222
+ "financial.quickTx.attachment": "Anexo",
7223
+ "financial.quickTx.attachmentSoon": "Anexos em breve",
7224
+ "financial.quickTx.receipt": "Recibo",
7225
+ "financial.quickTx.receiptCapture": "Fotografar ou anexar recibo",
7226
+ "financial.quickTx.receiptAttached": "Recibo anexado",
7227
+ "financial.quickTx.receiptReplace": "Substituir",
7228
+ "financial.quickTx.receiptRemove": "Remover recibo",
7229
+ "financial.quickTx.receiptInvalid": "Escolha um arquivo de imagem",
7230
+ "financial.quickTx.sendReceipt": "Enviar recibo",
7231
+ "financial.quickTx.descriptionPlaceholder": "ex.: Mercado, Sal\xE1rio\u2026",
7232
+ "financial.quickTx.enterAmount": "Informe um valor",
7233
+ "financial.quickTx.save": "Salvar",
7234
+ "financial.quickTx.saving": "Salvando\u2026"
5898
7235
  };
5899
7236
 
5900
7237
  // src/locales/index.ts
@@ -5912,9 +7249,9 @@ var STATUS_STYLE = {
5912
7249
  function PersonStatementWidget({ person, provider, config }) {
5913
7250
  const t2 = core.useTranslation();
5914
7251
  const currency = config.currency;
5915
- const [invoices, setInvoices] = React14.useState([]);
5916
- const [loading, setLoading] = React14.useState(true);
5917
- React14.useEffect(() => {
7252
+ const [invoices, setInvoices] = React17.useState([]);
7253
+ const [loading, setLoading] = React17.useState(true);
7254
+ React17.useEffect(() => {
5918
7255
  let alive = true;
5919
7256
  if (!person?.id) {
5920
7257
  setLoading(false);
@@ -5934,7 +7271,7 @@ function PersonStatementWidget({ person, provider, config }) {
5934
7271
  };
5935
7272
  }, [person?.id, provider]);
5936
7273
  const fmt = (n) => saas.formatCurrency(n, currency);
5937
- const totals = React14.useMemo(() => {
7274
+ const totals = React17.useMemo(() => {
5938
7275
  const active = invoices.filter((i) => i.status !== "cancelled");
5939
7276
  const billed = active.reduce((s, i) => s + (i.totalAmount ?? 0), 0);
5940
7277
  const paid = active.reduce((s, i) => s + (i.paidAmount ?? 0), 0);
@@ -5944,7 +7281,7 @@ function PersonStatementWidget({ person, provider, config }) {
5944
7281
  const base = inv.direction === "credit" ? "receivables" : "payables";
5945
7282
  window.location.hash = `/financial/${base}/detail/${inv.id}`;
5946
7283
  };
5947
- const columns = React14.useMemo(() => [
7284
+ const columns = React17.useMemo(() => [
5948
7285
  {
5949
7286
  id: "date",
5950
7287
  header: t2("financial.invoice.columnDate"),
@@ -6044,6 +7381,8 @@ function resolveConfig(options) {
6044
7381
  // Opt-in: only shown when an app explicitly enables reconciliation (bank connector present).
6045
7382
  reconciliation: options?.modules?.reconciliation === true
6046
7383
  },
7384
+ // Opt-in: only render the plugin's own quick-add buttons/FAB when the host asks.
7385
+ quickAdd: options?.quickAdd === true,
6047
7386
  labels: { ...DEFAULT_LABELS, ...options?.labels },
6048
7387
  currency: { ...DEFAULT_CURRENCY, ...options?.currency },
6049
7388
  itemTypes: options?.itemTypes ?? DEFAULT_ITEM_TYPES,
@@ -6064,9 +7403,10 @@ function createFinancialPlugin(options) {
6064
7403
  const provider = options?.dataProvider ?? createSafeFinancialProvider();
6065
7404
  const store = createFinancialStore(provider);
6066
7405
  const dashboardWidgets = createFinancialDashboardWidgets({ config, provider, store });
6067
- const PersonStatementBound = (props) => React14__default.default.createElement(PersonStatementWidget, { person: props.item, provider, config });
7406
+ const registries = [...financialRegistries, ...options?.settingsRegistries ?? []];
7407
+ const PersonStatementBound = (props) => React17__namespace.default.createElement(PersonStatementWidget, { person: props.item, provider, config });
6068
7408
  PersonStatementBound.displayName = "FinancialPersonStatement";
6069
- const PageComponent = () => React14__default.default.createElement(FinancialPage, { config, provider, store, registries: financialRegistries });
7409
+ const PageComponent = () => React17__namespace.default.createElement(FinancialPage, { config, provider, store, registries });
6070
7410
  return {
6071
7411
  id: "financial",
6072
7412
  name: config.labels.pageTitle,
@@ -6171,18 +7511,18 @@ function createFinancialPlugin(options) {
6171
7511
  ]
6172
7512
  }
6173
7513
  ],
6174
- registries: financialRegistries,
7514
+ registries,
6175
7515
  settings: [
6176
7516
  {
6177
7517
  id: "financial",
6178
7518
  label: "Financial",
6179
7519
  icon: "DollarSign",
6180
7520
  component: (() => {
6181
- const FinancialSettingsTab = () => React14__default.default.createElement(saas.PluginSettingsPanel, {
7521
+ const FinancialSettingsTab = () => React17__namespace.default.createElement(saas.PluginSettingsPanel, {
6182
7522
  title: "Financial Settings",
6183
7523
  subtitle: "Payment methods, accounts, and configurations",
6184
- generalSettings: React14__default.default.createElement(FinancialGeneralSettings),
6185
- registries: financialRegistries,
7524
+ generalSettings: React17__namespace.default.createElement(FinancialGeneralSettings),
7525
+ registries,
6186
7526
  hostPluginId: "financial",
6187
7527
  routeBase: "/settings/financial"
6188
7528
  });
@@ -6198,6 +7538,8 @@ function createFinancialPlugin(options) {
6198
7538
  }
6199
7539
 
6200
7540
  exports.createFinancialPlugin = createFinancialPlugin;
7541
+ exports.createMockFinancialProvider = createMockFinancialProvider;
6201
7542
  exports.createSafeFinancialProvider = createSafeFinancialProvider;
7543
+ exports.openQuickAdd = openQuickAdd;
6202
7544
  //# sourceMappingURL=index.cjs.map
6203
7545
  //# sourceMappingURL=index.cjs.map