@fayz-ai/plugin-financial 0.20.0 → 0.21.1

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.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import * as React25 from 'react';
2
2
  import React25__default, { useState, useEffect, useMemo, useRef, useCallback } from 'react';
3
3
  import { recordRailFields, RECORD_GROUP, activeFacet, createConnectionStore, connectionSettings, connectionStatus, settingsStatus, connectionRuns, registerTranslations, getSupabaseClientOptional, createSafeDataProvider, registerMessageDefaults, reportDataError, useTranslation, createPendingCommand, useUnitMode, useDataChanged, countByTenant, tl, resolveDataProvider, useActiveUnitId, getActiveTenantId, emitDataChanged, exportCSV } from '@fayz-ai/core';
4
- import { INLINE_LINK_TONE, SearchSelect, ModalTask, toast, Button, useInModalTaskHost, useSaveBar, tourAnchor, DatePicker, SubpageHeader, defineKpiWidget, defineChartWidget, defineCustomWidget, defineTableWidget, Modal, ModalContent, ModalHeader, ModalTitle, ModalDescription, ModalBody, DataTable, Card, CardContent, Skeleton, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, MultiSelect, PageTransition, ModulePage, Badge, TooltipProvider, ConfirmDialog, CurrencyInput, Input, PageHeaderActions, ChoiceSelect, Hint, ModalFooter, PageTabs, Tooltip, TooltipTrigger, TooltipContent, Checkbox, Popover, PopoverTrigger, PopoverContent, DashboardCanvas, ComingSoon, StatTiles, ListView, DateRangeControl, FilterPanel, FilterPanelField, SegmentedControl, RequiredFilter, FilterMenuRow, ChoiceList, ModalFlow, Switch, WizardSteps, KpiCard, ChartWidget, CardHeader, CardTitle, TableWidget, useDashboardNavigate, GoldCard } from '@fayz-ai/ui';
4
+ import { INLINE_LINK_TONE, SearchSelect, ModalTask, toast, Button, useInModalTaskHost, useSaveBar, tourAnchor, DatePicker, SubpageHeader, defineKpiWidget, defineChartWidget, defineCustomWidget, defineTableWidget, Modal, ModalContent, ModalHeader, ModalTitle, ModalDescription, ModalBody, DataTable, Card, CardContent, Skeleton, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, MultiSelect, PageTransition, ModulePage, Badge, TooltipProvider, ConfirmDialog, CurrencyInput, Input, PageHeaderActions, ChoiceSelect, ModalFooter, Hint, PageTabs, Tooltip, TooltipTrigger, TooltipContent, Checkbox, Popover, PopoverTrigger, PopoverContent, openPrintWindow, printDocument, DashboardCanvas, ComingSoon, StatTiles, ListView, DateRangeControl, FilterPanel, FilterPanelField, SegmentedControl, RequiredFilter, FilterMenuRow, ChoiceList, ModalFlow, Switch, WizardSteps, KpiCard, ChartWidget, CardHeader, CardTitle, TableWidget, useDashboardNavigate, GoldCard } from '@fayz-ai/ui';
5
5
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
6
- import { createPluginContext, fayzConnectorOAuth, formatCurrency, RightRailPage, createCrudPage, PluginSettingsPanel, dedup, useUnitFilter, useLimitGuard, usePermissionOptional, useLookupCreate, OrderFormSkeleton, OrderFormBlock, OrderFormView, OrderFormItemsCard, OrderFormItemRow, adminNavigateTo, OrderFormAddItemStep, useUnitStore, OrderDetailSkeleton, PageActions, OrderDetailBlock, OrderDetailView, PersonLink, useTenantPluginSettings, useModuleNavigation, usePluginOnboardingGate, useModuleNavAccess, PluginOnboardingGateSkeleton, ModuleActionBar, SettingsGroup, ToggleRow, createArchetypeLookup, invalidateLimit, useAgentSurface, parseViewId, EntitlementGate, UpgradePrompt, useChatStore, revealPage, useAuth, GetStarted, resolveEntityRoute, PermissionGate, createOneShotAsk, askAI, requestChatUpload, toInlineFile, shrinkForVision } from '@fayz-ai/admin';
6
+ import { createPluginContext, fayzConnectorOAuth, formatCurrency, RightRailPage, createCrudPage, PluginSettingsPanel, dedup, useUnitFilter, useLimitGuard, usePermissionOptional, useLookupCreate, OrderFormSkeleton, WidgetSlot, OrderFormBlock, OrderFormView, OrderFormItemsCard, OrderFormItemRow, adminNavigateTo, OrderFormAddItemStep, useUnitStore, OrderDetailSkeleton, PageActions, OrderDetailBlock, OrderDetailView, PersonLink, useTenantPluginSettings, useModuleNavigation, usePluginOnboardingGate, useModuleNavAccess, PluginOnboardingGateSkeleton, ModuleActionBar, SettingsGroup, ToggleRow, createArchetypeLookup, invalidateLimit, useAgentSurface, parseViewId, EntitlementGate, UpgradePrompt, useChatStore, revealPage, useAuth, GetStarted, resolveEntityRoute, PermissionGate, createOneShotAsk, askAI, requestChatUpload, toInlineFile, shrinkForVision } from '@fayz-ai/admin';
7
7
  import { Landmark, CircleDollarSign, FileText, TriangleAlert, Loader2, Check, X, MoreVertical, Ban, CircleDashed, CircleAlert, CircleCheckBig, CircleEllipsis, Pencil, Receipt, Gift, Briefcase, Package, CalendarDays, ExternalLink, DollarSign, LayoutList, Layers, Paperclip, Ticket, FileCheck, ArrowRightLeft, CreditCard, QrCode, Banknote, Undo2, Wallet, Plus, AlertTriangle, Filter, TrendingUp, Copy, Trash2, Search, ChevronsUpDown, ChevronsDownUp, ChevronRight, Building2, Image, UploadCloud, Calendar, User, Unlink, ChevronDown, Eye, Inbox, Clock, ClipboardCheck, BookOpen, Info, FolderOpen, Folder, RotateCcw, Settings, ArrowLeft, ChevronLeft, Calculator, Square, Play, ChevronUp, Printer, CalendarClock, BadgeCheck, Target, ArrowRight, Users, RefreshCw, Download, Camera, Sparkles, Link2, FileSearch, CheckCheck, Pause, ShoppingCart, Car, Home, Utensils, Zap, Film, HeartPulse, Dumbbell, Music, ShoppingBag, FileDown, ArrowUpRight, ArrowDownRight, EyeOff } from 'lucide-react';
8
8
  import { createPortal } from 'react-dom';
9
9
  import { createStore as createStore$1 } from 'zustand/vanilla';
@@ -1874,6 +1874,7 @@ function InvoiceAttachmentsModal({ invoiceId, onClose, onChanged }) {
1874
1874
  const [uploading, setUploading] = useState(0);
1875
1875
  const [over, setOver] = useState(false);
1876
1876
  const [preview, setPreview] = useState(null);
1877
+ const [added, setAdded] = useState(0);
1877
1878
  async function load() {
1878
1879
  try {
1879
1880
  setItems(await (provider.getInvoiceAttachments?.(invoiceId) ?? Promise.resolve([])));
@@ -1896,6 +1897,7 @@ function InvoiceAttachmentsModal({ invoiceId, onClose, onChanged }) {
1896
1897
  for (const file of ok) {
1897
1898
  try {
1898
1899
  await provider.addInvoiceAttachment(invoiceId, file);
1900
+ setAdded((n) => n + 1);
1899
1901
  } catch (e) {
1900
1902
  toast.error(`${file.name}: ${e?.message ?? String(e)}`);
1901
1903
  } finally {
@@ -1988,7 +1990,8 @@ function InvoiceAttachmentsModal({ invoiceId, onClose, onChanged }) {
1988
1990
  }
1989
1991
  }
1990
1992
  )
1991
- ] })
1993
+ ] }),
1994
+ /* @__PURE__ */ jsx(ModalFooter, { children: /* @__PURE__ */ jsx(Button, { onClick: onClose, disabled: uploading > 0, variant: added > 0 ? "default" : "outline", children: uploading > 0 ? "Enviando\u2026" : added > 0 ? "Concluir" : "Fechar" }) })
1992
1995
  ] }) }) });
1993
1996
  }
1994
1997
  function AttachmentPreview({ items, index, onIndex, onBack }) {
@@ -2489,14 +2492,17 @@ function InvoiceListView({ direction, onNew, onNewReceipt, onEdit }) {
2489
2492
  const printSelected = useCallback((rows) => {
2490
2493
  const safe = (value) => String(value ?? "").replace(/[&<>"']/g, (character) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[character] ?? character);
2491
2494
  const body = rows.map((row) => `<tr><td>${safe(row.dueDate)}</td><td>${safe(row.contactName)}<small>${safe(row.itemsSummary)}</small></td><td>${safe(formatCurrency(row.totalAmount, currency))}</td><td>${row.installmentNumber ?? 1}/${row.totalInstallments ?? 1}</td></tr>`).join("");
2492
- const popup = window.open("", "_blank");
2495
+ const title = direction === "debit" ? "Contas a pagar" : "Contas a receber";
2496
+ const popup = printDocument({
2497
+ title,
2498
+ css: "body{font:12px sans-serif}table{width:100%;border-collapse:collapse}th,td{border-bottom:1px solid #ddd;padding:8px;text-align:left}small{display:block;color:#666;margin-top:2px}",
2499
+ body: `<h1>${title}</h1><table><thead><tr><th>Vencimento</th><th>Descri\xE7\xE3o / itens</th><th>Valor</th><th>Parcela</th></tr></thead><tbody>${body}</tbody></table>`
2500
+ });
2493
2501
  if (!popup) {
2494
2502
  toast.error(t2("financial.invoice.printBlocked"));
2495
2503
  return;
2496
2504
  }
2497
2505
  popup.opener = null;
2498
- popup.document.write(`<html><head><title>${direction === "debit" ? "Contas a pagar" : "Contas a receber"}</title><style>body{font:12px sans-serif;padding:24px}table{width:100%;border-collapse:collapse}th,td{border-bottom:1px solid #ddd;padding:8px;text-align:left}small{display:block;color:#666;margin-top:2px}</style></head><body><h1>${direction === "debit" ? "Contas a pagar" : "Contas a receber"}</h1><table><thead><tr><th>Vencimento</th><th>Descri\xE7\xE3o / itens</th><th>Valor</th><th>Parcela</th></tr></thead><tbody>${body}</tbody></table><script>window.print();window.close()</script></body></html>`);
2499
- popup.document.close();
2500
2506
  }, [currency, direction, t2]);
2501
2507
  const bulkActions = useMemo(() => {
2502
2508
  const actions = [
@@ -2885,6 +2891,9 @@ function InvoiceListView({ direction, onNew, onNewReceipt, onEdit }) {
2885
2891
  var ACCOUNTS_ROUTE = "/registry/accounts";
2886
2892
  var CHART_OF_ACCOUNTS_ROUTE = "/settings/financial/chart-of-accounts";
2887
2893
  var COST_CENTERS_ROUTE = "/settings/financial/cost-centers";
2894
+ var FINANCIAL_INVOICE_ZONES = {
2895
+ headerActions: "financial.invoice.header.actions"
2896
+ };
2888
2897
  function useWritableUnits(fallback = []) {
2889
2898
  const unitMode = useUnitMode();
2890
2899
  const activeUnitId = useActiveUnitId() ?? void 0;
@@ -4055,7 +4064,7 @@ function createFinancialAgentMount(deps) {
4055
4064
  FinancialAgentMount.displayName = "FinancialAgentMount";
4056
4065
  return FinancialAgentMount;
4057
4066
  }
4058
- function useReceiptPicker(onPick) {
4067
+ function useReceiptPicker(onPick, onPickDocument) {
4059
4068
  const t2 = useTranslation();
4060
4069
  const ref = useRef(null);
4061
4070
  const input = /* @__PURE__ */ jsx(
@@ -4063,13 +4072,17 @@ function useReceiptPicker(onPick) {
4063
4072
  {
4064
4073
  ref,
4065
4074
  type: "file",
4066
- accept: "image/*",
4067
- capture: "environment",
4075
+ accept: onPickDocument ? "image/*,application/pdf" : "image/*",
4076
+ capture: onPickDocument ? void 0 : "environment",
4068
4077
  className: "hidden",
4069
4078
  onChange: (e) => {
4070
4079
  const file = e.target.files?.[0];
4071
4080
  e.target.value = "";
4072
4081
  if (!file) return;
4082
+ if (onPickDocument && file.type === "application/pdf") {
4083
+ onPickDocument(file);
4084
+ return;
4085
+ }
4073
4086
  if (!file.type.startsWith("image/")) {
4074
4087
  toast.error(t2("financial.quickTx.receiptInvalid"));
4075
4088
  return;
@@ -4899,7 +4912,8 @@ function InstallmentRow({
4899
4912
  ] })
4900
4913
  ] }),
4901
4914
  /* @__PURE__ */ jsx("div", { className: "w-44 shrink-0", onClick: stop, children: source }),
4902
- (actions || onClick) && /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-1.5", onClick: stop, children: [
4915
+ (actions || onClick) && // Min width fits attach + "Pagar": rows where Pay is absent (unsaved, paid) keep the source column aligned.
4916
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-32 shrink-0 items-center justify-end gap-1.5", onClick: stop, children: [
4903
4917
  actions,
4904
4918
  onClick && /* @__PURE__ */ jsx(ChevronRight, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground", "aria-hidden": true })
4905
4919
  ] })
@@ -4938,10 +4952,10 @@ function InstallmentReceiptButton({ onClick, title, attached, pending: pending2,
4938
4952
  onClick,
4939
4953
  title,
4940
4954
  "aria-label": title,
4941
- className: `inline-flex shrink-0 items-center gap-1 rounded-lg border bg-card px-2.5 py-1.5 text-xs font-medium shadow-button transition-colors hover:bg-muted active:shadow-button-inset ${attached ? "text-success" : pending2 ? "text-primary" : ""}`,
4955
+ className: `relative inline-flex shrink-0 items-center gap-1 rounded-lg border bg-card px-2.5 py-1.5 text-xs font-medium shadow-button transition-colors hover:bg-muted active:shadow-button-inset ${attached ? "text-success" : pending2 ? "text-primary" : ""}`,
4942
4956
  children: [
4943
4957
  /* @__PURE__ */ jsx(Paperclip, { className: "h-3 w-3" }),
4944
- !!count && /* @__PURE__ */ jsx("span", { className: "tabular-nums", children: count })
4958
+ !!count && /* @__PURE__ */ jsx("span", { className: "absolute -right-1.5 -top-1.5 flex h-4 min-w-4 items-center justify-center rounded-full bg-primary px-1 text-[10px] font-semibold leading-none text-primary-foreground tabular-nums", children: count })
4945
4959
  ]
4946
4960
  }
4947
4961
  );
@@ -5110,18 +5124,18 @@ function InvoiceFormView({ direction, editId, onSaved, focusReceipt = false, fro
5110
5124
  const showUnitField = unitMode ? reachableUnits.length > 1 : unitChoices.length > 1;
5111
5125
  const [giftCardsEnabled, setGiftCardsEnabled] = useState(false);
5112
5126
  useEffect(() => {
5113
- let cancelled = false;
5127
+ let cancelled2 = false;
5114
5128
  if (direction !== "credit" || !provider.giftCardsEnabled) {
5115
5129
  setGiftCardsEnabled(false);
5116
5130
  return;
5117
5131
  }
5118
5132
  void provider.giftCardsEnabled().then((enabled) => {
5119
- if (!cancelled) setGiftCardsEnabled(enabled);
5133
+ if (!cancelled2) setGiftCardsEnabled(enabled);
5120
5134
  }).catch(() => {
5121
- if (!cancelled) setGiftCardsEnabled(false);
5135
+ if (!cancelled2) setGiftCardsEnabled(false);
5122
5136
  });
5123
5137
  return () => {
5124
- cancelled = true;
5138
+ cancelled2 = true;
5125
5139
  };
5126
5140
  }, [direction, provider]);
5127
5141
  const giftCardLookup = useMemo(() => {
@@ -5193,20 +5207,29 @@ function InvoiceFormView({ direction, editId, onSaved, focusReceipt = false, fro
5193
5207
  const canManageFinancial = can("financial", "manage");
5194
5208
  const isEdit = !!editId;
5195
5209
  const [attachmentsOpen, setAttachmentsOpen] = useState(false);
5210
+ const [attachmentCount, setAttachmentCount] = useState(0);
5211
+ const loadAttachmentCount = React25__default.useCallback(() => {
5212
+ if (!editId || !provider.getInvoiceAttachments) return;
5213
+ provider.getInvoiceAttachments(editId).then((list) => setAttachmentCount(list.length)).catch(() => {
5214
+ });
5215
+ }, [editId, provider]);
5216
+ useEffect(() => {
5217
+ loadAttachmentCount();
5218
+ }, [loadAttachmentCount]);
5196
5219
  useEffect(() => {
5197
5220
  void fetchBankAccounts();
5198
5221
  void fetchPaymentMethods();
5199
5222
  }, []);
5200
5223
  useEffect(() => {
5201
- let cancelled = false;
5224
+ let cancelled2 = false;
5202
5225
  void Promise.all([provider.getChartOfAccounts(), provider.getCostCenters()]).then(([accountRows, costCenterRows]) => {
5203
- if (cancelled) return;
5226
+ if (cancelled2) return;
5204
5227
  setAccounts(accountRows);
5205
5228
  setCostCenters(costCenterRows);
5206
5229
  }).catch(() => {
5207
5230
  });
5208
5231
  return () => {
5209
- cancelled = true;
5232
+ cancelled2 = true;
5210
5233
  };
5211
5234
  }, [provider]);
5212
5235
  const contactLookup = useMemo(
@@ -5252,6 +5275,8 @@ function InvoiceFormView({ direction, editId, onSaved, focusReceipt = false, fro
5252
5275
  const [expandedItemId, setExpandedItemId] = useState(null);
5253
5276
  const [addingItem, setAddingItem] = useState(false);
5254
5277
  const [installments, setInstallments] = useState([]);
5278
+ const [cancelled, setCancelled] = useState(false);
5279
+ const [savedTotal, setSavedTotal] = useState(null);
5255
5280
  const [savedMovements, setSavedMovements] = useState([]);
5256
5281
  const [payingMovement, setPayingMovement] = useState(null);
5257
5282
  const [pendingReceipt, setPendingReceipt] = useState();
@@ -5262,6 +5287,7 @@ function InvoiceFormView({ direction, editId, onSaved, focusReceipt = false, fro
5262
5287
  });
5263
5288
  const [pendingContact, setPendingContact] = useState(null);
5264
5289
  const [receiptTarget, setReceiptTarget] = useState(null);
5290
+ const [pendingDocs, setPendingDocs] = useState([]);
5265
5291
  const receiptPicker = useReceiptPicker((dataUrl) => {
5266
5292
  const i = receiptTarget;
5267
5293
  setReceiptTarget(null);
@@ -5274,7 +5300,10 @@ function InvoiceFormView({ direction, editId, onSaved, focusReceipt = false, fro
5274
5300
  return;
5275
5301
  }
5276
5302
  setInstallments((prev) => prev.map((inst, idx) => idx === i ? { ...inst, receiptUrl: dataUrl } : inst));
5277
- });
5303
+ }, provider.addInvoiceAttachment ? (file) => {
5304
+ setReceiptTarget(null);
5305
+ setPendingDocs((prev) => [...prev, file]);
5306
+ } : void 0);
5278
5307
  const [saving, setSaving] = useState(false);
5279
5308
  const [menuOpen, setMenuOpen] = useState(false);
5280
5309
  const [confirmCancel, setConfirmCancel] = useState(false);
@@ -5333,6 +5362,8 @@ function InvoiceFormView({ direction, editId, onSaved, focusReceipt = false, fro
5333
5362
  setInvoiceDate(invoice.invoiceDate);
5334
5363
  setSavedInvoiceDate(invoice.invoiceDate);
5335
5364
  setSavedContactId(invoice.contactId);
5365
+ setCancelled(invoice.status === "cancelled");
5366
+ setSavedTotal(invoice.totalAmount);
5336
5367
  setFiscalNumber(String(invoice.metadata?.fiscalNumber ?? ""));
5337
5368
  setObservations(invoice.observations ?? "");
5338
5369
  const invoiceItems = await provider.getInvoiceItems(editId);
@@ -5380,7 +5411,7 @@ function InvoiceFormView({ direction, editId, onSaved, focusReceipt = false, fro
5380
5411
  return sum + it.quantity * it.unitPrice - (it.discount ?? 0) + (it.surcharge ?? 0);
5381
5412
  }, 0);
5382
5413
  const itemsDirty = isEdit && loaded && itemsKey(items) !== savedItemsKey;
5383
- const scheduleTotal = isEdit && savedMovements.length > 0 && !itemsDirty ? Math.round(savedMovements.reduce((sum, m) => sum + m.amount, 0) * 100) / 100 : totalAmount;
5414
+ const scheduleTotal = isEdit && savedMovements.length > 0 && !itemsDirty ? savedTotal ?? Math.round(savedMovements.reduce((sum, m) => sum + m.amount, 0) * 100) / 100 : totalAmount;
5384
5415
  const prevItemCount = useRef(items.length);
5385
5416
  useEffect(() => {
5386
5417
  if (items.length > 0 && prevItemCount.current === 0 && installments.length === 0 && !isEdit) {
@@ -5608,6 +5639,7 @@ function InvoiceFormView({ direction, editId, onSaved, focusReceipt = false, fro
5608
5639
  if (isEdit && editId) {
5609
5640
  if (canEditItems && provider.replaceInvoiceItems && itemsDirty) {
5610
5641
  await provider.replaceInvoiceItems(editId, items.map(({ _id, ...rest }) => rest));
5642
+ setSavedTotal(Math.round(totalAmount * 100) / 100);
5611
5643
  }
5612
5644
  await provider.updateInvoice(editId, {
5613
5645
  unitId: unitId || void 0,
@@ -5675,6 +5707,16 @@ function InvoiceFormView({ direction, editId, onSaved, focusReceipt = false, fro
5675
5707
  });
5676
5708
  }
5677
5709
  }
5710
+ if (pendingDocs.length > 0 && provider.addInvoiceAttachment) {
5711
+ const failed = [];
5712
+ for (const file of pendingDocs) {
5713
+ await provider.addInvoiceAttachment(invoice.id, file).catch(() => {
5714
+ failed.push(file.name);
5715
+ });
5716
+ }
5717
+ setPendingDocs([]);
5718
+ if (failed.length) toast.error(t2("financial.invoiceForm.attachFailed"), { description: failed.join(", ") });
5719
+ }
5678
5720
  createdId.current = invoice.id;
5679
5721
  if (!opts?.stay) onSaved?.(invoice.id);
5680
5722
  savedId = invoice.id;
@@ -5747,23 +5789,26 @@ function InvoiceFormView({ direction, editId, onSaved, focusReceipt = false, fro
5747
5789
  const subtitle = isEdit ? t2("financial.invoiceForm.editing") : t2("financial.invoiceForm.creating");
5748
5790
  if (loading) return /* @__PURE__ */ jsx(OrderFormSkeleton, { parentLabel: embedded ? void 0 : direction === "debit" ? t2("financial.nav.payables") : t2("financial.nav.receivables"), onBack: embedded ? void 0 : () => onSaved?.() });
5749
5791
  const money4 = (v) => formatCurrency(v, currency);
5750
- const actions = isEdit ? /* @__PURE__ */ jsxs("div", { className: "relative", ref: menuRef, children: [
5751
- /* @__PURE__ */ jsx(Button, { variant: "outline", size: "icon", onClick: () => setMenuOpen(!menuOpen), "aria-label": "More actions", children: /* @__PURE__ */ jsx(MoreVertical, { className: "h-4 w-4" }) }),
5752
- menuOpen && /* @__PURE__ */ jsx("div", { className: "fayz-glass-surface absolute right-0 top-full z-20 mt-1 w-44 rounded-lg border bg-popover py-1 shadow-md", style: { animation: "field-slide-in 150ms ease-out" }, children: /* @__PURE__ */ jsxs(
5753
- "button",
5754
- {
5755
- onClick: () => {
5756
- setConfirmCancel(true);
5757
- setMenuOpen(false);
5758
- },
5759
- className: "flex w-full items-center gap-2 px-3 py-2 text-xs text-destructive transition-colors hover:bg-destructive/10",
5760
- children: [
5761
- /* @__PURE__ */ jsx(Ban, { className: "h-3.5 w-3.5" }),
5762
- " ",
5763
- t2("financial.invoiceForm.cancelInvoice")
5764
- ]
5765
- }
5766
- ) })
5792
+ const actions = isEdit ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
5793
+ /* @__PURE__ */ jsx(WidgetSlot, { zone: FINANCIAL_INVOICE_ZONES.headerActions, invoiceId: editId, direction, cancelled }),
5794
+ /* @__PURE__ */ jsxs("div", { className: "relative", ref: menuRef, children: [
5795
+ /* @__PURE__ */ jsx(Button, { variant: "outline", size: "icon", onClick: () => setMenuOpen(!menuOpen), "aria-label": "More actions", children: /* @__PURE__ */ jsx(MoreVertical, { className: "h-4 w-4" }) }),
5796
+ menuOpen && /* @__PURE__ */ jsx("div", { className: "fayz-glass-surface absolute right-0 top-full z-20 mt-1 w-44 rounded-lg border bg-popover py-1 shadow-md", style: { animation: "field-slide-in 150ms ease-out" }, children: /* @__PURE__ */ jsxs(
5797
+ "button",
5798
+ {
5799
+ onClick: () => {
5800
+ setConfirmCancel(true);
5801
+ setMenuOpen(false);
5802
+ },
5803
+ className: "flex w-full items-center gap-2 px-3 py-2 text-xs text-destructive transition-colors hover:bg-destructive/10",
5804
+ children: [
5805
+ /* @__PURE__ */ jsx(Ban, { className: "h-3.5 w-3.5" }),
5806
+ " ",
5807
+ t2("financial.invoiceForm.cancelInvoice")
5808
+ ]
5809
+ }
5810
+ ) })
5811
+ ] })
5767
5812
  ] }) : null;
5768
5813
  const paidSoFar = savedMovements.reduce((sum, m) => sum + (m.paidAmount ?? 0), 0);
5769
5814
  const hasPayments = paidSoFar > 0;
@@ -5829,7 +5874,8 @@ function InvoiceFormView({ direction, editId, onSaved, focusReceipt = false, fro
5829
5874
  (canAttach || isEdit) && /* @__PURE__ */ jsx(
5830
5875
  InstallmentReceiptButton,
5831
5876
  {
5832
- attached: !!inst.receiptUrl,
5877
+ attached: !!inst.receiptUrl || isEdit && attachmentCount > 0,
5878
+ count: isEdit ? attachmentCount : void 0,
5833
5879
  pending: !inst.receiptUrl && !!pendingReceipt,
5834
5880
  title: !inst.receiptUrl && pendingReceipt ? t2("financial.receipt.attachRead") : t2("financial.quickTx.receiptCapture"),
5835
5881
  onClick: () => {
@@ -5883,7 +5929,25 @@ function InvoiceFormView({ direction, editId, onSaved, focusReceipt = false, fro
5883
5929
  )
5884
5930
  ] })
5885
5931
  ] }, inst._id);
5886
- }) })
5932
+ }) }),
5933
+ pendingDocs.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: pendingDocs.map((file, idx) => /* @__PURE__ */ jsxs("span", { className: "inline-flex max-w-full items-center gap-1.5 rounded-md border bg-muted/30 px-2 py-1 text-xs", children: [
5934
+ /* @__PURE__ */ jsx(FileText, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
5935
+ /* @__PURE__ */ jsx("span", { className: "truncate", children: file.name }),
5936
+ /* @__PURE__ */ jsxs("span", { className: "shrink-0 text-muted-foreground", children: [
5937
+ "\xB7 ",
5938
+ t2("financial.invoiceForm.attachOnSave")
5939
+ ] }),
5940
+ /* @__PURE__ */ jsx(
5941
+ "button",
5942
+ {
5943
+ type: "button",
5944
+ onClick: () => setPendingDocs((prev) => prev.filter((_, j) => j !== idx)),
5945
+ "aria-label": t2("financial.quickTx.receiptRemove"),
5946
+ className: "flex h-5 w-5 shrink-0 items-center justify-center rounded text-muted-foreground hover:bg-muted hover:text-foreground",
5947
+ children: /* @__PURE__ */ jsx(X, { className: "h-3 w-3" })
5948
+ }
5949
+ )
5950
+ ] }, `${file.name}-${idx}`)) })
5887
5951
  ] }) }) })
5888
5952
  );
5889
5953
  const contactSection = /* @__PURE__ */ jsx("div", { ...tourAnchor("financial.contact"), children: /* @__PURE__ */ jsxs(OrderFormBlock, { title: direction === "debit" ? t2("financial.invoiceForm.payTo") : t2("financial.invoiceForm.receiveFrom"), children: [
@@ -6178,7 +6242,7 @@ function InvoiceFormView({ direction, editId, onSaved, focusReceipt = false, fro
6178
6242
  }
6179
6243
  ),
6180
6244
  receiptPicker.input,
6181
- attachmentsOpen && editId && /* @__PURE__ */ jsx(InvoiceAttachmentsModal, { invoiceId: editId, onClose: () => setAttachmentsOpen(false) }),
6245
+ attachmentsOpen && editId && /* @__PURE__ */ jsx(InvoiceAttachmentsModal, { invoiceId: editId, onClose: () => setAttachmentsOpen(false), onChanged: loadAttachmentCount }),
6182
6246
  payingMovement && /* @__PURE__ */ jsx(
6183
6247
  PaymentModal,
6184
6248
  {
@@ -6646,11 +6710,8 @@ function InvoiceDetailView({ invoiceId, direction, onBack, onEdit, backLabel, em
6646
6710
  ...totalRemaining > 0 ? [{ label: t2("financial.invoice.balance"), value: formatCurrency(totalRemaining, currency) }] : []
6647
6711
  ];
6648
6712
  direction === "debit" ? t2("financial.invoice.accountsPayable") : t2("financial.invoice.accountsReceivable");
6649
- const actions = (
6650
- // Declared: the shell gives it a caret on desktop and the FAB on a phone.
6651
- // This was an outline button beside a hand-rolled popup — its own useRef
6652
- // outside-click listener and an inline `style={{animation}}` — sitting next
6653
- // to a Radix Dropdown that already exists.
6713
+ const actions = /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
6714
+ /* @__PURE__ */ jsx(WidgetSlot, { zone: FINANCIAL_INVOICE_ZONES.headerActions, invoiceId: invoice.id, direction, cancelled }),
6654
6715
  /* @__PURE__ */ jsx(
6655
6716
  PageActions,
6656
6717
  {
@@ -6660,7 +6721,7 @@ function InvoiceDetailView({ invoiceId, direction, onBack, onEdit, backLabel, em
6660
6721
  ] : []
6661
6722
  }
6662
6723
  )
6663
- );
6724
+ ] });
6664
6725
  const sideBlocks = /* @__PURE__ */ jsxs(Fragment, { children: [
6665
6726
  invoice.bookingStartsAt && /* @__PURE__ */ jsx(OrderDetailBlock, { title: t2("financial.invoice.booking"), children: /* @__PURE__ */ jsxs(
6666
6727
  "button",
@@ -7115,12 +7176,16 @@ function CashSessionReviewModal({ sessionId, open, onOpenChange, mode, onReviewe
7115
7176
  }
7116
7177
  function handlePrint() {
7117
7178
  if (!session) return;
7118
- const popup = window.open("", "_blank", "width=720,height=900");
7179
+ const popup = openPrintWindow("width=720,height=900");
7119
7180
  if (!popup) return;
7120
7181
  const title = session.bankAccountName ?? t2("financial.cash.title");
7121
7182
  const rows = (movements ?? []).map((m) => `<tr><td>${m.paymentDate ? new Date(m.paymentDate).toLocaleString() : "\u2014"}</td><td>${m.method ? t2(`financial.method.${m.method}`) : "\u2014"}</td><td style="text-align:right">${m.direction === "credit" ? "+" : "-"}${formatCurrency(m.paidAmount, currency)}</td></tr>`).join("");
7122
- popup.document.write(`<html><head><title>${title}</title><style>body{font:12px sans-serif;padding:24px}table{width:100%;border-collapse:collapse;margin-top:16px}th,td{border-bottom:1px solid #ddd;padding:8px;text-align:left}h1{font-size:16px;margin-bottom:8px}p{margin:2px 0}</style></head><body><h1>${title}</h1><p>${t2("financial.cash.opened")}: ${new Date(session.openedAt).toLocaleString()}${session.openedByName ? ` ${t2("financial.cash.by")} ${session.openedByName}` : ""}</p>` + (session.closedAt ? `<p>${t2("financial.cash.closeLabel")}: ${new Date(session.closedAt).toLocaleString()}${session.closedByName ? ` ${t2("financial.cash.by")} ${session.closedByName}` : ""}</p>` : "") + `<p>${t2("financial.cash.openingBalance")}: ${formatCurrency(session.openingBalance, currency)}</p><p>${t2("financial.cash.finalValue")}: ${formatCurrency(session.closingBalance ?? 0, currency)}</p><p>${t2("financial.cash.difference")}: ${(session.difference ?? 0) >= 0 ? "+" : ""}${formatCurrency(session.difference ?? 0, currency)}</p><table><thead><tr><th>${t2("financial.cash.opened")}</th><th>${t2("financial.cash.method")}</th><th style="text-align:right">${t2("financial.cash.finalValue")}</th></tr></thead><tbody>${rows}</tbody></table><script>window.print();window.close()</script></body></html>`);
7123
- popup.document.close();
7183
+ printDocument({
7184
+ title,
7185
+ css: "body{font:12px sans-serif}table{width:100%;border-collapse:collapse;margin-top:16px}th,td{border-bottom:1px solid #ddd;padding:8px;text-align:left}h1{font-size:16px;margin-bottom:8px}p{margin:2px 0}",
7186
+ body: `<h1>${title}</h1><p>${t2("financial.cash.opened")}: ${new Date(session.openedAt).toLocaleString()}${session.openedByName ? ` ${t2("financial.cash.by")} ${session.openedByName}` : ""}</p>` + (session.closedAt ? `<p>${t2("financial.cash.closeLabel")}: ${new Date(session.closedAt).toLocaleString()}${session.closedByName ? ` ${t2("financial.cash.by")} ${session.closedByName}` : ""}</p>` : "") + `<p>${t2("financial.cash.openingBalance")}: ${formatCurrency(session.openingBalance, currency)}</p><p>${t2("financial.cash.finalValue")}: ${formatCurrency(session.closingBalance ?? 0, currency)}</p><p>${t2("financial.cash.difference")}: ${(session.difference ?? 0) >= 0 ? "+" : ""}${formatCurrency(session.difference ?? 0, currency)}</p><table><thead><tr><th>${t2("financial.cash.opened")}</th><th>${t2("financial.cash.method")}</th><th style="text-align:right">${t2("financial.cash.finalValue")}</th></tr></thead><tbody>${rows}</tbody></table>`,
7187
+ target: popup
7188
+ });
7124
7189
  }
7125
7190
  return /* @__PURE__ */ jsx(Modal, { open, onOpenChange, children: /* @__PURE__ */ jsxs(ModalContent, { size: "lg", noPadding: true, className: "gap-0", children: [
7126
7191
  /* @__PURE__ */ jsxs(ModalHeader, { className: "border-b px-4 py-3", children: [
@@ -18470,6 +18535,8 @@ var en = {
18470
18535
  "financial.invoiceForm.scheduleSourceHint": "Method and account are set on each due date.",
18471
18536
  "financial.invoiceForm.paidNeedsMethod": "Tell us the payment method and the account",
18472
18537
  "financial.invoiceForm.willBePaid": "This installment will be settled",
18538
+ "financial.invoiceForm.attachFailed": "The bill was saved, but an attachment did not upload",
18539
+ "financial.invoiceForm.attachOnSave": "attached on save",
18473
18540
  "financial.invoiceForm.clear": "Clear",
18474
18541
  "financial.invoiceForm.manageAccounts": "Manage accounts",
18475
18542
  "financial.invoiceForm.manageChart": "Manage chart of accounts",
@@ -19238,11 +19305,11 @@ var en = {
19238
19305
  "financial.quickTx.attachment": "Attachment",
19239
19306
  "financial.quickTx.attachmentSoon": "Attachments coming soon",
19240
19307
  "financial.quickTx.receipt": "Receipt",
19241
- "financial.quickTx.receiptCapture": "Snap or attach a receipt",
19308
+ "financial.quickTx.receiptCapture": "Attach a receipt or bill (photo or PDF)",
19242
19309
  "financial.quickTx.receiptAttached": "Receipt attached",
19243
19310
  "financial.quickTx.receiptReplace": "Replace",
19244
19311
  "financial.quickTx.receiptRemove": "Remove receipt",
19245
- "financial.quickTx.receiptInvalid": "Please choose an image file",
19312
+ "financial.quickTx.receiptInvalid": "Please choose an image or PDF",
19246
19313
  "financial.quickTx.sendReceipt": "Send receipt",
19247
19314
  "financial.quickTx.digitizeExpense": "Digitize expense",
19248
19315
  "financial.quickTx.digitizeReceipt": "Digitize receipt",
@@ -19410,6 +19477,8 @@ var ptBR = {
19410
19477
  "financial.invoiceForm.scheduleSourceHint": "Forma e conta ficam configur\xE1veis em cada vencimento.",
19411
19478
  "financial.invoiceForm.paidNeedsMethod": "Diga a forma de pagamento e a conta",
19412
19479
  "financial.invoiceForm.willBePaid": "Esta parcela entra como paga",
19480
+ "financial.invoiceForm.attachFailed": "A conta foi salva, mas um anexo n\xE3o subiu",
19481
+ "financial.invoiceForm.attachOnSave": "anexa ao salvar",
19413
19482
  "financial.invoiceForm.clear": "Limpar",
19414
19483
  "financial.invoiceForm.manageAccounts": "Gerenciar contas",
19415
19484
  "financial.invoiceForm.manageChart": "Gerenciar plano de contas",
@@ -20181,11 +20250,11 @@ var ptBR = {
20181
20250
  "financial.quickTx.attachment": "Anexo",
20182
20251
  "financial.quickTx.attachmentSoon": "Anexos em breve",
20183
20252
  "financial.quickTx.receipt": "Recibo",
20184
- "financial.quickTx.receiptCapture": "Fotografar ou anexar recibo",
20253
+ "financial.quickTx.receiptCapture": "Anexar comprovante ou boleto (foto ou PDF)",
20185
20254
  "financial.quickTx.receiptAttached": "Recibo anexado",
20186
20255
  "financial.quickTx.receiptReplace": "Substituir",
20187
20256
  "financial.quickTx.receiptRemove": "Remover recibo",
20188
- "financial.quickTx.receiptInvalid": "Escolha um arquivo de imagem",
20257
+ "financial.quickTx.receiptInvalid": "Escolha uma imagem ou PDF",
20189
20258
  "financial.quickTx.sendReceipt": "Enviar recibo",
20190
20259
  "financial.quickTx.digitizeExpense": "Digitalizar despesa",
20191
20260
  "financial.quickTx.digitizeReceipt": "Digitalizar comprovante",
@@ -45131,6 +45200,133 @@ REVOKE ALL ON FUNCTION public.financial_gift_card_by_code(text) FROM anon;
45131
45200
  GRANT EXECUTE ON FUNCTION public.financial_gift_card_by_code(text) TO authenticated;
45132
45201
  GRANT EXECUTE ON FUNCTION public.financial_gift_card_by_code(text) TO service_role;
45133
45202
  `;
45203
+ var MIGRATION_119_AN_UNPAID_LEGACY_BILL_CAN_BE_RESCHEDULED = `-- An unpaid bill migrated from V1 could not be rescheduled.
45204
+ --
45205
+ -- Editing the lines of such a bill saved the new lines and total, then
45206
+ -- \`financial_reschedule_invoice\` refused with "carries legacy bill movements":
45207
+ -- the installment kept the old amount and every later save failed the same way.
45208
+ --
45209
+ -- The \`bill\` mirror in plg_financial_movements has had no reader since 044 \u2014
45210
+ -- the installment is the obligation. Its amount is append-only, its status is
45211
+ -- not, so an unpaid mirror is cancelled (stamped in metadata) and the schedule
45212
+ -- goes through. A mirror that records a payment still blocks.
45213
+ --
45214
+ -- Idempotent: replaces the function.
45215
+
45216
+ CREATE OR REPLACE FUNCTION public.financial_reschedule_invoice(
45217
+ p_invoice_id uuid,
45218
+ p_installments jsonb,
45219
+ p_idempotency_key text DEFAULT NULL::text
45220
+ )
45221
+ RETURNS jsonb
45222
+ LANGUAGE plpgsql
45223
+ SECURITY DEFINER
45224
+ SET search_path TO ''
45225
+ AS $function$
45226
+ DECLARE
45227
+ v_tenant uuid := public.plg_financial_require_tenant();
45228
+ v_invoice public.plg_financial_invoices%ROWTYPE;
45229
+ v_paid numeric;
45230
+ v_mirror int;
45231
+ v_sum numeric := 0;
45232
+ v_i jsonb;
45233
+ v_n int := 0;
45234
+ v_out jsonb := '[]'::jsonb;
45235
+ v_inst_id uuid;
45236
+ v_due date;
45237
+ v_amount numeric;
45238
+ v_meta jsonb;
45239
+ v_total int;
45240
+ BEGIN
45241
+ SELECT * INTO v_invoice FROM public.plg_financial_invoices WHERE id = p_invoice_id AND tenant_id = v_tenant;
45242
+ IF NOT FOUND THEN
45243
+ RAISE EXCEPTION 'financial_reschedule_invoice: invoice % not found', p_invoice_id USING ERRCODE = 'P0002';
45244
+ END IF;
45245
+ PERFORM public.plg_financial_require_permission('financial.edit', v_invoice.unit_id);
45246
+ PERFORM public.plg_financial_claim_idempotency(v_tenant, p_idempotency_key);
45247
+
45248
+ IF v_invoice.cancelled_at IS NOT NULL THEN
45249
+ RAISE EXCEPTION 'financial_reschedule_invoice: invoice % is cancelled', v_invoice.number USING ERRCODE = '55000';
45250
+ END IF;
45251
+
45252
+ SELECT coalesce(sum(b.paid), 0) INTO v_paid
45253
+ FROM public.v_financial_installment_balances b WHERE b.invoice_id = p_invoice_id;
45254
+ IF v_paid > 0 THEN
45255
+ RAISE EXCEPTION 'financial_reschedule_invoice: invoice % has % already received; its schedule is history now', v_invoice.number, v_paid
45256
+ USING ERRCODE = '55000',
45257
+ HINT = 'Move the due date of an unpaid installment instead, or cancel and reissue.';
45258
+ END IF;
45259
+
45260
+ -- The legacy \`bill\` mirror can't change amount, but nothing reads it any more
45261
+ -- (the installment is the obligation since 044) and its status may move.
45262
+ -- Retire it unless it records a payment the installments don't know about.
45263
+ SELECT count(*) INTO v_mirror FROM public.plg_financial_movements m
45264
+ WHERE m.financial_invoice_id = p_invoice_id AND m.movement_kind = 'bill'
45265
+ AND m.status <> 'cancelled' AND coalesce(m.paid_amount, 0) > 0;
45266
+ IF v_mirror > 0 THEN
45267
+ RAISE EXCEPTION 'financial_reschedule_invoice: invoice % carries a paid legacy bill movement and cannot be rescheduled', v_invoice.number
45268
+ USING ERRCODE = '55000',
45269
+ HINT = 'Cancel and reissue this invoice.';
45270
+ END IF;
45271
+ UPDATE public.plg_financial_movements m
45272
+ SET status = 'cancelled', updated_at = now(),
45273
+ metadata = coalesce(m.metadata, '{}'::jsonb)
45274
+ || jsonb_build_object('retired_by', 'financial_reschedule_invoice', 'retired_at', now())
45275
+ WHERE m.financial_invoice_id = p_invoice_id AND m.movement_kind = 'bill' AND m.status <> 'cancelled';
45276
+
45277
+ IF jsonb_typeof(p_installments) <> 'array' OR jsonb_array_length(p_installments) = 0 THEN
45278
+ RAISE EXCEPTION 'financial_reschedule_invoice: installments must be a non-empty array' USING ERRCODE = '22023';
45279
+ END IF;
45280
+ FOR v_i IN SELECT * FROM jsonb_array_elements(p_installments) LOOP
45281
+ v_sum := v_sum + round(coalesce((v_i ->> 'amount')::numeric, 0), 2);
45282
+ END LOOP;
45283
+ IF v_sum <> round(v_invoice.total, 2) THEN
45284
+ RAISE EXCEPTION 'financial_reschedule_invoice: installments sum to % but the invoice total is %', v_sum, v_invoice.total
45285
+ USING ERRCODE = '23514';
45286
+ END IF;
45287
+
45288
+ v_total := jsonb_array_length(p_installments);
45289
+
45290
+ -- 1. A sobra sai PRIMEIRO. Se ela tiver movimento, o banco recusa aqui \u2014 e \xE9
45291
+ -- a recusa certa: encolher o cronograma apagaria a linha que um
45292
+ -- lan\xE7amento aponta.
45293
+ DELETE FROM public.plg_financial_invoice_installments
45294
+ WHERE invoice_id = p_invoice_id AND number > v_total;
45295
+
45296
+ -- 2. E a parcela de n\xFAmero N continua sendo a de n\xFAmero N.
45297
+ FOR v_i IN SELECT * FROM jsonb_array_elements(p_installments) LOOP
45298
+ v_n := v_n + 1;
45299
+ v_due := coalesce((v_i ->> 'due_date')::date, v_invoice.competence_date, current_date);
45300
+ v_amount := round(coalesce((v_i ->> 'amount')::numeric, 0), 2);
45301
+ v_meta := CASE WHEN jsonb_typeof(v_i -> 'metadata') = 'object' THEN v_i -> 'metadata' ELSE NULL END;
45302
+
45303
+ UPDATE public.plg_financial_invoice_installments
45304
+ SET due_date = v_due,
45305
+ amount = v_amount,
45306
+ metadata = coalesce(v_meta, metadata),
45307
+ updated_at = now()
45308
+ WHERE invoice_id = p_invoice_id AND number = v_n
45309
+ RETURNING id INTO v_inst_id;
45310
+
45311
+ IF v_inst_id IS NULL THEN
45312
+ INSERT INTO public.plg_financial_invoice_installments
45313
+ (tenant_id, unit_id, invoice_id, number, due_date, amount, metadata)
45314
+ VALUES (v_tenant, v_invoice.unit_id, p_invoice_id, v_n, v_due, v_amount, coalesce(v_meta, '{}'::jsonb))
45315
+ RETURNING id INTO v_inst_id;
45316
+ END IF;
45317
+
45318
+ v_out := v_out || jsonb_build_object('id', v_inst_id, 'number', v_n, 'due_date', v_due, 'amount', v_amount);
45319
+ END LOOP;
45320
+
45321
+ PERFORM public.plg_financial_audit(v_tenant, 'financial.invoice.reschedule', 'plg_financial_invoices', p_invoice_id::text,
45322
+ jsonb_build_object('number', v_invoice.number, 'installments', v_n, 'idempotency_key', p_idempotency_key));
45323
+
45324
+ RETURN jsonb_build_object('invoice_id', p_invoice_id, 'installments', v_out);
45325
+ END $function$;
45326
+
45327
+ COMMENT ON FUNCTION public.financial_reschedule_invoice(uuid, jsonb, text) IS
45328
+ 'Rewrites the schedule by UPDATING each numbered installment in place, and retires an unpaid legacy bill mirror instead of refusing (119).';
45329
+ `;
45134
45330
  var MIGRATIONS = [
45135
45331
  { id: "000_baseline", sql: MIGRATION_000_BASELINE },
45136
45332
  { id: "001_the_comanda_becomes_a_receivable_when_it_closes", sql: MIGRATION_001_THE_COMANDA_BECOMES_A_RECEIVABLE_WHEN_IT_CLOSES },
@@ -45250,7 +45446,8 @@ var MIGRATIONS = [
45250
45446
  { id: "115_a_remessa_aponta_para_a_conta_que_existe", sql: MIGRATION_115_A_REMESSA_APONTA_PARA_A_CONTA_QUE_EXISTE },
45251
45447
  { id: "116_um_estorno_nao_se_estorna", sql: MIGRATION_116_UM_ESTORNO_NAO_SE_ESTORNA },
45252
45448
  { id: "117_copying_lines_is_an_internal_step", sql: MIGRATION_117_COPYING_LINES_IS_AN_INTERNAL_STEP },
45253
- { id: "118_gift_card_found_by_exact_code", sql: MIGRATION_118_GIFT_CARD_FOUND_BY_EXACT_CODE }
45449
+ { id: "118_gift_card_found_by_exact_code", sql: MIGRATION_118_GIFT_CARD_FOUND_BY_EXACT_CODE },
45450
+ { id: "119_an_unpaid_legacy_bill_can_be_rescheduled", sql: MIGRATION_119_AN_UNPAID_LEGACY_BILL_CAN_BE_RESCHEDULED }
45254
45451
  ];
45255
45452
  var STANDALONE_CONFIG = resolveConfig();
45256
45453
  registerTranslations(financialLocales);
@@ -46037,6 +46234,6 @@ function createFinancialPlugin(options) {
46037
46234
  };
46038
46235
  }
46039
46236
 
46040
- export { ClientAccountInline, ClientAccountModal, ClientAccountPanel, FINANCIAL_NAV_FEATURES, ReceivePaymentModal, buildFinancialDomainEvents, buildFinancialMessageDefaults, createFinancialPlugin, createFinancialSettingsPlugin, createMockFinancialProvider, createSafeFinancialProvider };
46237
+ export { ClientAccountInline, ClientAccountModal, ClientAccountPanel, FINANCIAL_INVOICE_ZONES, FINANCIAL_NAV_FEATURES, ReceivePaymentModal, buildFinancialDomainEvents, buildFinancialMessageDefaults, createFinancialPlugin, createFinancialSettingsPlugin, createMockFinancialProvider, createSafeFinancialProvider };
46041
46238
  //# sourceMappingURL=index.js.map
46042
46239
  //# sourceMappingURL=index.js.map