@fayz-ai/plugin-fiscal-br 0.2.5 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -950,9 +950,638 @@ BEGIN
950
950
  RETURNING j.*;
951
951
  END $$;
952
952
  `;
953
+ var MIGRATION_002_A_NOTA_QUE_CHEGA_TEM_ONDE_ESPERAR = `-- A nota que chega tem onde esperar.
954
+ --
955
+ -- O V1 recebe NF-e de fornecedor pela SEFAZ e guarda cada uma numa caixa de
956
+ -- entrada antes de algu\xE9m decidir o que fazer com ela: manifestar, importar
957
+ -- para o estoque, ou nada. Essa caixa n\xE3o tinha destino no V2.
958
+ --
959
+ -- dfe_inbox 703 a nota recebida, com o XML inteiro
960
+ -- dfe_inbox_items 3.215 o item da nota, com todo o tributo
961
+ -- dfe_inbox_payments 739 a forma de pagamento declarada
962
+ -- dfe_inbox_duplicatas 830 o vencimento da duplicata
963
+ -- fiscal_groups 11 o grupo fiscal (CFOP, CST, al\xEDquotas)
964
+ --
965
+ -- Os n\xFAmeros somam os dois tenants: Espa\xE7o Facial e Pertinho do C\xE9u. \xC9 o \xFAnico
966
+ -- dom\xEDnio fiscal que os dois usam.
967
+ --
968
+ -- \u2500\u2500 O XML \xE9 arquivo, e arquivo mora em public.documents \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
969
+ --
970
+ -- \`dfe_inbox.xml_content\` \xE9 o XML inteiro numa coluna de texto, e
971
+ -- \`pdf_storage_path\` aponta para o DANFE no storage do V1. Os dois s\xE3o ARQUIVO,
972
+ -- e o V2 j\xE1 tem o arqu\xE9tipo: \`public.documents\`, com kind, checksum, storage_*
973
+ -- e a RLS de arquivo que uma coluna de texto nunca teria.
974
+ --
975
+ -- Ent\xE3o a extens\xE3o guarda um PONTEIRO \u2014 \`document_id\` \u2014 e os bytes v\xE3o para o
976
+ -- arqu\xE9tipo, pelo est\xE1gio de assets (\`make mig-assets\`), que \xE9 quem alcan\xE7a
977
+ -- object storage. Enquanto os bytes n\xE3o chegam, \`document_id\` fica nulo e o
978
+ -- caminho de origem fica em metadata: a linha \xE9 verdadeira nos dois momentos.
979
+ --
980
+ -- \u2500\u2500 O tributo vem inteiro, e de prop\xF3sito \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
981
+ --
982
+ -- 30 colunas de imposto por item (ICMS, ICMS-ST, PIS, COFINS, IPI, com base,
983
+ -- al\xEDquota e valor de cada). \xC9 muita coluna, e a tenta\xE7\xE3o \xE9 jogar tudo num
984
+ -- jsonb. N\xE3o: isto \xE9 documento fiscal recebido, e a pergunta que se faz dele \xE9
985
+ -- "quanto de ICMS entrou neste m\xEAs" \u2014 uma soma, sobre coluna, com \xEDndice. Um
986
+ -- jsonb transformaria toda apura\xE7\xE3o numa varredura.
987
+ --
988
+ -- O que VAI para jsonb \xE9 o \`raw_xml_item\`, que j\xE1 \xE9 jsonb na origem e existe
989
+ -- para confer\xEAncia, n\xE3o para conta.
990
+ --
991
+ -- Idempotente.
992
+
993
+ CREATE TABLE IF NOT EXISTS public.plg_fiscalbr_inbox_documents (
994
+ id uuid DEFAULT gen_random_uuid() NOT NULL,
995
+ tenant_id uuid NOT NULL,
996
+ unit_id uuid,
997
+ -- O ponteiro para o arqu\xE9tipo. Nulo enquanto os bytes n\xE3o subiram \u2014 o
998
+ -- caminho de origem fica em metadata at\xE9 l\xE1.
999
+ document_id uuid,
1000
+ access_key text,
1001
+ nfe_number text,
1002
+ nfe_series text,
1003
+ nfe_model text,
1004
+ issue_date timestamp with time zone,
1005
+ received_at timestamp with time zone,
1006
+ status text DEFAULT 'received'::text NOT NULL,
1007
+ -- A manifesta\xE7\xE3o do destinat\xE1rio \xE9 outro eixo que o status: uma nota pode
1008
+ -- estar recebida e n\xE3o manifestada, e \xE9 a manifesta\xE7\xE3o que a SEFAZ cobra.
1009
+ manifestation_status text,
1010
+ manifested_at timestamp with time zone,
1011
+ manifestation_attempts integer DEFAULT 0 NOT NULL,
1012
+ manifestation_response jsonb,
1013
+ supplier_party_id uuid,
1014
+ supplier_cnpj text,
1015
+ supplier_name text,
1016
+ supplier_ie text,
1017
+ total_value numeric(14,2),
1018
+ total_products numeric(14,2),
1019
+ total_discount numeric(14,2),
1020
+ total_freight numeric(14,2),
1021
+ total_insurance numeric(14,2),
1022
+ total_other numeric(14,2),
1023
+ total_icms_base numeric(14,2),
1024
+ total_icms_value numeric(14,2),
1025
+ total_icms_st_base numeric(14,2),
1026
+ total_icms_st_value numeric(14,2),
1027
+ total_pis_value numeric(14,2),
1028
+ total_cofins_value numeric(14,2),
1029
+ total_ipi_value numeric(14,2),
1030
+ nfe_protocol text,
1031
+ nfe_authorized_at timestamp with time zone,
1032
+ carrier_name text,
1033
+ carrier_cnpj text,
1034
+ freight_mode_code text,
1035
+ additional_info text,
1036
+ reviewed_at timestamp with time zone,
1037
+ -- O que essa nota virou no estoque, quando virou. Nulo \xE9 nota recebida e
1038
+ -- n\xE3o importada, que \xE9 a maioria.
1039
+ inventory_operation_id uuid,
1040
+ owner_id uuid,
1041
+ metadata jsonb DEFAULT '{}'::jsonb NOT NULL,
1042
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
1043
+ updated_at timestamp with time zone DEFAULT now() NOT NULL
1044
+ );
1045
+
1046
+ COMMENT ON TABLE public.plg_fiscalbr_inbox_documents IS
1047
+ 'A NF-e de fornecedor recebida da SEFAZ, esperando manifesta\xE7\xE3o ou importa\xE7\xE3o. V1: dfe_inbox.';
1048
+ COMMENT ON COLUMN public.plg_fiscalbr_inbox_documents.document_id IS
1049
+ 'V1: xml_content + pdf_storage_path. O XML e o DANFE s\xE3o arquivo; os bytes moram em public.documents e aqui fica o ponteiro.';
1050
+
1051
+ CREATE TABLE IF NOT EXISTS public.plg_fiscalbr_inbox_items (
1052
+ id uuid DEFAULT gen_random_uuid() NOT NULL,
1053
+ tenant_id uuid NOT NULL,
1054
+ inbox_document_id uuid NOT NULL,
1055
+ item_number integer,
1056
+ supplier_product_code text,
1057
+ ean_barcode text,
1058
+ ean_taxable text,
1059
+ description text,
1060
+ ncm text,
1061
+ cest text,
1062
+ cfop text,
1063
+ unit_commercial text,
1064
+ unit_taxable text,
1065
+ quantity_commercial numeric(18,4),
1066
+ quantity_taxable numeric(18,4),
1067
+ unit_price_commercial numeric(18,6),
1068
+ unit_price_taxable numeric(18,6),
1069
+ total_price numeric(14,2),
1070
+ discount numeric(14,2),
1071
+ freight numeric(14,2),
1072
+ insurance numeric(14,2),
1073
+ other_expenses numeric(14,2),
1074
+ icms_cst text, icms_csosn text, icms_origin text,
1075
+ icms_base numeric(14,2), icms_rate numeric(9,4), icms_value numeric(14,2),
1076
+ icms_st_base numeric(14,2), icms_st_value numeric(14,2),
1077
+ pis_cst text, pis_base numeric(14,2), pis_rate numeric(9,4), pis_value numeric(14,2),
1078
+ cofins_cst text, cofins_base numeric(14,2), cofins_rate numeric(9,4), cofins_value numeric(14,2),
1079
+ ipi_cst text, ipi_rate numeric(9,4), ipi_value numeric(14,2),
1080
+ -- O produto do V2 que esta linha da nota representa. \`reconciled\` \xE9 a
1081
+ -- decis\xE3o de quem conferiu; o id \xE9 o resultado dela.
1082
+ product_id uuid,
1083
+ reconciled boolean DEFAULT false NOT NULL,
1084
+ raw_xml_item jsonb,
1085
+ metadata jsonb DEFAULT '{}'::jsonb NOT NULL,
1086
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
1087
+ updated_at timestamp with time zone DEFAULT now() NOT NULL
1088
+ );
1089
+
1090
+ COMMENT ON TABLE public.plg_fiscalbr_inbox_items IS
1091
+ 'O item da NF-e recebida, com o tributo em coluna \u2014 a apura\xE7\xE3o soma coluna, n\xE3o varre jsonb. V1: dfe_inbox_items.';
1092
+
1093
+ CREATE TABLE IF NOT EXISTS public.plg_fiscalbr_inbox_payments (
1094
+ id uuid DEFAULT gen_random_uuid() NOT NULL,
1095
+ tenant_id uuid NOT NULL,
1096
+ inbox_document_id uuid NOT NULL,
1097
+ payment_index integer,
1098
+ payment_indicator text,
1099
+ payment_type_code text,
1100
+ payment_type_label text,
1101
+ value numeric(14,2),
1102
+ change_given numeric(14,2),
1103
+ card_brand text,
1104
+ card_acquirer_cnpj text,
1105
+ card_auth_code text,
1106
+ metadata jsonb DEFAULT '{}'::jsonb NOT NULL,
1107
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
1108
+ updated_at timestamp with time zone DEFAULT now() NOT NULL
1109
+ );
1110
+
1111
+ CREATE TABLE IF NOT EXISTS public.plg_fiscalbr_inbox_duplicates (
1112
+ id uuid DEFAULT gen_random_uuid() NOT NULL,
1113
+ tenant_id uuid NOT NULL,
1114
+ inbox_document_id uuid NOT NULL,
1115
+ duplicate_index integer,
1116
+ number text,
1117
+ due_date date,
1118
+ value numeric(14,2),
1119
+ -- O que essa duplicata virou no contas a pagar, se algu\xE9m a lan\xE7ou.
1120
+ installment_id uuid,
1121
+ metadata jsonb DEFAULT '{}'::jsonb NOT NULL,
1122
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
1123
+ updated_at timestamp with time zone DEFAULT now() NOT NULL
1124
+ );
1125
+
1126
+ COMMENT ON TABLE public.plg_fiscalbr_inbox_duplicates IS
1127
+ 'O vencimento declarado na NF-e recebida. Vira parcela do contas a pagar quando algu\xE9m lan\xE7a a nota. V1: dfe_inbox_duplicatas.';
1128
+
1129
+ CREATE TABLE IF NOT EXISTS public.plg_fiscalbr_tax_groups (
1130
+ id uuid DEFAULT gen_random_uuid() NOT NULL,
1131
+ tenant_id uuid NOT NULL,
1132
+ name text NOT NULL,
1133
+ cfop text,
1134
+ csosn text,
1135
+ cst text,
1136
+ icms_origin text,
1137
+ icms_rate numeric(9,4),
1138
+ icms_bc_mode text,
1139
+ pis_situation text,
1140
+ pis_rate numeric(9,4),
1141
+ cofins_situation text,
1142
+ cofins_rate numeric(9,4),
1143
+ -- A reforma tribut\xE1ria j\xE1 est\xE1 no cadastro do V1 e vem junto: deixar de
1144
+ -- fora obrigaria a recadastrar tudo no dia em que IBS/CBS valerem.
1145
+ ibs_cbs_situation text,
1146
+ ibs_cbs_classification text,
1147
+ base_calculation_mode text,
1148
+ benefit_code text,
1149
+ cest text,
1150
+ poverty_fund_rate numeric(9,4),
1151
+ is_active boolean DEFAULT true NOT NULL,
1152
+ metadata jsonb DEFAULT '{}'::jsonb NOT NULL,
1153
+ created_at timestamp with time zone DEFAULT now() NOT NULL,
1154
+ updated_at timestamp with time zone DEFAULT now() NOT NULL
1155
+ );
1156
+
1157
+ COMMENT ON TABLE public.plg_fiscalbr_tax_groups IS
1158
+ 'O grupo fiscal: CFOP, CST/CSOSN e al\xEDquotas que o produto herda na emiss\xE3o. V1: fiscal_groups. Traz IBS/CBS porque o cadastro do V1 j\xE1 os tem.';
1159
+
1160
+ -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
1161
+ -- As chaves, os \xEDndices e a cerca
1162
+ -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
1163
+
1164
+ DO $$
1165
+ DECLARE t text;
1166
+ BEGIN
1167
+ FOREACH t IN ARRAY ARRAY['plg_fiscalbr_inbox_documents', 'plg_fiscalbr_inbox_items',
1168
+ 'plg_fiscalbr_inbox_payments', 'plg_fiscalbr_inbox_duplicates',
1169
+ 'plg_fiscalbr_tax_groups'] LOOP
1170
+ IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conrelid = ('public.' || t)::regclass AND contype = 'p') THEN
1171
+ EXECUTE format('ALTER TABLE ONLY public.%I ADD CONSTRAINT %I PRIMARY KEY (id)', t, t || '_pkey');
1172
+ END IF;
1173
+ IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = t || '_tenant_id_id_key') THEN
1174
+ EXECUTE format('ALTER TABLE ONLY public.%I ADD CONSTRAINT %I UNIQUE (tenant_id, id)', t, t || '_tenant_id_id_key');
1175
+ END IF;
1176
+ IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = t || '_tenant_fkey') THEN
1177
+ EXECUTE format('ALTER TABLE ONLY public.%I ADD CONSTRAINT %I FOREIGN KEY (tenant_id) REFERENCES public.tenants(id) ON DELETE CASCADE', t, t || '_tenant_fkey');
1178
+ END IF;
1179
+ END LOOP;
1180
+ END $$;
1181
+
1182
+ DO $$ BEGIN
1183
+ IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_fiscalbr_inbox_documents_unit_fkey') THEN
1184
+ ALTER TABLE ONLY public.plg_fiscalbr_inbox_documents ADD CONSTRAINT plg_fiscalbr_inbox_documents_unit_fkey
1185
+ FOREIGN KEY (tenant_id, unit_id) REFERENCES app.units(tenant_id, id) ON DELETE SET NULL;
1186
+ END IF;
1187
+ -- O arquivo pode ser apagado sem levar a nota junto: a nota fiscal existe
1188
+ -- mesmo sem o XML \xE0 m\xE3o, e \xE9 ela que a SEFAZ conhece.
1189
+ IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_fiscalbr_inbox_documents_document_fkey') THEN
1190
+ ALTER TABLE ONLY public.plg_fiscalbr_inbox_documents ADD CONSTRAINT plg_fiscalbr_inbox_documents_document_fkey
1191
+ FOREIGN KEY (document_id) REFERENCES public.documents(id) ON DELETE SET NULL;
1192
+ END IF;
1193
+ IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_fiscalbr_inbox_documents_supplier_fkey') THEN
1194
+ ALTER TABLE ONLY public.plg_fiscalbr_inbox_documents ADD CONSTRAINT plg_fiscalbr_inbox_documents_supplier_fkey
1195
+ FOREIGN KEY (supplier_party_id) REFERENCES public.people(id) ON DELETE SET NULL;
1196
+ END IF;
1197
+ IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_fiscalbr_inbox_documents_operation_fkey') THEN
1198
+ ALTER TABLE ONLY public.plg_fiscalbr_inbox_documents ADD CONSTRAINT plg_fiscalbr_inbox_documents_operation_fkey
1199
+ FOREIGN KEY (inventory_operation_id) REFERENCES public.plg_inventory_operations(id) ON DELETE SET NULL;
1200
+ END IF;
1201
+
1202
+ -- Item, pagamento e duplicata n\xE3o existem fora da nota: CASCADE.
1203
+ IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_fiscalbr_inbox_items_document_fkey') THEN
1204
+ ALTER TABLE ONLY public.plg_fiscalbr_inbox_items ADD CONSTRAINT plg_fiscalbr_inbox_items_document_fkey
1205
+ FOREIGN KEY (tenant_id, inbox_document_id) REFERENCES public.plg_fiscalbr_inbox_documents(tenant_id, id) ON DELETE CASCADE;
1206
+ END IF;
1207
+ IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_fiscalbr_inbox_items_product_fkey') THEN
1208
+ ALTER TABLE ONLY public.plg_fiscalbr_inbox_items ADD CONSTRAINT plg_fiscalbr_inbox_items_product_fkey
1209
+ FOREIGN KEY (product_id) REFERENCES public.products(id) ON DELETE SET NULL;
1210
+ END IF;
1211
+ IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_fiscalbr_inbox_payments_document_fkey') THEN
1212
+ ALTER TABLE ONLY public.plg_fiscalbr_inbox_payments ADD CONSTRAINT plg_fiscalbr_inbox_payments_document_fkey
1213
+ FOREIGN KEY (tenant_id, inbox_document_id) REFERENCES public.plg_fiscalbr_inbox_documents(tenant_id, id) ON DELETE CASCADE;
1214
+ END IF;
1215
+ IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_fiscalbr_inbox_duplicates_document_fkey') THEN
1216
+ ALTER TABLE ONLY public.plg_fiscalbr_inbox_duplicates ADD CONSTRAINT plg_fiscalbr_inbox_duplicates_document_fkey
1217
+ FOREIGN KEY (tenant_id, inbox_document_id) REFERENCES public.plg_fiscalbr_inbox_documents(tenant_id, id) ON DELETE CASCADE;
1218
+ END IF;
1219
+ IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'plg_fiscalbr_inbox_duplicates_installment_fkey') THEN
1220
+ ALTER TABLE ONLY public.plg_fiscalbr_inbox_duplicates ADD CONSTRAINT plg_fiscalbr_inbox_duplicates_installment_fkey
1221
+ FOREIGN KEY (installment_id) REFERENCES public.plg_financial_invoice_installments(id) ON DELETE SET NULL;
1222
+ END IF;
1223
+ END $$;
1224
+
1225
+ -- A chave de acesso \xE9 \xFAnica por casa: a mesma nota chegando duas vezes da SEFAZ
1226
+ -- \xE9 a mesma nota, e \xE9 isso que impede a importa\xE7\xE3o em dobro.
1227
+ CREATE UNIQUE INDEX IF NOT EXISTS plg_fiscalbr_inbox_documents_access_key_uidx
1228
+ ON public.plg_fiscalbr_inbox_documents USING btree (tenant_id, access_key)
1229
+ WHERE access_key IS NOT NULL;
1230
+ CREATE INDEX IF NOT EXISTS plg_fiscalbr_inbox_documents_pending_idx
1231
+ ON public.plg_fiscalbr_inbox_documents USING btree (tenant_id, unit_id, issue_date DESC)
1232
+ WHERE inventory_operation_id IS NULL;
1233
+ CREATE INDEX IF NOT EXISTS plg_fiscalbr_inbox_items_document_idx
1234
+ ON public.plg_fiscalbr_inbox_items USING btree (tenant_id, inbox_document_id);
1235
+ CREATE INDEX IF NOT EXISTS plg_fiscalbr_inbox_items_product_idx
1236
+ ON public.plg_fiscalbr_inbox_items USING btree (tenant_id, product_id) WHERE product_id IS NOT NULL;
1237
+ CREATE INDEX IF NOT EXISTS plg_fiscalbr_inbox_payments_document_idx
1238
+ ON public.plg_fiscalbr_inbox_payments USING btree (tenant_id, inbox_document_id);
1239
+ CREATE INDEX IF NOT EXISTS plg_fiscalbr_inbox_duplicates_document_idx
1240
+ ON public.plg_fiscalbr_inbox_duplicates USING btree (tenant_id, inbox_document_id);
1241
+ CREATE UNIQUE INDEX IF NOT EXISTS plg_fiscalbr_tax_groups_name_uidx
1242
+ ON public.plg_fiscalbr_tax_groups USING btree (tenant_id, lower(name));
1243
+
1244
+ DO $$
1245
+ DECLARE t text;
1246
+ BEGIN
1247
+ FOREACH t IN ARRAY ARRAY['plg_fiscalbr_inbox_documents', 'plg_fiscalbr_inbox_items',
1248
+ 'plg_fiscalbr_inbox_payments', 'plg_fiscalbr_inbox_duplicates',
1249
+ 'plg_fiscalbr_tax_groups'] LOOP
1250
+ EXECUTE format('DROP TRIGGER IF EXISTS %I ON public.%I', t || '_updated_at', t);
1251
+ EXECUTE format('CREATE TRIGGER %I BEFORE UPDATE ON public.%I FOR EACH ROW EXECUTE FUNCTION public.handle_updated_at()', t || '_updated_at', t);
1252
+ END LOOP;
1253
+ END $$;
1254
+
1255
+ -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
1256
+ -- Quem enxerga
1257
+ -- \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
1258
+ --
1259
+ -- Nota fiscal \xE9 do FINANCEIRO, e a permiss\xE3o \xE9 a que ele j\xE1 usa. A caixa de
1260
+ -- entrada n\xE3o tem unidade nos filhos \u2014 eles herdam a da nota \u2014, ent\xE3o o escopo
1261
+ -- de unidade vale s\xF3 no documento; o resto \xE9 do tenant, e \xE9 a CASCADE da FK que
1262
+ -- garante que ningu\xE9m veja filho de nota alheia.
1263
+ -- RLS, uma a uma e por extenso. O la\xE7o adiante j\xE1 liga tudo isto \u2014 mas ele liga
1264
+ -- por \`EXECUTE format(...)\`, e o port\xE3o que revisa plugin l\xEA o ARQUIVO, n\xE3o o
1265
+ -- banco: para ele, tabela com tenant_id e sem um ENABLE literal \xE9 tabela
1266
+ -- aberta. Uma garantia que o revisor n\xE3o consegue ler \xE9 uma garantia que
1267
+ -- ningu\xE9m confere.
1268
+ ALTER TABLE public.plg_fiscalbr_inbox_documents ENABLE ROW LEVEL SECURITY;
1269
+ ALTER TABLE public.plg_fiscalbr_inbox_items ENABLE ROW LEVEL SECURITY;
1270
+ ALTER TABLE public.plg_fiscalbr_tax_groups ENABLE ROW LEVEL SECURITY;
1271
+ ALTER TABLE public.plg_fiscalbr_inbox_payments ENABLE ROW LEVEL SECURITY;
1272
+ ALTER TABLE public.plg_fiscalbr_inbox_duplicates ENABLE ROW LEVEL SECURITY;
1273
+
1274
+ DO $$
1275
+ DECLARE
1276
+ t text;
1277
+ doc boolean;
1278
+ BEGIN
1279
+ FOREACH t IN ARRAY ARRAY['plg_fiscalbr_inbox_documents', 'plg_fiscalbr_inbox_items',
1280
+ 'plg_fiscalbr_inbox_payments', 'plg_fiscalbr_inbox_duplicates',
1281
+ 'plg_fiscalbr_tax_groups'] LOOP
1282
+ doc := t = 'plg_fiscalbr_inbox_documents';
1283
+ EXECUTE format('ALTER TABLE public.%I FORCE ROW LEVEL SECURITY', t);
1284
+ EXECUTE format('ALTER TABLE public.%I ENABLE ROW LEVEL SECURITY', t);
1285
+ EXECUTE format('GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE public.%I TO authenticated', t);
1286
+ EXECUTE format('GRANT ALL ON TABLE public.%I TO service_role', t);
1287
+
1288
+ EXECUTE format('DROP POLICY IF EXISTS %I ON public.%I', t || '_authz_select', t);
1289
+ EXECUTE format($f$CREATE POLICY %I ON public.%I FOR SELECT TO authenticated USING (
1290
+ tenant_id = (SELECT app.current_tenant_id())
1291
+ AND (%s)
1292
+ AND (SELECT app.has_permission('financial.read', %s)))$f$,
1293
+ t || '_authz_select', t,
1294
+ CASE WHEN doc THEN format('unit_id IS NULL OR (SELECT app.has_unit(%I.unit_id))', t) ELSE 'true' END,
1295
+ CASE WHEN doc THEN format('%I.unit_id', t) ELSE 'NULL::uuid' END);
1296
+
1297
+ EXECUTE format('DROP POLICY IF EXISTS %I ON public.%I', t || '_authz_write', t);
1298
+ EXECUTE format($f$CREATE POLICY %I ON public.%I FOR ALL TO authenticated USING (
1299
+ tenant_id = (SELECT app.current_tenant_id())
1300
+ AND (SELECT app.has_permission('financial.edit', %s)))
1301
+ WITH CHECK (
1302
+ tenant_id = (SELECT app.current_tenant_id())
1303
+ AND (SELECT app.has_permission('financial.edit', %s)))$f$,
1304
+ t || '_authz_write', t,
1305
+ CASE WHEN doc THEN format('%I.unit_id', t) ELSE 'NULL::uuid' END,
1306
+ CASE WHEN doc THEN format('%I.unit_id', t) ELSE 'NULL::uuid' END);
1307
+ END LOOP;
1308
+ END $$;
1309
+
1310
+ INSERT INTO public.scoped_resources (resource_table, unit_column, owner_column, shareable, default_visibility, label)
1311
+ VALUES ('plg_fiscalbr_inbox_documents', 'unit_id', 'owner_id', false, 'unit', 'Notas recebidas')
1312
+ ON CONFLICT (resource_table) DO UPDATE
1313
+ SET unit_column = EXCLUDED.unit_column, default_visibility = EXCLUDED.default_visibility, label = EXCLUDED.label;
1314
+ `;
1315
+ var MIGRATION_003_A_CAIXA_DE_ENTRADA_ATRAVESSA = `-- A caixa de entrada atravessa.
1316
+ --
1317
+ -- A 002 fez as cinco tabelas. Esta escreve o de-para. As cinco usam o writer
1318
+ -- gen\xE9rico \`by_shape\` (spine 123): as colunas do destino foram desenhadas
1319
+ -- olhando a origem, ent\xE3o o que falta \xE9 dizer qual nome vira qual \u2014 n\xE3o uma
1320
+ -- fun\xE7\xE3o de upsert por tabela.
1321
+ --
1322
+ -- \u2500\u2500 O arquivo n\xE3o vem por aqui \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
1323
+ --
1324
+ -- \`xml_content\` guarda o XML inteiro e \`pdf_storage_path\` aponta para o DANFE.
1325
+ -- Os dois saem do de-para com \`-\`: arquivo atravessa pelo est\xE1gio de assets,
1326
+ -- que \xE9 quem alcan\xE7a object storage, e vira linha de \`public.documents\`. O
1327
+ -- caminho de origem fica em metadata para o est\xE1gio achar.
1328
+ --
1329
+ -- \u2500\u2500 O fornecedor fica para a costura \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
1330
+ --
1331
+ -- \`supplier_party_id\` n\xE3o \xE9 preenchido aqui. A origem guarda CNPJ e nome, n\xE3o
1332
+ -- um id de contato, e casar CNPJ com \`public.people\` \xE9 uma decis\xE3o de
1333
+ -- identidade \u2014 a mesma que j\xE1 p\xF4s 438 clientes em quarentena. Fica nulo, com o
1334
+ -- CNPJ na coluna ao lado, e uma passada de costura resolve quando algu\xE9m
1335
+ -- decidir a regra.
1336
+ --
1337
+ -- Idempotente.
1338
+
1339
+ SET LOCAL migration.allowlist_unlock = 'on';
1340
+
1341
+ SELECT migration._allow(
1342
+ 'fiscal_groups', 'public.plg_fiscalbr_tax_groups', 'fiscal_br', 'by_shape',
1343
+ jsonb_build_object('target', 'public.plg_fiscalbr_tax_groups'),
1344
+ NULL::text[],
1345
+ jsonb_build_object(
1346
+ 'uuid', 'id',
1347
+ 'name', 'name',
1348
+ 'cfop', 'cfop',
1349
+ 'csosn', 'csosn',
1350
+ 'cst', 'cst',
1351
+ 'icms_origin', 'icms_origin',
1352
+ 'icms_rate', 'icms_rate',
1353
+ 'icms_modalidade_bc', 'icms_bc_mode',
1354
+ 'pis_situation', 'pis_situation',
1355
+ 'pis_rate', 'pis_rate',
1356
+ 'cofins_situation', 'cofins_situation',
1357
+ 'cofins_rate', 'cofins_rate',
1358
+ 'ibs_cbs_situation', 'ibs_cbs_situation',
1359
+ 'ibs_cbs_classification', 'ibs_cbs_classification',
1360
+ 'base_calculation_mode', 'base_calculation_mode',
1361
+ 'cbenef', 'benefit_code',
1362
+ 'cest', 'cest',
1363
+ 'poverty_fund_rate', 'poverty_fund_rate',
1364
+ 'active', 'is_active',
1365
+ 'created_at', 'created_at',
1366
+ 'updated_at', 'updated_at',
1367
+ 'tenant_id', '-',
1368
+ 'id', 'jsonb:fiscalbr.v1_ref'),
1369
+ 'O grupo fiscal: CFOP, CST/CSOSN e al\xEDquotas que o produto herda na emiss\xE3o. '
1370
+ 'IBS/CBS v\xEAm junto porque o cadastro do V1 j\xE1 os tem \u2014 deixar de fora '
1371
+ 'obrigaria a recadastrar tudo no dia em que a reforma valer.'
1372
+ );
1373
+
1374
+ SELECT migration._allow(
1375
+ 'dfe_inbox', 'public.plg_fiscalbr_inbox_documents', 'fiscal_br', 'by_shape',
1376
+ jsonb_build_object('target', 'public.plg_fiscalbr_inbox_documents'),
1377
+ NULL::text[],
1378
+ jsonb_build_object(
1379
+ 'uuid', 'id',
1380
+ 'company_id', 'unit_id@companies',
1381
+ 'access_key', 'access_key',
1382
+ 'nfe_number', 'nfe_number',
1383
+ 'nfe_series', 'nfe_series',
1384
+ 'nfe_model', 'nfe_model',
1385
+ 'issue_date', 'issue_date',
1386
+ 'received_at', 'received_at',
1387
+ 'status', 'status',
1388
+ 'manifestation_status', 'manifestation_status',
1389
+ 'manifested_at', 'manifested_at',
1390
+ 'manifestation_attempts', 'manifestation_attempts',
1391
+ 'manifestation_response', 'manifestation_response',
1392
+ 'supplier_cnpj', 'supplier_cnpj',
1393
+ 'supplier_name', 'supplier_name',
1394
+ 'supplier_ie', 'supplier_ie',
1395
+ 'total_value', 'total_value',
1396
+ 'total_products', 'total_products',
1397
+ 'total_discount', 'total_discount',
1398
+ 'total_freight', 'total_freight',
1399
+ 'total_insurance', 'total_insurance',
1400
+ 'total_other', 'total_other',
1401
+ 'total_icms_base', 'total_icms_base',
1402
+ 'total_icms_value', 'total_icms_value',
1403
+ 'total_icms_st_base', 'total_icms_st_base',
1404
+ 'total_icms_st_value', 'total_icms_st_value',
1405
+ 'total_pis_value', 'total_pis_value',
1406
+ 'total_cofins_value', 'total_cofins_value',
1407
+ 'total_ipi_value', 'total_ipi_value',
1408
+ 'nfe_protocol', 'nfe_protocol') ||
1409
+ -- \`jsonb_build_object\` aceita no m\xE1ximo 100 argumentos, e este de-para tem
1410
+ -- 59 pares. Dois objetos concatenados, e n\xE3o uma tabela a menos.
1411
+ jsonb_build_object(
1412
+ 'nfe_authorized_at', 'nfe_authorized_at',
1413
+ 'carrier_name', 'carrier_name',
1414
+ 'carrier_cnpj', 'carrier_cnpj',
1415
+ 'freight_mode_code', 'freight_mode_code',
1416
+ 'additional_info', 'additional_info',
1417
+ 'reviewed_at', 'reviewed_at',
1418
+ 'created_at', 'created_at',
1419
+ 'updated_at', 'updated_at',
1420
+ 'tenant_id', '-',
1421
+ 'reviewed_by', '-',
1422
+ 'xml_content', '-',
1423
+ 'pdf_storage_path', 'jsonb:fiscalbr.v1_pdf_path',
1424
+ 'pdf_fetched_at', 'jsonb:fiscalbr.v1_pdf_fetched_at',
1425
+ 'danfe_import_id', 'jsonb:fiscalbr.v1_danfe_import_ref',
1426
+ 'plugnotas_payload', 'jsonb:fiscalbr.v1_plugnotas_payload',
1427
+ 'plugnotas_received_at', 'jsonb:fiscalbr.v1_plugnotas_received_at',
1428
+ 'nfe_cnf', 'jsonb:fiscalbr.nfe.cnf',
1429
+ 'nfe_natureza_operacao', 'jsonb:fiscalbr.nfe.natureza_operacao',
1430
+ 'nfe_finalidade', 'jsonb:fiscalbr.nfe.finalidade',
1431
+ 'nfe_tipo_operacao', 'jsonb:fiscalbr.nfe.tipo_operacao',
1432
+ 'nfe_destination', 'jsonb:fiscalbr.nfe.destination',
1433
+ 'supplier_address', 'jsonb:fiscalbr.supplier.street',
1434
+ 'supplier_number', 'jsonb:fiscalbr.supplier.number',
1435
+ 'supplier_complement', 'jsonb:fiscalbr.supplier.complement',
1436
+ 'supplier_neighborhood', 'jsonb:fiscalbr.supplier.neighborhood',
1437
+ 'supplier_city', 'jsonb:fiscalbr.supplier.city',
1438
+ 'supplier_state', 'jsonb:fiscalbr.supplier.state',
1439
+ 'supplier_postal_code', 'jsonb:fiscalbr.supplier.postal_code',
1440
+ 'supplier_phone', 'jsonb:fiscalbr.supplier.phone',
1441
+ 'supplier_email', 'jsonb:fiscalbr.supplier.email',
1442
+ 'id', 'jsonb:fiscalbr.v1_ref'),
1443
+ 'A NF-e de fornecedor recebida da SEFAZ. \`xml_content\` sai com \`-\`: arquivo '
1444
+ 'atravessa pelo est\xE1gio de assets e vira public.documents, e o caminho do '
1445
+ 'DANFE fica em metadata para o est\xE1gio achar. O endere\xE7o do fornecedor vai '
1446
+ 'para metadata porque o fornecedor \xE9 \`public.people\`, e duplic\xE1-lo em coluna '
1447
+ 'daria duas respostas para "onde ele fica".'
1448
+ );
1449
+
1450
+ SELECT migration._allow(
1451
+ 'dfe_inbox_items', 'public.plg_fiscalbr_inbox_items', 'fiscal_br', 'by_shape',
1452
+ jsonb_build_object('target', 'public.plg_fiscalbr_inbox_items'),
1453
+ NULL::text[],
1454
+ jsonb_build_object(
1455
+ 'uuid', 'id',
1456
+ 'dfe_inbox_id', 'inbox_document_id@dfe_inbox',
1457
+ 'item_number', 'item_number',
1458
+ 'product_code_supplier', 'supplier_product_code',
1459
+ 'ean_barcode', 'ean_barcode',
1460
+ 'ean_trib', 'ean_taxable',
1461
+ 'description', 'description',
1462
+ 'ncm', 'ncm',
1463
+ 'cest', 'cest',
1464
+ 'cfop', 'cfop',
1465
+ 'unit_commercial', 'unit_commercial',
1466
+ 'unit_taxable', 'unit_taxable',
1467
+ 'quantity_commercial', 'quantity_commercial',
1468
+ 'quantity_taxable', 'quantity_taxable',
1469
+ 'unit_price_commercial', 'unit_price_commercial',
1470
+ 'unit_price_taxable', 'unit_price_taxable',
1471
+ 'total_price', 'total_price',
1472
+ 'discount', 'discount',
1473
+ 'freight', 'freight',
1474
+ 'insurance', 'insurance',
1475
+ 'other_expenses', 'other_expenses',
1476
+ 'icms_cst', 'icms_cst',
1477
+ 'icms_csosn', 'icms_csosn',
1478
+ 'icms_origin', 'icms_origin',
1479
+ 'icms_base', 'icms_base',
1480
+ 'icms_rate', 'icms_rate',
1481
+ 'icms_value', 'icms_value',
1482
+ 'icms_st_base', 'icms_st_base',
1483
+ 'icms_st_value', 'icms_st_value',
1484
+ 'pis_cst', 'pis_cst',
1485
+ 'pis_base', 'pis_base',
1486
+ 'pis_rate', 'pis_rate',
1487
+ 'pis_value', 'pis_value',
1488
+ 'cofins_cst', 'cofins_cst',
1489
+ 'cofins_base', 'cofins_base',
1490
+ 'cofins_rate', 'cofins_rate',
1491
+ 'cofins_value', 'cofins_value',
1492
+ 'ipi_cst', 'ipi_cst',
1493
+ 'ipi_rate', 'ipi_rate',
1494
+ 'ipi_value', 'ipi_value',
1495
+ 'linked_product_id', 'product_id@products',
1496
+ 'reconciled', 'reconciled',
1497
+ 'raw_xml_item', 'raw_xml_item',
1498
+ 'created_at', 'created_at',
1499
+ 'updated_at', 'updated_at',
1500
+ 'tenant_id', '-',
1501
+ 'id', 'jsonb:fiscalbr.v1_ref'),
1502
+ 'O item da nota, com o tributo em COLUNA \u2014 a apura\xE7\xE3o soma coluna, n\xE3o varre '
1503
+ 'jsonb. \`raw_xml_item\` \xE9 a exce\xE7\xE3o: j\xE1 \xE9 jsonb na origem e serve para '
1504
+ 'confer\xEAncia, n\xE3o para conta.'
1505
+ );
1506
+
1507
+ SELECT migration._allow(
1508
+ 'dfe_inbox_payments', 'public.plg_fiscalbr_inbox_payments', 'fiscal_br', 'by_shape',
1509
+ jsonb_build_object('target', 'public.plg_fiscalbr_inbox_payments'),
1510
+ NULL::text[],
1511
+ jsonb_build_object(
1512
+ 'uuid', 'id',
1513
+ 'dfe_inbox_id', 'inbox_document_id@dfe_inbox',
1514
+ 'payment_index', 'payment_index',
1515
+ 'indicador_pagamento', 'payment_indicator',
1516
+ 'tipo_pagamento_code', 'payment_type_code',
1517
+ 'tipo_pagamento_label', 'payment_type_label',
1518
+ 'value', 'value',
1519
+ 'troco', 'change_given',
1520
+ 'card_flag', 'card_brand',
1521
+ 'card_acquirer_cnpj', 'card_acquirer_cnpj',
1522
+ 'card_auth_code', 'card_auth_code',
1523
+ 'created_at', 'created_at',
1524
+ 'updated_at', 'updated_at',
1525
+ 'tenant_id', '-',
1526
+ 'id', 'jsonb:fiscalbr.v1_ref'),
1527
+ 'A forma de pagamento declarada na nota recebida.'
1528
+ );
1529
+
1530
+ SELECT migration._allow(
1531
+ 'dfe_inbox_duplicatas', 'public.plg_fiscalbr_inbox_duplicates', 'fiscal_br', 'by_shape',
1532
+ jsonb_build_object('target', 'public.plg_fiscalbr_inbox_duplicates'),
1533
+ NULL::text[],
1534
+ jsonb_build_object(
1535
+ 'uuid', 'id',
1536
+ 'dfe_inbox_id', 'inbox_document_id@dfe_inbox',
1537
+ 'duplicata_index', 'duplicate_index',
1538
+ 'numero', 'number',
1539
+ 'vencimento', 'due_date',
1540
+ 'valor', 'value',
1541
+ 'created_at', 'created_at',
1542
+ 'updated_at', 'updated_at',
1543
+ 'tenant_id', '-',
1544
+ 'id', 'jsonb:fiscalbr.v1_ref'),
1545
+ 'O vencimento declarado na nota. Vira parcela do contas a pagar quando algu\xE9m '
1546
+ 'lan\xE7a a nota \u2014 \`installment_id\` fica nulo at\xE9 l\xE1, porque a parcela \xE9 '
1547
+ 'decis\xE3o de quem lan\xE7a, n\xE3o da SEFAZ.'
1548
+ );
1549
+
1550
+ DELETE FROM migration.excluded_tables
1551
+ WHERE source_table IN ('dfe_inbox', 'dfe_inbox_items', 'dfe_inbox_payments',
1552
+ 'dfe_inbox_duplicatas', 'fiscal_groups');
1553
+
1554
+ RESET migration.allowlist_unlock;
1555
+ `;
1556
+ var MIGRATION_004_O_GRUPO_FISCAL_DO_V1_REPETE_NOME = `-- O grupo fiscal do V1 repete nome.
1557
+ --
1558
+ -- A 002 criou \xEDndice \xDANICO em \`(tenant_id, lower(name))\`. O V1 tem, no tenant
1559
+ -- 8, "Bebidas Alco\xF3licas", "Bebidas N\xE3o Alco\xF3licas" e "Vinhos e Espumantes"
1560
+ -- DUAS vezes cada \u2014 grupos fiscais diferentes com o mesmo r\xF3tulo, e o V1
1561
+ -- permite. Tr\xEAs das onze linhas foram para a quarentena por uma regra que eu
1562
+ -- inventei, n\xE3o que a origem tenha.
1563
+ --
1564
+ -- O \xEDndice vira comum: serve para buscar, n\xE3o para proibir. Quem quiser proibir
1565
+ -- decide isso na tela, com o dado j\xE1 dentro \u2014 e sabendo quais tr\xEAs s\xE3o.
1566
+ --
1567
+ -- Esta corre\xE7\xE3o nasceu dentro de \`financial/083\` e mudou de arquivo: o
1568
+ -- financeiro roda ANTES do fiscal_br na corrente, e um arquivo do financeiro
1569
+ -- que mexe numa tabela do fiscal_br falha do zero com
1570
+ -- \`relation "public.plg_fiscalbr_tax_groups" does not exist\`. Cada plugin mexe
1571
+ -- na tabela que \xE9 dele.
1572
+ --
1573
+ -- Idempotente.
1574
+
1575
+ DROP INDEX IF EXISTS public.plg_fiscalbr_tax_groups_name_uidx;
1576
+ CREATE INDEX IF NOT EXISTS plg_fiscalbr_tax_groups_name_idx
1577
+ ON public.plg_fiscalbr_tax_groups USING btree (tenant_id, lower(name));
1578
+ `;
953
1579
  var MIGRATIONS = [
954
1580
  { id: "000_baseline", sql: MIGRATION_000_BASELINE },
955
- { id: "001_preserve_terminal_results_and_recover_leases", sql: MIGRATION_001_PRESERVE_TERMINAL_RESULTS_AND_RECOVER_LEASES }
1581
+ { id: "001_preserve_terminal_results_and_recover_leases", sql: MIGRATION_001_PRESERVE_TERMINAL_RESULTS_AND_RECOVER_LEASES },
1582
+ { id: "002_a_nota_que_chega_tem_onde_esperar", sql: MIGRATION_002_A_NOTA_QUE_CHEGA_TEM_ONDE_ESPERAR },
1583
+ { id: "003_a_caixa_de_entrada_atravessa", sql: MIGRATION_003_A_CAIXA_DE_ENTRADA_ATRAVESSA },
1584
+ { id: "004_o_grupo_fiscal_do_v1_repete_nome", sql: MIGRATION_004_O_GRUPO_FISCAL_DO_V1_REPETE_NOME }
956
1585
  ];
957
1586
 
958
1587
  // src/lib/financial-provider.ts