@fayz-ai/plugin-fiscal-br 0.5.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/data/inbox.d.ts +73 -0
- package/dist/data/inbox.d.ts.map +1 -1
- package/dist/index.js +888 -175
- package/dist/index.js.map +1 -1
- package/dist/lib/note-suggestion.d.ts +1 -1
- package/dist/lib/note-suggestion.d.ts.map +1 -1
- package/dist/migrations/index.d.ts +2 -0
- package/dist/migrations/index.d.ts.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/views/InboundNotesView.d.ts.map +1 -1
- package/dist/views/InvoiceNotesButton.d.ts.map +1 -1
- package/dist/views/ManifestView.d.ts.map +1 -1
- package/dist/views/NoteAttachmentsCard.d.ts +19 -0
- package/dist/views/NoteAttachmentsCard.d.ts.map +1 -0
- package/dist/views/NoteReconcileView.d.ts.map +1 -1
- package/dist/views/PullByKeyDialog.d.ts +13 -0
- package/dist/views/PullByKeyDialog.d.ts.map +1 -0
- package/dist/views/inventoryView.d.ts.map +1 -1
- package/functions/fiscalbr-dfe-pull/index.ts +192 -0
- package/functions/fiscalbr-payment-extract/index.ts +138 -0
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { recordRailFields, RECORD_GROUP, activeFacet, getSupabaseClientOptional, connectionSettings, connectionStatus, definePlugin, createConnectionStore, settingsStatus, maskCpfCnpj } from '@fayz-ai/core';
|
|
2
|
-
import
|
|
3
|
-
import { ModalHeader, ModalTitle, ModalBody, Skeleton, AiActionButton,
|
|
1
|
+
import { recordRailFields, RECORD_GROUP, activeFacet, describeError, getSupabaseClientOptional, connectionSettings, connectionStatus, definePlugin, createConnectionStore, settingsStatus, maskCpfCnpj } from '@fayz-ai/core';
|
|
2
|
+
import React7, { useState, useCallback, useEffect, useMemo, useRef } from 'react';
|
|
3
|
+
import { ModalHeader, ModalTitle, ModalBody, Skeleton, AiActionButton, Dropdown, DropdownTrigger, Button, DropdownContent, DropdownItem, Hint, Card, SearchSelect, Input, EmBreve, DatePicker, ModalFooter, SubpageHeader, useFilterDraft, RowActions, PageHeaderActions, FilterPanel, FilterPanelField, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, SearchField, TooltipProvider, DataTable, Tooltip, TooltipTrigger, TooltipContent, ListFilterBar, Modal, ModalContent, ModalDescription, 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, getActiveTenantId, useUnitFilter, usePermissionOptional, UNIT_DETAIL_ZONES, adminNavigateTo } from '@fayz-ai/admin';
|
|
6
|
-
import {
|
|
5
|
+
import { registerDocumentOpener, PersonLink, getActiveTenantId, useUnitFilter, usePermissionOptional, UNIT_DETAIL_ZONES, adminNavigateTo } from '@fayz-ai/admin';
|
|
6
|
+
import { Loader2, Download, ChevronDown, FileCode2, FileText, RefreshCw, UserPlus, Gift, AlertTriangle, ChevronRight, Check, Trash2, Plus, Image, UploadCloud, Paperclip, ScanLine, Eye, ListChecks, Inbox, KeyRound, FileDown, ShieldCheck, ExternalLink, CheckCircle2, FileCheck2, XCircle, X, Info } from 'lucide-react';
|
|
7
7
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
8
8
|
import { FINANCIAL_INVOICE_ZONES } from '@fayz-ai/plugin-financial';
|
|
9
9
|
|
|
@@ -3771,6 +3771,164 @@ REVOKE ALL ON FUNCTION public.fiscalbr_note_apply(uuid, text, jsonb, jsonb) FROM
|
|
|
3771
3771
|
GRANT EXECUTE ON FUNCTION public.fiscalbr_note_for_provider(uuid, text) TO authenticated;
|
|
3772
3772
|
GRANT EXECUTE ON FUNCTION public.fiscalbr_note_apply(uuid, text, jsonb, jsonb) TO authenticated;
|
|
3773
3773
|
`;
|
|
3774
|
+
var MIGRATION_020_A_NOTA_ACHA_O_FORNECEDOR_PELO_CNPJ = `-- A nota acha o fornecedor pelo CNPJ \u2014 e, se n\xE3o achar, cadastra.
|
|
3775
|
+
--
|
|
3776
|
+
-- O est\xE1gio (009) s\xF3 casava o CNPJ no momento do import. As notas que vieram
|
|
3777
|
+
-- do V1 atravessaram sem o v\xEDnculo (003 deixou para "a costura"), e um
|
|
3778
|
+
-- fornecedor cadastrado depois nunca era religado: 1029 notas com o fornecedor
|
|
3779
|
+
-- no cadastro e a tela dizendo "n\xE3o est\xE1 no cadastro", e o t\xEDtulo aceito no V2
|
|
3780
|
+
-- nascendo sem contraparte (o tra\xE7o em Contas a Pagar).
|
|
3781
|
+
--
|
|
3782
|
+
-- O V1 nunca pediu cadastro: ao aceitar, \`resolveSupplierId\` procura o
|
|
3783
|
+
-- fornecedor pelo CNPJ e, sem achar, cria com o nome e o CNPJ da nota. Esta
|
|
3784
|
+
-- fun\xE7\xE3o \xE9 esse gesto, com duas pontas:
|
|
3785
|
+
--
|
|
3786
|
+
-- p_create = false s\xF3 casa (ao abrir a nota)
|
|
3787
|
+
-- p_create = true casa ou cria (antes de aceitar)
|
|
3788
|
+
--
|
|
3789
|
+
-- O t\xEDtulo da nota, se j\xE1 existe e est\xE1 SEM contraparte, recebe a mesma pessoa.
|
|
3790
|
+
-- Nunca troca um v\xEDnculo gravado. Idempotente.
|
|
3791
|
+
|
|
3792
|
+
CREATE OR REPLACE FUNCTION public.plg_fiscalbr_supplier_for_cnpj(p_tenant uuid, p_cnpj text)
|
|
3793
|
+
RETURNS uuid
|
|
3794
|
+
LANGUAGE sql
|
|
3795
|
+
STABLE
|
|
3796
|
+
SET search_path TO ''
|
|
3797
|
+
AS $$
|
|
3798
|
+
SELECT p.id FROM public.people p
|
|
3799
|
+
WHERE p.tenant_id = p_tenant
|
|
3800
|
+
AND p_cnpj <> ''
|
|
3801
|
+
AND public.plg_fiscalbr_digits(p.document_number) = p_cnpj
|
|
3802
|
+
ORDER BY (p.kind = 'supplier') DESC, p.created_at
|
|
3803
|
+
LIMIT 1
|
|
3804
|
+
$$;
|
|
3805
|
+
|
|
3806
|
+
CREATE OR REPLACE FUNCTION public.fiscalbr_link_inbox_supplier(p_document_id uuid, p_create boolean DEFAULT false)
|
|
3807
|
+
RETURNS jsonb
|
|
3808
|
+
LANGUAGE plpgsql
|
|
3809
|
+
SECURITY DEFINER
|
|
3810
|
+
SET search_path TO ''
|
|
3811
|
+
AS $$
|
|
3812
|
+
DECLARE
|
|
3813
|
+
v_tenant uuid := public.plg_financial_require_tenant();
|
|
3814
|
+
v_doc public.plg_fiscalbr_inbox_documents%ROWTYPE;
|
|
3815
|
+
v_cnpj text;
|
|
3816
|
+
v_party uuid;
|
|
3817
|
+
v_created boolean := false;
|
|
3818
|
+
BEGIN
|
|
3819
|
+
SELECT * INTO v_doc FROM public.plg_fiscalbr_inbox_documents
|
|
3820
|
+
WHERE id = p_document_id AND tenant_id = v_tenant;
|
|
3821
|
+
IF NOT FOUND THEN
|
|
3822
|
+
RAISE EXCEPTION 'fiscal: inbox note not found' USING ERRCODE = 'P0002';
|
|
3823
|
+
END IF;
|
|
3824
|
+
PERFORM public.plg_financial_require_permission(
|
|
3825
|
+
CASE WHEN p_create THEN 'financial.create' ELSE 'financial.read' END, v_doc.unit_id);
|
|
3826
|
+
|
|
3827
|
+
v_party := v_doc.supplier_party_id;
|
|
3828
|
+
v_cnpj := public.plg_fiscalbr_digits(v_doc.supplier_cnpj);
|
|
3829
|
+
|
|
3830
|
+
IF v_party IS NULL THEN
|
|
3831
|
+
v_party := public.plg_fiscalbr_supplier_for_cnpj(v_tenant, v_cnpj);
|
|
3832
|
+
END IF;
|
|
3833
|
+
|
|
3834
|
+
-- Without a CNPJ there is nothing to match on; a name-only person would be a
|
|
3835
|
+
-- duplicate waiting to happen, so creation needs the document.
|
|
3836
|
+
IF v_party IS NULL AND p_create AND v_cnpj <> '' THEN
|
|
3837
|
+
INSERT INTO public.people (tenant_id, kind, name, document_number)
|
|
3838
|
+
VALUES (v_tenant, 'supplier', coalesce(nullif(trim(v_doc.supplier_name), ''), 'Fornecedor ' || v_cnpj), v_cnpj)
|
|
3839
|
+
RETURNING id INTO v_party;
|
|
3840
|
+
v_created := true;
|
|
3841
|
+
END IF;
|
|
3842
|
+
|
|
3843
|
+
IF v_party IS NOT NULL AND v_doc.supplier_party_id IS NULL THEN
|
|
3844
|
+
UPDATE public.plg_fiscalbr_inbox_documents
|
|
3845
|
+
SET supplier_party_id = v_party
|
|
3846
|
+
WHERE id = v_doc.id AND supplier_party_id IS NULL;
|
|
3847
|
+
END IF;
|
|
3848
|
+
|
|
3849
|
+
IF v_party IS NOT NULL AND v_doc.invoice_id IS NOT NULL THEN
|
|
3850
|
+
UPDATE public.plg_financial_invoices
|
|
3851
|
+
SET counterparty_person_id = v_party
|
|
3852
|
+
WHERE id = v_doc.invoice_id AND tenant_id = v_tenant AND counterparty_person_id IS NULL;
|
|
3853
|
+
END IF;
|
|
3854
|
+
|
|
3855
|
+
RETURN jsonb_build_object('supplier_party_id', v_party, 'created', v_created);
|
|
3856
|
+
END;
|
|
3857
|
+
$$;
|
|
3858
|
+
|
|
3859
|
+
REVOKE ALL ON FUNCTION public.fiscalbr_link_inbox_supplier(uuid, boolean) FROM PUBLIC;
|
|
3860
|
+
GRANT EXECUTE ON FUNCTION public.fiscalbr_link_inbox_supplier(uuid, boolean) TO authenticated;
|
|
3861
|
+
|
|
3862
|
+
-- Backfill: match only, NULLs only. Nothing is created here \u2014 creating a person
|
|
3863
|
+
-- is the operator's gesture (accepting), not a migration's.
|
|
3864
|
+
WITH p AS (
|
|
3865
|
+
SELECT DISTINCT ON (tenant_id, dg) tenant_id, dg, id
|
|
3866
|
+
FROM (SELECT tenant_id, id, kind, created_at, public.plg_fiscalbr_digits(document_number) AS dg
|
|
3867
|
+
FROM public.people
|
|
3868
|
+
WHERE document_number IS NOT NULL) x
|
|
3869
|
+
WHERE length(dg) = 14
|
|
3870
|
+
ORDER BY tenant_id, dg, (kind = 'supplier') DESC, created_at
|
|
3871
|
+
)
|
|
3872
|
+
UPDATE public.plg_fiscalbr_inbox_documents d
|
|
3873
|
+
SET supplier_party_id = p.id
|
|
3874
|
+
FROM p
|
|
3875
|
+
WHERE d.supplier_party_id IS NULL
|
|
3876
|
+
AND p.tenant_id = d.tenant_id
|
|
3877
|
+
AND p.dg = public.plg_fiscalbr_digits(d.supplier_cnpj);
|
|
3878
|
+
|
|
3879
|
+
UPDATE public.plg_financial_invoices i
|
|
3880
|
+
SET counterparty_person_id = d.supplier_party_id
|
|
3881
|
+
FROM public.plg_fiscalbr_inbox_documents d
|
|
3882
|
+
WHERE d.invoice_id = i.id
|
|
3883
|
+
AND d.tenant_id = i.tenant_id
|
|
3884
|
+
AND d.supplier_party_id IS NOT NULL
|
|
3885
|
+
AND i.counterparty_person_id IS NULL;
|
|
3886
|
+
`;
|
|
3887
|
+
var MIGRATION_021_USO_E_CONSUMO_ENTRA_NO_ESTOQUE = `-- "Materiais de Uso e Consumo" vira um tipo de registro da nota recebida.
|
|
3888
|
+
--
|
|
3889
|
+
-- \xC9 o que a casa gasta sem vender nem transformar \u2014 luva, descart\xE1vel, material
|
|
3890
|
+
-- de limpeza \u2014 e que ainda assim se conta no estoque. Entra no estoque como o
|
|
3891
|
+
-- insumo: precisa de produto vinculado e gera movimento ao aceitar.
|
|
3892
|
+
--
|
|
3893
|
+
-- Aditivo e idempotente. A fun\xE7\xE3o de aceite \xE9 REMENDADA, n\xE3o reescrita (mesmo
|
|
3894
|
+
-- padr\xE3o da 015): copiar o corpo da 010 apagaria o \`reason\` que a 015 enxertou.
|
|
3895
|
+
|
|
3896
|
+
ALTER TABLE public.plg_fiscalbr_inbox_items
|
|
3897
|
+
DROP CONSTRAINT IF EXISTS plg_fiscalbr_inbox_items_entry_type_chk;
|
|
3898
|
+
ALTER TABLE public.plg_fiscalbr_inbox_items
|
|
3899
|
+
ADD CONSTRAINT plg_fiscalbr_inbox_items_entry_type_chk
|
|
3900
|
+
CHECK (entry_type IS NULL OR entry_type IN ('insumo','revenda','patrimonio','uso_consumo','despesa','servico'));
|
|
3901
|
+
|
|
3902
|
+
ALTER TABLE public.plg_fiscalbr_supplier_product_map
|
|
3903
|
+
DROP CONSTRAINT IF EXISTS plg_fiscalbr_supplier_product_map_entry_type_chk;
|
|
3904
|
+
ALTER TABLE public.plg_fiscalbr_supplier_product_map
|
|
3905
|
+
ADD CONSTRAINT plg_fiscalbr_supplier_product_map_entry_type_chk
|
|
3906
|
+
CHECK (entry_type IS NULL OR entry_type IN ('insumo','revenda','patrimonio','uso_consumo','despesa','servico'));
|
|
3907
|
+
|
|
3908
|
+
DO $m$
|
|
3909
|
+
DECLARE
|
|
3910
|
+
v_def text;
|
|
3911
|
+
v_antes text := $q$entry_type IN ('insumo','revenda','patrimonio')$q$;
|
|
3912
|
+
v_depois text := $q$entry_type IN ('insumo','revenda','patrimonio','uso_consumo')$q$;
|
|
3913
|
+
BEGIN
|
|
3914
|
+
SELECT pg_get_functiondef(p.oid) INTO v_def
|
|
3915
|
+
FROM pg_proc p JOIN pg_namespace n ON n.oid = p.pronamespace
|
|
3916
|
+
WHERE n.nspname = 'public' AND p.proname = 'fiscalbr_accept_inbox_document';
|
|
3917
|
+
|
|
3918
|
+
IF v_def IS NULL THEN
|
|
3919
|
+
RAISE EXCEPTION 'fiscalbr/021: fiscalbr_accept_inbox_document n\xE3o existe \u2014 aplicar 009/010 antes';
|
|
3920
|
+
END IF;
|
|
3921
|
+
|
|
3922
|
+
IF position('uso_consumo' in v_def) > 0 THEN RETURN; END IF;
|
|
3923
|
+
|
|
3924
|
+
IF position(v_antes in v_def) = 0 THEN
|
|
3925
|
+
RAISE EXCEPTION 'fiscalbr/021: o corpo de fiscalbr_accept_inbox_document n\xE3o \xE9 o esperado \u2014 confira \xE0 m\xE3o em vez de deixar passar calado';
|
|
3926
|
+
END IF;
|
|
3927
|
+
|
|
3928
|
+
EXECUTE replace(v_def, v_antes, v_depois);
|
|
3929
|
+
END
|
|
3930
|
+
$m$;
|
|
3931
|
+
`;
|
|
3774
3932
|
var MIGRATIONS = [
|
|
3775
3933
|
{ id: "000_baseline", sql: MIGRATION_000_BASELINE },
|
|
3776
3934
|
{ id: "001_preserve_terminal_results_and_recover_leases", sql: MIGRATION_001_PRESERVE_TERMINAL_RESULTS_AND_RECOVER_LEASES },
|
|
@@ -3791,7 +3949,9 @@ var MIGRATIONS = [
|
|
|
3791
3949
|
{ id: "016_a_nota_guarda_o_proprio_xml", sql: MIGRATION_016_A_NOTA_GUARDA_O_PROPRIO_XML },
|
|
3792
3950
|
{ id: "017_quem_emite_e_o_cnpj_nao_a_loja", sql: MIGRATION_017_QUEM_EMITE_E_O_CNPJ_NAO_A_LOJA },
|
|
3793
3951
|
{ id: "018_a_nota_do_v1_alcanca_a_conta", sql: MIGRATION_018_A_NOTA_DO_V1_ALCANCA_A_CONTA },
|
|
3794
|
-
{ id: "019_a_nota_emitida_se_cancela_pelo_v2", sql: MIGRATION_019_A_NOTA_EMITIDA_SE_CANCELA_PELO_V2 }
|
|
3952
|
+
{ id: "019_a_nota_emitida_se_cancela_pelo_v2", sql: MIGRATION_019_A_NOTA_EMITIDA_SE_CANCELA_PELO_V2 },
|
|
3953
|
+
{ id: "020_a_nota_acha_o_fornecedor_pelo_cnpj", sql: MIGRATION_020_A_NOTA_ACHA_O_FORNECEDOR_PELO_CNPJ },
|
|
3954
|
+
{ id: "021_uso_e_consumo_entra_no_estoque", sql: MIGRATION_021_USO_E_CONSUMO_ENTRA_NO_ESTOQUE }
|
|
3795
3955
|
];
|
|
3796
3956
|
var taxGroupEntity = {
|
|
3797
3957
|
name: "Grupo fiscal",
|
|
@@ -4366,6 +4526,44 @@ async function stageNoteFromXml(xml, options = {}) {
|
|
|
4366
4526
|
parsed
|
|
4367
4527
|
};
|
|
4368
4528
|
}
|
|
4529
|
+
var PullByKeyError = class extends Error {
|
|
4530
|
+
constructor(message, code, options) {
|
|
4531
|
+
super(message);
|
|
4532
|
+
this.code = code;
|
|
4533
|
+
this.options = options;
|
|
4534
|
+
}
|
|
4535
|
+
};
|
|
4536
|
+
async function pullNoteByKey(key, options = {}) {
|
|
4537
|
+
const { data, error } = await sb().functions.invoke("fiscalbr-dfe-pull", {
|
|
4538
|
+
body: { key: key.replace(/\D/g, ""), legalEntityId: options.legalEntityId, tenantId: getActiveTenantId() ?? null }
|
|
4539
|
+
});
|
|
4540
|
+
if (error) {
|
|
4541
|
+
let body = null;
|
|
4542
|
+
try {
|
|
4543
|
+
body = await error?.context?.json?.();
|
|
4544
|
+
} catch {
|
|
4545
|
+
}
|
|
4546
|
+
throw new PullByKeyError(body?.error || error.message || "Falha ao falar com a SEFAZ.", body?.code, body?.options);
|
|
4547
|
+
}
|
|
4548
|
+
if (data?.pending) return { status: "pending", message: String(data.message ?? "") };
|
|
4549
|
+
if (!data?.xml) throw new PullByKeyError("A SEFAZ n\xE3o devolveu o XML desta nota.");
|
|
4550
|
+
return { status: "staged", ...await stageNoteFromXml(String(data.xml), { unitId: options.unitId }) };
|
|
4551
|
+
}
|
|
4552
|
+
async function getInboxNotePdf(accessKey) {
|
|
4553
|
+
const { data, error } = await sb().functions.invoke("fiscalbr-dfe-pull", {
|
|
4554
|
+
body: { action: "pdf", key: accessKey, tenantId: getActiveTenantId() ?? null }
|
|
4555
|
+
});
|
|
4556
|
+
if (error) {
|
|
4557
|
+
let body = null;
|
|
4558
|
+
try {
|
|
4559
|
+
body = await error?.context?.json?.();
|
|
4560
|
+
} catch {
|
|
4561
|
+
}
|
|
4562
|
+
throw new PullByKeyError(body?.error || error.message || "Falha ao buscar o DANFE.", body?.code);
|
|
4563
|
+
}
|
|
4564
|
+
if (!(data instanceof Blob)) throw new PullByKeyError("O servi\xE7o fiscal n\xE3o devolveu um PDF.");
|
|
4565
|
+
return data;
|
|
4566
|
+
}
|
|
4369
4567
|
async function saveNoteDecision(input) {
|
|
4370
4568
|
const { data, error } = await sb().rpc("fiscalbr_save_inbox_decision", {
|
|
4371
4569
|
p_document_id: input.documentId,
|
|
@@ -4404,7 +4602,16 @@ async function saveNoteDecision(input) {
|
|
|
4404
4602
|
reconciled: Number(res.reconciled ?? 0)
|
|
4405
4603
|
};
|
|
4406
4604
|
}
|
|
4605
|
+
async function linkInboxSupplier(documentId, create = false) {
|
|
4606
|
+
const { data, error } = await sb().rpc("fiscalbr_link_inbox_supplier", { p_document_id: documentId, p_create: create });
|
|
4607
|
+
if (error) throw error;
|
|
4608
|
+
const res = data ?? {};
|
|
4609
|
+
return { supplierPartyId: res.supplier_party_id ?? null, created: Boolean(res.created) };
|
|
4610
|
+
}
|
|
4407
4611
|
async function acceptNote(documentId, locationId) {
|
|
4612
|
+
await linkInboxSupplier(documentId, true).catch((e) => {
|
|
4613
|
+
if (e?.code !== "PGRST202" && e?.code !== "42883") throw e;
|
|
4614
|
+
});
|
|
4408
4615
|
const { data, error } = await sb().rpc("fiscalbr_accept_inbox_document", {
|
|
4409
4616
|
p_document_id: documentId,
|
|
4410
4617
|
p_location_id: locationId ?? null
|
|
@@ -4531,6 +4738,222 @@ async function listSupplierMap(supplierCnpj) {
|
|
|
4531
4738
|
lastUsedAt: m.last_used_at ?? null
|
|
4532
4739
|
}));
|
|
4533
4740
|
}
|
|
4741
|
+
var NOTE_SUBJECT = "fiscalbr_inbox_document";
|
|
4742
|
+
var INVOICE_SUBJECT = "financial_invoice";
|
|
4743
|
+
async function listNoteAttachments(noteId, invoiceId) {
|
|
4744
|
+
const subjects = [`and(subject_type.eq.${NOTE_SUBJECT},subject_id.eq.${noteId})`];
|
|
4745
|
+
if (invoiceId) subjects.push(`and(subject_type.eq.${INVOICE_SUBJECT},subject_id.eq.${invoiceId})`);
|
|
4746
|
+
const { data, error } = await sb().from("documents").select("id, file_name, file_size, mime_type, storage_bucket, storage_path, created_at").or(subjects.join(",")).eq("is_active", true).order("created_at");
|
|
4747
|
+
if (error) throw error;
|
|
4748
|
+
const rows = data ?? [];
|
|
4749
|
+
const signed = /* @__PURE__ */ new Map();
|
|
4750
|
+
const byBucket = /* @__PURE__ */ new Map();
|
|
4751
|
+
for (const r of rows) {
|
|
4752
|
+
if (!r.storage_bucket || !r.storage_path) continue;
|
|
4753
|
+
byBucket.set(r.storage_bucket, [...byBucket.get(r.storage_bucket) ?? [], r.storage_path]);
|
|
4754
|
+
}
|
|
4755
|
+
for (const [bucket, paths] of byBucket) {
|
|
4756
|
+
const { data: urls } = await sb().storage.from(bucket).createSignedUrls(paths, 60 * 30);
|
|
4757
|
+
for (const u of urls ?? []) if (u.path && u.signedUrl) signed.set(u.path, u.signedUrl);
|
|
4758
|
+
}
|
|
4759
|
+
return rows.map((r) => ({
|
|
4760
|
+
id: r.id,
|
|
4761
|
+
fileName: r.file_name ?? "Anexo",
|
|
4762
|
+
fileSize: r.file_size ?? void 0,
|
|
4763
|
+
mimeType: r.mime_type ?? void 0,
|
|
4764
|
+
url: signed.get(r.storage_path) ?? void 0,
|
|
4765
|
+
createdAt: r.created_at
|
|
4766
|
+
}));
|
|
4767
|
+
}
|
|
4768
|
+
async function addNoteAttachment(noteId, invoiceId, file) {
|
|
4769
|
+
const tenantId = getActiveTenantId();
|
|
4770
|
+
if (!tenantId) throw new Error("Conta sem empresa ativa");
|
|
4771
|
+
const subjectType = invoiceId ? INVOICE_SUBJECT : NOTE_SUBJECT;
|
|
4772
|
+
const subjectId = invoiceId ?? noteId;
|
|
4773
|
+
const path = `${tenantId}/${subjectType}/${subjectId}/${Date.now()}_${file.name.replace(/[^\w.\-]+/g, "_")}`;
|
|
4774
|
+
const { error: upErr } = await sb().storage.from("attachments").upload(path, file, { contentType: file.type || void 0 });
|
|
4775
|
+
if (upErr) throw upErr;
|
|
4776
|
+
const { error } = await sb().from("documents").insert({
|
|
4777
|
+
tenant_id: tenantId,
|
|
4778
|
+
kind: "attachment",
|
|
4779
|
+
status: "active",
|
|
4780
|
+
subject_type: subjectType,
|
|
4781
|
+
subject_id: subjectId,
|
|
4782
|
+
file_name: file.name,
|
|
4783
|
+
file_size: file.size,
|
|
4784
|
+
mime_type: file.type || null,
|
|
4785
|
+
storage_provider: "supabase",
|
|
4786
|
+
storage_bucket: "attachments",
|
|
4787
|
+
storage_path: path
|
|
4788
|
+
});
|
|
4789
|
+
if (error) {
|
|
4790
|
+
await sb().storage.from("attachments").remove([path]).catch(() => {
|
|
4791
|
+
});
|
|
4792
|
+
throw error;
|
|
4793
|
+
}
|
|
4794
|
+
}
|
|
4795
|
+
async function removeNoteAttachment(id) {
|
|
4796
|
+
const { error } = await sb().from("documents").update({ is_active: false }).eq("id", id);
|
|
4797
|
+
if (error) throw error;
|
|
4798
|
+
}
|
|
4799
|
+
async function moveNoteAttachmentsToInvoice(noteId, invoiceId) {
|
|
4800
|
+
const { error } = await sb().from("documents").update({ subject_type: INVOICE_SUBJECT, subject_id: invoiceId }).eq("subject_type", NOTE_SUBJECT).eq("subject_id", noteId);
|
|
4801
|
+
if (error) throw error;
|
|
4802
|
+
}
|
|
4803
|
+
async function extractPaymentCode(file) {
|
|
4804
|
+
const base64 = await new Promise((resolve, reject) => {
|
|
4805
|
+
const reader = new FileReader();
|
|
4806
|
+
reader.onload = () => {
|
|
4807
|
+
const r = String(reader.result);
|
|
4808
|
+
resolve(r.slice(r.indexOf(",") + 1));
|
|
4809
|
+
};
|
|
4810
|
+
reader.onerror = () => reject(reader.error);
|
|
4811
|
+
reader.readAsDataURL(file);
|
|
4812
|
+
});
|
|
4813
|
+
const { data, error } = await sb().functions.invoke("fiscalbr-payment-extract", {
|
|
4814
|
+
body: { name: file.name, mime: file.type, base64 }
|
|
4815
|
+
});
|
|
4816
|
+
if (error) {
|
|
4817
|
+
let body = null;
|
|
4818
|
+
try {
|
|
4819
|
+
body = await error?.context?.json?.();
|
|
4820
|
+
} catch {
|
|
4821
|
+
}
|
|
4822
|
+
throw new Error(body?.error || error.message || "Falha ao ler o boleto.");
|
|
4823
|
+
}
|
|
4824
|
+
if (!data?.ok || data.kind === "none" || !data.code) return null;
|
|
4825
|
+
const code = String(data.code);
|
|
4826
|
+
if (data.kind === "barcode") {
|
|
4827
|
+
const parsed = parseBoleto(code);
|
|
4828
|
+
return {
|
|
4829
|
+
kind: "barcode",
|
|
4830
|
+
code: code.replace(/\D/g, ""),
|
|
4831
|
+
amount: parsed?.amount ?? (typeof data.amount === "number" ? data.amount : null),
|
|
4832
|
+
dueDate: parsed?.dueDate ?? (data.due_date ?? null)
|
|
4833
|
+
};
|
|
4834
|
+
}
|
|
4835
|
+
return { kind: "pix", code, amount: typeof data.amount === "number" ? data.amount : null, dueDate: data.due_date ?? null };
|
|
4836
|
+
}
|
|
4837
|
+
function parseBoleto(raw) {
|
|
4838
|
+
const d = raw.replace(/\D/g, "");
|
|
4839
|
+
if (d.startsWith("8")) return null;
|
|
4840
|
+
let barcode;
|
|
4841
|
+
if (d.length === 44) barcode = d;
|
|
4842
|
+
else if (d.length === 47) barcode = d.slice(0, 4) + d[32] + d.slice(33, 47) + d.slice(4, 9) + d.slice(10, 20) + d.slice(21, 31);
|
|
4843
|
+
else return null;
|
|
4844
|
+
const factor = Number(barcode.slice(5, 9));
|
|
4845
|
+
const cents = Number(barcode.slice(9, 19));
|
|
4846
|
+
let dueDate = null;
|
|
4847
|
+
if (factor > 0) {
|
|
4848
|
+
const base = factor >= 1e3 && Date.now() >= Date.UTC(2025, 1, 22) ? Date.UTC(2025, 1, 22) - 1e3 * 864e5 : Date.UTC(1997, 9, 7);
|
|
4849
|
+
dueDate = new Date(base + factor * 864e5).toISOString().slice(0, 10);
|
|
4850
|
+
}
|
|
4851
|
+
return { amount: cents > 0 ? cents / 100 : null, dueDate };
|
|
4852
|
+
}
|
|
4853
|
+
var formatCnpj = (d) => `${d.slice(0, 2)}.${d.slice(2, 5)}.${d.slice(5, 8)}/${d.slice(8, 12)}-${d.slice(12)}`;
|
|
4854
|
+
var groupKey = (digits2) => digits2.replace(/(\d{4})(?=\d)/g, "$1 ");
|
|
4855
|
+
function PullByKeyDialog({ open, onOpenChange, unitId, onPulled }) {
|
|
4856
|
+
const [value, setValue] = useState("");
|
|
4857
|
+
const [busy, setBusy] = useState(false);
|
|
4858
|
+
const [error, setError] = useState(null);
|
|
4859
|
+
const [notice, setNotice] = useState(null);
|
|
4860
|
+
const [cnpjOptions, setCnpjOptions] = useState(null);
|
|
4861
|
+
const [legalEntityId, setLegalEntityId] = useState("");
|
|
4862
|
+
useEffect(() => {
|
|
4863
|
+
if (open) return;
|
|
4864
|
+
setValue("");
|
|
4865
|
+
setError(null);
|
|
4866
|
+
setNotice(null);
|
|
4867
|
+
setCnpjOptions(null);
|
|
4868
|
+
setLegalEntityId("");
|
|
4869
|
+
}, [open]);
|
|
4870
|
+
const digits2 = value.replace(/\D/g, "").slice(0, 44);
|
|
4871
|
+
const needsCnpj = !!cnpjOptions && !legalEntityId;
|
|
4872
|
+
const blocked = digits2.length !== 44 ? `Faltam ${44 - digits2.length} d\xEDgitos` : needsCnpj ? "Escolha o CNPJ" : null;
|
|
4873
|
+
const pull = async () => {
|
|
4874
|
+
setBusy(true);
|
|
4875
|
+
setError(null);
|
|
4876
|
+
setNotice(null);
|
|
4877
|
+
try {
|
|
4878
|
+
const result = await pullNoteByKey(digits2, { legalEntityId: legalEntityId || void 0, unitId });
|
|
4879
|
+
if (result.status === "pending") {
|
|
4880
|
+
setNotice(result.message);
|
|
4881
|
+
return;
|
|
4882
|
+
}
|
|
4883
|
+
onPulled(result);
|
|
4884
|
+
onOpenChange(false);
|
|
4885
|
+
} catch (e) {
|
|
4886
|
+
if (e instanceof PullByKeyError && e.code === "choose_cnpj" && e.options?.length) {
|
|
4887
|
+
setCnpjOptions(e.options);
|
|
4888
|
+
setError(null);
|
|
4889
|
+
return;
|
|
4890
|
+
}
|
|
4891
|
+
setError(e instanceof Error ? e.message : String(e));
|
|
4892
|
+
} finally {
|
|
4893
|
+
setBusy(false);
|
|
4894
|
+
}
|
|
4895
|
+
};
|
|
4896
|
+
return /* @__PURE__ */ jsx(Modal, { open, onOpenChange: (o) => {
|
|
4897
|
+
if (!busy) onOpenChange(o);
|
|
4898
|
+
}, children: /* @__PURE__ */ jsxs(ModalContent, { size: "md", children: [
|
|
4899
|
+
/* @__PURE__ */ jsxs(ModalHeader, { children: [
|
|
4900
|
+
/* @__PURE__ */ jsxs(ModalTitle, { className: "flex items-center gap-2", children: [
|
|
4901
|
+
/* @__PURE__ */ jsx(KeyRound, { className: "h-5 w-5", "aria-hidden": true }),
|
|
4902
|
+
"Puxar NF-e por chave de acesso"
|
|
4903
|
+
] }),
|
|
4904
|
+
/* @__PURE__ */ jsx(ModalDescription, { children: "Para baixar uma nota que n\xE3o veio na coleta autom\xE1tica (por exemplo, emitida antes de ligar o recebimento de DANFes). Cole a chave de acesso de 44 d\xEDgitos." })
|
|
4905
|
+
] }),
|
|
4906
|
+
/* @__PURE__ */ jsxs(ModalBody, { className: "space-y-3", children: [
|
|
4907
|
+
/* @__PURE__ */ jsx(
|
|
4908
|
+
Input,
|
|
4909
|
+
{
|
|
4910
|
+
value: groupKey(digits2),
|
|
4911
|
+
onChange: (e) => {
|
|
4912
|
+
setValue(e.target.value);
|
|
4913
|
+
setError(null);
|
|
4914
|
+
setNotice(null);
|
|
4915
|
+
},
|
|
4916
|
+
onKeyDown: (e) => {
|
|
4917
|
+
if (e.key === "Enter" && !blocked && !busy) void pull();
|
|
4918
|
+
},
|
|
4919
|
+
placeholder: "0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000",
|
|
4920
|
+
inputMode: "numeric",
|
|
4921
|
+
autoFocus: true,
|
|
4922
|
+
className: "font-mono tabular-nums",
|
|
4923
|
+
"aria-label": "Chave de acesso",
|
|
4924
|
+
"data-testid": "pull-by-key-input"
|
|
4925
|
+
}
|
|
4926
|
+
),
|
|
4927
|
+
/* @__PURE__ */ jsxs("p", { className: `text-xs tabular-nums ${digits2.length === 44 ? "text-success-soft-foreground" : "text-muted-foreground"}`, children: [
|
|
4928
|
+
digits2.length,
|
|
4929
|
+
"/44 d\xEDgitos"
|
|
4930
|
+
] }),
|
|
4931
|
+
cnpjOptions && /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
|
|
4932
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: "De qual CNPJ \xE9 esta nota?" }),
|
|
4933
|
+
/* @__PURE__ */ jsxs(Select, { value: legalEntityId, onValueChange: setLegalEntityId, children: [
|
|
4934
|
+
/* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Escolha o CNPJ destinat\xE1rio" }) }),
|
|
4935
|
+
/* @__PURE__ */ jsx(SelectContent, { children: cnpjOptions.map((o) => /* @__PURE__ */ jsxs(SelectItem, { value: o.id, children: [
|
|
4936
|
+
o.name,
|
|
4937
|
+
" \xB7 ",
|
|
4938
|
+
formatCnpj(o.cnpj)
|
|
4939
|
+
] }, o.id)) })
|
|
4940
|
+
] })
|
|
4941
|
+
] }),
|
|
4942
|
+
error && /* @__PURE__ */ jsx("p", { className: "rounded-md bg-destructive/10 px-3 py-2 text-sm text-destructive", role: "alert", children: error }),
|
|
4943
|
+
notice && /* @__PURE__ */ jsx("p", { className: "rounded-md bg-warning-soft px-3 py-2 text-sm text-warning-soft-foreground", role: "status", children: notice }),
|
|
4944
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Puxar n\xE3o manifesta a nota na SEFAZ \u2014 a manifesta\xE7\xE3o continua sendo feita no sistema antigo." })
|
|
4945
|
+
] }),
|
|
4946
|
+
/* @__PURE__ */ jsxs(ModalFooter, { children: [
|
|
4947
|
+
/* @__PURE__ */ jsx(Button, { variant: "outline", onClick: () => onOpenChange(false), disabled: busy, children: "Cancelar" }),
|
|
4948
|
+
/* @__PURE__ */ jsxs(Button, { onClick: () => {
|
|
4949
|
+
void pull();
|
|
4950
|
+
}, disabled: busy || !!blocked, "data-testid": "pull-by-key-submit", children: [
|
|
4951
|
+
busy ? /* @__PURE__ */ jsx(Loader2, { className: "mr-1.5 h-4 w-4 animate-spin" }) : /* @__PURE__ */ jsx(KeyRound, { className: "mr-1.5 h-4 w-4" }),
|
|
4952
|
+
busy ? "Buscando na SEFAZ\u2026" : blocked ?? "Puxar nota"
|
|
4953
|
+
] })
|
|
4954
|
+
] })
|
|
4955
|
+
] }) });
|
|
4956
|
+
}
|
|
4534
4957
|
var money = (value) => new Intl.NumberFormat("pt-BR", { style: "currency", currency: "BRL" }).format(value || 0);
|
|
4535
4958
|
var day = (iso) => iso ? iso.slice(0, 10).split("-").reverse().join("/") : "\u2014";
|
|
4536
4959
|
var cnpj = (digits2) => {
|
|
@@ -4554,6 +4977,7 @@ function InboundNotesView({ onOpenNote, onOpenManifest }) {
|
|
|
4554
4977
|
const [busy, setBusy] = useState(false);
|
|
4555
4978
|
const [report, setReport] = useState(null);
|
|
4556
4979
|
const [dragging, setDragging] = useState(false);
|
|
4980
|
+
const [pullOpen, setPullOpen] = useState(false);
|
|
4557
4981
|
const fileInput = useRef(null);
|
|
4558
4982
|
const unidades = useUnitFilter({ scope: "list" });
|
|
4559
4983
|
const { draft, applied, patch, setDraft, dirty, apply, reset } = useFilterDraft({
|
|
@@ -4614,6 +5038,36 @@ function InboundNotesView({ onOpenNote, onOpenManifest }) {
|
|
|
4614
5038
|
setReport(next);
|
|
4615
5039
|
await reload();
|
|
4616
5040
|
}, [reload]);
|
|
5041
|
+
const [rowError, setRowError] = useState(null);
|
|
5042
|
+
const downloadXml = useCallback(async (note) => {
|
|
5043
|
+
setRowError(null);
|
|
5044
|
+
try {
|
|
5045
|
+
const xml = await getInboxNoteXml(note.id);
|
|
5046
|
+
if (!xml) {
|
|
5047
|
+
setRowError(`O XML da nota ${note.number} n\xE3o est\xE1 guardado.`);
|
|
5048
|
+
return;
|
|
5049
|
+
}
|
|
5050
|
+
const url = URL.createObjectURL(new Blob([xml], { type: "application/xml" }));
|
|
5051
|
+
const a = document.createElement("a");
|
|
5052
|
+
a.href = url;
|
|
5053
|
+
a.download = `${note.accessKey || note.number || "nfe"}.xml`;
|
|
5054
|
+
a.click();
|
|
5055
|
+
URL.revokeObjectURL(url);
|
|
5056
|
+
} catch (e) {
|
|
5057
|
+
setRowError(e instanceof Error ? e.message : String(e));
|
|
5058
|
+
}
|
|
5059
|
+
}, []);
|
|
5060
|
+
const openPdf = useCallback(async (note) => {
|
|
5061
|
+
setRowError(null);
|
|
5062
|
+
const tab = window.open("", "_blank");
|
|
5063
|
+
try {
|
|
5064
|
+
const pdf = await getInboxNotePdf(note.accessKey ?? "");
|
|
5065
|
+
if (tab) tab.location.href = URL.createObjectURL(pdf);
|
|
5066
|
+
} catch (e) {
|
|
5067
|
+
tab?.close();
|
|
5068
|
+
setRowError(e instanceof Error ? e.message : String(e));
|
|
5069
|
+
}
|
|
5070
|
+
}, []);
|
|
4617
5071
|
const remove = useCallback(async (note) => {
|
|
4618
5072
|
await rejectNote(note.id, "Recusada na lista de entrada");
|
|
4619
5073
|
await reload();
|
|
@@ -4653,17 +5107,12 @@ function InboundNotesView({ onOpenNote, onOpenManifest }) {
|
|
|
4653
5107
|
id: "supplier",
|
|
4654
5108
|
header: "Fornecedor",
|
|
4655
5109
|
accessorFn: (note) => note.supplierName,
|
|
5110
|
+
meta: { truncate: true },
|
|
4656
5111
|
cell: ({ row }) => /* @__PURE__ */ jsxs("div", { children: [
|
|
4657
5112
|
/* @__PURE__ */ jsx("p", { className: "font-medium leading-tight", children: row.original.supplierName || "\u2014" }),
|
|
4658
5113
|
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground tabular-nums", children: cnpj(row.original.supplierCnpj) })
|
|
4659
5114
|
] })
|
|
4660
5115
|
},
|
|
4661
|
-
{
|
|
4662
|
-
id: "items",
|
|
4663
|
-
header: () => /* @__PURE__ */ jsx("span", { className: "block text-right", children: "Itens" }),
|
|
4664
|
-
accessorFn: (note) => note.itemCount,
|
|
4665
|
-
cell: ({ row }) => /* @__PURE__ */ jsx("span", { className: "block text-right tabular-nums text-muted-foreground", children: row.original.itemCount })
|
|
4666
|
-
},
|
|
4667
5116
|
{
|
|
4668
5117
|
id: "reconciled",
|
|
4669
5118
|
header: () => /* @__PURE__ */ jsx("span", { className: "block text-center", children: "Concilia\xE7\xE3o" }),
|
|
@@ -4697,24 +5146,44 @@ function InboundNotesView({ onOpenNote, onOpenManifest }) {
|
|
|
4697
5146
|
enableSorting: false,
|
|
4698
5147
|
cell: ({ row }) => {
|
|
4699
5148
|
const note = row.original;
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
{
|
|
4705
|
-
|
|
4706
|
-
|
|
4707
|
-
|
|
4708
|
-
|
|
4709
|
-
|
|
4710
|
-
|
|
4711
|
-
|
|
4712
|
-
|
|
4713
|
-
|
|
4714
|
-
|
|
5149
|
+
const done = !!note.stockedAt || note.status === "rejected";
|
|
5150
|
+
return (
|
|
5151
|
+
// The row itself opens the note; the buttons must not fire it a second time.
|
|
5152
|
+
/* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-1", onClick: (e) => e.stopPropagation(), children: [
|
|
5153
|
+
/* @__PURE__ */ jsx(ActionIcon, { label: done ? "Ver nota" : "Conciliar", children: /* @__PURE__ */ jsx(
|
|
5154
|
+
Button,
|
|
5155
|
+
{
|
|
5156
|
+
size: "icon",
|
|
5157
|
+
variant: "ghost",
|
|
5158
|
+
"aria-label": done ? `Ver a nota ${note.number}` : `Conciliar a nota ${note.number}`,
|
|
5159
|
+
className: done ? "" : "bg-foreground text-background hover:bg-foreground/85 hover:text-background",
|
|
5160
|
+
onClick: () => onOpenNote(note.id),
|
|
5161
|
+
children: done ? /* @__PURE__ */ jsx(Eye, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(ListChecks, { className: "h-4 w-4" })
|
|
5162
|
+
}
|
|
5163
|
+
) }),
|
|
5164
|
+
/* @__PURE__ */ jsx(
|
|
5165
|
+
RowActions,
|
|
5166
|
+
{
|
|
5167
|
+
inlineLimit: 0,
|
|
5168
|
+
actions: [
|
|
5169
|
+
{ id: "xml", label: "Baixar XML", icon: FileCode2, onSelect: () => downloadXml(note) },
|
|
5170
|
+
{ id: "pdf", label: "Abrir PDF", icon: FileText, onSelect: () => openPdf(note), hidden: !note.accessKey },
|
|
5171
|
+
{
|
|
5172
|
+
id: "reject",
|
|
5173
|
+
label: "Recusar nota",
|
|
5174
|
+
icon: Trash2,
|
|
5175
|
+
intent: "danger",
|
|
5176
|
+
onSelect: () => remove(note),
|
|
5177
|
+
hidden: done || !!note.invoiceId
|
|
5178
|
+
}
|
|
5179
|
+
]
|
|
5180
|
+
}
|
|
5181
|
+
)
|
|
5182
|
+
] })
|
|
5183
|
+
);
|
|
4715
5184
|
}
|
|
4716
5185
|
}
|
|
4717
|
-
], [onOpenNote, remove]);
|
|
5186
|
+
], [onOpenNote, remove, downloadXml, openPdf]);
|
|
4718
5187
|
const emptyMessage = query || activeCount > 0 ? /* @__PURE__ */ jsxs("div", { children: [
|
|
4719
5188
|
/* @__PURE__ */ jsx(Inbox, { className: "mx-auto h-8 w-8 text-muted-foreground", "aria-hidden": true }),
|
|
4720
5189
|
/* @__PURE__ */ jsx("p", { className: "mt-2 text-sm font-medium", children: "Nenhuma nota encontrada" }),
|
|
@@ -4730,6 +5199,10 @@ function InboundNotesView({ onOpenNote, onOpenManifest }) {
|
|
|
4730
5199
|
/* @__PURE__ */ jsx(Inbox, { className: "h-4 w-4 mr-1.5" }),
|
|
4731
5200
|
"Fila da SEFAZ"
|
|
4732
5201
|
] }),
|
|
5202
|
+
/* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", onClick: () => setPullOpen(true), "data-testid": "pull-by-key", children: [
|
|
5203
|
+
/* @__PURE__ */ jsx(KeyRound, { className: "h-4 w-4 mr-1.5" }),
|
|
5204
|
+
"Puxar por chave"
|
|
5205
|
+
] }),
|
|
4733
5206
|
/* @__PURE__ */ jsxs(Button, { size: "sm", onClick: () => fileInput.current?.click(), disabled: busy, children: [
|
|
4734
5207
|
busy ? /* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 mr-1.5 animate-spin" }) : /* @__PURE__ */ jsx(UploadCloud, { className: "h-4 w-4 mr-1.5" }),
|
|
4735
5208
|
"Importar XML"
|
|
@@ -4770,6 +5243,21 @@ function InboundNotesView({ onOpenNote, onOpenManifest }) {
|
|
|
4770
5243
|
]
|
|
4771
5244
|
}
|
|
4772
5245
|
),
|
|
5246
|
+
/* @__PURE__ */ jsx(
|
|
5247
|
+
PullByKeyDialog,
|
|
5248
|
+
{
|
|
5249
|
+
open: pullOpen,
|
|
5250
|
+
onOpenChange: setPullOpen,
|
|
5251
|
+
unitId: applied.unitId || null,
|
|
5252
|
+
onPulled: (r) => {
|
|
5253
|
+
setReport({
|
|
5254
|
+
ok: [{ file: "chave", number: r.parsed.nfeNumber, items: r.itemCount, matched: r.matchedCount, repeated: r.alreadyAccepted }],
|
|
5255
|
+
failed: []
|
|
5256
|
+
});
|
|
5257
|
+
void reload();
|
|
5258
|
+
}
|
|
5259
|
+
}
|
|
5260
|
+
),
|
|
4773
5261
|
report && /* @__PURE__ */ jsxs(Card, { className: "p-4 space-y-2", children: [
|
|
4774
5262
|
report.ok.map((r) => /* @__PURE__ */ jsxs("p", { className: "text-sm", children: [
|
|
4775
5263
|
/* @__PURE__ */ jsxs("span", { className: "font-medium", children: [
|
|
@@ -4822,6 +5310,7 @@ function InboundNotesView({ onOpenNote, onOpenManifest }) {
|
|
|
4822
5310
|
]
|
|
4823
5311
|
}
|
|
4824
5312
|
),
|
|
5313
|
+
rowError && /* @__PURE__ */ jsx("p", { className: "rounded-md bg-destructive/10 px-3 py-2 text-sm text-destructive", role: "alert", children: rowError }),
|
|
4825
5314
|
/* @__PURE__ */ jsxs(Card, { className: "overflow-hidden", children: [
|
|
4826
5315
|
/* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center gap-2 border-b border-border px-3 py-2", children: /* @__PURE__ */ jsx("div", { className: "min-w-[10rem] flex-1", children: /* @__PURE__ */ jsx(
|
|
4827
5316
|
SearchField,
|
|
@@ -4832,7 +5321,7 @@ function InboundNotesView({ onOpenNote, onOpenManifest }) {
|
|
|
4832
5321
|
"data-testid": "inbound-notes-search"
|
|
4833
5322
|
}
|
|
4834
5323
|
) }) }),
|
|
4835
|
-
/* @__PURE__ */ jsx(
|
|
5324
|
+
/* @__PURE__ */ jsx(TooltipProvider, { delayDuration: 200, children: /* @__PURE__ */ jsx(
|
|
4836
5325
|
DataTable,
|
|
4837
5326
|
{
|
|
4838
5327
|
variant: "bare",
|
|
@@ -4840,12 +5329,19 @@ function InboundNotesView({ onOpenNote, onOpenManifest }) {
|
|
|
4840
5329
|
data: loading ? [] : shown,
|
|
4841
5330
|
loading,
|
|
4842
5331
|
getRowId: (note) => note.id,
|
|
5332
|
+
onRowClick: (note) => onOpenNote(note.id),
|
|
4843
5333
|
emptyMessage
|
|
4844
5334
|
}
|
|
4845
|
-
)
|
|
5335
|
+
) })
|
|
4846
5336
|
] })
|
|
4847
5337
|
] });
|
|
4848
5338
|
}
|
|
5339
|
+
function ActionIcon({ label, children }) {
|
|
5340
|
+
return /* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
5341
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children }),
|
|
5342
|
+
/* @__PURE__ */ jsx(TooltipContent, { children: label })
|
|
5343
|
+
] });
|
|
5344
|
+
}
|
|
4849
5345
|
function ReconcileBadge({ done, total }) {
|
|
4850
5346
|
const full = total > 0 && done === total;
|
|
4851
5347
|
return /* @__PURE__ */ jsxs(
|
|
@@ -4869,9 +5365,185 @@ function StockBadge({ stockedAt, status }) {
|
|
|
4869
5365
|
"Estocado"
|
|
4870
5366
|
] }) : /* @__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" });
|
|
4871
5367
|
}
|
|
5368
|
+
var MAX_BYTES = 15 * 1024 * 1024;
|
|
5369
|
+
var money2 = (v) => new Intl.NumberFormat("pt-BR", { style: "currency", currency: "BRL" }).format(v || 0);
|
|
5370
|
+
var day2 = (iso) => iso ? iso.slice(0, 10).split("-").reverse().join("/") : "\u2014";
|
|
5371
|
+
var size = (b) => !b ? "" : b < 1024 * 1024 ? `${Math.max(1, Math.round(b / 1024))} KB` : `${(b / 1024 / 1024).toFixed(1)} MB`;
|
|
5372
|
+
function applyPaymentCode(list, code) {
|
|
5373
|
+
const field = code.kind === "pix" ? "pixKey" : "barcode";
|
|
5374
|
+
const free = list.map((p, i) => ({ p, i })).filter(({ p }) => !p[field]);
|
|
5375
|
+
const sameAmount = code.amount != null ? free.find(({ p }) => Math.abs((Number(p.amount) || 0) - code.amount) < 0.01) : void 0;
|
|
5376
|
+
const target = sameAmount ?? free[0];
|
|
5377
|
+
const patch = (p) => ({
|
|
5378
|
+
...p,
|
|
5379
|
+
[field]: code.code,
|
|
5380
|
+
paymentType: code.kind === "pix" ? "pix" : "boleto",
|
|
5381
|
+
dueDate: p.dueDate || code.dueDate,
|
|
5382
|
+
amount: Number(p.amount) > 0 ? p.amount : code.amount ?? 0
|
|
5383
|
+
});
|
|
5384
|
+
if (target) return { next: list.map((p, i) => i === target.i ? patch(p) : p), index: target.i };
|
|
5385
|
+
const fresh = patch({ index: list.length, amount: 0 });
|
|
5386
|
+
return { next: [...list, fresh], index: list.length };
|
|
5387
|
+
}
|
|
5388
|
+
function NoteAttachmentsCard({ noteId, invoiceId, readOnly, instalments, onInstalments }) {
|
|
5389
|
+
const input = useRef(null);
|
|
5390
|
+
const [items, setItems] = useState(null);
|
|
5391
|
+
const [busy, setBusy] = useState(null);
|
|
5392
|
+
const [over, setOver] = useState(false);
|
|
5393
|
+
const [confirming, setConfirming] = useState(null);
|
|
5394
|
+
const [messages, setMessages] = useState([]);
|
|
5395
|
+
const current = useRef(instalments);
|
|
5396
|
+
current.current = instalments;
|
|
5397
|
+
const load = useCallback(async () => {
|
|
5398
|
+
try {
|
|
5399
|
+
setItems(await listNoteAttachments(noteId, invoiceId));
|
|
5400
|
+
} catch {
|
|
5401
|
+
setItems([]);
|
|
5402
|
+
}
|
|
5403
|
+
}, [noteId, invoiceId]);
|
|
5404
|
+
useEffect(() => {
|
|
5405
|
+
void load();
|
|
5406
|
+
}, [load]);
|
|
5407
|
+
const upload = async (files) => {
|
|
5408
|
+
const out = [];
|
|
5409
|
+
for (const file of files) {
|
|
5410
|
+
if (!(file.type.startsWith("image/") || file.type === "application/pdf") || file.size > MAX_BYTES) {
|
|
5411
|
+
out.push({ tone: "error", text: `${file.name}: envie imagem ou PDF de at\xE9 15 MB.` });
|
|
5412
|
+
continue;
|
|
5413
|
+
}
|
|
5414
|
+
setBusy(`Anexando ${file.name}\u2026`);
|
|
5415
|
+
try {
|
|
5416
|
+
await addNoteAttachment(noteId, invoiceId, file);
|
|
5417
|
+
} catch (e) {
|
|
5418
|
+
out.push({ tone: "error", text: `${file.name}: ${e instanceof Error ? e.message : String(e)}` });
|
|
5419
|
+
continue;
|
|
5420
|
+
}
|
|
5421
|
+
if (readOnly) continue;
|
|
5422
|
+
setBusy(`Lendo ${file.name}\u2026`);
|
|
5423
|
+
try {
|
|
5424
|
+
const code = await extractPaymentCode(file);
|
|
5425
|
+
if (!code) {
|
|
5426
|
+
out.push({ tone: "warn", text: `${file.name}: anexado. N\xE3o achei c\xF3digo de boleto nem Pix nele.` });
|
|
5427
|
+
} else {
|
|
5428
|
+
const { next, index } = applyPaymentCode(current.current, code);
|
|
5429
|
+
current.current = next;
|
|
5430
|
+
onInstalments(next);
|
|
5431
|
+
const p = next[index];
|
|
5432
|
+
out.push({
|
|
5433
|
+
tone: "ok",
|
|
5434
|
+
text: `${code.kind === "pix" ? "Pix" : "Boleto"} lido \u2192 parcela ${index + 1}: ${money2(Number(p.amount) || 0)}, vence ${day2(p.dueDate ?? null)}. Confira e salve.`
|
|
5435
|
+
});
|
|
5436
|
+
}
|
|
5437
|
+
} catch (e) {
|
|
5438
|
+
out.push({ tone: "warn", text: `${file.name}: anexado, mas n\xE3o consegui ler o c\xF3digo (${e instanceof Error ? e.message : String(e)}).` });
|
|
5439
|
+
}
|
|
5440
|
+
}
|
|
5441
|
+
setBusy(null);
|
|
5442
|
+
setMessages(out);
|
|
5443
|
+
await load();
|
|
5444
|
+
};
|
|
5445
|
+
const remove = async (a) => {
|
|
5446
|
+
setBusy(`Removendo ${a.fileName}\u2026`);
|
|
5447
|
+
try {
|
|
5448
|
+
await removeNoteAttachment(a.id);
|
|
5449
|
+
setMessages([{ tone: "ok", text: `${a.fileName} removido.` }]);
|
|
5450
|
+
} catch (e) {
|
|
5451
|
+
setMessages([{ tone: "error", text: `${a.fileName}: ${e instanceof Error ? e.message : String(e)}` }]);
|
|
5452
|
+
} finally {
|
|
5453
|
+
setBusy(null);
|
|
5454
|
+
await load();
|
|
5455
|
+
}
|
|
5456
|
+
};
|
|
5457
|
+
return /* @__PURE__ */ jsxs(Card, { className: "p-4", children: [
|
|
5458
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-3", children: [
|
|
5459
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
5460
|
+
/* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold", children: "Anexos da conta" }),
|
|
5461
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: "Boleto, comprovante, foto da nota. Boleto e Pix anexados s\xE3o lidos e preenchem a parcela." })
|
|
5462
|
+
] }),
|
|
5463
|
+
items && items.length > 0 && /* @__PURE__ */ jsxs("span", { className: "shrink-0 text-xs text-muted-foreground", children: [
|
|
5464
|
+
items.length,
|
|
5465
|
+
" ",
|
|
5466
|
+
items.length === 1 ? "anexo" : "anexos"
|
|
5467
|
+
] })
|
|
5468
|
+
] }),
|
|
5469
|
+
items === null ? /* @__PURE__ */ jsx("div", { className: "mt-3 h-10 animate-pulse rounded-md bg-muted" }) : items.length > 0 && /* @__PURE__ */ jsx("ul", { className: "mt-3 divide-y rounded-md border", children: items.map((a) => /* @__PURE__ */ jsxs("li", { className: "flex items-center gap-2 px-3 py-2 text-sm", children: [
|
|
5470
|
+
a.mimeType?.startsWith("image/") ? /* @__PURE__ */ jsx(Image, { className: "h-4 w-4 shrink-0 text-muted-foreground", "aria-hidden": true }) : /* @__PURE__ */ jsx(FileText, { className: "h-4 w-4 shrink-0 text-muted-foreground", "aria-hidden": true }),
|
|
5471
|
+
a.url ? /* @__PURE__ */ jsx("a", { href: a.url, target: "_blank", rel: "noreferrer", className: "min-w-0 flex-1 truncate hover:underline", children: a.fileName }) : /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-muted-foreground", children: a.fileName }),
|
|
5472
|
+
confirming === a.id ? (
|
|
5473
|
+
// Inline, not a dialog: this card already lives inside a modal.
|
|
5474
|
+
/* @__PURE__ */ jsxs("span", { className: "flex shrink-0 items-center gap-1", children: [
|
|
5475
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: "Remover?" }),
|
|
5476
|
+
/* @__PURE__ */ jsx(Button, { variant: "destructive", size: "sm", onClick: () => {
|
|
5477
|
+
setConfirming(null);
|
|
5478
|
+
void remove(a);
|
|
5479
|
+
}, children: "Remover" }),
|
|
5480
|
+
/* @__PURE__ */ jsx(Button, { variant: "ghost", size: "sm", onClick: () => setConfirming(null), children: "Cancelar" })
|
|
5481
|
+
] })
|
|
5482
|
+
) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5483
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0 text-xs text-muted-foreground", children: size(a.fileSize) }),
|
|
5484
|
+
/* @__PURE__ */ jsx(Hint, { label: "Remover anexo", children: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon", "aria-label": `Remover ${a.fileName}`, disabled: !!busy, onClick: () => setConfirming(a.id), children: /* @__PURE__ */ jsx(Trash2, { className: "h-4 w-4" }) }) })
|
|
5485
|
+
] })
|
|
5486
|
+
] }, a.id)) }),
|
|
5487
|
+
/* @__PURE__ */ jsxs(
|
|
5488
|
+
"div",
|
|
5489
|
+
{
|
|
5490
|
+
className: `mt-3 flex flex-col items-center gap-1 rounded-md border border-dashed px-4 py-5 text-center transition-colors ${over ? "border-primary bg-primary/5" : "border-input"}`,
|
|
5491
|
+
onDragOver: (e) => {
|
|
5492
|
+
e.preventDefault();
|
|
5493
|
+
setOver(true);
|
|
5494
|
+
},
|
|
5495
|
+
onDragLeave: () => setOver(false),
|
|
5496
|
+
onDrop: (e) => {
|
|
5497
|
+
e.preventDefault();
|
|
5498
|
+
setOver(false);
|
|
5499
|
+
void upload(Array.from(e.dataTransfer.files));
|
|
5500
|
+
},
|
|
5501
|
+
children: [
|
|
5502
|
+
busy ? /* @__PURE__ */ jsxs("p", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
|
|
5503
|
+
/* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin" }),
|
|
5504
|
+
busy
|
|
5505
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5506
|
+
/* @__PURE__ */ jsx(UploadCloud, { className: "h-6 w-6 text-muted-foreground", "aria-hidden": true }),
|
|
5507
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm", children: "Arraste o boleto ou o comprovante aqui" }),
|
|
5508
|
+
/* @__PURE__ */ jsx("div", { className: "mt-1 flex gap-2", children: /* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", onClick: () => input.current?.click(), "data-testid": "note-attach", children: [
|
|
5509
|
+
/* @__PURE__ */ jsx(Paperclip, { className: "mr-1.5 h-4 w-4" }),
|
|
5510
|
+
"Anexar arquivo"
|
|
5511
|
+
] }) }),
|
|
5512
|
+
!readOnly && /* @__PURE__ */ jsxs("p", { className: "mt-1 flex items-center gap-1 text-[11px] text-muted-foreground", children: [
|
|
5513
|
+
/* @__PURE__ */ jsx(ScanLine, { className: "h-3 w-3", "aria-hidden": true }),
|
|
5514
|
+
" o c\xF3digo de barras e o Pix s\xE3o lidos sozinhos"
|
|
5515
|
+
] })
|
|
5516
|
+
] }),
|
|
5517
|
+
/* @__PURE__ */ jsx(
|
|
5518
|
+
"input",
|
|
5519
|
+
{
|
|
5520
|
+
ref: input,
|
|
5521
|
+
type: "file",
|
|
5522
|
+
multiple: true,
|
|
5523
|
+
accept: "image/*,application/pdf",
|
|
5524
|
+
className: "hidden",
|
|
5525
|
+
onChange: (e) => {
|
|
5526
|
+
void upload(Array.from(e.target.files ?? []));
|
|
5527
|
+
e.target.value = "";
|
|
5528
|
+
}
|
|
5529
|
+
}
|
|
5530
|
+
)
|
|
5531
|
+
]
|
|
5532
|
+
}
|
|
5533
|
+
),
|
|
5534
|
+
messages.length > 0 && /* @__PURE__ */ jsx("ul", { className: "mt-3 space-y-1", children: messages.map((m, i) => /* @__PURE__ */ jsx(
|
|
5535
|
+
"li",
|
|
5536
|
+
{
|
|
5537
|
+
className: `text-xs ${m.tone === "ok" ? "text-success-soft-foreground" : m.tone === "warn" ? "text-warning-soft-foreground" : "text-destructive"}`,
|
|
5538
|
+
children: m.text
|
|
5539
|
+
},
|
|
5540
|
+
i
|
|
5541
|
+
)) })
|
|
5542
|
+
] });
|
|
5543
|
+
}
|
|
4872
5544
|
|
|
4873
5545
|
// src/types.ts
|
|
4874
|
-
var STOCK_BEARING_ENTRY_TYPES = ["insumo", "revenda", "patrimonio"];
|
|
5546
|
+
var STOCK_BEARING_ENTRY_TYPES = ["insumo", "revenda", "patrimonio", "uso_consumo"];
|
|
4875
5547
|
var isStockBearing = (type) => STOCK_BEARING_ENTRY_TYPES.includes(type);
|
|
4876
5548
|
|
|
4877
5549
|
// src/lib/note-suggestion.ts
|
|
@@ -4891,13 +5563,14 @@ var norm = (u) => (u ?? "").trim().toUpperCase().replace(/\.$/, "");
|
|
|
4891
5563
|
function packagingCount(commercialUnit) {
|
|
4892
5564
|
return PACKAGING_COUNT[norm(commercialUnit)] ?? null;
|
|
4893
5565
|
}
|
|
4894
|
-
var
|
|
5566
|
+
var money3 = (v) => new Intl.NumberFormat("pt-BR", { style: "currency", currency: "BRL" }).format(v || 0);
|
|
4895
5567
|
var qty = (v) => new Intl.NumberFormat("pt-BR", { maximumFractionDigits: 4 }).format(v || 0);
|
|
4896
|
-
var
|
|
5568
|
+
var day3 = (iso) => iso ? iso.slice(0, 10).split("-").reverse().join("/") : "\u2014";
|
|
4897
5569
|
var ENTRY_TYPES = [
|
|
4898
5570
|
{ value: "insumo", label: "Insumo" },
|
|
4899
5571
|
{ value: "revenda", label: "Produto Revenda" },
|
|
4900
5572
|
{ value: "patrimonio", label: "Patrim\xF4nio" },
|
|
5573
|
+
{ value: "uso_consumo", label: "Uso e Consumo", hint: "com estoque" },
|
|
4901
5574
|
{ value: "despesa", label: "Despesa", hint: "n\xE3o vira estoque" },
|
|
4902
5575
|
{ value: "servico", label: "Servi\xE7o", hint: "n\xE3o vira estoque" }
|
|
4903
5576
|
];
|
|
@@ -4945,7 +5618,11 @@ function NoteReconcileView({ noteId, onBack, onOpenInvoice, chrome = "page" }) {
|
|
|
4945
5618
|
const load = useCallback(async () => {
|
|
4946
5619
|
setLoading(true);
|
|
4947
5620
|
try {
|
|
4948
|
-
|
|
5621
|
+
let detail = await getInboxNote(noteId);
|
|
5622
|
+
if (detail && !detail.supplierPartyId && detail.supplierCnpj) {
|
|
5623
|
+
const linked = await linkInboxSupplier(noteId).catch(() => null);
|
|
5624
|
+
if (linked?.supplierPartyId) detail = { ...detail, supplierPartyId: linked.supplierPartyId };
|
|
5625
|
+
}
|
|
4949
5626
|
setNote(detail);
|
|
4950
5627
|
const failed = [];
|
|
4951
5628
|
const [u, a, l] = await Promise.all([
|
|
@@ -5121,18 +5798,54 @@ function NoteReconcileView({ noteId, onBack, onOpenInvoice, chrome = "page" }) {
|
|
|
5121
5798
|
const moldura = (node, titulo, rodape2) => emModal ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5122
5799
|
/* @__PURE__ */ jsxs(ModalHeader, { className: "shrink-0 flex-row items-center justify-between gap-3 space-y-0 border-b px-6 py-3 pr-14 text-left sm:flex-row", children: [
|
|
5123
5800
|
/* @__PURE__ */ jsx(ModalTitle, { className: "min-w-0 truncate", children: titulo }),
|
|
5124
|
-
|
|
5801
|
+
/* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [
|
|
5802
|
+
botaoIA,
|
|
5803
|
+
ferramentas
|
|
5804
|
+
] })
|
|
5125
5805
|
] }),
|
|
5126
5806
|
/* @__PURE__ */ jsx(ModalBody, { className: "px-6 py-4", children: node }),
|
|
5127
|
-
rodape2 && /* @__PURE__ */ jsx(ModalFooter, {
|
|
5807
|
+
rodape2 && /* @__PURE__ */ jsx(ModalFooter, { variant: "bar", start: rodape2.start, children: rodape2.end })
|
|
5128
5808
|
] }) : (
|
|
5129
5809
|
// Em tela cheia não há moldura onde pendurar o rodapé: ele volta para dentro
|
|
5130
5810
|
// do conteúdo, grudado na base da janela enquanto a página rola.
|
|
5131
5811
|
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5132
5812
|
node,
|
|
5133
|
-
rodape2 && /* @__PURE__ */
|
|
5813
|
+
rodape2 && /* @__PURE__ */ jsxs("div", { className: `sticky bottom-0 ${sangria} flex items-center justify-between gap-3 border-t bg-card/95 py-3 pr-16 backdrop-blur`, children: [
|
|
5814
|
+
/* @__PURE__ */ jsx("div", { className: "flex min-w-0 items-center gap-3", children: rodape2.start }),
|
|
5815
|
+
/* @__PURE__ */ jsx("div", { className: "flex shrink-0 items-center gap-2", children: rodape2.end })
|
|
5816
|
+
] })
|
|
5134
5817
|
] })
|
|
5135
5818
|
);
|
|
5819
|
+
const [cadastrando, setCadastrando] = useState(false);
|
|
5820
|
+
const cadastrarFornecedor = useCallback(async () => {
|
|
5821
|
+
if (!note) return;
|
|
5822
|
+
setCadastrando(true);
|
|
5823
|
+
setError(null);
|
|
5824
|
+
try {
|
|
5825
|
+
const { supplierPartyId } = await linkInboxSupplier(note.id, true);
|
|
5826
|
+
if (supplierPartyId) setNote({ ...note, supplierPartyId });
|
|
5827
|
+
} catch (e) {
|
|
5828
|
+
setError(e instanceof Error ? e.message : String(e));
|
|
5829
|
+
} finally {
|
|
5830
|
+
setCadastrando(false);
|
|
5831
|
+
}
|
|
5832
|
+
}, [note]);
|
|
5833
|
+
const [abrindoPdf, setAbrindoPdf] = useState(false);
|
|
5834
|
+
const abrirPdf = useCallback(async () => {
|
|
5835
|
+
if (!note?.accessKey) return;
|
|
5836
|
+
const tab = window.open("", "_blank");
|
|
5837
|
+
setAbrindoPdf(true);
|
|
5838
|
+
setError(null);
|
|
5839
|
+
try {
|
|
5840
|
+
const pdf = await getInboxNotePdf(note.accessKey);
|
|
5841
|
+
if (tab) tab.location.href = URL.createObjectURL(pdf);
|
|
5842
|
+
} catch (e) {
|
|
5843
|
+
tab?.close();
|
|
5844
|
+
setError(e instanceof Error ? e.message : String(e));
|
|
5845
|
+
} finally {
|
|
5846
|
+
setAbrindoPdf(false);
|
|
5847
|
+
}
|
|
5848
|
+
}, [note]);
|
|
5136
5849
|
const baixarXml = useCallback(async () => {
|
|
5137
5850
|
if (!note) return;
|
|
5138
5851
|
setBaixandoXml(true);
|
|
@@ -5155,6 +5868,32 @@ function NoteReconcileView({ noteId, onBack, onOpenInvoice, chrome = "page" }) {
|
|
|
5155
5868
|
setBaixandoXml(false);
|
|
5156
5869
|
}
|
|
5157
5870
|
}, [note]);
|
|
5871
|
+
const ferramentas = note ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
5872
|
+
/* @__PURE__ */ jsxs(Dropdown, { children: [
|
|
5873
|
+
/* @__PURE__ */ jsx(DropdownTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", disabled: baixandoXml || abrindoPdf, children: [
|
|
5874
|
+
baixandoXml || abrindoPdf ? /* @__PURE__ */ jsx(Loader2, { className: "mr-1.5 h-4 w-4 animate-spin" }) : /* @__PURE__ */ jsx(Download, { className: "mr-1.5 h-4 w-4" }),
|
|
5875
|
+
"Baixar",
|
|
5876
|
+
/* @__PURE__ */ jsx(ChevronDown, { className: "ml-1 h-3.5 w-3.5 opacity-60" })
|
|
5877
|
+
] }) }),
|
|
5878
|
+
/* @__PURE__ */ jsxs(DropdownContent, { align: "end", children: [
|
|
5879
|
+
/* @__PURE__ */ jsxs(DropdownItem, { className: "gap-2", disabled: !note.hasXml, onSelect: () => {
|
|
5880
|
+
void baixarXml();
|
|
5881
|
+
}, children: [
|
|
5882
|
+
/* @__PURE__ */ jsx(FileCode2, { className: "h-4 w-4" }),
|
|
5883
|
+
note.hasXml ? "XML da nota" : "XML n\xE3o guardado \u2014 reimporte o .xml"
|
|
5884
|
+
] }),
|
|
5885
|
+
/* @__PURE__ */ jsxs(DropdownItem, { className: "gap-2", disabled: !note.accessKey, onSelect: () => {
|
|
5886
|
+
void abrirPdf();
|
|
5887
|
+
}, children: [
|
|
5888
|
+
/* @__PURE__ */ jsx(FileText, { className: "h-4 w-4" }),
|
|
5889
|
+
"DANFE (PDF)"
|
|
5890
|
+
] })
|
|
5891
|
+
] })
|
|
5892
|
+
] }),
|
|
5893
|
+
/* @__PURE__ */ jsx(Hint, { label: "Atualizar", children: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon", "aria-label": "Atualizar a nota", onClick: () => {
|
|
5894
|
+
void load();
|
|
5895
|
+
}, children: /* @__PURE__ */ jsx(RefreshCw, { className: "h-4 w-4" }) }) })
|
|
5896
|
+
] }) : null;
|
|
5158
5897
|
const save = async () => {
|
|
5159
5898
|
if (!note) return;
|
|
5160
5899
|
setSaving(true);
|
|
@@ -5186,7 +5925,10 @@ function NoteReconcileView({ noteId, onBack, onOpenInvoice, chrome = "page" }) {
|
|
|
5186
5925
|
defaultLocationId: location,
|
|
5187
5926
|
instalments
|
|
5188
5927
|
});
|
|
5189
|
-
|
|
5928
|
+
const result = await acceptNote(note.id, location);
|
|
5929
|
+
if (result.invoiceId) await moveNoteAttachmentsToInvoice(note.id, result.invoiceId).catch(() => {
|
|
5930
|
+
});
|
|
5931
|
+
setAccepted(result);
|
|
5190
5932
|
await load();
|
|
5191
5933
|
} catch (e) {
|
|
5192
5934
|
setError(e instanceof Error ? e.message : String(e));
|
|
@@ -5231,61 +5973,68 @@ function NoteReconcileView({ noteId, onBack, onOpenInvoice, chrome = "page" }) {
|
|
|
5231
5973
|
] }) : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Nota n\xE3o encontrada." }) })
|
|
5232
5974
|
] }), "Concilia\xE7\xE3o");
|
|
5233
5975
|
}
|
|
5234
|
-
const
|
|
5235
|
-
|
|
5236
|
-
|
|
5237
|
-
|
|
5238
|
-
|
|
5239
|
-
|
|
5240
|
-
|
|
5241
|
-
|
|
5242
|
-
|
|
5243
|
-
|
|
5244
|
-
|
|
5245
|
-
|
|
5246
|
-
"
|
|
5247
|
-
|
|
5248
|
-
|
|
5249
|
-
|
|
5250
|
-
|
|
5251
|
-
|
|
5252
|
-
|
|
5253
|
-
|
|
5254
|
-
|
|
5255
|
-
|
|
5256
|
-
|
|
5257
|
-
|
|
5258
|
-
/* @__PURE__ */
|
|
5976
|
+
const pendencias = [
|
|
5977
|
+
unverifiedFactor > 0 && `${unverifiedFactor} com fator por conferir`,
|
|
5978
|
+
missingType > 0 && `${missingType} sem tipo`,
|
|
5979
|
+
missingProduct > 0 && `${missingProduct} sem produto`
|
|
5980
|
+
].filter(Boolean).join(" \xB7 ");
|
|
5981
|
+
const rodape = readOnly ? null : {
|
|
5982
|
+
start: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5983
|
+
/* @__PURE__ */ jsxs(
|
|
5984
|
+
Button,
|
|
5985
|
+
{
|
|
5986
|
+
variant: "ghost",
|
|
5987
|
+
size: "sm",
|
|
5988
|
+
className: "text-destructive hover:bg-destructive/10 hover:text-destructive",
|
|
5989
|
+
onClick: async () => {
|
|
5990
|
+
await rejectNote(note.id);
|
|
5991
|
+
onBack();
|
|
5992
|
+
},
|
|
5993
|
+
disabled: saving || accepting,
|
|
5994
|
+
children: [
|
|
5995
|
+
/* @__PURE__ */ jsx(X, { className: "mr-1.5 h-3.5 w-3.5" }),
|
|
5996
|
+
"Rejeitar"
|
|
5997
|
+
]
|
|
5998
|
+
}
|
|
5999
|
+
),
|
|
6000
|
+
pendencias && /* @__PURE__ */ jsx("span", { className: "truncate text-xs text-muted-foreground", children: pendencias })
|
|
6001
|
+
] }),
|
|
6002
|
+
end: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
6003
|
+
/* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", onClick: () => {
|
|
5259
6004
|
void save();
|
|
5260
6005
|
}, disabled: saving || accepting, children: [
|
|
5261
|
-
saving && /* @__PURE__ */ jsx(Loader2, { className: "mr-1.5 h-
|
|
6006
|
+
saving && /* @__PURE__ */ jsx(Loader2, { className: "mr-1.5 h-3.5 w-3.5 animate-spin" }),
|
|
5262
6007
|
"Salvar concilia\xE7\xE3o"
|
|
5263
6008
|
] }),
|
|
5264
6009
|
/* @__PURE__ */ jsxs(
|
|
5265
6010
|
Button,
|
|
5266
6011
|
{
|
|
6012
|
+
size: "sm",
|
|
5267
6013
|
onClick: () => {
|
|
5268
6014
|
void accept();
|
|
5269
6015
|
},
|
|
5270
6016
|
disabled: accepting || saving || missingType > 0 || missingProduct > 0 || unverifiedFactor > 0,
|
|
5271
6017
|
children: [
|
|
5272
|
-
accepting ? /* @__PURE__ */ jsx(Loader2, { className: "mr-1.5 h-
|
|
6018
|
+
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" }),
|
|
5273
6019
|
"Aceitar"
|
|
5274
6020
|
]
|
|
5275
6021
|
}
|
|
5276
6022
|
)
|
|
5277
6023
|
] })
|
|
5278
|
-
|
|
6024
|
+
};
|
|
5279
6025
|
return moldura(/* @__PURE__ */ jsxs("div", { className: `space-y-4 ${emModal ? "" : "pb-24"}`, children: [
|
|
5280
6026
|
cabecalho(`Concilia\xE7\xE3o \xB7 NF-e ${note.number}`),
|
|
5281
6027
|
accepted && /* @__PURE__ */ jsxs(Card, { className: "border-success bg-success-soft p-4", children: [
|
|
5282
|
-
/* @__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 ${
|
|
6028
|
+
/* @__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"}.` }),
|
|
5283
6029
|
accepted.invoiceId && onOpenInvoice && /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", className: "mt-2", onClick: () => onOpenInvoice(accepted.invoiceId), children: "Abrir a conta a pagar" })
|
|
5284
6030
|
] }),
|
|
5285
6031
|
/* @__PURE__ */ jsxs(Card, { className: "p-4", children: [
|
|
5286
6032
|
/* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold", children: "Situa\xE7\xE3o fiscal" }),
|
|
5287
6033
|
/* @__PURE__ */ jsxs("dl", { className: "mt-3 grid gap-x-6 gap-y-2 text-sm sm:grid-cols-2 lg:grid-cols-3", children: [
|
|
5288
|
-
/* @__PURE__ */
|
|
6034
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
6035
|
+
/* @__PURE__ */ jsx("dt", { className: "text-xs text-muted-foreground", children: "Fornecedor" }),
|
|
6036
|
+
/* @__PURE__ */ jsx("dd", { className: "text-sm", children: note.supplierPartyId ? /* @__PURE__ */ jsx(PersonLink, { personId: note.supplierPartyId, name: note.supplierName || "\u2014", kind: "supplier" }) : note.supplierName || "\u2014" })
|
|
6037
|
+
] }),
|
|
5289
6038
|
/* @__PURE__ */ jsx(Field, { label: "CNPJ", value: note.supplierCnpj ?? "\u2014", mono: true }),
|
|
5290
6039
|
/* @__PURE__ */ jsx(Field, { label: "Natureza da opera\xE7\xE3o", value: note.natureOperation ?? "\u2014" }),
|
|
5291
6040
|
/* @__PURE__ */ jsx(
|
|
@@ -5295,15 +6044,22 @@ function NoteReconcileView({ noteId, onBack, onOpenInvoice, chrome = "page" }) {
|
|
|
5295
6044
|
value: `${note.manifestationStatus ?? "n\xE3o manifestada"}${note.manifestationAttempts ? ` \xB7 ${note.manifestationAttempts} tentativa(s)` : ""}`
|
|
5296
6045
|
}
|
|
5297
6046
|
),
|
|
5298
|
-
/* @__PURE__ */ jsx(Field, { label: "Manifestada em", value:
|
|
5299
|
-
/* @__PURE__ */ jsx(Field, { label: "Recebida em", value:
|
|
6047
|
+
/* @__PURE__ */ jsx(Field, { label: "Manifestada em", value: day3(note.manifestedAt) }),
|
|
6048
|
+
/* @__PURE__ */ jsx(Field, { label: "Recebida em", value: day3(note.receivedAt) })
|
|
6049
|
+
] }),
|
|
6050
|
+
!note.supplierPartyId && /* @__PURE__ */ jsxs("div", { className: "mt-3 flex flex-wrap items-center justify-between gap-2 rounded-md border border-input bg-muted/40 px-3 py-2", children: [
|
|
6051
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: note.supplierCnpj ? /* @__PURE__ */ jsx(Fragment, { children: "Este fornecedor ainda n\xE3o est\xE1 no cadastro. Ao aceitar, ele \xE9 cadastrado com o nome e o CNPJ da nota." }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
6052
|
+
"A nota n\xE3o traz o CNPJ do fornecedor, ent\xE3o a conta a pagar vai nascer ",
|
|
6053
|
+
/* @__PURE__ */ jsx("strong", { children: "sem fornecedor" }),
|
|
6054
|
+
"."
|
|
6055
|
+
] }) }),
|
|
6056
|
+
note.supplierCnpj && !readOnly && /* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", disabled: cadastrando, onClick: () => {
|
|
6057
|
+
void cadastrarFornecedor();
|
|
6058
|
+
}, children: [
|
|
6059
|
+
cadastrando ? /* @__PURE__ */ jsx(Loader2, { className: "mr-1.5 h-4 w-4 animate-spin" }) : /* @__PURE__ */ jsx(UserPlus, { className: "mr-1.5 h-4 w-4" }),
|
|
6060
|
+
"Cadastrar agora"
|
|
6061
|
+
] })
|
|
5300
6062
|
] }),
|
|
5301
|
-
!note.supplierPartyId && /* @__PURE__ */ jsx("div", { className: "mt-3 rounded-md border border-warning bg-warning-soft px-3 py-2", children: /* @__PURE__ */ jsxs("p", { className: "text-xs text-warning-soft-foreground", children: [
|
|
5302
|
-
"Este fornecedor n\xE3o est\xE1 no cadastro de pessoas, ent\xE3o o t\xEDtulo a pagar vai nascer",
|
|
5303
|
-
" ",
|
|
5304
|
-
/* @__PURE__ */ jsx("strong", { children: "sem contraparte" }),
|
|
5305
|
-
". Cadastre o CNPJ antes de aceitar para a conta saber a quem se deve."
|
|
5306
|
-
] }) }),
|
|
5307
6063
|
/bonific|brinde|doacao|doação/i.test(note.natureOperation ?? "") && /* @__PURE__ */ jsx("div", { className: "mt-3 rounded-md border border-dashed border-input px-3 py-2", children: /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [
|
|
5308
6064
|
/* @__PURE__ */ jsx(Gift, { className: "mr-1 inline h-3.5 w-3.5", "aria-hidden": true }),
|
|
5309
6065
|
"A natureza desta nota \xE9 ",
|
|
@@ -5315,41 +6071,7 @@ function NoteReconcileView({ noteId, onBack, onOpenInvoice, chrome = "page" }) {
|
|
|
5315
6071
|
" ",
|
|
5316
6072
|
/* @__PURE__ */ jsx("span", { className: "rounded-full bg-muted px-1.5 py-0.5 text-[10px]", children: "Em breve" })
|
|
5317
6073
|
] }) }),
|
|
5318
|
-
/* @__PURE__ */
|
|
5319
|
-
/* @__PURE__ */ jsxs(Button, { variant: "ghost", size: "sm", onClick: () => {
|
|
5320
|
-
void load();
|
|
5321
|
-
}, children: [
|
|
5322
|
-
/* @__PURE__ */ jsx(RefreshCw, { className: "mr-1.5 h-4 w-4" }),
|
|
5323
|
-
"Atualizar status"
|
|
5324
|
-
] }),
|
|
5325
|
-
note.hasXml ? /* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", disabled: baixandoXml, onClick: () => {
|
|
5326
|
-
void baixarXml();
|
|
5327
|
-
}, children: [
|
|
5328
|
-
baixandoXml ? /* @__PURE__ */ jsx(Loader2, { className: "mr-1.5 h-4 w-4 animate-spin" }) : /* @__PURE__ */ jsx(FileDown, { className: "mr-1.5 h-4 w-4" }),
|
|
5329
|
-
"Baixar XML"
|
|
5330
|
-
] }) : /* @__PURE__ */ jsx(
|
|
5331
|
-
EmBreve,
|
|
5332
|
-
{
|
|
5333
|
-
label: "Baixar XML",
|
|
5334
|
-
o_que: "O arquivo desta nota n\xE3o foi guardado \u2014 ela entrou antes de o est\xE1gio passar a gravar o XML. Reimportar o .xml preenche"
|
|
5335
|
-
}
|
|
5336
|
-
),
|
|
5337
|
-
/* @__PURE__ */ jsx(
|
|
5338
|
-
EmBreve,
|
|
5339
|
-
{
|
|
5340
|
-
label: "DANFE (PDF)",
|
|
5341
|
-
o_que: "O espelho impresso da nota. Tem layout fixado pela SEFAZ e vinha renderizado da PlugNotas no V1 \u2014 n\xE3o sai do XML sozinho"
|
|
5342
|
-
}
|
|
5343
|
-
),
|
|
5344
|
-
/* @__PURE__ */ jsx(
|
|
5345
|
-
EmBreve,
|
|
5346
|
-
{
|
|
5347
|
-
label: "Cadastrar fornecedor",
|
|
5348
|
-
o_que: "Criar a pessoa do fornecedor aqui, sem sair da nota \u2014 \xE9 o que preenche a contraparte do t\xEDtulo",
|
|
5349
|
-
quantas: "a Laissa cadastrou 37 fornecedores no V1 enquanto importava"
|
|
5350
|
-
}
|
|
5351
|
-
)
|
|
5352
|
-
] })
|
|
6074
|
+
!emModal && /* @__PURE__ */ jsx("div", { className: "mt-3 flex flex-wrap items-center gap-2", children: ferramentas })
|
|
5353
6075
|
] }),
|
|
5354
6076
|
/* @__PURE__ */ jsxs(Card, { className: "p-4", children: [
|
|
5355
6077
|
/* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold", children: "Padr\xF5es desta nota" }),
|
|
@@ -5479,11 +6201,11 @@ function NoteReconcileView({ noteId, onBack, onOpenInvoice, chrome = "page" }) {
|
|
|
5479
6201
|
" ",
|
|
5480
6202
|
item.unit ?? "",
|
|
5481
6203
|
" \xB7 ",
|
|
5482
|
-
|
|
6204
|
+
money3(item.unitPrice),
|
|
5483
6205
|
typeLabel ? ` \xB7 ${typeLabel}` : " \xB7 sem tipo"
|
|
5484
6206
|
] })
|
|
5485
6207
|
] }),
|
|
5486
|
-
/* @__PURE__ */ jsx("span", { className: "shrink-0 text-sm tabular-nums", children:
|
|
6208
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0 text-sm tabular-nums", children: money3(item.total) }),
|
|
5487
6209
|
d.suggestedBy && !done && /* @__PURE__ */ jsx(AuthorBadge, { draft: d }),
|
|
5488
6210
|
/* @__PURE__ */ jsx(ItemState, { done: done && ready, ready })
|
|
5489
6211
|
]
|
|
@@ -5499,8 +6221,8 @@ function NoteReconcileView({ noteId, onBack, onOpenInvoice, chrome = "page" }) {
|
|
|
5499
6221
|
] }),
|
|
5500
6222
|
/* @__PURE__ */ jsxs("dl", { className: "mt-2 grid grid-cols-2 gap-x-4 gap-y-1 text-xs sm:grid-cols-4", children: [
|
|
5501
6223
|
/* @__PURE__ */ jsx(Field, { small: true, label: "Qtd", value: `${qty(item.quantity)} ${item.unit ?? ""}` }),
|
|
5502
|
-
/* @__PURE__ */ jsx(Field, { small: true, label: "Vl. unit.", value:
|
|
5503
|
-
/* @__PURE__ */ jsx(Field, { small: true, label: "Total", value:
|
|
6224
|
+
/* @__PURE__ */ jsx(Field, { small: true, label: "Vl. unit.", value: money3(item.unitPrice) }),
|
|
6225
|
+
/* @__PURE__ */ jsx(Field, { small: true, label: "Total", value: money3(item.total) }),
|
|
5504
6226
|
/* @__PURE__ */ jsx(Field, { small: true, label: "C\xF3d", value: item.supplierProductCode || "\u2014", mono: true }),
|
|
5505
6227
|
/* @__PURE__ */ jsx(Field, { small: true, label: "EAN", value: item.eanBarcode ?? "\u2014", mono: true }),
|
|
5506
6228
|
/* @__PURE__ */ jsx(Field, { small: true, label: "NCM", value: item.ncm ?? "\u2014", mono: true }),
|
|
@@ -5617,7 +6339,7 @@ function NoteReconcileView({ noteId, onBack, onOpenInvoice, chrome = "page" }) {
|
|
|
5617
6339
|
] }),
|
|
5618
6340
|
/* @__PURE__ */ jsxs("div", { className: "flex items-baseline justify-between text-sm", children: [
|
|
5619
6341
|
/* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: "Novo custo unit\xE1rio" }),
|
|
5620
|
-
/* @__PURE__ */ jsx("span", { className: "tabular-nums", children:
|
|
6342
|
+
/* @__PURE__ */ jsx("span", { className: "tabular-nums", children: money3(unitCost) })
|
|
5621
6343
|
] })
|
|
5622
6344
|
] }),
|
|
5623
6345
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
|
|
@@ -5720,18 +6442,18 @@ function NoteReconcileView({ noteId, onBack, onOpenInvoice, chrome = "page" }) {
|
|
|
5720
6442
|
instalments.length === 1 ? "parcela" : "parcelas",
|
|
5721
6443
|
" \xB7",
|
|
5722
6444
|
" ",
|
|
5723
|
-
/* @__PURE__ */ jsx("span", { className: "tabular-nums", children:
|
|
6445
|
+
/* @__PURE__ */ jsx("span", { className: "tabular-nums", children: money3(instalmentSum) })
|
|
5724
6446
|
] })
|
|
5725
6447
|
] }),
|
|
5726
6448
|
note.declaredPayments.length > 0 && /* @__PURE__ */ jsxs("p", { className: "mt-1 text-xs text-muted-foreground", children: [
|
|
5727
6449
|
"A nota declarou: ",
|
|
5728
|
-
note.declaredPayments.map((p) => `${p.label ?? p.code} ${
|
|
6450
|
+
note.declaredPayments.map((p) => `${p.label ?? p.code} ${money3(p.value)}`).join(" \xB7 ")
|
|
5729
6451
|
] }),
|
|
5730
6452
|
/* @__PURE__ */ jsx("div", { className: "mt-3 space-y-2", children: instalments.map((inst, i) => /* @__PURE__ */ jsxs("div", { className: "grid items-end gap-2 sm:grid-cols-[2rem_1fr_1fr_1fr_2rem]", children: [
|
|
5731
6453
|
/* @__PURE__ */ jsx("span", { className: "pb-2 text-xs tabular-nums text-muted-foreground", children: inst.index }),
|
|
5732
6454
|
/* @__PURE__ */ jsxs("label", { className: "block", children: [
|
|
5733
6455
|
/* @__PURE__ */ jsx("span", { className: "text-[11px] text-muted-foreground", children: "Vencimento" }),
|
|
5734
|
-
readOnly ? /* @__PURE__ */ jsx("p", { className: "py-2 text-sm tabular-nums", children:
|
|
6456
|
+
readOnly ? /* @__PURE__ */ jsx("p", { className: "py-2 text-sm tabular-nums", children: day3(inst.dueDate) }) : /* @__PURE__ */ jsx(
|
|
5735
6457
|
DatePicker,
|
|
5736
6458
|
{
|
|
5737
6459
|
value: inst.dueDate ?? "",
|
|
@@ -5795,41 +6517,24 @@ function NoteReconcileView({ noteId, onBack, onOpenInvoice, chrome = "page" }) {
|
|
|
5795
6517
|
Math.abs(instalmentSum - note.total) > 0.01 && /* @__PURE__ */ jsx(Hint, { className: "mt-3", children: /* @__PURE__ */ jsxs("span", { children: [
|
|
5796
6518
|
/* @__PURE__ */ jsx(AlertTriangle, { className: "mr-1 inline h-3.5 w-3.5", "aria-hidden": true }),
|
|
5797
6519
|
"A nota diz ",
|
|
5798
|
-
|
|
6520
|
+
money3(note.total),
|
|
5799
6521
|
" e as parcelas somam ",
|
|
5800
|
-
|
|
6522
|
+
money3(instalmentSum),
|
|
5801
6523
|
". O t\xEDtulo vai nascer com ",
|
|
5802
|
-
/* @__PURE__ */ jsx("strong", { children:
|
|
6524
|
+
/* @__PURE__ */ jsx("strong", { children: money3(instalmentSum) }),
|
|
5803
6525
|
" \u2014 \xE9 a soma das parcelas que define o saldo a pagar."
|
|
5804
6526
|
] }) })
|
|
5805
6527
|
] }),
|
|
5806
|
-
/* @__PURE__ */
|
|
5807
|
-
|
|
5808
|
-
|
|
5809
|
-
|
|
5810
|
-
|
|
5811
|
-
|
|
5812
|
-
|
|
5813
|
-
|
|
5814
|
-
|
|
5815
|
-
|
|
5816
|
-
EmBreve,
|
|
5817
|
-
{
|
|
5818
|
-
label: "Anexar boleto",
|
|
5819
|
-
o_que: "Guardar o arquivo no t\xEDtulo que esta nota cria",
|
|
5820
|
-
quantas: "25 anexos no V1, o \xFAltimo hoje"
|
|
5821
|
-
}
|
|
5822
|
-
),
|
|
5823
|
-
/* @__PURE__ */ jsx(
|
|
5824
|
-
EmBreve,
|
|
5825
|
-
{
|
|
5826
|
-
label: "Ler o c\xF3digo de barras do boleto",
|
|
5827
|
-
o_que: "Preencher vencimento e valor da parcela a partir do boleto anexado",
|
|
5828
|
-
quantas: "automa\xE7\xE3o do V1 que ningu\xE9m documentou"
|
|
5829
|
-
}
|
|
5830
|
-
)
|
|
5831
|
-
] })
|
|
5832
|
-
] }),
|
|
6528
|
+
/* @__PURE__ */ jsx(
|
|
6529
|
+
NoteAttachmentsCard,
|
|
6530
|
+
{
|
|
6531
|
+
noteId: note.id,
|
|
6532
|
+
invoiceId: note.invoiceId,
|
|
6533
|
+
readOnly,
|
|
6534
|
+
instalments,
|
|
6535
|
+
onInstalments: setInstalments
|
|
6536
|
+
}
|
|
6537
|
+
),
|
|
5833
6538
|
error && /* @__PURE__ */ jsx(Card, { className: "border-destructive bg-destructive/5 p-4", children: /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: error }) })
|
|
5834
6539
|
] }), `Concilia\xE7\xE3o \xB7 NF-e ${note.number}`, rodape);
|
|
5835
6540
|
}
|
|
@@ -5858,8 +6563,8 @@ function Field({ label, value, mono, small }) {
|
|
|
5858
6563
|
/* @__PURE__ */ jsx("dd", { className: `${mono ? "tabular-nums" : ""} ${small ? "text-xs" : "text-sm"}`, children: value })
|
|
5859
6564
|
] });
|
|
5860
6565
|
}
|
|
5861
|
-
var
|
|
5862
|
-
var
|
|
6566
|
+
var money4 = (v) => new Intl.NumberFormat("pt-BR", { style: "currency", currency: "BRL" }).format(v || 0);
|
|
6567
|
+
var day4 = (iso) => iso ? iso.slice(0, 10).split("-").reverse().join("/") : "\u2014";
|
|
5863
6568
|
var MANIFEST_TONE = {
|
|
5864
6569
|
confirmada: "bg-success-soft text-success-soft-foreground",
|
|
5865
6570
|
processando: "bg-info-soft text-info-soft-foreground",
|
|
@@ -5869,6 +6574,7 @@ function ManifestView({ onOpenNote, onBack }) {
|
|
|
5869
6574
|
const [notes, setNotes] = useState([]);
|
|
5870
6575
|
const [loading, setLoading] = useState(true);
|
|
5871
6576
|
const [tab, setTab] = useState("pendentes");
|
|
6577
|
+
const [pullOpen, setPullOpen] = useState(false);
|
|
5872
6578
|
const reload = useCallback(async () => {
|
|
5873
6579
|
setLoading(true);
|
|
5874
6580
|
try {
|
|
@@ -5918,12 +6624,19 @@ function ManifestView({ onOpenNote, onBack }) {
|
|
|
5918
6624
|
/* @__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." }) }),
|
|
5919
6625
|
/* @__PURE__ */ jsxs("div", { className: "mt-3 flex flex-wrap gap-2", children: [
|
|
5920
6626
|
/* @__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" }),
|
|
5921
|
-
/* @__PURE__ */
|
|
6627
|
+
/* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", onClick: () => setPullOpen(true), children: [
|
|
6628
|
+
/* @__PURE__ */ jsx(KeyRound, { className: "mr-1.5 h-4 w-4" }),
|
|
6629
|
+
"Puxar por chave"
|
|
6630
|
+
] }),
|
|
5922
6631
|
/* @__PURE__ */ jsx(EmBreve, { label: "Sincronizar agora", o_que: "Pedir \xE0 SEFAZ o que chegou desde a \xFAltima varredura" }),
|
|
5923
6632
|
/* @__PURE__ */ jsx(EmBreve, { label: "Resincronizar tudo", o_que: "Refazer a varredura inteira do per\xEDodo" }),
|
|
5924
6633
|
/* @__PURE__ */ jsx(EmBreve, { label: "Diagnosticar", o_que: "Por que uma nota n\xE3o chegou: certificado, credencial ou cursor parado" })
|
|
5925
6634
|
] })
|
|
5926
6635
|
] }),
|
|
6636
|
+
/* @__PURE__ */ jsx(PullByKeyDialog, { open: pullOpen, onOpenChange: setPullOpen, onPulled: (r) => {
|
|
6637
|
+
void reload();
|
|
6638
|
+
onOpenNote(r.documentId);
|
|
6639
|
+
} }),
|
|
5927
6640
|
/* @__PURE__ */ jsx(ListFilterBar, { filters, onClear: () => setTab("todas"), activeCount: tab === "todas" ? 0 : 1 }),
|
|
5928
6641
|
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: [
|
|
5929
6642
|
/* @__PURE__ */ jsx(FileText, { className: "mx-auto h-8 w-8 text-muted-foreground", "aria-hidden": true }),
|
|
@@ -5939,10 +6652,10 @@ function ManifestView({ onOpenNote, onBack }) {
|
|
|
5939
6652
|
/* @__PURE__ */ jsx("th", { className: "px-3 py-2 text-right font-medium", children: "A\xE7\xF5es" })
|
|
5940
6653
|
] }) }),
|
|
5941
6654
|
/* @__PURE__ */ jsx("tbody", { children: shown.map((note) => /* @__PURE__ */ jsxs("tr", { className: "border-b last:border-0 hover:bg-muted/30", children: [
|
|
5942
|
-
/* @__PURE__ */ jsx("td", { className: "px-3 py-2 tabular-nums text-muted-foreground", children:
|
|
6655
|
+
/* @__PURE__ */ jsx("td", { className: "px-3 py-2 tabular-nums text-muted-foreground", children: day4(note.issueDate) }),
|
|
5943
6656
|
/* @__PURE__ */ jsx("td", { className: "px-3 py-2 tabular-nums font-medium", children: note.number }),
|
|
5944
6657
|
/* @__PURE__ */ jsx("td", { className: "px-3 py-2", children: note.supplierName || "\u2014" }),
|
|
5945
|
-
/* @__PURE__ */ jsx("td", { className: "px-3 py-2 text-right tabular-nums", children:
|
|
6658
|
+
/* @__PURE__ */ jsx("td", { className: "px-3 py-2 text-right tabular-nums", children: money4(note.total) }),
|
|
5946
6659
|
/* @__PURE__ */ jsx("td", { className: "px-3 py-2 text-right tabular-nums text-muted-foreground", children: note.instalmentCount }),
|
|
5947
6660
|
/* @__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" }) }),
|
|
5948
6661
|
/* @__PURE__ */ jsx("td", { className: "px-3 py-2", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-1.5", children: [
|
|
@@ -6078,9 +6791,9 @@ var COLUMNS = [
|
|
|
6078
6791
|
].join(", ");
|
|
6079
6792
|
var sb2 = () => getSupabaseClientOptional();
|
|
6080
6793
|
function useEmitterSettings(legalEntityId) {
|
|
6081
|
-
const [row, setRow] =
|
|
6082
|
-
const [loading, setLoading] =
|
|
6083
|
-
|
|
6794
|
+
const [row, setRow] = React7.useState(null);
|
|
6795
|
+
const [loading, setLoading] = React7.useState(true);
|
|
6796
|
+
React7.useEffect(() => {
|
|
6084
6797
|
if (!legalEntityId) {
|
|
6085
6798
|
setLoading(false);
|
|
6086
6799
|
return;
|
|
@@ -6096,7 +6809,7 @@ function useEmitterSettings(legalEntityId) {
|
|
|
6096
6809
|
alive = false;
|
|
6097
6810
|
};
|
|
6098
6811
|
}, [legalEntityId]);
|
|
6099
|
-
const save =
|
|
6812
|
+
const save = React7.useCallback(async (tenantId, patch) => {
|
|
6100
6813
|
if (!legalEntityId) return false;
|
|
6101
6814
|
const payload = { ...patch, tenant_id: tenantId, legal_entity_id: legalEntityId, updated_at: (/* @__PURE__ */ new Date()).toISOString() };
|
|
6102
6815
|
const { data, error } = await sb2().from("plg_fiscalbr_emitter_settings").upsert(payload, { onConflict: "legal_entity_id" }).select(COLUMNS).single();
|
|
@@ -6149,7 +6862,7 @@ function SummaryCard({ title, lines, badge, onConfigure }) {
|
|
|
6149
6862
|
return /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsxs(CardHeader, { className: "flex-row items-start justify-between gap-3 space-y-0", children: [
|
|
6150
6863
|
/* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
|
|
6151
6864
|
/* @__PURE__ */ jsx(CardTitle, { className: "text-base", children: title }),
|
|
6152
|
-
/* @__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(
|
|
6865
|
+
/* @__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(React7.Fragment, { children: [
|
|
6153
6866
|
/* @__PURE__ */ jsx("dt", { className: "text-muted-foreground", children: l.label }),
|
|
6154
6867
|
/* @__PURE__ */ jsx("dd", { className: "text-foreground", children: l.value })
|
|
6155
6868
|
] }, l.label)) })
|
|
@@ -6170,7 +6883,7 @@ function SummaryCard({ title, lines, badge, onConfigure }) {
|
|
|
6170
6883
|
var fmtDateTime = (v) => v ? new Date(v).toLocaleString("pt-BR") : null;
|
|
6171
6884
|
function UnitCertificateWidget({ item }) {
|
|
6172
6885
|
const { row, loading, save } = useEmitterSettings(item?.legalEntityId);
|
|
6173
|
-
const [open, setOpen] =
|
|
6886
|
+
const [open, setOpen] = React7.useState(false);
|
|
6174
6887
|
if (!item?.id) return null;
|
|
6175
6888
|
if (!item.legalEntityId) return /* @__PURE__ */ jsx(NeedsLegalEntity, { item, what: "O certificado digital" });
|
|
6176
6889
|
if (loading || !row) return /* @__PURE__ */ jsx(LoadingCard, {});
|
|
@@ -6273,11 +6986,11 @@ function EnvSelect({ value, onChange, disabled }) {
|
|
|
6273
6986
|
}
|
|
6274
6987
|
function UnitFiscalWidget({ item }) {
|
|
6275
6988
|
const { row, loading, save } = useEmitterSettings(item?.legalEntityId);
|
|
6276
|
-
const [draft, setDraft] =
|
|
6277
|
-
const [cscToken, setCscToken] =
|
|
6278
|
-
const [saving, setSaving] =
|
|
6279
|
-
const [open, setOpen] =
|
|
6280
|
-
|
|
6989
|
+
const [draft, setDraft] = React7.useState({});
|
|
6990
|
+
const [cscToken, setCscToken] = React7.useState("");
|
|
6991
|
+
const [saving, setSaving] = React7.useState(false);
|
|
6992
|
+
const [open, setOpen] = React7.useState(false);
|
|
6993
|
+
React7.useEffect(() => {
|
|
6281
6994
|
if (row) setDraft(row);
|
|
6282
6995
|
}, [row]);
|
|
6283
6996
|
if (!item?.id) return null;
|
|
@@ -6645,7 +7358,7 @@ var dayOrDateTime = (v) => {
|
|
|
6645
7358
|
const d = new Date(v);
|
|
6646
7359
|
return d.getHours() === 0 && d.getMinutes() === 0 && d.getSeconds() === 0 ? d.toLocaleDateString("pt-BR") : dateTime(v);
|
|
6647
7360
|
};
|
|
6648
|
-
var
|
|
7361
|
+
var money5 = (v) => v == null ? "\u2014" : v.toLocaleString("pt-BR", { style: "currency", currency: "BRL" });
|
|
6649
7362
|
function buttonHint(s) {
|
|
6650
7363
|
const parts = [s.hasValid ? "Notas fiscais desta conta \u2014 h\xE1 uma nota v\xE1lida" : "Notas fiscais desta conta"];
|
|
6651
7364
|
if (s.withoutEffect > 0) parts.push(`${s.withoutEffect} cancelada(s), rejeitada(s) ou com erro`);
|
|
@@ -6713,7 +7426,7 @@ function NoteRow({ note, canCancel, onChanged }) {
|
|
|
6713
7426
|
else window.location.assign(url);
|
|
6714
7427
|
} catch (e) {
|
|
6715
7428
|
w?.close();
|
|
6716
|
-
toast.error("PDF indispon\xEDvel", { description:
|
|
7429
|
+
toast.error("PDF indispon\xEDvel", { description: describeError(e) });
|
|
6717
7430
|
} finally {
|
|
6718
7431
|
setBusy(null);
|
|
6719
7432
|
}
|
|
@@ -6725,7 +7438,7 @@ function NoteRow({ note, canCancel, onChanged }) {
|
|
|
6725
7438
|
await onChanged();
|
|
6726
7439
|
toast(status === note.status ? "Ainda em processamento na SEFAZ/prefeitura" : `Nota ${statusLabel({ status, cancelledAt: null }).toLowerCase()}`);
|
|
6727
7440
|
} catch (e) {
|
|
6728
|
-
toast.error("N\xE3o foi poss\xEDvel consultar", { description:
|
|
7441
|
+
toast.error("N\xE3o foi poss\xEDvel consultar", { description: describeError(e) });
|
|
6729
7442
|
} finally {
|
|
6730
7443
|
setBusy(null);
|
|
6731
7444
|
}
|
|
@@ -6813,7 +7526,7 @@ function CancelNotePanel({ note, onClose, onDone }) {
|
|
|
6813
7526
|
else toast("Cancelamento solicitado", { description: "A SEFAZ/prefeitura ainda est\xE1 processando. Use \xABAtualizar\xBB para conferir." });
|
|
6814
7527
|
await onDone();
|
|
6815
7528
|
} catch (e) {
|
|
6816
|
-
setError(
|
|
7529
|
+
setError(describeError(e));
|
|
6817
7530
|
setWorking(null);
|
|
6818
7531
|
}
|
|
6819
7532
|
};
|
|
@@ -6884,7 +7597,7 @@ function NoteDetails({ note }) {
|
|
|
6884
7597
|
["Refer\xEAncia", note.integrationId && /* @__PURE__ */ jsx("span", { className: "break-all font-mono text-xs", children: note.integrationId })],
|
|
6885
7598
|
["Chave de acesso", note.accessKey && /* @__PURE__ */ jsx("span", { className: "break-all font-mono text-xs", children: note.accessKey })],
|
|
6886
7599
|
["C\xF3digo de verifica\xE7\xE3o", note.verificationCode],
|
|
6887
|
-
["Valor",
|
|
7600
|
+
["Valor", money5(note.totalValue)],
|
|
6888
7601
|
["Tomador", recipientLabel(note.recipient)],
|
|
6889
7602
|
["Criada em", dateTime(note.createdAt)],
|
|
6890
7603
|
["Autorizada em", note.authorizedAt && dayOrDateTime(note.authorizedAt)],
|
|
@@ -7099,9 +7812,9 @@ function inboundNotesInventoryView(options = {}) {
|
|
|
7099
7812
|
};
|
|
7100
7813
|
}
|
|
7101
7814
|
function InboundNoteDocumentModal({ movement, onClose }) {
|
|
7102
|
-
const [noteId, setNoteId] =
|
|
7103
|
-
const [erro, setErro] =
|
|
7104
|
-
|
|
7815
|
+
const [noteId, setNoteId] = React7.useState(null);
|
|
7816
|
+
const [erro, setErro] = React7.useState(null);
|
|
7817
|
+
React7.useEffect(() => {
|
|
7105
7818
|
let vivo = true;
|
|
7106
7819
|
const numero = nfeNumberOf(movement);
|
|
7107
7820
|
const busca = movement.operationId ? findInboxNoteByOperation(movement.operationId).then((id) => id ?? (numero ? findInboxNoteByNumber(numero) : null)) : numero ? findInboxNoteByNumber(numero) : Promise.resolve(null);
|
|
@@ -7110,7 +7823,7 @@ function InboundNoteDocumentModal({ movement, onClose }) {
|
|
|
7110
7823
|
if (id) setNoteId(id);
|
|
7111
7824
|
else setErro("N\xE3o achei a nota desta entrada nesta conta.");
|
|
7112
7825
|
}).catch((e) => {
|
|
7113
|
-
if (vivo) setErro(
|
|
7826
|
+
if (vivo) setErro(describeError(e));
|
|
7114
7827
|
});
|
|
7115
7828
|
return () => {
|
|
7116
7829
|
vivo = false;
|
|
@@ -7283,6 +7996,6 @@ function createPlugNotasPlugin(options = {}) {
|
|
|
7283
7996
|
});
|
|
7284
7997
|
}
|
|
7285
7998
|
|
|
7286
|
-
export { EVENT_LABEL, InboundNoteDocumentModal, InboundNotesPage, InboundNotesView, InvoiceNotesButton, IssuedNotesView, MODEL_LABEL, ManifestView, NfeParseError, NoteReconcileView, PLUGNOTAS_CONNECTOR_ID, PLUGNOTAS_FIELDS, PLUGNOTAS_SETTINGS, ReturnedNotesView, STATUS_META, STOCK_BEARING_ENTRY_TYPES, TaxGroupsView, acceptNote, cancelNote, createPlugNotasConnector, createPlugNotasFinancialProvider, createPlugNotasPlugin, eventStatusLabel, explainRejection, fetchNotePdf, findInboxNoteByNumber, findInboxNoteByOperation, getInboxNote, getInboxNoteXml, inboundNoteDocumentModal, inboundNotesInventoryView, isStockBearing, isValidCnpj, isWithoutEffect, listChartAccounts, listInboxNotes, listInvoiceNotes, listMeasurementUnits, listNoteEvents, listProductsByIds, listStockLocations, listSupplierMap, markPlugNotasEmitterReady, notesButtonState, onlyDigits, parseNfeXml, paymentLabel, paymentTypeFromCode, recipientLabel, refreshNote, rejectNote, saveNoteDecision, searchProducts, stageNoteFromXml, statusLabel, suggestNoteItems, summarizeNotes, toStagePayload };
|
|
7999
|
+
export { EVENT_LABEL, InboundNoteDocumentModal, InboundNotesPage, InboundNotesView, InvoiceNotesButton, IssuedNotesView, MODEL_LABEL, ManifestView, 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, findInboxNoteByNumber, findInboxNoteByOperation, getInboxNote, getInboxNotePdf, getInboxNoteXml, inboundNoteDocumentModal, inboundNotesInventoryView, isStockBearing, isValidCnpj, isWithoutEffect, linkInboxSupplier, listChartAccounts, listInboxNotes, listInvoiceNotes, listMeasurementUnits, listNoteAttachments, listNoteEvents, listProductsByIds, listStockLocations, listSupplierMap, markPlugNotasEmitterReady, moveNoteAttachmentsToInvoice, notesButtonState, onlyDigits, parseBoleto, parseNfeXml, paymentLabel, paymentTypeFromCode, pullNoteByKey, recipientLabel, refreshNote, rejectNote, removeNoteAttachment, saveNoteDecision, searchProducts, stageNoteFromXml, statusLabel, suggestNoteItems, summarizeNotes, toStagePayload };
|
|
7287
8000
|
//# sourceMappingURL=index.js.map
|
|
7288
8001
|
//# sourceMappingURL=index.js.map
|