@fayz-ai/plugin-fiscal-br 0.7.5 → 0.8.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/data/inbox.d.ts +43 -0
- package/dist/data/inbox.d.ts.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +782 -187
- package/dist/index.js.map +1 -1
- package/dist/lib/financial-provider.d.ts +1 -1
- package/dist/lib/financial-provider.d.ts.map +1 -1
- package/dist/migrations/index.d.ts +5 -0
- package/dist/migrations/index.d.ts.map +1 -1
- package/dist/types.d.ts +2 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/views/InboundNotesPage.d.ts.map +1 -1
- package/dist/views/InboundNotesView.d.ts +1 -2
- package/dist/views/InboundNotesView.d.ts.map +1 -1
- package/dist/views/NoteAttachmentsCard.d.ts.map +1 -1
- package/dist/views/NoteReconcileView.d.ts.map +1 -1
- package/dist/views/UnitFiscalWidgets.d.ts.map +1 -1
- package/dist/views/inventoryView.d.ts.map +1 -1
- package/functions/fiscalbr-certificate/index.ts +162 -0
- package/functions/fiscalbr-dfe-pull/index.ts +86 -0
- package/package.json +5 -5
- package/dist/views/ComingSoon.d.ts +0 -2
- package/dist/views/ComingSoon.d.ts.map +0 -1
- package/dist/views/ManifestView.d.ts +0 -8
- package/dist/views/ManifestView.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { recordRailFields, RECORD_GROUP, activeFacet, describeError, getSupabaseClientOptional, connectionSettings, connectionStatus, definePlugin, createConnectionStore, settingsStatus, maskCpfCnpj } from '@fayz-ai/core';
|
|
2
|
-
import
|
|
3
|
-
import { ModalHeader, ModalTitle, ModalBody, Skeleton, AiActionButton, Dropdown, DropdownTrigger, Button, DropdownContent, DropdownItem, Hint, Card, SearchSelect, Input, EmBreve, DatePicker, ModalFooter, SubpageHeader, Modal, ModalContent, ModalDescription, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, useFilterDraft, RowActions, PageHeaderActions, FilterPanel, FilterPanelField, SearchField, TooltipProvider, DataTable, ChevronPager, Tooltip, TooltipTrigger, TooltipContent,
|
|
1
|
+
import { recordRailFields, RECORD_GROUP, activeFacet, describeError, getSupabaseClientOptional, formatCurrency, connectionSettings, connectionStatus, definePlugin, createConnectionStore, settingsStatus, maskCpfCnpj, getActiveTenantId as getActiveTenantId$1 } from '@fayz-ai/core';
|
|
2
|
+
import React6, { useState, useCallback, useEffect, useMemo, useRef } from 'react';
|
|
3
|
+
import { ModalHeader, ModalTitle, ModalBody, Skeleton, AiActionButton, Dropdown, DropdownTrigger, Button, DropdownContent, DropdownItem, Hint, Card, InlineLink, SearchSelect, Input, EmBreve, DatePicker, ModalFooter, SubpageHeader, Modal, ModalContent, ModalDescription, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, useFilterDraft, RowActions, PageHeaderActions, FilterPanel, FilterPanelField, SearchField, TooltipProvider, DataTable, ChevronPager, Tooltip, TooltipTrigger, TooltipContent, Badge, SegmentedControl, ComingSoon, toast, CardHeader, CardTitle, CardContent, CardDescription, Switch } from '@fayz-ai/ui';
|
|
4
4
|
export { ComingSoon, EmBreve } from '@fayz-ai/ui';
|
|
5
|
-
import { registerDocumentOpener, PersonLink, getActiveTenantId, useUnitFilter, PageActions, usePermissionOptional, UNIT_DETAIL_ZONES
|
|
6
|
-
import { Loader2, Download, ChevronDown, FileCode2, FileText, RefreshCw, UserPlus, Gift, AlertTriangle, ChevronRight, Check, Trash2, Plus, KeyRound, Image, UploadCloud, Paperclip, ScanLine, Eye, ListChecks,
|
|
5
|
+
import { registerDocumentOpener, PersonLink, getActiveTenantId, useUnitFilter, PageActions, adminNavigateTo, usePermissionOptional, UNIT_DETAIL_ZONES } from '@fayz-ai/admin';
|
|
6
|
+
import { Loader2, Download, ChevronDown, FileCode2, FileText, RefreshCw, UserPlus, Gift, AlertTriangle, ChevronRight, Check, Trash2, Plus, KeyRound, Image, UploadCloud, Paperclip, ScanLine, Eye, ListChecks, FileDown, CheckCircle2, FileCheck2, XCircle, Inbox, X, Info, ShieldCheck } from 'lucide-react';
|
|
7
7
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
8
|
-
import { FINANCIAL_INVOICE_ZONES } from '@fayz-ai/
|
|
8
|
+
import { FINANCIAL_INVOICE_ZONES } from '@fayz-ai/financial/views/zones';
|
|
9
9
|
|
|
10
10
|
// src/index.ts
|
|
11
11
|
var PLUGNOTAS_CONNECTOR_ID = "plugnotas";
|
|
@@ -4017,6 +4017,399 @@ $function$;
|
|
|
4017
4017
|
REVOKE ALL ON FUNCTION public.fiscalbr_fill_inbox_lines(uuid, jsonb) FROM PUBLIC;
|
|
4018
4018
|
GRANT EXECUTE ON FUNCTION public.fiscalbr_fill_inbox_lines(uuid, jsonb) TO authenticated;
|
|
4019
4019
|
`;
|
|
4020
|
+
var MIGRATION_024_A_NOTA_NAO_APONTA_PARA_CONTA_QUE_SUMIU = `-- ---------------------------------------------------------------------------
|
|
4021
|
+
-- A note never points at a payable (or stock movement) that no longer exists.
|
|
4022
|
+
-- ---------------------------------------------------------------------------
|
|
4023
|
+
-- invoice_id and stock_movement_id cross into other plugins, so they carry no
|
|
4024
|
+
-- foreign key. When a re-copy rebuilt a tenant's payables under new ids, the
|
|
4025
|
+
-- notes kept the old ones: the screen read "already accepted" and hid every
|
|
4026
|
+
-- action, while Contas a Pagar had nothing. This heals a note: a dead payable
|
|
4027
|
+
-- link is re-pointed to the live payable of the same NF-e when exactly one
|
|
4028
|
+
-- exists, otherwise cleared; a dead movement link is cleared, and the note
|
|
4029
|
+
-- stops counting as stocked only when that dead movement was all it had. A
|
|
4030
|
+
-- cleared note can be accepted again, which writes the payable and the stock.
|
|
4031
|
+
-- ---------------------------------------------------------------------------
|
|
4032
|
+
|
|
4033
|
+
CREATE OR REPLACE FUNCTION public.plg_fiscalbr_heal_note_links(p_tenant uuid, p_document_id uuid)
|
|
4034
|
+
RETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path TO '' AS $function$
|
|
4035
|
+
DECLARE
|
|
4036
|
+
v_doc public.plg_fiscalbr_inbox_documents%ROWTYPE;
|
|
4037
|
+
v_invoice uuid;
|
|
4038
|
+
v_matches integer;
|
|
4039
|
+
v_dead_mv integer := 0;
|
|
4040
|
+
v_relinked boolean := false;
|
|
4041
|
+
v_released boolean := false;
|
|
4042
|
+
v_unstocked boolean := false;
|
|
4043
|
+
BEGIN
|
|
4044
|
+
SELECT * INTO v_doc FROM public.plg_fiscalbr_inbox_documents
|
|
4045
|
+
WHERE tenant_id = p_tenant AND id = p_document_id
|
|
4046
|
+
FOR UPDATE;
|
|
4047
|
+
IF NOT FOUND THEN
|
|
4048
|
+
RETURN jsonb_build_object('document_id', p_document_id, 'changed', false);
|
|
4049
|
+
END IF;
|
|
4050
|
+
|
|
4051
|
+
IF v_doc.invoice_id IS NOT NULL AND NOT EXISTS (
|
|
4052
|
+
SELECT 1 FROM public.plg_financial_invoices f WHERE f.id = v_doc.invoice_id) THEN
|
|
4053
|
+
-- Same NF-e: the key this plugin writes, or the V1 conciliation's text for the same supplier.
|
|
4054
|
+
SELECT count(*), min(f.id::text)::uuid INTO v_matches, v_invoice
|
|
4055
|
+
FROM public.plg_financial_invoices f
|
|
4056
|
+
WHERE f.tenant_id = p_tenant AND f.direction = 'payable' AND f.cancelled_at IS NULL
|
|
4057
|
+
AND (f.idempotency_key = 'danfe:' || v_doc.access_key
|
|
4058
|
+
OR (v_doc.supplier_party_id IS NOT NULL
|
|
4059
|
+
AND f.counterparty_person_id = v_doc.supplier_party_id
|
|
4060
|
+
AND f.description ~ ('NF-e 0*' || ltrim(v_doc.nfe_number, '0') || '(\\D|$)')))
|
|
4061
|
+
AND NOT EXISTS (SELECT 1 FROM public.plg_fiscalbr_inbox_documents o
|
|
4062
|
+
WHERE o.tenant_id = p_tenant AND o.invoice_id = f.id AND o.id <> v_doc.id);
|
|
4063
|
+
IF v_matches = 1 THEN
|
|
4064
|
+
v_relinked := true;
|
|
4065
|
+
ELSE
|
|
4066
|
+
v_invoice := NULL;
|
|
4067
|
+
v_released := true;
|
|
4068
|
+
END IF;
|
|
4069
|
+
UPDATE public.plg_fiscalbr_inbox_documents SET invoice_id = v_invoice, updated_at = now()
|
|
4070
|
+
WHERE id = v_doc.id;
|
|
4071
|
+
END IF;
|
|
4072
|
+
|
|
4073
|
+
UPDATE public.plg_fiscalbr_inbox_items i SET stock_movement_id = NULL, updated_at = now()
|
|
4074
|
+
WHERE i.tenant_id = p_tenant AND i.inbox_document_id = v_doc.id
|
|
4075
|
+
AND i.stock_movement_id IS NOT NULL
|
|
4076
|
+
AND NOT EXISTS (SELECT 1 FROM public.plg_inventory_stock_movements m WHERE m.id = i.stock_movement_id);
|
|
4077
|
+
GET DIAGNOSTICS v_dead_mv = ROW_COUNT;
|
|
4078
|
+
|
|
4079
|
+
IF v_dead_mv > 0 AND v_doc.stocked_at IS NOT NULL
|
|
4080
|
+
AND v_doc.inventory_operation_id IS NULL
|
|
4081
|
+
AND NOT EXISTS (SELECT 1 FROM public.plg_fiscalbr_inbox_items i
|
|
4082
|
+
WHERE i.tenant_id = p_tenant AND i.inbox_document_id = v_doc.id
|
|
4083
|
+
AND i.stock_movement_id IS NOT NULL) THEN
|
|
4084
|
+
UPDATE public.plg_fiscalbr_inbox_documents SET stocked_at = NULL, updated_at = now()
|
|
4085
|
+
WHERE id = v_doc.id;
|
|
4086
|
+
v_unstocked := true;
|
|
4087
|
+
END IF;
|
|
4088
|
+
|
|
4089
|
+
RETURN jsonb_build_object('document_id', v_doc.id,
|
|
4090
|
+
'changed', v_relinked OR v_released OR v_dead_mv > 0,
|
|
4091
|
+
'relinked', v_relinked, 'released', v_released,
|
|
4092
|
+
'dead_movements', v_dead_mv, 'unstocked', v_unstocked);
|
|
4093
|
+
END;
|
|
4094
|
+
$function$;
|
|
4095
|
+
|
|
4096
|
+
REVOKE ALL ON FUNCTION public.plg_fiscalbr_heal_note_links(uuid, uuid) FROM PUBLIC, anon, authenticated;
|
|
4097
|
+
|
|
4098
|
+
-- The screen heals the note it opens, so a future re-copy cannot strand one again.
|
|
4099
|
+
CREATE OR REPLACE FUNCTION public.fiscalbr_heal_inbox_note(p_document_id uuid)
|
|
4100
|
+
RETURNS jsonb LANGUAGE plpgsql SECURITY DEFINER SET search_path TO '' AS $function$
|
|
4101
|
+
DECLARE
|
|
4102
|
+
v_tenant uuid := public.plg_financial_require_tenant();
|
|
4103
|
+
v_unit uuid;
|
|
4104
|
+
BEGIN
|
|
4105
|
+
SELECT unit_id INTO v_unit FROM public.plg_fiscalbr_inbox_documents
|
|
4106
|
+
WHERE tenant_id = v_tenant AND id = p_document_id;
|
|
4107
|
+
IF NOT FOUND THEN
|
|
4108
|
+
RAISE EXCEPTION 'fiscalbr: nota n\xE3o encontrada' USING ERRCODE = 'P0002';
|
|
4109
|
+
END IF;
|
|
4110
|
+
PERFORM public.plg_financial_require_permission('financial.create', v_unit);
|
|
4111
|
+
RETURN public.plg_fiscalbr_heal_note_links(v_tenant, p_document_id);
|
|
4112
|
+
END;
|
|
4113
|
+
$function$;
|
|
4114
|
+
|
|
4115
|
+
REVOKE ALL ON FUNCTION public.fiscalbr_heal_inbox_note(uuid) FROM PUBLIC;
|
|
4116
|
+
GRANT EXECUTE ON FUNCTION public.fiscalbr_heal_inbox_note(uuid) TO authenticated;
|
|
4117
|
+
|
|
4118
|
+
-- Heal what is already stranded.
|
|
4119
|
+
DO $backfill$
|
|
4120
|
+
DECLARE r record;
|
|
4121
|
+
BEGIN
|
|
4122
|
+
FOR r IN
|
|
4123
|
+
SELECT DISTINCT d.tenant_id, d.id
|
|
4124
|
+
FROM public.plg_fiscalbr_inbox_documents d
|
|
4125
|
+
LEFT JOIN public.plg_fiscalbr_inbox_items i
|
|
4126
|
+
ON i.tenant_id = d.tenant_id AND i.inbox_document_id = d.id
|
|
4127
|
+
WHERE (d.invoice_id IS NOT NULL
|
|
4128
|
+
AND NOT EXISTS (SELECT 1 FROM public.plg_financial_invoices f WHERE f.id = d.invoice_id))
|
|
4129
|
+
OR (i.stock_movement_id IS NOT NULL
|
|
4130
|
+
AND NOT EXISTS (SELECT 1 FROM public.plg_inventory_stock_movements m WHERE m.id = i.stock_movement_id))
|
|
4131
|
+
LOOP
|
|
4132
|
+
PERFORM public.plg_fiscalbr_heal_note_links(r.tenant_id, r.id);
|
|
4133
|
+
END LOOP;
|
|
4134
|
+
END
|
|
4135
|
+
$backfill$;
|
|
4136
|
+
`;
|
|
4137
|
+
var MIGRATION_025_A_CONTA_DA_NOTA_FECHA_COM_O_TOTAL = `-- ---------------------------------------------------------------------------
|
|
4138
|
+
-- The payable a note opens lists products as products, and adds up to its total.
|
|
4139
|
+
-- ---------------------------------------------------------------------------
|
|
4140
|
+
-- Two defects in the lines fiscalbr_accept_inbox_document wrote:
|
|
4141
|
+
-- 1. \`itemKind\` carried the fiscal entry type ('insumo', 'revenda'\u2026), which the
|
|
4142
|
+
-- financial screens do not know, so a linked product showed as "Insumo"
|
|
4143
|
+
-- with no product. The kind is 'product' when the line has one; the entry
|
|
4144
|
+
-- type moves to \`entryType\`, and product/chart account go to their columns.
|
|
4145
|
+
-- 2. Only the product lines were written, so freight, insurance, other
|
|
4146
|
+
-- expenses, IPI, ICMS-ST and discount were in the total but in no line
|
|
4147
|
+
-- (NF-e 1430116: R$ 480,47 owed, R$ 478,47 listed). Each becomes a line,
|
|
4148
|
+
-- and whatever still differs from the instalments becomes one more.
|
|
4149
|
+
-- ---------------------------------------------------------------------------
|
|
4150
|
+
|
|
4151
|
+
CREATE OR REPLACE FUNCTION public.plg_fiscalbr_note_charge_lines(
|
|
4152
|
+
p_tenant uuid, p_document_id uuid, p_invoice_id uuid, p_total numeric)
|
|
4153
|
+
RETURNS integer LANGUAGE plpgsql SECURITY DEFINER SET search_path TO '' AS $function$
|
|
4154
|
+
DECLARE
|
|
4155
|
+
v_doc public.plg_fiscalbr_inbox_documents%ROWTYPE;
|
|
4156
|
+
v_sum numeric;
|
|
4157
|
+
v_rest numeric;
|
|
4158
|
+
v_n integer := 0;
|
|
4159
|
+
v_c record;
|
|
4160
|
+
BEGIN
|
|
4161
|
+
SELECT * INTO v_doc FROM public.plg_fiscalbr_inbox_documents
|
|
4162
|
+
WHERE tenant_id = p_tenant AND id = p_document_id;
|
|
4163
|
+
IF NOT FOUND OR p_invoice_id IS NULL THEN RETURN 0; END IF;
|
|
4164
|
+
IF EXISTS (SELECT 1 FROM public.items
|
|
4165
|
+
WHERE tenant_id = p_tenant AND invoice_id = p_invoice_id
|
|
4166
|
+
AND metadata ? 'noteCharge') THEN
|
|
4167
|
+
RETURN 0;
|
|
4168
|
+
END IF;
|
|
4169
|
+
-- Only a payable that already lists the note's products: a V1 copy with no lines
|
|
4170
|
+
-- would get its whole total as one "difference" line.
|
|
4171
|
+
IF NOT EXISTS (SELECT 1 FROM public.items
|
|
4172
|
+
WHERE tenant_id = p_tenant AND invoice_id = p_invoice_id
|
|
4173
|
+
AND metadata ? 'cfop') THEN
|
|
4174
|
+
RETURN 0;
|
|
4175
|
+
END IF;
|
|
4176
|
+
|
|
4177
|
+
FOR v_c IN
|
|
4178
|
+
SELECT * FROM (VALUES
|
|
4179
|
+
(1, 'freight', 'Frete', round(coalesce(v_doc.total_freight, 0), 2)),
|
|
4180
|
+
(2, 'insurance', 'Seguro', round(coalesce(v_doc.total_insurance, 0), 2)),
|
|
4181
|
+
(3, 'other', 'Outras despesas da nota', round(coalesce(v_doc.total_other, 0), 2)),
|
|
4182
|
+
(4, 'ipi', 'IPI', round(coalesce(v_doc.total_ipi_value, 0), 2)),
|
|
4183
|
+
(5, 'icms_st', 'ICMS-ST', round(coalesce(v_doc.total_icms_st_value, 0), 2)),
|
|
4184
|
+
(6, 'discount', 'Desconto da nota', -round(coalesce(v_doc.total_discount, 0), 2))
|
|
4185
|
+
) AS c(ord, code, label, amount)
|
|
4186
|
+
WHERE amount <> 0
|
|
4187
|
+
ORDER BY ord
|
|
4188
|
+
LOOP
|
|
4189
|
+
INSERT INTO public.items (tenant_id, invoice_id, name, quantity, unit_price, total, sort_order, metadata)
|
|
4190
|
+
VALUES (p_tenant, p_invoice_id, v_c.label, 1, v_c.amount, v_c.amount, 1000 + v_c.ord,
|
|
4191
|
+
jsonb_build_object('itemKind', 'other', 'noteCharge', v_c.code));
|
|
4192
|
+
v_n := v_n + 1;
|
|
4193
|
+
END LOOP;
|
|
4194
|
+
|
|
4195
|
+
SELECT coalesce(sum(total), 0) INTO v_sum FROM public.items
|
|
4196
|
+
WHERE tenant_id = p_tenant AND invoice_id = p_invoice_id AND cancelled_at IS NULL;
|
|
4197
|
+
v_rest := round(coalesce(p_total, 0) - v_sum, 2);
|
|
4198
|
+
IF v_rest <> 0 THEN
|
|
4199
|
+
INSERT INTO public.items (tenant_id, invoice_id, name, quantity, unit_price, total, sort_order, metadata)
|
|
4200
|
+
VALUES (p_tenant, p_invoice_id, 'Diferen\xE7a entre a nota e as parcelas', 1, v_rest, v_rest, 1099,
|
|
4201
|
+
jsonb_build_object('itemKind', 'other', 'noteCharge', 'instalment_difference'));
|
|
4202
|
+
v_n := v_n + 1;
|
|
4203
|
+
END IF;
|
|
4204
|
+
RETURN v_n;
|
|
4205
|
+
END;
|
|
4206
|
+
$function$;
|
|
4207
|
+
|
|
4208
|
+
REVOKE ALL ON FUNCTION public.plg_fiscalbr_note_charge_lines(uuid, uuid, uuid, numeric) FROM PUBLIC, anon, authenticated;
|
|
4209
|
+
|
|
4210
|
+
DO $m$
|
|
4211
|
+
DECLARE
|
|
4212
|
+
v_def text;
|
|
4213
|
+
v_start integer;
|
|
4214
|
+
v_end integer;
|
|
4215
|
+
v_marker text := 'INSERT INTO public.items (tenant_id, invoice_id, name, quantity, unit_price, total, sort_order, metadata)';
|
|
4216
|
+
v_close text := 'ON CONFLICT DO NOTHING;';
|
|
4217
|
+
v_new text := $q$INSERT INTO public.items (tenant_id, invoice_id, product_id, chart_account_id, name, quantity, unit_price, total, sort_order, metadata)
|
|
4218
|
+
SELECT v_tenant, v_invoice, i.product_id, coalesce(i.chart_account_id, v_doc.default_chart_account_id),
|
|
4219
|
+
i.description, i.quantity_commercial, i.unit_price_commercial,
|
|
4220
|
+
round(coalesce(i.total_price, 0), 2), i.item_number,
|
|
4221
|
+
jsonb_strip_nulls(jsonb_build_object(
|
|
4222
|
+
'itemKind', CASE WHEN i.product_id IS NOT NULL THEN 'product' ELSE 'other' END,
|
|
4223
|
+
'referenceId', i.product_id, 'entryType', i.entry_type,
|
|
4224
|
+
'chartAccountId', coalesce(i.chart_account_id, v_doc.default_chart_account_id),
|
|
4225
|
+
'ncm', i.ncm, 'cfop', i.cfop,
|
|
4226
|
+
'supplierProductCode', i.supplier_product_code))
|
|
4227
|
+
FROM public.plg_fiscalbr_inbox_items i
|
|
4228
|
+
WHERE i.tenant_id = v_tenant AND i.inbox_document_id = v_doc.id
|
|
4229
|
+
ORDER BY i.item_number
|
|
4230
|
+
ON CONFLICT DO NOTHING;
|
|
4231
|
+
PERFORM public.plg_fiscalbr_note_charge_lines(v_tenant, v_doc.id, v_invoice, v_total);$q$;
|
|
4232
|
+
BEGIN
|
|
4233
|
+
SELECT pg_get_functiondef(p.oid) INTO v_def
|
|
4234
|
+
FROM pg_proc p JOIN pg_namespace n ON n.oid = p.pronamespace
|
|
4235
|
+
WHERE n.nspname = 'public' AND p.proname = 'fiscalbr_accept_inbox_document';
|
|
4236
|
+
IF v_def IS NULL THEN
|
|
4237
|
+
RAISE EXCEPTION 'fiscalbr/025: fiscalbr_accept_inbox_document does not exist';
|
|
4238
|
+
END IF;
|
|
4239
|
+
IF position('plg_fiscalbr_note_charge_lines' in v_def) > 0 THEN RETURN; END IF;
|
|
4240
|
+
|
|
4241
|
+
v_start := position(v_marker in v_def);
|
|
4242
|
+
IF v_start = 0 THEN
|
|
4243
|
+
RAISE EXCEPTION 'fiscalbr/025: unexpected body of fiscalbr_accept_inbox_document \u2014 check by hand';
|
|
4244
|
+
END IF;
|
|
4245
|
+
v_end := v_start + position(v_close in substr(v_def, v_start)) - 1 + length(v_close);
|
|
4246
|
+
EXECUTE substr(v_def, 1, v_start - 1) || v_new || substr(v_def, v_end);
|
|
4247
|
+
END
|
|
4248
|
+
$m$;
|
|
4249
|
+
|
|
4250
|
+
-- The payables already opened by notes: same kind/product fix, and the missing charge lines.
|
|
4251
|
+
ALTER TABLE public.items DISABLE TRIGGER items_invoice_line_immutable;
|
|
4252
|
+
|
|
4253
|
+
UPDATE public.items it
|
|
4254
|
+
SET product_id = coalesce(it.product_id, (it.metadata->>'referenceId')::uuid),
|
|
4255
|
+
metadata = jsonb_set(it.metadata || jsonb_build_object('entryType', it.metadata->>'itemKind'),
|
|
4256
|
+
'{itemKind}', '"product"'::jsonb, true),
|
|
4257
|
+
updated_at = now()
|
|
4258
|
+
FROM public.plg_financial_invoices f
|
|
4259
|
+
WHERE f.id = it.invoice_id
|
|
4260
|
+
AND f.metadata ? 'danfe'
|
|
4261
|
+
AND it.metadata->>'itemKind' IN ('insumo','revenda','patrimonio','uso_consumo','despesa','servico')
|
|
4262
|
+
AND it.metadata->>'referenceId' IS NOT NULL
|
|
4263
|
+
AND EXISTS (SELECT 1 FROM public.products p WHERE p.id = (it.metadata->>'referenceId')::uuid);
|
|
4264
|
+
|
|
4265
|
+
UPDATE public.items it
|
|
4266
|
+
SET metadata = jsonb_set(it.metadata || jsonb_build_object('entryType', it.metadata->>'itemKind'),
|
|
4267
|
+
'{itemKind}', '"other"'::jsonb, true),
|
|
4268
|
+
updated_at = now()
|
|
4269
|
+
FROM public.plg_financial_invoices f
|
|
4270
|
+
WHERE f.id = it.invoice_id
|
|
4271
|
+
AND f.metadata ? 'danfe'
|
|
4272
|
+
AND it.metadata->>'itemKind' IN ('insumo','revenda','patrimonio','uso_consumo','despesa','servico');
|
|
4273
|
+
|
|
4274
|
+
ALTER TABLE public.items ENABLE TRIGGER items_invoice_line_immutable;
|
|
4275
|
+
|
|
4276
|
+
DO $backfill$
|
|
4277
|
+
DECLARE r record;
|
|
4278
|
+
BEGIN
|
|
4279
|
+
FOR r IN
|
|
4280
|
+
SELECT d.tenant_id, d.id, f.id AS invoice_id, f.total
|
|
4281
|
+
FROM public.plg_fiscalbr_inbox_documents d
|
|
4282
|
+
JOIN public.plg_financial_invoices f ON f.id = d.invoice_id AND f.tenant_id = d.tenant_id
|
|
4283
|
+
WHERE f.metadata ? 'danfe' AND f.cancelled_at IS NULL
|
|
4284
|
+
LOOP
|
|
4285
|
+
PERFORM public.plg_fiscalbr_note_charge_lines(r.tenant_id, r.id, r.invoice_id, r.total);
|
|
4286
|
+
END LOOP;
|
|
4287
|
+
END
|
|
4288
|
+
$backfill$;
|
|
4289
|
+
`;
|
|
4290
|
+
var MIGRATION_026_O_RECEBIMENTO_PARADO_DIZ_POR_QUE = `-- ---------------------------------------------------------------------------
|
|
4291
|
+
-- When notes stop arriving, the emitter row says why.
|
|
4292
|
+
-- ---------------------------------------------------------------------------
|
|
4293
|
+
-- The SEFAZ pull fails per CNPJ (expired A1 certificate, provider refusal) and
|
|
4294
|
+
-- the V1 records only the last failure (integration_sync_state.last_error). The
|
|
4295
|
+
-- V2 kept nothing, so a tenant could go two weeks without a note and no screen
|
|
4296
|
+
-- would say so. These two columns hold that last failure; the notes list warns
|
|
4297
|
+
-- from them and from a stale dfe_last_sync_at.
|
|
4298
|
+
-- ---------------------------------------------------------------------------
|
|
4299
|
+
|
|
4300
|
+
ALTER TABLE public.plg_fiscalbr_emitter_settings
|
|
4301
|
+
ADD COLUMN IF NOT EXISTS dfe_last_error text,
|
|
4302
|
+
ADD COLUMN IF NOT EXISTS dfe_last_error_at timestamptz;
|
|
4303
|
+
|
|
4304
|
+
COMMENT ON COLUMN public.plg_fiscalbr_emitter_settings.dfe_last_error IS
|
|
4305
|
+
'V1: integration_sync_state.last_error (source = dfe_inbox) \u2014 last failure pulling notes from SEFAZ; null when the last pull worked.';
|
|
4306
|
+
COMMENT ON COLUMN public.plg_fiscalbr_emitter_settings.dfe_last_error_at IS
|
|
4307
|
+
'V1: integration_sync_state.last_synced_at when last_status = error.';
|
|
4308
|
+
|
|
4309
|
+
GRANT SELECT (dfe_last_error, dfe_last_error_at) ON public.plg_fiscalbr_emitter_settings TO authenticated;
|
|
4310
|
+
`;
|
|
4311
|
+
var MIGRATION_027_A_NOTA_COM_CONTA_E_SEM_ESTOQUE_TERMINA_NO_V2 = `-- ---------------------------------------------------------------------------
|
|
4312
|
+
-- A note that has its payable but never reached stock can be finished in V2.
|
|
4313
|
+
-- ---------------------------------------------------------------------------
|
|
4314
|
+
-- In the V1, saving the payment plan of a DANFE import opened the payable
|
|
4315
|
+
-- before anyone reconciled the lines; many imports stopped there. Copied over,
|
|
4316
|
+
-- those notes carry invoice_id and no stock, and both RPCs read invoice_id as
|
|
4317
|
+
-- "accepted": nothing could be reconciled and the goods never entered stock
|
|
4318
|
+
-- (Artorius 18, Espa\xE7o Facial 72, Pertinho 17 on 14/10/2026).
|
|
4319
|
+
--
|
|
4320
|
+
-- "Settled" is now: stocked, or a payable with no stock line left to receive.
|
|
4321
|
+
-- Saving decisions is allowed until then, and accepting a note that already has
|
|
4322
|
+
-- its payable receives the stock against it instead of opening a second one.
|
|
4323
|
+
-- ---------------------------------------------------------------------------
|
|
4324
|
+
|
|
4325
|
+
DO $m$
|
|
4326
|
+
DECLARE
|
|
4327
|
+
v_def text;
|
|
4328
|
+
v_old text;
|
|
4329
|
+
v_new text;
|
|
4330
|
+
v_start integer;
|
|
4331
|
+
v_end integer;
|
|
4332
|
+
v_pending constant text := $q$NOT EXISTS (SELECT 1 FROM public.plg_fiscalbr_inbox_items x
|
|
4333
|
+
WHERE x.tenant_id = v_tenant AND x.inbox_document_id = v_doc.id
|
|
4334
|
+
AND x.stock_movement_id IS NULL
|
|
4335
|
+
AND (x.entry_type IS NULL OR x.entry_type = '' OR x.entry_type IN ('insumo','revenda','patrimonio','uso_consumo')))$q$;
|
|
4336
|
+
BEGIN
|
|
4337
|
+
-- 1. Saving decisions.
|
|
4338
|
+
SELECT pg_get_functiondef(p.oid) INTO v_def FROM pg_proc p JOIN pg_namespace n ON n.oid = p.pronamespace
|
|
4339
|
+
WHERE n.nspname = 'public' AND p.proname = 'fiscalbr_save_inbox_decision';
|
|
4340
|
+
v_old := 'IF v_doc.stocked_at IS NOT NULL OR v_doc.invoice_id IS NOT NULL THEN';
|
|
4341
|
+
IF v_def IS NULL THEN RAISE EXCEPTION 'fiscalbr/027: fiscalbr_save_inbox_decision does not exist'; END IF;
|
|
4342
|
+
IF position(v_old in v_def) > 0 THEN
|
|
4343
|
+
v_def := replace(v_def, v_old, 'IF v_doc.stocked_at IS NOT NULL OR (v_doc.invoice_id IS NOT NULL AND ' || v_pending || ') THEN');
|
|
4344
|
+
-- v_tenant is that function's own variable name too.
|
|
4345
|
+
EXECUTE v_def;
|
|
4346
|
+
ELSIF position('x.stock_movement_id IS NULL' in v_def) = 0 THEN
|
|
4347
|
+
RAISE EXCEPTION 'fiscalbr/027: unexpected body of fiscalbr_save_inbox_decision \u2014 check by hand';
|
|
4348
|
+
END IF;
|
|
4349
|
+
|
|
4350
|
+
-- 2. Accepting.
|
|
4351
|
+
SELECT pg_get_functiondef(p.oid) INTO v_def FROM pg_proc p JOIN pg_namespace n ON n.oid = p.pronamespace
|
|
4352
|
+
WHERE n.nspname = 'public' AND p.proname = 'fiscalbr_accept_inbox_document';
|
|
4353
|
+
IF v_def IS NULL THEN RAISE EXCEPTION 'fiscalbr/027: fiscalbr_accept_inbox_document does not exist'; END IF;
|
|
4354
|
+
IF position('Half-done in the V1' in v_def) > 0 THEN RETURN; END IF;
|
|
4355
|
+
|
|
4356
|
+
IF position(v_old in v_def) = 0 THEN
|
|
4357
|
+
RAISE EXCEPTION 'fiscalbr/027: unexpected guard in fiscalbr_accept_inbox_document \u2014 check by hand';
|
|
4358
|
+
END IF;
|
|
4359
|
+
v_def := replace(v_def, v_old, 'IF v_doc.stocked_at IS NOT NULL OR (v_doc.invoice_id IS NOT NULL AND ' || v_pending || ') THEN');
|
|
4360
|
+
|
|
4361
|
+
v_start := position(' SELECT coalesce(sum(value), 0),' in v_def);
|
|
4362
|
+
v_new := 'PERFORM public.plg_fiscalbr_note_charge_lines(v_tenant, v_doc.id, v_invoice, v_total);';
|
|
4363
|
+
v_end := position(v_new in v_def);
|
|
4364
|
+
IF v_start = 0 OR v_end = 0 OR v_end < v_start THEN
|
|
4365
|
+
RAISE EXCEPTION 'fiscalbr/027: unexpected payable block in fiscalbr_accept_inbox_document \u2014 check by hand';
|
|
4366
|
+
END IF;
|
|
4367
|
+
v_end := v_end + length(v_new);
|
|
4368
|
+
v_def := substr(v_def, 1, v_start - 1)
|
|
4369
|
+
|| $q$ IF v_doc.invoice_id IS NOT NULL THEN
|
|
4370
|
+
-- Half-done in the V1: the payable exists; only the stock is missing.
|
|
4371
|
+
v_invoice := v_doc.invoice_id;
|
|
4372
|
+
SELECT total INTO v_total FROM public.plg_financial_invoices WHERE id = v_invoice;
|
|
4373
|
+
v_insts := '[]'::jsonb;
|
|
4374
|
+
ELSE
|
|
4375
|
+
$q$ || substr(v_def, v_start, v_end - v_start) || $q$
|
|
4376
|
+
END IF;$q$
|
|
4377
|
+
|| substr(v_def, v_end);
|
|
4378
|
+
EXECUTE v_def;
|
|
4379
|
+
END
|
|
4380
|
+
$m$;
|
|
4381
|
+
`;
|
|
4382
|
+
var MIGRATION_028_A_LINHA_DE_ESTOQUE_TEM_UNIDADE = `-- ---------------------------------------------------------------------------
|
|
4383
|
+
-- A stock line enters with its unit.
|
|
4384
|
+
-- ---------------------------------------------------------------------------
|
|
4385
|
+
-- Accepting let a stock line through with no stock unit; the movement then
|
|
4386
|
+
-- carried a bare quantity that every screen reads as "unidade" (Artorius, NF-e
|
|
4387
|
+
-- 222879: 20 kg of copa lombo entered as 20 units). The screen now suggests the
|
|
4388
|
+
-- unit and refuses without one; this is the same rule where it cannot be
|
|
4389
|
+
-- skipped.
|
|
4390
|
+
-- ---------------------------------------------------------------------------
|
|
4391
|
+
|
|
4392
|
+
DO $m$
|
|
4393
|
+
DECLARE
|
|
4394
|
+
v_def text;
|
|
4395
|
+
v_old constant text := $q$ IF v_it.product_id IS NULL THEN$q$;
|
|
4396
|
+
v_new constant text := $q$ IF v_it.stock_unit_id IS NULL THEN
|
|
4397
|
+
RAISE EXCEPTION 'fiscalbr: item % entra no estoque sem unidade \u2014 escolha a unidade de estoque', v_it.item_number
|
|
4398
|
+
USING ERRCODE = '23514';
|
|
4399
|
+
END IF;
|
|
4400
|
+
IF v_it.product_id IS NULL THEN$q$;
|
|
4401
|
+
BEGIN
|
|
4402
|
+
SELECT pg_get_functiondef(p.oid) INTO v_def FROM pg_proc p JOIN pg_namespace n ON n.oid = p.pronamespace
|
|
4403
|
+
WHERE n.nspname = 'public' AND p.proname = 'fiscalbr_accept_inbox_document';
|
|
4404
|
+
IF v_def IS NULL THEN RAISE EXCEPTION 'fiscalbr/028: fiscalbr_accept_inbox_document does not exist'; END IF;
|
|
4405
|
+
IF position('entra no estoque sem unidade' in v_def) > 0 THEN RETURN; END IF;
|
|
4406
|
+
IF position(v_old in v_def) = 0 THEN
|
|
4407
|
+
RAISE EXCEPTION 'fiscalbr/028: unexpected body of fiscalbr_accept_inbox_document \u2014 check by hand';
|
|
4408
|
+
END IF;
|
|
4409
|
+
EXECUTE replace(v_def, v_old, v_new);
|
|
4410
|
+
END
|
|
4411
|
+
$m$;
|
|
4412
|
+
`;
|
|
4020
4413
|
var MIGRATIONS = [
|
|
4021
4414
|
{ id: "000_baseline", sql: MIGRATION_000_BASELINE },
|
|
4022
4415
|
{ id: "001_preserve_terminal_results_and_recover_leases", sql: MIGRATION_001_PRESERVE_TERMINAL_RESULTS_AND_RECOVER_LEASES },
|
|
@@ -4041,7 +4434,12 @@ var MIGRATIONS = [
|
|
|
4041
4434
|
{ id: "020_a_nota_acha_o_fornecedor_pelo_cnpj", sql: MIGRATION_020_A_NOTA_ACHA_O_FORNECEDOR_PELO_CNPJ },
|
|
4042
4435
|
{ id: "021_uso_e_consumo_entra_no_estoque", sql: MIGRATION_021_USO_E_CONSUMO_ENTRA_NO_ESTOQUE },
|
|
4043
4436
|
{ id: "022_a_nota_do_v1_traz_o_xml", sql: MIGRATION_022_A_NOTA_DO_V1_TRAZ_O_XML },
|
|
4044
|
-
{ id: "023_a_nota_aceita_sem_linhas_recebe_as_linhas", sql: MIGRATION_023_A_NOTA_ACEITA_SEM_LINHAS_RECEBE_AS_LINHAS }
|
|
4437
|
+
{ id: "023_a_nota_aceita_sem_linhas_recebe_as_linhas", sql: MIGRATION_023_A_NOTA_ACEITA_SEM_LINHAS_RECEBE_AS_LINHAS },
|
|
4438
|
+
{ id: "024_a_nota_nao_aponta_para_conta_que_sumiu", sql: MIGRATION_024_A_NOTA_NAO_APONTA_PARA_CONTA_QUE_SUMIU },
|
|
4439
|
+
{ id: "025_a_conta_da_nota_fecha_com_o_total", sql: MIGRATION_025_A_CONTA_DA_NOTA_FECHA_COM_O_TOTAL },
|
|
4440
|
+
{ id: "026_o_recebimento_parado_diz_por_que", sql: MIGRATION_026_O_RECEBIMENTO_PARADO_DIZ_POR_QUE },
|
|
4441
|
+
{ id: "027_a_nota_com_conta_e_sem_estoque_termina_no_v2", sql: MIGRATION_027_A_NOTA_COM_CONTA_E_SEM_ESTOQUE_TERMINA_NO_V2 },
|
|
4442
|
+
{ id: "028_a_linha_de_estoque_tem_unidade", sql: MIGRATION_028_A_LINHA_DE_ESTOQUE_TEM_UNIDADE }
|
|
4045
4443
|
];
|
|
4046
4444
|
var taxGroupEntity = {
|
|
4047
4445
|
name: "Grupo fiscal",
|
|
@@ -4501,7 +4899,7 @@ async function listInboxNotes(options = {}) {
|
|
|
4501
4899
|
if (filter === "stocked") query = query.not("stocked_at", "is", null);
|
|
4502
4900
|
if (filter === "pending") query = query.is("stocked_at", null);
|
|
4503
4901
|
if (filter === "rejected") query = query.eq("status", "rejected");
|
|
4504
|
-
if (filter === "
|
|
4902
|
+
if (filter === "manifest_error") query = query.eq("manifestation_status", "erro");
|
|
4505
4903
|
if (search?.trim()) {
|
|
4506
4904
|
const term = search.trim();
|
|
4507
4905
|
query = query.or(
|
|
@@ -4625,6 +5023,18 @@ async function fillInboxLines(documentId, xml) {
|
|
|
4625
5023
|
if (error) throw error;
|
|
4626
5024
|
return Number(data?.items ?? 0);
|
|
4627
5025
|
}
|
|
5026
|
+
async function healInboxNote(documentId) {
|
|
5027
|
+
const { data, error } = await sb().rpc("fiscalbr_heal_inbox_note", { p_document_id: documentId });
|
|
5028
|
+
if (error) throw error;
|
|
5029
|
+
const r = data ?? {};
|
|
5030
|
+
return { changed: Boolean(r.changed), released: Boolean(r.released) };
|
|
5031
|
+
}
|
|
5032
|
+
async function getNotePayable(invoiceId) {
|
|
5033
|
+
const { data, error } = await sb().from("plg_financial_invoices").select("id, number, total, cancelled_at").eq("id", invoiceId).maybeSingle();
|
|
5034
|
+
if (error) throw error;
|
|
5035
|
+
if (!data) return null;
|
|
5036
|
+
return { id: data.id, number: data.number ?? null, total: Number(data.total ?? 0), cancelledAt: data.cancelled_at ?? null };
|
|
5037
|
+
}
|
|
4628
5038
|
var PullByKeyError = class extends Error {
|
|
4629
5039
|
constructor(message, code, options) {
|
|
4630
5040
|
super(message);
|
|
@@ -4949,6 +5359,67 @@ function parseBoleto(raw) {
|
|
|
4949
5359
|
}
|
|
4950
5360
|
return { amount: cents > 0 ? cents / 100 : null, dueDate };
|
|
4951
5361
|
}
|
|
5362
|
+
var STALE_AFTER_MS = 24 * 60 * 60 * 1e3;
|
|
5363
|
+
function expiryFromError(error) {
|
|
5364
|
+
const m = error?.match(/vencido em:?\s*(\d{2})\/(\d{2})\/(\d{4})/i);
|
|
5365
|
+
return m ? `${m[3]}-${m[2]}-${m[1]}` : null;
|
|
5366
|
+
}
|
|
5367
|
+
async function getInboxIntakeHealth() {
|
|
5368
|
+
const { data, error } = await sb().from("plg_fiscalbr_emitter_settings").select("legal_entity_id, dfe_sync_enabled, dfe_last_sync_at, dfe_last_error, certificate_expires_at").eq("dfe_sync_enabled", true);
|
|
5369
|
+
if (error) throw error;
|
|
5370
|
+
const now = Date.now();
|
|
5371
|
+
const stalled = (data ?? []).filter((r) => {
|
|
5372
|
+
const expired = r.certificate_expires_at && Date.parse(r.certificate_expires_at) < now;
|
|
5373
|
+
const stale = !r.dfe_last_sync_at || now - Date.parse(r.dfe_last_sync_at) > STALE_AFTER_MS;
|
|
5374
|
+
return expired || stale || Boolean(r.dfe_last_error);
|
|
5375
|
+
});
|
|
5376
|
+
if (stalled.length === 0) return null;
|
|
5377
|
+
const since = stalled.map((r) => r.dfe_last_sync_at).filter(Boolean).sort()[0] ?? null;
|
|
5378
|
+
const withError = stalled.find((r) => r.dfe_last_error);
|
|
5379
|
+
const certificateExpiredAt = stalled.map((r) => r.certificate_expires_at && Date.parse(r.certificate_expires_at) < now ? r.certificate_expires_at : expiryFromError(r.dfe_last_error)).find(Boolean) ?? null;
|
|
5380
|
+
const target = stalled.find((r) => r.certificate_expires_at && Date.parse(r.certificate_expires_at) < now) ?? withError ?? stalled[0];
|
|
5381
|
+
const { data: unit } = await sb().from("v_unit_company_legal_entities").select("unit_id").eq("company_legal_entity_id", target.legal_entity_id).limit(1).maybeSingle();
|
|
5382
|
+
return { stalled: stalled.length, since, certificateExpiredAt, error: withError?.dfe_last_error ?? null, unitId: unit?.unit_id ?? null };
|
|
5383
|
+
}
|
|
5384
|
+
async function syncNewNotes(max = 25) {
|
|
5385
|
+
const { data: newest } = await sb().from("plg_fiscalbr_inbox_documents").select("issue_date").order("issue_date", { ascending: false }).limit(1).maybeSingle();
|
|
5386
|
+
const since = newest?.issue_date ? new Date(Date.parse(newest.issue_date) - 2 * 864e5).toISOString().slice(0, 10) : void 0;
|
|
5387
|
+
const { data, error } = await sb().functions.invoke("fiscalbr-dfe-pull", {
|
|
5388
|
+
body: { action: "list", since, tenantId: getActiveTenantId() ?? null }
|
|
5389
|
+
});
|
|
5390
|
+
if (error) {
|
|
5391
|
+
let body = null;
|
|
5392
|
+
try {
|
|
5393
|
+
body = await error?.context?.json?.();
|
|
5394
|
+
} catch {
|
|
5395
|
+
}
|
|
5396
|
+
throw new PullByKeyError(body?.error || error.message || "Falha ao falar com a SEFAZ.", body?.code);
|
|
5397
|
+
}
|
|
5398
|
+
const listed = data?.notes ?? [];
|
|
5399
|
+
if (listed.length === 0) return { added: 0, waiting: 0, failed: (data?.failures ?? []).length };
|
|
5400
|
+
const keys = [...new Set(listed.map((n) => n.key))];
|
|
5401
|
+
const { data: known } = await sb().from("plg_fiscalbr_inbox_documents").select("access_key").in("access_key", keys);
|
|
5402
|
+
const have = new Set((known ?? []).map((r) => r.access_key));
|
|
5403
|
+
const missing = listed.filter((n, i) => !have.has(n.key) && listed.findIndex((m) => m.key === n.key) === i).slice(0, max);
|
|
5404
|
+
const result = { added: 0, waiting: 0, failed: (data?.failures ?? []).length };
|
|
5405
|
+
for (const n of missing) {
|
|
5406
|
+
try {
|
|
5407
|
+
const r = await pullNoteByKey(n.key, { legalEntityId: n.legalEntityId });
|
|
5408
|
+
if (r.status === "staged") result.added++;
|
|
5409
|
+
else result.waiting++;
|
|
5410
|
+
} catch (e) {
|
|
5411
|
+
if (e instanceof PullByKeyError && (e.code === "summary_only" || e.code === "throttled")) result.waiting++;
|
|
5412
|
+
else result.failed++;
|
|
5413
|
+
}
|
|
5414
|
+
}
|
|
5415
|
+
return result;
|
|
5416
|
+
}
|
|
5417
|
+
async function listProductStockUnits(productIds) {
|
|
5418
|
+
if (productIds.length === 0) return /* @__PURE__ */ new Map();
|
|
5419
|
+
const { data, error } = await sb().from("plg_inventory_product_details").select("product_id, measurement_unit_id").in("product_id", productIds).not("measurement_unit_id", "is", null);
|
|
5420
|
+
if (error) throw error;
|
|
5421
|
+
return new Map((data ?? []).map((r) => [String(r.product_id), String(r.measurement_unit_id)]));
|
|
5422
|
+
}
|
|
4952
5423
|
var formatCnpj = (d) => `${d.slice(0, 2)}.${d.slice(2, 5)}.${d.slice(5, 8)}/${d.slice(8, 12)}-${d.slice(12)}`;
|
|
4953
5424
|
var groupKey = (digits2) => digits2.replace(/(\d{4})(?=\d)/g, "$1 ");
|
|
4954
5425
|
function PullByKeyDialog({ open, onOpenChange, unitId, initialKey, onPulled }) {
|
|
@@ -5056,23 +5527,24 @@ function PullByKeyDialog({ open, onOpenChange, unitId, initialKey, onPulled }) {
|
|
|
5056
5527
|
] })
|
|
5057
5528
|
] }) });
|
|
5058
5529
|
}
|
|
5059
|
-
var money = (value) =>
|
|
5530
|
+
var money = (value) => formatCurrency(value || 0, "BRL");
|
|
5060
5531
|
var day = (iso) => iso ? iso.slice(0, 10).split("-").reverse().join("/") : "\u2014";
|
|
5061
5532
|
var cnpj = (digits2) => {
|
|
5062
5533
|
const d = (digits2 ?? "").replace(/\D/g, "");
|
|
5063
5534
|
if (d.length !== 14) return digits2 ?? "\u2014";
|
|
5064
5535
|
return `${d.slice(0, 2)}.${d.slice(2, 5)}.${d.slice(5, 8)}/${d.slice(8, 12)}-${d.slice(12)}`;
|
|
5065
5536
|
};
|
|
5066
|
-
var CAMPO = "h-9 w-full rounded-
|
|
5537
|
+
var CAMPO = "h-9 w-full rounded-input border border-input bg-background px-3 text-sm shadow-sm focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2";
|
|
5067
5538
|
var STATE_OPTIONS = [
|
|
5068
5539
|
{ value: "all", label: "Todos" },
|
|
5069
5540
|
{ value: "pending", label: "Estoque pendente" },
|
|
5070
5541
|
{ value: "stocked", label: "Estocado" },
|
|
5071
|
-
{ value: "
|
|
5542
|
+
{ value: "manifest_error", label: "Manifesta\xE7\xE3o com erro" },
|
|
5072
5543
|
{ value: "rejected", label: "Recusada" }
|
|
5073
5544
|
];
|
|
5074
5545
|
var isoDay = (d) => d.toISOString().slice(0, 10);
|
|
5075
|
-
|
|
5546
|
+
var SYNC_KEY = "fiscalbr.inbox.lastSefazSync";
|
|
5547
|
+
function InboundNotesView({ onOpenNote }) {
|
|
5076
5548
|
const [notes, setNotes] = useState([]);
|
|
5077
5549
|
const [loading, setLoading] = useState(true);
|
|
5078
5550
|
const [search, setSearch] = useState("");
|
|
@@ -5116,6 +5588,44 @@ function InboundNotesView({ onOpenNote, onOpenManifest }) {
|
|
|
5116
5588
|
useEffect(() => {
|
|
5117
5589
|
void reload();
|
|
5118
5590
|
}, [reload]);
|
|
5591
|
+
const [intake, setIntake] = useState(null);
|
|
5592
|
+
const [syncing, setSyncing] = useState(false);
|
|
5593
|
+
const [syncNote, setSyncNote] = useState(null);
|
|
5594
|
+
const refreshIntake = useCallback(() => {
|
|
5595
|
+
getInboxIntakeHealth().then(setIntake).catch(() => setIntake(null));
|
|
5596
|
+
}, []);
|
|
5597
|
+
const syncNow = useCallback(async (quiet) => {
|
|
5598
|
+
setSyncing(true);
|
|
5599
|
+
if (!quiet) setSyncNote(null);
|
|
5600
|
+
try {
|
|
5601
|
+
const r = await syncNewNotes();
|
|
5602
|
+
try {
|
|
5603
|
+
localStorage.setItem(SYNC_KEY, String(Date.now()));
|
|
5604
|
+
} catch {
|
|
5605
|
+
}
|
|
5606
|
+
if (r.added) void reload();
|
|
5607
|
+
const parts = [
|
|
5608
|
+
r.added ? `${r.added} ${r.added === 1 ? "nota nova" : "notas novas"}` : null,
|
|
5609
|
+
r.waiting ? `${r.waiting} ainda sem o XML completo na SEFAZ` : null,
|
|
5610
|
+
r.failed ? `${r.failed} com erro` : null
|
|
5611
|
+
].filter(Boolean);
|
|
5612
|
+
if (!quiet || parts.length) setSyncNote(parts.length ? `SEFAZ: ${parts.join(" \xB7 ")}.` : "SEFAZ: nenhuma nota nova.");
|
|
5613
|
+
} catch (e) {
|
|
5614
|
+
if (!quiet) setSyncNote(e instanceof Error ? e.message : String(e));
|
|
5615
|
+
} finally {
|
|
5616
|
+
setSyncing(false);
|
|
5617
|
+
refreshIntake();
|
|
5618
|
+
}
|
|
5619
|
+
}, [reload, refreshIntake]);
|
|
5620
|
+
useEffect(() => {
|
|
5621
|
+
refreshIntake();
|
|
5622
|
+
let last = 0;
|
|
5623
|
+
try {
|
|
5624
|
+
last = Number(localStorage.getItem(SYNC_KEY) ?? 0);
|
|
5625
|
+
} catch {
|
|
5626
|
+
}
|
|
5627
|
+
if (Date.now() - last > 30 * 6e4) void syncNow(true);
|
|
5628
|
+
}, []);
|
|
5119
5629
|
const ingest = useCallback(async (files) => {
|
|
5120
5630
|
const xmls = files.filter((f) => /\.xml$/i.test(f.name));
|
|
5121
5631
|
if (xmls.length === 0) {
|
|
@@ -5300,7 +5810,7 @@ function InboundNotesView({ onOpenNote, onOpenManifest }) {
|
|
|
5300
5810
|
] }) : /* @__PURE__ */ jsxs("div", { children: [
|
|
5301
5811
|
/* @__PURE__ */ jsx(Inbox, { className: "mx-auto h-8 w-8 text-muted-foreground", "aria-hidden": true }),
|
|
5302
5812
|
/* @__PURE__ */ jsx("p", { className: "mt-2 text-sm font-medium", children: "Nenhuma nota de entrada" }),
|
|
5303
|
-
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "As notas chegam da SEFAZ
|
|
5813
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "As notas chegam da SEFAZ sozinhas, ou voc\xEA arrasta o XML aqui." })
|
|
5304
5814
|
] });
|
|
5305
5815
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
5306
5816
|
/* @__PURE__ */ jsx(PageHeaderActions, { children: /* @__PURE__ */ jsx(
|
|
@@ -5318,6 +5828,16 @@ function InboundNotesView({ onOpenNote, onOpenManifest }) {
|
|
|
5318
5828
|
disabled: busy,
|
|
5319
5829
|
onSelect: () => fileInput.current?.click()
|
|
5320
5830
|
},
|
|
5831
|
+
{
|
|
5832
|
+
id: "sync-sefaz",
|
|
5833
|
+
label: syncing ? "Buscando na SEFAZ\u2026" : "Buscar notas novas",
|
|
5834
|
+
icon: syncing ? Loader2 : RefreshCw,
|
|
5835
|
+
disabled: syncing,
|
|
5836
|
+
testId: "sync-sefaz",
|
|
5837
|
+
onSelect: () => {
|
|
5838
|
+
void syncNow(false);
|
|
5839
|
+
}
|
|
5840
|
+
},
|
|
5321
5841
|
{
|
|
5322
5842
|
id: "pull-by-key",
|
|
5323
5843
|
label: "Puxar por chave",
|
|
@@ -5325,11 +5845,29 @@ function InboundNotesView({ onOpenNote, onOpenManifest }) {
|
|
|
5325
5845
|
creates: true,
|
|
5326
5846
|
testId: "pull-by-key",
|
|
5327
5847
|
onSelect: () => setPullOpen(true)
|
|
5328
|
-
}
|
|
5329
|
-
...onOpenManifest ? [{ id: "manifest", label: "Fila da SEFAZ", icon: Inbox, onSelect: onOpenManifest }] : []
|
|
5848
|
+
}
|
|
5330
5849
|
]
|
|
5331
5850
|
}
|
|
5332
5851
|
) }),
|
|
5852
|
+
syncNote && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", "data-testid": "sync-note", children: syncNote }),
|
|
5853
|
+
intake && /* @__PURE__ */ jsxs(Card, { className: "border-warning bg-warning-soft p-4", "data-testid": "intake-stalled", children: [
|
|
5854
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-warning-soft-foreground", children: intake.certificateExpiredAt ? `As notas da SEFAZ n\xE3o est\xE3o chegando: o certificado digital venceu em ${day(intake.certificateExpiredAt)}.` : `As notas da SEFAZ n\xE3o est\xE3o chegando${intake.since ? ` desde ${day(intake.since)}` : ""}.` }),
|
|
5855
|
+
/* @__PURE__ */ jsxs("p", { className: "mt-1 text-xs text-warning-soft-foreground", children: [
|
|
5856
|
+
intake.certificateExpiredAt ? "Renove o certificado A1 do CNPJ e envie o arquivo novo. As notas que ficaram para tr\xE1s chegam sozinhas depois disso." : intake.error ?? "A busca autom\xE1tica parou. Enquanto isso, d\xE1 para importar o XML ou puxar a nota pela chave.",
|
|
5857
|
+
intake.stalled > 1 ? ` (${intake.stalled} CNPJs afetados)` : ""
|
|
5858
|
+
] }),
|
|
5859
|
+
intake.unitId && (intake.certificateExpiredAt || intake.error) && /* @__PURE__ */ jsx(
|
|
5860
|
+
Button,
|
|
5861
|
+
{
|
|
5862
|
+
size: "sm",
|
|
5863
|
+
variant: "outline",
|
|
5864
|
+
className: "mt-3",
|
|
5865
|
+
"data-testid": "intake-update-certificate",
|
|
5866
|
+
onClick: () => adminNavigateTo(`/settings/locations/${intake.unitId}/fields:tax`),
|
|
5867
|
+
children: "Atualizar certificado"
|
|
5868
|
+
}
|
|
5869
|
+
)
|
|
5870
|
+
] }),
|
|
5333
5871
|
/* @__PURE__ */ jsxs(
|
|
5334
5872
|
Card,
|
|
5335
5873
|
{
|
|
@@ -5491,7 +6029,7 @@ function StockBadge({ stockedAt, status }) {
|
|
|
5491
6029
|
] }) : /* @__PURE__ */ jsx("span", { className: "inline-flex items-center rounded-full bg-warning-soft px-2 py-0.5 text-[11px] font-medium text-warning-soft-foreground", children: "Pendente" });
|
|
5492
6030
|
}
|
|
5493
6031
|
var MAX_BYTES = 15 * 1024 * 1024;
|
|
5494
|
-
var money2 = (v) =>
|
|
6032
|
+
var money2 = (v) => formatCurrency(v || 0);
|
|
5495
6033
|
var day2 = (iso) => iso ? iso.slice(0, 10).split("-").reverse().join("/") : "\u2014";
|
|
5496
6034
|
var size = (b) => !b ? "" : b < 1024 * 1024 ? `${Math.max(1, Math.round(b / 1024))} KB` : `${(b / 1024 / 1024).toFixed(1)} MB`;
|
|
5497
6035
|
function applyPaymentCode(list, code) {
|
|
@@ -5688,7 +6226,7 @@ var norm = (u) => (u ?? "").trim().toUpperCase().replace(/\.$/, "");
|
|
|
5688
6226
|
function packagingCount(commercialUnit) {
|
|
5689
6227
|
return PACKAGING_COUNT[norm(commercialUnit)] ?? null;
|
|
5690
6228
|
}
|
|
5691
|
-
var money3 = (v) =>
|
|
6229
|
+
var money3 = (v) => formatCurrency(v || 0, "BRL");
|
|
5692
6230
|
var qty = (v) => new Intl.NumberFormat("pt-BR", { maximumFractionDigits: 4 }).format(v || 0);
|
|
5693
6231
|
var day3 = (iso) => iso ? iso.slice(0, 10).split("-").reverse().join("/") : "\u2014";
|
|
5694
6232
|
var ENTRY_TYPES = [
|
|
@@ -5704,6 +6242,32 @@ var localSearch = (options) => (query) => {
|
|
|
5704
6242
|
return (q ? options.filter((o) => o.label.toLowerCase().includes(q)) : options).slice(0, 40);
|
|
5705
6243
|
};
|
|
5706
6244
|
var labelOf = (options, id) => options.find((o) => o.id === id)?.label;
|
|
6245
|
+
var NOTE_UNIT_CODES = {
|
|
6246
|
+
KG: "kg",
|
|
6247
|
+
KGS: "kg",
|
|
6248
|
+
KILO: "kg",
|
|
6249
|
+
QUILO: "kg",
|
|
6250
|
+
G: "g",
|
|
6251
|
+
GR: "g",
|
|
6252
|
+
GRS: "g",
|
|
6253
|
+
L: "l",
|
|
6254
|
+
LT: "l",
|
|
6255
|
+
LTS: "l",
|
|
6256
|
+
LITRO: "l",
|
|
6257
|
+
ML: "ml",
|
|
6258
|
+
UN: "un",
|
|
6259
|
+
UND: "un",
|
|
6260
|
+
UNID: "un",
|
|
6261
|
+
UNI: "un",
|
|
6262
|
+
UNIDADE: "un"
|
|
6263
|
+
};
|
|
6264
|
+
function suggestedStockUnit(item, units, productUnits, productId) {
|
|
6265
|
+
const fromProduct = productId ? productUnits.get(productId) : void 0;
|
|
6266
|
+
if (fromProduct && units.some((u) => u.id === fromProduct)) return fromProduct;
|
|
6267
|
+
if (packagingCount(item.unit) !== null) return null;
|
|
6268
|
+
const code = NOTE_UNIT_CODES[String(item.unit ?? "").trim().toUpperCase().replace(/\d+$/, "")];
|
|
6269
|
+
return code ? units.find((u) => u.abbreviation.toLowerCase() === code)?.id ?? null : null;
|
|
6270
|
+
}
|
|
5707
6271
|
var draftOf = (item) => ({
|
|
5708
6272
|
productId: item.productId,
|
|
5709
6273
|
productLabel: "",
|
|
@@ -5728,6 +6292,7 @@ function NoteReconcileView({ noteId, onBack, onOpenInvoice, chrome = "page" }) {
|
|
|
5728
6292
|
const [defaultAccount, setDefaultAccount] = useState(null);
|
|
5729
6293
|
const [location, setLocation] = useState(null);
|
|
5730
6294
|
const [units, setUnits] = useState([]);
|
|
6295
|
+
const [productUnits, setProductUnits] = useState(() => /* @__PURE__ */ new Map());
|
|
5731
6296
|
const [accounts, setAccounts] = useState([]);
|
|
5732
6297
|
const [locations, setLocations] = useState([]);
|
|
5733
6298
|
const [saving, setSaving] = useState(false);
|
|
@@ -5741,6 +6306,8 @@ function NoteReconcileView({ noteId, onBack, onOpenInvoice, chrome = "page" }) {
|
|
|
5741
6306
|
const [suggesting, setSuggesting] = useState(false);
|
|
5742
6307
|
const [suggestionNote, setSuggestionNote] = useState(null);
|
|
5743
6308
|
const [pullOpen, setPullOpen] = useState(false);
|
|
6309
|
+
const [payable, setPayable] = useState(void 0);
|
|
6310
|
+
const [payableLost, setPayableLost] = useState(false);
|
|
5744
6311
|
const load = useCallback(async () => {
|
|
5745
6312
|
setLoading(true);
|
|
5746
6313
|
try {
|
|
@@ -5749,6 +6316,12 @@ function NoteReconcileView({ noteId, onBack, onOpenInvoice, chrome = "page" }) {
|
|
|
5749
6316
|
const linked = await linkInboxSupplier(noteId).catch(() => null);
|
|
5750
6317
|
if (linked?.supplierPartyId) detail = { ...detail, supplierPartyId: linked.supplierPartyId };
|
|
5751
6318
|
}
|
|
6319
|
+
if (detail && (detail.invoiceId || detail.stockedAt)) {
|
|
6320
|
+
const healed = await healInboxNote(noteId).catch(() => null);
|
|
6321
|
+
if (healed?.released) setPayableLost(true);
|
|
6322
|
+
if (healed?.changed) detail = await getInboxNote(noteId) ?? detail;
|
|
6323
|
+
}
|
|
6324
|
+
setPayable(detail?.invoiceId ? await getNotePayable(detail.invoiceId).catch(() => void 0) : void 0);
|
|
5752
6325
|
if (detail && detail.items.length === 0 && detail.hasXml && detail.status !== "rejected") {
|
|
5753
6326
|
const xml = await getInboxNoteXml(noteId).catch(() => null);
|
|
5754
6327
|
if (xml) {
|
|
@@ -5780,9 +6353,16 @@ function NoteReconcileView({ noteId, onBack, onOpenInvoice, chrome = "page" }) {
|
|
|
5780
6353
|
if (detail) {
|
|
5781
6354
|
const vinculados = [...new Set(detail.items.map((i) => i.productId).filter((id) => !!id))];
|
|
5782
6355
|
const nomes = vinculados.length ? new Map((await listProductsByIds(vinculados).catch(() => [])).map((p) => [p.id, p.name])) : /* @__PURE__ */ new Map();
|
|
6356
|
+
const unidadesDoProduto = await listProductStockUnits(vinculados).catch(() => /* @__PURE__ */ new Map());
|
|
6357
|
+
setProductUnits(unidadesDoProduto);
|
|
5783
6358
|
setDrafts(Object.fromEntries(detail.items.map((i) => [
|
|
5784
6359
|
i.id,
|
|
5785
|
-
{
|
|
6360
|
+
{
|
|
6361
|
+
...draftOf(i),
|
|
6362
|
+
productLabel: i.productId && nomes.get(i.productId) || "",
|
|
6363
|
+
// Stocked lines keep what was recorded; open ones get a unit instead of a blank.
|
|
6364
|
+
stockUnitId: i.stockUnitId ?? (i.stockMovementId ? null : suggestedStockUnit(i, u, unidadesDoProduto, i.productId))
|
|
6365
|
+
}
|
|
5786
6366
|
])));
|
|
5787
6367
|
setChecked(Object.fromEntries(detail.items.filter((i) => i.reconciled).map((i) => [i.id, true])));
|
|
5788
6368
|
const pending = detail.items.find((i) => !i.reconciled);
|
|
@@ -5850,11 +6430,18 @@ function NoteReconcileView({ noteId, onBack, onOpenInvoice, chrome = "page" }) {
|
|
|
5850
6430
|
const decisions = useMemo(() => buildDecisions(drafts), [buildDecisions, drafts]);
|
|
5851
6431
|
const stockLines = decisions.filter((d) => isStockBearing(d.entryType));
|
|
5852
6432
|
const missingProduct = stockLines.filter((d) => !d.productId).length;
|
|
6433
|
+
const missingUnit = stockLines.filter((d) => {
|
|
6434
|
+
const item = note?.items.find((i) => i.id === d.id);
|
|
6435
|
+
return !d.stockUnitId && !item?.stockMovementId;
|
|
6436
|
+
}).length;
|
|
5853
6437
|
const missingType = decisions.filter((d) => !d.entryType).length;
|
|
5854
6438
|
const suspectFactor = (item, d) => packagingCount(item.unit) !== null && isStockBearing(d.entryType) && ((Number(d.conversionFactor.replace(",", ".")) || 1) === 1 || !d.stockUnitId);
|
|
5855
6439
|
const unverifiedFactor = note ? note.items.filter((i) => suspectFactor(i, drafts[i.id] ?? draftOf(i))).length : 0;
|
|
5856
6440
|
const instalmentSum = instalments.reduce((acc, d) => acc + (Number(d.amount) || 0), 0);
|
|
5857
|
-
const
|
|
6441
|
+
const hasPayable = Boolean(note?.invoiceId);
|
|
6442
|
+
const pendingStock = (note?.items ?? []).some((i) => !i.stockMovementId && (!i.entryType || isStockBearing(i.entryType)));
|
|
6443
|
+
const readOnly = Boolean(note?.stockedAt || hasPayable && !pendingStock);
|
|
6444
|
+
const paymentLocked = readOnly || hasPayable;
|
|
5858
6445
|
const isReady = (item, d) => Boolean(d.entryType) && (!isStockBearing(d.entryType) || Boolean(d.productId)) && !suspectFactor(item, d);
|
|
5859
6446
|
const doneCount = note ? note.items.filter((i) => checked[i.id]).length : 0;
|
|
5860
6447
|
const toggleItem = (id) => setOpenIds((prev) => prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id]);
|
|
@@ -6109,11 +6696,12 @@ function NoteReconcileView({ noteId, onBack, onOpenInvoice, chrome = "page" }) {
|
|
|
6109
6696
|
const pendencias = [
|
|
6110
6697
|
unverifiedFactor > 0 && `${unverifiedFactor} com fator por conferir`,
|
|
6111
6698
|
missingType > 0 && `${missingType} sem tipo`,
|
|
6112
|
-
missingProduct > 0 && `${missingProduct} sem produto
|
|
6699
|
+
missingProduct > 0 && `${missingProduct} sem produto`,
|
|
6700
|
+
missingUnit > 0 && `${missingUnit} sem unidade de estoque`
|
|
6113
6701
|
].filter(Boolean).join(" \xB7 ");
|
|
6114
6702
|
const rodape = readOnly ? null : {
|
|
6115
6703
|
start: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
6116
|
-
/* @__PURE__ */ jsxs(
|
|
6704
|
+
!hasPayable && /* @__PURE__ */ jsxs(
|
|
6117
6705
|
Button,
|
|
6118
6706
|
{
|
|
6119
6707
|
variant: "ghost",
|
|
@@ -6146,10 +6734,10 @@ function NoteReconcileView({ noteId, onBack, onOpenInvoice, chrome = "page" }) {
|
|
|
6146
6734
|
onClick: () => {
|
|
6147
6735
|
void accept();
|
|
6148
6736
|
},
|
|
6149
|
-
disabled: accepting || saving || missingType > 0 || missingProduct > 0 || unverifiedFactor > 0,
|
|
6737
|
+
disabled: accepting || saving || missingType > 0 || missingProduct > 0 || missingUnit > 0 || unverifiedFactor > 0,
|
|
6150
6738
|
children: [
|
|
6151
6739
|
accepting ? /* @__PURE__ */ jsx(Loader2, { className: "mr-1.5 h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ jsx(Check, { className: "mr-1.5 h-3.5 w-3.5" }),
|
|
6152
|
-
"Aceitar"
|
|
6740
|
+
hasPayable ? "Dar entrada no estoque" : "Aceitar"
|
|
6153
6741
|
]
|
|
6154
6742
|
}
|
|
6155
6743
|
)
|
|
@@ -6158,9 +6746,35 @@ function NoteReconcileView({ noteId, onBack, onOpenInvoice, chrome = "page" }) {
|
|
|
6158
6746
|
return moldura(/* @__PURE__ */ jsxs("div", { className: `space-y-4 ${emModal ? "" : "pb-24"}`, children: [
|
|
6159
6747
|
cabecalho(`Concilia\xE7\xE3o \xB7 NF-e ${note.number}`),
|
|
6160
6748
|
accepted && /* @__PURE__ */ jsxs(Card, { className: "border-success bg-success-soft p-4", children: [
|
|
6161
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-success-soft-foreground", children: accepted.alreadyAccepted ? "Esta nota j\xE1 havia sido aceita \u2014 nada foi lan\xE7ado de novo." : `Aceita: ${accepted.stockLines} ${accepted.stockLines === 1 ? "linha" : "linhas"} de estoque e um t\xEDtulo de ${money3(accepted.invoiceTotal)} em ${accepted.instalments} ${accepted.instalments === 1 ? "parcela" : "parcelas"}.` }),
|
|
6749
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-success-soft-foreground", children: accepted.alreadyAccepted ? "Esta nota j\xE1 havia sido aceita \u2014 nada foi lan\xE7ado de novo." : accepted.instalments === 0 ? `Entrada no estoque: ${accepted.stockLines} ${accepted.stockLines === 1 ? "linha" : "linhas"}, ligadas \xE0 conta a pagar que a nota j\xE1 tinha (${money3(accepted.invoiceTotal)}).` : `Aceita: ${accepted.stockLines} ${accepted.stockLines === 1 ? "linha" : "linhas"} de estoque e um t\xEDtulo de ${money3(accepted.invoiceTotal)} em ${accepted.instalments} ${accepted.instalments === 1 ? "parcela" : "parcelas"}.` }),
|
|
6162
6750
|
accepted.invoiceId && onOpenInvoice && /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", className: "mt-2", onClick: () => onOpenInvoice(accepted.invoiceId), children: "Abrir a conta a pagar" })
|
|
6163
6751
|
] }),
|
|
6752
|
+
payableLost && !readOnly && /* @__PURE__ */ jsxs(Card, { className: "border-warning bg-warning-soft p-4", "data-testid": "note-payable-lost", children: [
|
|
6753
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-warning-soft-foreground", children: "A conta a pagar e a entrada no estoque desta nota foram apagadas fora daqui." }),
|
|
6754
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-warning-soft-foreground", children: "Confira a concilia\xE7\xE3o e clique em Aceitar para lan\xE7ar as duas de novo." })
|
|
6755
|
+
] }),
|
|
6756
|
+
!accepted && /* @__PURE__ */ jsxs(Card, { className: "p-4", "data-testid": "note-postings", children: [
|
|
6757
|
+
/* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold", children: "Lan\xE7amentos desta nota" }),
|
|
6758
|
+
/* @__PURE__ */ jsxs("dl", { className: "mt-3 grid gap-x-6 gap-y-3 text-sm sm:grid-cols-2", children: [
|
|
6759
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
6760
|
+
/* @__PURE__ */ jsx("dt", { className: "text-xs text-muted-foreground", children: "Conta a pagar" }),
|
|
6761
|
+
/* @__PURE__ */ jsxs("dd", { className: "mt-0.5 flex flex-wrap items-center gap-2", children: [
|
|
6762
|
+
!note.invoiceId && /* @__PURE__ */ jsx("span", { className: payableLost ? "text-destructive" : "text-muted-foreground", children: payableLost ? "N\xE3o existe mais \u2014 foi apagada; aceite a nota para lan\xE7ar de novo" : readOnly ? "Nenhuma \u2014 esta nota n\xE3o abriu conta a pagar" : "Ainda n\xE3o lan\xE7ada \u2014 nasce quando a nota for aceita" }),
|
|
6763
|
+
note.invoiceId && payable === null && /* @__PURE__ */ jsx("span", { className: "text-destructive", children: "N\xE3o encontrada \u2014 a conta foi apagada" }),
|
|
6764
|
+
payable && /* @__PURE__ */ jsxs("span", { "data-testid": "note-payable-link", children: [
|
|
6765
|
+
onOpenInvoice ? /* @__PURE__ */ jsx(InlineLink, { onClick: () => onOpenInvoice(payable.id), children: payable.number ?? "Conta a pagar" }) : payable.number ?? "Conta a pagar",
|
|
6766
|
+
" \xB7 ",
|
|
6767
|
+
money3(payable.total),
|
|
6768
|
+
payable.cancelledAt && /* @__PURE__ */ jsx("span", { className: "text-destructive", children: " \xB7 cancelada" })
|
|
6769
|
+
] })
|
|
6770
|
+
] })
|
|
6771
|
+
] }),
|
|
6772
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
6773
|
+
/* @__PURE__ */ jsx("dt", { className: "text-xs text-muted-foreground", children: "Estoque" }),
|
|
6774
|
+
/* @__PURE__ */ jsx("dd", { className: "mt-0.5", children: note.stockedAt ? `Entrada em ${day3(note.stockedAt)}` : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: readOnly ? "Sem entrada no estoque" : hasPayable ? "Ainda sem entrada \u2014 conclua a concilia\xE7\xE3o e d\xEA entrada" : "Ainda sem entrada \u2014 entra quando a nota for aceita" }) })
|
|
6775
|
+
] })
|
|
6776
|
+
] })
|
|
6777
|
+
] }),
|
|
6164
6778
|
/* @__PURE__ */ jsxs(Card, { className: "p-4", children: [
|
|
6165
6779
|
/* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold", children: "Situa\xE7\xE3o fiscal" }),
|
|
6166
6780
|
/* @__PURE__ */ jsxs("dl", { className: "mt-3 grid gap-x-6 gap-y-2 text-sm sm:grid-cols-2 lg:grid-cols-3", children: [
|
|
@@ -6290,10 +6904,12 @@ function NoteReconcileView({ noteId, onBack, onOpenInvoice, chrome = "page" }) {
|
|
|
6290
6904
|
suggestionNote && /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2 rounded-md border border-magic/30 bg-magic-soft px-3 py-2", children: [
|
|
6291
6905
|
/* @__PURE__ */ jsx("p", { className: "flex-1 text-xs text-magic-soft-foreground", children: suggestionNote }),
|
|
6292
6906
|
/* @__PURE__ */ jsx(
|
|
6293
|
-
|
|
6907
|
+
Button,
|
|
6294
6908
|
{
|
|
6909
|
+
variant: "bare",
|
|
6910
|
+
size: "bare",
|
|
6295
6911
|
type: "button",
|
|
6296
|
-
className: "shrink-0 text-xs text-magic-soft-foreground/70 hover:underline",
|
|
6912
|
+
className: "shrink-0 text-xs text-magic-soft-foreground/70 hover:underline font-normal",
|
|
6297
6913
|
onClick: () => setSuggestionNote(null),
|
|
6298
6914
|
children: "Fechar"
|
|
6299
6915
|
}
|
|
@@ -6332,12 +6948,14 @@ function NoteReconcileView({ noteId, onBack, onOpenInvoice, chrome = "page" }) {
|
|
|
6332
6948
|
const typeLabel = ENTRY_TYPES.find((t) => t.value === d.entryType)?.label;
|
|
6333
6949
|
return /* @__PURE__ */ jsxs(Card, { className: "overflow-hidden", children: [
|
|
6334
6950
|
/* @__PURE__ */ jsxs(
|
|
6335
|
-
|
|
6951
|
+
Button,
|
|
6336
6952
|
{
|
|
6953
|
+
variant: "bare",
|
|
6954
|
+
size: "bare",
|
|
6337
6955
|
type: "button",
|
|
6338
6956
|
onClick: () => toggleItem(item.id),
|
|
6339
6957
|
"aria-expanded": open,
|
|
6340
|
-
className: "flex w-full items-center gap-3 px-4 py-3 text-left transition-colors hover:bg-muted/30",
|
|
6958
|
+
className: "flex w-full items-center justify-start gap-3 rounded-none px-4 py-3 text-left font-normal transition-colors hover:bg-muted/30",
|
|
6341
6959
|
children: [
|
|
6342
6960
|
/* @__PURE__ */ jsx(
|
|
6343
6961
|
ChevronRight,
|
|
@@ -6388,12 +7006,14 @@ function NoteReconcileView({ noteId, onBack, onOpenInvoice, chrome = "page" }) {
|
|
|
6388
7006
|
/* @__PURE__ */ jsxs("label", { className: "block", children: [
|
|
6389
7007
|
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Tipo do registro" }),
|
|
6390
7008
|
/* @__PURE__ */ jsx("div", { className: "mt-1 flex flex-wrap gap-1", children: ENTRY_TYPES.map((t) => /* @__PURE__ */ jsxs(
|
|
6391
|
-
|
|
7009
|
+
Button,
|
|
6392
7010
|
{
|
|
7011
|
+
variant: "bare",
|
|
7012
|
+
size: "bare",
|
|
6393
7013
|
type: "button",
|
|
6394
7014
|
disabled: readOnly,
|
|
6395
7015
|
onClick: () => patch(item.id, { entryType: t.value }),
|
|
6396
|
-
className: `rounded-full border px-2.5 py-1 text-[11px] transition-colors disabled:opacity-60 ${d.entryType === t.value ? "border-primary bg-primary text-primary-foreground" : "border-input hover:bg-muted"}`,
|
|
7016
|
+
className: `gap-0 font-normal rounded-full border px-2.5 py-1 text-[11px] transition-colors disabled:opacity-60 ${d.entryType === t.value ? "border-primary bg-primary text-primary-foreground" : "border-input hover:bg-muted"}`,
|
|
6397
7017
|
children: [
|
|
6398
7018
|
t.label,
|
|
6399
7019
|
t.hint && /* @__PURE__ */ jsxs("span", { className: "ml-1 opacity-70", children: [
|
|
@@ -6413,7 +7033,17 @@ function NoteReconcileView({ noteId, onBack, onOpenInvoice, chrome = "page" }) {
|
|
|
6413
7033
|
{
|
|
6414
7034
|
value: d.productId ?? void 0,
|
|
6415
7035
|
displayValue: d.productLabel || void 0,
|
|
6416
|
-
onChange: (id, option) =>
|
|
7036
|
+
onChange: (id, option) => {
|
|
7037
|
+
patch(item.id, { productId: id || null, productLabel: option?.label ?? "" });
|
|
7038
|
+
if (id && !d.stockUnitId) {
|
|
7039
|
+
void listProductStockUnits([id]).then((m) => {
|
|
7040
|
+
setProductUnits((prev) => new Map([...prev, ...m]));
|
|
7041
|
+
const unit = suggestedStockUnit(item, units, m, id);
|
|
7042
|
+
if (unit) patch(item.id, { stockUnitId: unit });
|
|
7043
|
+
}).catch(() => {
|
|
7044
|
+
});
|
|
7045
|
+
}
|
|
7046
|
+
},
|
|
6417
7047
|
onSearch: async (term) => {
|
|
6418
7048
|
const found = await searchProducts(term || item.description.slice(0, 24));
|
|
6419
7049
|
return found.map((prod) => ({
|
|
@@ -6454,7 +7084,7 @@ function NoteReconcileView({ noteId, onBack, onOpenInvoice, chrome = "page" }) {
|
|
|
6454
7084
|
displayValue: labelOf(unitOptions, d.stockUnitId),
|
|
6455
7085
|
onChange: (id) => patch(item.id, { stockUnitId: id || null }),
|
|
6456
7086
|
minChars: 0,
|
|
6457
|
-
placeholder: "
|
|
7087
|
+
placeholder: "Escolha a unidade",
|
|
6458
7088
|
noResultsLabel: "Nenhuma unidade",
|
|
6459
7089
|
searchingLabel: "Buscando\u2026",
|
|
6460
7090
|
clearLabel: "Limpar",
|
|
@@ -6517,12 +7147,14 @@ function NoteReconcileView({ noteId, onBack, onOpenInvoice, chrome = "page" }) {
|
|
|
6517
7147
|
/* @__PURE__ */ jsxs("label", { className: "block", children: [
|
|
6518
7148
|
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Modo de custo" }),
|
|
6519
7149
|
/* @__PURE__ */ jsx("div", { className: "mt-1 flex gap-1", children: ["novo", "media"].map((mode) => /* @__PURE__ */ jsx(
|
|
6520
|
-
|
|
7150
|
+
Button,
|
|
6521
7151
|
{
|
|
7152
|
+
variant: "bare",
|
|
7153
|
+
size: "bare",
|
|
6522
7154
|
type: "button",
|
|
6523
7155
|
disabled: readOnly,
|
|
6524
7156
|
onClick: () => patch(item.id, { costMode: mode }),
|
|
6525
|
-
className: `flex-1 rounded-md border px-2 py-1 text-[11px] disabled:opacity-60 ${d.costMode === mode ? "border-primary bg-primary/10" : "border-input hover:bg-muted"}`,
|
|
7157
|
+
className: `font-normal flex-1 rounded-md border px-2 py-1 text-[11px] disabled:opacity-60 ${d.costMode === mode ? "border-primary bg-primary/10" : "border-input hover:bg-muted"}`,
|
|
6526
7158
|
children: mode === "novo" ? "Novo" : "M\xE9dia"
|
|
6527
7159
|
},
|
|
6528
7160
|
mode
|
|
@@ -6606,7 +7238,7 @@ function NoteReconcileView({ noteId, onBack, onOpenInvoice, chrome = "page" }) {
|
|
|
6606
7238
|
/* @__PURE__ */ jsx("span", { className: "pb-2 text-xs tabular-nums text-muted-foreground", children: inst.index }),
|
|
6607
7239
|
/* @__PURE__ */ jsxs("label", { className: "block", children: [
|
|
6608
7240
|
/* @__PURE__ */ jsx("span", { className: "text-[11px] text-muted-foreground", children: "Vencimento" }),
|
|
6609
|
-
|
|
7241
|
+
paymentLocked ? /* @__PURE__ */ jsx("p", { className: "py-2 text-sm tabular-nums", children: day3(inst.dueDate) }) : /* @__PURE__ */ jsx(
|
|
6610
7242
|
DatePicker,
|
|
6611
7243
|
{
|
|
6612
7244
|
value: inst.dueDate ?? "",
|
|
@@ -6621,7 +7253,7 @@ function NoteReconcileView({ noteId, onBack, onOpenInvoice, chrome = "page" }) {
|
|
|
6621
7253
|
{
|
|
6622
7254
|
value: String(inst.amount),
|
|
6623
7255
|
inputMode: "decimal",
|
|
6624
|
-
disabled:
|
|
7256
|
+
disabled: paymentLocked,
|
|
6625
7257
|
onChange: (e) => setInstalments((prev) => prev.map((p, j) => j === i ? { ...p, amount: Number(e.target.value.replace(",", ".")) || 0 } : p))
|
|
6626
7258
|
}
|
|
6627
7259
|
)
|
|
@@ -6632,12 +7264,12 @@ function NoteReconcileView({ noteId, onBack, onOpenInvoice, chrome = "page" }) {
|
|
|
6632
7264
|
Input,
|
|
6633
7265
|
{
|
|
6634
7266
|
value: inst.barcode ?? inst.pixKey ?? "",
|
|
6635
|
-
disabled:
|
|
7267
|
+
disabled: paymentLocked,
|
|
6636
7268
|
onChange: (e) => setInstalments((prev) => prev.map((p, j) => j === i ? { ...p, barcode: e.target.value } : p))
|
|
6637
7269
|
}
|
|
6638
7270
|
)
|
|
6639
7271
|
] }),
|
|
6640
|
-
!
|
|
7272
|
+
!paymentLocked && /* @__PURE__ */ jsx(
|
|
6641
7273
|
Button,
|
|
6642
7274
|
{
|
|
6643
7275
|
variant: "ghost",
|
|
@@ -6648,7 +7280,7 @@ function NoteReconcileView({ noteId, onBack, onOpenInvoice, chrome = "page" }) {
|
|
|
6648
7280
|
}
|
|
6649
7281
|
)
|
|
6650
7282
|
] }, i)) }),
|
|
6651
|
-
!
|
|
7283
|
+
!paymentLocked && /* @__PURE__ */ jsxs(
|
|
6652
7284
|
Button,
|
|
6653
7285
|
{
|
|
6654
7286
|
variant: "outline",
|
|
@@ -6716,132 +7348,20 @@ function Field({ label, value, mono, small }) {
|
|
|
6716
7348
|
/* @__PURE__ */ jsx("dd", { className: `${mono ? "tabular-nums" : ""} ${small ? "text-xs" : "text-sm"}`, children: value })
|
|
6717
7349
|
] });
|
|
6718
7350
|
}
|
|
6719
|
-
var money4 = (v) => new Intl.NumberFormat("pt-BR", { style: "currency", currency: "BRL" }).format(v || 0);
|
|
6720
|
-
var day4 = (iso) => iso ? iso.slice(0, 10).split("-").reverse().join("/") : "\u2014";
|
|
6721
|
-
var MANIFEST_TONE = {
|
|
6722
|
-
confirmada: "bg-success-soft text-success-soft-foreground",
|
|
6723
|
-
processando: "bg-info-soft text-info-soft-foreground",
|
|
6724
|
-
erro: "bg-destructive/10 text-destructive"
|
|
6725
|
-
};
|
|
6726
|
-
function ManifestView({ onOpenNote, onBack }) {
|
|
6727
|
-
const [notes, setNotes] = useState([]);
|
|
6728
|
-
const [loading, setLoading] = useState(true);
|
|
6729
|
-
const [tab, setTab] = useState("pendentes");
|
|
6730
|
-
const [pullOpen, setPullOpen] = useState(false);
|
|
6731
|
-
const reload = useCallback(async () => {
|
|
6732
|
-
setLoading(true);
|
|
6733
|
-
try {
|
|
6734
|
-
setNotes(await listInboxNotes({ filter: "all", limit: 300 }));
|
|
6735
|
-
} finally {
|
|
6736
|
-
setLoading(false);
|
|
6737
|
-
}
|
|
6738
|
-
}, []);
|
|
6739
|
-
useEffect(() => {
|
|
6740
|
-
void reload();
|
|
6741
|
-
}, [reload]);
|
|
6742
|
-
const shown = useMemo(() => notes.filter((n) => {
|
|
6743
|
-
const status = n.manifestationStatus ?? "";
|
|
6744
|
-
if (tab === "todas") return true;
|
|
6745
|
-
if (tab === "confirmadas") return status === "confirmada";
|
|
6746
|
-
if (tab === "erro") return status === "erro";
|
|
6747
|
-
return status !== "confirmada";
|
|
6748
|
-
}), [notes, tab]);
|
|
6749
|
-
const pending = notes.filter((n) => (n.manifestationStatus ?? "") !== "confirmada").length;
|
|
6750
|
-
const filters = useMemo(() => [{
|
|
6751
|
-
id: "manifestacao",
|
|
6752
|
-
label: "Manifesta\xE7\xE3o",
|
|
6753
|
-
allLabel: "Todas",
|
|
6754
|
-
value: tab === "todas" ? void 0 : tab,
|
|
6755
|
-
onChange: (v) => setTab(v ?? "todas"),
|
|
6756
|
-
options: [
|
|
6757
|
-
{ value: "pendentes", label: "Pendentes" },
|
|
6758
|
-
{ value: "confirmadas", label: "Confirmadas" },
|
|
6759
|
-
{ value: "erro", label: "Com erro" }
|
|
6760
|
-
]
|
|
6761
|
-
}], [tab]);
|
|
6762
|
-
return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
|
|
6763
|
-
onBack && /* @__PURE__ */ jsx(SubpageHeader, { title: "Fila da SEFAZ", onBack, parentLabel: "Manifesto de Notas" }),
|
|
6764
|
-
/* @__PURE__ */ jsxs(Card, { className: "p-4", children: [
|
|
6765
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
|
|
6766
|
-
/* @__PURE__ */ jsx(ShieldCheck, { className: "mt-0.5 h-5 w-5 text-muted-foreground", "aria-hidden": true }),
|
|
6767
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
6768
|
-
/* @__PURE__ */ jsxs("p", { className: "text-sm font-medium", children: [
|
|
6769
|
-
pending,
|
|
6770
|
-
" ",
|
|
6771
|
-
pending === 1 ? "nota aguardando" : "notas aguardando",
|
|
6772
|
-
" manifesta\xE7\xE3o \xE0 SEFAZ"
|
|
6773
|
-
] }),
|
|
6774
|
-
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Manifestar responde \xE0 SEFAZ e tem prazo. Dar entrada responde ao seu estoque e ao financeiro \u2014 s\xE3o duas filas." })
|
|
6775
|
-
] })
|
|
6776
|
-
] }),
|
|
6777
|
-
/* @__PURE__ */ jsx(Hint, { className: "mt-3", children: /* @__PURE__ */ jsx("span", { children: "A manifesta\xE7\xE3o continua sendo feita no sistema antigo por enquanto. Aqui voc\xEA l\xEA a fila e o que a SEFAZ respondeu; a entrada no estoque e a conta a pagar j\xE1 s\xE3o feitas nesta tela nova." }) }),
|
|
6778
|
-
/* @__PURE__ */ jsxs("div", { className: "mt-3 flex flex-wrap gap-2", children: [
|
|
6779
|
-
/* @__PURE__ */ jsx(EmBreve, { label: "Aceitar / Recusar", o_que: "Responder \xE0 SEFAZ \u2014 \xE9 obriga\xE7\xE3o com prazo. Hoje a manifesta\xE7\xE3o \xE9 feita no sistema antigo" }),
|
|
6780
|
-
/* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", onClick: () => setPullOpen(true), children: [
|
|
6781
|
-
/* @__PURE__ */ jsx(KeyRound, { className: "mr-1.5 h-4 w-4" }),
|
|
6782
|
-
"Puxar por chave"
|
|
6783
|
-
] }),
|
|
6784
|
-
/* @__PURE__ */ jsx(EmBreve, { label: "Sincronizar agora", o_que: "Pedir \xE0 SEFAZ o que chegou desde a \xFAltima varredura" }),
|
|
6785
|
-
/* @__PURE__ */ jsx(EmBreve, { label: "Resincronizar tudo", o_que: "Refazer a varredura inteira do per\xEDodo" }),
|
|
6786
|
-
/* @__PURE__ */ jsx(EmBreve, { label: "Diagnosticar", o_que: "Por que uma nota n\xE3o chegou: certificado, credencial ou cursor parado" })
|
|
6787
|
-
] })
|
|
6788
|
-
] }),
|
|
6789
|
-
/* @__PURE__ */ jsx(PullByKeyDialog, { open: pullOpen, onOpenChange: setPullOpen, onPulled: (r) => {
|
|
6790
|
-
void reload();
|
|
6791
|
-
onOpenNote(r.documentId);
|
|
6792
|
-
} }),
|
|
6793
|
-
/* @__PURE__ */ jsx(ListFilterBar, { filters, onClear: () => setTab("todas"), activeCount: tab === "todas" ? 0 : 1 }),
|
|
6794
|
-
loading ? /* @__PURE__ */ jsx("div", { className: "space-y-2", children: [0, 1, 2].map((i) => /* @__PURE__ */ jsx(Skeleton, { className: "h-12 w-full" }, i)) }) : shown.length === 0 ? /* @__PURE__ */ jsxs(Card, { className: "p-10 text-center", children: [
|
|
6795
|
-
/* @__PURE__ */ jsx(FileText, { className: "mx-auto h-8 w-8 text-muted-foreground", "aria-hidden": true }),
|
|
6796
|
-
/* @__PURE__ */ jsx("p", { className: "mt-2 text-sm font-medium", children: "Nenhuma nota nesta fila" })
|
|
6797
|
-
] }) : /* @__PURE__ */ jsx(Card, { className: "overflow-hidden", children: /* @__PURE__ */ jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs("table", { className: "w-full text-sm", children: [
|
|
6798
|
-
/* @__PURE__ */ jsx("thead", { className: "border-b bg-muted/40 text-xs text-muted-foreground", children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
6799
|
-
/* @__PURE__ */ jsx("th", { className: "px-3 py-2 text-left font-medium", children: "Emiss\xE3o" }),
|
|
6800
|
-
/* @__PURE__ */ jsx("th", { className: "px-3 py-2 text-left font-medium", children: "N\xBA" }),
|
|
6801
|
-
/* @__PURE__ */ jsx("th", { className: "px-3 py-2 text-left font-medium", children: "Fornecedor" }),
|
|
6802
|
-
/* @__PURE__ */ jsx("th", { className: "px-3 py-2 text-right font-medium", children: "Valor" }),
|
|
6803
|
-
/* @__PURE__ */ jsx("th", { className: "px-3 py-2 text-right font-medium", children: "Parcelas" }),
|
|
6804
|
-
/* @__PURE__ */ jsx("th", { className: "px-3 py-2 text-center font-medium", children: "Manifesta\xE7\xE3o" }),
|
|
6805
|
-
/* @__PURE__ */ jsx("th", { className: "px-3 py-2 text-right font-medium", children: "A\xE7\xF5es" })
|
|
6806
|
-
] }) }),
|
|
6807
|
-
/* @__PURE__ */ jsx("tbody", { children: shown.map((note) => /* @__PURE__ */ jsxs("tr", { className: "border-b last:border-0 hover:bg-muted/30", children: [
|
|
6808
|
-
/* @__PURE__ */ jsx("td", { className: "px-3 py-2 tabular-nums text-muted-foreground", children: day4(note.issueDate) }),
|
|
6809
|
-
/* @__PURE__ */ jsx("td", { className: "px-3 py-2 tabular-nums font-medium", children: note.number }),
|
|
6810
|
-
/* @__PURE__ */ jsx("td", { className: "px-3 py-2", children: note.supplierName || "\u2014" }),
|
|
6811
|
-
/* @__PURE__ */ jsx("td", { className: "px-3 py-2 text-right tabular-nums", children: money4(note.total) }),
|
|
6812
|
-
/* @__PURE__ */ jsx("td", { className: "px-3 py-2 text-right tabular-nums text-muted-foreground", children: note.instalmentCount }),
|
|
6813
|
-
/* @__PURE__ */ jsx("td", { className: "px-3 py-2 text-center", children: /* @__PURE__ */ jsx("span", { className: `inline-flex items-center rounded-full px-2 py-0.5 text-[11px] font-medium ${MANIFEST_TONE[note.manifestationStatus ?? ""] ?? "bg-muted text-muted-foreground"}`, children: note.manifestationStatus ?? "n\xE3o manifestada" }) }),
|
|
6814
|
-
/* @__PURE__ */ jsx("td", { className: "px-3 py-2", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-1.5", children: [
|
|
6815
|
-
/* @__PURE__ */ jsx(EmBreve, { label: "XML", o_que: "Ver o XML bruto autorizado desta nota" }),
|
|
6816
|
-
/* @__PURE__ */ jsx(EmBreve, { label: "PDF", o_que: "Abrir o DANFE desta nota" }),
|
|
6817
|
-
/* @__PURE__ */ jsxs(Button, { size: "sm", variant: "outline", onClick: () => onOpenNote(note.id), children: [
|
|
6818
|
-
"Abrir concilia\xE7\xE3o",
|
|
6819
|
-
/* @__PURE__ */ jsx(ExternalLink, { className: "ml-1.5 h-3.5 w-3.5" })
|
|
6820
|
-
] })
|
|
6821
|
-
] }) })
|
|
6822
|
-
] }, note.id)) })
|
|
6823
|
-
] }) }) })
|
|
6824
|
-
] });
|
|
6825
|
-
}
|
|
6826
7351
|
var HASH_PREFIX = "#/inbound-notes";
|
|
6827
7352
|
function viewFromLocation() {
|
|
6828
7353
|
if (typeof window === "undefined") return { kind: "list" };
|
|
6829
7354
|
const hash = window.location.hash;
|
|
6830
7355
|
const note = hash.match(/\/inbound-notes\/note\/([0-9a-f-]{36})/i);
|
|
6831
7356
|
if (note) return { kind: "note", id: note[1] };
|
|
6832
|
-
if (/\/inbound-notes\/manifest/.test(hash)) return { kind: "manifest" };
|
|
6833
7357
|
return { kind: "list" };
|
|
6834
7358
|
}
|
|
6835
|
-
var pathOf = (view) => view.kind === "note" ? `${HASH_PREFIX}/note/${view.id}` :
|
|
7359
|
+
var pathOf = (view) => view.kind === "note" ? `${HASH_PREFIX}/note/${view.id}` : HASH_PREFIX;
|
|
6836
7360
|
var STACK_MARK = { inboundNotes: true };
|
|
6837
|
-
function InboundNotesPage({ payableRoute } = {}) {
|
|
7361
|
+
function InboundNotesPage({ payableRoute = (id) => `/financial/payables/${id}` } = {}) {
|
|
6838
7362
|
const [view, setView] = useState(viewFromLocation);
|
|
6839
|
-
const [background, setBackground] = useState(
|
|
6840
|
-
() => viewFromLocation().kind === "manifest" ? "manifest" : "list"
|
|
6841
|
-
);
|
|
6842
7363
|
const go = useCallback((next) => {
|
|
6843
7364
|
setView(next);
|
|
6844
|
-
if (next.kind !== "note") setBackground(next.kind);
|
|
6845
7365
|
if (typeof window === "undefined") return;
|
|
6846
7366
|
const path = pathOf(next);
|
|
6847
7367
|
if (window.location.hash === path) return;
|
|
@@ -6858,7 +7378,6 @@ function InboundNotesPage({ payableRoute } = {}) {
|
|
|
6858
7378
|
const onPop = () => {
|
|
6859
7379
|
const next = viewFromLocation();
|
|
6860
7380
|
setView(next);
|
|
6861
|
-
if (next.kind !== "note") setBackground(next.kind);
|
|
6862
7381
|
};
|
|
6863
7382
|
window.addEventListener("popstate", onPop);
|
|
6864
7383
|
window.addEventListener("hashchange", onPop);
|
|
@@ -6867,7 +7386,7 @@ function InboundNotesPage({ payableRoute } = {}) {
|
|
|
6867
7386
|
window.removeEventListener("hashchange", onPop);
|
|
6868
7387
|
};
|
|
6869
7388
|
}, []);
|
|
6870
|
-
const fecharNota = useCallback(() => go({ kind:
|
|
7389
|
+
const fecharNota = useCallback(() => go({ kind: "list" }), [go]);
|
|
6871
7390
|
useEffect(() => {
|
|
6872
7391
|
if (typeof window === "undefined") return;
|
|
6873
7392
|
const op = window.location.hash.match(/[?&]operation=([0-9a-f-]{36})/i)?.[1];
|
|
@@ -6882,13 +7401,7 @@ function InboundNotesPage({ payableRoute } = {}) {
|
|
|
6882
7401
|
};
|
|
6883
7402
|
}, [go]);
|
|
6884
7403
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
6885
|
-
|
|
6886
|
-
InboundNotesView,
|
|
6887
|
-
{
|
|
6888
|
-
onOpenNote: (id) => go({ kind: "note", id }),
|
|
6889
|
-
onOpenManifest: () => go({ kind: "manifest" })
|
|
6890
|
-
}
|
|
6891
|
-
),
|
|
7404
|
+
/* @__PURE__ */ jsx(InboundNotesView, { onOpenNote: (id) => go({ kind: "note", id }) }),
|
|
6892
7405
|
/* @__PURE__ */ jsx(Modal, { open: view.kind === "note", onOpenChange: (open) => {
|
|
6893
7406
|
if (!open) fecharNota();
|
|
6894
7407
|
}, children: view.kind === "note" && // `noPadding`: a conciliação desenha o próprio cabeçalho e o próprio
|
|
@@ -6940,13 +7453,31 @@ var COLUMNS = [
|
|
|
6940
7453
|
"certificate_uploaded_at",
|
|
6941
7454
|
"dfe_sync_enabled",
|
|
6942
7455
|
"dfe_last_sync_at",
|
|
7456
|
+
"dfe_last_error",
|
|
6943
7457
|
"provider_synced_at"
|
|
6944
7458
|
].join(", ");
|
|
6945
7459
|
var sb2 = () => getSupabaseClientOptional();
|
|
7460
|
+
async function uploadCertificate(legalEntityId, file, password) {
|
|
7461
|
+
const buf = new Uint8Array(await file.arrayBuffer());
|
|
7462
|
+
let bin = "";
|
|
7463
|
+
for (let i = 0; i < buf.length; i++) bin += String.fromCharCode(buf[i]);
|
|
7464
|
+
const { data, error } = await sb2().functions.invoke("fiscalbr-certificate", {
|
|
7465
|
+
body: { legalEntityId, pfxBase64: btoa(bin), password, fileName: file.name, tenantId: getActiveTenantId$1() ?? null }
|
|
7466
|
+
});
|
|
7467
|
+
if (error) {
|
|
7468
|
+
let body = null;
|
|
7469
|
+
try {
|
|
7470
|
+
body = await error?.context?.json?.();
|
|
7471
|
+
} catch {
|
|
7472
|
+
}
|
|
7473
|
+
throw new Error(body?.error || error.message || "Falha ao falar com o servi\xE7o fiscal.");
|
|
7474
|
+
}
|
|
7475
|
+
return data;
|
|
7476
|
+
}
|
|
6946
7477
|
function useEmitterSettings(legalEntityId) {
|
|
6947
|
-
const [row, setRow] =
|
|
6948
|
-
const [loading, setLoading] =
|
|
6949
|
-
|
|
7478
|
+
const [row, setRow] = React6.useState(null);
|
|
7479
|
+
const [loading, setLoading] = React6.useState(true);
|
|
7480
|
+
React6.useEffect(() => {
|
|
6950
7481
|
if (!legalEntityId) {
|
|
6951
7482
|
setLoading(false);
|
|
6952
7483
|
return;
|
|
@@ -6962,7 +7493,7 @@ function useEmitterSettings(legalEntityId) {
|
|
|
6962
7493
|
alive = false;
|
|
6963
7494
|
};
|
|
6964
7495
|
}, [legalEntityId]);
|
|
6965
|
-
const save =
|
|
7496
|
+
const save = React6.useCallback(async (tenantId, patch) => {
|
|
6966
7497
|
if (!legalEntityId) return false;
|
|
6967
7498
|
const payload = { ...patch, tenant_id: tenantId, legal_entity_id: legalEntityId, updated_at: (/* @__PURE__ */ new Date()).toISOString() };
|
|
6968
7499
|
const { data, error } = await sb2().from("plg_fiscalbr_emitter_settings").upsert(payload, { onConflict: "legal_entity_id" }).select(COLUMNS).single();
|
|
@@ -6973,7 +7504,7 @@ function useEmitterSettings(legalEntityId) {
|
|
|
6973
7504
|
setRow(data);
|
|
6974
7505
|
return true;
|
|
6975
7506
|
}, [legalEntityId]);
|
|
6976
|
-
return { row, loading, save };
|
|
7507
|
+
return { row, loading, save, setRow };
|
|
6977
7508
|
}
|
|
6978
7509
|
function NeedsLegalEntity({ item, what }) {
|
|
6979
7510
|
return /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsxs(CardContent, { className: "flex flex-col items-start gap-3 py-6", children: [
|
|
@@ -7015,7 +7546,7 @@ function SummaryCard({ title, lines, badge, onConfigure }) {
|
|
|
7015
7546
|
return /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsxs(CardHeader, { className: "flex-row items-start justify-between gap-3 space-y-0", children: [
|
|
7016
7547
|
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
7017
7548
|
/* @__PURE__ */ jsx(CardTitle, { className: "text-base", children: title }),
|
|
7018
|
-
/* @__PURE__ */ jsx("dl", { className: "mt-2 grid gap-x-6 gap-y-1 text-sm", style: { gridTemplateColumns: "auto 1fr" }, children: lines.map((l) => /* @__PURE__ */ jsxs(
|
|
7549
|
+
/* @__PURE__ */ jsx("dl", { className: "mt-2 grid gap-x-6 gap-y-1 text-sm", style: { gridTemplateColumns: "auto 1fr" }, children: lines.map((l) => /* @__PURE__ */ jsxs(React6.Fragment, { children: [
|
|
7019
7550
|
/* @__PURE__ */ jsx("dt", { className: "text-muted-foreground", children: l.label }),
|
|
7020
7551
|
/* @__PURE__ */ jsx("dd", { className: "text-foreground", children: l.value })
|
|
7021
7552
|
] }, l.label)) })
|
|
@@ -7035,8 +7566,15 @@ function SummaryCard({ title, lines, badge, onConfigure }) {
|
|
|
7035
7566
|
}
|
|
7036
7567
|
var fmtDateTime = (v) => v ? new Date(v).toLocaleString("pt-BR") : null;
|
|
7037
7568
|
function UnitCertificateWidget({ item }) {
|
|
7038
|
-
const { row, loading, save } = useEmitterSettings(item?.legalEntityId);
|
|
7039
|
-
const [open, setOpen] =
|
|
7569
|
+
const { row, loading, save, setRow } = useEmitterSettings(item?.legalEntityId);
|
|
7570
|
+
const [open, setOpen] = React6.useState(false);
|
|
7571
|
+
const [file, setFile] = React6.useState(null);
|
|
7572
|
+
const [password, setPassword] = React6.useState("");
|
|
7573
|
+
const [sending, setSending] = React6.useState(false);
|
|
7574
|
+
const expiredNow = !!row?.certificate_expires_at && Date.parse(row.certificate_expires_at) < Date.now();
|
|
7575
|
+
React6.useEffect(() => {
|
|
7576
|
+
if (expiredNow) setOpen(true);
|
|
7577
|
+
}, [expiredNow]);
|
|
7040
7578
|
if (!item?.id) return null;
|
|
7041
7579
|
if (!item.legalEntityId) return /* @__PURE__ */ jsx(NeedsLegalEntity, { item, what: "O certificado digital" });
|
|
7042
7580
|
if (loading || !row) return /* @__PURE__ */ jsx(LoadingCard, {});
|
|
@@ -7104,10 +7642,55 @@ function UnitCertificateWidget({ item }) {
|
|
|
7104
7642
|
hasCertificate && /* @__PURE__ */ jsx(Badge, { variant: expired ? "destructive" : "secondary", children: expired ? "Vencido" : "Ativo" })
|
|
7105
7643
|
] }),
|
|
7106
7644
|
/* @__PURE__ */ jsx("div", { className: "fz-container", children: /* @__PURE__ */ jsxs("div", { className: "fz-fields fz-fields-2 gap-4", children: [
|
|
7107
|
-
/* @__PURE__ */ jsx(Field2, { label: "Arquivo (.pfx)", children: /* @__PURE__ */ jsx(
|
|
7108
|
-
|
|
7645
|
+
/* @__PURE__ */ jsx(Field2, { label: "Arquivo (.pfx)", children: /* @__PURE__ */ jsx(
|
|
7646
|
+
Input,
|
|
7647
|
+
{
|
|
7648
|
+
type: "file",
|
|
7649
|
+
accept: ".pfx,.p12,application/x-pkcs12",
|
|
7650
|
+
"data-testid": "certificate-file",
|
|
7651
|
+
onChange: (e) => setFile(e.target.files?.[0] ?? null)
|
|
7652
|
+
}
|
|
7653
|
+
) }),
|
|
7654
|
+
/* @__PURE__ */ jsx(Field2, { label: "Senha do certificado", children: /* @__PURE__ */ jsx(
|
|
7655
|
+
Input,
|
|
7656
|
+
{
|
|
7657
|
+
type: "password",
|
|
7658
|
+
autoComplete: "new-password",
|
|
7659
|
+
name: "pfx-password",
|
|
7660
|
+
value: password,
|
|
7661
|
+
"data-testid": "certificate-password",
|
|
7662
|
+
onChange: (e) => setPassword(e.target.value)
|
|
7663
|
+
}
|
|
7664
|
+
) })
|
|
7109
7665
|
] }) }),
|
|
7110
|
-
/* @__PURE__ */ jsx("
|
|
7666
|
+
/* @__PURE__ */ jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsx(
|
|
7667
|
+
Button,
|
|
7668
|
+
{
|
|
7669
|
+
size: "sm",
|
|
7670
|
+
"data-testid": "certificate-send",
|
|
7671
|
+
disabled: !file || !password || sending,
|
|
7672
|
+
onClick: () => {
|
|
7673
|
+
if (!file) return;
|
|
7674
|
+
setSending(true);
|
|
7675
|
+
void uploadCertificate(item.legalEntityId, file, password).then((res) => {
|
|
7676
|
+
setRow((r) => ({
|
|
7677
|
+
...r ?? {},
|
|
7678
|
+
certificate_cn: res.cn,
|
|
7679
|
+
certificate_expires_at: res.expiresAt,
|
|
7680
|
+
certificate_uploaded_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7681
|
+
dfe_sync_enabled: true,
|
|
7682
|
+
dfe_last_error: res.warning ?? null
|
|
7683
|
+
}));
|
|
7684
|
+
setFile(null);
|
|
7685
|
+
setPassword("");
|
|
7686
|
+
if (res.warning) toast.warning("Certificado enviado, com um aviso", { description: res.warning });
|
|
7687
|
+
else toast.success(`Certificado enviado \xB7 v\xE1lido at\xE9 ${new Date(res.expiresAt).toLocaleDateString("pt-BR")}`);
|
|
7688
|
+
}).catch((e) => toast.error("N\xE3o foi poss\xEDvel enviar o certificado", { description: e.message })).finally(() => setSending(false));
|
|
7689
|
+
},
|
|
7690
|
+
children: sending ? "Enviando\u2026" : hasCertificate ? "Atualizar certificado" : "Enviar certificado"
|
|
7691
|
+
}
|
|
7692
|
+
) }),
|
|
7693
|
+
row.dfe_last_error && /* @__PURE__ */ jsx("p", { className: "text-xs text-destructive", children: row.dfe_last_error })
|
|
7111
7694
|
] }),
|
|
7112
7695
|
/* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [
|
|
7113
7696
|
"\xDAltima sincroniza\xE7\xE3o: ",
|
|
@@ -7139,11 +7722,11 @@ function EnvSelect({ value, onChange, disabled }) {
|
|
|
7139
7722
|
}
|
|
7140
7723
|
function UnitFiscalWidget({ item }) {
|
|
7141
7724
|
const { row, loading, save } = useEmitterSettings(item?.legalEntityId);
|
|
7142
|
-
const [draft, setDraft] =
|
|
7143
|
-
const [cscToken, setCscToken] =
|
|
7144
|
-
const [saving, setSaving] =
|
|
7145
|
-
const [open, setOpen] =
|
|
7146
|
-
|
|
7725
|
+
const [draft, setDraft] = React6.useState({});
|
|
7726
|
+
const [cscToken, setCscToken] = React6.useState("");
|
|
7727
|
+
const [saving, setSaving] = React6.useState(false);
|
|
7728
|
+
const [open, setOpen] = React6.useState(false);
|
|
7729
|
+
React6.useEffect(() => {
|
|
7147
7730
|
if (row) setDraft(row);
|
|
7148
7731
|
}, [row]);
|
|
7149
7732
|
if (!item?.id) return null;
|
|
@@ -7511,7 +8094,7 @@ var dayOrDateTime = (v) => {
|
|
|
7511
8094
|
const d = new Date(v);
|
|
7512
8095
|
return d.getHours() === 0 && d.getMinutes() === 0 && d.getSeconds() === 0 ? d.toLocaleDateString("pt-BR") : dateTime(v);
|
|
7513
8096
|
};
|
|
7514
|
-
var
|
|
8097
|
+
var money4 = (v) => v == null ? "\u2014" : formatCurrency(v);
|
|
7515
8098
|
function buttonHint(s) {
|
|
7516
8099
|
const parts = [s.hasValid ? "Notas fiscais desta conta \u2014 h\xE1 uma nota v\xE1lida" : "Notas fiscais desta conta"];
|
|
7517
8100
|
if (s.withoutEffect > 0) parts.push(`${s.withoutEffect} cancelada(s), rejeitada(s) ou com erro`);
|
|
@@ -7598,10 +8181,12 @@ function NoteRow({ note, canCancel, onChanged }) {
|
|
|
7598
8181
|
};
|
|
7599
8182
|
return /* @__PURE__ */ jsxs("div", { className: `rounded-lg border ${dimmed ? "bg-muted/30" : ""}`, children: [
|
|
7600
8183
|
/* @__PURE__ */ jsxs(
|
|
7601
|
-
|
|
8184
|
+
Button,
|
|
7602
8185
|
{
|
|
8186
|
+
variant: "bare",
|
|
8187
|
+
size: "bare",
|
|
7603
8188
|
type: "button",
|
|
7604
|
-
className: "flex w-full items-center gap-2 p-3 text-left",
|
|
8189
|
+
className: "font-normal whitespace-normal justify-start flex w-full items-center gap-2 p-3 text-left",
|
|
7605
8190
|
onClick: () => setExpanded((v) => !v),
|
|
7606
8191
|
"aria-expanded": expanded,
|
|
7607
8192
|
children: [
|
|
@@ -7750,7 +8335,7 @@ function NoteDetails({ note }) {
|
|
|
7750
8335
|
["Refer\xEAncia", note.integrationId && /* @__PURE__ */ jsx("span", { className: "break-all font-mono text-xs", children: note.integrationId })],
|
|
7751
8336
|
["Chave de acesso", note.accessKey && /* @__PURE__ */ jsx("span", { className: "break-all font-mono text-xs", children: note.accessKey })],
|
|
7752
8337
|
["C\xF3digo de verifica\xE7\xE3o", note.verificationCode],
|
|
7753
|
-
["Valor",
|
|
8338
|
+
["Valor", money4(note.totalValue)],
|
|
7754
8339
|
["Tomador", recipientLabel(note.recipient)],
|
|
7755
8340
|
["Criada em", dateTime(note.createdAt)],
|
|
7756
8341
|
["Autorizada em", note.authorizedAt && dayOrDateTime(note.authorizedAt)],
|
|
@@ -7965,9 +8550,9 @@ function inboundNotesInventoryView(options = {}) {
|
|
|
7965
8550
|
};
|
|
7966
8551
|
}
|
|
7967
8552
|
function InboundNoteDocumentModal({ movement, onClose }) {
|
|
7968
|
-
const [noteId, setNoteId] =
|
|
7969
|
-
const [erro, setErro] =
|
|
7970
|
-
|
|
8553
|
+
const [noteId, setNoteId] = React6.useState(null);
|
|
8554
|
+
const [erro, setErro] = React6.useState(null);
|
|
8555
|
+
React6.useEffect(() => {
|
|
7971
8556
|
let vivo = true;
|
|
7972
8557
|
const numero = nfeNumberOf(movement);
|
|
7973
8558
|
const busca = movement.operationId ? findInboxNoteByOperation(movement.operationId).then((id) => id ?? (numero ? findInboxNoteByNumber(numero) : null)) : numero ? findInboxNoteByNumber(numero) : Promise.resolve(null);
|
|
@@ -7998,7 +8583,17 @@ function InboundNoteDocumentModal({ movement, onClose }) {
|
|
|
7998
8583
|
] })
|
|
7999
8584
|
] });
|
|
8000
8585
|
}
|
|
8001
|
-
return /* @__PURE__ */ jsx(
|
|
8586
|
+
return /* @__PURE__ */ jsx(
|
|
8587
|
+
NoteReconcileView,
|
|
8588
|
+
{
|
|
8589
|
+
chrome: "modal",
|
|
8590
|
+
noteId,
|
|
8591
|
+
onBack: onClose,
|
|
8592
|
+
onOpenInvoice: (id) => {
|
|
8593
|
+
window.location.hash = `/financial/payables/${id}`;
|
|
8594
|
+
}
|
|
8595
|
+
}
|
|
8596
|
+
);
|
|
8002
8597
|
}
|
|
8003
8598
|
function inboundNoteDocumentModal(movement, close) {
|
|
8004
8599
|
if (movement.documentType !== "nfe" || !movement.operationId) return void 0;
|
|
@@ -8149,6 +8744,6 @@ function createPlugNotasPlugin(options = {}) {
|
|
|
8149
8744
|
});
|
|
8150
8745
|
}
|
|
8151
8746
|
|
|
8152
|
-
export { EVENT_LABEL, InboundNoteDocumentModal, InboundNotesPage, InboundNotesView, InvoiceNotesButton, IssuedNotesView, MODEL_LABEL,
|
|
8747
|
+
export { EVENT_LABEL, InboundNoteDocumentModal, InboundNotesPage, InboundNotesView, InvoiceNotesButton, IssuedNotesView, MODEL_LABEL, NfeParseError, NoteReconcileView, PLUGNOTAS_CONNECTOR_ID, PLUGNOTAS_FIELDS, PLUGNOTAS_SETTINGS, PullByKeyError, ReturnedNotesView, STATUS_META, STOCK_BEARING_ENTRY_TYPES, TaxGroupsView, acceptNote, addNoteAttachment, cancelNote, createPlugNotasConnector, createPlugNotasFinancialProvider, createPlugNotasPlugin, eventStatusLabel, explainRejection, extractPaymentCode, fetchNotePdf, fillInboxLines, findInboxNoteByNumber, findInboxNoteByOperation, getInboxIntakeHealth, getInboxNote, getInboxNotePdf, getInboxNoteXml, getNotePayable, healInboxNote, inboundNoteDocumentModal, inboundNotesInventoryView, isStockBearing, isValidCnpj, isWithoutEffect, linkInboxSupplier, listChartAccounts, listInboxNotes, listInvoiceNotes, listMeasurementUnits, listNoteAttachments, listNoteEvents, listProductStockUnits, listProductsByIds, listStockLocations, listSupplierMap, markPlugNotasEmitterReady, moveNoteAttachmentsToInvoice, notesButtonState, onlyDigits, parseBoleto, parseNfeXml, paymentLabel, paymentTypeFromCode, pullNoteByKey, recipientLabel, refreshNote, rejectNote, removeNoteAttachment, saveNoteDecision, searchProducts, stageNoteFromXml, statusLabel, suggestNoteItems, summarizeNotes, syncNewNotes, toStagePayload };
|
|
8153
8748
|
//# sourceMappingURL=index.js.map
|
|
8154
8749
|
//# sourceMappingURL=index.js.map
|