@fayz-ai/plugin-financial 0.8.1 → 0.8.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -26,6 +26,7 @@ export interface FinancialPluginLabels {
26
26
  cards: string;
27
27
  cardsOverview: string;
28
28
  cardsReconciliation: string;
29
+ notasFiscais: string;
29
30
  }
30
31
  export interface ItemTypeOption {
31
32
  value: string;
@@ -42,6 +43,8 @@ export interface FinancialPluginOptions {
42
43
  cards?: boolean;
43
44
  /** Bank reconciliation (conciliação). Defaults off — enable with a bank connector. */
44
45
  reconciliation?: boolean;
46
+ /** Notas fiscais (NF-e/NFC-e/NFS-e). Defaults off — opt-in per app. */
47
+ notasFiscais?: boolean;
45
48
  };
46
49
  labels?: Partial<FinancialPluginLabels>;
47
50
  currency?: {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
- import * as React17 from 'react';
2
- import React17__default, { useState, useEffect, useMemo, useCallback, useRef } from 'react';
1
+ import * as React18 from 'react';
2
+ import React18__default, { useState, useEffect, useMemo, useCallback, useRef } from 'react';
3
3
  import { createSafeDataProvider, registerTranslations, useTranslation, getSupabaseClientOptional, getActiveTenantId } from '@fayz-ai/core';
4
- import { toast, defineKpiWidget, defineChartWidget, defineCustomWidget, defineTableWidget, DataTable, PageTransition, ModulePage, Button, Modal, ModalContent, DatePicker, DashboardCanvas, SubpageHeader, TooltipProvider, Tooltip, TooltipTrigger, TooltipContent, CurrencyInput, useSaveBar, SearchSelect, ListView, KpiCard, ChartWidget, Card, CardHeader, CardTitle, CardContent, TableWidget, useDashboardNavigate, GoldCard } from '@fayz-ai/ui';
4
+ import { toast, defineKpiWidget, defineChartWidget, defineCustomWidget, defineTableWidget, DataTable, PageTransition, ModulePage, Button, Modal, ModalContent, DatePicker, DashboardCanvas, SubpageHeader, Skeleton, Input, TooltipProvider, Tooltip, TooltipTrigger, TooltipContent, CurrencyInput, useSaveBar, SearchSelect, ListView, KpiCard, ChartWidget, Card, CardHeader, CardTitle, CardContent, TableWidget, useDashboardNavigate, GoldCard } from '@fayz-ai/ui';
5
5
  import { createPluginContext, PluginSettingsPanel, dedup, useModuleNavigation, usePermissionOptional, useModuleNavAccess, PermissionGate, ModuleActionBar, useTenantPluginSettings, SettingsGroup, ToggleRow, formatCurrency, parseViewId, EntitlementGate, UpgradePrompt, useLimitGuard, invalidateLimit, PersonLink } from '@fayz-ai/saas';
6
- import { Wallet, Plus, DollarSign, Landmark, CreditCard, BookOpen, Check, ChevronRight, X, CalendarDays, Paperclip, Camera, Tag, Repeat, ChevronDown, CalendarClock, RefreshCw, ArrowDownCircle, ArrowUpCircle, Sparkles, Link2, ArrowRightLeft, Receipt, Clock, ArrowLeftRight, CheckCheck, Calculator, StickyNote, Play, Square, ChevronUp, MoreVertical, Ban, LayoutList, CircleDashed, CircleAlert, CircleCheckBig, CircleEllipsis, Pencil, FileText, User, Calendar, Hash, ExternalLink, Building2, ShoppingCart, Car, Home, Utensils, Zap, Film, HeartPulse, Dumbbell, Music, ShoppingBag, CircleDollarSign, Search, Trash2, FileCheck, QrCode, Banknote, ArrowUpRight, ArrowDownRight, AlertTriangle, EyeOff, Eye } from 'lucide-react';
6
+ import { Wallet, Plus, DollarSign, Landmark, CreditCard, BookOpen, Check, ChevronRight, X, CalendarDays, Paperclip, Camera, Tag, Repeat, ChevronDown, FileText, FileCheck2, ExternalLink, Send, Ban, CalendarClock, RefreshCw, ArrowDownCircle, ArrowUpCircle, Sparkles, Link2, ArrowRightLeft, Receipt, Clock, ArrowLeftRight, CheckCheck, Calculator, StickyNote, Play, Square, ChevronUp, MoreVertical, LayoutList, CircleDashed, CircleAlert, CircleCheckBig, CircleEllipsis, Pencil, User, Calendar, Hash, Building2, ShoppingCart, Car, Home, Utensils, Zap, Film, HeartPulse, Dumbbell, Music, ShoppingBag, CircleDollarSign, Search, Trash2, FileCheck, QrCode, Banknote, ArrowUpRight, ArrowDownRight, AlertTriangle, EyeOff, Eye } from 'lucide-react';
7
7
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
8
  import { createPortal } from 'react-dom';
9
9
  import { createStore as createStore$1 } from 'zustand/vanilla';
@@ -641,7 +641,7 @@ function getSnapshot() {
641
641
  return pending;
642
642
  }
643
643
  function usePendingQuickAdd() {
644
- return React17.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
644
+ return React18.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
645
645
  }
646
646
  var STATUS_OPTIONS = [
647
647
  { value: "open", labelKey: "financial.invoice.statusOpen", color: "bg-info-soft text-info-soft-foreground", icon: CircleDashed },
@@ -2086,7 +2086,9 @@ function InvoiceDetailView({ invoiceId, direction, onBack, onEdit, backLabel })
2086
2086
  const [inv, invItems, movResult] = await Promise.all([
2087
2087
  provider.getInvoiceById(invoiceId),
2088
2088
  provider.getInvoiceItems(invoiceId),
2089
- provider.getMovements({ direction })
2089
+ // Scope to THIS invoice (not the tenant-wide first-50 page) so every
2090
+ // installment/payment loads regardless of how many movements exist.
2091
+ provider.getMovements({ direction, invoiceId, pageSize: 500 })
2090
2092
  ]);
2091
2093
  setInvoice(inv);
2092
2094
  setItems(invItems);
@@ -3776,6 +3778,161 @@ function ReconciliationView() {
3776
3778
  ] })
3777
3779
  ] });
3778
3780
  }
3781
+ var MODEL_LABEL = {
3782
+ nfe: "NF-e",
3783
+ nfce: "NFC-e",
3784
+ nfse: "NFS-e"
3785
+ };
3786
+ var STATUS_META = {
3787
+ draft: { label: "Rascunho", className: "bg-muted text-muted-foreground" },
3788
+ processing: { label: "Processando", className: "bg-blue-100 text-blue-800" },
3789
+ issued: { label: "Emitida", className: "bg-emerald-100 text-emerald-800" },
3790
+ cancelled: { label: "Cancelada", className: "bg-red-100 text-red-700" },
3791
+ error: { label: "Erro", className: "bg-orange-100 text-orange-700" }
3792
+ };
3793
+ function NotasFiscaisView() {
3794
+ const provider = useFinancialProvider();
3795
+ const { currency } = useFinancialConfig();
3796
+ const [notas, setNotas] = useState([]);
3797
+ const [loading, setLoading] = useState(true);
3798
+ const [creating, setCreating] = useState(false);
3799
+ const [busy, setBusy] = useState(null);
3800
+ const supported = typeof provider.getNotas === "function";
3801
+ const reload = useCallback(async () => {
3802
+ if (!provider.getNotas) {
3803
+ setLoading(false);
3804
+ return;
3805
+ }
3806
+ setLoading(true);
3807
+ try {
3808
+ const res = await provider.getNotas({ pageSize: 100 });
3809
+ setNotas(res.data);
3810
+ } finally {
3811
+ setLoading(false);
3812
+ }
3813
+ }, [provider]);
3814
+ useEffect(() => {
3815
+ void reload();
3816
+ }, [reload]);
3817
+ const create = async (input) => {
3818
+ if (!provider.createNota) return;
3819
+ await provider.createNota(input);
3820
+ setCreating(false);
3821
+ await reload();
3822
+ };
3823
+ const issue = async (id) => {
3824
+ if (!provider.issueNota) return;
3825
+ setBusy(id);
3826
+ try {
3827
+ await provider.issueNota(id);
3828
+ await reload();
3829
+ } finally {
3830
+ setBusy(null);
3831
+ }
3832
+ };
3833
+ const cancel = async (id) => {
3834
+ if (!provider.cancelNota) return;
3835
+ setBusy(id);
3836
+ try {
3837
+ await provider.cancelNota(id);
3838
+ await reload();
3839
+ } finally {
3840
+ setBusy(null);
3841
+ }
3842
+ };
3843
+ if (!supported) {
3844
+ return /* @__PURE__ */ jsxs("div", { className: "p-1", children: [
3845
+ /* @__PURE__ */ jsx(SubpageHeader, { title: "Notas Fiscais", subtitle: "Emiss\xE3o e acompanhamento de NF-e / NFC-e / NFS-e", icon: "FileText" }),
3846
+ /* @__PURE__ */ jsx("p", { className: "mt-4 text-sm text-muted-foreground", children: "Este provedor financeiro ainda n\xE3o exp\xF5e notas fiscais." })
3847
+ ] });
3848
+ }
3849
+ return /* @__PURE__ */ jsxs("div", { className: "p-1", children: [
3850
+ /* @__PURE__ */ jsx(
3851
+ SubpageHeader,
3852
+ {
3853
+ title: "Notas Fiscais",
3854
+ subtitle: "Emiss\xE3o e acompanhamento de NF-e / NFC-e / NFS-e",
3855
+ icon: "FileText",
3856
+ actions: /* @__PURE__ */ jsx(PermissionGate, { feature: "financial", action: "create", children: /* @__PURE__ */ jsxs(Button, { size: "sm", onClick: () => setCreating(true), children: [
3857
+ /* @__PURE__ */ jsx(Plus, { className: "mr-1.5 h-4 w-4" }),
3858
+ " Nova nota"
3859
+ ] }) })
3860
+ }
3861
+ ),
3862
+ /* @__PURE__ */ jsx("div", { className: "mt-3 rounded-md border border-amber-300/50 bg-amber-50 px-3 py-2 text-xs text-amber-800 dark:bg-amber-950/30 dark:text-amber-300", children: 'Emiss\xE3o fiscal (SEFAZ) ainda n\xE3o integrada \u2014 "Emitir" atribui n\xFAmero/s\xE9rie localmente para acompanhamento. A integra\xE7\xE3o com o emissor entra sem mudar esta tela.' }),
3863
+ creating && /* @__PURE__ */ jsx(CreateForm, { onCancel: () => setCreating(false), onCreate: create }),
3864
+ loading ? /* @__PURE__ */ jsx("div", { className: "mt-4 space-y-2", children: Array.from({ length: 4 }).map((_, i) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 rounded-card border border-border bg-card p-3", children: [
3865
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-9 w-9 shrink-0 rounded-full" }),
3866
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 space-y-2", children: [
3867
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-3.5 w-40 rounded" }),
3868
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-56 rounded" })
3869
+ ] }),
3870
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-20 shrink-0 rounded-md" })
3871
+ ] }, i)) }) : notas.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "mt-4 rounded-card border border-dashed border-border p-8 text-center", children: [
3872
+ /* @__PURE__ */ jsx(FileText, { className: "mx-auto h-8 w-8 text-muted-foreground" }),
3873
+ /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm font-medium text-foreground", children: "Nenhuma nota fiscal ainda" }),
3874
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: "Crie uma nota a partir de um pedido ou manualmente." })
3875
+ ] }) : /* @__PURE__ */ jsx("div", { className: "mt-4 space-y-2", children: notas.map((n) => {
3876
+ const meta = STATUS_META[n.status];
3877
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 rounded-card border border-border bg-card p-3", children: [
3878
+ /* @__PURE__ */ jsx("div", { className: "flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-primary/10", children: /* @__PURE__ */ jsx(FileText, { className: "h-4 w-4 text-primary" }) }),
3879
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
3880
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
3881
+ /* @__PURE__ */ jsxs("span", { className: "text-sm font-medium text-foreground", children: [
3882
+ MODEL_LABEL[n.model],
3883
+ " ",
3884
+ n.number ? `#${n.number}` : "(rascunho)"
3885
+ ] }),
3886
+ /* @__PURE__ */ jsx("span", { className: `rounded-full px-2 py-0.5 text-xs font-medium ${meta.className}`, children: meta.label })
3887
+ ] }),
3888
+ /* @__PURE__ */ jsxs("p", { className: "truncate text-xs text-muted-foreground", children: [
3889
+ n.contactName || "Sem destinat\xE1rio",
3890
+ " \xB7 ",
3891
+ formatCurrency(n.totalAmount, currency),
3892
+ n.issuedAt ? ` \xB7 ${n.issuedAt.slice(0, 10)}` : ""
3893
+ ] })
3894
+ ] }),
3895
+ /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [
3896
+ n.danfeUrl && /* @__PURE__ */ jsx(Button, { size: "sm", variant: "ghost", onClick: () => window.open(n.danfeUrl, "_blank", "noopener,noreferrer"), title: "DANFE", children: /* @__PURE__ */ jsx(FileCheck2, { className: "h-4 w-4" }) }),
3897
+ n.xmlUrl && /* @__PURE__ */ jsx(Button, { size: "sm", variant: "ghost", onClick: () => window.open(n.xmlUrl, "_blank", "noopener,noreferrer"), title: "XML", children: /* @__PURE__ */ jsx(ExternalLink, { className: "h-4 w-4" }) }),
3898
+ n.status === "draft" && /* @__PURE__ */ jsx(PermissionGate, { feature: "financial", action: "edit", children: /* @__PURE__ */ jsxs(Button, { size: "sm", disabled: busy === n.id, onClick: () => issue(n.id), children: [
3899
+ /* @__PURE__ */ jsx(Send, { className: "mr-1.5 h-3.5 w-3.5" }),
3900
+ " Emitir"
3901
+ ] }) }),
3902
+ n.status === "issued" && /* @__PURE__ */ jsx(PermissionGate, { feature: "financial", action: "edit", children: /* @__PURE__ */ jsx(Button, { size: "sm", variant: "ghost", disabled: busy === n.id, onClick: () => cancel(n.id), title: "Cancelar", children: /* @__PURE__ */ jsx(Ban, { className: "h-4 w-4 text-red-500" }) }) })
3903
+ ] })
3904
+ ] }, n.id);
3905
+ }) })
3906
+ ] });
3907
+ }
3908
+ function CreateForm({ onCancel, onCreate }) {
3909
+ const [model, setModel] = useState("nfe");
3910
+ const [contactName, setContactName] = useState("");
3911
+ const [total, setTotal] = useState("");
3912
+ const [observations, setObservations] = useState("");
3913
+ const models = ["nfe", "nfce", "nfse"];
3914
+ return /* @__PURE__ */ jsxs("div", { className: "mt-4 rounded-card border border-border bg-card p-4", children: [
3915
+ /* @__PURE__ */ jsx("p", { className: "mb-3 text-sm font-semibold text-foreground", children: "Nova nota fiscal" }),
3916
+ /* @__PURE__ */ jsx("div", { className: "mb-3 flex flex-wrap gap-2", children: models.map((m) => /* @__PURE__ */ jsx("button", { type: "button", onClick: () => setModel(m), className: `rounded-full px-3 py-1 text-xs font-medium ${m === model ? "bg-primary text-primary-foreground" : "bg-muted text-muted-foreground hover:text-foreground"}`, children: MODEL_LABEL[m] }, m)) }),
3917
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 sm:flex-row", children: [
3918
+ /* @__PURE__ */ jsx(Input, { value: contactName, placeholder: "Destinat\xE1rio", onChange: (e) => setContactName(e.target.value), className: "flex-1" }),
3919
+ /* @__PURE__ */ jsx(Input, { value: total, placeholder: "Valor total", inputMode: "decimal", onChange: (e) => setTotal(e.target.value), className: "sm:w-40" })
3920
+ ] }),
3921
+ /* @__PURE__ */ jsx(Input, { value: observations, placeholder: "Observa\xE7\xF5es (opcional)", onChange: (e) => setObservations(e.target.value), className: "mt-2" }),
3922
+ /* @__PURE__ */ jsxs("div", { className: "mt-3 flex gap-2", children: [
3923
+ /* @__PURE__ */ jsx(
3924
+ Button,
3925
+ {
3926
+ size: "sm",
3927
+ disabled: !total || Number.isNaN(Number(total)),
3928
+ onClick: () => onCreate({ model, contactName: contactName || void 0, totalAmount: Number(total) || 0, observations: observations || void 0 }),
3929
+ children: "Criar rascunho"
3930
+ }
3931
+ ),
3932
+ /* @__PURE__ */ jsx(Button, { size: "sm", variant: "outline", onClick: onCancel, children: "Cancelar" })
3933
+ ] })
3934
+ ] });
3935
+ }
3779
3936
  var FINANCIAL_DEFAULTS = {
3780
3937
  autoInstallments: true,
3781
3938
  requireDoc: false,
@@ -3919,6 +4076,15 @@ function buildNav(config, activeView, navigate, t2) {
3919
4076
  onClick: () => navigate("reconciliation")
3920
4077
  });
3921
4078
  }
4079
+ if (config.modules.notasFiscais) {
4080
+ items.push({
4081
+ id: "notas-fiscais",
4082
+ label: t2("financial.nav.notasFiscais"),
4083
+ icon: "FileText",
4084
+ active: activeView === "notas-fiscais",
4085
+ onClick: () => navigate("notas-fiscais")
4086
+ });
4087
+ }
3922
4088
  if (config.modules.commissions) {
3923
4089
  items.push({
3924
4090
  id: "commissions",
@@ -3959,6 +4125,7 @@ function FinancialPage({ config, provider, store, registries }) {
3959
4125
  reconciliation: 0,
3960
4126
  commissions: 0,
3961
4127
  cards: 0,
4128
+ "notas-fiscais": 0,
3962
4129
  settings: 1
3963
4130
  });
3964
4131
  const [onboardingComplete, setOnboardingComplete] = useState(() => {
@@ -4075,6 +4242,8 @@ function FinancialPage({ config, provider, store, registries }) {
4075
4242
  return /* @__PURE__ */ jsx(CommissionsView, {});
4076
4243
  case "cards":
4077
4244
  return /* @__PURE__ */ jsx(CardsView, {});
4245
+ case "notas-fiscais":
4246
+ return /* @__PURE__ */ jsx(NotasFiscaisView, {});
4078
4247
  default:
4079
4248
  return /* @__PURE__ */ jsx(SummaryView, {});
4080
4249
  }
@@ -4297,7 +4466,7 @@ function BalanceHero() {
4297
4466
  const summary = useFinancialStore((s) => s.summary);
4298
4467
  const navigate = useDashboardNavigate();
4299
4468
  useEnsureSummary();
4300
- const [hidden, setHidden] = React17__default.useState(false);
4469
+ const [hidden, setHidden] = React18__default.useState(false);
4301
4470
  const money = (v) => hidden ? "\u2022\u2022\u2022\u2022\u2022\u2022" : formatCurrency(v ?? 0, currency);
4302
4471
  const inflow = summary?.monthlyInflow ?? 0;
4303
4472
  const outflow = summary?.monthlyOutflow ?? 0;
@@ -4370,7 +4539,7 @@ function categorizeSpend(notes) {
4370
4539
  function SpendByCategoryChart() {
4371
4540
  const t2 = useTranslation();
4372
4541
  const provider = useFinancialProvider();
4373
- const [rows, setRows] = React17__default.useState([]);
4542
+ const [rows, setRows] = React18__default.useState([]);
4374
4543
  useEffect(() => {
4375
4544
  let alive = true;
4376
4545
  void (async () => {
@@ -4413,7 +4582,7 @@ function UpcomingBills() {
4413
4582
  const { currency } = useFinancialConfig();
4414
4583
  const provider = useFinancialProvider();
4415
4584
  const dueLabel = useDueLabel();
4416
- const [bills, setBills] = React17__default.useState([]);
4585
+ const [bills, setBills] = React18__default.useState([]);
4417
4586
  useEffect(() => {
4418
4587
  let alive = true;
4419
4588
  void (async () => {
@@ -4588,7 +4757,8 @@ function createStore(options) {
4588
4757
  paymentMethodTypes: defaultPMTypes,
4589
4758
  chartOfAccounts: [],
4590
4759
  costCenters: [],
4591
- cardTransactions: []
4760
+ cardTransactions: [],
4761
+ notas: []
4592
4762
  };
4593
4763
  }
4594
4764
  function createMockFinancialProvider(options) {
@@ -5137,6 +5307,66 @@ function createMockFinancialProvider(options) {
5137
5307
  internal.updatedAt = now();
5138
5308
  }
5139
5309
  }
5310
+ },
5311
+ // --- Notas fiscais (NF-e / NFC-e / NFS-e) ---
5312
+ async getNotas(query) {
5313
+ let list = [...store.notas].sort((a, b) => b.createdAt.localeCompare(a.createdAt));
5314
+ if (query.status) list = list.filter((n) => matchesStatus(n.status, query.status));
5315
+ if (query.model) list = list.filter((n) => n.model === query.model);
5316
+ if (query.orderId) list = list.filter((n) => n.orderId === query.orderId);
5317
+ if (query.search) {
5318
+ const q = query.search.toLowerCase();
5319
+ list = list.filter((n) => (n.number ?? "").toLowerCase().includes(q) || (n.contactName ?? "").toLowerCase().includes(q));
5320
+ }
5321
+ return paginate(list, query.page, query.pageSize);
5322
+ },
5323
+ async getNotaById(id) {
5324
+ return store.notas.find((n) => n.id === id) ?? null;
5325
+ },
5326
+ async createNota(input) {
5327
+ const nota = {
5328
+ id: uid(),
5329
+ tenantId: "mock-tenant",
5330
+ model: input.model ?? "nfe",
5331
+ status: "draft",
5332
+ number: null,
5333
+ series: input.series ?? null,
5334
+ orderId: input.orderId,
5335
+ contactId: input.contactId,
5336
+ contactName: input.contactName,
5337
+ totalAmount: input.totalAmount,
5338
+ observations: input.observations,
5339
+ createdAt: now(),
5340
+ updatedAt: now()
5341
+ };
5342
+ store.notas.unshift(nota);
5343
+ return nota;
5344
+ },
5345
+ async updateNota(id, patch) {
5346
+ const nota = store.notas.find((n) => n.id === id);
5347
+ if (!nota) throw new Error("Nota fiscal not found");
5348
+ Object.assign(nota, patch, { updatedAt: now() });
5349
+ return nota;
5350
+ },
5351
+ async issueNota(id) {
5352
+ const nota = store.notas.find((n) => n.id === id);
5353
+ if (!nota) throw new Error("Nota fiscal not found");
5354
+ const issuedCount = store.notas.filter((n) => n.status === "issued").length;
5355
+ nota.status = "issued";
5356
+ nota.number = String(issuedCount + 1).padStart(6, "0");
5357
+ nota.series = nota.series ?? "1";
5358
+ nota.issuedAt = now();
5359
+ nota.emissor = "manual";
5360
+ nota.updatedAt = now();
5361
+ return nota;
5362
+ },
5363
+ async cancelNota(id, reason) {
5364
+ const nota = store.notas.find((n) => n.id === id);
5365
+ if (!nota) throw new Error("Nota fiscal not found");
5366
+ nota.status = "cancelled";
5367
+ nota.errorMessage = reason;
5368
+ nota.updatedAt = now();
5369
+ return nota;
5140
5370
  }
5141
5371
  };
5142
5372
  return provider;
@@ -5151,7 +5381,8 @@ var T = {
5151
5381
  costCenters: "plg_financial_cost_centers",
5152
5382
  cashRegisterSessions: "plg_financial_cash_register_sessions",
5153
5383
  paymentMethods: "plg_financial_payment_methods",
5154
- paymentMethodTypes: "plg_financial_payment_method_types"
5384
+ paymentMethodTypes: "plg_financial_payment_method_types",
5385
+ notas: "plg_financial_nfe"
5155
5386
  };
5156
5387
 
5157
5388
  // src/data/supabase.ts
@@ -5462,6 +5693,7 @@ function createSupabaseFinancialProvider() {
5462
5693
  }
5463
5694
  if (query.bankAccountId) qb = qb.eq("bank_account_id", query.bankAccountId);
5464
5695
  if (query.cashSessionId) qb = qb.eq("cash_session_id", query.cashSessionId);
5696
+ if (query.invoiceId) qb = qb.eq("invoice_id", query.invoiceId);
5465
5697
  if (query.dateRange) qb = qb.gte("due_date", query.dateRange.from).lte("due_date", query.dateRange.to);
5466
5698
  const page = query.page ?? 1;
5467
5699
  const pageSize = query.pageSize ?? 50;
@@ -5885,6 +6117,75 @@ function createSupabaseFinancialProvider() {
5885
6117
  if (line?.matched_movement_id) {
5886
6118
  await pub.from(T.movements).update({ reconciled_at: null }).eq("id", line.matched_movement_id);
5887
6119
  }
6120
+ },
6121
+ // --- Notas fiscais (NF-e / NFC-e / NFS-e) ---
6122
+ async getNotas(query) {
6123
+ const { pub } = getClients();
6124
+ let qb = pub.from(T.notas).select("*", { count: "exact" });
6125
+ if (query.status) {
6126
+ const statuses = Array.isArray(query.status) ? query.status : [query.status];
6127
+ qb = qb.in("status", statuses);
6128
+ }
6129
+ if (query.model) qb = qb.eq("model", query.model);
6130
+ if (query.orderId) qb = qb.eq("order_id", query.orderId);
6131
+ if (query.search) qb = qb.or(`number.ilike.%${query.search}%,contact_name.ilike.%${query.search}%`);
6132
+ const page = query.page ?? 1;
6133
+ const pageSize = query.pageSize ?? 50;
6134
+ qb = qb.range((page - 1) * pageSize, page * pageSize - 1).order("created_at", { ascending: false });
6135
+ const { data, count } = await qb;
6136
+ return { data: (data ?? []).map((r) => snakeToCamel(r)), total: count ?? 0 };
6137
+ },
6138
+ async getNotaById(id) {
6139
+ const { pub } = getClients();
6140
+ const { data } = await pub.from(T.notas).select("*").eq("id", id).maybeSingle();
6141
+ return data ? snakeToCamel(data) : null;
6142
+ },
6143
+ async createNota(input) {
6144
+ const { pub } = getClients();
6145
+ const row = {
6146
+ tenant_id: getTenantId(),
6147
+ model: input.model ?? "nfe",
6148
+ status: "draft",
6149
+ series: input.series ?? null,
6150
+ order_id: input.orderId ?? null,
6151
+ contact_id: input.contactId ?? null,
6152
+ contact_name: input.contactName ?? null,
6153
+ total_amount: input.totalAmount,
6154
+ observations: input.observations ?? null
6155
+ };
6156
+ const { data, error } = await pub.from(T.notas).insert(row).select().single();
6157
+ if (error) throw error;
6158
+ return snakeToCamel(data);
6159
+ },
6160
+ async updateNota(id, patch) {
6161
+ const { pub } = getClients();
6162
+ const { data, error } = await pub.from(T.notas).update(camelToSnake(patch)).eq("id", id).select().single();
6163
+ if (error) throw error;
6164
+ return snakeToCamel(data);
6165
+ },
6166
+ // Emission seam: no SEFAZ integration yet, so assign a número/série locally
6167
+ // and mark it issued. An external emissor replaces this body (or overrides
6168
+ // issueNota on a wrapping provider) without any UI change.
6169
+ async issueNota(id) {
6170
+ const { pub } = getClients();
6171
+ const { data: current } = await pub.from(T.notas).select("series").eq("id", id).single();
6172
+ const { count } = await pub.from(T.notas).select("id", { count: "exact", head: true }).eq("status", "issued");
6173
+ const patch = {
6174
+ status: "issued",
6175
+ number: String((count ?? 0) + 1).padStart(6, "0"),
6176
+ series: current?.series ?? "1",
6177
+ issued_at: (/* @__PURE__ */ new Date()).toISOString(),
6178
+ emissor: "manual"
6179
+ };
6180
+ const { data, error } = await pub.from(T.notas).update(patch).eq("id", id).select().single();
6181
+ if (error) throw error;
6182
+ return snakeToCamel(data);
6183
+ },
6184
+ async cancelNota(id, reason) {
6185
+ const { pub } = getClients();
6186
+ const { data, error } = await pub.from(T.notas).update({ status: "cancelled", error_message: reason ?? null }).eq("id", id).select().single();
6187
+ if (error) throw error;
6188
+ return snakeToCamel(data);
5888
6189
  }
5889
6190
  };
5890
6191
  return provider;
@@ -6512,6 +6813,7 @@ var en = {
6512
6813
  "financial.nav.payables": "Accounts Payable",
6513
6814
  "financial.nav.receivables": "Accounts Receivable",
6514
6815
  "financial.nav.reconciliation": "Reconciliation",
6816
+ "financial.nav.notasFiscais": "Fiscal Invoices",
6515
6817
  "financial.nav.recurringExpenses": "Recurring Expenses",
6516
6818
  "financial.nav.rules": "Rules",
6517
6819
  "financial.nav.statements": "Statements",
@@ -7005,6 +7307,7 @@ var ptBR = {
7005
7307
  "financial.nav.payables": "Contas a Pagar",
7006
7308
  "financial.nav.receivables": "Contas a Receber",
7007
7309
  "financial.nav.reconciliation": "Concilia\xE7\xE3o",
7310
+ "financial.nav.notasFiscais": "Notas Fiscais",
7008
7311
  "financial.nav.recurringExpenses": "Despesas Recorrentes",
7009
7312
  "financial.nav.rules": "Regras",
7010
7313
  "financial.nav.statements": "Extratos",
@@ -7489,7 +7792,8 @@ var DEFAULT_LABELS = {
7489
7792
  commissionsRules: "Rules",
7490
7793
  cards: "Cards",
7491
7794
  cardsOverview: "Overview",
7492
- cardsReconciliation: "Reconciliation"
7795
+ cardsReconciliation: "Reconciliation",
7796
+ notasFiscais: "Fiscal Invoices"
7493
7797
  };
7494
7798
  var DEFAULT_CURRENCY = { code: "BRL", locale: "pt-BR", symbol: "R$" };
7495
7799
  var FINANCIAL_NAV_FEATURES = {
@@ -7516,7 +7820,9 @@ function resolveConfig(options) {
7516
7820
  commissions: options?.modules?.commissions !== false,
7517
7821
  cards: options?.modules?.cards !== false,
7518
7822
  // Opt-in: only shown when an app explicitly enables reconciliation (bank connector present).
7519
- reconciliation: options?.modules?.reconciliation === true
7823
+ reconciliation: options?.modules?.reconciliation === true,
7824
+ // Opt-in: only shown when an app explicitly enables fiscal-invoice tracking.
7825
+ notasFiscais: options?.modules?.notasFiscais === true
7520
7826
  },
7521
7827
  // Opt-in: only render the plugin's own quick-add buttons/FAB when the host asks.
7522
7828
  quickAdd: options?.quickAdd === true,
@@ -7542,9 +7848,9 @@ function createFinancialPlugin(options) {
7542
7848
  const store = createFinancialStore(provider);
7543
7849
  const dashboardWidgets = createFinancialDashboardWidgets({ config, provider, store });
7544
7850
  const registries = [...financialRegistries, ...options?.settingsRegistries ?? []];
7545
- const PersonStatementBound = (props) => React17__default.createElement(PersonStatementWidget, { person: props.item, provider, config });
7851
+ const PersonStatementBound = (props) => React18__default.createElement(PersonStatementWidget, { person: props.item, provider, config });
7546
7852
  PersonStatementBound.displayName = "FinancialPersonStatement";
7547
- const PageComponent = () => React17__default.createElement(FinancialPage, { config, provider, store, registries });
7853
+ const PageComponent = () => React18__default.createElement(FinancialPage, { config, provider, store, registries });
7548
7854
  return {
7549
7855
  id: "financial",
7550
7856
  name: config.labels.pageTitle,
@@ -7748,10 +8054,10 @@ function createFinancialPlugin(options) {
7748
8054
  label: "Financial",
7749
8055
  icon: "DollarSign",
7750
8056
  component: (() => {
7751
- const FinancialSettingsTab = () => React17__default.createElement(PluginSettingsPanel, {
8057
+ const FinancialSettingsTab = () => React18__default.createElement(PluginSettingsPanel, {
7752
8058
  title: "Financial Settings",
7753
8059
  subtitle: "Payment methods, accounts, and configurations",
7754
- generalSettings: React17__default.createElement(FinancialGeneralSettings),
8060
+ generalSettings: React18__default.createElement(FinancialGeneralSettings),
7755
8061
  registries,
7756
8062
  hostPluginId: "financial",
7757
8063
  routeBase: "/settings/financial"