From e81e28b5f191c2a03aefc97933b9f7d4b6dfab5d Mon Sep 17 00:00:00 2001
From: Hanna Tiharu <129420244+HannaTiharu@users.noreply.github.com>
Date: Thu, 6 Feb 2025 08:30:42 -0300
Subject: [PATCH 001/175] feat(cte-event): Adiciona arquivos XSDs para cte
---
pynfe/data/XSDs/CT-e/GTVe_v4.00.xsd | 10 +
.../XSDs/CT-e/consSitCTeTiposBasico_v4.00.xsd | 123 +
pynfe/data/XSDs/CT-e/consSitCTe_v4.00.xsd | 10 +
.../data/XSDs/CT-e/consStatServCTe_v4.00.xsd | 10 +
.../CT-e/consStatServTiposBasico_v4.00.xsd | 115 +
pynfe/data/XSDs/CT-e/cteModalAereo_v4.00.xsd | 240 +
.../XSDs/CT-e/cteModalAquaviario_v4.00.xsd | 207 +
.../XSDs/CT-e/cteModalDutoviario_v4.00.xsd | 30 +
.../XSDs/CT-e/cteModalFerroviario_v4.00.xsd | 231 +
.../XSDs/CT-e/cteModalRodoviarioOS_v4.00.xsd | 193 +
.../XSDs/CT-e/cteModalRodoviario_v4.00.xsd | 102 +
pynfe/data/XSDs/CT-e/cteMultiModal_v4.00.xsd | 100 +
pynfe/data/XSDs/CT-e/cteOS_v4.00.xsd | 10 +
pynfe/data/XSDs/CT-e/cteSimp_v4.00.xsd | 10 +
pynfe/data/XSDs/CT-e/cteTiposBasico_v4.00.xsd | 7966 +++++++++++++++++
pynfe/data/XSDs/CT-e/cte_v4.00.xsd | 10 +
pynfe/data/XSDs/CT-e/evCCeCTe_v4.00.xsd | 98 +
pynfe/data/XSDs/CT-e/evCECTe_v4.00.xsd | 108 +
pynfe/data/XSDs/CT-e/evCancCECTe_v4.00.xsd | 36 +
pynfe/data/XSDs/CT-e/evCancCTe_v4.00.xsd | 36 +
pynfe/data/XSDs/CT-e/evCancIECTe_v4.00.xsd | 36 +
.../XSDs/CT-e/evCancPrestDesacordo_v4.00.xsd | 32 +
pynfe/data/XSDs/CT-e/evEPECCTe_v4.00.xsd | 161 +
pynfe/data/XSDs/CT-e/evGTV_v4.00.xsd | 255 +
pynfe/data/XSDs/CT-e/evIECTe_v4.00.xsd | 126 +
.../data/XSDs/CT-e/evPrestDesacordo_v4.00.xsd | 49 +
.../data/XSDs/CT-e/evRegMultimodal_v4.00.xsd | 51 +
.../XSDs/CT-e/eventoCTeTiposBasico_v4.00.xsd | 331 +
pynfe/data/XSDs/CT-e/eventoCTe_v4.00.xsd | 10 +
pynfe/data/XSDs/CT-e/procCTeOS_v4.00.xsd | 37 +
pynfe/data/XSDs/CT-e/procCTeSimp_v4.00.xsd | 37 +
pynfe/data/XSDs/CT-e/procCTe_v4.00.xsd | 37 +
pynfe/data/XSDs/CT-e/procEventoCTe_v4.00.xsd | 15 +
pynfe/data/XSDs/CT-e/procGTVe_v4.00.xsd | 37 +
pynfe/data/XSDs/CT-e/retCTeOS_v4.00.xsd | 10 +
pynfe/data/XSDs/CT-e/retCTeSimp_v4.00.xsd | 10 +
pynfe/data/XSDs/CT-e/retCTe_v4.00.xsd | 10 +
pynfe/data/XSDs/CT-e/retConsSitCTe_v4.00.xsd | 10 +
.../XSDs/CT-e/retConsStatServCTe_v4.00.xsd | 10 +
pynfe/data/XSDs/CT-e/retEventoCTe_v4.00.xsd | 10 +
pynfe/data/XSDs/CT-e/retGTVe_v4.00.xsd | 10 +
pynfe/data/XSDs/CT-e/tiposGeralCTe_v4.00.xsd | 647 ++
.../XSDs/CT-e/xmldsig-core-schema_v1.01.xsd | 98 +
43 files changed, 11674 insertions(+)
create mode 100644 pynfe/data/XSDs/CT-e/GTVe_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/consSitCTeTiposBasico_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/consSitCTe_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/consStatServCTe_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/consStatServTiposBasico_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/cteModalAereo_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/cteModalAquaviario_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/cteModalDutoviario_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/cteModalFerroviario_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/cteModalRodoviarioOS_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/cteModalRodoviario_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/cteMultiModal_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/cteOS_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/cteSimp_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/cteTiposBasico_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/cte_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/evCCeCTe_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/evCECTe_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/evCancCECTe_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/evCancCTe_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/evCancIECTe_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/evCancPrestDesacordo_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/evEPECCTe_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/evGTV_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/evIECTe_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/evPrestDesacordo_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/evRegMultimodal_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/eventoCTeTiposBasico_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/eventoCTe_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/procCTeOS_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/procCTeSimp_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/procCTe_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/procEventoCTe_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/procGTVe_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/retCTeOS_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/retCTeSimp_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/retCTe_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/retConsSitCTe_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/retConsStatServCTe_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/retEventoCTe_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/retGTVe_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/tiposGeralCTe_v4.00.xsd
create mode 100644 pynfe/data/XSDs/CT-e/xmldsig-core-schema_v1.01.xsd
diff --git a/pynfe/data/XSDs/CT-e/GTVe_v4.00.xsd b/pynfe/data/XSDs/CT-e/GTVe_v4.00.xsd
new file mode 100644
index 00000000..66cd2adb
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/GTVe_v4.00.xsd
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+ Guia de Trasnsporte Eletrônica
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/consSitCTeTiposBasico_v4.00.xsd b/pynfe/data/XSDs/CT-e/consSitCTeTiposBasico_v4.00.xsd
new file mode 100644
index 00000000..27525a23
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/consSitCTeTiposBasico_v4.00.xsd
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+ Tipo Pedido de Consulta da Situação Atual do Conhecimento de Transporte eletrônico
+
+
+
+
+ Identificação do Ambiente:
+1 - Produção
+2 - Homologação
+
+
+
+
+ Serviço Solicitado
+
+
+
+
+ Chaves de acesso da CT-e
+
+
+
+
+
+
+
+
+
+
+
+ Tipo Retorno de Pedido de Consulta da Situação Atual do Conhecimento de Transporte eletrônico
+
+
+
+
+ Identificação do Ambiente:
+1 - Produção
+2 - Homologação
+
+
+
+
+ Versão do Aplicativo que processou o CT-e
+
+
+
+
+ Código do status da mensagem enviada.
+
+
+
+
+ Descrição literal do status do serviço solicitado.
+
+
+
+
+ código da UF de atendimento
+
+
+
+
+
+
+
+ Retornar protCTe da versão correspondente do CT-e autorizado
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Retornar procEventoCTe da versão correspondente do evento CT-e autorizado
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tipo Versão do Consulta situação de CT-e - 4.00
+
+
+
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/consSitCTe_v4.00.xsd b/pynfe/data/XSDs/CT-e/consSitCTe_v4.00.xsd
new file mode 100644
index 00000000..c9825f32
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/consSitCTe_v4.00.xsd
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+ Schema de validação XML dp Pedido de Consulta da Situação Atual do CT-e.
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/consStatServCTe_v4.00.xsd b/pynfe/data/XSDs/CT-e/consStatServCTe_v4.00.xsd
new file mode 100644
index 00000000..bc2ed359
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/consStatServCTe_v4.00.xsd
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+ Schema XML de validação do Pedido de Consulta do Status do Serviço CT-e
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/consStatServTiposBasico_v4.00.xsd b/pynfe/data/XSDs/CT-e/consStatServTiposBasico_v4.00.xsd
new file mode 100644
index 00000000..a79fae2c
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/consStatServTiposBasico_v4.00.xsd
@@ -0,0 +1,115 @@
+
+
+
+
+
+
+ Tipo Pedido de Consulta do Status do Serviço CTe
+
+
+
+
+ Identificação do Ambiente:
+1 - Produção
+2 - Homologação
+
+
+
+
+ Código da UF a ser verificado o status
+ Utilizar a Tabela do IBGE.
+
+
+
+
+ Serviço Solicitado
+
+
+
+
+
+
+
+
+
+
+
+ Tipo Resultado da Consulta do Status do Serviço CTe
+
+
+
+
+ Identificação do Ambiente:
+1 - Produção
+2 - Homologação
+
+
+
+
+ Versão do Aplicativo que processou o CT-e
+
+
+
+
+
+
+
+
+
+ Código do status da mensagem enviada.
+
+
+
+
+ Descrição literal do status do serviço solicitado.
+
+
+
+
+ Código da UF responsável pelo serviço
+
+
+
+
+ AAAA-MM-DDTHH:MM:SS TZD
+
+
+
+
+ Tempo médio de resposta do serviço (em segundos) dos últimos 5 minutos
+
+
+
+
+
+
+
+
+
+ AAAA-MM-DDTHH:MM:SSDeve ser preenchida com data e hora previstas para o retorno dos serviços prestados.
+
+
+
+
+ Campo observação utilizado para incluir informações ao contribuinte
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tipo Versão do Consulta do Status do Serviço CTe
+
+
+
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/cteModalAereo_v4.00.xsd b/pynfe/data/XSDs/CT-e/cteModalAereo_v4.00.xsd
new file mode 100644
index 00000000..fbb25460
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/cteModalAereo_v4.00.xsd
@@ -0,0 +1,240 @@
+
+
+
+
+
+
+ Informações do modal Aéreo
+
+
+
+
+
+ Número da Minuta
+ Documento que precede o CT-e, assinado pelo expedidor, espécie de pedido de serviço
+
+
+
+
+
+
+
+
+
+
+ Número Operacional do Conhecimento Aéreo
+ Representa o número de controle comumente utilizado pelo conhecimento aéreo composto por uma sequência numérica de onze dígitos. Os três primeiros dígitos representam um código que os operadores de transporte aéreo associados à IATA possuem. Em seguida um número de série de sete dígitos determinados pelo operador de transporte aéreo. Para finalizar, um dígito verificador, que é um sistema de módulo sete imponderado o qual divide o número de série do conhecimento aéreo por sete e usa o resto como dígito de verificação.
+
+
+
+
+
+
+
+
+
+
+ Data prevista da entrega
+ Formato AAAA-MM-DD
+
+
+
+
+ Natureza da carga
+
+
+
+
+
+ Dimensão
+ Formato:1234X1234X1234 (cm). Esse campo deve sempre que possível ser preenchido. Entretanto, quando for impossível o preenchimento das dimensões, fica obrigatório o preenchimento da cubagem em metro cúbico do leiaute do CT-e da estrutura genérica (infQ).
+
+
+
+
+
+
+
+
+
+
+
+ Informações de manuseio
+ 01 - certificado do expedidor para embarque de animal vivo;
+
+02 - artigo perigoso conforme Declaração do Expedidor anexa;
+
+03 - somente em aeronave cargueira;
+
+04 - artigo perigoso - declaração do expedidor não requerida;
+
+05 - artigo perigoso em quantidade isenta;
+
+06 - gelo seco para refrigeração (especificar no campo observações a quantidade);
+
+07 - não restrito (especificar a Disposição Especial no campo observações);
+
+08 - artigo perigoso em carga consolidada (especificar a quantidade no campo observações)
+;
+09 - autorização da autoridade governamental anexa (especificar no campo observações);
+
+10 – baterias de íons de lítio em conformidade com a Seção II da PI965 – CAO
+;
+11 - baterias de íons de lítio em conformidade com a Seção II da PI966
+;
+12 - baterias de íons de lítio em conformidade com a Seção II da PI967
+;
+13 – baterias de metal lítio em conformidade com a Seção II da PI968 — CAO;
+
+14 - baterias de metal lítio em conformidade com a Seção II da PI969;
+
+15 - baterias de metal lítio em conformidade com a Seção II da PI970
+;
+99 - outro (especificar no campo observações)
+.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Informações de tarifa
+
+
+
+
+
+ Classe
+ Preencher com:
+ M - Tarifa Mínima;
+ G - Tarifa Geral;
+ E - Tarifa Específica
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Código da Tarifa
+ Deverão ser incluídos os códigos de três dígitos, correspondentes à tarifa.
+
+
+
+
+
+
+
+
+
+
+ Valor da Tarifa
+ Valor da tarifa por kg quando for o caso.
+
+
+
+
+
+
+
+ Preenchido quando for transporte de produtos classificados pela ONU como perigosos.
+ O preenchimento desses campos não desobriga a empresa aérea de emitir os demais documentos que constam na legislação vigente.
+
+
+
+
+
+ Número ONU/UN
+ Ver a legislação de transporte de produtos perigosos aplicadas ao modal
+
+
+
+
+
+
+
+
+
+
+ Quantidade total de volumes contendo artigos perigosos
+ Preencher com o número de volumes (unidades) de artigos perigosos, ou seja, cada embalagem devidamente marcada e etiquetada (por ex.: número de caixas, de tambores, de bombonas, dentre outros). Não deve ser preenchido com o número de ULD, pallets ou containers.
+
+
+
+
+
+
+
+
+
+
+ Grupo de informações das quantidades totais de artigos perigosos
+ Preencher conforme a legislação de transporte de produtos perigosos aplicada ao modal
+
+
+
+
+
+ Quantidade total de artigos perigosos
+ 15 posições, sendo 11 inteiras e 4 decimais.
+Deve indicar a quantidade total do artigo perigoso, tendo como base a unidade referenciada na Tabela 3-1 do Doc 9284, por exemplo: litros; quilogramas; quilograma bruto etc. O preenchimento não deve, entretanto, incluir a unidade de medida. No caso de transporte de material radioativo, deve-se indicar o somatório dos Índices de Transporte (TI). Não indicar a quantidade do artigo perigoso por embalagem.
+
+
+
+
+ Unidade de medida
+ 1 – KG;
+2 – KG G (quilograma bruto);
+3 – LITROS;
+4 – TI (índice de transporte para radioativos); 5- Unidades (apenas para artigos perigosos medidos em unidades que não se enquadram nos itens acima. Exemplo: baterias, celulares, equipamentos, veículos, dentre outros)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/cteModalAquaviario_v4.00.xsd b/pynfe/data/XSDs/CT-e/cteModalAquaviario_v4.00.xsd
new file mode 100644
index 00000000..a4fe0839
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/cteModalAquaviario_v4.00.xsd
@@ -0,0 +1,207 @@
+
+
+
+
+
+
+ Informações do modal Aquaviário
+
+
+
+
+
+ Valor da Prestação Base de Cálculo do AFRMM
+
+
+
+
+ AFRMM (Adicional de Frete para Renovação da Marinha Mercante)
+
+
+
+
+ Identificação do Navio
+
+
+
+
+
+
+
+
+
+
+ Grupo de informações das balsas
+
+
+
+
+
+ Identificador da Balsa
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Número da Viagem
+
+
+
+
+
+
+
+
+
+
+ Direção
+ Preencher com: N-Norte, L-Leste, S-Sul, O-Oeste
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Irin do navio sempre deverá ser informado
+
+
+
+
+
+
+
+
+
+
+
+ Grupo de informações de detalhamento dos conteiners
+(Somente para Redespacho Intermediário e Serviço Vinculado a Multimodal)
+
+
+
+
+
+ Identificação do Container
+
+
+
+
+ Grupo de informações dos lacres dos cointainers da qtde da carga
+
+
+
+
+
+ Lacre
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Informações dos documentos dos conteiners
+
+
+
+
+
+ Informações das NF
+
+
+
+
+
+ Série
+
+
+
+
+
+
+
+
+
+
+ Número
+
+
+
+
+
+
+
+
+
+
+ Unidade de medida rateada (Peso,Volume)
+
+
+
+
+
+
+
+ Informações das NFe
+
+
+
+
+
+ Chave de acesso da NF-e
+
+
+
+
+ Unidade de medida rateada (Peso,Volume)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tipo de Navegação
+ Preencher com:
+ 0 - Interior;
+ 1 - Cabotagem
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/cteModalDutoviario_v4.00.xsd b/pynfe/data/XSDs/CT-e/cteModalDutoviario_v4.00.xsd
new file mode 100644
index 00000000..bc9c8940
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/cteModalDutoviario_v4.00.xsd
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+ Informações do modal Dutoviário
+
+
+
+
+
+ Valor da tarifa
+
+
+
+
+ Data de Início da prestação do serviço
+
+
+
+
+ Data de Fim da prestação do serviço
+
+
+
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/cteModalFerroviario_v4.00.xsd b/pynfe/data/XSDs/CT-e/cteModalFerroviario_v4.00.xsd
new file mode 100644
index 00000000..2a789ac6
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/cteModalFerroviario_v4.00.xsd
@@ -0,0 +1,231 @@
+
+
+
+
+
+
+
+ Tipo Dados do Endereço
+
+
+
+
+ Logradouro
+
+
+
+
+
+
+
+
+
+
+ Número
+
+
+
+
+
+
+
+
+
+
+ Complemento
+
+
+
+
+
+
+
+
+
+
+ Bairro
+
+
+
+
+
+
+
+
+
+
+ Código do município
+ Utilizar a tabela do IBGE
+ Informar 9999999 para operações com o exterior.
+
+
+
+
+ Nome do município
+ Informar EXTERIOR para operações com o exterior.
+
+
+
+
+
+
+
+
+
+
+ CEP
+
+
+
+
+
+
+
+
+
+
+ Sigla da UF
+ Informar EX para operações com o exterior.
+
+
+
+
+
+
+ Informações do modal Ferroviário
+
+
+
+
+
+ Tipo de Tráfego
+ Preencher com:
+ 0-Próprio;
+ 1-Mútuo;
+ 2-Rodoferroviário;
+ 3-Rodoviário.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Detalhamento de informações para o tráfego mútuo
+
+
+
+
+
+ Responsável pelo Faturamento
+ Preencher com:
+ 1-Ferrovia de origem;
+ 2-Ferrovia de destino
+
+
+
+
+
+
+
+
+
+
+
+ Ferrovia Emitente do CTe
+ Preencher com:
+ 1-Ferrovia de origem;
+ 2-Ferrovia de destino
+
+
+
+
+
+
+
+
+
+
+
+ Valor do Frete do Tráfego Mútuo
+
+
+
+
+ Chave de acesso do CT-e emitido pelo ferrovia de origem
+
+
+
+
+ Informações das Ferrovias Envolvidas
+
+
+
+
+
+ Número do CNPJ
+ Informar o CNPJ da Ferrovia Envolvida. Caso a Ferrovia envolvida não seja inscrita no CNPJ o campo deverá preenchido com zeros.
+Informar os zeros não significativos.
+
+
+
+
+ Código interno da Ferrovia envolvida
+ Uso da transportadora
+
+
+
+
+
+
+
+
+
+
+ Inscrição Estadual
+
+
+
+
+ Razão Social ou Nome
+
+
+
+
+
+
+
+
+
+
+ Dados do endereço da ferrovia envolvida
+
+
+
+
+
+
+
+
+
+
+ Fluxo Ferroviário
+ Trata-se de um número identificador do contrato firmado com o cliente
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/cteModalRodoviarioOS_v4.00.xsd b/pynfe/data/XSDs/CT-e/cteModalRodoviarioOS_v4.00.xsd
new file mode 100644
index 00000000..23bcb62a
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/cteModalRodoviarioOS_v4.00.xsd
@@ -0,0 +1,193 @@
+
+
+
+
+
+
+
+ Tipo Termo de Autorização de Fretamento – TAF
+
+
+
+
+
+
+
+
+
+ Tipo Número de Registro Estadual
+
+
+
+
+
+
+
+
+
+ Informações do modal Rodoviário
+
+
+
+
+
+
+ Termo de Autorização de Fretamento – TAF
+ Registro obrigatório do emitente do CT-e OS junto à ANTT, de acordo com a Resolução ANTT nº 4.777/2015
+
+
+
+
+ Número do Registro Estadual
+ Registro obrigatório do emitente do CT-e OS junto à Agência Reguladora Estadual.
+
+
+
+
+
+ Dados do Veículo
+
+
+
+
+
+ Placa do veículo
+
+
+
+
+
+
+
+ RENAVAM do veículo
+
+
+
+
+
+
+
+
+
+
+ Proprietário ou possuidor do Veículo.
+Só preenchido quando o veículo não pertencer à empresa emitente do CT-e OS
+
+
+
+
+
+
+ Número do CPF
+ Informar os zeros não significativos.
+
+
+
+
+ Número do CNPJ
+ Informar os zeros não significativos.
+
+
+
+
+
+
+ Termo de Autorização de Fretamento – TAF
+ De acordo com a Resolução ANTT nº 4.777/2015
+
+
+
+
+ Número do Registro Estadual
+ Registro obrigatório do emitente do CT-e OS junto à Agência Reguladora Estadual
+
+
+
+
+
+ Razão Social ou Nome do proprietário
+
+
+
+
+
+
+
+
+
+
+
+ Inscrição Estadual
+
+
+
+
+
+
+
+ UF
+
+
+
+
+
+ Tipo Proprietário ou possuidor
+ Preencher com:
+ 0-TAC – Agregado;
+ 1-TAC Independente; ou
+ 2 – Outros.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ UF em que veículo está licenciado
+ Sigla da UF de licenciamento do veículo.
+
+
+
+
+
+
+
+ Dados do fretamento (apenas para Transporte de Pessoas)
+
+
+
+
+
+ Tipo Fretamento
+ Preencher com:
+ 1 - Eventual 2 - Continuo
+
+
+
+
+
+
+
+
+
+
+
+ Data e hora da viagem (Apenas para fretamento eventual)
+ Formato AAAA-MM-DDTHH:MM:DD TZD
+
+
+
+
+
+
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/cteModalRodoviario_v4.00.xsd b/pynfe/data/XSDs/CT-e/cteModalRodoviario_v4.00.xsd
new file mode 100644
index 00000000..21023229
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/cteModalRodoviario_v4.00.xsd
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+
+ Informações do modal Rodoviário
+
+
+
+
+
+ Registro Nacional de Transportadores Rodoviários de Carga
+ Registro obrigatório do emitente do CT-e junto à ANTT para exercer a atividade de transportador rodoviário de cargas por conta de terceiros e mediante remuneração.
+
+
+
+
+
+
+
+
+ Ordens de Coleta associados
+
+
+
+
+
+ Série da OCC
+
+
+
+
+
+
+
+
+
+
+ Número da Ordem de coleta
+
+
+
+
+
+
+
+
+
+
+ Data de emissão da ordem de coleta
+ Formato AAAA-MM-DD
+
+
+
+
+
+
+
+ Número do CNPJ
+ Informar os zeros não significativos.
+
+
+
+
+ Código interno de uso da transportadora
+ Uso intermo das transportadoras.
+
+
+
+
+
+
+
+
+
+
+ Inscrição Estadual
+
+
+
+
+ Sigla da UF
+ Informar EX para operações com o exterior.
+
+
+
+
+ Telefone
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/cteMultiModal_v4.00.xsd b/pynfe/data/XSDs/CT-e/cteMultiModal_v4.00.xsd
new file mode 100644
index 00000000..05dc7949
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/cteMultiModal_v4.00.xsd
@@ -0,0 +1,100 @@
+
+
+
+
+
+
+
+ Informações do Multimodal
+
+
+
+
+
+ Número do Certificado do Operador de Transporte Multimodal
+
+
+
+
+
+
+
+
+
+
+
+
+ Indicador Negociável
+Preencher com: 0 - Não Negociável; 1 - Negociável
+
+
+
+
+
+
+
+
+
+
+
+ Informações de Seguro do Multimodal
+
+
+
+
+
+ Informações da seguradora
+
+
+
+
+
+ Nome da Seguradora
+
+
+
+
+
+
+
+
+
+
+ Número do CNPJ da seguradora
+ Obrigatório apenas se responsável pelo seguro for (2) responsável pela contratação do transporte - pessoa jurídica
+
+
+
+
+
+
+
+ Número da Apólice
+ Obrigatório pela lei 11.442/07 (RCTRC)
+
+
+
+
+
+
+
+
+
+
+ Número da Averbação
+ Não é obrigatório, pois muitas averbações ocorrem aapós a emissão do CT, mensalmente, por exemplo.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/cteOS_v4.00.xsd b/pynfe/data/XSDs/CT-e/cteOS_v4.00.xsd
new file mode 100644
index 00000000..9ac66b26
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/cteOS_v4.00.xsd
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+ Conhecimento de Transporte Eletrônico Outros Serviços
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/cteSimp_v4.00.xsd b/pynfe/data/XSDs/CT-e/cteSimp_v4.00.xsd
new file mode 100644
index 00000000..a6b23e03
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/cteSimp_v4.00.xsd
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+ Conhecimento de Transporte Eletrônico Simplificado
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/cteTiposBasico_v4.00.xsd b/pynfe/data/XSDs/CT-e/cteTiposBasico_v4.00.xsd
new file mode 100644
index 00000000..54889a58
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/cteTiposBasico_v4.00.xsd
@@ -0,0 +1,7966 @@
+
+
+
+
+
+
+
+ Tipo Modal transporte GTVe
+
+
+
+
+
+
+
+
+
+ Tipo Finalidade da GTV-e
+
+
+
+
+
+
+
+
+ Tipo Guia de Transporte de Valores Eletrônica (Modelo 64)
+
+
+
+
+ Informações do CT-e do tipo GTV-e
+
+
+
+
+
+ Identificação da GTV-e
+
+
+
+
+
+ Código da UF do emitente da GTV-e.
+ Utilizar a Tabela do IBGE.
+
+
+
+
+ Código numérico que compõe a Chave de Acesso.
+ Número aleatório gerado pelo emitente para cada CT-e, com o objetivo de evitar acessos indevidos ao documento.
+
+
+
+
+
+
+
+
+
+
+ Código Fiscal de Operações e Prestações
+
+
+
+
+ Natureza da Operação
+
+
+
+
+
+
+
+
+
+
+ Modelo do documento fiscal
+ Utilizar o código 64 para identificação do CT-e Guia de Transporte de Valores
+
+
+
+
+ Série da GTV-e
+ Preencher com "0" no caso de série única
+
+
+
+
+
+
+
+ Número da GTV-e
+
+
+
+
+ Data e hora de emissão da GTV-e
+ Formato AAAA-MM-DDTHH:MM:DD TZD
+
+
+
+
+
+
+
+ Formato de impressão do DACTE
+ Preencher com: 1 - Retrato; 2 - Paisagem.
+
+
+
+
+
+
+
+
+
+
+
+ Forma de emissão da GTV-e
+ Preencher com:
+1 - Normal;
+ 2- Contingencia offline
+7 - Autorização pela SVC-RS;
+ 8 - Autorização pela SVC-SP
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Digito Verificador da chave de acesso da GTV-e
+ Informar o dígito de controle da chave de acesso do CT-e, que deve ser calculado com a aplicação do algoritmo módulo 11 (base 2,9) da chave de acesso.
+
+
+
+
+
+
+
+
+
+
+ Tipo do Ambiente
+ Preencher com:1 - Produção; 2 - Homologação
+
+
+
+
+ Tipo da GTV-e
+ Preencher com:
+ 4 - GTV-e
+
+
+
+
+
+
+
+ Versão do processo de emissão
+ Iinformar a versão do aplicativo emissor de CT-e.
+
+
+
+
+
+
+
+
+
+
+ Código do Município de envio da GTV-e (de onde o documento foi transmitido)
+ Utilizar a tabela do IBGE. Informar 9999999 para as operações com o exterior.
+
+
+
+
+ Nome do Município de envio da GTV-e (de onde o documento foi transmitido)
+ Informar PAIS/Municipio para as operações com o exterior.
+
+
+
+
+
+
+
+
+
+
+ Sigla da UF de envio da GTV-e (de onde o documento foi transmitido)
+ Informar 'EX' para operações com o exterior.
+
+
+
+
+ Modal da GTV-e
+ Preencher com:
+01-Rodoviário
+06-Multimodal
+
+
+
+
+
+
+
+
+
+
+ Tipo do Serviço
+ Preencher com:
+
+9 - GTV
+
+
+
+
+
+
+
+
+
+
+ Indicador da IE do tomador:
+1 – Contribuinte ICMS;
+2 – Contribuinte isento de inscrição;
+9 – Não Contribuinte
+ Aplica-se ao tomador que for indicado no toma3 ou toma4
+
+
+
+
+
+
+
+
+
+
+
+
+ Data e hora de saida da origem
+ Formato AAAA-MM-DDTHH:MM:DD TZD
+
+
+
+
+
+
+
+ Data e hora de chegada no destino
+ Formato AAAA-MM-DDTHH:MM:DD TZD
+
+
+
+
+
+
+
+
+ Indicador do "papel" do tomador do serviço no GT-e
+
+
+
+
+
+ Tomador do Serviço
+ Preencher com:
+ 0-Remetente;
+ 1-Destinatário
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Indicador do "papel" do tomador do serviço no CTV-e
+
+
+
+
+
+ Tomador do Serviço
+ Preencher com:
+ 4 - Outros
+ Obs: Informar os dados cadastrais do tomador do serviço
+
+
+
+
+
+
+
+
+
+
+
+ Número do CNPJ
+ Em caso de empresa não estabelecida no Brasil, será informado o CNPJ com zeros.
+Informar os zeros não significativos.
+
+
+
+
+ Número do CPF
+ Informar os zeros não significativos.
+
+
+
+
+
+ Inscrição Estadual
+ Informar a IE do tomador ou ISENTO se tomador é contribuinte do ICMS isento de inscrição no cadastro de contribuintes do ICMS. Caso o tomador não seja contribuinte do ICMS não informar o conteúdo.
+
+
+
+
+
+
+
+ Razão Social ou Nome
+
+
+
+
+
+
+
+
+
+
+ Nome Fantasia
+
+
+
+
+
+
+
+
+
+
+ Telefone
+
+
+
+
+ Dados do endereço
+
+
+
+
+ Endereço de email
+
+
+
+
+
+
+
+
+ Informar apenas
+para tpEmis diferente de 1
+
+
+
+ Data e Hora da entrada em contingência
+ Informar a data e hora no formato AAAA-MM-DDTHH:MM:SS
+
+
+
+
+ Justificativa da entrada em contingência
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Dados complementares da GTV-e para fins operacionais ou comerciais
+
+
+
+
+
+ Característica adicional do transporte
+ Texto livre:
+REENTREGA; DEVOLUÇÃO; REFATURAMENTO; etc
+
+
+
+
+
+
+
+
+
+
+ Característica adicional do serviço
+ Texto livre:
+ ENTREGA EXPRESSA; LOGÍSTICA REVERSA; CONVENCIONAL; EMERGENCIAL; etc
+
+
+
+
+
+
+
+
+
+
+ Funcionário emissor da GTV-e
+
+
+
+
+
+
+
+
+
+
+ Observações Gerais
+
+
+
+
+
+
+
+
+
+
+ Campo de uso livre do contribuinte
+ Informar o nome do campo no atributo xCampo e o conteúdo do campo no XTexto
+
+
+
+
+
+ Conteúdo do campo
+
+
+
+
+
+
+
+
+
+
+
+ Identificação do campo
+
+
+
+
+
+
+
+
+
+
+
+
+ Campo de uso livre do contribuinte
+ Informar o nome do campo no atributo xCampo e o conteúdo do campo no XTexto
+
+
+
+
+
+ Conteúdo do campo
+
+
+
+
+
+
+
+
+
+
+
+ Identificação do campo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Identificação do Emitente da GTV-e
+
+
+
+
+
+ CNPJ do emitente
+ Informar zeros não significativos
+
+
+
+
+ Inscrição Estadual do Emitente
+
+
+
+
+
+
+
+ Inscrição Estadual do Substituto Tributário
+
+
+
+
+
+
+
+ Razão social ou Nome do emitente
+
+
+
+
+
+
+
+
+
+
+ Nome fantasia
+
+
+
+
+
+
+
+
+
+
+ Endereço do emitente
+
+
+
+
+
+
+
+ Informações do Remetente
+ Poderá não ser informado para os CT-e de redespacho intermediário e serviço vinculado a multimodal. Nos demais casos deverá sempre ser informado.
+
+
+
+
+
+
+ Número do CNPJ
+ Em caso de empresa não estabelecida no Brasil, será informado o CNPJ com zeros.
+ Informar os zeros não significativos.
+
+
+
+
+ Número do CPF
+ Informar os zeros não significativos.
+
+
+
+
+
+ Inscrição Estadual
+ Informar a IE do remetente ou ISENTO se remetente é contribuinte do ICMS isento de inscrição no cadastro de contribuintes do ICMS. Caso o remetente não seja contribuinte do ICMS não informar a tag.
+
+
+
+
+
+
+
+ Razão social ou nome do remetente
+
+
+
+
+
+
+
+
+
+
+ Nome fantasia
+
+
+
+
+
+
+
+
+
+
+ Telefone
+
+
+
+
+ Dados do endereço
+
+
+
+
+ Endereço de email
+
+
+
+
+
+
+
+
+
+
+ Informações do Destinatário
+ Poderá não ser informado para os CT-e de redespacho intermediário e serviço vinculado a multimodal. Nos demais casos deverá sempre ser informado.
+
+
+
+
+
+
+ Número do CNPJ
+ Em caso de empresa não estabelecida no Brasil, será informado o CNPJ com zeros.
+ Informar os zeros não significativos.
+
+
+
+
+ Número do CPF
+ Informar os zeros não significativos.
+
+
+
+
+
+ Inscrição Estadual
+ Informar a IE do destinatário ou ISENTO se destinatário é contribuinte do ICMS isento de inscrição no cadastro de contribuintes do ICMS. Caso o destinatário não seja contribuinte do ICMS não informar o conteúdo.
+
+
+
+
+
+
+
+ Razão Social ou Nome do destinatário
+
+
+
+
+
+
+
+
+
+
+ Telefone
+
+
+
+
+ Inscrição na SUFRAMA
+ (Obrigatório nas operações com as áreas com benefícios de incentivos fiscais sob controle da SUFRAMA)
+
+
+
+
+
+
+
+
+
+
+ Dados do endereço
+
+
+
+
+ Endereço de email
+
+
+
+
+
+
+
+ Informações do endereço da origem do serviço
+
+
+
+
+ Informações do endereço do destino do serviço
+
+
+
+
+ Grupo de informações detalhadas da GTV-e
+
+
+
+
+
+ Informações das Espécies transportadas
+
+
+
+
+
+ Tipo da Espécie
+ 1 - Cédula
+2 - Cheque
+3 - Moeda
+4 - Outros
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Valor Transportada em Espécie indicada
+
+
+
+
+ Nacionalidade do Numerário
+ 1 - Nacional
+2 - Estrangeiro
+
+
+
+
+
+
+
+
+
+
+
+ Nome da Moeda
+ Informar somente se tipo de numerário for 2 - Estrangeiro
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Quantidade de volumes/malotes
+
+
+
+
+ Grupo de informações dos veículos utilizados no transporte de valores
+
+
+
+
+
+ Placa do veículo
+
+
+
+
+ UF em que veículo está licenciado
+ Sigla da UF de licenciamento do veículo.
+
+
+
+
+ RNTRC do transportador
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Autorizados para download do XML do DF-e
+ Informar CNPJ ou CPF. Preencher os zeros não significativos.
+
+
+
+
+
+
+ CNPJ do autorizado
+ Informar zeros não significativos
+
+
+
+
+ CPF do autorizado
+ Informar zeros não significativos
+
+
+
+
+
+
+
+
+ Informações do Responsável Técnico pela emissão do DF-e
+
+
+
+
+
+ Versão do leiaute
+ Ex: "4.00"
+
+
+
+
+
+
+
+ Identificador da tag a ser assinada
+ Informar a chave de acesso do CT-e OS e precedida do literal "CTe"
+
+
+
+
+
+
+
+
+
+
+
+ Informações suplementares da GTV-e
+
+
+
+
+
+ Texto com o QR-Code impresso no DACTE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Versão do leiaute
+
+
+
+
+
+
+
+
+ Tipo Protocolo de status resultado do processamento da CT-e
+
+
+
+
+ Dados do protocolo de status
+
+
+
+
+
+ Identificação do Ambiente:
+1 - Produção
+2 - Homologação
+
+
+
+
+ Versão do Aplicativo que processou o CT-e
+
+
+
+
+ Chaves de acesso da CT-e,
+
+
+
+
+ Data e hora de processamento, no formato AAAA-MM-DDTHH:MM:SS TZD.
+
+
+
+
+ Número do Protocolo de Status do CT-e.
+
+
+
+
+ Digest Value da CT-e processado. Utilizado para conferir a integridade do CT-e original.
+
+
+
+
+ Código do status do CT-e.
+
+
+
+
+
+
+
+ Descrição literal do status do CT-e.
+
+
+
+
+
+
+
+
+ Mensagem do Fisco
+
+
+
+
+
+ Código do status da mensagem do fisco
+
+
+
+
+
+
+
+ Mensagem do Fisco
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tipo Protocolo de status resultado do processamento do CT-e OS (Modelo 67)
+
+
+
+
+ Dados do protocolo de status
+
+
+
+
+
+ Identificação do Ambiente:
+1 - Produção
+2 - Homologação
+
+
+
+
+ Versão do Aplicativo que processou o CT-e
+
+
+
+
+ Chaves de acesso da CT-e
+
+
+
+
+ Data e hora de processamento, no formato AAAA-MM-DDTHH:MM:SS TZD.
+
+
+
+
+ Número do Protocolo de Status do CT-e.
+
+
+
+
+ Digest Value da CT-e processado. Utilizado para conferir a integridade do CT-e original.
+
+
+
+
+ Código do status do CT-e.
+
+
+
+
+
+
+
+ Descrição literal do status do CT-e.
+
+
+
+
+
+
+
+
+ Mensagem do Fisco
+
+
+
+
+
+ Código do status da mensagem do fisco
+
+
+
+
+
+
+
+ Mensagem do Fisco
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tipo Protocolo de status resultado do processamento da GTV-e (Modelo 64)
+
+
+
+
+ Dados do protocolo de status
+
+
+
+
+
+ Identificação do Ambiente:
+1 - Produção
+2 - Homologação
+
+
+
+
+ Versão do Aplicativo que processou a GTV-e
+
+
+
+
+ Chaves de acesso da CT-e
+
+
+
+
+ Data e hora de processamento, no formato AAAA-MM-DDTHH:MM:SS TZD.
+
+
+
+
+ Número do Protocolo de Status da GTV-e
+
+
+
+
+ Digest Value da GTV-e processado. Utilizado para conferir a integridade da GTV-e original.
+
+
+
+
+ Código do status da GTV-e.
+
+
+
+
+
+
+
+ Descrição literal do status da GTV-e.
+
+
+
+
+
+
+
+
+ Mensagem do Fisco
+
+
+
+
+
+ Código do status da mensagem do fisco
+
+
+
+
+
+
+
+ Mensagem do Fisco
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tipo Retorno do Pedido de Autorização de CT-e Simplificado (Modelo 57)
+
+
+
+
+ Identificação do Ambiente:
+1 - Produção
+2 - Homologação
+
+
+
+
+ Identificação da UF
+
+
+
+
+ Versão do Aplicativo que processou a CT-e
+
+
+
+
+ código do status do retorno da consulta.
+
+
+
+
+ Descrição literal do status do do retorno da consulta.
+
+
+
+
+ Reposta ao processamento do CT-e
+
+
+
+
+
+
+
+ Tipo Retorno do Pedido de Autorização de CT-e (Modelo 57)
+
+
+
+
+ Identificação do Ambiente:
+1 - Produção
+2 - Homologação
+
+
+
+
+ Identificação da UF
+
+
+
+
+ Versão do Aplicativo que processou a CT-e
+
+
+
+
+ código do status do retorno da consulta.
+
+
+
+
+ Descrição literal do status do do retorno da consulta.
+
+
+
+
+ Reposta ao processamento do CT-e
+
+
+
+
+
+
+
+ Tipo Retorno do Pedido de Autorização de GTV-e (Modelo 64)
+
+
+
+
+ Identificação do Ambiente:
+1 - Produção
+2 - Homologação
+
+
+
+
+ Identificação da UF
+
+
+
+
+ Versão do Aplicativo que processou a GTV-e
+
+
+
+
+ código do status do retorno da consulta.
+
+
+
+
+ Descrição literal do status do do retorno da consulta.
+
+
+
+
+ Reposta ao processamento do CT-e
+
+
+
+
+
+
+
+ Tipo Retorno do Pedido de Autorização de CT-e OS (Modelo 67)
+
+
+
+
+ Identificação do Ambiente:
+1 - Produção
+2 - Homologação
+
+
+
+
+ Identificação da UF
+
+
+
+
+ Versão do Aplicativo que processou a CT-e
+
+
+
+
+ código do status do retorno da consulta.
+
+
+
+
+ Descrição literal do status do do retorno da consulta.
+
+
+
+
+ Reposta ao processamento do CT-e
+
+
+
+
+
+
+
+ Tipo Conhecimento de Transporte Eletrônico (Modelo 57) - Modelo Simplificado
+
+
+
+
+ Informações do CT-e
+
+
+
+
+
+ Identificação do CT-e
+
+
+
+
+
+ Código da UF do emitente do CT-e.
+ Utilizar a Tabela do IBGE.
+
+
+
+
+ Código numérico que compõe a Chave de Acesso.
+ Número aleatório gerado pelo emitente para cada CT-e, com o objetivo de evitar acessos indevidos ao documento.
+
+
+
+
+
+
+
+
+
+
+ Código Fiscal de Operações e Prestações
+
+
+
+
+ Natureza da Operação
+
+
+
+
+
+
+
+
+
+
+ Modelo do documento fiscal
+ Utilizar o código 57 para identificação do CT-e, emitido em substituição aos modelos de conhecimentos em papel.
+
+
+
+
+ Série do CT-e
+ Preencher com "0" no caso de série única
+
+
+
+
+
+
+
+ Número do CT-e
+
+
+
+
+ Data e hora de emissão do CT-e
+ Formato AAAA-MM-DDTHH:MM:DD TZD
+
+
+
+
+
+
+
+ Formato de impressão do DACTE
+ Preencher com: 1 - Retrato; 2 - Paisagem.
+
+
+
+
+
+
+
+
+
+
+
+ Forma de emissão do CT-e
+ Preencher com:
+1 - Normal;
+3 - Regime Especial NFF;
+4 - EPEC pela SVC;
+7 - Autorização pela SVC-RS;
+8 - Autorização pela SVC-SP
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Digito Verificador da chave de acesso do CT-e
+ Informar o dígito de controle da chave de acesso do CT-e, que deve ser calculado com a aplicação do algoritmo módulo 11 (base 2,9) da chave de acesso.
+
+
+
+
+
+
+
+
+
+
+ Tipo do Ambiente
+ Preencher com:1 - Produção; 2 - Homologação.
+
+
+
+
+ Tipo do CT-e Simplificado
+ Preencher com:
+5 - CTe Simplificado
+6 - Substituição CTe Simplificado
+
+
+
+
+ Identificador do processo de emissão do CT-e
+ Preencher com:
+ 0 - emissão de CT-e com aplicativo do contribuinte;
+ 3- emissão CT-e pelo contribuinte com aplicativo fornecido pelo SEBRAE.
+
+
+
+
+ Versão do processo de emissão
+ Informar a versão do aplicativo emissor de CT-e.
+
+
+
+
+
+
+
+
+
+
+ Código do Município de envio do CT-e (de onde o documento foi transmitido)
+ Utilizar a tabela do IBGE. Informar 9999999 para as operações com o exterior.
+
+
+
+
+ Nome do Município de envio do CT-e (de onde o documento foi transmitido)
+ Informar PAIS/Municipio para as operações com o exterior.
+
+
+
+
+
+
+
+
+
+
+ Sigla da UF de envio do CT-e (de onde o documento foi transmitido)
+ Informar 'EX' para operações com o exterior.
+
+
+
+
+ Modal
+ Preencher com:
+01-Rodoviário
+02-Aéreo
+03-Aquaviário
+
+
+
+
+ Tipo do Serviço
+ Preencher com:
+0 - Normal;
+1 - Subcontratação;
+2 - Redespacho;
+
+
+
+
+
+
+
+
+
+
+
+
+ UF do início da prestação
+ Informar 'EX' para operações com o exterior.
+
+
+
+
+ UF do término da prestação
+ Informar 'EX' para operações com o exterior.
+
+
+
+
+ Indicador se o Recebedor retira no Aeroporto, Filial, Porto ou Estação de Destino?
+ Preencher com: 0 - sim; 1 - não
+
+
+
+
+
+
+
+
+
+
+
+ Detalhes do retira
+
+
+
+
+
+
+
+
+
+
+ Informar apenas
+para tpEmis diferente de 1
+
+
+
+ Data e Hora da entrada em contingência
+ Informar a data e hora no formato AAAA-MM-DDTHH:MM:SS
+
+
+
+
+ Justificativa da entrada em contingência
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Dados complementares do CT-e para fins operacionais ou comerciais
+
+
+
+
+
+ Característica adicional do transporte
+ Texto livre:
+REENTREGA; DEVOLUÇÃO; REFATURAMENTO; etc
+
+
+
+
+
+
+
+
+
+
+ Característica adicional do serviço
+ Texto livre:
+ ENTREGA EXPRESSA; LOGÍSTICA REVERSA; CONVENCIONAL; EMERGENCIAL; etc
+
+
+
+
+
+
+
+
+
+
+ Previsão do fluxo da carga
+ Preenchimento obrigatório para o modal aéreo.
+
+
+
+
+
+ Sigla ou código interno da Filial/Porto/Estação/ Aeroporto de Origem
+ Observações para o modal aéreo:
+ - Preenchimento obrigatório para o modal aéreo.
+ - O código de três letras IATA do aeroporto de partida deverá ser incluído como primeira anotação. Quando não for possível, utilizar a sigla OACI.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sigla ou código interno da Filial/Porto/Estação/Aeroporto de Passagem
+ Observação para o modal aéreo:
+ - O código de três letras IATA, referente ao aeroporto de transferência, deverá ser incluído, quando for o caso. Quando não for possível, utilizar a sigla OACI. Qualquer solicitação de itinerário deverá ser incluída.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sigla ou código interno da Filial/Porto/Estação/Aeroporto de Destino
+ Observações para o modal aéreo:
+ - Preenchimento obrigatório para o modal aéreo.
+ - Deverá ser incluído o código de três letras IATA do aeroporto de destino. Quando não for possível, utilizar a sigla OACI.
+
+
+
+
+
+
+
+
+
+
+ Código da Rota de Entrega
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Observações Gerais
+
+
+
+
+
+
+
+
+
+
+ Campo de uso livre do contribuinte
+ Informar o nome do campo no atributo xCampo e o conteúdo do campo no XTexto
+
+
+
+
+
+ Conteúdo do campo
+
+
+
+
+
+
+
+
+
+
+
+ Identificação do campo
+
+
+
+
+
+
+
+
+
+
+
+
+ Campo de uso livre do contribuinte
+ Informar o nome do campo no atributo xCampo e o conteúdo do campo no XTexto
+
+
+
+
+
+ Conteúdo do campo
+
+
+
+
+
+
+
+
+
+
+
+ Identificação do campo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Identificação do Emitente do CT-e
+
+
+
+
+
+
+ CNPJ do emitente
+ Informar zeros não significativos
+
+
+
+
+ CPF do emitente
+ Informar zeros não significativos.
+
+Usar com série específica 920-969 para emitente pessoa física com inscrição estadual
+
+
+
+
+
+ Inscrição Estadual do Emitente
+ A IE do emitente somente ficará sem informação para o caso do Regime Especial da NFF (tpEmis=3)
+
+
+
+
+
+
+
+ Inscrição Estadual do Substituto Tributário
+
+
+
+
+
+
+
+ Razão social ou Nome do emitente
+
+
+
+
+
+
+
+
+
+
+ Nome fantasia
+
+
+
+
+
+
+
+
+
+
+ Endereço do emitente
+
+
+
+
+ Código do Regime Tributário
+ Informar: 1=Simples Nacional;
+2=Simples Nacional, excesso sublimite de receita bruta;
+3=Regime Normal.
+4=Simples Nacional - Microempreendedor Individual – MEI.
+
+
+
+
+
+
+
+
+ Identificação do tomador do serviço no CT-e
+
+
+
+
+
+ Tomador do Serviço
+ Preencher com:
+
+0-Remetente;
+1-Expedidor;
+2-Recebedor;
+3-Destinatário
+4-Terceiro
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Indicador do papel do tomador na prestação do serviço:
+1 – Contribuinte ICMS;
+2 – Contribuinte isento de inscrição;
+9 – Não Contribuinte
+ Aplica-se ao tomador que for indicado no toma
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Número do CNPJ
+ Em caso de empresa não estabelecida no Brasil, será informado o CNPJ com zeros.
+Informar os zeros não significativos.
+
+
+
+
+ Número do CPF
+ Informar os zeros não significativos.
+
+
+
+
+
+ Inscrição Estadual
+ Informar a IE do tomador ou ISENTO se tomador é contribuinte do ICMS isento de inscrição no cadastro de contribuintes do ICMS. Caso o tomador não seja contribuinte do ICMS não informar o conteúdo.
+
+
+
+
+
+
+
+ Razão Social ou Nome
+
+
+
+
+
+
+
+
+
+
+ Inscrição na SUFRAMA
+ (Obrigatório nas operações com as áreas com benefícios de incentivos fiscais sob controle da SUFRAMA)
+
+
+
+
+
+
+
+
+
+
+ Telefone
+
+
+
+
+ Dados do endereço
+
+
+
+
+ Endereço de email
+
+
+
+
+
+
+
+ Informações da Carga do CT-e
+
+
+
+
+
+ Valor total da carga
+
+
+
+
+ Produto predominante
+ Informar a descrição do produto predominante
+
+
+
+
+
+
+
+
+
+
+ Outras características da carga
+ "FRIA", "GRANEL", "REFRIGERADA", "Medidas: 12X12X12"
+
+
+
+
+
+
+
+
+
+
+ Informações de quantidades da Carga do CT-e
+ Para o Aéreo é obrigatório o preenchimento desse campo da seguinte forma.
+1 - Peso Bruto, sempre em quilogramas (obrigatório);
+2 - Peso Cubado; sempre em quilogramas;
+3 - Quantidade de volumes, sempre em unidades (obrigatório);
+4 - Cubagem, sempre em metros cúbicos (obrigatório apenas quando for impossível preencher as dimensões da(s) embalagem(ens) na tag xDime do leiaute do Aéreo).
+
+
+
+
+
+ Código da Unidade de Medida
+ Preencher com:
+00-M3;
+01-KG;
+02-TON;
+03-UNIDADE;
+04-LITROS;
+05-MMBTU
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tipo da Medida
+ Informar com:
+00-Cubagem da NF-e
+01-Cubagem Aferida pelo Transportador
+02-Peso Bruto da NF-e
+03-Peso Bruto Aferido pelo Transportador
+04-Peso Cubado
+05-Peso Base do Cálculo do Frete
+06-Peso para uso Operacional
+07-Caixas
+08-Paletes
+09-Sacas
+10-Containers
+11-Rolos
+12-Bombonas
+13-Latas
+14-Litragem
+15-Milhão de BTU (British Thermal Units)
+99-Outros
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Quantidade
+
+
+
+
+
+
+
+ Valor da Carga para efeito de averbação
+ Normalmente igual ao valor declarado da mercadoria, diferente por exemplo, quando a mercadoria transportada é isenta de tributos nacionais para exportação, onde é preciso averbar um valor maior, pois no caso de indenização, o valor a ser pago será maior
+
+
+
+
+
+
+
+ Detalhamento das entregas / prestações do CTe Simplificado
+
+
+
+
+
+
+ Código do Município de início da prestação
+ Utilizar a tabela do IBGE. Informar 9999999 para operações com o exterior.
+
+
+
+
+ Nome do Município do início da prestação
+ Informar 'EXTERIOR' para operações com o exterior.
+
+
+
+
+
+
+
+
+
+
+
+
+ Código do Município de término da prestação
+ Utilizar a tabela do IBGE. Informar 9999999 para operações com o exterior.
+
+
+
+
+ Nome do Município do término da prestação
+ Informar 'EXTERIOR' para operações com o exterior.
+
+
+
+
+
+
+
+
+
+
+
+ Valorl da Prestação do Serviço
+ Pode conter zeros quando o CT-e for de complemento de ICMS
+
+
+
+
+ Valor a Receber
+
+
+
+
+ Componentes do Valor da Prestação
+
+
+
+
+
+ Nome do componente
+ Exxemplos: FRETE PESO, FRETE VALOR, SEC/CAT, ADEME, AGENDAMENTO, etc
+
+
+
+
+
+
+
+
+
+
+ Valor do componente
+
+
+
+
+
+
+
+
+ Informações das NF-e
+
+
+
+
+
+ Chave de acesso da NF-e
+
+
+
+
+ PIN SUFRAMA
+ PIN atribuído pela SUFRAMA para a operação.
+
+
+
+
+
+
+
+
+
+
+
+
+ Data prevista de entrega
+ Formato AAAA-MM-DD
+
+
+
+
+
+ Informações das Unidades de Carga (Containeres/ULD/Outros)
+ Dispositivo de carga utilizada (Unit Load Device - ULD) significa todo tipo de contêiner de carga, vagão, contêiner de avião, palete de aeronave com rede ou palete de aeronave com rede sobre um iglu.
+
+
+
+
+ Informações das Unidades de Transporte (Carreta/Reboque/Vagão)
+ Deve ser preenchido com as informações das unidades de transporte utilizadas.
+
+
+
+
+
+
+
+
+ Documentos anteriores
+
+
+
+
+
+ Chave de acesso do CT-e
+
+
+
+
+ indica se a prestação é total ou parcial em relação as notas do documento anterior
+ Preencher com:
+
+1 - Total
+2 - Parcial
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Chave de acesso da NF-e
+ Informando o tpPrest com “2 – Parcial” deve-se informar as chaves de acesso das NF-e que acobertam a carga transportada.
+
+
+
+
+
+
+
+
+
+
+
+
+ Número identificador do item agrupador da prestação
+
+
+
+
+
+
+
+
+
+
+
+
+ Informações do modal
+
+
+
+
+
+ XML do modal
+Insira neste local o XML específico do modal (rodoviário, aéreo, ferroviário, aquaviário ou dutoviário).
+ O elemento do tipo -any- permite estender o documento XML com elementos não especificados pelo schema.
+ Insira neste local - any- o XML específico do modal (rodoviário, aéreo, ferroviário, aquaviário ou dutoviário). A especificação do schema XML para cada modal pode ser encontrada nos arquivos que acompanham este pacote de liberação:
+ Rodoviário - ver arquivo CTeModalRodoviario_v9.99
+ Aéreo - ver arquivo CTeModalAereo_v9.99
+ Aquaviário - arquivo CTeModalAquaviario_v9.99
+ Ferroviário - arquivo CTeModalFerroviario_v9.99
+ Dutoviário - arquivo CTeModalDutoviario_v9.99
+
+Onde v9.99 é a a designação genérica para a versão do arquivo. Por exemplo, o arquivo para o schema do modal Rodoviário na versão 1.04 será denominado "CTeModalRodoviario_v1.04".
+
+
+
+
+
+ Versão do leiaute específico para o Modal
+
+
+
+
+
+
+
+
+
+
+
+
+ Dados da cobrança do CT-e
+
+
+
+
+
+ Dados da fatura
+
+
+
+
+
+ Número da fatura
+
+
+
+
+
+
+
+
+
+
+ Valor original da fatura
+
+
+
+
+ Valor do desconto da fatura
+
+
+
+
+ Valor líquido da fatura
+
+
+
+
+
+
+
+ Dados das duplicatas
+
+
+
+
+
+ Número da duplicata
+
+
+
+
+
+
+
+
+
+
+ Data de vencimento da duplicata (AAAA-MM-DD)
+
+
+
+
+ Valor da duplicata
+
+
+
+
+
+
+
+
+
+
+ Informações do CT-e de substituição
+
+
+
+
+
+ Chave de acesso do CT-e a ser substituído (original)
+
+
+
+
+
+
+
+
+
+ Indicador de CT-e Alteração de Tomador
+
+
+
+
+
+
+
+
+
+
+
+
+ Informações relativas aos Impostos
+
+
+
+
+
+ Informações relativas ao ICMS
+
+
+
+
+
+ Valor Total dos Tributos
+
+
+
+
+ Informações adicionais de interesse do Fisco
+ Norma referenciada, informações complementares, etc
+
+
+
+
+
+
+
+
+
+
+ Informações do ICMS de partilha com a UF de término do serviço de transporte na operação interestadual
+ Grupo a ser informado nas prestações interestaduais para consumidor final, não contribuinte do ICMS
+
+
+
+
+
+ Valor da BC do ICMS na UF de término da prestação do serviço de transporte
+
+
+
+
+ Percentual do ICMS relativo ao Fundo de Combate à pobreza (FCP) na UF de término da prestação do serviço de transporte
+ Alíquota adotada nas operações internas na UF do destinatário
+
+
+
+
+ Alíquota interna da UF de término da prestação do serviço de transporte
+ Alíquota adotada nas operações internas na UF do destinatário
+
+
+
+
+ Alíquota interestadual das UF envolvidas
+ Alíquota interestadual das UF envolvidas
+
+
+
+
+
+ Valor do ICMS relativo ao Fundo de Combate á Pobreza (FCP) da UF de término da prestação
+
+
+
+
+ Valor do ICMS de partilha para a UF de término da prestação do serviço de transporte
+
+
+
+
+ Valor do ICMS de partilha para a UF de início da prestação do serviço de transporte
+
+
+
+
+
+
+
+
+
+
+ Valores Totais do CTe
+
+
+
+
+
+ Valor Total da Prestação do Serviço
+ Pode conter zeros quando o CT-e for de complemento de ICMS
+
+
+
+
+ Valor total a Receber
+
+
+
+
+
+
+
+ Autorizados para download do XML do DF-e
+ Informar CNPJ ou CPF. Preencher os zeros não significativos.
+
+
+
+
+
+
+ CNPJ do autorizado
+ Informar zeros não significativos
+
+
+
+
+ CPF do autorizado
+ Informar zeros não significativos
+
+
+
+
+
+
+
+
+ Informações do Responsável Técnico pela emissão do DF-e
+
+
+
+
+ Grupo de informações do pedido de emissão da Nota Fiscal Fácil
+
+
+
+
+
+ Solicitação do pedido de emissão da NFF.
+ Será preenchido com a totalidade de campos informados no aplicativo emissor serializado.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Grupo de Informação do Provedor de Assinatura e Autorização
+
+
+
+
+
+ CNPJ do Provedor de Assinatura e Autorização
+
+
+
+
+ Assinatura RSA do Emitente para DFe gerados por PAA
+
+
+
+
+
+ Assinatura digital padrão RSA
+ Converter o atributo Id do DFe para array de bytes e assinar com a chave privada do RSA com algoritmo SHA1 gerando um valor no formato base64.
+
+
+
+
+ Chave Publica no padrão XML RSA Key
+
+
+
+
+
+
+
+
+
+
+
+ Versão do leiaute
+ Ex: "4.00"
+
+
+
+
+
+
+
+ Identificador da tag a ser assinada
+ Informar a chave de acesso do CT-e e precedida do literal "CTe"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Informações suplementares do CT-e
+
+
+
+
+
+ Texto com o QR-Code impresso no DACTE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tipo Conhecimento de Transporte Eletrônico (Modelo 57)
+
+
+
+
+ Informações do CT-e
+
+
+
+
+
+ Identificação do CT-e
+
+
+
+
+
+ Código da UF do emitente do CT-e.
+ Utilizar a Tabela do IBGE.
+
+
+
+
+ Código numérico que compõe a Chave de Acesso.
+ Número aleatório gerado pelo emitente para cada CT-e, com o objetivo de evitar acessos indevidos ao documento.
+
+
+
+
+
+
+
+
+
+
+ Código Fiscal de Operações e Prestações
+
+
+
+
+ Natureza da Operação
+
+
+
+
+
+
+
+
+
+
+ Modelo do documento fiscal
+ Utilizar o código 57 para identificação do CT-e, emitido em substituição aos modelos de conhecimentos em papel.
+
+
+
+
+ Série do CT-e
+ Preencher com "0" no caso de série única
+
+
+
+
+
+
+
+ Número do CT-e
+
+
+
+
+ Data e hora de emissão do CT-e
+ Formato AAAA-MM-DDTHH:MM:DD TZD
+
+
+
+
+
+
+
+ Formato de impressão do DACTE
+ Preencher com: 1 - Retrato; 2 - Paisagem.
+
+
+
+
+
+
+
+
+
+
+
+ Forma de emissão do CT-e
+ Preencher com:
+1 - Normal;
+ 3-Regime Especial NFF; 4-EPEC pela SVC; 5 - Contingência FSDA;
+ 7 - Autorização pela SVC-RS;
+ 8 - Autorização pela SVC-SP
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Digito Verificador da chave de acesso do CT-e
+ Informar o dígito de controle da chave de acesso do CT-e, que deve ser calculado com a aplicação do algoritmo módulo 11 (base 2,9) da chave de acesso.
+
+
+
+
+
+
+
+
+
+
+ Tipo do Ambiente
+ Preencher com:1 - Produção; 2 - Homologação.
+
+
+
+
+ Tipo do CT-e
+ Preencher com:
+ 0 - CT-e Normal;
+ 1 - CT-e de Complemento de Valores;
+ 3 - CT-e de Substituição
+
+
+
+
+ Identificador do processo de emissão do CT-e
+ Preencher com:
+ 0 - emissão de CT-e com aplicativo do contribuinte;
+ 3- emissão CT-e pelo contribuinte com aplicativo fornecido pelo SEBRAE.
+
+
+
+
+ Versão do processo de emissão
+ Iinformar a versão do aplicativo emissor de CT-e.
+
+
+
+
+
+
+
+
+
+
+ Indicador de CT-e Globalizado
+ Informar valor 1 quando for Globalizado e não informar a tag quando não tratar de CT-e Globalizado
+
+
+
+
+
+
+
+
+
+ Código do Município de envio do CT-e (de onde o documento foi transmitido)
+ Utilizar a tabela do IBGE. Informar 9999999 para as operações com o exterior.
+
+
+
+
+ Nome do Município de envio do CT-e (de onde o documento foi transmitido)
+ Informar PAIS/Municipio para as operações com o exterior.
+
+
+
+
+
+
+
+
+
+
+ Sigla da UF de envio do CT-e (de onde o documento foi transmitido)
+ Informar 'EX' para operações com o exterior.
+
+
+
+
+ Modal
+ Preencher com:01-Rodoviário;
+02-Aéreo;03-Aquaviário;04-Ferroviário;05-Dutoviário;06-Multimodal;
+
+
+
+
+ Tipo do Serviço
+ Preencher com:
+0 - Normal;
+1 - Subcontratação;
+2 - Redespacho;
+3 - Redespacho Intermediário;
+4 - Serviço Vinculado a Multimodal
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Código do Município de início da prestação
+ Utilizar a tabela do IBGE. Informar 9999999 para operações com o exterior.
+
+
+
+
+ Nome do Município do início da prestação
+ Informar 'EXTERIOR' para operações com o exterior.
+
+
+
+
+
+
+
+
+
+
+ UF do início da prestação
+ Informar 'EX' para operações com o exterior.
+
+
+
+
+ Código do Município de término da prestação
+ Utilizar a tabela do IBGE. Informar 9999999 para operações com o exterior.
+
+
+
+
+ Nome do Município do término da prestação
+ Informar 'EXTERIOR' para operações com o exterior.
+
+
+
+
+
+
+
+
+
+
+ UF do término da prestação
+ Informar 'EX' para operações com o exterior.
+
+
+
+
+ Indicador se o Recebedor retira no Aeroporto, Filial, Porto ou Estação de Destino?
+ Preencher com: 0 - sim; 1 - não
+
+
+
+
+
+
+
+
+
+
+
+ Detalhes do retira
+
+
+
+
+
+
+
+
+
+
+ Indicador do papel do tomador na prestação do serviço:
+1 – Contribuinte ICMS;
+2 – Contribuinte isento de inscrição;
+9 – Não Contribuinte
+ Aplica-se ao tomador que for indicado no toma3 ou toma4
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Indicador do "papel" do tomador do serviço no CT-e
+
+
+
+
+
+ Tomador do Serviço
+ Preencher com:
+ 0-Remetente;
+ 1-Expedidor;
+ 2-Recebedor;
+ 3-Destinatário
+ Serão utilizadas as informações contidas no respectivo grupo, conforme indicado pelo conteúdo deste campo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Indicador do "papel" do tomador do serviço no CT-e
+
+
+
+
+
+ Tomador do Serviço
+ Preencher com:
+ 4 - Outros
+ Obs: Informar os dados cadastrais do tomador do serviço
+
+
+
+
+
+
+
+
+
+
+
+ Número do CNPJ
+ Em caso de empresa não estabelecida no Brasil, será informado o CNPJ com zeros.
+Informar os zeros não significativos.
+
+
+
+
+ Número do CPF
+ Informar os zeros não significativos.
+
+
+
+
+
+ Inscrição Estadual
+ Informar a IE do tomador ou ISENTO se tomador é contribuinte do ICMS isento de inscrição no cadastro de contribuintes do ICMS. Caso o tomador não seja contribuinte do ICMS não informar o conteúdo.
+
+
+
+
+
+
+
+
+ Razão Social ou Nome
+
+
+
+
+
+
+
+
+
+
+ Nome Fantasia
+
+
+
+
+
+
+
+
+
+
+ Telefone
+
+
+
+
+ Dados do endereço
+
+
+
+
+ Endereço de email
+
+
+
+
+
+
+
+
+
+ Informar apenas
+para tpEmis diferente de 1
+
+
+
+ Data e Hora da entrada em contingência
+ Informar a data e hora no formato AAAA-MM-DDTHH:MM:SS
+
+
+
+
+ Justificativa da entrada em contingência
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Dados complementares do CT-e para fins operacionais ou comerciais
+
+
+
+
+
+ Característica adicional do transporte
+ Texto livre:
+REENTREGA; DEVOLUÇÃO; REFATURAMENTO; etc
+
+
+
+
+
+
+
+
+
+
+ Característica adicional do serviço
+ Texto livre:
+ ENTREGA EXPRESSA; LOGÍSTICA REVERSA; CONVENCIONAL; EMERGENCIAL; etc
+
+
+
+
+
+
+
+
+
+
+ Funcionário emissor do CTe
+
+
+
+
+
+
+
+
+
+
+ Previsão do fluxo da carga
+ Preenchimento obrigatório para o modal aéreo.
+
+
+
+
+
+ Sigla ou código interno da Filial/Porto/Estação/ Aeroporto de Origem
+ Observações para o modal aéreo:
+ - Preenchimento obrigatório para o modal aéreo.
+ - O código de três letras IATA do aeroporto de partida deverá ser incluído como primeira anotação. Quando não for possível, utilizar a sigla OACI.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sigla ou código interno da Filial/Porto/Estação/Aeroporto de Passagem
+ Observação para o modal aéreo:
+ - O código de três letras IATA, referente ao aeroporto de transferência, deverá ser incluído, quando for o caso. Quando não for possível, utilizar a sigla OACI. Qualquer solicitação de itinerário deverá ser incluída.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sigla ou código interno da Filial/Porto/Estação/Aeroporto de Destino
+ Observações para o modal aéreo:
+ - Preenchimento obrigatório para o modal aéreo.
+ - Deverá ser incluído o código de três letras IATA do aeroporto de destino. Quando não for possível, utilizar a sigla OACI.
+
+
+
+
+
+
+
+
+
+
+ Código da Rota de Entrega
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Informações ref. a previsão de entrega
+
+
+
+
+
+
+ Entrega sem data definida
+ Esta opção é proibida para o modal aéreo.
+
+
+
+
+
+ Tipo de data/período programado para entrega
+ 0- Sem data definida
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Entrega com data definida
+
+
+
+
+
+ Tipo de data/período programado para entrega
+ Preencher com:
+ 1-Na data;
+ 2-Até a data;
+ 3-A partir da data
+
+
+
+
+
+
+
+
+
+
+
+
+ Data programada
+ Formato AAAA-MM-DD
+
+
+
+
+
+
+
+ Entrega no período definido
+
+
+
+
+
+ Tipo período
+ 4-no período
+
+
+
+
+
+
+
+
+
+
+ Data inicial
+ Formato AAAA-MM-DD
+
+
+
+
+ Data final
+ Formato AAAA-MM-DD
+
+
+
+
+
+
+
+
+
+ Entrega sem hora definida
+
+
+
+
+
+ Tipo de hora
+ 0- Sem hora definida
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Entrega com hora definida
+
+
+
+
+
+ Tipo de hora
+ Preencher com:
+ 1 - No horário;
+ 2 - Até o horário;
+ 3 - A partir do horário.
+
+
+
+
+
+
+
+
+
+
+
+
+ Hora programada
+ Formato HH:MM:SS
+
+
+
+
+
+
+
+ Entrega no intervalo de horário definido
+
+
+
+
+
+ Tipo de hora
+ 4 - No intervalo de tempo
+
+
+
+
+
+
+
+
+
+
+ Hora inicial
+ Formato HH:MM:SS
+
+
+
+
+ Hora final
+ Formato HH:MM:SS
+
+
+
+
+
+
+
+
+
+
+
+ Município de origem para efeito de cálculo do frete
+
+
+
+
+
+
+
+
+
+
+ Município de destino para efeito de cálculo do frete
+
+
+
+
+
+
+
+
+
+
+ Observações Gerais
+
+
+
+
+
+
+
+
+
+
+ Campo de uso livre do contribuinte
+ Informar o nome do campo no atributo xCampo e o conteúdo do campo no XTexto
+
+
+
+
+
+ Conteúdo do campo
+
+
+
+
+
+
+
+
+
+
+
+ Identificação do campo
+
+
+
+
+
+
+
+
+
+
+
+
+ Campo de uso livre do contribuinte
+ Informar o nome do campo no atributo xCampo e o conteúdo do campo no XTexto
+
+
+
+
+
+ Conteúdo do campo
+
+
+
+
+
+
+
+
+
+
+
+ Identificação do campo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Identificação do Emitente do CT-e
+
+
+
+
+
+
+ CNPJ do emitente
+ Informar zeros não significativos
+
+
+
+
+ CPF do emitente
+ Informar zeros não significativos.
+
+Usar com série específica 920-969 para emitente pessoa física com inscrição estadual
+
+
+
+
+
+ Inscrição Estadual do Emitente
+ A IE do emitente somente ficará sem informação para o caso do Regime Especial da NFF (tpEmis=3)
+
+
+
+
+
+
+
+ Inscrição Estadual do Substituto Tributário
+
+
+
+
+
+
+
+ Razão social ou Nome do emitente
+
+
+
+
+
+
+
+
+
+
+ Nome fantasia
+
+
+
+
+
+
+
+
+
+
+ Endereço do emitente
+
+
+
+
+ Código do Regime Tributário
+ Informar: 1=Simples Nacional;
+2=Simples Nacional, excesso sublimite de receita bruta;
+3=Regime Normal.
+4=Simples Nacional - Microempreendedor Individual – MEI.
+
+
+
+
+
+
+
+
+ Informações do Remetente das mercadorias transportadas pelo CT-e
+ Poderá não ser informado para os CT-e de redespacho intermediário e serviço vinculado a multimodal. Nos demais casos deverá sempre ser informado.
+
+
+
+
+
+
+ Número do CNPJ
+ Em caso de empresa não estabelecida no Brasil, será informado o CNPJ com zeros.
+ Informar os zeros não significativos.
+
+
+
+
+ Número do CPF
+ Informar os zeros não significativos.
+
+
+
+
+
+ Inscrição Estadual
+ Informar a IE do remetente ou ISENTO se remetente é contribuinte do ICMS isento de inscrição no cadastro de contribuintes do ICMS. Caso o remetente não seja contribuinte do ICMS não informar a tag.
+
+
+
+
+
+
+
+ Razão social ou nome do remetente
+
+
+
+
+
+
+
+
+
+
+ Nome fantasia
+
+
+
+
+
+
+
+
+
+
+ Telefone
+
+
+
+
+ Dados do endereço
+
+
+
+
+ Endereço de email
+
+
+
+
+
+
+
+
+
+
+ Informações do Expedidor da Carga
+
+
+
+
+
+
+ Número do CNPJ
+ Em caso de empresa não estabelecida no Brasil, será informado o CNPJ com zeros.
+ Informar os zeros não significativos.
+
+
+
+
+ Número do CPF
+ Informar os zeros não significativos.
+
+
+
+
+
+ Inscrição Estadual
+ Informar a IE do expedidor ou ISENTO se expedidor é contribuinte do ICMS isento de inscrição no cadastro de contribuintes do ICMS. Caso o expedidor não seja contribuinte do ICMS não informar a tag.
+
+
+
+
+
+
+
+ Razão Social ou Nome
+
+
+
+
+
+
+
+
+
+
+ Telefone
+
+
+
+
+ Dados do endereço
+
+
+
+
+ Endereço de email
+
+
+
+
+
+
+
+ Informações do Recebedor da Carga
+
+
+
+
+
+
+ Número do CNPJ
+ Em caso de empresa não estabelecida no Brasil, será informado o CNPJ com zeros.
+ Informar os zeros não significativos.
+
+
+
+
+ Número do CPF
+ Informar os zeros não significativos.
+
+
+
+
+
+ Inscrição Estadual
+ Informar a IE do recebedor ou ISENTO se recebedor é contribuinte do ICMS isento de inscrição no cadastro de contribuintes do ICMS. Caso o recebedor não seja contribuinte do ICMS não informar o conteúdo.
+
+
+
+
+
+
+
+ Razão Social ou Nome
+
+
+
+
+
+
+
+
+
+
+ Telefone
+
+
+
+
+ Dados do endereço
+
+
+
+
+ Endereço de email
+
+
+
+
+
+
+
+ Informações do Destinatário do CT-e
+ Poderá não ser informado para os CT-e de redespacho intermediário e serviço vinculado a multimodal. Nos demais casos deverá sempre ser informado.
+
+
+
+
+
+
+ Número do CNPJ
+ Em caso de empresa não estabelecida no Brasil, será informado o CNPJ com zeros.
+ Informar os zeros não significativos.
+
+
+
+
+ Número do CPF
+ Informar os zeros não significativos.
+
+
+
+
+
+ Inscrição Estadual
+ Informar a IE do destinatário ou ISENTO se destinatário é contribuinte do ICMS isento de inscrição no cadastro de contribuintes do ICMS. Caso o destinatário não seja contribuinte do ICMS não informar o conteúdo.
+
+
+
+
+
+
+
+ Razão Social ou Nome do destinatário
+
+
+
+
+
+
+
+
+
+
+ Telefone
+
+
+
+
+ Inscrição na SUFRAMA
+ (Obrigatório nas operações com as áreas com benefícios de incentivos fiscais sob controle da SUFRAMA)
+
+
+
+
+
+
+
+
+
+
+ Dados do endereço
+
+
+
+
+ Endereço de email
+
+
+
+
+
+
+
+ Valores da Prestação de Serviço
+
+
+
+
+
+ Valor Total da Prestação do Serviço
+ Pode conter zeros quando o CT-e for de complemento de ICMS
+
+
+
+
+ Valor a Receber
+
+
+
+
+ Componentes do Valor da Prestação
+
+
+
+
+
+ Nome do componente
+ Exxemplos: FRETE PESO, FRETE VALOR, SEC/CAT, ADEME, AGENDAMENTO, etc
+
+
+
+
+
+
+
+
+
+
+ Valor do componente
+
+
+
+
+
+
+
+
+
+
+ Informações relativas aos Impostos
+
+
+
+
+
+ Informações relativas ao ICMS
+
+
+
+
+
+ Valor Total dos Tributos
+
+
+
+
+ Informações adicionais de interesse do Fisco
+ Norma referenciada, informações complementares, etc
+
+
+
+
+
+
+
+
+
+
+ Informações do ICMS de partilha com a UF de término do serviço de transporte na operação interestadual
+ Grupo a ser informado nas prestações interestaduais para consumidor final, não contribuinte do ICMS
+
+
+
+
+
+ Valor da BC do ICMS na UF de término da prestação do serviço de transporte
+
+
+
+
+ Percentual do ICMS relativo ao Fundo de Combate à pobreza (FCP) na UF de término da prestação do serviço de transporte
+ Alíquota adotada nas operações internas na UF do destinatário
+
+
+
+
+ Alíquota interna da UF de término da prestação do serviço de transporte
+ Alíquota adotada nas operações internas na UF do destinatário
+
+
+
+
+ Alíquota interestadual das UF envolvidas
+ Alíquota interestadual das UF envolvidas
+
+
+
+
+
+ Valor do ICMS relativo ao Fundo de Combate á Pobreza (FCP) da UF de término da prestação
+
+
+
+
+ Valor do ICMS de partilha para a UF de término da prestação do serviço de transporte
+
+
+
+
+ Valor do ICMS de partilha para a UF de início da prestação do serviço de transporte
+
+
+
+
+
+
+
+
+
+
+
+ Grupo de informações do CT-e Normal e Substituto
+
+
+
+
+
+ Informações da Carga do CT-e
+
+
+
+
+
+ Valor total da carga
+ Dever ser informado para todos os modais, com exceção para o Dutoviário.
+
+
+
+
+ Produto predominante
+ Informar a descrição do produto predominante
+
+
+
+
+
+
+
+
+
+
+ Outras características da carga
+ "FRIA", "GRANEL", "REFRIGERADA", "Medidas: 12X12X12"
+
+
+
+
+
+
+
+
+
+
+ Informações de quantidades da Carga do CT-e
+ Para o Aéreo é obrigatório o preenchimento desse campo da seguinte forma.
+1 - Peso Bruto, sempre em quilogramas (obrigatório);
+2 - Peso Cubado; sempre em quilogramas;
+3 - Quantidade de volumes, sempre em unidades (obrigatório);
+4 - Cubagem, sempre em metros cúbicos (obrigatório apenas quando for impossível preencher as dimensões da(s) embalagem(ens) na tag xDime do leiaute do Aéreo).
+
+
+
+
+
+ Código da Unidade de Medida
+ Preencher com:
+ 00-M3;
+ 01-KG;
+ 02-TON;
+ 03-UNIDADE;
+ 04-LITROS;
+ 05-MMBTU
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tipo da Medida
+ Exemplos:
+PESO BRUTO, PESO DECLARADO, PESO CUBADO, PESO AFORADO, PESO AFERIDO, PESO BASE DE CÁLCULO, LITRAGEM, CAIXAS e etc
+
+
+
+
+
+
+
+
+
+
+ Quantidade
+
+
+
+
+
+
+
+ Valor da Carga para efeito de averbação
+ Normalmente igual ao valor declarado da mercadoria, diferente por exemplo, quando a mercadoria transportada é isenta de tributos nacionais para exportação, onde é preciso averbar um valor maior, pois no caso de indenização, o valor a ser pago será maior
+
+
+
+
+
+
+
+ Informações dos documentos transportados pelo CT-e
+Opcional para Redespacho Intermediario e Serviço vinculado a multimodal.
+ Poderá não ser informado para os CT-e de redespacho intermediário e serviço vinculado a multimodal. Nos demais casos deverá sempre ser informado.
+
+
+
+
+
+
+ Informações das NF
+ Este grupo deve ser informado quando o documento originário for NF
+
+
+
+
+
+ Número do Romaneio da NF
+
+
+
+
+
+
+
+
+
+
+ Número do Pedido da NF
+
+
+
+
+
+
+
+
+
+
+ Modelo da Nota Fiscal
+ Preencher com:
+01 - NF Modelo 01/1A e Avulsa;
+04 - NF de Produtor
+
+
+
+
+ Série
+
+
+
+
+
+
+
+
+
+
+ Número
+
+
+
+
+
+
+
+
+
+
+ Data de Emissão
+ Formato AAAA-MM-DD
+
+
+
+
+ Valor da Base de Cálculo do ICMS
+
+
+
+
+ Valor Total do ICMS
+
+
+
+
+ Valor da Base de Cálculo do ICMS ST
+
+
+
+
+ Valor Total do ICMS ST
+
+
+
+
+ Valor Total dos Produtos
+
+
+
+
+ Valor Total da NF
+
+
+
+
+ CFOP Predominante
+ CFOP da NF ou, na existência de mais de um, predominância pelo critério de valor econômico.
+
+
+
+
+ Peso total em Kg
+
+
+
+
+ PIN SUFRAMA
+ PIN atribuído pela SUFRAMA para a operação.
+
+
+
+
+
+
+
+
+
+
+
+
+ Data prevista de entrega
+ Formato AAAA-MM-DD
+
+
+
+
+
+ Informações das Unidades de Carga (Containeres/ULD/Outros)
+ Dispositivo de carga utilizada (Unit Load Device - ULD) significa todo tipo de contêiner de carga, vagão, contêiner de avião, palete de aeronave com rede ou palete de aeronave com rede sobre um iglu.
+
+
+
+
+ Informações das Unidades de Transporte (Carreta/Reboque/Vagão)
+ Deve ser preenchido com as informações das unidades de transporte utilizadas.
+
+
+
+
+
+
+
+
+ Informações das NF-e
+
+
+
+
+
+ Chave de acesso da NF-e
+
+
+
+
+ PIN SUFRAMA
+ PIN atribuído pela SUFRAMA para a operação.
+
+
+
+
+
+
+
+
+
+
+
+
+ Data prevista de entrega
+ Formato AAAA-MM-DD
+
+
+
+
+
+ Informações das Unidades de Carga (Containeres/ULD/Outros)
+ Dispositivo de carga utilizada (Unit Load Device - ULD) significa todo tipo de contêiner de carga, vagão, contêiner de avião, palete de aeronave com rede ou palete de aeronave com rede sobre um iglu.
+
+
+
+
+ Informações das Unidades de Transporte (Carreta/Reboque/Vagão)
+ Deve ser preenchido com as informações das unidades de transporte utilizadas.
+
+
+
+
+
+
+
+
+ Informações dos demais documentos
+
+
+
+
+
+ Tipo de documento originário
+ Preencher com:
+ 00 - Declaração;
+ 10 - Dutoviário;
+
+
+59 - CF-e SAT;
+
+65 - NFC-e;
+ 99 - Outros
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Descrição do documento
+
+
+
+
+
+
+
+
+
+
+ Número
+
+
+
+
+
+
+
+
+
+
+ Data de Emissão
+ Formato AAAA-MM-DD
+
+
+
+
+ Valor do documento
+
+
+
+
+ Data prevista de entrega
+ Formato AAAA-MM-DD
+
+
+
+
+
+ Informações das Unidades de Carga (Containeres/ULD/Outros)
+ Dispositivo de carga utilizada (Unit Load Device - ULD) significa todo tipo de contêiner de carga, vagão, contêiner de avião, palete de aeronave com rede ou palete de aeronave com rede sobre um iglu.
+
+
+
+
+ Informações das Unidades de Transporte (Carreta/Reboque/Vagão)
+ Deve ser preenchido com as informações das unidades de transporte utilizadas.
+
+
+
+
+
+
+
+
+
+
+
+
+ Documentos de Transporte Anterior
+
+
+
+
+
+ Emissor do documento anterior
+
+
+
+
+
+
+ Número do CNPJ
+ Em caso de empresa não estabelecida no Brasil, será informado o CNPJ com zeros.
+ Informar os zeros não significativos.
+
+
+
+
+ Número do CPF
+ Informar os zeros não significativos.
+
+
+
+
+
+
+ Inscrição Estadual
+
+
+
+
+ Sigla da UF
+ Informar EX para operações com o exterior.
+
+
+
+
+
+ Razão Social ou Nome do expedidor
+
+
+
+
+
+
+
+
+
+
+ Informações de identificação dos documentos de Transporte Anterior
+
+
+
+
+
+ Documentos de transporte anterior em papel
+
+
+
+
+
+ Tipo do Documento de Transporte Anterior
+ Preencher com:
+07-ATRE;
+08-DTA (Despacho de Transito Aduaneiro);
+09-Conhecimento Aéreo Internacional;
+10 – Conhecimento - Carta de Porte Internacional;
+11 – Conhecimento Avulso;
+12-TIF (Transporte Internacional Ferroviário); 13-BL (Bill of Lading)
+
+
+
+
+
+
+
+ Série do Documento Fiscal
+
+
+
+
+
+
+
+
+
+
+ Série do Documento Fiscal
+
+
+
+
+
+
+
+
+
+
+ Número do Documento Fiscal
+
+
+
+
+
+
+
+
+
+
+ Data de emissão (AAAA-MM-DD)
+
+
+
+
+
+
+
+ Documentos de transporte anterior eletrônicos
+
+
+
+
+
+ Chave de acesso do CT-e
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Informações do modal
+
+
+
+
+
+ XML do modal
+Insira neste local o XML específico do modal (rodoviário, aéreo, ferroviário, aquaviário ou dutoviário).
+ O elemento do tipo -any- permite estender o documento XML com elementos não especificados pelo schema.
+ Insira neste local - any- o XML específico do modal (rodoviário, aéreo, ferroviário, aquaviário ou dutoviário). A especificação do schema XML para cada modal pode ser encontrada nos arquivos que acompanham este pacote de liberação:
+ Rodoviário - ver arquivo CTeModalRodoviario_v9.99
+ Aéreo - ver arquivo CTeModalAereo_v9.99
+ Aquaviário - arquivo CTeModalAquaviario_v9.99
+ Ferroviário - arquivo CTeModalFerroviario_v9.99
+ Dutoviário - arquivo CTeModalDutoviario_v9.99
+
+Onde v9.99 é a a designação genérica para a versão do arquivo. Por exemplo, o arquivo para o schema do modal Rodoviário na versão 1.04 será denominado "CTeModalRodoviario_v1.04".
+
+
+
+
+
+ Versão do leiaute específico para o Modal
+
+
+
+
+
+
+
+
+
+
+
+
+ informações dos veículos transportados
+
+
+
+
+
+ Chassi do veículo
+
+
+
+
+
+
+
+
+
+
+
+ Cor do veículo
+ Código de cada montadora
+
+
+
+
+
+
+
+
+
+
+ Descrição da cor
+
+
+
+
+
+
+
+
+
+
+ Código Marca Modelo
+ Utilizar tabela RENAVAM
+
+
+
+
+
+
+
+
+
+
+ Valor Unitário do Veículo
+
+
+
+
+ Frete Unitário
+
+
+
+
+
+
+
+ Dados da cobrança do CT-e
+
+
+
+
+
+ Dados da fatura
+
+
+
+
+
+ Número da fatura
+
+
+
+
+
+
+
+
+
+
+ Valor original da fatura
+
+
+
+
+ Valor do desconto da fatura
+
+
+
+
+ Valor líquido da fatura
+
+
+
+
+
+
+
+ Dados das duplicatas
+
+
+
+
+
+ Número da duplicata
+
+
+
+
+
+
+
+
+
+
+ Data de vencimento da duplicata (AAAA-MM-DD)
+
+
+
+
+ Valor da duplicata
+
+
+
+
+
+
+
+
+
+
+ Informações do CT-e de substituição
+
+
+
+
+
+ Chave de acesso do CT-e a ser substituído (original)
+
+
+
+
+
+
+
+
+
+ Indicador de CT-e Alteração de Tomador
+
+
+
+
+
+
+
+
+
+
+
+
+ Informações do CT-e Globalizado
+
+
+
+
+
+ Preencher com informações adicionais, legislação do regime especial, etc
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Informações do Serviço Vinculado a Multimodal
+
+
+
+
+
+ informações do CT-e multimodal vinculado
+
+
+
+
+
+ Chave de acesso do CT-e Multimodal
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Detalhamento do CT-e complementado
+
+
+
+
+
+ Chave do CT-e complementado
+
+
+
+
+
+
+
+
+ Autorizados para download do XML do DF-e
+ Informar CNPJ ou CPF. Preencher os zeros não significativos.
+
+
+
+
+
+
+ CNPJ do autorizado
+ Informar zeros não significativos
+
+
+
+
+ CPF do autorizado
+ Informar zeros não significativos
+
+
+
+
+
+
+
+
+ Informações do Responsável Técnico pela emissão do DF-e
+
+
+
+
+ Grupo de informações do pedido de emissão da Nota Fiscal Fácil
+
+
+
+
+
+ Solicitação do pedido de emissão da NFF.
+ Será preenchido com a totalidade de campos informados no aplicativo emissor serializado.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Grupo de Informação do Provedor de Assinatura e Autorização
+
+
+
+
+
+ CNPJ do Provedor de Assinatura e Autorização
+
+
+
+
+ Assinatura RSA do Emitente para DFe gerados por PAA
+
+
+
+
+
+ Assinatura digital padrão RSA
+ Converter o atributo Id do DFe para array de bytes e assinar com a chave privada do RSA com algoritmo SHA1 gerando um valor no formato base64.
+
+
+
+
+ Chave Publica no padrão XML RSA Key
+
+
+
+
+
+
+
+
+
+
+
+ Versão do leiaute
+ Ex: "4.00"
+
+
+
+
+
+
+
+ Identificador da tag a ser assinada
+ Informar a chave de acesso do CT-e e precedida do literal "CTe"
+
+
+
+
+
+
+
+
+
+
+
+ Informações suplementares do CT-e
+
+
+
+
+
+ Texto com o QR-Code impresso no DACTE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tipo Conhecimento de Transporte Eletrônico Outros Serviços (Modelo 67)
+
+
+
+
+ Informações do CT-e Outros Serviços
+
+
+
+
+
+ Identificação do CT-e Outros Serviços
+
+
+
+
+
+ Código da UF do emitente do CT-e.
+ Utilizar a Tabela do IBGE.
+
+
+
+
+ Código numérico que compõe a Chave de Acesso.
+ Número aleatório gerado pelo emitente para cada CT-e, com o objetivo de evitar acessos indevidos ao documento.
+
+
+
+
+
+
+
+
+
+
+ Código Fiscal de Operações e Prestações
+
+
+
+
+ Natureza da Operação
+
+
+
+
+
+
+
+
+
+
+ Modelo do documento fiscal
+ Utilizar o código 67 para identificação do CT-e Outros Serviços, emitido em substituição a Nota Fiscal Modelo 7 para transporte de pessoas, valores e excesso de bagagem.
+
+
+
+
+ Série do CT-e OS
+ Preencher com "0" no caso de série única
+
+
+
+
+
+
+
+ Número do CT-e OS
+
+
+
+
+ Data e hora de emissão do CT-e OS
+ Formato AAAA-MM-DDTHH:MM:DD TZD
+
+
+
+
+
+
+
+ Formato de impressão do DACTE OS
+ Preencher com: 1 - Retrato; 2 - Paisagem.
+
+
+
+
+
+
+
+
+
+
+
+ Forma de emissão do CT-e
+ Preencher com:
+1 - Normal;
+ 5 - Contingência FSDA;
+7 - Autorização pela SVC-RS;
+ 8 - Autorização pela SVC-SP
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Digito Verificador da chave de acesso do CT-e
+ Informar o dígito de controle da chave de acesso do CT-e, que deve ser calculado com a aplicação do algoritmo módulo 11 (base 2,9) da chave de acesso.
+
+
+
+
+
+
+
+
+
+
+ Tipo do Ambiente
+ Preencher com:1 - Produção; 2 - Homologação
+
+
+
+
+ Tipo do CT-e OS
+ Preencher com:
+0 - CT-e Normal;
+1 - CT-e Complementar;
+3 - CT-e de Substituição.
+
+
+
+
+ Identificador do processo de emissão do CT-e OS
+ Preencher com:
+ 0 - emissão de CT-e com aplicativo do contribuinte;
+ 3- emissão CT-e pelo contribuinte com aplicativo fornecido pelo Fisco.
+
+
+
+
+ Versão do processo de emissão
+ Iinformar a versão do aplicativo emissor de CT-e.
+
+
+
+
+
+
+
+
+
+
+ Código do Município de envio do CT-e (de onde o documento foi transmitido)
+ Utilizar a tabela do IBGE. Informar 9999999 para as operações com o exterior.
+
+
+
+
+ Nome do Município de envio do CT-e (de onde o documento foi transmitido)
+ Informar PAIS/Municipio para as operações com o exterior.
+
+
+
+
+
+
+
+
+
+
+ Sigla da UF de envio do CT-e (de onde o documento foi transmitido)
+ Informar 'EX' para operações com o exterior.
+
+
+
+
+ Modal do CT-e OS
+ Preencher com:
+01-Rodoviário;
+02- Aéreo;
+03 - Aquaviário;
+04 - Ferroviário.
+
+
+
+
+ Tipo do Serviço
+ Preencher com:
+
+6 - Transporte de Pessoas;
+7 - Transporte de Valores;
+8 - Excesso de Bagagem.
+
+
+
+
+
+
+
+
+
+
+
+
+ Indicador da IE do tomador:
+1 – Contribuinte ICMS;
+2 – Contribuinte isento de inscrição;
+9 – Não Contribuinte
+ Aplica-se ao tomador que for indicado no toma3 ou toma4
+
+
+
+
+
+
+
+
+
+
+
+
+ Código do Município de início da prestação
+ Utilizar a tabela do IBGE. Informar 9999999 para operações com o exterior.
+
+
+
+
+ Nome do Município do início da prestação
+ Informar 'EXTERIOR' para operações com o exterior.
+
+
+
+
+
+
+
+
+
+
+ UF do início da prestação
+ Informar 'EX' para operações com o exterior.
+
+
+
+
+ Código do Município de término da prestação
+ Utilizar a tabela do IBGE. Informar 9999999 para operações com o exterior.
+
+
+
+
+ Nome do Município do término da prestação
+ Informar 'EXTERIOR' para operações com o exterior.
+
+
+
+
+
+
+
+
+
+
+ UF do término da prestação
+ Informar 'EX' para operações com o exterior.
+
+
+
+
+ Informações do Percurso do CT-e Outros Serviços
+
+
+
+
+
+ Sigla das Unidades da Federação do percurso do veículo.
+ Não é necessário repetir as UF de Início e Fim
+
+
+
+
+
+
+
+ Informar apenas
+para tpEmis diferente de 1
+
+
+
+ Data e Hora da entrada em contingência
+ Informar a data e hora no formato AAAA-MM-DDTHH:MM:SS
+
+
+
+
+ Justificativa da entrada em contingência
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Dados complementares do CT-e para fins operacionais ou comerciais
+
+
+
+
+
+ Característica adicional do transporte
+ Texto livre:
+REENTREGA; DEVOLUÇÃO; REFATURAMENTO; etc
+
+
+
+
+
+
+
+
+
+
+ Característica adicional do serviço
+ Texto livre:
+ ENTREGA EXPRESSA; LOGÍSTICA REVERSA; CONVENCIONAL; EMERGENCIAL; etc
+
+
+
+
+
+
+
+
+
+
+ Funcionário emissor do CTe
+
+
+
+
+
+
+
+
+
+
+ Observações Gerais
+
+
+
+
+
+
+
+
+
+
+ Campo de uso livre do contribuinte
+ Informar o nome do campo no atributo xCampo e o conteúdo do campo no XTexto
+
+
+
+
+
+ Conteúdo do campo
+
+
+
+
+
+
+
+
+
+
+
+ Identificação do campo
+
+
+
+
+
+
+
+
+
+
+
+
+ Campo de uso livre do contribuinte
+ Informar o nome do campo no atributo xCampo e o conteúdo do campo no XTexto
+
+
+
+
+
+ Conteúdo do campo
+
+
+
+
+
+
+
+
+
+
+
+ Identificação do campo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Identificação do Emitente do CT-e OS
+
+
+
+
+
+ CNPJ do emitente
+ Informar zeros não significativos
+
+
+
+
+ Inscrição Estadual do Emitente
+
+
+
+
+
+
+
+ Inscrição Estadual do Substituto Tributário
+
+
+
+
+
+
+
+ Razão social ou Nome do emitente
+
+
+
+
+
+
+
+
+
+
+ Nome fantasia
+
+
+
+
+
+
+
+
+
+
+ Endereço do emitente
+
+
+
+
+ Código do Regime Tributário
+ Informar: 1=Simples Nacional;
+2=Simples Nacional, excesso sublimite de receita bruta;
+3=Regime Normal;
+4=Simples Nacional - Microempreendedor Individual – MEI.
+
+
+
+
+
+
+
+
+ Informações do Tomador/Usuário do Serviço
+ Opcional para Excesso de Bagagem
+
+
+
+
+
+
+ Número do CNPJ
+ Em caso de empresa não estabelecida no Brasil, será informado o CNPJ com zeros.
+ Informar os zeros não significativos.
+
+
+
+
+ Número do CPF
+ Informar os zeros não significativos.
+
+
+
+
+
+ Inscrição Estadual
+ Informar a IE do tomador ou ISENTO se tomador é contribuinte do ICMS isento de inscrição no cadastro de contribuintes do ICMS. Caso o tomador não seja contribuinte do ICMS não informar o conteúdo.
+
+
+
+
+
+
+
+ Razão social ou nome do tomador
+
+
+
+
+
+
+
+
+
+
+ Nome fantasia
+
+
+
+
+
+
+
+
+
+
+ Telefone
+
+
+
+
+ Dados do endereço
+
+
+
+
+ Endereço de email
+
+
+
+
+
+
+
+
+
+
+ Valores da Prestação de Serviço
+
+
+
+
+
+ Valor Total da Prestação do Serviço
+ Pode conter zeros quando o CT-e for de complemento de ICMS
+
+
+
+
+ Valor a Receber
+
+
+
+
+ Componentes do Valor da Prestação
+
+
+
+
+
+ Nome do componente
+ Exxemplos: FRETE PESO, FRETE VALOR, SEC/CAT, ADEME, AGENDAMENTO, etc
+
+
+
+
+
+
+
+
+
+
+ Valor do componente
+
+
+
+
+
+
+
+
+
+
+ Informações relativas aos Impostos
+
+
+
+
+
+ Informações relativas ao ICMS
+
+
+
+
+
+ Valor Total dos Tributos
+
+
+
+
+ Informações adicionais de interesse do Fisco
+ Norma referenciada, informações complementares, etc
+
+
+
+
+
+
+
+
+
+
+ Informações do ICMS de partilha com a UF de término do serviço de transporte na operação interestadual
+ Grupo a ser informado nas prestações interestaduais para consumidor final, não contribuinte do ICMS
+
+
+
+
+
+ Valor da BC do ICMS na UF de término da prestação do serviço de transporte
+
+
+
+
+ Percentual do ICMS relativo ao Fundo de Combate à pobreza (FCP) na UF de término da prestação do serviço de transporte
+ Alíquota adotada nas operações internas na UF do destinatário
+
+
+
+
+ Alíquota interna da UF de término da prestação do serviço de transporte
+ Alíquota adotada nas operações internas na UF do destinatário
+
+
+
+
+ Alíquota interestadual das UF envolvidas
+ Alíquota interestadual das UF envolvidas
+
+
+
+
+
+ Valor do ICMS relativo ao Fundo de Combate á Pobreza (FCP) da UF de término da prestação
+
+
+
+
+ Valor do ICMS de partilha para a UF de término da prestação do serviço de transporte
+
+
+
+
+ Valor do ICMS de partilha para a UF de início da prestação do serviço de transporte
+
+
+
+
+
+
+
+ Informações dos tributos federais
+ Grupo a ser informado nas prestações interestaduais para consumidor final, não contribuinte do ICMS
+
+
+
+
+
+ Valor do PIS
+
+
+
+
+ Valor COFINS
+
+
+
+
+ Valor de Imposto de Renda
+
+
+
+
+ Valor do INSS
+
+
+
+
+ Valor do CSLL
+
+
+
+
+
+
+
+
+
+
+
+ Grupo de informações do CT-e OS Normal
+
+
+
+
+
+ Informações da Prestação do Serviço
+
+
+
+
+
+ Descrição do Serviço prestado
+
+
+
+
+
+
+
+
+
+
+ Informações de quantidades da Carga do CT-e
+ Para Transporte de Pessoas indicar número de passageiros, para excesso de bagagem e transporte de valores indicar número de Volumes/Malotes
+
+
+
+
+
+ Quantidade
+
+
+
+
+
+
+
+
+
+
+ Informações dos documentos referenciados
+
+
+
+
+
+
+ Número
+
+
+
+
+
+
+
+
+
+
+ Série
+
+
+
+
+
+
+
+
+
+
+ Subsérie
+
+
+
+
+
+
+
+
+
+
+ Data de Emissão
+ Formato AAAA-MM-DD
+
+
+
+
+ Valor Transportado
+
+
+
+
+
+ Chave de acesso do BP-e que possui eventos excesso de bagagem
+
+
+
+
+
+
+
+
+
+
+ Informações de Seguro da Carga
+
+
+
+
+
+ Responsável pelo seguro
+ Preencher com:
+
+4 - Emitente do CT-e;
+
+5 - Tomador de Serviço.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Nome da Seguradora
+
+
+
+
+
+
+
+
+
+
+ Número da Apólice
+ Obrigatório pela lei 11.442/07 (RCTRC)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Informações do modal
+Obrigatório para Pessoas e Bagagem
+
+
+
+
+
+ XML do modal
+Insira neste local o XML específico do modal
+ O elemento do tipo -any- permite estender o documento XML com elementos não especificados pelo schema.
+ Insira neste local - any- o XML específico do modal (rodoviário). A especificação do schema XML para cada modal pode ser encontrada nos arquivos que acompanham este pacote de liberação:
+ Rodoviário - ver arquivo CTeModalRodoviarioOS_v9.99
+
+Onde v9.99 é a a designação genérica para a versão do arquivo. Por exemplo, o arquivo para o schema do modal Rodoviário na versão 4.00 será denominado "CTeModalRodoviarioOS_v4.00".
+
+
+
+
+
+ Versão do leiaute específico para o Modal
+
+
+
+
+
+
+
+
+
+
+
+
+ Informações do CT-e de substituição
+
+
+
+
+
+ Chave de acesso do CT-e a ser substituído (original)
+
+
+
+
+
+
+
+
+
+
+
+
+ Chave de acesso do CT-e Cancelado
+Somente para Transporte de Valores
+
+
+
+
+
+
+
+ Dados da cobrança do CT-e
+
+
+
+
+
+ Dados da fatura
+
+
+
+
+
+ Número da fatura
+
+
+
+
+
+
+
+
+
+
+ Valor original da fatura
+
+
+
+
+ Valor do desconto da fatura
+
+
+
+
+ Valor líquido da fatura
+
+
+
+
+
+
+
+ Dados das duplicatas
+
+
+
+
+
+ Número da duplicata
+
+
+
+
+
+
+
+
+
+
+ Data de vencimento da duplicata (AAAA-MM-DD)
+
+
+
+
+ Valor da duplicata
+
+
+
+
+
+
+
+
+
+
+ Informações das GTV-e relacionadas ao CT-e OS
+
+
+
+
+
+ Chave de acesso da GTV-e
+
+
+
+
+
+
+
+
+
+ Componentes do Valor da GTVe
+
+
+
+
+
+ Tipo do Componente
+ 1-Custodia
+2-Embarque
+3-Tempo de espera
+4-Malote
+5-Ad Valorem
+6-Outros
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Valor do componente
+
+
+
+
+ Nome do componente (informar apenas para outros)
+ Exemplos: FRETE PESO, FRETE VALOR, SEC/CAT, ADEME, AGENDAMENTO, etc
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Detalhamento do CT-e complementado
+
+
+
+
+
+ Chave do CT-e complementado
+
+
+
+
+
+
+
+
+ Autorizados para download do XML do DF-e
+ Informar CNPJ ou CPF. Preencher os zeros não significativos.
+
+
+
+
+
+
+ CNPJ do autorizado
+ Informar zeros não significativos
+
+
+
+
+ CPF do autorizado
+ Informar zeros não significativos
+
+
+
+
+
+
+
+
+ Informações do Responsável Técnico pela emissão do DF-e
+
+
+
+
+
+ Versão do leiaute
+ Ex: "4.00"
+
+
+
+
+
+
+
+ Identificador da tag a ser assinada
+ Informar a chave de acesso do CT-e OS e precedida do literal "CTe"
+
+
+
+
+
+
+
+
+
+
+
+ Informações suplementares do CT-e
+
+
+
+
+
+ Texto com o QR-Code impresso no DACTE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Versão do leiaute
+
+
+
+
+
+
+
+
+ Tipo Dados do Endereço
+
+
+
+
+ Logradouro
+
+
+
+
+
+
+
+
+
+
+ Número
+
+
+
+
+
+
+
+
+
+
+ Complemento
+
+
+
+
+
+
+
+
+
+
+ Bairro
+
+
+
+
+
+
+
+
+
+
+ Código do município (utilizar a tabela do IBGE)
+
+
+
+
+ Nome do município
+
+
+
+
+
+
+
+
+
+
+ CEP
+ Informar zeros não significativos
+
+
+
+
+
+
+
+
+
+
+ Sigla da UF
+
+
+
+
+ Telefone
+
+
+
+
+
+
+ Tipo Dados do Endereço
+
+
+
+
+ Logradouro
+
+
+
+
+
+
+
+
+
+
+ Número
+
+
+
+
+
+
+
+
+
+
+ Complemento
+
+
+
+
+
+
+
+
+
+
+ Bairro
+
+
+
+
+
+
+
+
+
+
+ Código do município (utilizar a tabela do IBGE)
+ Informar 9999999 para operações com o exterior.
+
+
+
+
+ Nome do município
+ Informar EXTERIOR para operações com o exterior.
+
+
+
+
+
+
+
+
+
+
+ CEP
+ Informar os zeros não significativos
+
+
+
+
+
+
+
+
+
+
+ Sigla da UF
+ Informar EX para operações com o exterior.
+
+
+
+
+ Código do país
+ Utilizar a tabela do BACEN
+
+
+
+
+
+
+
+
+
+
+ Nome do país
+
+
+
+
+
+
+
+
+
+
+
+
+ Tipo Dados do Endereço
+
+
+
+
+ Logradouro
+
+
+
+
+
+
+
+
+
+
+ Número
+
+
+
+
+
+
+
+
+
+
+ Complemento
+
+
+
+
+
+
+
+
+
+
+ Bairro
+
+
+
+
+
+
+
+
+
+
+ Código do município (utilizar a tabela do IBGE), informar 9999999 para operações com o exterior.
+
+
+
+
+ Nome do município, , informar EXTERIOR para operações com o exterior.
+
+
+
+
+
+
+
+
+
+
+ CEP
+
+
+
+
+
+
+
+
+
+
+ Sigla da UF
+ Informar EX para operações com o exterior.
+
+
+
+
+
+
+ Tipo Dados do Endereço
+
+
+
+
+ Logradouro
+
+
+
+
+
+
+
+
+
+
+ Número
+
+
+
+
+
+
+
+
+
+
+ Complemento
+
+
+
+
+
+
+
+
+
+
+ Bairro
+
+
+
+
+
+
+
+
+
+
+ Código do município (utilizar a tabela do IBGE), informar 9999999 para operações com o exterior.
+
+
+
+
+ Nome do município
+ Informar EXTERIOR para operações com o exterior.
+
+
+
+
+
+
+
+
+
+
+ CEP
+
+
+
+
+
+
+
+
+
+
+ Sigla da UF
+ Informar EX para operações com o exterior.
+
+
+
+
+ Código do país
+
+
+
+
+
+
+
+
+
+
+ Nome do país
+
+
+
+
+
+
+
+
+
+
+ Telefone
+
+
+
+
+
+
+ Tipo Dados do Local de Origem ou Destino
+
+
+
+
+ Código do município (utilizar a tabela do IBGE)
+
+
+
+
+ Nome do município
+
+
+
+
+
+
+
+
+
+
+ Sigla da UF
+
+
+
+
+
+
+ Tipo Dados do Local de Retirada ou Entrega
+
+
+
+
+
+ Número do CNPJ
+
+
+
+
+ Número do CPF
+
+
+
+
+
+ Razão Social ou Nome
+
+
+
+
+
+
+
+
+
+
+ Logradouro
+
+
+
+
+
+
+
+
+
+
+ Número
+
+
+
+
+
+
+
+
+
+
+ Complemento
+
+
+
+
+
+
+
+
+
+
+ Bairro
+
+
+
+
+
+
+
+
+
+
+ Código do município (utilizar a tabela do IBGE)
+ Informar 9999999 para operações com o exterior.
+
+
+
+
+ Nome do município
+ Informar EXTERIOR para operações com o exterior.
+
+
+
+
+
+
+
+
+
+
+ Sigla da UF
+ Informar EX para operações com o exterior.
+
+
+
+
+
+
+ Tipo Dados do Imposto CT-e
+
+
+
+
+ Prestação sujeito à tributação normal do ICMS
+
+
+
+
+
+ classificação Tributária do Serviço
+ 00 - tributação normal ICMS
+
+
+
+
+
+
+
+
+
+
+ Valor da BC do ICMS
+
+
+
+
+ Alíquota do ICMS
+
+
+
+
+ Valor do ICMS
+
+
+
+
+
+
+
+ Prestação sujeito à tributação com redução de BC do ICMS
+
+
+
+
+
+ Classificação Tributária do serviço
+ 20 - tributação com BC reduzida do ICMS
+
+
+
+
+
+
+
+
+
+
+ Percentual de redução da BC
+
+
+
+
+ Valor da BC do ICMS
+
+
+
+
+ Alíquota do ICMS
+
+
+
+
+ Valor do ICMS
+
+
+
+
+ Sequencia XML
+
+
+
+ Valor do ICMS de desoneração
+
+
+
+
+ Código de Benefício Fiscal na UF
+ Código de Benefício Fiscal utilizado pela UF
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ICMS Isento, não Tributado ou diferido
+
+
+
+
+
+ Classificação Tributária do Serviço
+ Preencher com:
+ 40 - ICMS isenção;
+ 41 - ICMS não tributada;
+ 51 - ICMS diferido
+
+
+
+
+
+
+
+
+
+
+
+
+ Sequencia XML
+
+
+
+ Valor do ICMS de desoneração
+
+
+
+
+ Código de Benefício Fiscal na UF
+ Código de Benefício Fiscal utilizado pela UF
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tributação pelo ICMS60 - ICMS cobrado por substituição tributária.Responsabilidade do recolhimento do ICMS atribuído ao tomador ou 3º por ST
+
+
+
+
+
+ Classificação Tributária do Serviço
+ 60 - ICMS cobrado por substituição tributária
+
+
+
+
+
+
+
+
+
+
+ Valor da BC do ICMS ST retido
+ Valor do frete sobre o qual será calculado o ICMS a ser substituído na Prestação.
+
+
+
+
+ Valor do ICMS ST retido
+ Resultado da multiplicação do “vBCSTRet” x “pICMSSTRet” – que será valor do ICMS a ser retido pelo Substituto. Podendo o valor do ICMS a ser retido efetivamente, sofrer ajustes conforme a opção tributaria do transportador substituído.
+
+
+
+
+ Alíquota do ICMS
+ Percentual de Alíquota incidente na prestação de serviço de transporte.
+
+
+
+
+ Valor do Crédito outorgado/Presumido
+ Preencher somente quando o transportador substituído, for optante pelo crédito outorgado previsto no Convênio 106/96 e corresponde ao percentual de 20% do valor do ICMS ST retido.
+
+
+
+
+ Sequencia XML
+
+
+
+ Valor do ICMS de desoneração
+
+
+
+
+ Código de Benefício Fiscal na UF
+ Código de Benefício Fiscal utilizado pela UF
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ICMS Outros
+
+
+
+
+
+ Classificação Tributária do Serviço
+ 90 - ICMS outros
+
+
+
+
+
+
+
+
+
+
+ Percentual de redução da BC
+
+
+
+
+ Valor da BC do ICMS
+
+
+
+
+ Alíquota do ICMS
+
+
+
+
+ Valor do ICMS
+
+
+
+
+ Valor do Crédito Outorgado/Presumido
+
+
+
+
+ Sequencia XML
+
+
+
+ Valor do ICMS de desoneração
+
+
+
+
+ Código de Benefício Fiscal na UF
+ Código de Benefício Fiscal utilizado pela UF
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ICMS devido à UF de origem da prestação, quando diferente da UF do emitente
+
+
+
+
+
+ Classificação Tributária do Serviço
+ 90 - ICMS Outra UF
+
+
+
+
+
+
+
+
+
+
+ Percentual de redução da BC
+
+
+
+
+ Valor da BC do ICMS
+
+
+
+
+ Alíquota do ICMS
+
+
+
+
+ Valor do ICMS devido outra UF
+
+
+
+
+ Sequencia XML
+
+
+
+ Valor do ICMS de desoneração
+
+
+
+
+ Código de Benefício Fiscal na UF
+ Código de Benefício Fiscal utilizado pela UF
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Simples Nacional
+
+
+
+
+
+ Classificação Tributária do Serviço
+ 90 - ICMS Simples Nacional
+
+
+
+
+
+
+
+
+
+
+ Indica se o contribuinte é Simples Nacional 1=Sim
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tipo Dados do Imposto para CT-e OS
+
+
+
+
+ Prestação sujeito à tributação normal do ICMS
+
+
+
+
+
+ classificação Tributária do Serviço
+ 00 - tributação normal ICMS
+
+
+
+
+
+
+
+
+
+
+ Valor da BC do ICMS
+
+
+
+
+ Alíquota do ICMS
+
+
+
+
+ Valor do ICMS
+
+
+
+
+
+
+
+ Prestação sujeito à tributação com redução de BC do ICMS
+
+
+
+
+
+ Classificação Tributária do serviço
+ 20 - tributação com BC reduzida do ICMS
+
+
+
+
+
+
+
+
+
+
+ Percentual de redução da BC
+
+
+
+
+ Valor da BC do ICMS
+
+
+
+
+ Alíquota do ICMS
+
+
+
+
+ Valor do ICMS
+
+
+
+
+ Sequencia XML
+
+
+
+ Valor do ICMS de desoneração
+
+
+
+
+ Código de Benefício Fiscal na UF
+ Código de Benefício Fiscal utilizado pela UF
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ICMS Isento, não Tributado ou diferido
+
+
+
+
+
+ Classificação Tributária do Serviço
+ Preencher com:
+ 40 - ICMS isenção;
+ 41 - ICMS não tributada;
+ 51 - ICMS diferido
+
+
+
+
+
+
+
+
+
+
+
+
+ Sequencia XML
+
+
+
+ Valor do ICMS de desoneração
+
+
+
+
+ Código de Benefício Fiscal na UF
+ Código de Benefício Fiscal utilizado pela UF
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ICMS Outros
+
+
+
+
+
+ Classificação Tributária do Serviço
+ 90 - Outros
+
+
+
+
+
+
+
+
+
+
+ Percentual de redução da BC
+
+
+
+
+ Valor da BC do ICMS
+
+
+
+
+ Alíquota do ICMS
+
+
+
+
+ Valor do ICMS
+
+
+
+
+ Valor do Crédito Outorgado/Presumido
+
+
+
+
+ Sequencia XML
+
+
+
+ Valor do ICMS de desoneração
+
+
+
+
+ Código de Benefício Fiscal na UF
+ Código de Benefício Fiscal utilizado pela UF
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ICMS devido à UF de origem da prestação, quando diferente da UF do emitente
+
+
+
+
+
+ Classificação Tributária do Serviço
+ 90 - ICMS Outra UF
+
+
+
+
+
+
+
+
+
+
+ Percentual de redução da BC
+
+
+
+
+ Valor da BC do ICMS
+
+
+
+
+ Alíquota do ICMS
+
+
+
+
+ Valor do ICMS devido outra UF
+
+
+
+
+ Sequencia XML
+
+
+
+ Valor do ICMS de desoneração
+
+
+
+
+ Código de Benefício Fiscal na UF
+ Código de Benefício Fiscal utilizado pela UF
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Simples Nacional
+
+
+
+
+
+ Classificação Tributária do Serviço
+ 90 - ICMS Simples Nacional
+
+
+
+
+
+
+
+
+
+
+ Indica se o contribuinte é Simples Nacional 1=Sim
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tipo Dados Unidade de Transporte
+
+
+
+
+ Tipo da Unidade de Transporte
+ 1 - Rodoviário Tração
+2 - Rodoviário Reboque
+3 - Navio
+4 - Balsa
+5 - Aeronave
+6 - Vagão
+7 - Outros
+
+
+
+
+ Identificação da Unidade de Transporte
+ Informar a identificação conforme o tipo de unidade de transporte.
+Por exemplo: para rodoviário tração ou reboque deverá preencher com a placa do veículo.
+
+
+
+
+
+ Lacres das Unidades de Transporte
+
+
+
+
+
+ Número do lacre
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Informações das Unidades de Carga (Containeres/ULD/Outros)
+ Dispositivo de carga utilizada (Unit Load Device - ULD) significa todo tipo de contêiner de carga, vagão, contêiner de avião, palete de aeronave com rede ou palete de aeronave com rede sobre um iglu.
+
+
+
+
+ Quantidade rateada (Peso,Volume)
+
+
+
+
+
+
+ Tipo Dados Unidade de Carga
+
+
+
+
+ Tipo da Unidade de Carga
+ 1 - Container
+2 - ULD
+3 - Pallet
+4 - Outros
+
+
+
+
+ Identificação da Unidade de Carga
+ Informar a identificação da unidade de carga, por exemplo: número do container.
+
+
+
+
+ Lacres das Unidades de Carga
+
+
+
+
+
+ Número do lacre
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Quantidade rateada (Peso,Volume)
+
+
+
+
+
+
+ Tipo Dados da Responsável Técnico
+
+
+
+
+ CNPJ da pessoa jurídica responsável técnica pelo sistema utilizado na emissão do documento fiscal eletrônico
+ Informar o CNPJ da pessoa jurídica desenvolvedora do sistema utilizado na emissão do documento fiscal eletrônico.
+
+
+
+
+ Nome da pessoa a ser contatada
+ Informar o nome da pessoa a ser contatada na empresa desenvolvedora do sistema utilizado na emissão do documento fiscal eletrônico. No caso de pessoa física, informar o respectivo nome.
+
+
+
+
+
+
+
+
+
+
+ Email da pessoa jurídica a ser contatada
+
+
+
+
+ Telefone da pessoa jurídica a ser contatada
+ Preencher com o Código DDD + número do telefone.
+
+
+
+
+
+
+
+
+
+
+
+ Identificador do código de segurança do responsável técnico
+ Identificador do CSRT utilizado para geração do hash
+
+
+
+
+
+
+
+
+
+ Hash do token do código de segurança do responsável técnico
+ O hashCSRT é o resultado das funções SHA-1 e base64 do token CSRT fornecido pelo fisco + chave de acesso do DF-e. (Implementação em futura NT)
+
+Observação: 28 caracteres são representados no schema como 20 bytes do tipo base64Binary
+
+
+
+
+
+
+
+
+
+
+
+
+ Tipo CFOP
+
+
+
+
+
+
+
+
+ Tipo Código da Lista de Serviços LC 116/2003
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tipo Número do Container
+
+
+
+
+
+
+
+
+
+
+ Tipo Documento Associado
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tipo Email
+
+
+
+
+
+
+
+
+
+
+ Tipo Finalidade da CT-e
+
+
+
+
+
+
+
+
+
+
+ Tipos Finalidade de CT-e Simplificado
+
+
+
+
+
+
+
+
+
+ Tipo Identificador de controle do envio do lote. Número seqüencial auto-incremental, de controle correspondente ao identificador único do lote enviado. A responsabilidade de gerar e controlar esse número é do próprio contribuinte.
+
+
+
+
+
+
+
+
+ Tipo Modelo do Documento
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tipo Modal transporte Outros Serviços
+
+
+
+
+
+
+
+
+
+
+
+ Tipo Modal transporte
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tipo Modal transporte do CTe Simplificado
+
+
+
+
+
+
+
+
+
+
+ Tipo RNTRC - Registro Nacional Transportadores Rodoviários de Carga
+
+
+
+
+
+
+
+
+ Tipo CIOT - Código Identificador da Operação de Transporte
+
+
+
+
+
+
+
+
+ Tipo Código Regime Tributário
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tipo processo de emissão do CT-e
+
+
+
+
+
+
+
+
+
+ Tipo hora
+
+
+
+
+
+
+
+
+ Tipo Versão do CT-e - 4.00
+
+
+
+
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/cte_v4.00.xsd b/pynfe/data/XSDs/CT-e/cte_v4.00.xsd
new file mode 100644
index 00000000..b0cb9c1a
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/cte_v4.00.xsd
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+ Conhecimento de Transporte Eletrônico
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/evCCeCTe_v4.00.xsd b/pynfe/data/XSDs/CT-e/evCCeCTe_v4.00.xsd
new file mode 100644
index 00000000..92e78690
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/evCCeCTe_v4.00.xsd
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+ Schema XML de validação do evento carta de correção
+110110
+
+
+
+
+
+ Descrição do Evento - “Carta de Correção”
+
+
+
+
+
+
+
+
+
+
+
+ Grupo de Informações de Correção
+
+
+
+
+
+ Indicar o grupo de informações que pertence o campoAlterado. Ex: ide
+
+
+
+
+
+
+
+
+
+
+
+ Nome do campo modificado do CT-e Original.
+
+
+
+
+
+
+
+
+
+
+
+ Valor correspondente à alteração.
+
+
+
+
+
+
+
+
+
+
+
+ Preencher com o indice do item alterado caso a alteração ocorra em uma lista.
+OBS: O indice inicia sempre em 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Condições de uso da Carta de Correção,
+ informar a literal :Condições de uso da Carta de Correção, informar a literal:
+“A Carta de Correção é disciplinada pelo Art. 58-B do CONVÊNIO/SINIEF 06/89: Fica permitida a utilização de carta de correção, para regularização de erro ocorrido na emissão de documentos fiscais relativos à prestação de serviço de transporte, desde que o erro não esteja relacionado com: I - as variáveis que determinam o valor do imposto tais como: base de cálculo, alíquota, diferença de preço, quantidade, valor da prestação;II - a correção de dados cadastrais que implique mudança do emitente, tomador, remetente ou do destinatário;III - a data de emissão ou de saída.” (texto com acentuação) ou “A Carta de Correcao e disciplinada pelo Art. 58-B do CONVENIO/SINIEF 06/89: Fica permitida a utilizacao de carta de correcao, para regularizacao de erro ocorrido na emissao de documentos fiscais relativos a prestacao de servico de transporte, desde que o erro nao esteja relacionado com: I - as variaveis que determinam o valor do imposto tais como: base de calculo, aliquota, diferenca de preco, quantidade, valor da prestacao;II - a correcao de dados cadastrais que implique mudança do emitente, tomador, remetente ou do destinatario;III - a data de emissao ou de saida.” (texto sem acentuação)
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/evCECTe_v4.00.xsd b/pynfe/data/XSDs/CT-e/evCECTe_v4.00.xsd
new file mode 100644
index 00000000..17f9c36c
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/evCECTe_v4.00.xsd
@@ -0,0 +1,108 @@
+
+
+
+
+
+
+ Schema XML de validação do evento comprovante de entrega eletrônico do CT-e
+110180
+
+
+
+
+
+ Descrição do Evento - “Comprovante de Entrega do CT-e”
+
+
+
+
+
+
+
+
+
+
+ Número do Protocolo de autorização do CT-e
+
+
+
+
+ Data e hora de conclusão da entrega da NF-e
+ Formato AAAA-MM-DDTHH:MM:DD TZD
+
+
+
+
+
+
+
+ Número do Documento de identificação da pessoa que recebeu a entrega
+
+
+
+
+
+
+
+
+
+
+ Nome da pessoa que recebeu a entrega
+
+
+
+
+
+
+
+
+
+
+ Latitude do ponto de entrega
+
+
+
+
+ Longitude do ponto de entrega
+
+
+
+
+ Hash (SHA1) no formato Base64 resultante da concatenação: Chave de acesso do CT-e + Base64 da imagem capturada da entrega (Exemplo: imagem capturada da assinatura eletrônica, digital do recebedor, foto, etc)
+ O hashCSRT é o resultado das funções SHA-1 e base64 do token CSRT fornecido pelo fisco + chave de acesso do DF-e. (Implementação em futura NT)
+Observação: 28 caracteres são representados no schema como 20 bytes do tipo base64Binary
+
+
+
+
+
+
+
+
+
+ Data e hora de geração do hash entrega
+ Formato AAAA-MM-DDTHH:MM:DD TZD
+
+
+
+
+
+
+
+ Grupo de informações das NF-e que foram entregues ao Destinatário
+ Informar o grupo apenas para CT-e com tipo de serviço Normal
+
+
+
+
+
+ Chave de acesso da NF-e entregue
+
+
+
+
+
+
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/evCancCECTe_v4.00.xsd b/pynfe/data/XSDs/CT-e/evCancCECTe_v4.00.xsd
new file mode 100644
index 00000000..0a9f3ef5
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/evCancCECTe_v4.00.xsd
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+ Schema XML de validação do evento cancelamento do comprovante de entrega eletrônico do CT-e
+110181
+
+
+
+
+
+ Descrição do Evento - “Cancelamento do Comprovante de Entrega do CT-e”
+
+
+
+
+
+
+
+
+
+
+ Número do Protocolo de autorização do CT-e
+
+
+
+
+ Número do Protocolo de autorização do evento a ser cancelado
+
+
+
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/evCancCTe_v4.00.xsd b/pynfe/data/XSDs/CT-e/evCancCTe_v4.00.xsd
new file mode 100644
index 00000000..af1f280b
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/evCancCTe_v4.00.xsd
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+ Schema XML de validação do evento do cancelamento
+110111
+
+
+
+
+
+ Descrição do Evento - “Cancelamento”
+
+
+
+
+
+
+
+
+
+
+ Número do Protocolo de Status do CT-e
+
+
+
+
+ Justificativa do Cancelamento
+
+
+
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/evCancIECTe_v4.00.xsd b/pynfe/data/XSDs/CT-e/evCancIECTe_v4.00.xsd
new file mode 100644
index 00000000..20ce3b5f
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/evCancIECTe_v4.00.xsd
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+ Schema XML de validação do evento cancelamento do insucesso de entrega eletrônico do CT-e
+110191
+
+
+
+
+
+ Descrição do Evento - “Cancelamento do Insucesso de Entrega do CT-e”
+
+
+
+
+
+
+
+
+
+
+ Número do Protocolo de autorização do CT-e
+
+
+
+
+ Número do Protocolo de autorização do evento a ser cancelado
+
+
+
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/evCancPrestDesacordo_v4.00.xsd b/pynfe/data/XSDs/CT-e/evCancPrestDesacordo_v4.00.xsd
new file mode 100644
index 00000000..a3404d25
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/evCancPrestDesacordo_v4.00.xsd
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+ Schema XML de validação do evento Cancelamento Prestação do Serviço em Desacordo 610111
+
+
+
+
+
+ Descrição do Evento - “Cancelamento Prestação do Serviço em Desacordo”
+
+
+
+
+
+
+
+
+
+
+
+ Protocolo do evento que será cancelado
+ Informar o número do protocolo de autorização do evento de prestação de serviço em desacordo que será cancelado
+
+
+
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/evEPECCTe_v4.00.xsd b/pynfe/data/XSDs/CT-e/evEPECCTe_v4.00.xsd
new file mode 100644
index 00000000..be7452cd
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/evEPECCTe_v4.00.xsd
@@ -0,0 +1,161 @@
+
+
+
+
+
+
+ Schema XML de validação do evento de emissão prévia de emissão em contingência
+110113
+
+
+
+
+
+ Descrição do Evento - “EPEC”
+
+
+
+
+
+
+
+
+
+
+ Justificativa da Entrada em Contingencia
+
+
+
+
+ Valor do ICMS
+
+
+
+
+ Valor do ICMS ST
+
+
+
+
+ Valor Total da Prestação do Serviço
+ Pode conter zeros quando o CT-e for de complemento de ICMS
+
+
+
+
+ Valor total da carga
+ Dever ser informado para todos os modais, com exceção para o Dutoviário.
+
+
+
+
+ Indicador do "papel" do tomador do serviço no CT-e
+
+
+
+
+
+ Tomador do Serviço
+ Preencher com:
+0-Remetente;
+1-Expedidor;2-Recebedor;3-Destinatário
+;4 - Outros
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ UF do tomador do serviço
+ Informar 'EX' para operações com o exterior.
+
+
+
+
+
+ Número do CNPJ
+ Em caso de empresa não estabelecida no Brasil, será informado o CNPJ com zeros.
+Informar os zeros não significativos.
+
+
+
+
+ Número do CPF
+ Informar os zeros não significativos.
+
+
+
+
+
+ Inscrição Estadual
+ Informar a IE do tomador ou ISENTO se tomador é contribuinte do ICMS isento de inscrição no cadastro de contribuintes do ICMS. Caso o tomador não seja contribuinte do ICMS não informar o conteúdo.
+
+
+
+
+
+
+
+ Modal
+ Preencher com:
+
+01-Rodoviário;
+
+02-Aéreo;
+03-Aquaviário;
+
+04-Ferroviário;
+
+05-Dutoviário;
+06-Multimodal;
+
+
+
+
+ UF do início da prestação
+ Informar 'EX' para operações com o exterior.
+
+
+
+
+ UF do término da prestação
+ Informar 'EX' para operações com o exterior.
+
+
+
+
+ Tipo do CT-e - Aceitar apenas Tipo Normal = 0
+ Preencher com:
+ 0 - CT-e Normal;
+ 1 - CT-e de Complemento de Valores; 2 - CT-e de Anulação;
+ 3 - CT-e Substituto
+
+
+
+
+
+
+
+
+
+
+
+ Data e hora de emissão do CT-e
+ Formato AAAA-MM-DDTHH:MM:DD TZD
+
+
+
+
+
+
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/evGTV_v4.00.xsd b/pynfe/data/XSDs/CT-e/evGTV_v4.00.xsd
new file mode 100644
index 00000000..9b9cd01a
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/evGTV_v4.00.xsd
@@ -0,0 +1,255 @@
+
+
+
+
+
+
+ Schema XML de validação do evento informações da GTV 110170
+
+
+
+
+
+ Descrição do Evento - “Informações da GTV”
+
+
+
+
+
+
+
+
+
+
+
+ Grupo de Informações das GTV
+
+
+
+
+
+ Número da GTV
+
+
+
+
+
+
+
+
+
+
+ Identificador para diferenciar GTV de mesmo número (Usar número do AIDF ou identificador interno da empresa),
+
+
+
+
+
+
+
+
+
+
+ Série
+
+
+
+
+
+
+
+
+
+
+ Subsérie
+
+
+
+
+
+
+
+
+
+
+ Data de Emissão
+ Formato AAAA-MM-DD
+
+
+
+
+ Número Dígito Verificador
+
+
+
+
+
+
+
+
+
+
+ Quantidade de volumes/malotes
+
+
+
+
+ Informações das Espécies transportadas
+
+
+
+
+
+ Tipo da Espécie
+ 1 - Numerário
+2 - Cheque
+3 - Moeda
+4 - Outros
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Valor Transportada em Espécie indicada
+
+
+
+
+
+
+
+ Informações do Remetente da GTV
+
+
+
+
+
+
+ Número do CNPJ
+ Em caso de empresa não estabelecida no Brasil, será informado o CNPJ com zeros.
+ Informar os zeros não significativos.
+
+
+
+
+ Número do CPF
+ Informar os zeros não significativos.
+
+
+
+
+
+ Inscrição Estadual
+ Informar a IE do remetente ou ISENTO se remetente é contribuinte do ICMS isento de inscrição no cadastro de contribuintes do ICMS. Caso o remetente não seja contribuinte do ICMS não informar o conteúdo.
+
+
+
+
+
+
+
+ Sigla da UF
+ Informar EX para operações com o exterior.
+
+
+
+
+ Razão social ou nome do remetente
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Informações do Destinatário da GTV
+
+
+
+
+
+
+ Número do CNPJ
+ Em caso de empresa não estabelecida no Brasil, será informado o CNPJ com zeros.
+ Informar os zeros não significativos.
+
+
+
+
+ Número do CPF
+ Informar os zeros não significativos.
+
+
+
+
+
+ Inscrição Estadual
+ Informar a IE do destinatário ou ISENTO se remetente é contribuinte do ICMS isento de inscrição no cadastro de contribuintes do ICMS. Caso o remetente não seja contribuinte do ICMS não informar o conteúdo.
+
+
+
+
+
+
+
+ Sigla da UF
+ Informar EX para operações com o exterior.
+
+
+
+
+ Razão social ou nome do destinatário
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Placa do veículo
+
+
+
+
+ UF em que veículo está licenciado
+ Sigla da UF de licenciamento do veículo.
+
+
+
+
+ RNTRC do transportador
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/evIECTe_v4.00.xsd b/pynfe/data/XSDs/CT-e/evIECTe_v4.00.xsd
new file mode 100644
index 00000000..09266903
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/evIECTe_v4.00.xsd
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+ Schema XML de validação do evento insucesso na entrega eletrônico do CT-e
+110190
+
+
+
+
+
+ Descrição do Evento - “Insucesso na Entrega do CT-e”
+
+
+
+
+
+
+
+
+
+
+ Número do Protocolo de autorização do CT-e
+
+
+
+
+ Data e hora da tentativa da entrega da NF-e
+ Formato AAAA-MM-DDTHH:MM:DD TZD
+
+
+
+
+
+
+
+ Número da tentativa de entrega que não teve insucesso
+
+
+
+
+
+
+
+
+
+
+ Motivo do insucesso
+ 1- Recebedor não encontrado;
+2- Recusa do recebedor;
+3- Endereço inexistente;
+4- Outros (exige informar justificativa)
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Justificativa do Motivo de insucesso, informar apenas para tpMotivo = 4
+
+
+
+
+
+
+
+
+
+
+ Latitude do ponto de entrega
+
+
+
+
+ Longitude do ponto de entrega
+
+
+
+
+ Hash (SHA1) no formato Base64 resultante da concatenação: Chave de acesso do CT-e + Base64 da imagem capturada da tentativa com insucesso da entrega (Exemplo: foto do local que não recebeu a entrega ou do local sem recebedor)
+ O hashCSRT é o resultado das funções SHA-1 e base64 do token CSRT fornecido pelo fisco + chave de acesso do DF-e. (Implementação em futura NT)
+Observação: 28 caracteres são representados no schema como 20 bytes do tipo base64Binary
+
+
+
+
+
+
+
+
+
+ Data e hora de geração do hash tentativa entrega
+ Formato AAAA-MM-DDTHH:MM:DD TZD
+
+
+
+
+
+
+
+ Grupo de informações das NF-e que não tiveram sucesso na entrega ao Destinatário
+ Informar o grupo apenas para CT-e com tipo de serviço Normal
+
+
+
+
+
+ Chave de acesso da NF-e com insucesso na tentativa de entrega
+
+
+
+
+
+
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/evPrestDesacordo_v4.00.xsd b/pynfe/data/XSDs/CT-e/evPrestDesacordo_v4.00.xsd
new file mode 100644
index 00000000..34542d33
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/evPrestDesacordo_v4.00.xsd
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+ Schema XML de validação do evento Prestação do Serviço em Desacordo 610110
+
+
+
+
+
+ Descrição do Evento - “Prestação do Serviço em Desacordo”
+
+
+
+
+
+
+
+
+
+
+
+ Indicador de operação em desacordo
+
+
+
+
+
+
+
+
+
+ Observações do tomador
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/evRegMultimodal_v4.00.xsd b/pynfe/data/XSDs/CT-e/evRegMultimodal_v4.00.xsd
new file mode 100644
index 00000000..6ba3eccd
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/evRegMultimodal_v4.00.xsd
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+ Schema XML de validação do evento Registro Multimodal 110160
+
+
+
+
+
+ Descrição do Evento - “Registro Multimodal”
+
+
+
+
+
+
+
+
+
+
+ Informação complementar sobre o registro, indicação do tipo de documento utilizado e demais situações ocorridas no Multimodal (Texto Livre).
+
+
+
+
+
+
+
+
+
+
+
+
+ Numero do Documento lançado no CT-e Multimodal
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/eventoCTeTiposBasico_v4.00.xsd b/pynfe/data/XSDs/CT-e/eventoCTeTiposBasico_v4.00.xsd
new file mode 100644
index 00000000..d9090707
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/eventoCTeTiposBasico_v4.00.xsd
@@ -0,0 +1,331 @@
+
+
+
+
+
+
+
+ Tipo Evento
+
+
+
+
+
+
+
+ Código do órgão de recepção do Evento. Utilizar a Tabela do IBGE extendida, utilizar 90 para identificar SUFRAMA
+
+
+
+
+ Identificação do Ambiente:
+1 - Produção
+2 - Homologação
+
+
+
+
+
+ CNPJ do emissor do evento
+
+
+
+
+ CPF do emissor do evento
+ Informar zeros não significativos.
+
+Usar com série específica 920-969 para emitente pessoa física com inscrição estadual
+
+
+
+
+
+ Chave de Acesso do CT-e vinculado ao evento
+
+
+
+
+ Data e Hora do Evento, formato UTC (AAAA-MM-DDThh:mm:ssTZD)
+
+
+
+
+ Tipo do Evento
+
+
+
+
+
+
+
+
+
+
+ Seqüencial do evento para o mesmo tipo de evento. Para maioria dos eventos será 1, nos casos em que possa existir mais de um evento o autor do evento deve numerar de forma seqüencial.
+
+
+
+
+
+
+
+
+
+
+ Detalhamento do evento específico
+
+
+
+
+
+ XML do evento
+Insira neste local o XML específico do tipo de evento (cancelamento, encerramento, registro de passagem).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Grupo de informações do pedido de registro de evento da Nota Fiscal Fácil
+
+
+
+
+
+ Solicitação do pedido de registro de evento da NFF.
+ Será preenchido com a totalidade de campos informados no aplicativo emissor serializado.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Grupo de Informação do Provedor de Assinatura e Autorização
+
+
+
+
+
+ CNPJ do Provedor de Assinatura e Autorização
+
+
+
+
+ Assinatura RSA do Emitente para DFe gerados por PAA
+
+
+
+
+
+ Assinatura digital padrão RSA
+ Converter o atributo Id do DFe para array de bytes e assinar com a chave privada do RSA com algoritmo SHA1 gerando um valor no formato base64.
+
+
+
+
+ Chave Publica no padrão XML RSA Key
+
+
+
+
+
+
+
+
+
+
+
+ Identificador da TAG a ser assinada, a regra de formação do Id é:
+“ID” + tpEvento + chave do CT-e + nSeqEvento
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tipo retorno do Evento
+
+
+
+
+
+
+
+ Identificação do Ambiente:
+1 - Produção
+2 - Homologação
+
+
+
+
+ Versão do Aplicativo que recebeu o Evento
+
+
+
+
+ Código do órgão de recepção do Evento. Utilizar a Tabela do IBGE extendida, utilizar 90 para identificar SUFRAMA
+
+
+
+
+ Código do status da registro do Evento
+
+
+
+
+ Descrição literal do status do registro do Evento
+
+
+
+
+ Chave de Acesso CT-e vinculado
+
+
+
+
+ Tipo do Evento vinculado
+
+
+
+
+
+
+
+
+
+
+ Descrição do Evento
+
+
+
+
+
+
+
+
+
+
+ Seqüencial do evento
+
+
+
+
+
+
+
+
+
+
+ Data e Hora de do recebimento do evento ou do registro do evento formato AAAA-MM-DDThh:mm:ssTZD
+
+
+
+
+ Número do protocolo de registro do evento
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tipo procEvento
+
+
+
+
+
+
+
+
+ IP do transmissor do documento fiscal para o ambiente autorizador
+
+
+
+
+ Porta de origem utilizada na conexão (De 0 a 65535)
+
+
+
+
+
+
+
+
+
+ Data e Hora da Conexão de Origem
+
+
+
+
+
+ Tipo Versão do Evento
+
+
+
+
+
+
+
+
+ Tipo Modal transporte
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tipo número sequencial único do AN
+
+
+
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/eventoCTe_v4.00.xsd b/pynfe/data/XSDs/CT-e/eventoCTe_v4.00.xsd
new file mode 100644
index 00000000..a6197500
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/eventoCTe_v4.00.xsd
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+ Schema XML de validação do Pedido de Registro de Evento do CT-e
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/procCTeOS_v4.00.xsd b/pynfe/data/XSDs/CT-e/procCTeOS_v4.00.xsd
new file mode 100644
index 00000000..c019c2ec
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/procCTeOS_v4.00.xsd
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+ CT-e OS processado
+
+
+
+
+
+
+
+
+
+ IP do transmissor do documento fiscal para o ambiente autorizador
+
+
+
+
+ Porta de origem utilizada na conexão (De 0 a 65535)
+
+
+
+
+
+
+
+
+
+ Data e Hora da Conexão de Origem
+
+
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/procCTeSimp_v4.00.xsd b/pynfe/data/XSDs/CT-e/procCTeSimp_v4.00.xsd
new file mode 100644
index 00000000..ae7e19cb
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/procCTeSimp_v4.00.xsd
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+ CT-e Simplificado processado
+
+
+
+
+
+
+
+
+
+ IP do transmissor do documento fiscal para o ambiente autorizador
+
+
+
+
+ Porta de origem utilizada na conexão (De 0 a 65535)
+
+
+
+
+
+
+
+
+
+ Data e Hora da Conexão de Origem
+
+
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/procCTe_v4.00.xsd b/pynfe/data/XSDs/CT-e/procCTe_v4.00.xsd
new file mode 100644
index 00000000..c13cb4c8
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/procCTe_v4.00.xsd
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+ CT-e processado
+
+
+
+
+
+
+
+
+
+ IP do transmissor do documento fiscal para o ambiente autorizador
+
+
+
+
+ Porta de origem utilizada na conexão (De 0 a 65535)
+
+
+
+
+
+
+
+
+
+ Data e Hora da Conexão de Origem
+
+
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/procEventoCTe_v4.00.xsd b/pynfe/data/XSDs/CT-e/procEventoCTe_v4.00.xsd
new file mode 100644
index 00000000..ddfe9d4f
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/procEventoCTe_v4.00.xsd
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+ Pedido de Registro de Eventos de CT-e processado
+
+
+
+
+
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/procGTVe_v4.00.xsd b/pynfe/data/XSDs/CT-e/procGTVe_v4.00.xsd
new file mode 100644
index 00000000..b9a43893
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/procGTVe_v4.00.xsd
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+ GTV-e processada
+
+
+
+
+
+
+
+
+
+ IP do transmissor do documento fiscal para o ambiente autorizador
+
+
+
+
+ Porta de origem utilizada na conexão (De 0 a 65535)
+
+
+
+
+
+
+
+
+
+ Data e Hora da Conexão de Origem
+
+
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/retCTeOS_v4.00.xsd b/pynfe/data/XSDs/CT-e/retCTeOS_v4.00.xsd
new file mode 100644
index 00000000..3ca744be
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/retCTeOS_v4.00.xsd
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+ Schema XML de validação do retorno do recibo de envio do CT-e OS (Modelo 67)
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/retCTeSimp_v4.00.xsd b/pynfe/data/XSDs/CT-e/retCTeSimp_v4.00.xsd
new file mode 100644
index 00000000..8140961c
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/retCTeSimp_v4.00.xsd
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+ Schema XML de validação do retorno do recibo de envio do CT-e Simplificado (Modelo 57)
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/retCTe_v4.00.xsd b/pynfe/data/XSDs/CT-e/retCTe_v4.00.xsd
new file mode 100644
index 00000000..24f025dd
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/retCTe_v4.00.xsd
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+ Schema XML de validação do retorno do recibo de envio do CT-e (Modelo 57)
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/retConsSitCTe_v4.00.xsd b/pynfe/data/XSDs/CT-e/retConsSitCTe_v4.00.xsd
new file mode 100644
index 00000000..3e6aac4e
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/retConsSitCTe_v4.00.xsd
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+ Schema XML de validação do retorno da consulta da situação atual do CT-e.
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/retConsStatServCTe_v4.00.xsd b/pynfe/data/XSDs/CT-e/retConsStatServCTe_v4.00.xsd
new file mode 100644
index 00000000..4bc47d6c
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/retConsStatServCTe_v4.00.xsd
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+ Schema XML de validação do Resultado da Consulta do Status do Serviço de CT-e
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/retEventoCTe_v4.00.xsd b/pynfe/data/XSDs/CT-e/retEventoCTe_v4.00.xsd
new file mode 100644
index 00000000..41010ef8
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/retEventoCTe_v4.00.xsd
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+ Schema XML de validação do retorno Pedido de Evento do CT-e
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/retGTVe_v4.00.xsd b/pynfe/data/XSDs/CT-e/retGTVe_v4.00.xsd
new file mode 100644
index 00000000..f4e33316
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/retGTVe_v4.00.xsd
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+ Schema XML de validação do retorno do recibo de envio da GTV-e (Modelo 64)
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/tiposGeralCTe_v4.00.xsd b/pynfe/data/XSDs/CT-e/tiposGeralCTe_v4.00.xsd
new file mode 100644
index 00000000..6afdbea9
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/tiposGeralCTe_v4.00.xsd
@@ -0,0 +1,647 @@
+
+
+
+
+
+ Data e Hora, formato UTC (AAAA-MM-DDThh:mm:ssTZD, onde TZD = +hh:mm ou -hh:mm)
+
+
+
+
+
+
+
+
+ Tipo Ambiente
+
+
+
+
+
+
+
+
+
+ Tipo ano
+
+
+
+
+
+
+
+
+ Tipo Código da UF da tabela do IBGE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tipo Código do Município da tabela do IBGE
+
+
+
+
+
+
+
+
+ Tipo Código de orgão (UF da tabela do IBGE + 90 SUFRAMA + 91 RFB + 94 SVC-RS + 95 SVC-SP + 96 Sinc. Chaves do RS para SVSP
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tipo Chave de Documento Fiscal Eletrônico
+
+
+
+
+
+
+
+
+
+ Tipo Número do CNPJ
+
+
+
+
+
+
+
+
+ Tipo Número do Telefone
+
+
+
+
+
+
+
+
+ Tipo Número do CNPJ tamanho varíavel (3-14)
+
+
+
+
+
+
+
+
+ Tipo Número do CNPJ Opcional
+
+
+
+
+
+
+
+
+ Tipo Número do CPF
+
+
+
+
+
+
+
+
+ Tipo Número do CPF de tamanho variável (3-11)
+
+
+
+
+
+
+
+
+ Tipo data AAAA-MM-DD
+
+
+
+
+
+
+
+
+ Tipo Decimal com 5 dígitos, sendo 3 de corpo e 2 decimais
+
+
+
+
+
+
+
+
+ Tipo Decimal com 6 dígitos, sendo 3 de corpo e 3 decimais
+
+
+
+
+
+
+
+
+ Tipo Decimal com 6 ou 5 dígitos, sendo 3 de corpo e 3 ou 2 decimais
+
+
+
+
+
+
+
+
+ Tipo Decimal com 5 dígitos, sendo 3 de corpo e 2 decimais, utilizado em tags opcionais
+
+
+
+
+
+
+
+
+ Tipo Decimal com 11 dígitos, sendo 8 de corpo e 3 decimais
+
+
+
+
+
+
+
+
+ Tipo Decimal com 11 dígitos, sendo 8 de corpo e 3 decimais utilizado em tags opcionais
+
+
+
+
+
+
+
+
+ Tipo Decimal com 12 dígitos, sendo 8 de corpo e 4decimais
+
+
+
+
+
+
+
+
+ Tipo Decimal com 12 dígitos, sendo 8 de corpo e 4 decimais, utilizado em tags opcionais
+
+
+
+
+
+
+
+
+ Tipo Decimal com 15 dígitos, sendo 9 de corpo e 6 decimais, utilizado em tags opcionais
+
+
+
+
+
+
+
+
+ Tipo Decimal com 15 dígitos, sendo 11 de corpo e 4 decimais
+
+
+
+
+
+
+
+
+ Tipo Decimal com 15 dígitos, sendo 11 de corpo e 4 decimais, utilizado em tags opcionais
+
+
+
+
+
+
+
+
+ Tipo Decimal com 15 dígitos, sendo 12 de corpo e 3 decimais
+
+
+
+
+
+
+
+
+ Tipo Decimal com 15 dígitos, sendo 12 de corpo e 3 decimais, utilizado em tags opcionais
+
+
+
+
+
+
+
+
+ Tipo Decimal com 16 dígitos, sendo 12 de corpo e 4 decimais
+
+
+
+
+
+
+
+
+ Tipo Decimal com 16 dígitos, sendo 12 de corpo e 4 decimais, utilizado em tags opcionais
+
+
+
+
+
+
+
+
+ Tipo Decimal com 15 dígitos, sendo 13 de corpo e 2 decimais
+
+
+
+
+
+
+
+
+ Tipo Decimal com 15 dígitos, sendo 13 de corpo e 2 decimais, utilizado em tags opcionais
+
+
+
+
+
+
+
+
+ Tipo Inscrição Estadual do Emitente
+
+
+
+
+
+
+
+
+
+ Tipo Inscrição Estadual do Destinatário
+
+
+
+
+
+
+
+
+
+ Tipo Justificativa
+
+
+
+
+
+
+
+
+ Tipo temp médio em segundos
+
+
+
+
+
+
+
+
+ Tipo Modelo Documento Fiscal
+
+
+
+
+
+
+
+
+ Tipo Modelo Documento Fiscal
+
+
+
+
+
+
+
+
+ Tipo Modelo Documento Fiscal
+
+
+
+
+
+
+
+
+
+ Tipo Modelo Documento Fiscal
+
+
+
+
+
+
+
+
+ Tipo Modelo Documento Fiscal - NF Remetente
+
+
+
+
+
+
+
+
+
+ Tipo da Unidade de Transporte
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tipo da Unidade de Carga
+
+
+
+
+
+
+
+
+
+
+
+ Tipo Motivo
+
+
+
+
+
+
+
+
+ Tipo Número do Documento Fiscal
+
+
+
+
+
+
+
+
+ Tipo Número do Protocolo de Status
+
+
+
+
+
+
+
+
+ Tipo Número do Recibo do envio de lote de NF-e
+
+
+
+
+
+
+
+
+ Tipo Série do Documento Fiscal
+
+
+
+
+
+
+
+
+ Tipo Serviço solicitado
+
+
+
+
+
+ Tipo Código da Mensagem enviada
+
+
+
+
+
+
+
+
+ Tipo string genérico
+
+
+
+
+
+
+
+
+ Tipo Sigla da UF
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tipo Sigla da UF, sem Exterior
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tipo Versão do Aplicativo
+
+
+
+
+
+
+
+
+ Coordenada geográfica Latitude
+
+
+
+
+
+
+
+ Coordenada geográfica Longitude
+
+
+
+
+
+
+
+ Tipo IP versão 4
+
+
+
+
+
+
+
+
+ Tipo Placa
+
+
+
+
+
+
+
+
+ Tipo que representa uma chave publica padrão RSA
+
+
+
+
+
+
+
diff --git a/pynfe/data/XSDs/CT-e/xmldsig-core-schema_v1.01.xsd b/pynfe/data/XSDs/CT-e/xmldsig-core-schema_v1.01.xsd
new file mode 100644
index 00000000..76b74b38
--- /dev/null
+++ b/pynfe/data/XSDs/CT-e/xmldsig-core-schema_v1.01.xsd
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
From e482421bb3013917db29df9befea9f81dbc2540c Mon Sep 17 00:00:00 2001
From: Hanna Tiharu <129420244+HannaTiharu@users.noreply.github.com>
Date: Mon, 10 Feb 2025 09:53:54 -0300
Subject: [PATCH 002/175] =?UTF-8?q?feat(cte-event):=20evento=20criado=20pa?=
=?UTF-8?q?ra=20manifesta=C3=A7=C3=A3o=20de=20destinatario=20para=20cte,?=
=?UTF-8?q?=20url=20de=20webservices=20adicionada=20para=20eventos=20de=20?=
=?UTF-8?q?sp?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/entidades/evento.py | 58 ++++++++++++++++++++++++++++-
pynfe/processamento/comunicacao.py | 24 ++++++++++++
pynfe/processamento/serializacao.py | 42 +++++++++++++++++++++
pynfe/utils/webservices.py | 1 +
4 files changed, 123 insertions(+), 2 deletions(-)
diff --git a/pynfe/entidades/evento.py b/pynfe/entidades/evento.py
index 6fac5919..bfd100f9 100644
--- a/pynfe/entidades/evento.py
+++ b/pynfe/entidades/evento.py
@@ -10,14 +10,14 @@
class Evento(Entidade):
# - Identificador da TAG a ser assinada, a regra de formação do Id é:
- # “ID” + tpEvento + chave da NF-e + nSeqEvento
+ # “ID” + tpEvento + chave da NF-e ou do CT-e + nSeqEvento
id = str()
# - Código do órgão de recepção do Evento.
# Utilizar a Tabela do IBGE, utilizar 91 para identificar o Ambiente Nacional.
orgao = str()
# - CNPJ (obrigatorio)
cnpj = str()
- # - Chave de Acesso da NF-e vinculada ao Evento
+ # - Chave de Acesso da NF-e ou CT-e vinculada ao Evento
chave = str()
# - Data e hora do evento no formato AAAA-MM-DDThh:mm:ssTZD
data_emissao = None
@@ -235,3 +235,57 @@ def __init__(self, *args, **kwargs):
codBanco = str()
# - Código da Agência
codAgencia = str()
+
+
+class EventoManifestacaoDestCTe(Evento):
+ """Este serviço permite que o destinatário do Conhecimento de Transporte eletrônico confirme a sua
+ participação na operação acobertada pelo Conhecimento de Transporte eletrônico emitida para o seu CNPJ
+ """
+
+ def __init__(self, *args, **kwargs):
+ super(EventoManifestacaoDestCTe, self).__init__(*args, **kwargs)
+ # - numero da operacao
+ # 1=Comprovante de Entrega do CT-e
+ # 2=Cancelamento do Comprovante de Entrega do CT-e
+ # 3=Insucesso na Entrega do CT-e
+ # 4=Cancelamento do Insucesso de Entrega do CT-e
+ # 5=Prestação do Serviço em Desacordo
+ # 6=Cancelamento Prestação do Serviço em Desacordo
+ dict_tp_evento = {1: "110180", 2: "110181", 3: "110190", 4: "110191", 5: "610110", 6: "610111"}
+ """ Código do evento
+ 110180 – Comprovante de Entrega do CT-e
+ 110181 – Cancelamento do Comprovante de Entrega do CT-e
+ 110190 – Insucesso na Entrega do CT-e
+ 110191 – Cancelamento do Insucesso de Entrega do CT-e
+ 610110 – Prestação do Serviço em Desacordo
+ 610111 – Cancelamento Prestação do Serviço em Desacordo """
+ self.tp_evento = dict_tp_evento[self.operacao]
+ # - numero da operacao
+ # 1=Comprovante de Entrega do CT-e
+ # 2=Cancelamento do Comprovante de Entrega do CT-e
+ # 3=Insucesso na Entrega do CT-e
+ # 4=Cancelamento do Insucesso de Entrega do CT-e
+ # 5=Prestação do Serviço em Desacordo
+ # 6=Cancelamento Prestação do Serviço em Desacordo
+ dict_descricao = {
+ 1: "Comprovante de Entrega do CT-e",
+ 2: "Cancelamento do Comprovante de Entrega do CT-e",
+ 3: "Insucesso na Entrega do CT-e",
+ 4: "Cancelamento do Insucesso de Entrega do CT-e",
+ 5: "Prestação do Serviço em Desacordo",
+ 6: "Cancelamento Prestação do Serviço em Desacordo",
+ }
+ """ Informar a descrição do evento:
+ Comprovante de Entrega do CT-e
+ Cancelamento do Comprovante de Entrega do CT-e
+ Insucesso na Entrega do CT-e
+ Cancelamento do Insucesso de Entrega do CT-e
+ Prestação do Serviço em Desacordo
+ Cancelamento Prestação do Serviço em Desacordo """
+ self.descricao = dict_descricao[self.operacao]
+
+ # - Informar a justificativa porque a operação não foi realizada,
+ # este campo deve ser informado somente no evento de Insucesso na Entrega do CT-e.
+ # (min 15 max 255 caracteres)
+ justificativa = str()
+
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 4647eb19..9a1062e8 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -1316,6 +1316,28 @@ def _get_url(self, consulta):
else:
raise Exception(f"Url não encontrada para {consulta} {self.uf.upper()}")
return self.url
+
+ def evento(self, modelo, evento):
+ """
+ Envia eventos do MDFe como:
+ Comprovante de Entrega do CT-e
+ Cancelamento do Comprovante de Entrega do CT-e
+ Insucesso na Entrega do CT-e
+ Cancelamento do Insucesso de Entrega do CT-e
+ Prestação do Serviço em Desacordo
+ Cancelamento Prestação do Serviço em Desacordo
+ :param evento: Nome do Evento
+ :return:
+ """
+
+ # url do serviço
+ url = self._get_url("EVENTOS")
+
+ # Monta XML do corpo da requisição
+ raiz = etree.Element(evento, versao="1.00", xmlns=NAMESPACE_CTE)
+ xml = self._construir_xml_soap("CTeRecepcaoEventoV4", raiz)
+ return self._post(url, xml)
+
def _construir_xml_soap(self, metodo, dados, cabecalho=False):
"""Monta o XML para o envio via SOAP"""
@@ -1391,3 +1413,5 @@ def _post(self, url, xml):
raise e
finally:
certificado_a1.excluir()
+
+
diff --git a/pynfe/processamento/serializacao.py b/pynfe/processamento/serializacao.py
index 5c094d55..8a894294 100644
--- a/pynfe/processamento/serializacao.py
+++ b/pynfe/processamento/serializacao.py
@@ -2014,6 +2014,48 @@ def serializar_evento_mdfe(
return raiz
+ def serializar_evento_cte(self, evento, tag_raiz="eventoCTe", retorna_string=False):
+ tz = datetime.now().astimezone().strftime("%z")
+ tz = "{}:{}".format(tz[:-2], tz[-2:])
+ raiz = etree.Element(tag_raiz, versao=VERSAO_CTE, xmlns=NAMESPACE_CTE)
+ e = etree.SubElement(raiz, "infEvento", Id=evento.identificador)
+ etree.SubElement(e, "cOrgao").text = CODIGOS_ESTADOS[evento.uf.upper()]
+ etree.SubElement(e, "tpAmb").text = str(self._ambiente)
+ if len(so_numeros(evento.cnpj)) == 11:
+ etree.SubElement(e, "CPF").text = evento.cnpj
+ else:
+ etree.SubElement(e, "CNPJ").text = evento.cnpj
+ etree.SubElement(e, "chCTe").text = evento.chave
+ etree.SubElement(e, "dhEvento").text = (
+ evento.data_emissao.strftime("%Y-%m-%dT%H:%M:%S") + tz
+ )
+ etree.SubElement(e, "tpEvento").text = evento.tp_evento
+ etree.SubElement(e, "nSeqEvento").text = str(evento.n_seq_evento)
+ #etree.SubElement(e, "verEvento").text = "1.00" #comentei pq no mdfe tava versão cte direto sem essa linha
+ det = etree.SubElement(e, "detEvento", versao=VERSAO_CTE)
+ etree.SubElement(det, "descEvento").text = evento.descricao
+
+ # AJUSTAR AQUI TODOS OS CAMPOS PRA CADA EVENTO
+ if evento.descricao == "Comprovante de Entrega do CT-e":
+ etree.Subelement(det, "nProt").text = evento.protocolo
+ elif evento.descricao == "Cancelamento do Comprovante de Entrega do CT-e":
+ etree.Subelement(det, "nProt").text = evento.protocolo
+ elif evento.descricao == "Insucesso na Entrega do CT-e":
+ etree.Subelement(det, "nProt").text = evento.protocolo
+ etree.SubElement(det, "xJust").text = evento.justificativa
+ elif evento.descricao == "Cancelamento do Insucesso de Entrega do CT-e":
+ etree.Subelement(det, "nProt").text = evento.protocolo
+ elif evento.descricao == "Prestação do Serviço em Desacordo":
+ etree.Subelement(det, "nProt").text = evento.protocolo
+ elif evento.descricao == "Cancelamento Prestação do Serviço em Desacordo":
+ etree.Subelement(det, "nProt").text = evento.protocolo
+
+ if retorna_string:
+ return etree.tostring(raiz, encoding="unicode", pretty_print=True)
+ else:
+ return raiz
+
+
class SerializacaoQrcode(object):
"""Classe que gera e serializa o qrcode de NFC-e no xml"""
diff --git a/pynfe/utils/webservices.py b/pynfe/utils/webservices.py
index db37abdc..91f2f0f0 100644
--- a/pynfe/utils/webservices.py
+++ b/pynfe/utils/webservices.py
@@ -576,6 +576,7 @@
"HOMOLOGACAO": "https://cte-homologacao.",
},
"SP": {
+ "EVENTOS": "fazenda.sp.gov.br/CTeWS/WS/CTeRecepcaoEventoV4.asmx",
"STATUS": "fazenda.sp.gov.br/cteWEB/services/cteStatusServico.asmx",
"HTTPS": "https://nfe.",
"HOMOLOGACAO": "https://homologacao.nfe.",
From 321db75d3c35fe8a879ba0f8d892a7ffcb099326 Mon Sep 17 00:00:00 2001
From: Hanna Tiharu <129420244+HannaTiharu@users.noreply.github.com>
Date: Mon, 10 Feb 2025 12:36:53 -0300
Subject: [PATCH 003/175] feat(cte-event): adicionado campos para cada tipo
especifico de evento de destinatario
---
pynfe/processamento/comunicacao.py | 5 ++--
pynfe/processamento/serializacao.py | 43 ++++++++++++++++++++++++++---
2 files changed, 41 insertions(+), 7 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 9a1062e8..b37dd04e 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -1317,7 +1317,7 @@ def _get_url(self, consulta):
raise Exception(f"Url não encontrada para {consulta} {self.uf.upper()}")
return self.url
- def evento(self, modelo, evento):
+ def evento(self, evento):
"""
Envia eventos do MDFe como:
Comprovante de Entrega do CT-e
@@ -1334,8 +1334,7 @@ def evento(self, modelo, evento):
url = self._get_url("EVENTOS")
# Monta XML do corpo da requisição
- raiz = etree.Element(evento, versao="1.00", xmlns=NAMESPACE_CTE)
- xml = self._construir_xml_soap("CTeRecepcaoEventoV4", raiz)
+ xml = self._construir_xml_soap("CTeRecepcaoEventoV4", evento)
return self._post(url, xml)
diff --git a/pynfe/processamento/serializacao.py b/pynfe/processamento/serializacao.py
index 8a894294..461c1c9e 100644
--- a/pynfe/processamento/serializacao.py
+++ b/pynfe/processamento/serializacao.py
@@ -17,9 +17,11 @@
)
from pynfe.utils.flags import (
CODIGOS_ESTADOS,
+ NAMESPACE_CTE,
NAMESPACE_MDFE,
NAMESPACE_NFE,
NAMESPACE_SIG,
+ VERSAO_CTE,
VERSAO_MDFE,
VERSAO_PADRAO,
VERSAO_QRCODE,
@@ -2038,17 +2040,50 @@ def serializar_evento_cte(self, evento, tag_raiz="eventoCTe", retorna_string=Fal
# AJUSTAR AQUI TODOS OS CAMPOS PRA CADA EVENTO
if evento.descricao == "Comprovante de Entrega do CT-e":
etree.Subelement(det, "nProt").text = evento.protocolo
+ # Data e hora de conclusão da entrega da NF-e, Formato AAAA-MM-DDTHH:MM:DD TZD,
+ etree.SubElement(det, "dhEntrega").text = evento.data_hora
+ etree.SubElement(det, "nDoc").text = evento.documento_recebedor
+ etree.SubElement(det, "xNome").text = evento.nome_recebedor
+ etree.SubElement(det, "latitude").text = evento.latitude
+ etree.SubElement(det, "longitude").text = evento.longitude
+ etree.SubElement(det, "hashEntrega").text = evento.hash_entrega
+ #Hash (SHA1) no formato Base64 resultante da concatenação: Chave de acesso do CT-e + Base64 da imagem capturada da entrega (Exemplo: imagem capturada da assinatura eletrônica, digital do recebedor, foto, etc)
+ #O hashCSRT é o resultado das funções SHA-1 e base64 do token CSRT fornecido pelo fisco + chave de acesso do DF-e. (Implementação em futura NT)
+ #Observação: 28 caracteres são representados no schema como 20 bytes do tipo base64Binary
+ etree.SubElement(det, "dhHashEntrega").text = evento.datahora_hash #Formato AAAA-MM-DDTHH:MM:DD TZD
+ etree.SubElement(det, "infEntrega").text = evento.informacao_entrega #apenas para CT-e com tipo de serviço Normal
+ etree.SubElement(det, "chNFe").text = evento.chave_acesso #chave de acesso da NF-e entregue
elif evento.descricao == "Cancelamento do Comprovante de Entrega do CT-e":
- etree.Subelement(det, "nProt").text = evento.protocolo
+ etree.Subelement(det, "nProt").text = evento.protocolo #Número do Protocolo de autorização do CT-e
+ etree.SubElement(det, "nProtCE").text = evento.protocolo_evento #Número do Protocolo de autorização do evento a ser cancelado
elif evento.descricao == "Insucesso na Entrega do CT-e":
etree.Subelement(det, "nProt").text = evento.protocolo
- etree.SubElement(det, "xJust").text = evento.justificativa
+ etree.SubElement(det, "dhTentativaEntrega").text = evento.data_hora_tentativa #Formato AAAA-MM-DDTHH:MM:DD TZD
+ etree.SubElement(det, "nTentativa").text = evento.numero_tentativa
+ etree.SubElement(det, "tpMotivo").text = evento.tipo_motivo
+ #Motivo do insucesso:
+ # 1- Recebedor não encontrado;
+ # 2- Recusa do recebedor;
+ # 3- Endereço inexistente;
+ # 4- Outros (exige informar justificativa)
+ etree.SubElement(det, "xJustMotivo").text = evento.justificativa #apenas para tpMotivo = 4, 15-256 caracteres
+ etree.SubElement(det, "latitude").text = evento.latitude
+ etree.SubElement(det, "longitude").text = evento.longitude
+ etree.SubElement(det, "hashTentativaEntrega").text = evento.hash_entrega
+ # Hash (SHA1) no formato Base64 resultante da concatenação: Chave de acesso do CT-e + Base64 da imagem capturada da tentativa com insucesso da entrega (Exemplo: foto do local que não recebeu a entrega ou do local sem recebedor)
+ # O hashCSRT é o resultado das funções SHA-1 e base64 do token CSRT fornecido pelo fisco + chave de acesso do DF-e. (Implementação em futura NT)
+ # Observação: 28 caracteres são representados no schema como 20 bytes do tipo base64Binary
+ etree.SubElement(det, "dhHashTentativaEntrega").text = evento.datahora_hash #Formato AAAA-MM-DDTHH:MM:DD TZD
+ etree.SubElement(det, "infEntrega").text = evento.informacao_entrega #apenas para CT-e com tipo de serviço Normal
+ etree.SubElement(det, "chNFe").text = evento.chave_acesso #chave de acesso da NF-e com insucesso na entrega
elif evento.descricao == "Cancelamento do Insucesso de Entrega do CT-e":
etree.Subelement(det, "nProt").text = evento.protocolo
+ etree.Subelement(det, "nProtIE").text = evento.protocolo_evento
elif evento.descricao == "Prestação do Serviço em Desacordo":
- etree.Subelement(det, "nProt").text = evento.protocolo
+ etree.Subelement(det, "indDesacordoOper").text = evento.indicador_desacordo #Indicador de operação em desacordo
+ etree.Subelement(det, "xObs").text = evento.observacao
elif evento.descricao == "Cancelamento Prestação do Serviço em Desacordo":
- etree.Subelement(det, "nProt").text = evento.protocolo
+ etree.Subelement(det, "nProtEvPrestDes").text = evento.protocolo_evento
if retorna_string:
return etree.tostring(raiz, encoding="unicode", pretty_print=True)
From 8927610aba162c18efd48a7a4b2c741c0c2f66fe Mon Sep 17 00:00:00 2001
From: Hanna Tiharu <129420244+HannaTiharu@users.noreply.github.com>
Date: Tue, 11 Feb 2025 13:38:22 -0300
Subject: [PATCH 004/175] fix(cte-event): comment untested code and fixed
version of serializar_evento_cte to 4.0
---
pynfe/processamento/serializacao.py | 97 ++++++++++++++---------------
1 file changed, 48 insertions(+), 49 deletions(-)
diff --git a/pynfe/processamento/serializacao.py b/pynfe/processamento/serializacao.py
index 461c1c9e..48576087 100644
--- a/pynfe/processamento/serializacao.py
+++ b/pynfe/processamento/serializacao.py
@@ -2019,7 +2019,7 @@ def serializar_evento_mdfe(
def serializar_evento_cte(self, evento, tag_raiz="eventoCTe", retorna_string=False):
tz = datetime.now().astimezone().strftime("%z")
tz = "{}:{}".format(tz[:-2], tz[-2:])
- raiz = etree.Element(tag_raiz, versao=VERSAO_CTE, xmlns=NAMESPACE_CTE)
+ raiz = etree.Element(tag_raiz, versao="4.0", xmlns=NAMESPACE_CTE)
e = etree.SubElement(raiz, "infEvento", Id=evento.identificador)
etree.SubElement(e, "cOrgao").text = CODIGOS_ESTADOS[evento.uf.upper()]
etree.SubElement(e, "tpAmb").text = str(self._ambiente)
@@ -2033,57 +2033,56 @@ def serializar_evento_cte(self, evento, tag_raiz="eventoCTe", retorna_string=Fal
)
etree.SubElement(e, "tpEvento").text = evento.tp_evento
etree.SubElement(e, "nSeqEvento").text = str(evento.n_seq_evento)
- #etree.SubElement(e, "verEvento").text = "1.00" #comentei pq no mdfe tava versão cte direto sem essa linha
- det = etree.SubElement(e, "detEvento", versao=VERSAO_CTE)
+ det = etree.SubElement(e, "detEvento", versaoEvento="4.0")
etree.SubElement(det, "descEvento").text = evento.descricao
- # AJUSTAR AQUI TODOS OS CAMPOS PRA CADA EVENTO
- if evento.descricao == "Comprovante de Entrega do CT-e":
- etree.Subelement(det, "nProt").text = evento.protocolo
- # Data e hora de conclusão da entrega da NF-e, Formato AAAA-MM-DDTHH:MM:DD TZD,
- etree.SubElement(det, "dhEntrega").text = evento.data_hora
- etree.SubElement(det, "nDoc").text = evento.documento_recebedor
- etree.SubElement(det, "xNome").text = evento.nome_recebedor
- etree.SubElement(det, "latitude").text = evento.latitude
- etree.SubElement(det, "longitude").text = evento.longitude
- etree.SubElement(det, "hashEntrega").text = evento.hash_entrega
- #Hash (SHA1) no formato Base64 resultante da concatenação: Chave de acesso do CT-e + Base64 da imagem capturada da entrega (Exemplo: imagem capturada da assinatura eletrônica, digital do recebedor, foto, etc)
- #O hashCSRT é o resultado das funções SHA-1 e base64 do token CSRT fornecido pelo fisco + chave de acesso do DF-e. (Implementação em futura NT)
- #Observação: 28 caracteres são representados no schema como 20 bytes do tipo base64Binary
- etree.SubElement(det, "dhHashEntrega").text = evento.datahora_hash #Formato AAAA-MM-DDTHH:MM:DD TZD
- etree.SubElement(det, "infEntrega").text = evento.informacao_entrega #apenas para CT-e com tipo de serviço Normal
- etree.SubElement(det, "chNFe").text = evento.chave_acesso #chave de acesso da NF-e entregue
- elif evento.descricao == "Cancelamento do Comprovante de Entrega do CT-e":
- etree.Subelement(det, "nProt").text = evento.protocolo #Número do Protocolo de autorização do CT-e
- etree.SubElement(det, "nProtCE").text = evento.protocolo_evento #Número do Protocolo de autorização do evento a ser cancelado
- elif evento.descricao == "Insucesso na Entrega do CT-e":
- etree.Subelement(det, "nProt").text = evento.protocolo
- etree.SubElement(det, "dhTentativaEntrega").text = evento.data_hora_tentativa #Formato AAAA-MM-DDTHH:MM:DD TZD
- etree.SubElement(det, "nTentativa").text = evento.numero_tentativa
- etree.SubElement(det, "tpMotivo").text = evento.tipo_motivo
- #Motivo do insucesso:
- # 1- Recebedor não encontrado;
- # 2- Recusa do recebedor;
- # 3- Endereço inexistente;
- # 4- Outros (exige informar justificativa)
- etree.SubElement(det, "xJustMotivo").text = evento.justificativa #apenas para tpMotivo = 4, 15-256 caracteres
- etree.SubElement(det, "latitude").text = evento.latitude
- etree.SubElement(det, "longitude").text = evento.longitude
- etree.SubElement(det, "hashTentativaEntrega").text = evento.hash_entrega
- # Hash (SHA1) no formato Base64 resultante da concatenação: Chave de acesso do CT-e + Base64 da imagem capturada da tentativa com insucesso da entrega (Exemplo: foto do local que não recebeu a entrega ou do local sem recebedor)
- # O hashCSRT é o resultado das funções SHA-1 e base64 do token CSRT fornecido pelo fisco + chave de acesso do DF-e. (Implementação em futura NT)
- # Observação: 28 caracteres são representados no schema como 20 bytes do tipo base64Binary
- etree.SubElement(det, "dhHashTentativaEntrega").text = evento.datahora_hash #Formato AAAA-MM-DDTHH:MM:DD TZD
- etree.SubElement(det, "infEntrega").text = evento.informacao_entrega #apenas para CT-e com tipo de serviço Normal
- etree.SubElement(det, "chNFe").text = evento.chave_acesso #chave de acesso da NF-e com insucesso na entrega
- elif evento.descricao == "Cancelamento do Insucesso de Entrega do CT-e":
- etree.Subelement(det, "nProt").text = evento.protocolo
- etree.Subelement(det, "nProtIE").text = evento.protocolo_evento
- elif evento.descricao == "Prestação do Serviço em Desacordo":
- etree.Subelement(det, "indDesacordoOper").text = evento.indicador_desacordo #Indicador de operação em desacordo
- etree.Subelement(det, "xObs").text = evento.observacao
+ # EVENTOS COMENTADOS NÂO TESTADOS
+ # if evento.descricao == "Comprovante de Entrega do CT-e":
+ # etree.Subelement(det, "nProt").text = evento.protocolo
+ # # Data e hora de conclusão da entrega da NF-e, Formato AAAA-MM-DDTHH:MM:DD TZD,
+ # etree.SubElement(det, "dhEntrega").text = evento.data_hora.strftime("%Y-%m-%dT%H:%M:%S") + tz
+ # etree.SubElement(det, "nDoc").text = evento.documento_recebedor
+ # etree.SubElement(det, "xNome").text = evento.nome_recebedor
+ # etree.SubElement(det, "latitude").text = evento.latitude
+ # etree.SubElement(det, "longitude").text = evento.longitude
+ # etree.SubElement(det, "hashEntrega").text = evento.hash_entrega # concatenação: Chave de acesso do CT-e + Base64 da imagem capturada da entrega (Exemplo: imagem capturada da assinatura eletrônica, digital do recebedor, foto, etc), resultado das funções SHA-1 e base64 do token CSRT fornecido pelo fisco + chave de acesso do DF-e. (Implementação em futura NT)
+ # etree.SubElement(det, "dhHashEntrega").text = evento.datahora_hash.strftime("%Y-%m-%dT%H:%M:%S") + tz #Formato AAAA-MM-DDTHH:MM:DD TZD
+ # if evento.informacao_entrega:
+ # inf_entrega = etree.SubElement(det, "infEntrega") #apenas para CT-e com tipo de serviço Normal
+ # etree.SubElement(inf_entrega, "chNFe").text = evento.chave_acesso #chave de acesso da NF-e entregue
+ # elif evento.descricao == "Cancelamento do Comprovante de Entrega do CT-e":
+ # etree.SubElement(det, "nProt").text = evento.protocolo #Número do Protocolo de autorização do CT-e
+ # etree.SubElement(det, "nProtCE").text = evento.protocolo_evento #Número do Protocolo de autorização do evento a ser cancelado
+ # elif evento.descricao == "Insucesso na Entrega do CT-e":
+ # etree.SubElement(det, "nProt").text = evento.protocolo
+ # etree.SubElement(det, "dhTentativaEntrega").text = evento.data_hora_tentativa.strftime("%Y-%m-%dT%H:%M:%S") + tz #Formato AAAA-MM-DDTHH:MM:DD TZD
+ # etree.SubElement(det, "nTentativa").text = evento.numero_tentativa
+ # etree.SubElement(det, "tpMotivo").text = evento.tipo_motivo
+ # #Motivo do insucesso:
+ # # 1- Recebedor não encontrado;
+ # # 2- Recusa do recebedor;
+ # # 3- Endereço inexistente;
+ # # 4- Outros (exige informar justificativa)
+ # if evento.tipo_motivo == 4:
+ # etree.SubElement(det, "xJustMotivo").text = evento.justificativa #apenas para tpMotivo = 4, 15-256 caracteres
+ # etree.SubElement(det, "latitude").text = evento.latitude
+ # etree.SubElement(det, "longitude").text = evento.longitude
+ # etree.SubElement(det, "hashTentativaEntrega").text = evento.hash_entrega
+ # # Hash (SHA1) no formato Base64 resultante da concatenação: Chave de acesso do CT-e + Base64 da imagem capturada da tentativa com insucesso da entrega (Exemplo: foto do local que não recebeu a entrega ou do local sem recebedor)
+ # # O hashCSRT é o resultado das funções SHA-1 e base64 do token CSRT fornecido pelo fisco + chave de acesso do DF-e. (Implementação em futura NT)
+ # # Observação: 28 caracteres são representados no schema como 20 bytes do tipo base64Binary
+ # etree.SubElement(det, "dhHashTentativaEntrega").text = evento.datahora_hash.strftime("%Y-%m-%dT%H:%M:%S") + tz #Formato AAAA-MM-DDTHH:MM:DD TZD
+ # if evento.informacao_entrega:
+ # inf_entrega = etree.SubElement(det, "infEntrega") #apenas para CT-e com tipo de serviço Normal
+ # etree.SubElement(inf_entrega, "chNFe").text = evento.chave_acesso #chave de acesso da NF-e com insucesso na entrega
+ # elif evento.descricao == "Cancelamento do Insucesso de Entrega do CT-e":
+ # etree.SubElement(det, "nProt").text = evento.protocolo
+ # etree.SubElement(det, "nProtIE").text = evento.protocolo_evento
+ if evento.descricao == "Prestação do Serviço em Desacordo":
+ etree.SubElement(det, "indDesacordoOper").text = 1 #Indicador de operação em desacordo
+ etree.SubElement(det, "xObs").text = evento.observacao
elif evento.descricao == "Cancelamento Prestação do Serviço em Desacordo":
- etree.Subelement(det, "nProtEvPrestDes").text = evento.protocolo_evento
+ etree.SubElement(det, "nProtEvPrestDes").text = evento.protocolo_evento
if retorna_string:
return etree.tostring(raiz, encoding="unicode", pretty_print=True)
From 62e8170bfafb517f78113c5ad310a051cdda3812 Mon Sep 17 00:00:00 2001
From: Hanna Tiharu <129420244+HannaTiharu@users.noreply.github.com>
Date: Wed, 12 Feb 2025 13:56:14 -0300
Subject: [PATCH 005/175] =?UTF-8?q?fix(cte-event):=20fixed=20int=20value?=
=?UTF-8?q?=20to=20string=20value=20for=20xml=20indicador=20de=20opera?=
=?UTF-8?q?=C3=A7=C3=A3o=20field?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 2 +-
pynfe/processamento/serializacao.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index b37dd04e..78d04fcc 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -1319,7 +1319,7 @@ def _get_url(self, consulta):
def evento(self, evento):
"""
- Envia eventos do MDFe como:
+ Envia eventos do CTe como:
Comprovante de Entrega do CT-e
Cancelamento do Comprovante de Entrega do CT-e
Insucesso na Entrega do CT-e
diff --git a/pynfe/processamento/serializacao.py b/pynfe/processamento/serializacao.py
index 48576087..ef8c2dd6 100644
--- a/pynfe/processamento/serializacao.py
+++ b/pynfe/processamento/serializacao.py
@@ -2079,7 +2079,7 @@ def serializar_evento_cte(self, evento, tag_raiz="eventoCTe", retorna_string=Fal
# etree.SubElement(det, "nProt").text = evento.protocolo
# etree.SubElement(det, "nProtIE").text = evento.protocolo_evento
if evento.descricao == "Prestação do Serviço em Desacordo":
- etree.SubElement(det, "indDesacordoOper").text = 1 #Indicador de operação em desacordo
+ etree.SubElement(det, "indDesacordoOper").text = "1" #Indicador de operação em desacordo
etree.SubElement(det, "xObs").text = evento.observacao
elif evento.descricao == "Cancelamento Prestação do Serviço em Desacordo":
etree.SubElement(det, "nProtEvPrestDes").text = evento.protocolo_evento
From 136ba9e520217d16aa3d0841ea735af6a92b60cd Mon Sep 17 00:00:00 2001
From: Hanna Tiharu <129420244+HannaTiharu@users.noreply.github.com>
Date: Wed, 12 Feb 2025 14:50:35 -0300
Subject: [PATCH 006/175] feat(cte-event): added names of events for det
---
pynfe/processamento/serializacao.py | 24 ++++++++++++++----------
1 file changed, 14 insertions(+), 10 deletions(-)
diff --git a/pynfe/processamento/serializacao.py b/pynfe/processamento/serializacao.py
index ef8c2dd6..5bcd00b9 100644
--- a/pynfe/processamento/serializacao.py
+++ b/pynfe/processamento/serializacao.py
@@ -2050,9 +2050,10 @@ def serializar_evento_cte(self, evento, tag_raiz="eventoCTe", retorna_string=Fal
# if evento.informacao_entrega:
# inf_entrega = etree.SubElement(det, "infEntrega") #apenas para CT-e com tipo de serviço Normal
# etree.SubElement(inf_entrega, "chNFe").text = evento.chave_acesso #chave de acesso da NF-e entregue
- # elif evento.descricao == "Cancelamento do Comprovante de Entrega do CT-e":
- # etree.SubElement(det, "nProt").text = evento.protocolo #Número do Protocolo de autorização do CT-e
- # etree.SubElement(det, "nProtCE").text = evento.protocolo_evento #Número do Protocolo de autorização do evento a ser cancelado
+ if evento.descricao == "Cancelamento do Comprovante de Entrega do CT-e":
+ cancelamento = etree.SubElement(det, "evCancCECTe")
+ etree.SubElement(cancelamento, "nProt").text = evento.protocolo #Número do Protocolo de autorização do CT-e
+ etree.SubElement(cancelamento, "nProtCE").text = evento.protocolo_evento #Número do Protocolo de autorização do evento a ser cancelado
# elif evento.descricao == "Insucesso na Entrega do CT-e":
# etree.SubElement(det, "nProt").text = evento.protocolo
# etree.SubElement(det, "dhTentativaEntrega").text = evento.data_hora_tentativa.strftime("%Y-%m-%dT%H:%M:%S") + tz #Formato AAAA-MM-DDTHH:MM:DD TZD
@@ -2075,14 +2076,17 @@ def serializar_evento_cte(self, evento, tag_raiz="eventoCTe", retorna_string=Fal
# if evento.informacao_entrega:
# inf_entrega = etree.SubElement(det, "infEntrega") #apenas para CT-e com tipo de serviço Normal
# etree.SubElement(inf_entrega, "chNFe").text = evento.chave_acesso #chave de acesso da NF-e com insucesso na entrega
- # elif evento.descricao == "Cancelamento do Insucesso de Entrega do CT-e":
- # etree.SubElement(det, "nProt").text = evento.protocolo
- # etree.SubElement(det, "nProtIE").text = evento.protocolo_evento
- if evento.descricao == "Prestação do Serviço em Desacordo":
- etree.SubElement(det, "indDesacordoOper").text = "1" #Indicador de operação em desacordo
- etree.SubElement(det, "xObs").text = evento.observacao
+ elif evento.descricao == "Cancelamento do Insucesso de Entrega do CT-e":
+ cancelamento = etree.SubElement(det, "evCancIECTe")
+ etree.SubElement(cancelamento, "nProt").text = evento.protocolo
+ etree.SubElement(cancelamento, "nProtIE").text = evento.protocolo_evento
+ elif evento.descricao == "Prestação do Serviço em Desacordo":
+ desacordo = etree.SubElement(det, "evPrestDesacordo")
+ etree.SubElement(desacordo, "indDesacordoOper").text = "1" #Indicador de operação em desacordo
+ etree.SubElement(desacordo, "xObs").text = evento.observacao
elif evento.descricao == "Cancelamento Prestação do Serviço em Desacordo":
- etree.SubElement(det, "nProtEvPrestDes").text = evento.protocolo_evento
+ cancelamento = etree.SubElement(det, "evCancPrestDesacordo")
+ etree.SubElement(cancelamento, "nProtEvPrestDes").text = evento.protocolo_evento
if retorna_string:
return etree.tostring(raiz, encoding="unicode", pretty_print=True)
From a424af468ba71a54eff194a692d5fd4d5cb38770 Mon Sep 17 00:00:00 2001
From: Hanna Tiharu <129420244+HannaTiharu@users.noreply.github.com>
Date: Wed, 12 Feb 2025 15:18:54 -0300
Subject: [PATCH 007/175] fix(cte-event): fix descEvento
---
pynfe/processamento/serializacao.py | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/pynfe/processamento/serializacao.py b/pynfe/processamento/serializacao.py
index 5bcd00b9..f90ff89f 100644
--- a/pynfe/processamento/serializacao.py
+++ b/pynfe/processamento/serializacao.py
@@ -2034,8 +2034,6 @@ def serializar_evento_cte(self, evento, tag_raiz="eventoCTe", retorna_string=Fal
etree.SubElement(e, "tpEvento").text = evento.tp_evento
etree.SubElement(e, "nSeqEvento").text = str(evento.n_seq_evento)
det = etree.SubElement(e, "detEvento", versaoEvento="4.0")
- etree.SubElement(det, "descEvento").text = evento.descricao
-
# EVENTOS COMENTADOS NÂO TESTADOS
# if evento.descricao == "Comprovante de Entrega do CT-e":
# etree.Subelement(det, "nProt").text = evento.protocolo
@@ -2052,6 +2050,7 @@ def serializar_evento_cte(self, evento, tag_raiz="eventoCTe", retorna_string=Fal
# etree.SubElement(inf_entrega, "chNFe").text = evento.chave_acesso #chave de acesso da NF-e entregue
if evento.descricao == "Cancelamento do Comprovante de Entrega do CT-e":
cancelamento = etree.SubElement(det, "evCancCECTe")
+ etree.SubElement(cancelamento, "descEvento").text = evento.descricao
etree.SubElement(cancelamento, "nProt").text = evento.protocolo #Número do Protocolo de autorização do CT-e
etree.SubElement(cancelamento, "nProtCE").text = evento.protocolo_evento #Número do Protocolo de autorização do evento a ser cancelado
# elif evento.descricao == "Insucesso na Entrega do CT-e":
@@ -2078,14 +2077,17 @@ def serializar_evento_cte(self, evento, tag_raiz="eventoCTe", retorna_string=Fal
# etree.SubElement(inf_entrega, "chNFe").text = evento.chave_acesso #chave de acesso da NF-e com insucesso na entrega
elif evento.descricao == "Cancelamento do Insucesso de Entrega do CT-e":
cancelamento = etree.SubElement(det, "evCancIECTe")
+ etree.SubElement(cancelamento, "descEvento").text = evento.descricao
etree.SubElement(cancelamento, "nProt").text = evento.protocolo
etree.SubElement(cancelamento, "nProtIE").text = evento.protocolo_evento
elif evento.descricao == "Prestação do Serviço em Desacordo":
desacordo = etree.SubElement(det, "evPrestDesacordo")
+ etree.SubElement(desacordo, "descEvento").text = evento.descricao
etree.SubElement(desacordo, "indDesacordoOper").text = "1" #Indicador de operação em desacordo
etree.SubElement(desacordo, "xObs").text = evento.observacao
elif evento.descricao == "Cancelamento Prestação do Serviço em Desacordo":
cancelamento = etree.SubElement(det, "evCancPrestDesacordo")
+ etree.SubElement(cancelamento, "descEvento").text = evento.descricao
etree.SubElement(cancelamento, "nProtEvPrestDes").text = evento.protocolo_evento
if retorna_string:
From 66ec54d8864d11b5def59eb60bcce32732a2edf8 Mon Sep 17 00:00:00 2001
From: Hanna Tiharu <129420244+HannaTiharu@users.noreply.github.com>
Date: Thu, 20 Feb 2025 15:08:46 -0300
Subject: [PATCH 008/175] feat(testing-comunicacao): added debbuger print
---
pynfe/processamento/comunicacao.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 78d04fcc..3c3328f1 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -1395,6 +1395,9 @@ def _post(self, url, xml):
)
xml = xml_declaration + xml
+ xml_text = etree.tostring(xml, encoding="unicode", pretty_print=True)
+ print(f"xml_text:{xml_text}")
+
# Faz o request com o servidor
result = requests.post(
url,
From 37d7615f0a29c2a5b7071681a432671cb7fe809e Mon Sep 17 00:00:00 2001
From: Hanna Tiharu <129420244+HannaTiharu@users.noreply.github.com>
Date: Thu, 20 Feb 2025 15:18:55 -0300
Subject: [PATCH 009/175] fix(testing-comunicacao): it was already string ahaha
---
pynfe/processamento/comunicacao.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 3c3328f1..0b84d090 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -1395,8 +1395,7 @@ def _post(self, url, xml):
)
xml = xml_declaration + xml
- xml_text = etree.tostring(xml, encoding="unicode", pretty_print=True)
- print(f"xml_text:{xml_text}")
+ print(xml)
# Faz o request com o servidor
result = requests.post(
From 0c9f5706bff340df895926f1b127455965f53895 Mon Sep 17 00:00:00 2001
From: Hanna Tiharu <129420244+HannaTiharu@users.noreply.github.com>
Date: Thu, 20 Feb 2025 15:56:24 -0300
Subject: [PATCH 010/175] fix(main): fix
---
pynfe/processamento/comunicacao.py | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 0b84d090..ab861f33 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -1334,8 +1334,8 @@ def evento(self, evento):
url = self._get_url("EVENTOS")
# Monta XML do corpo da requisição
- xml = self._construir_xml_soap("CTeRecepcaoEventoV4", evento)
- return self._post(url, xml)
+ #xml = self._construir_xml_soap("CTeRecepcaoEventoV4", evento)
+ return self._post(url, evento)
def _construir_xml_soap(self, metodo, dados, cabecalho=False):
@@ -1394,7 +1394,6 @@ def _post(self, url, xml):
etree.tostring(xml, encoding="unicode").replace("\n", ""),
)
xml = xml_declaration + xml
-
print(xml)
# Faz o request com o servidor
From 723762ca6b652b7b713e7180581c16df87a9232f Mon Sep 17 00:00:00 2001
From: Hanna Tiharu <129420244+HannaTiharu@users.noreply.github.com>
Date: Thu, 20 Feb 2025 16:19:47 -0300
Subject: [PATCH 011/175] fix(main): added soap
---
pynfe/processamento/comunicacao.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index ab861f33..ebc3c7ca 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -1334,8 +1334,8 @@ def evento(self, evento):
url = self._get_url("EVENTOS")
# Monta XML do corpo da requisição
- #xml = self._construir_xml_soap("CTeRecepcaoEventoV4", evento)
- return self._post(url, evento)
+ xml = self._construir_xml_soap("CTeRecepcaoEventoV4", evento)
+ return self._post(url, xml)
def _construir_xml_soap(self, metodo, dados, cabecalho=False):
@@ -1343,7 +1343,7 @@ def _construir_xml_soap(self, metodo, dados, cabecalho=False):
raiz = etree.Element(
"{%s}Envelope" % NAMESPACE_SOAP,
- nsmap={"xsi": NAMESPACE_XSI, "xsd": NAMESPACE_XSD, "soap": NAMESPACE_SOAP},
+ nsmap={"soap": NAMESPACE_SOAP}, #"xsi": NAMESPACE_XSI, "xsd": NAMESPACE_XSD,
)
if self._header:
From 3adaba0fdeff1249a5a8185d13e4948a9eb8de08 Mon Sep 17 00:00:00 2001
From: Hanna Tiharu <129420244+HannaTiharu@users.noreply.github.com>
Date: Thu, 20 Feb 2025 16:46:15 -0300
Subject: [PATCH 012/175] fix(main): versaoDados to 4.0
---
pynfe/processamento/comunicacao.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index ebc3c7ca..9ee8160f 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -1260,7 +1260,7 @@ def _cabecalho_soap(self, metodo):
raiz = etree.Element(self._header, xmlns=self._namespace_metodo + metodo)
etree.SubElement(raiz, "cUF").text = CODIGOS_ESTADOS[self.uf.upper()]
- etree.SubElement(raiz, "versaoDados").text = "3.00"
+ etree.SubElement(raiz, "versaoDados").text = "4.0"
return raiz
def _get_url(self, consulta):
From 8190b74fc73bac3b897949f48b20905c68441722 Mon Sep 17 00:00:00 2001
From: Hanna Tiharu <129420244+HannaTiharu@users.noreply.github.com>
Date: Thu, 20 Feb 2025 20:58:02 -0300
Subject: [PATCH 013/175] fix(main): testing with version 3.0
---
pynfe/processamento/comunicacao.py | 2 +-
pynfe/processamento/serializacao.py | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 9ee8160f..7f1b984e 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -1260,7 +1260,7 @@ def _cabecalho_soap(self, metodo):
raiz = etree.Element(self._header, xmlns=self._namespace_metodo + metodo)
etree.SubElement(raiz, "cUF").text = CODIGOS_ESTADOS[self.uf.upper()]
- etree.SubElement(raiz, "versaoDados").text = "4.0"
+ etree.SubElement(raiz, "versaoDados").text = "3.0"
return raiz
def _get_url(self, consulta):
diff --git a/pynfe/processamento/serializacao.py b/pynfe/processamento/serializacao.py
index f90ff89f..334348ca 100644
--- a/pynfe/processamento/serializacao.py
+++ b/pynfe/processamento/serializacao.py
@@ -2019,7 +2019,7 @@ def serializar_evento_mdfe(
def serializar_evento_cte(self, evento, tag_raiz="eventoCTe", retorna_string=False):
tz = datetime.now().astimezone().strftime("%z")
tz = "{}:{}".format(tz[:-2], tz[-2:])
- raiz = etree.Element(tag_raiz, versao="4.0", xmlns=NAMESPACE_CTE)
+ raiz = etree.Element(tag_raiz, versao="3.0", xmlns=NAMESPACE_CTE)
e = etree.SubElement(raiz, "infEvento", Id=evento.identificador)
etree.SubElement(e, "cOrgao").text = CODIGOS_ESTADOS[evento.uf.upper()]
etree.SubElement(e, "tpAmb").text = str(self._ambiente)
@@ -2033,7 +2033,7 @@ def serializar_evento_cte(self, evento, tag_raiz="eventoCTe", retorna_string=Fal
)
etree.SubElement(e, "tpEvento").text = evento.tp_evento
etree.SubElement(e, "nSeqEvento").text = str(evento.n_seq_evento)
- det = etree.SubElement(e, "detEvento", versaoEvento="4.0")
+ det = etree.SubElement(e, "detEvento", versaoEvento="3.0")
# EVENTOS COMENTADOS NÂO TESTADOS
# if evento.descricao == "Comprovante de Entrega do CT-e":
# etree.Subelement(det, "nProt").text = evento.protocolo
From 57ced00f5e48434835677726b796f696b6b0c81e Mon Sep 17 00:00:00 2001
From: Hanna Tiharu <129420244+HannaTiharu@users.noreply.github.com>
Date: Thu, 20 Feb 2025 21:18:48 -0300
Subject: [PATCH 014/175] fix(main): version 4.00 not 4.0
---
pynfe/processamento/comunicacao.py | 2 +-
pynfe/processamento/serializacao.py | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 7f1b984e..d66b12ff 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -1260,7 +1260,7 @@ def _cabecalho_soap(self, metodo):
raiz = etree.Element(self._header, xmlns=self._namespace_metodo + metodo)
etree.SubElement(raiz, "cUF").text = CODIGOS_ESTADOS[self.uf.upper()]
- etree.SubElement(raiz, "versaoDados").text = "3.0"
+ etree.SubElement(raiz, "versaoDados").text = "4.00"
return raiz
def _get_url(self, consulta):
diff --git a/pynfe/processamento/serializacao.py b/pynfe/processamento/serializacao.py
index 334348ca..c5a1c69b 100644
--- a/pynfe/processamento/serializacao.py
+++ b/pynfe/processamento/serializacao.py
@@ -2019,7 +2019,7 @@ def serializar_evento_mdfe(
def serializar_evento_cte(self, evento, tag_raiz="eventoCTe", retorna_string=False):
tz = datetime.now().astimezone().strftime("%z")
tz = "{}:{}".format(tz[:-2], tz[-2:])
- raiz = etree.Element(tag_raiz, versao="3.0", xmlns=NAMESPACE_CTE)
+ raiz = etree.Element(tag_raiz, versao="4.00", xmlns=NAMESPACE_CTE)
e = etree.SubElement(raiz, "infEvento", Id=evento.identificador)
etree.SubElement(e, "cOrgao").text = CODIGOS_ESTADOS[evento.uf.upper()]
etree.SubElement(e, "tpAmb").text = str(self._ambiente)
@@ -2033,7 +2033,7 @@ def serializar_evento_cte(self, evento, tag_raiz="eventoCTe", retorna_string=Fal
)
etree.SubElement(e, "tpEvento").text = evento.tp_evento
etree.SubElement(e, "nSeqEvento").text = str(evento.n_seq_evento)
- det = etree.SubElement(e, "detEvento", versaoEvento="3.0")
+ det = etree.SubElement(e, "detEvento", versaoEvento="4.00")
# EVENTOS COMENTADOS NÂO TESTADOS
# if evento.descricao == "Comprovante de Entrega do CT-e":
# etree.Subelement(det, "nProt").text = evento.protocolo
From bcced62c1956d25f1663e516cc04a15fd5d94f6c Mon Sep 17 00:00:00 2001
From: Hanna Tiharu <129420244+HannaTiharu@users.noreply.github.com>
Date: Thu, 20 Feb 2025 21:56:02 -0300
Subject: [PATCH 015/175] fix(main): xsi and xsd
---
pynfe/processamento/comunicacao.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index d66b12ff..30c4d475 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -1343,7 +1343,7 @@ def _construir_xml_soap(self, metodo, dados, cabecalho=False):
raiz = etree.Element(
"{%s}Envelope" % NAMESPACE_SOAP,
- nsmap={"soap": NAMESPACE_SOAP}, #"xsi": NAMESPACE_XSI, "xsd": NAMESPACE_XSD,
+ nsmap={"xsi": NAMESPACE_XSI, "xsd": NAMESPACE_XSD, "soap": NAMESPACE_SOAP},
)
if self._header:
From 00abf31283a751e28f52d7b06e8f4f0d7742066b Mon Sep 17 00:00:00 2001
From: Hanna Tiharu <129420244+HannaTiharu@users.noreply.github.com>
Date: Thu, 20 Feb 2025 22:08:17 -0300
Subject: [PATCH 016/175] fix(main): fix
---
pynfe/processamento/serializacao.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pynfe/processamento/serializacao.py b/pynfe/processamento/serializacao.py
index c5a1c69b..f90ff89f 100644
--- a/pynfe/processamento/serializacao.py
+++ b/pynfe/processamento/serializacao.py
@@ -2019,7 +2019,7 @@ def serializar_evento_mdfe(
def serializar_evento_cte(self, evento, tag_raiz="eventoCTe", retorna_string=False):
tz = datetime.now().astimezone().strftime("%z")
tz = "{}:{}".format(tz[:-2], tz[-2:])
- raiz = etree.Element(tag_raiz, versao="4.00", xmlns=NAMESPACE_CTE)
+ raiz = etree.Element(tag_raiz, versao="4.0", xmlns=NAMESPACE_CTE)
e = etree.SubElement(raiz, "infEvento", Id=evento.identificador)
etree.SubElement(e, "cOrgao").text = CODIGOS_ESTADOS[evento.uf.upper()]
etree.SubElement(e, "tpAmb").text = str(self._ambiente)
@@ -2033,7 +2033,7 @@ def serializar_evento_cte(self, evento, tag_raiz="eventoCTe", retorna_string=Fal
)
etree.SubElement(e, "tpEvento").text = evento.tp_evento
etree.SubElement(e, "nSeqEvento").text = str(evento.n_seq_evento)
- det = etree.SubElement(e, "detEvento", versaoEvento="4.00")
+ det = etree.SubElement(e, "detEvento", versaoEvento="4.0")
# EVENTOS COMENTADOS NÂO TESTADOS
# if evento.descricao == "Comprovante de Entrega do CT-e":
# etree.Subelement(det, "nProt").text = evento.protocolo
From 2be1cb81fe964d89e5bddec55329cbb751aa5ab6 Mon Sep 17 00:00:00 2001
From: Hanna Tiharu <129420244+HannaTiharu@users.noreply.github.com>
Date: Thu, 20 Feb 2025 23:09:19 -0300
Subject: [PATCH 017/175] fix(main): added namespaces
---
pynfe/processamento/comunicacao.py | 4 ++--
pynfe/processamento/serializacao.py | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 30c4d475..2b49e1fb 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -16,6 +16,7 @@
NAMESPACE_MDFE_METODO,
NAMESPACE_METODO,
NAMESPACE_NFE,
+ NAMESPACE_SIG,
NAMESPACE_SOAP,
NAMESPACE_XSD,
NAMESPACE_XSI,
@@ -1343,9 +1344,8 @@ def _construir_xml_soap(self, metodo, dados, cabecalho=False):
raiz = etree.Element(
"{%s}Envelope" % NAMESPACE_SOAP,
- nsmap={"xsi": NAMESPACE_XSI, "xsd": NAMESPACE_XSD, "soap": NAMESPACE_SOAP},
+ nsmap={"ds": NAMESPACE_SIG, "xs": NAMESPACE_XSD, "soap": NAMESPACE_SOAP}, #"xsi": NAMESPACE_XSI, "xsd": NAMESPACE_XSD
)
-
if self._header:
cabecalho = self._cabecalho_soap(metodo)
c = etree.SubElement(raiz, "{%s}Header" % self._namespace_soap)
diff --git a/pynfe/processamento/serializacao.py b/pynfe/processamento/serializacao.py
index f90ff89f..80acd593 100644
--- a/pynfe/processamento/serializacao.py
+++ b/pynfe/processamento/serializacao.py
@@ -2019,7 +2019,7 @@ def serializar_evento_mdfe(
def serializar_evento_cte(self, evento, tag_raiz="eventoCTe", retorna_string=False):
tz = datetime.now().astimezone().strftime("%z")
tz = "{}:{}".format(tz[:-2], tz[-2:])
- raiz = etree.Element(tag_raiz, versao="4.0", xmlns=NAMESPACE_CTE)
+ raiz = etree.Element(tag_raiz, versao="4.0", xmlns=NAMESPACE_CTE, xmlns_ds=NAMESPACE_SIG)
e = etree.SubElement(raiz, "infEvento", Id=evento.identificador)
etree.SubElement(e, "cOrgao").text = CODIGOS_ESTADOS[evento.uf.upper()]
etree.SubElement(e, "tpAmb").text = str(self._ambiente)
From f6cc144831e0b2430b3c86ea34bbcf2cd310850b Mon Sep 17 00:00:00 2001
From: Hanna Tiharu <129420244+HannaTiharu@users.noreply.github.com>
Date: Thu, 20 Feb 2025 23:35:16 -0300
Subject: [PATCH 018/175] fix(main): added any tag at det
---
pynfe/processamento/serializacao.py | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/pynfe/processamento/serializacao.py b/pynfe/processamento/serializacao.py
index 80acd593..d92cd38a 100644
--- a/pynfe/processamento/serializacao.py
+++ b/pynfe/processamento/serializacao.py
@@ -2019,7 +2019,7 @@ def serializar_evento_mdfe(
def serializar_evento_cte(self, evento, tag_raiz="eventoCTe", retorna_string=False):
tz = datetime.now().astimezone().strftime("%z")
tz = "{}:{}".format(tz[:-2], tz[-2:])
- raiz = etree.Element(tag_raiz, versao="4.0", xmlns=NAMESPACE_CTE, xmlns_ds=NAMESPACE_SIG)
+ raiz = etree.Element(tag_raiz, versao="4.00", xmlns=NAMESPACE_CTE, xmlns_ds=NAMESPACE_SIG)
e = etree.SubElement(raiz, "infEvento", Id=evento.identificador)
etree.SubElement(e, "cOrgao").text = CODIGOS_ESTADOS[evento.uf.upper()]
etree.SubElement(e, "tpAmb").text = str(self._ambiente)
@@ -2033,7 +2033,8 @@ def serializar_evento_cte(self, evento, tag_raiz="eventoCTe", retorna_string=Fal
)
etree.SubElement(e, "tpEvento").text = evento.tp_evento
etree.SubElement(e, "nSeqEvento").text = str(evento.n_seq_evento)
- det = etree.SubElement(e, "detEvento", versaoEvento="4.0")
+ det = etree.SubElement(e, "detEvento", versaoEvento="4.00")
+ det_any = etree.SubElement(det, "any")
# EVENTOS COMENTADOS NÂO TESTADOS
# if evento.descricao == "Comprovante de Entrega do CT-e":
# etree.Subelement(det, "nProt").text = evento.protocolo
@@ -2049,7 +2050,7 @@ def serializar_evento_cte(self, evento, tag_raiz="eventoCTe", retorna_string=Fal
# inf_entrega = etree.SubElement(det, "infEntrega") #apenas para CT-e com tipo de serviço Normal
# etree.SubElement(inf_entrega, "chNFe").text = evento.chave_acesso #chave de acesso da NF-e entregue
if evento.descricao == "Cancelamento do Comprovante de Entrega do CT-e":
- cancelamento = etree.SubElement(det, "evCancCECTe")
+ cancelamento = etree.SubElement(det_any, "evCancCECTe")
etree.SubElement(cancelamento, "descEvento").text = evento.descricao
etree.SubElement(cancelamento, "nProt").text = evento.protocolo #Número do Protocolo de autorização do CT-e
etree.SubElement(cancelamento, "nProtCE").text = evento.protocolo_evento #Número do Protocolo de autorização do evento a ser cancelado
@@ -2076,17 +2077,17 @@ def serializar_evento_cte(self, evento, tag_raiz="eventoCTe", retorna_string=Fal
# inf_entrega = etree.SubElement(det, "infEntrega") #apenas para CT-e com tipo de serviço Normal
# etree.SubElement(inf_entrega, "chNFe").text = evento.chave_acesso #chave de acesso da NF-e com insucesso na entrega
elif evento.descricao == "Cancelamento do Insucesso de Entrega do CT-e":
- cancelamento = etree.SubElement(det, "evCancIECTe")
+ cancelamento = etree.SubElement(det_any, "evCancIECTe")
etree.SubElement(cancelamento, "descEvento").text = evento.descricao
etree.SubElement(cancelamento, "nProt").text = evento.protocolo
etree.SubElement(cancelamento, "nProtIE").text = evento.protocolo_evento
elif evento.descricao == "Prestação do Serviço em Desacordo":
- desacordo = etree.SubElement(det, "evPrestDesacordo")
+ desacordo = etree.SubElement(det_any, "evPrestDesacordo")
etree.SubElement(desacordo, "descEvento").text = evento.descricao
etree.SubElement(desacordo, "indDesacordoOper").text = "1" #Indicador de operação em desacordo
etree.SubElement(desacordo, "xObs").text = evento.observacao
elif evento.descricao == "Cancelamento Prestação do Serviço em Desacordo":
- cancelamento = etree.SubElement(det, "evCancPrestDesacordo")
+ cancelamento = etree.SubElement(det_any, "evCancPrestDesacordo")
etree.SubElement(cancelamento, "descEvento").text = evento.descricao
etree.SubElement(cancelamento, "nProtEvPrestDes").text = evento.protocolo_evento
From 646f241852e5108d268f7b00c6030f33427630c9 Mon Sep 17 00:00:00 2001
From: Hanna Tiharu <129420244+HannaTiharu@users.noreply.github.com>
Date: Fri, 21 Feb 2025 08:16:53 -0300
Subject: [PATCH 019/175] fix(main): added namespace to det event
---
pynfe/processamento/comunicacao.py | 2 +-
pynfe/processamento/serializacao.py | 9 ++++-----
2 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 2b49e1fb..a5a20a1a 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -1344,7 +1344,7 @@ def _construir_xml_soap(self, metodo, dados, cabecalho=False):
raiz = etree.Element(
"{%s}Envelope" % NAMESPACE_SOAP,
- nsmap={"ds": NAMESPACE_SIG, "xs": NAMESPACE_XSD, "soap": NAMESPACE_SOAP}, #"xsi": NAMESPACE_XSI, "xsd": NAMESPACE_XSD
+ nsmap={"xsi": NAMESPACE_XSI, "xsd": NAMESPACE_XSD, "soap": NAMESPACE_SOAP},
)
if self._header:
cabecalho = self._cabecalho_soap(metodo)
diff --git a/pynfe/processamento/serializacao.py b/pynfe/processamento/serializacao.py
index d92cd38a..a1005c74 100644
--- a/pynfe/processamento/serializacao.py
+++ b/pynfe/processamento/serializacao.py
@@ -2034,7 +2034,6 @@ def serializar_evento_cte(self, evento, tag_raiz="eventoCTe", retorna_string=Fal
etree.SubElement(e, "tpEvento").text = evento.tp_evento
etree.SubElement(e, "nSeqEvento").text = str(evento.n_seq_evento)
det = etree.SubElement(e, "detEvento", versaoEvento="4.00")
- det_any = etree.SubElement(det, "any")
# EVENTOS COMENTADOS NÂO TESTADOS
# if evento.descricao == "Comprovante de Entrega do CT-e":
# etree.Subelement(det, "nProt").text = evento.protocolo
@@ -2050,7 +2049,7 @@ def serializar_evento_cte(self, evento, tag_raiz="eventoCTe", retorna_string=Fal
# inf_entrega = etree.SubElement(det, "infEntrega") #apenas para CT-e com tipo de serviço Normal
# etree.SubElement(inf_entrega, "chNFe").text = evento.chave_acesso #chave de acesso da NF-e entregue
if evento.descricao == "Cancelamento do Comprovante de Entrega do CT-e":
- cancelamento = etree.SubElement(det_any, "evCancCECTe")
+ cancelamento = etree.SubElement(det, "evCancCECTe", xmlns = NAMESPACE_CTE)
etree.SubElement(cancelamento, "descEvento").text = evento.descricao
etree.SubElement(cancelamento, "nProt").text = evento.protocolo #Número do Protocolo de autorização do CT-e
etree.SubElement(cancelamento, "nProtCE").text = evento.protocolo_evento #Número do Protocolo de autorização do evento a ser cancelado
@@ -2077,17 +2076,17 @@ def serializar_evento_cte(self, evento, tag_raiz="eventoCTe", retorna_string=Fal
# inf_entrega = etree.SubElement(det, "infEntrega") #apenas para CT-e com tipo de serviço Normal
# etree.SubElement(inf_entrega, "chNFe").text = evento.chave_acesso #chave de acesso da NF-e com insucesso na entrega
elif evento.descricao == "Cancelamento do Insucesso de Entrega do CT-e":
- cancelamento = etree.SubElement(det_any, "evCancIECTe")
+ cancelamento = etree.SubElement(det, "evCancIECTe", xmlns = NAMESPACE_CTE)
etree.SubElement(cancelamento, "descEvento").text = evento.descricao
etree.SubElement(cancelamento, "nProt").text = evento.protocolo
etree.SubElement(cancelamento, "nProtIE").text = evento.protocolo_evento
elif evento.descricao == "Prestação do Serviço em Desacordo":
- desacordo = etree.SubElement(det_any, "evPrestDesacordo")
+ desacordo = etree.SubElement(det, "evPrestDesacordo", xmlns = NAMESPACE_CTE)
etree.SubElement(desacordo, "descEvento").text = evento.descricao
etree.SubElement(desacordo, "indDesacordoOper").text = "1" #Indicador de operação em desacordo
etree.SubElement(desacordo, "xObs").text = evento.observacao
elif evento.descricao == "Cancelamento Prestação do Serviço em Desacordo":
- cancelamento = etree.SubElement(det_any, "evCancPrestDesacordo")
+ cancelamento = etree.SubElement(det, "evCancPrestDesacordo", xmlns = NAMESPACE_CTE)
etree.SubElement(cancelamento, "descEvento").text = evento.descricao
etree.SubElement(cancelamento, "nProtEvPrestDes").text = evento.protocolo_evento
From 476b2ef2e4a479be72c2c515a3af3fb109f23dd2 Mon Sep 17 00:00:00 2001
From: Hanna Tiharu <129420244+HannaTiharu@users.noreply.github.com>
Date: Fri, 21 Feb 2025 08:20:42 -0300
Subject: [PATCH 020/175] fix(main): namespace ds to event nsmap
---
pynfe/processamento/serializacao.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pynfe/processamento/serializacao.py b/pynfe/processamento/serializacao.py
index a1005c74..aa0a4d49 100644
--- a/pynfe/processamento/serializacao.py
+++ b/pynfe/processamento/serializacao.py
@@ -2019,7 +2019,7 @@ def serializar_evento_mdfe(
def serializar_evento_cte(self, evento, tag_raiz="eventoCTe", retorna_string=False):
tz = datetime.now().astimezone().strftime("%z")
tz = "{}:{}".format(tz[:-2], tz[-2:])
- raiz = etree.Element(tag_raiz, versao="4.00", xmlns=NAMESPACE_CTE, xmlns_ds=NAMESPACE_SIG)
+ raiz = etree.Element(tag_raiz, versao="4.00", nsmap={None: NAMESPACE_CTE, "ds": NAMESPACE_SIG})
e = etree.SubElement(raiz, "infEvento", Id=evento.identificador)
etree.SubElement(e, "cOrgao").text = CODIGOS_ESTADOS[evento.uf.upper()]
etree.SubElement(e, "tpAmb").text = str(self._ambiente)
From a7c6384dff15b252c1d565a6f17bb630a91b5720 Mon Sep 17 00:00:00 2001
From: Hanna Tiharu <129420244+HannaTiharu@users.noreply.github.com>
Date: Fri, 21 Feb 2025 08:33:07 -0300
Subject: [PATCH 021/175] fix(main): removed header of soap
---
pynfe/processamento/comunicacao.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index a5a20a1a..e38d82a8 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -1346,10 +1346,10 @@ def _construir_xml_soap(self, metodo, dados, cabecalho=False):
"{%s}Envelope" % NAMESPACE_SOAP,
nsmap={"xsi": NAMESPACE_XSI, "xsd": NAMESPACE_XSD, "soap": NAMESPACE_SOAP},
)
- if self._header:
- cabecalho = self._cabecalho_soap(metodo)
- c = etree.SubElement(raiz, "{%s}Header" % self._namespace_soap)
- c.append(cabecalho)
+ # if self._header:
+ # cabecalho = self._cabecalho_soap(metodo)
+ # c = etree.SubElement(raiz, "{%s}Header" % self._namespace_soap)
+ # c.append(cabecalho)
body = etree.SubElement(raiz, "{%s}Body" % NAMESPACE_SOAP)
# distribuição tem um corpo de xml diferente
From baf91abfd8b902a4546aac2d393b61fead603af1 Mon Sep 17 00:00:00 2001
From: Hanna Tiharu <129420244+HannaTiharu@users.noreply.github.com>
Date: Fri, 21 Feb 2025 08:46:33 -0300
Subject: [PATCH 022/175] fix(main): nsmap at the det event
---
pynfe/processamento/serializacao.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/pynfe/processamento/serializacao.py b/pynfe/processamento/serializacao.py
index aa0a4d49..ae5ab3e2 100644
--- a/pynfe/processamento/serializacao.py
+++ b/pynfe/processamento/serializacao.py
@@ -2049,7 +2049,7 @@ def serializar_evento_cte(self, evento, tag_raiz="eventoCTe", retorna_string=Fal
# inf_entrega = etree.SubElement(det, "infEntrega") #apenas para CT-e com tipo de serviço Normal
# etree.SubElement(inf_entrega, "chNFe").text = evento.chave_acesso #chave de acesso da NF-e entregue
if evento.descricao == "Cancelamento do Comprovante de Entrega do CT-e":
- cancelamento = etree.SubElement(det, "evCancCECTe", xmlns = NAMESPACE_CTE)
+ cancelamento = etree.SubElement(det, "evCancCECTe", nsmap={None: NAMESPACE_CTE})
etree.SubElement(cancelamento, "descEvento").text = evento.descricao
etree.SubElement(cancelamento, "nProt").text = evento.protocolo #Número do Protocolo de autorização do CT-e
etree.SubElement(cancelamento, "nProtCE").text = evento.protocolo_evento #Número do Protocolo de autorização do evento a ser cancelado
@@ -2076,17 +2076,17 @@ def serializar_evento_cte(self, evento, tag_raiz="eventoCTe", retorna_string=Fal
# inf_entrega = etree.SubElement(det, "infEntrega") #apenas para CT-e com tipo de serviço Normal
# etree.SubElement(inf_entrega, "chNFe").text = evento.chave_acesso #chave de acesso da NF-e com insucesso na entrega
elif evento.descricao == "Cancelamento do Insucesso de Entrega do CT-e":
- cancelamento = etree.SubElement(det, "evCancIECTe", xmlns = NAMESPACE_CTE)
+ cancelamento = etree.SubElement(det, "evCancIECTe", nsmap={None: NAMESPACE_CTE})
etree.SubElement(cancelamento, "descEvento").text = evento.descricao
etree.SubElement(cancelamento, "nProt").text = evento.protocolo
etree.SubElement(cancelamento, "nProtIE").text = evento.protocolo_evento
elif evento.descricao == "Prestação do Serviço em Desacordo":
- desacordo = etree.SubElement(det, "evPrestDesacordo", xmlns = NAMESPACE_CTE)
+ desacordo = etree.SubElement(det, "evPrestDesacordo", nsmap={None: NAMESPACE_CTE})
etree.SubElement(desacordo, "descEvento").text = evento.descricao
etree.SubElement(desacordo, "indDesacordoOper").text = "1" #Indicador de operação em desacordo
etree.SubElement(desacordo, "xObs").text = evento.observacao
elif evento.descricao == "Cancelamento Prestação do Serviço em Desacordo":
- cancelamento = etree.SubElement(det, "evCancPrestDesacordo", xmlns = NAMESPACE_CTE)
+ cancelamento = etree.SubElement(det, "evCancPrestDesacordo", nsmap={None: NAMESPACE_CTE})
etree.SubElement(cancelamento, "descEvento").text = evento.descricao
etree.SubElement(cancelamento, "nProtEvPrestDes").text = evento.protocolo_evento
From a6dadcaa560f743532a4b8c4b58101f93d798c8b Mon Sep 17 00:00:00 2001
From: Hanna Tiharu <129420244+HannaTiharu@users.noreply.github.com>
Date: Fri, 21 Feb 2025 09:05:53 -0300
Subject: [PATCH 023/175] fix(main): fix
---
pynfe/processamento/serializacao.py | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/pynfe/processamento/serializacao.py b/pynfe/processamento/serializacao.py
index ae5ab3e2..999394fd 100644
--- a/pynfe/processamento/serializacao.py
+++ b/pynfe/processamento/serializacao.py
@@ -2033,7 +2033,7 @@ def serializar_evento_cte(self, evento, tag_raiz="eventoCTe", retorna_string=Fal
)
etree.SubElement(e, "tpEvento").text = evento.tp_evento
etree.SubElement(e, "nSeqEvento").text = str(evento.n_seq_evento)
- det = etree.SubElement(e, "detEvento", versaoEvento="4.00")
+ det = etree.SubElement(e, "detEvento", versaoEvento="4.00", nsmap={None:NAMESPACE_CTE })
# EVENTOS COMENTADOS NÂO TESTADOS
# if evento.descricao == "Comprovante de Entrega do CT-e":
# etree.Subelement(det, "nProt").text = evento.protocolo
@@ -2049,7 +2049,7 @@ def serializar_evento_cte(self, evento, tag_raiz="eventoCTe", retorna_string=Fal
# inf_entrega = etree.SubElement(det, "infEntrega") #apenas para CT-e com tipo de serviço Normal
# etree.SubElement(inf_entrega, "chNFe").text = evento.chave_acesso #chave de acesso da NF-e entregue
if evento.descricao == "Cancelamento do Comprovante de Entrega do CT-e":
- cancelamento = etree.SubElement(det, "evCancCECTe", nsmap={None: NAMESPACE_CTE})
+ cancelamento = etree.SubElement(det, "evCancCECTe")
etree.SubElement(cancelamento, "descEvento").text = evento.descricao
etree.SubElement(cancelamento, "nProt").text = evento.protocolo #Número do Protocolo de autorização do CT-e
etree.SubElement(cancelamento, "nProtCE").text = evento.protocolo_evento #Número do Protocolo de autorização do evento a ser cancelado
@@ -2076,17 +2076,17 @@ def serializar_evento_cte(self, evento, tag_raiz="eventoCTe", retorna_string=Fal
# inf_entrega = etree.SubElement(det, "infEntrega") #apenas para CT-e com tipo de serviço Normal
# etree.SubElement(inf_entrega, "chNFe").text = evento.chave_acesso #chave de acesso da NF-e com insucesso na entrega
elif evento.descricao == "Cancelamento do Insucesso de Entrega do CT-e":
- cancelamento = etree.SubElement(det, "evCancIECTe", nsmap={None: NAMESPACE_CTE})
+ cancelamento = etree.SubElement(det, "evCancIECTe")
etree.SubElement(cancelamento, "descEvento").text = evento.descricao
etree.SubElement(cancelamento, "nProt").text = evento.protocolo
etree.SubElement(cancelamento, "nProtIE").text = evento.protocolo_evento
elif evento.descricao == "Prestação do Serviço em Desacordo":
- desacordo = etree.SubElement(det, "evPrestDesacordo", nsmap={None: NAMESPACE_CTE})
+ desacordo = etree.SubElement(det, "evPrestDesacordo", nsmap={None:NAMESPACE_CTE})
etree.SubElement(desacordo, "descEvento").text = evento.descricao
etree.SubElement(desacordo, "indDesacordoOper").text = "1" #Indicador de operação em desacordo
etree.SubElement(desacordo, "xObs").text = evento.observacao
elif evento.descricao == "Cancelamento Prestação do Serviço em Desacordo":
- cancelamento = etree.SubElement(det, "evCancPrestDesacordo", nsmap={None: NAMESPACE_CTE})
+ cancelamento = etree.SubElement(det, "evCancPrestDesacordo")
etree.SubElement(cancelamento, "descEvento").text = evento.descricao
etree.SubElement(cancelamento, "nProtEvPrestDes").text = evento.protocolo_evento
From 9cefedef6741375dc4b6c17499dabb51b1102b47 Mon Sep 17 00:00:00 2001
From: Hanna Tiharu <129420244+HannaTiharu@users.noreply.github.com>
Date: Fri, 21 Feb 2025 11:08:00 -0300
Subject: [PATCH 024/175] fix(main): fix
---
pynfe/processamento/comunicacao.py | 15 +++------------
pynfe/processamento/serializacao.py | 6 +++---
2 files changed, 6 insertions(+), 15 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index e38d82a8..d0de12ad 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -1344,7 +1344,7 @@ def _construir_xml_soap(self, metodo, dados, cabecalho=False):
raiz = etree.Element(
"{%s}Envelope" % NAMESPACE_SOAP,
- nsmap={"xsi": NAMESPACE_XSI, "xsd": NAMESPACE_XSD, "soap": NAMESPACE_SOAP},
+ nsmap={"soap": NAMESPACE_SOAP, "xsi": NAMESPACE_XSI, "xsd": NAMESPACE_XSD},
)
# if self._header:
# cabecalho = self._cabecalho_soap(metodo)
@@ -1352,17 +1352,8 @@ def _construir_xml_soap(self, metodo, dados, cabecalho=False):
# c.append(cabecalho)
body = etree.SubElement(raiz, "{%s}Body" % NAMESPACE_SOAP)
- # distribuição tem um corpo de xml diferente
- if metodo == "CTeDistribuicaoDFe":
- x = etree.SubElement(
- body, "cteDistDFeInteresse", xmlns=NAMESPACE_CTE_METODO + metodo
- )
- a = etree.SubElement(x, "cteDadosMsg")
- else:
- a = etree.SubElement(
- body, "cteDadosMsg", xmlns=NAMESPACE_CTE_METODO + metodo
- )
- a.append(dados)
+ cte_dados_msg = etree.SubElement(body, "cteDadosMsg", xmlns=NAMESPACE_CTE_METODO + metodo)
+ cte_dados_msg.append(dados)
return raiz
def _post_header(self):
diff --git a/pynfe/processamento/serializacao.py b/pynfe/processamento/serializacao.py
index 999394fd..15f1848b 100644
--- a/pynfe/processamento/serializacao.py
+++ b/pynfe/processamento/serializacao.py
@@ -2019,7 +2019,7 @@ def serializar_evento_mdfe(
def serializar_evento_cte(self, evento, tag_raiz="eventoCTe", retorna_string=False):
tz = datetime.now().astimezone().strftime("%z")
tz = "{}:{}".format(tz[:-2], tz[-2:])
- raiz = etree.Element(tag_raiz, versao="4.00", nsmap={None: NAMESPACE_CTE, "ds": NAMESPACE_SIG})
+ raiz = etree.Element(tag_raiz, versao="4.00", nsmap={None: NAMESPACE_CTE})
e = etree.SubElement(raiz, "infEvento", Id=evento.identificador)
etree.SubElement(e, "cOrgao").text = CODIGOS_ESTADOS[evento.uf.upper()]
etree.SubElement(e, "tpAmb").text = str(self._ambiente)
@@ -2033,7 +2033,7 @@ def serializar_evento_cte(self, evento, tag_raiz="eventoCTe", retorna_string=Fal
)
etree.SubElement(e, "tpEvento").text = evento.tp_evento
etree.SubElement(e, "nSeqEvento").text = str(evento.n_seq_evento)
- det = etree.SubElement(e, "detEvento", versaoEvento="4.00", nsmap={None:NAMESPACE_CTE })
+ det = etree.SubElement(e, "detEvento", versaoEvento="4.00")
# EVENTOS COMENTADOS NÂO TESTADOS
# if evento.descricao == "Comprovante de Entrega do CT-e":
# etree.Subelement(det, "nProt").text = evento.protocolo
@@ -2081,7 +2081,7 @@ def serializar_evento_cte(self, evento, tag_raiz="eventoCTe", retorna_string=Fal
etree.SubElement(cancelamento, "nProt").text = evento.protocolo
etree.SubElement(cancelamento, "nProtIE").text = evento.protocolo_evento
elif evento.descricao == "Prestação do Serviço em Desacordo":
- desacordo = etree.SubElement(det, "evPrestDesacordo", nsmap={None:NAMESPACE_CTE})
+ desacordo = etree.SubElement(det, "evPrestDesacordo")
etree.SubElement(desacordo, "descEvento").text = evento.descricao
etree.SubElement(desacordo, "indDesacordoOper").text = "1" #Indicador de operação em desacordo
etree.SubElement(desacordo, "xObs").text = evento.observacao
From 0ff50493dfe011697b1c453ba027394df01da6e8 Mon Sep 17 00:00:00 2001
From: Hanna Tiharu <129420244+HannaTiharu@users.noreply.github.com>
Date: Fri, 21 Feb 2025 12:16:50 -0300
Subject: [PATCH 025/175] fix(main): comment soap namespace
---
pynfe/processamento/comunicacao.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index d0de12ad..dacef75a 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -1344,7 +1344,7 @@ def _construir_xml_soap(self, metodo, dados, cabecalho=False):
raiz = etree.Element(
"{%s}Envelope" % NAMESPACE_SOAP,
- nsmap={"soap": NAMESPACE_SOAP, "xsi": NAMESPACE_XSI, "xsd": NAMESPACE_XSD},
+ # nsmap={"soap": NAMESPACE_SOAP, "xsi": NAMESPACE_XSI, "xsd": NAMESPACE_XSD},
)
# if self._header:
# cabecalho = self._cabecalho_soap(metodo)
From 15d0940e78f0c7d6e61cb7ba021f1a3cb08cd6e2 Mon Sep 17 00:00:00 2001
From: Hanna Tiharu <129420244+HannaTiharu@users.noreply.github.com>
Date: Fri, 21 Feb 2025 12:45:48 -0300
Subject: [PATCH 026/175] main(fix): fix
---
pynfe/processamento/comunicacao.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index dacef75a..54e6f9bf 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -1344,7 +1344,7 @@ def _construir_xml_soap(self, metodo, dados, cabecalho=False):
raiz = etree.Element(
"{%s}Envelope" % NAMESPACE_SOAP,
- # nsmap={"soap": NAMESPACE_SOAP, "xsi": NAMESPACE_XSI, "xsd": NAMESPACE_XSD},
+ nsmap={"soap12": NAMESPACE_SOAP, "xsi": NAMESPACE_XSI, "xsd": NAMESPACE_XSD},
)
# if self._header:
# cabecalho = self._cabecalho_soap(metodo)
From fdafa162adf53f722d9f229413fbc71abbeff7aa Mon Sep 17 00:00:00 2001
From: Hanna Tiharu <129420244+HannaTiharu@users.noreply.github.com>
Date: Fri, 21 Feb 2025 14:22:09 -0300
Subject: [PATCH 027/175] fix(main): id fixed
---
pynfe/entidades/evento.py | 13 +++++++++++++
pynfe/processamento/serializacao.py | 2 +-
2 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/pynfe/entidades/evento.py b/pynfe/entidades/evento.py
index bfd100f9..d75d4adf 100644
--- a/pynfe/entidades/evento.py
+++ b/pynfe/entidades/evento.py
@@ -44,6 +44,19 @@ def identificador(self):
"n_seq_evento": str(self.n_seq_evento).zfill(2),
}
return self.id
+
+ def identificador_cte(self):
+ """
+ Gera o valor para o campo id
+ A regra de formação do Id é: “ID” + tpEvento + chave da NF-e + nSeqEvento
+ O n_seq_evento pra eventos de cte tem 3 digitos
+ """
+ self.id = "ID%(tp_evento)s%(chave)s%(n_seq_evento)s" % {
+ "tp_evento": self.tp_evento,
+ "chave": self.chave,
+ "n_seq_evento": str(self.n_seq_evento).zfill(3),
+ }
+ return self.id
class EventoCancelarNota(Evento):
diff --git a/pynfe/processamento/serializacao.py b/pynfe/processamento/serializacao.py
index 15f1848b..95cd329e 100644
--- a/pynfe/processamento/serializacao.py
+++ b/pynfe/processamento/serializacao.py
@@ -2020,7 +2020,7 @@ def serializar_evento_cte(self, evento, tag_raiz="eventoCTe", retorna_string=Fal
tz = datetime.now().astimezone().strftime("%z")
tz = "{}:{}".format(tz[:-2], tz[-2:])
raiz = etree.Element(tag_raiz, versao="4.00", nsmap={None: NAMESPACE_CTE})
- e = etree.SubElement(raiz, "infEvento", Id=evento.identificador)
+ e = etree.SubElement(raiz, "infEvento", Id=evento.identificador_cte)
etree.SubElement(e, "cOrgao").text = CODIGOS_ESTADOS[evento.uf.upper()]
etree.SubElement(e, "tpAmb").text = str(self._ambiente)
if len(so_numeros(evento.cnpj)) == 11:
From 02bd42b2875aa6c43df028fba6cff7e85f5e31b7 Mon Sep 17 00:00:00 2001
From: Hanna Tiharu <129420244+HannaTiharu@users.noreply.github.com>
Date: Fri, 21 Feb 2025 14:23:04 -0300
Subject: [PATCH 028/175] fix(main): property of id
---
pynfe/entidades/evento.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/pynfe/entidades/evento.py b/pynfe/entidades/evento.py
index d75d4adf..6df24b67 100644
--- a/pynfe/entidades/evento.py
+++ b/pynfe/entidades/evento.py
@@ -45,6 +45,7 @@ def identificador(self):
}
return self.id
+ @property
def identificador_cte(self):
"""
Gera o valor para o campo id
From a62cf713d591644a79099d2b1200fa3149d009de Mon Sep 17 00:00:00 2001
From: Hanna Tiharu <129420244+HannaTiharu@users.noreply.github.com>
Date: Fri, 21 Feb 2025 14:34:36 -0300
Subject: [PATCH 029/175] fix(main): fix namespace
---
pynfe/processamento/comunicacao.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 54e6f9bf..d0de12ad 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -1344,7 +1344,7 @@ def _construir_xml_soap(self, metodo, dados, cabecalho=False):
raiz = etree.Element(
"{%s}Envelope" % NAMESPACE_SOAP,
- nsmap={"soap12": NAMESPACE_SOAP, "xsi": NAMESPACE_XSI, "xsd": NAMESPACE_XSD},
+ nsmap={"soap": NAMESPACE_SOAP, "xsi": NAMESPACE_XSI, "xsd": NAMESPACE_XSD},
)
# if self._header:
# cabecalho = self._cabecalho_soap(metodo)
From 96d2c6b45cf47c1af3493428c65738f106d45963 Mon Sep 17 00:00:00 2001
From: Hanna Tiharu <129420244+HannaTiharu@users.noreply.github.com>
Date: Fri, 21 Feb 2025 15:36:10 -0300
Subject: [PATCH 030/175] feat(main): added webservices url to eventos
---
pynfe/utils/webservices.py | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/pynfe/utils/webservices.py b/pynfe/utils/webservices.py
index 91f2f0f0..0f041f42 100644
--- a/pynfe/utils/webservices.py
+++ b/pynfe/utils/webservices.py
@@ -551,26 +551,31 @@
"HOMOLOGACAO": "https://hom1",
},
"MT": {
+ "EVENTOS": "sefaz.mt.gov.br/ctews2/services/CTeRecepcaoEventoV4?wsdl"
"STATUS": "sefaz.mt.gov.br/ctews/services/CteStatusServico",
"HTTPS": "https://cte.",
"HOMOLOGACAO": "https://homologacao.",
},
"MS": {
+ "EVENTOS": "cte.ms.gov.br/ws/CTeRecepcaoEventoV4",
"STATUS": "cte.ms.gov.br/ws/CteStatusServico",
"HTTPS": "https://producao.",
"HOMOLOGACAO": "https://homologacao.",
},
"MG": {
+ "EVENTOS": "fazenda.mg.gov.br/cte/services/CTeRecepcaoEventoV4",
"STATUS": "fazenda.mg.gov.br/cte/services/CteStatusServico",
"HTTPS": "https://cte.",
"HOMOLOGACAO": "https://hcte.",
},
"PR": {
+ "EVENTOS": "fazenda.pr.gov.br/cte4/CTeRecepcaoEventoV4?wsdl",
"STATUS": "fazenda.pr.gov.br/cte/CteStatusServico?wsdl",
"HTTPS": "https://cte.",
"HOMOLOGACAO": "https://homologacao.",
},
"RS": {
+ "EVENTOS": "svrs.rs.gov.br/ws/CTeRecepcaoEventoV4/CTeRecepcaoEventoV4.asmx",
"STATUS": "svrs.rs.gov.br/ws/ctestatusservico/CteStatusServico.asmx",
"HTTPS": "https://cte.",
"HOMOLOGACAO": "https://cte-homologacao.",
@@ -582,11 +587,13 @@
"HOMOLOGACAO": "https://homologacao.nfe.",
},
"SVRS": {
+ "EVENTOS": "svrs.rs.gov.br/ws/CTeRecepcaoEventoV4/CTeRecepcaoEventoV4.asmx",
"STATUS": "svrs.rs.gov.br/ws/ctestatusservico/CteStatusServico.asmx",
"HTTPS": "https://cte.",
"HOMOLOGACAO": "https://cte-homologacao.",
},
"SVSP": {
+ "EVENTOS": "fazenda.sp.gov.br/CTeWS/WS/CTeRecepcaoEventoV4.asmx",
"STATUS": "fazenda.sp.gov.br/cteWEB/services/CteStatusServico.asmx",
"HTTPS": "https://nfe.",
"HOMOLOGACAO": "https://homologacao.nfe.",
From e79a9741e57fae9e616c7e41e21e0ce015f1b149 Mon Sep 17 00:00:00 2001
From: Hanna Tiharu <129420244+HannaTiharu@users.noreply.github.com>
Date: Fri, 21 Feb 2025 15:45:21 -0300
Subject: [PATCH 031/175] fix(main): added comma
---
pynfe/utils/webservices.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pynfe/utils/webservices.py b/pynfe/utils/webservices.py
index 0f041f42..17e96716 100644
--- a/pynfe/utils/webservices.py
+++ b/pynfe/utils/webservices.py
@@ -551,7 +551,7 @@
"HOMOLOGACAO": "https://hom1",
},
"MT": {
- "EVENTOS": "sefaz.mt.gov.br/ctews2/services/CTeRecepcaoEventoV4?wsdl"
+ "EVENTOS": "sefaz.mt.gov.br/ctews2/services/CTeRecepcaoEventoV4?wsdl",
"STATUS": "sefaz.mt.gov.br/ctews/services/CteStatusServico",
"HTTPS": "https://cte.",
"HOMOLOGACAO": "https://homologacao.",
From 60f3a2076ae3fe16d5a3892cb48034287a6336c5 Mon Sep 17 00:00:00 2001
From: Hanna Tiharu <129420244+HannaTiharu@users.noreply.github.com>
Date: Sat, 22 Feb 2025 14:45:28 -0300
Subject: [PATCH 032/175] fix(main): print url for debbug
---
pynfe/processamento/comunicacao.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index d0de12ad..3740cec1 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -1333,6 +1333,7 @@ def evento(self, evento):
# url do serviço
url = self._get_url("EVENTOS")
+ print(url)
# Monta XML do corpo da requisição
xml = self._construir_xml_soap("CTeRecepcaoEventoV4", evento)
From 9b908e57c68aedd44782f80685c785a0b34c403c Mon Sep 17 00:00:00 2001
From: Hanna Tiharu <129420244+HannaTiharu@users.noreply.github.com>
Date: Sat, 22 Feb 2025 14:57:55 -0300
Subject: [PATCH 033/175] fix(main): print uf to debug
---
pynfe/processamento/comunicacao.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 3740cec1..20ca2175 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -1269,6 +1269,7 @@ def _get_url(self, consulta):
# Estados que implementam webservices proprios
lista = ["MT", "MS", "MG", "PR", "RS", "SP"]
+ print(self.uf.upper())
if self.uf.upper() in lista:
if self._ambiente == 1:
ambiente = "HTTPS"
From c0e0abec003fa351adbfdc61ba76d22376213ffc Mon Sep 17 00:00:00 2001
From: Hanna Tiharu <129420244+HannaTiharu@users.noreply.github.com>
Date: Sat, 22 Feb 2025 15:26:03 -0300
Subject: [PATCH 034/175] fix(main): removed debugger prints
---
pynfe/processamento/comunicacao.py | 3 ---
1 file changed, 3 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 20ca2175..7edc7578 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -1269,7 +1269,6 @@ def _get_url(self, consulta):
# Estados que implementam webservices proprios
lista = ["MT", "MS", "MG", "PR", "RS", "SP"]
- print(self.uf.upper())
if self.uf.upper() in lista:
if self._ambiente == 1:
ambiente = "HTTPS"
@@ -1334,7 +1333,6 @@ def evento(self, evento):
# url do serviço
url = self._get_url("EVENTOS")
- print(url)
# Monta XML do corpo da requisição
xml = self._construir_xml_soap("CTeRecepcaoEventoV4", evento)
@@ -1387,7 +1385,6 @@ def _post(self, url, xml):
etree.tostring(xml, encoding="unicode").replace("\n", ""),
)
xml = xml_declaration + xml
- print(xml)
# Faz o request com o servidor
result = requests.post(
From 6dcabb996e7449f6ef23429cd8363f89c77ccd42 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Thu, 13 Mar 2025 11:57:09 -0300
Subject: [PATCH 035/175] fix: resolver bug
---
pynfe/processamento/comunicacao.py | 230 +++++++++++------------------
1 file changed, 88 insertions(+), 142 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 20ca2175..5e585bbf 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -3,7 +3,6 @@
import re
import requests
-
from pynfe.entidades.certificado import CertificadoA1
from pynfe.utils import etree, so_numeros
from pynfe.utils.flags import (
@@ -16,7 +15,6 @@
NAMESPACE_MDFE_METODO,
NAMESPACE_METODO,
NAMESPACE_NFE,
- NAMESPACE_SIG,
NAMESPACE_SOAP,
NAMESPACE_XSD,
NAMESPACE_XSI,
@@ -103,17 +101,11 @@ def autorizacao(
# Estados como GO vem com a tag header
inf_prot = prot[1][0]
- lote_status = inf_prot.xpath(
- "ns:retEnviNFe/ns:cStat", namespaces=ns
- )[0].text
+ lote_status = inf_prot.xpath("ns:retEnviNFe/ns:cStat", namespaces=ns)[0].text
# Lote processado
if lote_status == "104":
- prot_nfe = inf_prot.xpath(
- "ns:retEnviNFe/ns:protNFe", namespaces=ns
- )[0]
- status = prot_nfe.xpath("ns:infProt/ns:cStat", namespaces=ns)[
- 0
- ].text
+ prot_nfe = inf_prot.xpath("ns:retEnviNFe/ns:protNFe", namespaces=ns)[0]
+ status = prot_nfe.xpath("ns:infProt/ns:cStat", namespaces=ns)[0].text
# autorizado usa da NF-e
# retorna xml final (protNFe+NFe)
if status in ["100", "150"]:
@@ -132,9 +124,7 @@ def autorizacao(
status = rec.xpath("ns:retEnviNFe/ns:cStat", namespaces=ns)[0].text
# Lote Recebido com Sucesso!
if status == "103":
- nrec = rec.xpath("ns:retEnviNFe/ns:infRec/ns:nRec", namespaces=ns)[
- 0
- ].text
+ nrec = rec.xpath("ns:retEnviNFe/ns:infRec/ns:nRec", namespaces=ns)[0].text
return 0, nrec, nota_fiscal
return 1, retorno, nota_fiscal
@@ -239,7 +229,7 @@ def consulta_distribuicao(
return self._post(url, xml)
- def consulta_cadastro(self, modelo, documento, tipo='CNPJ', uf=None):
+ def consulta_cadastro(self, modelo, documento, tipo="CNPJ", uf=None):
"""
Consulta de cadastro
:param modelo: Modelo da nota
@@ -249,10 +239,24 @@ def consulta_cadastro(self, modelo, documento, tipo='CNPJ', uf=None):
:return:
"""
# UF que utilizam a SVRS - Sefaz Virtual do RS:
- lista_svrs = ["AC", "AL", "AP", "CE",
- "DF", "ES", "PA", "PB",
- "PI", "RJ", "RN", "RO",
- "RR", "SC", "SE", "TO"]
+ lista_svrs = [
+ "AC",
+ "AL",
+ "AP",
+ "CE",
+ "DF",
+ "ES",
+ "PA",
+ "PB",
+ "PI",
+ "RJ",
+ "RN",
+ "RO",
+ "RR",
+ "SC",
+ "SE",
+ "TO",
+ ]
# Se não informada UF nos parâmetros da função,
# utiliza a UF do construtor
@@ -275,10 +279,10 @@ def consulta_cadastro(self, modelo, documento, tipo='CNPJ', uf=None):
info = etree.SubElement(raiz, "infCons")
etree.SubElement(info, "xServ").text = "CONS-CAD"
etree.SubElement(info, "UF").text = uf.upper()
-
+
# Monta tipo de documento CNPJ, CPF ou IE
etree.SubElement(info, tipo.upper()).text = documento
-
+
# etree.SubElement(info, 'CPF').text = cpf
# Monta XML para envio da requisição
@@ -366,18 +370,15 @@ def inutilizacao(
# Identificador da TAG a ser assinada formada com Código da UF + Ano (2 posições) +
# CNPJ + modelo + série + nro inicial e nro final precedida do literal “ID”
- id_unico = (
- "ID%(uf)s%(ano)s%(cnpj)s%(modelo)s%(serie)s%(num_ini)s%(num_fin)s"
- % {
- "uf": uf,
- "ano": ano,
- "cnpj": cnpjcpf_chaveacesso,
- "modelo": "55" if modelo == "nfe" else "65", # 55=NF-e; 65=NFC-e;
- "serie": str(serie).zfill(3),
- "num_ini": str(numero_inicial).zfill(9),
- "num_fin": str(numero_final).zfill(9),
- }
- )
+ id_unico = "ID%(uf)s%(ano)s%(cnpj)s%(modelo)s%(serie)s%(num_ini)s%(num_fin)s" % {
+ "uf": uf,
+ "ano": ano,
+ "cnpj": cnpjcpf_chaveacesso,
+ "modelo": "55" if modelo == "nfe" else "65", # 55=NF-e; 65=NFC-e;
+ "serie": str(serie).zfill(3),
+ "num_ini": str(numero_inicial).zfill(9),
+ "num_fin": str(numero_final).zfill(9),
+ }
# Monta XML do corpo da requisição # FIXME
raiz = etree.Element("inutNFe", versao=VERSAO_PADRAO, xmlns=NAMESPACE_NFE)
@@ -458,9 +459,7 @@ def _get_url(self, modelo, consulta, contingencia=False):
# nfce Ex: https://homologacao.nfce.fazenda.pr.gov.br/nfce/NFeStatusServico3
self.url = NFCE["SVRS"][ambiente] + NFCE["SVRS"][consulta]
else:
- raise Exception(
- 'Modelo não encontrado! Defina modelo="nfe" ou "nfce"'
- )
+ raise Exception('Modelo não encontrado! Defina modelo="nfe" ou "nfce"')
elif self.uf.upper() in contingencia_svan:
if self._ambiente == 1:
ambiente = "HTTPS"
@@ -473,9 +472,7 @@ def _get_url(self, modelo, consulta, contingencia=False):
# nfce Ex: https://homologacao.nfce.fazenda.pr.gov.br/nfce/NFeStatusServico3
self.url = NFCE["SVRS"][ambiente] + NFCE["SVRS"][consulta]
else:
- raise Exception(
- 'Modelo não encontrado! Defina modelo="nfe" ou "nfce"'
- )
+ raise Exception('Modelo não encontrado! Defina modelo="nfe" ou "nfce"')
return self.url
# estado que implementam webservices proprios
@@ -491,19 +488,14 @@ def _get_url(self, modelo, consulta, contingencia=False):
self.url = NFE["SVRS"][ambiente] + NFE["SVRS"][consulta]
else:
# nfe Ex: https://nfe.fazenda.pr.gov.br/nfe/NFeStatusServico3
- self.url = (
- NFE[self.uf.upper()][ambiente] + NFE[self.uf.upper()][consulta]
- )
+ self.url = NFE[self.uf.upper()][ambiente] + NFE[self.uf.upper()][consulta]
elif modelo == "nfce":
# PE e BA são as únicas UF'sque possuem NFE proprio e SVRS para NFCe
if self.uf.upper() == "PE" or self.uf.upper() == "BA":
self.url = NFCE["SVRS"][ambiente] + NFCE["SVRS"][consulta]
else:
# nfce Ex: https://homologacao.nfce.fazenda.pr.gov.br/nfce/NFeStatusServico3
- self.url = (
- NFCE[self.uf.upper()][ambiente]
- + NFCE[self.uf.upper()][consulta]
- )
+ self.url = NFCE[self.uf.upper()][ambiente] + NFCE[self.uf.upper()][consulta]
else:
raise Exception('Modelo não encontrado! Defina modelo="nfe" ou "nfce"')
# Estados que utilizam outros ambientes
@@ -537,9 +529,7 @@ def _get_url(self, modelo, consulta, contingencia=False):
# nfce Ex: https://homologacao.nfce.fazenda.pr.gov.br/nfce/NFeStatusServico3
self.url = NFCE["SVRS"][ambiente] + NFCE["SVRS"][consulta]
else:
- raise Exception(
- 'Modelo não encontrado! Defina modelo="nfe" ou "nfce"'
- )
+ raise Exception('Modelo não encontrado! Defina modelo="nfe" ou "nfce"')
# unico UF que utiliza SVAN ainda para NF-e
# SVRS para NFC-e
elif self.uf.upper() == "MA":
@@ -554,13 +544,9 @@ def _get_url(self, modelo, consulta, contingencia=False):
# nfce Ex: https://homologacao.nfce.fazenda.pr.gov.br/nfce/NFeStatusServico3
self.url = NFCE["SVRS"][ambiente] + NFCE["SVRS"][consulta]
else:
- raise Exception(
- 'Modelo não encontrado! Defina modelo="nfe" ou "nfce"'
- )
+ raise Exception('Modelo não encontrado! Defina modelo="nfe" ou "nfce"')
else:
- raise Exception(
- f"Url não encontrada para {modelo} e {consulta} {self.uf.upper()}"
- )
+ raise Exception(f"Url não encontrada para {modelo} e {consulta} {self.uf.upper()}")
return self.url
def _construir_xml_soap(self, metodo, dados, cabecalho=False):
@@ -572,14 +558,10 @@ def _construir_xml_soap(self, metodo, dados, cabecalho=False):
body = etree.SubElement(raiz, "{%s}Body" % NAMESPACE_SOAP)
# distribuição tem um corpo de xml diferente
if metodo == "NFeDistribuicaoDFe":
- x = etree.SubElement(
- body, "nfeDistDFeInteresse", xmlns=NAMESPACE_METODO + metodo
- )
+ x = etree.SubElement(body, "nfeDistDFeInteresse", xmlns=NAMESPACE_METODO + metodo)
a = etree.SubElement(x, "nfeDadosMsg")
elif metodo == "CadConsultaCadastro4" and self.uf.upper() == "MT":
- x = etree.SubElement(
- body, "consultaCadastro", xmlns=NAMESPACE_METODO + metodo
- )
+ x = etree.SubElement(body, "consultaCadastro", xmlns=NAMESPACE_METODO + metodo)
a = etree.SubElement(x, "nfeDadosMsg")
else:
a = etree.SubElement(body, "nfeDadosMsg", xmlns=NAMESPACE_METODO + metodo)
@@ -599,9 +581,7 @@ def _post_header(self):
def _post(self, url, xml, timeout=None):
certificado_a1 = CertificadoA1(self.certificado)
- chave, cert = certificado_a1.separar_arquivo(
- self.certificado_senha, caminho=True
- )
+ chave, cert = certificado_a1.separar_arquivo(self.certificado_senha, caminho=True)
chave_cert = (cert, chave)
# Abre a conexão HTTPS
try:
@@ -610,10 +590,7 @@ def _post(self, url, xml, timeout=None):
# limpa xml com caracteres bugados para infNFeSupl em NFC-e
xml = re.sub(
"(.*?)",
- lambda x: x.group(0)
- .replace("<", "<")
- .replace(">", ">")
- .replace("&", ""),
+ lambda x: x.group(0).replace("<", "<").replace(">", ">").replace("&", ""),
etree.tostring(xml, encoding="unicode").replace("\n", ""),
)
xml = xml_declaration + xml
@@ -756,9 +733,9 @@ def _cabecalho(self, retorna_string=True):
etree.SubElement(raiz, "versaoDados").text = self._versao
if retorna_string:
- cabecalho = etree.tostring(
- raiz, encoding="unicode", pretty_print=False
- ).replace("\n", "")
+ cabecalho = etree.tostring(raiz, encoding="unicode", pretty_print=False).replace(
+ "\n", ""
+ )
cabecalho = xml_declaration + cabecalho
return cabecalho
else:
@@ -775,9 +752,9 @@ def _cabecalho2(self, retorna_string=True):
etree.SubElement(raiz, "versaoDados").text = self._versao
if retorna_string:
- cabecalho = etree.tostring(
- raiz, encoding="unicode", pretty_print=False
- ).replace("\n", "")
+ cabecalho = etree.tostring(raiz, encoding="unicode", pretty_print=False).replace(
+ "\n", ""
+ )
cabecalho = xml_declaration + cabecalho
return cabecalho
else:
@@ -831,18 +808,13 @@ def _post_https(self, url, xml, metodo):
cabecalho = self._cabecalho()
# comunicacao wsdl
try:
- from suds.client import Client
-
from pynfe.utils.https_nfse import HttpAuthenticated
+ from suds.client import Client
certificadoA1 = CertificadoA1(self.certificado)
- chave, cert = certificadoA1.separar_arquivo(
- self.certificado_senha, caminho=True
- )
+ chave, cert = certificadoA1.separar_arquivo(self.certificado_senha, caminho=True)
- cliente = Client(
- url, transport=HttpAuthenticated(key=chave, cert=cert, endereco=url)
- )
+ cliente = Client(url, transport=HttpAuthenticated(key=chave, cert=cert, endereco=url))
# gerar nfse
if metodo == "gerar":
@@ -949,24 +921,16 @@ def autorizacao(self, manifesto, id_lote=1, ind_sinc=1):
try:
# Protocolo com envio OK
inf_prot = prot[1][0]
- lote_status = inf_prot.xpath(
- "ns:retEnviMDFe/ns:cStat", namespaces=ns
- )[0].text
+ lote_status = inf_prot.xpath("ns:retEnviMDFe/ns:cStat", namespaces=ns)[0].text
# Lote processado
if lote_status == self._edoc_situacao_lote_processado:
- prot_mdfe = inf_prot.xpath(
- "ns:retEnviMDFe/ns:protMDFe", namespaces=ns
- )[0]
- status = prot_mdfe.xpath("ns:infProt/ns:cStat", namespaces=ns)[
- 0
- ].text
+ prot_mdfe = inf_prot.xpath("ns:retEnviMDFe/ns:protMDFe", namespaces=ns)[0]
+ status = prot_mdfe.xpath("ns:infProt/ns:cStat", namespaces=ns)[0].text
# autorizado uso do MDF-e
# retorna xml final (protMDFe + MDFe)
- if (
- status in self._edoc_situacao_ja_enviado
- ): # if status == '100':
+ if status in self._edoc_situacao_ja_enviado: # if status == '100':
raiz = etree.Element(
"mdfeProc", xmlns=NAMESPACE_MDFE, versao=VERSAO_MDFE
)
@@ -985,18 +949,14 @@ def autorizacao(self, manifesto, id_lote=1, ind_sinc=1):
self._edoc_situacao_arquivo_recebido_com_sucesso,
self._edoc_situacao_em_processamento,
):
- nrec = rec.xpath("ns:retEnviMDFe/ns:infRec/ns:nRec", namespaces=ns)[
- 0
- ].text
+ nrec = rec.xpath("ns:retEnviMDFe/ns:infRec/ns:nRec", namespaces=ns)[0].text
return 0, nrec, manifesto
return 1, retorno, manifesto
def status_servico(self):
url = self._get_url("STATUS")
# Monta XML do corpo da requisição
- raiz = etree.Element(
- "consStatServMDFe", versao=self._versao, xmlns=NAMESPACE_MDFE
- )
+ raiz = etree.Element("consStatServMDFe", versao=self._versao, xmlns=NAMESPACE_MDFE)
etree.SubElement(raiz, "tpAmb").text = str(self._ambiente)
etree.SubElement(raiz, "xServ").text = "STATUS"
xml = self._construir_xml_soap("MDFeStatusServico", raiz)
@@ -1016,9 +976,7 @@ def consulta(self, chave):
def consulta_nao_encerrados(self, cpfcnpj):
url = self._get_url("NAO_ENCERRADOS")
# Monta XML do corpo da requisição
- raiz = etree.Element(
- "consMDFeNaoEnc", xmlns=NAMESPACE_MDFE, versao=self._versao
- )
+ raiz = etree.Element("consMDFeNaoEnc", xmlns=NAMESPACE_MDFE, versao=self._versao)
etree.SubElement(raiz, "tpAmb").text = str(self._ambiente)
etree.SubElement(raiz, "xServ").text = "CONSULTAR NÃO ENCERRADOS"
if len(cpfcnpj) == 11:
@@ -1075,9 +1033,7 @@ def _construir_xml_soap(self, metodo, dados):
body = etree.SubElement(raiz, "{%s}Body" % self._namespace_soap)
- a = etree.SubElement(
- body, self._envio_mensagem, xmlns=self._namespace_metodo + metodo
- )
+ a = etree.SubElement(body, self._envio_mensagem, xmlns=self._namespace_metodo + metodo)
# if metodo == 'MDFeRecepcaoSinc':
# body_base64 = base64.b16encode(a).decode()
@@ -1093,9 +1049,9 @@ def _post_header(self, soap_webservice_method=False):
# PE é a únca UF que exige SOAPAction no header
if soap_webservice_method:
- header[b"SOAPAction"] = (
- self._namespace_metodo + soap_webservice_method
- ).encode("utf-8")
+ header[b"SOAPAction"] = (self._namespace_metodo + soap_webservice_method).encode(
+ "utf-8"
+ )
if self._accept:
header[b"Accept"] = b"application/soap+xml; charset=utf-8;"
@@ -1104,9 +1060,7 @@ def _post_header(self, soap_webservice_method=False):
def _post(self, url, xml):
certificado_a1 = CertificadoA1(self.certificado)
- chave, cert = certificado_a1.separar_arquivo(
- self.certificado_senha, caminho=True
- )
+ chave, cert = certificado_a1.separar_arquivo(self.certificado_senha, caminho=True)
chave_cert = (cert, chave)
# Abre a conexão HTTPS
try:
@@ -1115,16 +1069,11 @@ def _post(self, url, xml):
# limpa xml com caracteres bugados para infMDFeSupl em NFC-e
xml = re.sub(
"(.*?)",
- lambda x: x.group(0)
- .replace("<", "<")
- .replace(">", ">")
- .replace("amp;", ""),
+ lambda x: x.group(0).replace("<", "<").replace(">", ">").replace("amp;", ""),
etree.tostring(xml, encoding="unicode").replace("\n", ""),
)
xml = xml_declaration + xml
- xml = xml.encode(
- "utf8"
- ) # necessário para o evento "CONSULTAR NÃO ENCERRADOS"
+ xml = xml.encode("utf8") # necessário para o evento "CONSULTAR NÃO ENCERRADOS"
print(xml)
print("-" * 20)
@@ -1189,15 +1138,15 @@ def status_servico(self):
"""
url = self._get_url("STATUS")
# Monta XML do corpo da requisição
- raiz = etree.Element(
- "consStatServCte", versao=self._versao, xmlns=NAMESPACE_CTE
- )
+ raiz = etree.Element("consStatServCte", versao=self._versao, xmlns=NAMESPACE_CTE)
etree.SubElement(raiz, "tpAmb").text = str(self._ambiente)
etree.SubElement(raiz, "xServ").text = "STATUS"
xml = self._construir_xml_soap("CteStatusServico", raiz)
return self._post(url, xml)
- def consulta_distribuicao(self, cnpj=None, cpf=None, chave=None, nsu=0, consulta_nsu_especifico=False):
+ def consulta_distribuicao(
+ self, cnpj=None, cpf=None, chave=None, nsu=0, consulta_nsu_especifico=False
+ ):
"""
O XML do pedido de distribuição suporta três tipos de consultas que são
definidas de acordo com a tag informada no XML.
@@ -1261,7 +1210,7 @@ def _cabecalho_soap(self, metodo):
raiz = etree.Element(self._header, xmlns=self._namespace_metodo + metodo)
etree.SubElement(raiz, "cUF").text = CODIGOS_ESTADOS[self.uf.upper()]
- etree.SubElement(raiz, "versaoDados").text = "4.00"
+ etree.SubElement(raiz, "versaoDados").text = "3.00"
return raiz
def _get_url(self, consulta):
@@ -1318,7 +1267,7 @@ def _get_url(self, consulta):
else:
raise Exception(f"Url não encontrada para {consulta} {self.uf.upper()}")
return self.url
-
+
def evento(self, evento):
"""
Envia eventos do CTe como:
@@ -1334,12 +1283,10 @@ def evento(self, evento):
# url do serviço
url = self._get_url("EVENTOS")
- print(url)
# Monta XML do corpo da requisição
xml = self._construir_xml_soap("CTeRecepcaoEventoV4", evento)
return self._post(url, xml)
-
def _construir_xml_soap(self, metodo, dados, cabecalho=False):
"""Monta o XML para o envio via SOAP"""
@@ -1348,14 +1295,20 @@ def _construir_xml_soap(self, metodo, dados, cabecalho=False):
"{%s}Envelope" % NAMESPACE_SOAP,
nsmap={"soap": NAMESPACE_SOAP, "xsi": NAMESPACE_XSI, "xsd": NAMESPACE_XSD},
)
- # if self._header:
- # cabecalho = self._cabecalho_soap(metodo)
- # c = etree.SubElement(raiz, "{%s}Header" % self._namespace_soap)
- # c.append(cabecalho)
+ if self._header and metodo != "CTeRecepcaoEventoV4":
+ cabecalho = self._cabecalho_soap(metodo)
+ c = etree.SubElement(raiz, "{%s}Header" % self._namespace_soap)
+ c.append(cabecalho)
body = etree.SubElement(raiz, "{%s}Body" % NAMESPACE_SOAP)
- cte_dados_msg = etree.SubElement(body, "cteDadosMsg", xmlns=NAMESPACE_CTE_METODO + metodo)
- cte_dados_msg.append(dados)
+
+ # distribuição tem um corpo de xml diferente
+ if metodo == "CTeDistribuicaoDFe":
+ x = etree.SubElement(body, "cteDistDFeInteresse", xmlns=NAMESPACE_CTE_METODO + metodo)
+ a = etree.SubElement(x, "cteDadosMsg")
+ else:
+ a = etree.SubElement(body, "cteDadosMsg", xmlns=NAMESPACE_CTE_METODO + metodo)
+ a.append(dados)
return raiz
def _post_header(self):
@@ -1369,9 +1322,7 @@ def _post_header(self):
def _post(self, url, xml):
certificado_a1 = CertificadoA1(self.certificado)
- chave, cert = certificado_a1.separar_arquivo(
- self.certificado_senha, caminho=True
- )
+ chave, cert = certificado_a1.separar_arquivo(self.certificado_senha, caminho=True)
chave_cert = (cert, chave)
# Abre a conexão HTTPS
try:
@@ -1380,10 +1331,7 @@ def _post(self, url, xml):
# limpa xml com caracteres bugados para infNFeSupl em NFC-e
xml = re.sub(
"(.*?)",
- lambda x: x.group(0)
- .replace("<", "<")
- .replace(">", ">")
- .replace("&", ""),
+ lambda x: x.group(0).replace("<", "<").replace(">", ">").replace("&", ""),
etree.tostring(xml, encoding="unicode").replace("\n", ""),
)
xml = xml_declaration + xml
@@ -1406,5 +1354,3 @@ def _post(self, url, xml):
raise e
finally:
certificado_a1.excluir()
-
-
From 9e82086739061dcda2bf2f14f89b920beab29b9c Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Sat, 23 Aug 2025 22:35:24 -0300
Subject: [PATCH 036/175] feat: Refactor code structure for improved
readability and maintainability
---
pynfe/data/SCHEMAs/NF-e/schemaNFe_v1.00.json | 1092 ++++++++++++++++
.../data/XSDs/NF-e/DFeTiposBasicos_v1.00.xsd | 1097 +++++++++++++++++
pynfe/data/XSDs/NF-e/leiauteNFe_v4.00.xsd | 176 ++-
pynfe/utils/flags.py | 29 +-
4 files changed, 2366 insertions(+), 28 deletions(-)
create mode 100644 pynfe/data/SCHEMAs/NF-e/schemaNFe_v1.00.json
create mode 100644 pynfe/data/XSDs/NF-e/DFeTiposBasicos_v1.00.xsd
diff --git a/pynfe/data/SCHEMAs/NF-e/schemaNFe_v1.00.json b/pynfe/data/SCHEMAs/NF-e/schemaNFe_v1.00.json
new file mode 100644
index 00000000..44b0c686
--- /dev/null
+++ b/pynfe/data/SCHEMAs/NF-e/schemaNFe_v1.00.json
@@ -0,0 +1,1092 @@
+{
+ "versaoManual": "NFe/infNFe/@versao",
+ "idIntegracao": "NFe/infNFe/@Id",
+ "estado": "NFe/infNFe/ide/cUF",
+ "codigo": "NFe/infNFe/ide/cNF",
+ "natureza": "NFe/infNFe/ide/natOp",
+ "modelo": "NFe/infNFe/ide/mod",
+ "serie": "NFe/infNFe/ide/serie",
+ "numero": "NFe/infNFe/ide/nNF",
+ "dataEmissao": "NFe/infNFe/ide/dhEmi",
+ "dataSaidaEntradaTz": "NFe/infNFe/ide/dhSaiEnt",
+ "saida": "NFe/infNFe/ide/tpNF",
+ "codigoIdentificacaoDestino": "NFe/infNFe/ide/idDest",
+ "codigoMunicipioFatoGerador": "NFe/infNFe/ide/cMunFG",
+ "codigoMunicipioFatoGeradorIBS": "NFe/infNFe/ide/cMunFGIBS",
+ "tipoImpressao": "NFe/infNFe/ide/tpImp",
+ "tipoEmissao": "NFe/infNFe/ide/tpEmis",
+ "digitoVerificador": "NFe/infNFe/ide/cDV",
+ "ambiente": "NFe/infNFe/ide/tpAmb",
+ "finalidade": "NFe/infNFe/ide/finNFe",
+ "tipoNotaDebito": "NFe/infNFe/ide/tpNFDebito",
+ "tipoNotaCredito": "NFe/infNFe/ide/tpNFCredito",
+ "consumidorFinal": "NFe/infNFe/ide/indFinal",
+ "presencial": "NFe/infNFe/ide/indPres",
+ "intermediador": "NFe/infNFe/ide/indIntermed",
+ "processoEmissao": "NFe/infNFe/ide/procEmi",
+ "versaoProcessoEmissao": "NFe/infNFe/ide/verProc",
+ "dataContingencia": "NFe/infNFe/ide/dhCont",
+ "justificativaContingencia": "NFe/infNFe/ide/xJust",
+ "compraGovernamental": {
+ "tipoEnte": "NFe/infNFe/ide/gCompraGov/tpEnteGov",
+ "percentual": "NFe/infNFe/ide/gCompraGov/pRedutor",
+ "tipoOperacao": "NFe/infNFe/ide/gCompraGov/tpOperGov"
+ },
+ "pagAntecipado": [{
+ "chave": "NFe/infNFe/ide/gPagAntecipado/refNFe"
+ }],
+ "emitente": {
+ "cpfCnpj": "NFe/infNFe/emit/CNPJ",
+ "razaoSocial": "NFe/infNFe/emit/xNome",
+ "nomeFantasia": "NFe/infNFe/emit/xFant",
+ "endereco": {
+ "logradouro": "NFe/infNFe/emit/enderEmit/xLgr",
+ "numero": "NFe/infNFe/emit/enderEmit/nro",
+ "complemento": "NFe/infNFe/emit/enderEmit/xCpl",
+ "bairro": "NFe/infNFe/emit/enderEmit/xBairro",
+ "codigoCidade": "NFe/infNFe/emit/enderEmit/cMun",
+ "descricaoCidade": "NFe/infNFe/emit/enderEmit/xMun",
+ "estado": "NFe/infNFe/emit/enderEmit/UF",
+ "cep": "NFe/infNFe/emit/enderEmit/CEP",
+ "codigoPais": "NFe/infNFe/emit/enderEmit/cPais",
+ "descricaoPais": "NFe/infNFe/emit/enderEmit/xPais"
+ },
+ "telefone": "NFe/infNFe/emit/enderEmit/fone",
+ "inscricaoEstadual": "NFe/infNFe/emit/IE",
+ "inscricaoEstadualSubstituto": "NFe/infNFe/emit/IEST",
+ "inscricaoMunicipal": "NFe/infNFe/emit/IM",
+ "cnae": "NFe/infNFe/emit/CNAE",
+ "regimeTributario": "NFe/infNFe/emit/CRT"
+ },
+ "avulsa": {
+ "cnpj": "NFe/infNFe/avulsa/CNPJ",
+ "orgao": "NFe/infNFe/avulsa/xOrgao",
+ "matricula": "NFe/infNFe/avulsa/matr",
+ "nomdeAgente": "NFe/infNFe/avulsa/xAgente",
+ "telefone": "NFe/infNFe/avulsa/fone",
+ "estado": "NFe/infNFe/avulsa/UF",
+ "numeroDocumentoArrecadacao": "NFe/infNFe/avulsa/nDAR",
+ "dataEmissao": "NFe/infNFe/avulsa/dEmi",
+ "valorTotal": "NFe/infNFe/avulsa/vDAR",
+ "reparticaoFiscal": "NFe/infNFe/avulsa/repEmi",
+ "dataPagamento": "NFe/infNFe/avulsa/dPag"
+ },
+ "destinatario": {
+ "cpfCnpj": "NFe/infNFe/dest/CNPJ",
+ "codigoEstrangeiro": "NFe/infNFe/dest/idEstrangeiro",
+ "razaoSocial": "NFe/infNFe/dest/xNome",
+ "endereco": {
+ "logradouro": "NFe/infNFe/dest/enderDest/xLgr",
+ "numero": "NFe/infNFe/dest/enderDest/nro",
+ "complemento": "NFe/infNFe/dest/enderDest/xCpl",
+ "bairro": "NFe/infNFe/dest/enderDest/xBairro",
+ "codigoCidade": "NFe/infNFe/dest/enderDest/cMun",
+ "descricaoCidade": "NFe/infNFe/dest/enderDest/xMun",
+ "estado": "NFe/infNFe/dest/enderDest/UF",
+ "cep": "NFe/infNFe/dest/enderDest/CEP",
+ "codigoPais": "NFe/infNFe/dest/enderDest/cPais",
+ "descricaoPais": "NFe/infNFe/dest/enderDest/xPais",
+ "telefone": "NFe/infNFe/dest/enderDest/fone"
+ },
+ "indicadorInscricaoEstadual": "NFe/infNFe/dest/indIEDest",
+ "inscricaoEstadual": "NFe/infNFe/dest/IE",
+ "inscricaoSuframa": "NFe/infNFe/dest/ISUF",
+ "inscricaoMunicipal": "NFe/infNFe/dest/IM",
+ "email": "NFe/infNFe/dest/email"
+ },
+ "localRetirada": {
+ "cpfCnpj": "NFe/infNFe/retirada/CNPJ",
+ "nome": "NFe/infNFe/retirada/xNome",
+ "lougradouro": "NFe/infNFe/retirada/xLgr",
+ "numero": "NFe/infNFe/retirada/nro",
+ "complemento": "NFe/infNFe/retirada/xCpl",
+ "bairro": "NFe/infNFe/retirada/xBairro",
+ "codigoCidade": "NFe/infNFe/retirada/cMun",
+ "descricaoCidade": "NFe/infNFe/retirada/xMun",
+ "estado": "NFe/infNFe/retirada/UF",
+ "cep": "NFe/infNFe/retirada/CEP",
+ "codigoPais": "NFe/infNFe/retirada/cPais",
+ "descricaoPais": "NFe/infNFe/retirada/xPais",
+ "telefone": "NFe/infNFe/retirada/fone",
+ "email": "NFe/infNFe/retirada/email",
+ "inscricaoEstadual": "NFe/infNFe/retirada/IE"
+ },
+ "localEntrega": {
+ "cpfCnpj": "NFe/infNFe/entrega/CNPJ",
+ "razaoSocial": "NFe/infNFe/entrega/xNome",
+ "endereco": {
+ "logradouro": "NFe/infNFe/entrega/xLgr",
+ "numero": "NFe/infNFe/entrega/nro",
+ "complemento": "NFe/infNFe/entrega/xCpl",
+ "bairro": "NFe/infNFe/entrega/xBairro",
+ "codigoCidade": "NFe/infNFe/entrega/cMun",
+ "descricaoCidade": "NFe/infNFe/entrega/xMun",
+ "estado": "NFe/infNFe/entrega/UF",
+ "cep": "NFe/infNFe/entrega/CEP",
+ "codigoPais": "NFe/infNFe/entrega/cPais",
+ "descricaoPais": "NFe/infNFe/entrega/xPais"
+ },
+ "telefone": "NFe/infNFe/entrega/fone",
+ "email": "NFe/infNFe/entrega/email",
+ "inscricaoEstadual": "NFe/infNFe/entrega/IE"
+ },
+ "total": {
+ "baseCalculoIcms": "NFe/infNFe/total/ICMSTot/vBC",
+ "valorIcms": "NFe/infNFe/total/ICMSTot/vICMS",
+ "valorIcmsDesonerado": "NFe/infNFe/total/ICMSTot/vICMSDeson",
+ "valorIcmsFcp": "NFe/infNFe/total/ICMSTot/vFCPUFDest",
+ "valorIcmsEstadoDestino": "NFe/infNFe/total/ICMSTot/vICMSUFDest",
+ "valorIcmsEstadoRemetente": "NFe/infNFe/total/ICMSTot/vICMSUFRemet",
+ "valorFcp": "NFe/infNFe/total/ICMSTot/vFCP",
+ "baseCalculoIcmsSt": "NFe/infNFe/total/ICMSTot/vBCST",
+ "valorIcmsSt": "NFe/infNFe/total/ICMSTot/vST",
+ "valorFcpSt": "NFe/infNFe/total/ICMSTot/vFCPST",
+ "valorFcpStRetido": "NFe/infNFe/total/ICMSTot/vFCPSTRet",
+ "baseCalculoMono": "NFe/infNFe/total/ICMSTot/qBCMono",
+ "valorIcmsMono": "NFe/infNFe/total/ICMSTot/vICMSMono",
+ "baseCalculoMonoRetencao": "NFe/infNFe/total/ICMSTot/qBCMonoReten",
+ "valorIcmsMonoRetencao": "NFe/infNFe/total/ICMSTot/vICMSMonoReten",
+ "baseCalculoMonoRetido": "NFe/infNFe/total/ICMSTot/qBCMonoRet",
+ "valorIcmsMonoRetido": "NFe/infNFe/total/ICMSTot/vICMSMonoRet",
+ "valorProdutosServicos": "NFe/infNFe/total/ICMSTot/vProd",
+ "valorFrete": "NFe/infNFe/total/ICMSTot/vFrete",
+ "valorSeguro": "NFe/infNFe/total/ICMSTot/vSeg",
+ "valorDesconto": "NFe/infNFe/total/ICMSTot/vDesc",
+ "valorIi": "NFe/infNFe/total/ICMSTot/vII",
+ "valorIpi": "NFe/infNFe/total/ICMSTot/vIPI",
+ "valorIpiDevolvido": "NFe/infNFe/total/ICMSTot/vIPIDevol",
+ "valorPis": "NFe/infNFe/total/ICMSTot/vPIS",
+ "valorCofins": "NFe/infNFe/total/ICMSTot/vCOFINS",
+ "valorOutros": "NFe/infNFe/total/ICMSTot/vOutro",
+ "valorNfe": "NFe/infNFe/total/ICMSTot/vNF",
+ "valorAproximadoTributos": "NFe/infNFe/total/ICMSTot/vTotTrib",
+ "servico": {
+ "valor": "NFe/infNFe/total/ISSQNtot/vServ",
+ "baseCalculo": "NFe/infNFe/total/ISSQNtot/vBC",
+ "valorIss": "NFe/infNFe/total/ISSQNtot/vISS",
+ "valorPis": "NFe/infNFe/total/ISSQNtot/vPIS",
+ "valorCofins": "NFe/infNFe/total/ISSQNtot/vCOFINS",
+ "dataPrestacao": "NFe/infNFe/total/ISSQNtot/dCompet",
+ "valorDeducao": "NFe/infNFe/total/ISSQNtot/vDeducao",
+ "valorOutros": "NFe/infNFe/total/ISSQNtot/vOutro",
+ "descontoIncondicionado": "NFe/infNFe/total/ISSQNtot/vDescIncond",
+ "descontoCondicionado": "NFe/infNFe/total/ISSQNtot/vDescCond",
+ "valorRetencaoIss": "NFe/infNFe/total/ISSQNtot/vISSRet",
+ "codigoRegimeEspecial": "NFe/infNFe/total/ISSQNtot/cRegTrib"
+ },
+ "valorPisRetido": "NFe/infNFe/total/retTrib/vRetPIS",
+ "valorCofinsRetido": "NFe/infNFe/total/retTrib/vRetCOFINS",
+ "valorCsllRetido": "NFe/infNFe/total/retTrib/vRetCSLL",
+ "baseCalculoIrrf": "NFe/infNFe/total/retTrib/vBCIRRF",
+ "valorIrrfRetido": "NFe/infNFe/total/retTrib/vIRRF",
+ "baseCalculoRetencao": "NFe/infNFe/total/retTrib/vBCRetPrev",
+ "valorPrevidenciaRetido": "NFe/infNFe/total/retTrib/vRetPrev",
+ "baseCalculoIs": "NFe/infNFe/total/ISTot/vIS",
+ "baseCalculoIbsCbs": "NFe/infNFe/total/IBSCBSTot/vBCIBSCBS",
+ "valorDiferimentoIbsUF": "NFe/infNFe/total/IBSCBSTot/gIBS/gIBSUF/vDif",
+ "valorDevolucaoIbsUF": "NFe/infNFe/total/IBSCBSTot/gIBS/gIBSUF/vDevTrib",
+ "valorIbsUF": "NFe/infNFe/total/IBSCBSTot/gIBS/gIBSUF/vIBSUF",
+ "valorDiferimentoIbsMunicipio": "NFe/infNFe/total/IBSCBSTot/gIBS/gIBSMun/vDif",
+ "valorDevolucaoIbsMunicipio": "NFe/infNFe/total/IBSCBSTot/gIBS/gIBSMun/vDevTrib",
+ "valorIbsMunicipio": "NFe/infNFe/total/IBSCBSTot/gIBS/gIBSMun/vIBSMun",
+ "valorIbs": "NFe/infNFe/total/IBSCBSTot/gIBS/vIBS",
+ "valorIbsCreditoPresumindo": "NFe/infNFe/total/IBSCBSTot/gIBS/vCredPres",
+ "valorIbsCreditoPresumidoSupensao": "NFe/infNFe/total/IBSCBSTot/gIBS/vCredPresCondSus",
+ "valorCbsDiferimento": "NFe/infNFe/total/IBSCBSTot/gCBS/vDif",
+ "valorCbsDevolucao": "NFe/infNFe/total/IBSCBSTot/gCBS/vDevTrib",
+ "valorCbs": "NFe/infNFe/total/IBSCBSTot/gCBS/vCBS",
+ "valorCbsCreditoPresumido": "NFe/infNFe/total/IBSCBSTot/gCBS/vCredPres",
+ "valorCbsCreditoPresumidoSupensao": "NFe/infNFe/total/IBSCBSTot/gCBS/vCredPresCondSus",
+ "valorIbsMono": "NFe/infNFe/total/IBSCBSTot/gMono/vIBSMono",
+ "valorCbsMono": "NFe/infNFe/total/IBSCBSTot/gMono/vCBSMono",
+ "valorIbsMonoRetencao": "NFe/infNFe/total/IBSCBSTot/gMono/vIBSMonoReten",
+ "valorCbsMonoRetenencao": "NFe/infNFe/total/IBSCBSTot/gMono/vCBSMonoReten",
+ "valorIbsMonoRetido": "NFe/infNFe/total/IBSCBSTot/gMono/vIBSMonoRet",
+ "valorCbsMonoRetido": "NFe/infNFe/total/IBSCBSTot/gMono/vCBSMonoRet",
+ "valorIbsCbsIs": "NFe/infNFe/total/vNFTot"
+ },
+ "transporte": {
+ "modalidadeFrete": "NFe/infNFe/transp/modFrete",
+ "transportador": {
+ "cpfCnpj": "NFe/infNFe/transp/transporta/CNPJ",
+ "nome": "NFe/infNFe/transp/transporta/xNome",
+ "inscricaoEstadual": "NFe/infNFe/transp/transporta/IE",
+ "endereco": {
+ "logradouro": "NFe/infNFe/transp/transporta/xEnder",
+ "descricaoCidade": "NFe/infNFe/transp/transporta/xMun",
+ "uf": "NFe/infNFe/transp/transporta/UF"
+ }
+ },
+ "retencaoICMS": {
+ "valorServico": "NFe/infNFe/transp/retTransp/vServ",
+ "baseICMS": "NFe/infNFe/transp/retTransp/vBCRet",
+ "aliquota": "NFe/infNFe/transp/retTransp/pICMSRet",
+ "valorICMSRet": "NFe/infNFe/transp/retTransp/vICMSRet",
+ "cfop": "NFe/infNFe/transp/retTransp/CFOP",
+ "codigoMunicipioOcorrencia": "NFe/infNFe/transp/retTransp/cMunFG"
+ },
+ "veiculo": {
+ "placa": "NFe/infNFe/transp/veicTransp/placa",
+ "uf": "NFe/infNFe/transp/veicTransp/UF",
+ "rntc": "NFe/infNFe/transp/veicTransp/RNTC"
+ },
+ "reboque": [{
+ "vagao": "NFe/infNFe/transp/vagao",
+ "balsa": "NFe/infNFe/transp/balsa",
+ "placa": "NFe/infNFe/transp/reboque/placa",
+ "uf": "NFe/infNFe/transp/reboque/UF",
+ "rntc": "NFe/infNFe/transp/reboque/RNTC"
+ }],
+ "volumes": [{
+ "quantidade": "NFe/infNFe/transp/vol/qVol",
+ "especie": "NFe/infNFe/transp/vol/esp",
+ "marca": "NFe/infNFe/transp/vol/marca",
+ "numeracao": "NFe/infNFe/transp/vol/nVol",
+ "pesoLiquido": "NFe/infNFe/transp/vol/pesoL",
+ "pesoBruto": "NFe/infNFe/transp/vol/pesoB",
+ "lacres": [{
+ "numero": "NFe/infNFe/transp/vol/lacres/nLacre"
+ }]
+ }]
+ },
+ "cobranca": {
+ "numero": "NFe/infNFe/cobr/fat/nFat",
+ "valorTotal": "NFe/infNFe/cobr/fat/vOrig",
+ "valorDesconto": "NFe/infNFe/cobr/fat/vDesc",
+ "valorLiquido": "NFe/infNFe/cobr/fat/vLiq",
+ "parcelas": [{
+ "numero": "NFe/infNFe/cobr/dup/nDup",
+ "dataVencimento": "NFe/infNFe/cobr/dup/dVenc",
+ "valor": "NFe/infNFe/cobr/dup/vDup"
+ }]
+ },
+ "valorTroco": "NFe/infNFe/pag/vTroco",
+ "informacoesComplementaresContribuinte": "NFe/infNFe/infAdic/infAdFisco",
+ "informacoesComplementares": "NFe/infNFe/infAdic/infCpl",
+ "exportacao": {
+ "estadoEmbarque": "NFe/infNFe/exporta/UFSaidaPais",
+ "descricaoLocalEmbarque": "NFe/infNFe/exporta/xLocExporta",
+ "descricaoLocalDespacho": "NFe/infNFe/exporta/xLocDespacho"
+ },
+ "compra": {
+ "notaEmpenho": "NFe/infNFe/compra/xNEmp",
+ "pedido": "NFe/infNFe/compra/xPed",
+ "contrato": "NFe/infNFe/compra/xCont"
+ },
+ "cana": {
+ "safra": "NFe/infNFe/cana/safra",
+ "dataReferencia": "NFe/infNFe/cana/ref",
+ "fornecimentoDiario": [{
+ "dia": "NFe/infNFe/cana/forDia/@dia",
+ "quantidadeKg": "NFe/infNFe/cana/forDia/qtde",
+ "quantidadeMes": "NFe/infNFe/cana/qTotMes",
+ "quantidadeAnterior": "NFe/infNFe/cana/qTotAnt",
+ "quantidadeGeral": "NFe/infNFe/cana/qTotGer"
+ }]
+ },
+ "canaDeducoes": [{
+ "descricao": "NFe/infNFe/cana/deduc/xDed",
+ "valor": "NFe/infNFe/cana/deduc/vDed",
+ "valorFornecimentos": "NFe/infNFe/cana/vFor",
+ "valorTotal": "NFe/infNFe/cana/vTotDed",
+ "valorLiquidoFornecimento": "NFe/infNFe/cana/vLiqFor"
+ }],
+ "nfeReferenciada": [{
+ "chave": "NFe/infNFe/ide/NFref/refNFe",
+ "chaveSigilo": "NFe/infNFe/ide/NFref/refNFeSig",
+ "nfePapel": {
+ "estado": "NFe/infNFe/ide/NFref/refNF/cUF",
+ "dataEmissao": "NFe/infNFe/ide/NFref/refNF/AAMM",
+ "cpfCnpj": "NFe/infNFe/ide/NFref/refNF/CNPJ",
+ "modelo": "NFe/infNFe/ide/NFref/refNF/mod",
+ "serie": "NFe/infNFe/ide/NFref/refNF/serie",
+ "numero": "NFe/infNFe/ide/NFref/refNF/nNF"
+ },
+ "produtorRural": {
+ "estado": "NFe/infNFe/ide/NFref/refNFP/cUF",
+ "dataEmissao": "NFe/infNFe/ide/NFref/refNFP/AAMM",
+ "cnpj": "NFe/infNFe/ide/NFref/refNFP/CNPJ",
+ "cpf": "NFe/infNFe/ide/NFref/refNFP/CPF",
+ "inscricaoEstadual": "NFe/infNFe/ide/NFref/refNFP/IE",
+ "modelo": "NFe/infNFe/ide/NFref/refNFP/mod",
+ "serie": "NFe/infNFe/ide/NFref/refNFP/serie",
+ "numero": "NFe/infNFe/ide/NFref/refNFP/nNF"
+ },
+ "chaveCte": "NFe/infNFe/ide/NFref/refCTe",
+ "cupomFiscal": {
+ "modelo": "NFe/infNFe/ide/NFref/refECF/mod",
+ "numeroOrdemSequencia": "NFe/infNFe/ide/NFref/refECF/nECF",
+ "numeroContador": "NFe/infNFe/ide/NFref/refECF/nCOO"
+ }
+ }],
+ "responsavelAutorizado": [{
+ "cpfCnpj": "NFe/infNFe/autXML/CNPJ"
+ }],
+ "itens": [{
+ "codigo": "NFe/infNFe/det/prod/cProd",
+ "codigoEAN": "NFe/infNFe/det/prod/cEAN",
+ "codigoBarras": "NFe/infNFe/det/prod/cBarra",
+ "descricao": "NFe/infNFe/det/prod/xProd",
+ "ncm": "NFe/infNFe/det/prod/NCM",
+ "cest": "NFe/infNFe/det/prod/CEST",
+ "indicadorEscalaRelevante": "NFe/infNFe/det/prod/indEscala",
+ "cnpjFabricante": "NFe/infNFe/det/prod/CNPJFab",
+ "codigoBeneficioFiscal": "NFe/infNFe/det/prod/cBenef",
+ "creditoPresumido": [{
+ "codigo": "NFe/infNFe/det/prod/gCred/cCredPresumido",
+ "percentual": "NFe/infNFe/det/prod/gCred/pCredPresumido",
+ "valor": "NFe/infNFe/det/prod/gCred/vCredPresumido"
+ }],
+ "exTipi": "NFe/infNFe/det/prod/EXTIPI",
+ "cfop": "NFe/infNFe/det/prod/CFOP",
+ "unidade": {
+ "comercial": "NFe/infNFe/det/prod/uCom",
+ "tributavel": "NFe/infNFe/det/prod/uTrib"
+ },
+ "quantidade": {
+ "comercial": "NFe/infNFe/det/prod/qCom",
+ "tributavel": "NFe/infNFe/det/prod/qTrib"
+ },
+ "valorUnitario": {
+ "comercial": "NFe/infNFe/det/prod/vUnCom",
+ "tributavel": "NFe/infNFe/det/prod/vUnTrib"
+ },
+ "valor": "NFe/infNFe/det/prod/vProd",
+ "codigoEANTributavel": "NFe/infNFe/det/prod/cEANTrib",
+ "codigoBarrasTributavel": "NFe/infNFe/det/prod/cBarraTrib",
+ "valorFrete": "NFe/infNFe/det/prod/vFrete",
+ "valorSeguro": "NFe/infNFe/det/prod/vSeg",
+ "valorDesconto": "NFe/infNFe/det/prod/vDesc",
+ "valorOutros": "NFe/infNFe/det/prod/vOutro",
+ "compoeTotal": "NFe/infNFe/det/prod/indTot",
+ "indicadorBemMovelUsado": "NFe/infNFe/det/prod/indBemMovelUsado",
+ "numeroCompra": "NFe/infNFe/det/prod/xPed",
+ "pedidoCompra": "NFe/infNFe/det/prod/nItemPed",
+ "numeroFci": "NFe/infNFe/det/prod/nFCI",
+ "veiculo": {
+ "tipoOperacao": "NFe/infNFe/det/prod/veicProd/tpOp",
+ "chassi": "NFe/infNFe/det/prod/veicProd/chassi",
+ "codigoCor": "NFe/infNFe/det/prod/veicProd/cCor",
+ "descricaoCor": "NFe/infNFe/det/prod/veicProd/xCor",
+ "potenciaMotor": "NFe/infNFe/det/prod/veicProd/pot",
+ "cilindradas": "NFe/infNFe/det/prod/veicProd/cilin",
+ "pesoLiquido": "NFe/infNFe/det/prod/veicProd/pesoL",
+ "pesoBruto": "NFe/infNFe/det/prod/veicProd/pesoB",
+ "numeroSerie": "NFe/infNFe/det/prod/veicProd/nSerie",
+ "tipoCombustivel": "NFe/infNFe/det/prod/veicProd/tpComb",
+ "numeroMotor": "NFe/infNFe/det/prod/veicProd/nMotor",
+ "capacidadeTracao": "NFe/infNFe/det/prod/veicProd/CMT",
+ "distanciaEixos": "NFe/infNFe/det/prod/veicProd/dist",
+ "anoModelo": "NFe/infNFe/det/prod/veicProd/anoMod",
+ "anoFabricacao": "NFe/infNFe/det/prod/veicProd/anoFab",
+ "tipoPintura": "NFe/infNFe/det/prod/veicProd/tpPint",
+ "tipo": "NFe/infNFe/det/prod/veicProd/tpVeic",
+ "especie": "NFe/infNFe/det/prod/veicProd/espVeic",
+ "condicaoVin": "NFe/infNFe/det/prod/veicProd/VIN",
+ "condicao": "NFe/infNFe/det/prod/veicProd/condVeic",
+ "codigoModelo": "NFe/infNFe/det/prod/veicProd/cMod",
+ "codigoCorDenatran": "NFe/infNFe/det/prod/veicProd/cCorDENATRAN",
+ "lotacaoMaxima": "NFe/infNFe/det/prod/veicProd/lota",
+ "restricao": "NFe/infNFe/det/prod/veicProd/tpRest"
+ },
+ "medicamentos": [{
+ "codigoAnvisa": "NFe/infNFe/det/prod/med/cProdANVISA",
+ "motivoInsencaoAnvisa": "NFe/infNFe/det/prod/med/xMotivoIsencao",
+ "valorMaximo": "NFe/infNFe/det/prod/med/vPMC"
+ }],
+ "combustivel": {
+ "codigoAnp": "NFe/infNFe/det/prod/comb/cProdANP",
+ "descricaoAnp": "NFe/infNFe/det/prod/comb/descANP",
+ "percentualGlp": "NFe/infNFe/det/prod/comb/pGLP",
+ "percentualGnn": "NFe/infNFe/det/prod/comb/pGNn",
+ "percentualGni": "NFe/infNFe/det/prod/comb/pGNi",
+ "valorPartida": "NFe/infNFe/det/prod/comb/vPart",
+ "codigoAutorizacao": "NFe/infNFe/det/prod/comb/CODIF",
+ "faturamentoTemperaturaAmbiente": "NFe/infNFe/det/prod/comb/qTemp",
+ "estadoConsumo": "NFe/infNFe/det/prod/comb/UFCons",
+ "percentualMistura": "NFe/infNFe/det/prod/comb/pBio",
+ "cide": {
+ "baseCalculo": "NFe/infNFe/det/prod/comb/CIDE/qBCProd",
+ "aliquota": "NFe/infNFe/det/prod/comb/CIDE/vAliqProd",
+ "valor": "NFe/infNFe/det/prod/comb/CIDE/vCIDE"
+ },
+ "encerrante": {
+ "numeroBico": "NFe/infNFe/det/prod/comb/encerrante/nBico",
+ "numeroBomba": "NFe/infNFe/det/prod/comb/encerrante/nBomba",
+ "numeroTanque": "NFe/infNFe/det/prod/comb/encerrante/nTanque",
+ "valorInicio": "NFe/infNFe/det/prod/comb/encerrante/vEncIni",
+ "valorFinal": "NFe/infNFe/det/prod/comb/encerrante/vEncFin"
+ },
+ "origemCombustivel": [{
+ "indicadorImportacao": "NFe/infNFe/det/prod/comb/origComb/indImport",
+ "codigoUf": "NFe/infNFe/det/prod/comb/origComb/cUFOrig",
+ "percentualOrigUf": "NFe/infNFe/det/prod/comb/origComb/pOrig"
+ }]
+ },
+ "papelImune": {
+ "numero": "NFe/infNFe/det/prod/nRECOPI"
+ },
+ "tributos": {
+ "valorAproximadoTributos": "NFe/infNFe/det/imposto/vTotTrib",
+ "icms": {
+ "origem_ICMS00": "NFe/infNFe/det/imposto/ICMS/ICMS00/orig",
+ "cst_ICMS00": "NFe/infNFe/det/imposto/ICMS/ICMS00/CST",
+ "baseCalculo": {
+ "modalidadeDeterminacao_ICMS00": "NFe/infNFe/det/imposto/ICMS/ICMS00/modBC",
+ "valor_ICMS00": "NFe/infNFe/det/imposto/ICMS/ICMS00/vBC",
+ "modalidadeDeterminacao_ICMS10": "NFe/infNFe/det/imposto/ICMS/ICMS10/modBC",
+ "valor_ICMS10": "NFe/infNFe/det/imposto/ICMS/ICMS10/vBC",
+ "modalidadeDeterminacao_ICMS20": "NFe/infNFe/det/imposto/ICMS/ICMS20/modBC",
+ "percentualReducao_ICMS20": "NFe/infNFe/det/imposto/ICMS/ICMS20/pRedBC",
+ "valor_ICMS20": "NFe/infNFe/det/imposto/ICMS/ICMS20/vBC",
+ "modalidadeDeterminacao_ICMS51": "NFe/infNFe/det/imposto/ICMS/ICMS51/modBC",
+ "percentualReducao_ICMS51": "NFe/infNFe/det/imposto/ICMS/ICMS51/pRedBC",
+ "valor_ICMS51": "NFe/infNFe/det/imposto/ICMS/ICMS51/vBC",
+ "modalidadeDeterminacao_ICMS70": "NFe/infNFe/det/imposto/ICMS/ICMS70/modBC",
+ "percentualReducao_ICMS70": "NFe/infNFe/det/imposto/ICMS/ICMS70/pRedBC",
+ "valor_ICMS70": "NFe/infNFe/det/imposto/ICMS/ICMS70/vBC",
+ "modalidadeDeterminacao_ICMS90": "NFe/infNFe/det/imposto/ICMS/ICMS90/modBC",
+ "valor_ICMS90": "NFe/infNFe/det/imposto/ICMS/ICMS90/vBC",
+ "percentualReducao_ICMS90": "NFe/infNFe/det/imposto/ICMS/ICMS90/pRedBC",
+ "modalidadeDeterminacao_ICMSPart": "NFe/infNFe/det/imposto/ICMS/ICMSPart/modBC",
+ "valor_ICMSPart": "NFe/infNFe/det/imposto/ICMS/ICMSPart/vBC",
+ "percentualReducao_ICMSPart": "NFe/infNFe/det/imposto/ICMS/ICMSPart/pRedBC",
+ "modalidadeDeterminacao_ICMSSN900": "NFe/infNFe/det/imposto/ICMS/ICMSSN900/modBC",
+ "valor_ICMSSN900": "NFe/infNFe/det/imposto/ICMS/ICMSSN900/vBC",
+ "percentualReducao_ICMSSN900": "NFe/infNFe/det/imposto/ICMS/ICMSSN900/pRedBC"
+ },
+ "aliquota_ICMS00": "NFe/infNFe/det/imposto/ICMS/ICMS00/pICMS",
+ "valor_ICMS00": "NFe/infNFe/det/imposto/ICMS/ICMS00/vICMS",
+ "fundoCombatePobreza": {
+ "baseCalculo": {
+ "aliquota_ICMS00": "NFe/infNFe/det/imposto/ICMS/ICMS00/pFCP",
+ "valor_ICMS00": "NFe/infNFe/det/imposto/ICMS/ICMS00/vFCP",
+ "valor_ICMS10": "NFe/infNFe/det/imposto/ICMS/ICMS10/vBCFCP",
+ "valor_ICMS20": "NFe/infNFe/det/imposto/ICMS/ICMS20/vBCFCP",
+ "valor_ICMS51": "NFe/infNFe/det/imposto/ICMS/ICMS51/vBCFCP",
+ "valor_ICMS70": "NFe/infNFe/det/imposto/ICMS/ICMS70/vBCFCP",
+ "valor_ICMS90": "NFe/infNFe/det/imposto/ICMS/ICMS90/vBCFCP"
+ },
+ "aliquota_ICMS10": "NFe/infNFe/det/imposto/ICMS/ICMS10/pFCP",
+ "valor_ICMS10": "NFe/infNFe/det/imposto/ICMS/ICMS10/vFCP",
+ "aliquota_ICMS20": "NFe/infNFe/det/imposto/ICMS/ICMS20/pFCP",
+ "valor_ICMS20": "NFe/infNFe/det/imposto/ICMS/ICMS20/vFCP",
+ "aliquota_ICMS51": "NFe/infNFe/det/imposto/ICMS/ICMS51/pFCP",
+ "valor_ICMS51": "NFe/infNFe/det/imposto/ICMS/ICMS51/vFCP",
+ "diferimento": {
+ "percentual_ICMS51": "NFe/infNFe/det/imposto/ICMS/ICMS51/pFCPDif",
+ "valor_ICMS51": "NFe/infNFe/det/imposto/ICMS/ICMS51/vFCPDif",
+ "valorEfetivo_ICMS51": "NFe/infNFe/det/imposto/ICMS/ICMS51/vFCPEfet"
+ },
+ "aliquota_ICMS70": "NFe/infNFe/det/imposto/ICMS/ICMS70/pFCP",
+ "valor_ICMS70": "NFe/infNFe/det/imposto/ICMS/ICMS70/vFCP",
+ "aliquota_ICMS90": "NFe/infNFe/det/imposto/ICMS/ICMS90/pFCP",
+ "valor_ICMS90": "NFe/infNFe/det/imposto/ICMS/ICMS90/vFCP"
+ },
+ "origem_ICMS02": "NFe/infNFe/det/imposto/ICMS/ICMS02/orig",
+ "cst_ICMS02": "NFe/infNFe/det/imposto/ICMS/ICMS02/CST",
+ "baseCalculoMono_ICMS02": "NFe/infNFe/det/imposto/ICMS/ICMS02/qBCMono",
+ "valorIcmsMono_ICMS02": "NFe/infNFe/det/imposto/ICMS/ICMS02/vICMSMono",
+ "aliquotaAdRem_ICMS02": "NFe/infNFe/det/imposto/ICMS/ICMS02/adRemICMS",
+ "origem_ICMS10": "NFe/infNFe/det/imposto/ICMS/ICMS10/orig",
+ "cst_ICMS10": "NFe/infNFe/det/imposto/ICMS/ICMS10/CST",
+ "aliquota_ICMS10": "NFe/infNFe/det/imposto/ICMS/ICMS10/pICMS",
+ "valor_ICMS10": "NFe/infNFe/det/imposto/ICMS/ICMS10/vICMS",
+ "substituicaoTributaria": {
+ "baseCalculo": {
+ "modalidadeDeterminacao_ICMS10": "NFe/infNFe/det/imposto/ICMS/ICMS10/modBCST",
+ "percentualReducao_ICMS10": "NFe/infNFe/det/imposto/ICMS/ICMS10/pRedBCST",
+ "valor_ICMS10": "NFe/infNFe/det/imposto/ICMS/ICMS10/vBCST",
+ "modalidadeDeterminacao_ICMS30": "NFe/infNFe/det/imposto/ICMS/ICMS30/modBCST",
+ "percentualReducao_ICMS30": "NFe/infNFe/det/imposto/ICMS/ICMS30/pRedBCST",
+ "valor_ICMS30": "NFe/infNFe/det/imposto/ICMS/ICMS30/vBCST",
+ "valor_ICMS60": "NFe/infNFe/det/imposto/ICMS/ICMS60/vBCSTRet",
+ "modalidadeDeterminacao_ICMS70": "NFe/infNFe/det/imposto/ICMS/ICMS70/modBCST",
+ "percentualReducao_ICMS70": "NFe/infNFe/det/imposto/ICMS/ICMS70/pRedBCST",
+ "valor_ICMS70": "NFe/infNFe/det/imposto/ICMS/ICMS70/vBCST",
+ "modalidadeDeterminacao_ICMS90": "NFe/infNFe/det/imposto/ICMS/ICMS90/modBCST",
+ "percentualReducao_ICMS90": "NFe/infNFe/det/imposto/ICMS/ICMS90/pRedBCST",
+ "valor_ICMS90": "NFe/infNFe/det/imposto/ICMS/ICMS90/vBCST",
+ "modalidadeDeterminacao_ICMSPart": "NFe/infNFe/det/imposto/ICMS/ICMSPart/modBCST",
+ "percentualReducao_ICMSPart": "NFe/infNFe/det/imposto/ICMS/ICMSPart/pRedBCST",
+ "valor_ICMSPart": "NFe/infNFe/det/imposto/ICMS/ICMSPart/vBCST",
+ "valor_ICMSST": "NFe/infNFe/det/imposto/ICMS/ICMSST/vBCSTRet",
+ "modalidadeDeterminacao_ICMSSN201": "NFe/infNFe/det/imposto/ICMS/ICMSSN201/modBCST",
+ "percentualReducao_ICMSSN201": "NFe/infNFe/det/imposto/ICMS/ICMSSN201/pRedBCST",
+ "valor_ICMSSN201": "NFe/infNFe/det/imposto/ICMS/ICMSSN201/vBCST",
+ "modalidadeDeterminacao_ICMSSN202": "NFe/infNFe/det/imposto/ICMS/ICMSSN202/modBCST",
+ "percentualReducao_ICMSSN202": "NFe/infNFe/det/imposto/ICMS/ICMSSN202/pRedBCST",
+ "valor_ICMSSN202": "NFe/infNFe/det/imposto/ICMS/ICMSSN202/vBCST",
+ "valor_ICMSSN500": "NFe/infNFe/det/imposto/ICMS/ICMSSN500/vBCSTRet",
+ "modalidadeDeterminacao_ICMSSN900": "NFe/infNFe/det/imposto/ICMS/ICMSSN900/modBCST",
+ "percentualReducao_ICMSSN900": "NFe/infNFe/det/imposto/ICMS/ICMSSN900/pRedBCST",
+ "valor_ICMSSN900": "NFe/infNFe/det/imposto/ICMS/ICMSSN900/vBCST"
+ },
+ "margemValorAdicionado": {
+ "percentual_ICMS10": "NFe/infNFe/det/imposto/ICMS/ICMS10/pMVAST",
+ "percentual_ICMS30": "NFe/infNFe/det/imposto/ICMS/ICMS30/pMVAST",
+ "percentual_ICMS70": "NFe/infNFe/det/imposto/ICMS/ICMS70/pMVAST",
+ "percentual_ICMS90": "NFe/infNFe/det/imposto/ICMS/ICMS90/pMVAST",
+ "percentual_ICMSPart": "NFe/infNFe/det/imposto/ICMS/ICMSPart/pMVAST",
+ "percentual_ICMSSN201": "NFe/infNFe/det/imposto/ICMS/ICMSSN201/pMVAST",
+ "percentual_ICMSSN202": "NFe/infNFe/det/imposto/ICMS/ICMSSN202/pMVAST",
+ "percentual_ICMSSN900": "NFe/infNFe/det/imposto/ICMS/ICMSSN900/pMVAST"
+ },
+ "aliquota_ICMS10": "NFe/infNFe/det/imposto/ICMS/ICMS10/pICMSST",
+ "valor_ICMS10": "NFe/infNFe/det/imposto/ICMS/ICMS10/vICMSST",
+ "fundoCombatePobreza": {
+ "baseCalculo": {
+ "valor_ICMS10": "NFe/infNFe/det/imposto/ICMS/ICMS10/vBCFCPST",
+ "valor_ICMS30": "NFe/infNFe/det/imposto/ICMS/ICMS30/vBCFCPST",
+ "valor_ICMS60": "NFe/infNFe/det/imposto/ICMS/ICMS60/vBCFCPSTRet",
+ "valor_ICMS70": "NFe/infNFe/det/imposto/ICMS/ICMS70/vBCFCPST",
+ "valor_ICMS90": "NFe/infNFe/det/imposto/ICMS/ICMS90/vBCFCPST",
+ "valor_ICMSPart": "NFe/infNFe/det/imposto/ICMS/ICMSPart/vBCFCPST",
+ "valor_ICMSST": "NFe/infNFe/det/imposto/ICMS/ICMSST/vBCFCPSTRet",
+ "valor_ICMSSN201": "NFe/infNFe/det/imposto/ICMS/ICMSSN201/vBCFCPST",
+ "valor_ICMSSN202": "NFe/infNFe/det/imposto/ICMS/ICMSSN202/vBCFCPST",
+ "valor_ICMSSN500": "NFe/infNFe/det/imposto/ICMS/ICMSSN500/vBCFCPSTRet",
+ "valor_ICMSSN900": "NFe/infNFe/det/imposto/ICMS/ICMSSN900/vBCFCPST"
+ },
+ "aliquota_ICMS10": "NFe/infNFe/det/imposto/ICMS/ICMS10/pFCPST",
+ "valor_ICMS10": "NFe/infNFe/det/imposto/ICMS/ICMS10/vFCPST",
+ "aliquota_ICMS30": "NFe/infNFe/det/imposto/ICMS/ICMS30/pFCPST",
+ "valor_ICMS30": "NFe/infNFe/det/imposto/ICMS/ICMS30/vFCPST",
+ "aliquota_ICMS60": "NFe/infNFe/det/imposto/ICMS/ICMS60/pFCPSTRet",
+ "valor_ICMS60": "NFe/infNFe/det/imposto/ICMS/ICMS60/vFCPSTRet",
+ "aliquota_ICMS70": "NFe/infNFe/det/imposto/ICMS/ICMS70/pFCPST",
+ "valor_ICMS70": "NFe/infNFe/det/imposto/ICMS/ICMS70/vFCPST",
+ "aliquota_ICMS90": "NFe/infNFe/det/imposto/ICMS/ICMS90/pFCPST",
+ "valor_ICMS90": "NFe/infNFe/det/imposto/ICMS/ICMS90/vFCPST",
+ "aliquota_ICMSPart": "NFe/infNFe/det/imposto/ICMS/ICMSPart/pFCPST",
+ "valor_ICMSPart": "NFe/infNFe/det/imposto/ICMS/ICMSPart/vFCPST",
+ "aliquota_ICMSST": "NFe/infNFe/det/imposto/ICMS/ICMSST/pFCPSTRet",
+ "valor_ICMSST": "NFe/infNFe/det/imposto/ICMS/ICMSST/vFCPSTRet",
+ "aliquota_ICMSSN201": "NFe/infNFe/det/imposto/ICMS/ICMSSN201/pFCPST",
+ "valor_ICMSSN201": "NFe/infNFe/det/imposto/ICMS/ICMSSN201/vFCPST",
+ "aliquota_ICMSSN202": "NFe/infNFe/det/imposto/ICMS/ICMSSN202/pFCPST",
+ "valor_ICMSSN202": "NFe/infNFe/det/imposto/ICMS/ICMSSN202/vFCPST",
+ "aliquota_ICMSSN500": "NFe/infNFe/det/imposto/ICMS/ICMSSN500/pFCPSTRet",
+ "valor_ICMSSN500": "NFe/infNFe/det/imposto/ICMS/ICMSSN500/vFCPSTRet",
+ "aliquota_ICMSSN900": "NFe/infNFe/det/imposto/ICMS/ICMSSN900/pFCPST",
+ "valor_ICMSSN900": "NFe/infNFe/det/imposto/ICMS/ICMSSN900/vFCPST"
+ },
+ "desoneracao": {
+ "valor_ICMS10": "NFe/infNFe/det/imposto/ICMS/ICMS10/vICMSSTDeson",
+ "motivo_ICMS10": "NFe/infNFe/det/imposto/ICMS/ICMS10/motDesICMSST",
+ "valor_ICMS70": "NFe/infNFe/det/imposto/ICMS/ICMS70/vICMSSTDeson",
+ "motivo_ICMS70": "NFe/infNFe/det/imposto/ICMS/ICMS70/motDesICMSST",
+ "valor_ICMS90": "NFe/infNFe/det/imposto/ICMS/ICMS90/vICMSSTDeson",
+ "motivo_ICMS90": "NFe/infNFe/det/imposto/ICMS/ICMS90/motDesICMSST"
+ },
+ "aliquota_ICMS30": "NFe/infNFe/det/imposto/ICMS/ICMS30/pICMSST",
+ "valor_ICMS30": "NFe/infNFe/det/imposto/ICMS/ICMS30/vICMSST",
+ "aliquota_ICMS60": "NFe/infNFe/det/imposto/ICMS/ICMS60/pST",
+ "valor_ICMS60": "NFe/infNFe/det/imposto/ICMS/ICMS60/vICMSSTRet",
+ "aliquota_ICMS70": "NFe/infNFe/det/imposto/ICMS/ICMS70/pICMSST",
+ "valor_ICMS70": "NFe/infNFe/det/imposto/ICMS/ICMS70/vICMSST",
+ "aliquota_ICMS90": "NFe/infNFe/det/imposto/ICMS/ICMS90/pICMSST",
+ "valor_ICMS90": "NFe/infNFe/det/imposto/ICMS/ICMS90/vICMSST",
+ "aliquota_ICMSPart": "NFe/infNFe/det/imposto/ICMS/ICMSPart/pICMSST",
+ "valor_ICMSPart": "NFe/infNFe/det/imposto/ICMS/ICMSPart/vICMSST",
+ "ufDevido_ICMSPart": "NFe/infNFe/det/imposto/ICMS/ICMSPart/UFST",
+ "aliquota_ICMSST": "NFe/infNFe/det/imposto/ICMS/ICMSST/pST",
+ "valor_ICMSST": "NFe/infNFe/det/imposto/ICMS/ICMSST/vICMSSTRet",
+ "ufDestino": {
+ "baseCalculo": {
+ "valor_ICMSST": "NFe/infNFe/det/imposto/ICMS/ICMSST/vBCSTDest"
+ },
+ "valor_ICMSST": "NFe/infNFe/det/imposto/ICMS/ICMSST/vICMSSTDest"
+ },
+ "aliquota_ICMSSN201": "NFe/infNFe/det/imposto/ICMS/ICMSSN201/pICMSST",
+ "valor_ICMSSN201": "NFe/infNFe/det/imposto/ICMS/ICMSSN201/vICMSST",
+ "aliquota_ICMSSN202": "NFe/infNFe/det/imposto/ICMS/ICMSSN202/pICMSST",
+ "valor_ICMSSN202": "NFe/infNFe/det/imposto/ICMS/ICMSSN202/vICMSST",
+ "aliquota_ICMSSN500": "NFe/infNFe/det/imposto/ICMS/ICMSSN500/pST",
+ "valor_ICMSSN500": "NFe/infNFe/det/imposto/ICMS/ICMSSN500/vICMSSTRet",
+ "aliquota_ICMSSN900": "NFe/infNFe/det/imposto/ICMS/ICMSSN900/pICMSST",
+ "valor_ICMSSN900": "NFe/infNFe/det/imposto/ICMS/ICMSSN900/vICMSST"
+ },
+ "origem_ICMS15": "NFe/infNFe/det/imposto/ICMS/ICMS15/orig",
+ "cst_ICMS15": "NFe/infNFe/det/imposto/ICMS/ICMS15/CST",
+ "baseCalculoMono_ICMS15": "NFe/infNFe/det/imposto/ICMS/ICMS15/qBCMono",
+ "valorIcmsMono_ICMS15": "NFe/infNFe/det/imposto/ICMS/ICMS15/vICMSMono",
+ "aliquotaAdRem_ICMS15": "NFe/infNFe/det/imposto/ICMS/ICMS15/adRemICMS",
+ "baseCalculoMonoRetencao_ICMS15": "NFe/infNFe/det/imposto/ICMS/ICMS15/qBCMonoReten",
+ "aliquotaAdRemRetencao_ICMS15": "NFe/infNFe/det/imposto/ICMS/ICMS15/adRemICMSReten",
+ "valorIcmsMonoRetencao_ICMS15": "NFe/infNFe/det/imposto/ICMS/ICMS15/vICMSMonoReten",
+ "percentualReducaoAdRem_ICMS15": "NFe/infNFe/det/imposto/ICMS/ICMS15/pRedAdRem",
+ "motivoReducaoAdRem_ICMS15": "NFe/infNFe/det/imposto/ICMS/ICMS15/motRedAdRem",
+ "origem_ICMS20": "NFe/infNFe/det/imposto/ICMS/ICMS20/orig",
+ "cst_ICMS20": "NFe/infNFe/det/imposto/ICMS/ICMS20/CST",
+ "aliquota_ICMS20": "NFe/infNFe/det/imposto/ICMS/ICMS20/pICMS",
+ "valor_ICMS20": "NFe/infNFe/det/imposto/ICMS/ICMS20/vICMS",
+ "desoneracao": {
+ "valor_ICMS20": "NFe/infNFe/det/imposto/ICMS/ICMS20/vICMSDeson",
+ "deduzItem_ICMS20": "NFe/infNFe/det/imposto/ICMS/ICMS20/indDeduzDeson",
+ "motivo_ICMS20": "NFe/infNFe/det/imposto/ICMS/ICMS20/motDesICMS",
+ "valor_ICMS30": "NFe/infNFe/det/imposto/ICMS/ICMS30/vICMSDeson",
+ "deduzItem_ICMS30": "NFe/infNFe/det/imposto/ICMS/ICMS30/indDeduzDeson",
+ "motivo_ICMS30": "NFe/infNFe/det/imposto/ICMS/ICMS30/motDesICMS",
+ "valor_ICMS40": "NFe/infNFe/det/imposto/ICMS/ICMS40/vICMSDeson",
+ "deduzItem_ICMS40": "NFe/infNFe/det/imposto/ICMS/ICMS40/indDeduzDeson",
+ "motivo_ICMS40": "NFe/infNFe/det/imposto/ICMS/ICMS40/motDesICMS",
+ "valor_ICMS70": "NFe/infNFe/det/imposto/ICMS/ICMS70/vICMSDeson",
+ "deduzItem_ICMS70": "NFe/infNFe/det/imposto/ICMS/ICMS70/indDeduzDeson",
+ "motivo_ICMS70": "NFe/infNFe/det/imposto/ICMS/ICMS70/motDesICMS",
+ "valor_ICMS90": "NFe/infNFe/det/imposto/ICMS/ICMS90/vICMSDeson",
+ "deduzItem_ICMS90": "NFe/infNFe/det/imposto/ICMS/ICMS90/indDeduzDeson",
+ "motivo_ICMS90": "NFe/infNFe/det/imposto/ICMS/ICMS90/motDesICMS"
+ },
+ "origem_ICMS30": "NFe/infNFe/det/imposto/ICMS/ICMS30/orig",
+ "cst_ICMS30": "NFe/infNFe/det/imposto/ICMS/ICMS30/CST",
+ "origem_ICMS40": "NFe/infNFe/det/imposto/ICMS/ICMS40/orig",
+ "cst_ICMS40": "NFe/infNFe/det/imposto/ICMS/ICMS40/CST",
+ "origem_ICMS51": "NFe/infNFe/det/imposto/ICMS/ICMS51/orig",
+ "cst_ICMS51": "NFe/infNFe/det/imposto/ICMS/ICMS51/CST",
+ "codigoBeneficioFiscalRBC_ICMS51": "NFe/infNFe/det/imposto/ICMS/ICMS51/cBenefRBC",
+ "aliquota_ICMS51": "NFe/infNFe/det/imposto/ICMS/ICMS51/pICMS",
+ "valor_ICMS51": "NFe/infNFe/det/imposto/ICMS/ICMS51/vICMSOp",
+ "diferimento": {
+ "percentual_ICMS51": "NFe/infNFe/det/imposto/ICMS/ICMS51/pDif",
+ "valor_ICMS51": "NFe/infNFe/det/imposto/ICMS/ICMS51/vICMSDif",
+ "valorIcmsDevido_ICMS51": "NFe/infNFe/det/imposto/ICMS/ICMS51/vICMS"
+ },
+ "origem_ICMS53": "NFe/infNFe/det/imposto/ICMS/ICMS53/orig",
+ "cst_ICMS53": "NFe/infNFe/det/imposto/ICMS/ICMS53/CST",
+ "baseCalculoMonoDiferido_ICMS53": "NFe/infNFe/det/imposto/ICMS/ICMS53/qBCMonoDif",
+ "aliquotaAdRemDiferido_ICMS53": "NFe/infNFe/det/imposto/ICMS/ICMS53/adRemICMSDif",
+ "valorIcmsDiferido_ICMS53": "NFe/infNFe/det/imposto/ICMS/ICMS53/vICMSMonoDif",
+ "baseCalculoMono_ICMS53": "NFe/infNFe/det/imposto/ICMS/ICMS53/qBCMono",
+ "aliquotaAdRem_ICMS53": "NFe/infNFe/det/imposto/ICMS/ICMS53/adRemICMS",
+ "valorIcmsMonoOperacao_ICMS53": "NFe/infNFe/det/imposto/ICMS/ICMS53/vICMSMonoOp",
+ "percentualDiferimento_ICMS53": "NFe/infNFe/det/imposto/ICMS/ICMS53/pDif",
+ "valorIcmsMono_ICMS53": "NFe/infNFe/det/imposto/ICMS/ICMS53/vICMSMono",
+ "origem_ICMS60": "NFe/infNFe/det/imposto/ICMS/ICMS60/orig",
+ "cst_ICMS60": "NFe/infNFe/det/imposto/ICMS/ICMS60/CST",
+ "valor_ICMS60": "NFe/infNFe/det/imposto/ICMS/ICMS60/vICMSSubstituto",
+ "efetivo": {
+ "baseCalculo": {
+ "percentualReducao_ICMS60": "NFe/infNFe/det/imposto/ICMS/ICMS60/pRedBCEfet",
+ "valor_ICMS60": "NFe/infNFe/det/imposto/ICMS/ICMS60/vBCEfet",
+ "percentualReducao_ICMSST": "NFe/infNFe/det/imposto/ICMS/ICMSST/pRedBCEfet",
+ "valor_ICMSST": "NFe/infNFe/det/imposto/ICMS/ICMSST/vBCEfet",
+ "percentualReducao_ICMSSN500": "NFe/infNFe/det/imposto/ICMS/ICMSSN500/pRedBCEfet",
+ "valor_ICMSSN500": "NFe/infNFe/det/imposto/ICMS/ICMSSN500/vBCEfet"
+ },
+ "aliquota_ICMS60": "NFe/infNFe/det/imposto/ICMS/ICMS60/pICMSEfet",
+ "valor_ICMS60": "NFe/infNFe/det/imposto/ICMS/ICMS60/vICMSEfet",
+ "aliquota_ICMSST": "NFe/infNFe/det/imposto/ICMS/ICMSST/pICMSEfet",
+ "valor_ICMSST": "NFe/infNFe/det/imposto/ICMS/ICMSST/vICMSEfet",
+ "aliquota_ICMSSN500": "NFe/infNFe/det/imposto/ICMS/ICMSSN500/pICMSEfet",
+ "valor_ICMSSN500": "NFe/infNFe/det/imposto/ICMS/ICMSSN500/vICMSEfet"
+ },
+ "origem_ICMS61": "NFe/infNFe/det/imposto/ICMS/ICMS61/orig",
+ "cst_ICMS61": "NFe/infNFe/det/imposto/ICMS/ICMS61/CST",
+ "baseCalculoMonoRetido_ICMS61": "NFe/infNFe/det/imposto/ICMS/ICMS61/qBCMonoRet",
+ "aliquotaAdRemRetido_ICMS61": "NFe/infNFe/det/imposto/ICMS/ICMS61/adRemICMSRet",
+ "valorIcmsMonoRetido_ICMS61": "NFe/infNFe/det/imposto/ICMS/ICMS61/vICMSMonoRet",
+ "origem_ICMS70": "NFe/infNFe/det/imposto/ICMS/ICMS70/orig",
+ "cst_ICMS70": "NFe/infNFe/det/imposto/ICMS/ICMS70/CST",
+ "aliquota_ICMS70": "NFe/infNFe/det/imposto/ICMS/ICMS70/pICMS",
+ "valor_ICMS70": "NFe/infNFe/det/imposto/ICMS/ICMS70/vICMS",
+ "origem_ICMS90": "NFe/infNFe/det/imposto/ICMS/ICMS90/orig",
+ "cst_ICMS90": "NFe/infNFe/det/imposto/ICMS/ICMS90/CST",
+ "aliquota_ICMS90": "NFe/infNFe/det/imposto/ICMS/ICMS90/pICMS",
+ "valor_ICMS90": "NFe/infNFe/det/imposto/ICMS/ICMS90/vICMS",
+ "origem_ICMSPart": "NFe/infNFe/det/imposto/ICMS/ICMSPart/orig",
+ "cst_ICMSPart": "NFe/infNFe/det/imposto/ICMS/ICMSPart/CST",
+ "aliquota_ICMSPart": "NFe/infNFe/det/imposto/ICMS/ICMSPart/pICMS",
+ "valor_ICMSPart": "NFe/infNFe/det/imposto/ICMS/ICMSPart/vICMS",
+ "operacaoPropria": {
+ "baseCalculo": {
+ "percentual_ICMSPart": "NFe/infNFe/det/imposto/ICMS/ICMSPart/pBCOp"
+ }
+ },
+ "origem_ICMSST": "NFe/infNFe/det/imposto/ICMS/ICMSST/orig",
+ "cst_ICMSST": "NFe/infNFe/det/imposto/ICMS/ICMSST/CST",
+ "valor_ICMSST": "NFe/infNFe/det/imposto/ICMS/ICMSST/vICMSSubstituto",
+ "origem_ICMSSN101": "NFe/infNFe/det/imposto/ICMS/ICMSSN101/orig",
+ "csosn_ICMSSN101": "NFe/infNFe/det/imposto/ICMS/ICMSSN101/CSOSN",
+ "creditoSimplesNacional": {
+ "percentual_ICMSSN101": "NFe/infNFe/det/imposto/ICMS/ICMSSN101/pCredSN",
+ "valor_ICMSSN101": "NFe/infNFe/det/imposto/ICMS/ICMSSN101/vCredICMSSN",
+ "percentual_ICMSSN201": "NFe/infNFe/det/imposto/ICMS/ICMSSN201/pCredSN",
+ "valor_ICMSSN201": "NFe/infNFe/det/imposto/ICMS/ICMSSN201/vCredICMSSN",
+ "percentual_ICMSSN900": "NFe/infNFe/det/imposto/ICMS/ICMSSN900/pCredSN",
+ "valor_ICMSSN900": "NFe/infNFe/det/imposto/ICMS/ICMSSN900/vCredICMSSN"
+ },
+ "origem_ICMSSN102": "NFe/infNFe/det/imposto/ICMS/ICMSSN102/orig",
+ "csosn_ICMSSN102": "NFe/infNFe/det/imposto/ICMS/ICMSSN102/CSOSN",
+ "origem_ICMSSN201": "NFe/infNFe/det/imposto/ICMS/ICMSSN201/orig",
+ "csosn_ICMSSN201": "NFe/infNFe/det/imposto/ICMS/ICMSSN201/CSOSN",
+ "origem_ICMSSN202": "NFe/infNFe/det/imposto/ICMS/ICMSSN202/orig",
+ "csosn_ICMSSN202": "NFe/infNFe/det/imposto/ICMS/ICMSSN202/CSOSN",
+ "origem_ICMSSN500": "NFe/infNFe/det/imposto/ICMS/ICMSSN500/orig",
+ "csosn_ICMSSN500": "NFe/infNFe/det/imposto/ICMS/ICMSSN500/CSOSN",
+ "valor_ICMSSN500": "NFe/infNFe/det/imposto/ICMS/ICMSSN500/vICMSSubstituto",
+ "origem_ICMSSN900": "NFe/infNFe/det/imposto/ICMS/ICMSSN900/orig",
+ "csosn_ICMSSN900": "NFe/infNFe/det/imposto/ICMS/ICMSSN900/CSOSN",
+ "aliquota_ICMSSN900": "NFe/infNFe/det/imposto/ICMS/ICMSSN900/pICMS",
+ "valor_ICMSSN900": "NFe/infNFe/det/imposto/ICMS/ICMSSN900/vICMS"
+ },
+ "is": {
+ "cst": "NFe/infNFe/det/imposto/IS/CSTIS",
+ "classificao": "NFe/infNFe/det/imposto/IS/cClassTribIS",
+ "baseCalculo": "NFe/infNFe/det/imposto/IS/vBCIS",
+ "aliquota": "NFe/infNFe/det/imposto/IS/pIS",
+ "aliquotaEspecifica": "NFe/infNFe/det/imposto/IS/pISEspec",
+ "unidade": "NFe/infNFe/det/imposto/IS/uTrib",
+ "quantidade": "NFe/infNFe/det/imposto/IS/qTrib",
+ "valor": "NFe/infNFe/det/imposto/IS/vIS"
+ },
+ "ibscbs": {
+ "cst": "NFe/infNFe/det/imposto/IBSCBS/CST",
+ "classificacao": "NFe/infNFe/det/imposto/IBSCBS/cClassTrib",
+ "baseCalculo": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/vBC",
+ "uf": {
+ "aliquota": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gIBSUF/pIBSUF",
+ "diferimento": {
+ "aliquota": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gIBSUF/gDif/pDif",
+ "valor": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gIBSUF/gDif/vDif"
+ },
+ "devolucao": {
+ "valor": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gIBSUF/gDevTrib/vDevTrib"
+ },
+ "reducao": {
+ "aliquota": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gIBSUF/gRed/pRedAliq",
+ "aliquotaEfetiva": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gIBSUF/gRed/pAliqEfet"
+ },
+ "valor": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gIBSUF/vIBSUF"
+ },
+ "municipio": {
+ "aliquota": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gIBSMun/pIBSMun",
+ "diferimento": {
+ "aliquota": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gIBSMun/gDif/pDif",
+ "valor": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gIBSMun/gDif/vDif"
+ },
+ "devolucao": {
+ "valor": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gIBSMun/gDevTrib/vDevTrib"
+ },
+ "reducao": {
+ "aliquota": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gIBSMun/gRed/pRedAliq",
+ "aliquotaEfetiva": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gIBSMun/gRed/pAliqEfet"
+ },
+ "valor": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gIBSMun/vIBSMun"
+ },
+ "cbs": {
+ "aliquota": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gCBS/pCBS",
+ "diferimento": {
+ "aliquota": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gCBS/gDif/pDif",
+ "valor": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gCBS/gDif/vDif"
+ },
+ "devolucao": {
+ "valor": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gCBS/gDevTrib/vDevTrib"
+ },
+ "reducao": {
+ "aliquota": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gCBS/gRed/pRedAliq",
+ "aliquotaEfetiva": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gCBS/gRed/pAliqEfet"
+ },
+ "valor": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gCBS/vCBS"
+ },
+ "tributacaoRegular": {
+ "cts": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gTribRegular/CSTReg",
+ "classificacao": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gTribRegular/cClassTribReg",
+ "aliquotaUF": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gTribRegular/pAliqEfetRegIBSUF",
+ "valorUF": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gTribRegular/vTribRegIBSUF",
+ "aliquotaMunicipio": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gTribRegular/pAliqEfetRegIBSMun",
+ "valorMunicipio": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gTribRegular/vTribRegIBSMun",
+ "aliquota": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gTribRegular/pAliqEfetRegCBS",
+ "valor": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gTribRegular/vTribRegCBS"
+ },
+ "ibsCreditoPresumido": {
+ "codigo": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gIBSCredPres/cCredPres",
+ "percentual": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gIBSCredPres/pCredPres",
+ "valor": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gIBSCredPres/vCredPres",
+ "valorSuspensivo": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gIBSCredPres/vCredPresCondSus"
+ },
+ "cbsCreditoPresumido": {
+ "codigo": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gCBSCredPres/cCredPres",
+ "percentual": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gCBSCredPres/pCredPres",
+ "valor": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gCBSCredPres/vCredPres",
+ "valorSuspensivo": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gCBSCredPres/vCredPresCondSus"
+ },
+ "compraGovernamental": {
+ "aliquotaUF": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gTribCompraGov/pAliqIBSUF",
+ "valorUF": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gTribCompraGov/vTribIBSUF",
+ "aliquotaMunicipio": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gTribCompraGov/pAliqIBSMun",
+ "valorMunicipio": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gTribCompraGov/vTribIBSMun",
+ "aliquotaCbs": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gTribCompraGov/pAliqCBS",
+ "valorCbs": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gTribCompraGov/vTribCBS"
+ },
+ "monofasico": {
+ "quantidade": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/qBCMono",
+ "aliquotaAdRemIbs": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/adRemIBS",
+ "aliquotaAdRemCbs": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/adRemCBS",
+ "valorIbs": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/vIBSMono",
+ "valorCbs": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/vCBSMono",
+ "quantidadeRetencao": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/qBCMonoReten",
+ "aliquotaAdRemIbsRetencao": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/adRemIBSReten",
+ "valorIbsRetencao": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/vIBSMonoReten",
+ "aliquotaAdRemCbsRetencao": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/adRemCBSReten",
+ "valorCbsRetencao": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/vCBSMonoReten",
+ "quantidadeRetida": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/qBCMonoRet",
+ "aliquotaAdRemIbsRetida": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/adRemIBSRet",
+ "valorIbsRetido": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/vIBSMonoRet",
+ "aliquotaAdRemCbsRetida": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/adRemCBSRet",
+ "valorCbsRetida": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/vCBSMonoRet",
+ "aliquotaIbsDiferimento": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/pDifIBS",
+ "valorIbsDiferimento": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/vIBSMonoDif",
+ "aliquotaCbsDiferimento": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/pDifCBS",
+ "valorCbsDiferimento": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/vCBSMonoDif",
+ "valorTotalIbs": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/vTotIBSMonoItem",
+ "valorTotalCbs": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/vTotCBSMonoItem"
+ },
+ "transferenciaCredito": {
+ "valorIbs": "NFe/infNFe/det/imposto/IBSCBS/gTransfCred/vIBS",
+ "valorCbs": "NFe/infNFe/det/imposto/IBSCBS/gTransfCred/vCBS"
+ },
+ "creditoPresumidoZfm": {
+ "tipo": "NFe/infNFe/det/imposto/IBSCBS/gCredPresIBSZFM/tpCredPresIBSZFM",
+ "valor": "NFe/infNFe/det/imposto/IBSCBS/gCredPresIBSZFM/vCredPresIBSZFM"
+ }
+ },
+ "ipi": {
+ "cnpjProdutor": "NFe/infNFe/det/imposto/IPI/CNPJProd",
+ "seloControle": {
+ "codigo": "NFe/infNFe/det/imposto/IPI/cSelo",
+ "quantidade": "NFe/infNFe/det/imposto/IPI/qSelo"
+ },
+ "codigoEnquadramentoLegal": "NFe/infNFe/det/imposto/IPI/cEnq",
+ "cst_IPITrib": "NFe/infNFe/det/imposto/IPI/IPITrib/CST",
+ "baseCalculo_IPITrib": "NFe/infNFe/det/imposto/IPI/IPITrib/vBC",
+ "unidade": {
+ "quantidade_IPITrib": "NFe/infNFe/det/imposto/IPI/IPITrib/qUnid",
+ "valor_IPITrib": "NFe/infNFe/det/imposto/IPI/IPITrib/vUnid"
+ },
+ "aliquota_IPITrib": "NFe/infNFe/det/imposto/IPI/IPITrib/pIPI",
+ "valor_IPITrib": "NFe/infNFe/det/imposto/IPI/IPITrib/vIPI",
+ "cst_IPINT": "NFe/infNFe/det/imposto/IPI/IPINT/CST"
+ },
+ "importacao": {
+ "baseCalculo": "NFe/infNFe/det/imposto/II/vBC",
+ "valorDespesasAduaneiras": "NFe/infNFe/det/imposto/II/vDespAdu",
+ "valor": "NFe/infNFe/det/imposto/II/vII",
+ "valorOperacoesFinanceiras": "NFe/infNFe/det/imposto/II/vIOF"
+ },
+ "issqn": {
+ "baseCalculo": "NFe/infNFe/det/imposto/ISSQN/vBC",
+ "aliquota": "NFe/infNFe/det/imposto/ISSQN/vAliq",
+ "valor": "NFe/infNFe/det/imposto/ISSQN/vISSQN",
+ "codigoMunicipioFatoGerador": "NFe/infNFe/det/imposto/ISSQN/cMunFG",
+ "codigoServico": "NFe/infNFe/det/imposto/ISSQN/cListServ",
+ "valorDeducao": "NFe/infNFe/det/imposto/ISSQN/vDeducao",
+ "valorOutros": "NFe/infNFe/det/imposto/ISSQN/vOutro",
+ "descontoIncondicionado": "NFe/infNFe/det/imposto/ISSQN/vDescIncond",
+ "descontoCondicionado": "NFe/infNFe/det/imposto/ISSQN/vDescCond",
+ "valorRetencaoIss": "NFe/infNFe/det/imposto/ISSQN/vISSRet",
+ "codigoExigibilidade": "NFe/infNFe/det/imposto/ISSQN/indISS",
+ "codigoMunicipalServico": "NFe/infNFe/det/imposto/ISSQN/cServico",
+ "codigoMunicipioIncidencia": "NFe/infNFe/det/imposto/ISSQN/cMun",
+ "codigoPais": "NFe/infNFe/det/imposto/ISSQN/cPais",
+ "numeroProcessoSuspensao": "NFe/infNFe/det/imposto/ISSQN/nProcesso",
+ "incentivoFiscal": "NFe/infNFe/det/imposto/ISSQN/indIncentivo"
+ },
+ "pis": {
+ "cst_PISAliq": "NFe/infNFe/det/imposto/PIS/PISAliq/CST",
+ "baseCalculo": {
+ "valor_PISAliq": "NFe/infNFe/det/imposto/PIS/PISAliq/vBC",
+ "valor_PISOutr": "NFe/infNFe/det/imposto/PIS/PISOutr/vBC"
+ },
+ "aliquota_PISAliq": "NFe/infNFe/det/imposto/PIS/PISAliq/pPIS",
+ "valor_PISAliq": "NFe/infNFe/det/imposto/PIS/PISAliq/vPIS",
+ "cst_PISQtde": "NFe/infNFe/det/imposto/PIS/PISQtde/CST",
+ "quantidadeVendida_PISQtde": "NFe/infNFe/det/imposto/PIS/PISQtde/qBCProd",
+ "aliquotaReais_PISQtde": "NFe/infNFe/det/imposto/PIS/PISQtde/vAliqProd",
+ "valor_PISQtde": "NFe/infNFe/det/imposto/PIS/PISQtde/vPIS",
+ "cst_PISNT": "NFe/infNFe/det/imposto/PIS/PISNT/CST",
+ "cst_PISOutr": "NFe/infNFe/det/imposto/PIS/PISOutr/CST",
+ "aliquota_PISOutr": "NFe/infNFe/det/imposto/PIS/PISOutr/pPIS",
+ "quantidadeVendida_PISOutr": "NFe/infNFe/det/imposto/PIS/PISOutr/qBCProd",
+ "aliquotaReais_PISOutr": "NFe/infNFe/det/imposto/PIS/PISOutr/vAliqProd",
+ "valor_PISOutr": "NFe/infNFe/det/imposto/PIS/PISOutr/vPIS",
+ "substituicaoTributaria": {
+ "baseCalculo": "NFe/infNFe/det/imposto/PISST/vBC",
+ "aliquota": "NFe/infNFe/det/imposto/PISST/pPIS",
+ "quantidadeVendida": "NFe/infNFe/det/imposto/PISST/qBCProd",
+ "aliquotaReais": "NFe/infNFe/det/imposto/PISST/vAliqProd",
+ "valor": "NFe/infNFe/det/imposto/PISST/vPIS",
+ "compoeTotal": "NFe/infNFe/det/imposto/PISST/indSomaPISST"
+ }
+ },
+ "cofins": {
+ "cst_COFINSAliq": "NFe/infNFe/det/imposto/COFINS/COFINSAliq/CST",
+ "baseCalculo": {
+ "valor_COFINSAliq": "NFe/infNFe/det/imposto/COFINS/COFINSAliq/vBC",
+ "valor_COFINSOutr": "NFe/infNFe/det/imposto/COFINS/COFINSOutr/vBC"
+ },
+ "aliquota_COFINSAliq": "NFe/infNFe/det/imposto/COFINS/COFINSAliq/pCOFINS",
+ "valor_COFINSAliq": "NFe/infNFe/det/imposto/COFINS/COFINSAliq/vCOFINS",
+ "cst_COFINSQtde": "NFe/infNFe/det/imposto/COFINS/COFINSQtde/CST",
+ "quantidadeVendida_COFINSQtde": "NFe/infNFe/det/imposto/COFINS/COFINSQtde/qBCProd",
+ "aliquotaReais_COFINSQtde": "NFe/infNFe/det/imposto/COFINS/COFINSQtde/vAliqProd",
+ "valor_COFINSQtde": "NFe/infNFe/det/imposto/COFINS/COFINSQtde/vCOFINS",
+ "cst_COFINSNT": "NFe/infNFe/det/imposto/COFINS/COFINSNT/CST",
+ "cst_COFINSOutr": "NFe/infNFe/det/imposto/COFINS/COFINSOutr/CST",
+ "aliquota_COFINSOutr": "NFe/infNFe/det/imposto/COFINS/COFINSOutr/pCOFINS",
+ "quantidadeVendida_COFINSOutr": "NFe/infNFe/det/imposto/COFINS/COFINSOutr/qBCProd",
+ "aliquotaReais_COFINSOutr": "NFe/infNFe/det/imposto/COFINS/COFINSOutr/vAliqProd",
+ "valor_COFINSOutr": "NFe/infNFe/det/imposto/COFINS/COFINSOutr/vCOFINS",
+ "substituicaoTributaria": {
+ "baseCalculo": "NFe/infNFe/det/imposto/COFINSST/vBC",
+ "aliquota": "NFe/infNFe/det/imposto/COFINSST/pCOFINS",
+ "quantidadeVendida": "NFe/infNFe/det/imposto/COFINSST/qBCProd",
+ "aliquotaReais": "NFe/infNFe/det/imposto/COFINSST/vAliqProd",
+ "valor": "NFe/infNFe/det/imposto/COFINSST/vCOFINS",
+ "compoeTotal": "NFe/infNFe/det/imposto/COFINSST/indSomaCOFINSST"
+ }
+ },
+ "partilha": {
+ "ufDestino": {
+ "baseCalculoIcms": "NFe/infNFe/det/imposto/ICMSUFDest/vBCUFDest",
+ "baseCalculoFcp": "NFe/infNFe/det/imposto/ICMSUFDest/vBCFCPUFDest",
+ "percentualIcmsFcp": "NFe/infNFe/det/imposto/ICMSUFDest/pFCPUFDest",
+ "aliquotaInterna": "NFe/infNFe/det/imposto/ICMSUFDest/pICMSUFDest",
+ "aliquotaInterestadual": "NFe/infNFe/det/imposto/ICMSUFDest/pICMSInter",
+ "percentualProvisorioIcmsInterestadual": "NFe/infNFe/det/imposto/ICMSUFDest/pICMSInterPart",
+ "icmsRelativoFcp": "NFe/infNFe/det/imposto/ICMSUFDest/vFCPUFDest",
+ "icmsInterestadual": "NFe/infNFe/det/imposto/ICMSUFDest/vICMSUFDest"
+ },
+ "ufRemetente": {
+ "icmsInterestadual": "NFe/infNFe/det/imposto/ICMSUFDest/vICMSUFRemet"
+ }
+ },
+ "percentualMercadoriaDevolvida": "NFe/infNFe/det/impostoDevol/pDevol",
+ "valorIpiDevolvido": "NFe/infNFe/det/impostoDevol/IPI/vIPIDevol"
+ },
+ "informacoesComplementares": "NFe/infNFe/det/infAdProd",
+ "numero": "NFe/infNFe/det/@nItem",
+ "nve": [{"numero": "NFe/infNFe/det/prod/NVE"}],
+ "importacao": [{
+ "numero": "NFe/infNFe/det/prod/DI/nDI",
+ "dataEmissao": "NFe/infNFe/det/prod/DI/dDI",
+ "desembaraco": {
+ "local": "NFe/infNFe/det/prod/DI/xLocDesemb",
+ "estado": "NFe/infNFe/det/prod/DI/UFDesemb",
+ "data": "NFe/infNFe/det/prod/DI/dDesemb"
+ },
+ "viaTransporte": "NFe/infNFe/det/prod/DI/tpViaTransp",
+ "valorAfrmm": "NFe/infNFe/det/prod/DI/vAFRMM",
+ "formaImportacao": "NFe/infNFe/det/prod/DI/tpIntermedio",
+ "adquirente": {
+ "cnpj": "NFe/infNFe/det/prod/DI/CNPJ",
+ "cpf": "NFe/infNFe/det/prod/DI/CPF",
+ "estado": "NFe/infNFe/det/prod/DI/UFTerceiro"
+ },
+ "codigoExportador": "NFe/infNFe/det/prod/DI/cExportador",
+ "adicoes": [{
+ "numero": "NFe/infNFe/det/prod/DI/adi/nAdicao",
+ "numeroSequencia": "NFe/infNFe/det/prod/DI/adi/nSeqAdic",
+ "codigoFabricante": "NFe/infNFe/det/prod/DI/adi/cFabricante",
+ "valorDesconto": "NFe/infNFe/det/prod/DI/adi/vDescDI",
+ "numeroDrawback": "NFe/infNFe/det/prod/DI/adi/nDraw"
+ }]
+ }],
+ "exportacao": [{
+ "numeroDrawback": "NFe/infNFe/det/prod/detExport/nDraw",
+ "exportacaoIndireta": {
+ "numero": "NFe/infNFe/det/prod/detExport/exportInd/nRE",
+ "chave": "NFe/infNFe/det/prod/detExport/exportInd/chNFe",
+ "quantidade": "NFe/infNFe/det/prod/detExport/exportInd/qExport"
+ }
+ }],
+ "rastreavel": [{
+ "lote": "NFe/infNFe/det/prod/rastro/nLote",
+ "quantidade": "NFe/infNFe/det/prod/rastro/qLote",
+ "dataFabricacao": "NFe/infNFe/det/prod/rastro/dFab",
+ "dataValidade": "NFe/infNFe/det/prod/rastro/dVal",
+ "codigoAgregacao": "NFe/infNFe/det/prod/rastro/cAgreg"
+ }],
+ "armamentos": [{
+ "tipo": "NFe/infNFe/det/prod/arma/tpArma",
+ "numeroSerie": "NFe/infNFe/det/prod/arma/nSerie",
+ "numeroSerieCano": "NFe/infNFe/det/prod/arma/nCano",
+ "descricao": "NFe/infNFe/det/prod/arma/descr"
+ }],
+ "observacoes": {
+ "contribuinte": [{
+ "campo": "NFe/infNFe/det/obsItem/obsCont/@xCampo",
+ "texto": "NFe/infNFe/det/obsItem/obsCont/xTexto"
+ }],
+ "fisco": [{
+ "texto": "NFe/infNFe/det/obsItem/obsFisco/@xCampo",
+ "campo": "NFe/infNFe/det/obsItem/obsFisco/xTexto"
+ }]
+ },
+ "valorTotal": "NFe/infNFe/det/vItem",
+ "dfeReferenciado": {
+ "chaveAcesso": "NFe/infNFe/det/DFeReferenciado/chaveAcesso",
+ "numero": "NFe/infNFe/det/DFeReferenciado/nItem"
+ }
+ }],
+ "pagamentos": [{
+ "aVista": "NFe/infNFe/pag/detPag/indPag",
+ "meio": "NFe/infNFe/pag/detPag/tPag",
+ "descricaoMeio": "NFe/infNFe/pag/detPag/xPag",
+ "valor": "NFe/infNFe/pag/detPag/vPag",
+ "cartao": {
+ "tipoIntegracao": "NFe/infNFe/pag/detPag/card/tpIntegra",
+ "cnpjCredenciadora": "NFe/infNFe/pag/detPag/card/CNPJ",
+ "bandeiraOperadora": "NFe/infNFe/pag/detPag/card/tBand",
+ "numeroAutorizacao": "NFe/infNFe/pag/detPag/card/cAut"
+ }
+ }],
+ "pagamento": {
+ "data": "NFe/infNFe/pag/detPag/dPag",
+ "cnpjTransacional": "NFe/infNFe/pag/detPag/CNPJPag",
+ "ufTransacional": "NFe/infNFe/pag/detPag/UFPag",
+ "cartao": {
+ "cnpjBeneficiario": "NFe/infNFe/pag/detPag/card/CNPJReceb",
+ "idTerminal": "NFe/infNFe/pag/detPag/card/idTermPag"
+ }
+ },
+ "intermediadorTransacao": {
+ "cpfCnpj": "NFe/infNFe/infIntermed/CNPJ",
+ "identificadorCadastro": "NFe/infNFe/infIntermed/idCadIntTran"
+ },
+ "observacoes": {
+ "contribuinte": [{
+ "campo": "NFe/infNFe/infAdic/obsCont/@xCampo",
+ "texto": "NFe/infNFe/infAdic/obsCont/xTexto"
+ }],
+ "fisco": [{
+ "texto": "NFe/infNFe/infAdic/obsFisco/xTexto",
+ "campo": "NFe/infNFe/infAdic/obsFisco/@xCampo"
+ }]
+ },
+ "processoReferenciado": [{
+ "identificador": "NFe/infNFe/infAdic/procRef/nProc",
+ "origem": "NFe/infNFe/infAdic/procRef/indProc",
+ "tipo": "NFe/infNFe/infAdic/procRef/tpAto"
+ }],
+ "responsavelTecnico": {
+ "cpfCnpj": "NFe/infNFe/infRespTec/CNPJ",
+ "nome": "NFe/infNFe/infRespTec/xContato",
+ "email": "NFe/infNFe/infRespTec/email",
+ "telefone": "NFe/infNFe/infRespTec/fone",
+ "idCSRT": "NFe/infNFe/infRespTec/idCSRT",
+ "hashCSRT": "NFe/infNFe/infRespTec/hashCSRT"
+ },
+ "agropecuario": {
+ "defensivo": [{
+ "numeroReceituario": "NFe/infNFe/agropecuario/defensivo/nReceituario",
+ "cpfResponsavelTecnico": "NFe/infNFe/agropecuario/defensivo/CPFRespTec"
+ }],
+ "guiaTransito": {
+ "tipoGuia": "NFe/infNFe/agropecuario/guiaTransito/tpGuia",
+ "ufGuia": "NFe/infNFe/agropecuario/guiaTransito/UFGuia",
+ "serieGuia": "NFe/infNFe/agropecuario/guiaTransito/serieGuia",
+ "numeroGuia": "NFe/infNFe/agropecuario/guiaTransito/nGuia"
+ }
+ }
+}
\ No newline at end of file
diff --git a/pynfe/data/XSDs/NF-e/DFeTiposBasicos_v1.00.xsd b/pynfe/data/XSDs/NF-e/DFeTiposBasicos_v1.00.xsd
new file mode 100644
index 00000000..44e4ec49
--- /dev/null
+++ b/pynfe/data/XSDs/NF-e/DFeTiposBasicos_v1.00.xsd
@@ -0,0 +1,1097 @@
+
+
+
+
+
+ Tipo string genérico
+
+
+
+
+
+
+
+
+ Código Situação Tributária do IBS/CBS
+
+
+
+
+
+
+
+
+ Código de Classificação Tributária do IBS e da CBS
+
+
+
+
+
+
+
+
+ Código de Classificação do Crédito Presumido do IBS e da CBS, conforme tabela cCredPres
+
+
+
+
+
+
+
+
+ Tipo Decimal com 15 dígitos, sendo 11 de corpo e 4 decimais
+
+
+
+
+
+
+
+
+ Tipo Decimal com 11 inteiros, podendo ter 4 decimais (utilizado em tags opcionais)
+
+
+
+
+
+
+
+
+ Tipo Decimal com 15 dígitos, sendo 13 de corpo e 2 decimais
+
+
+
+
+
+
+
+
+ Tipo Decimal com até 3 dígitos inteiros, podendo ter de 2 até 4 decimais
+
+
+
+
+
+
+
+
+ Tipo da Operação com Ente Governamental
+
+
+
+
+
+
+
+
+
+ Tipo de Ente Governamental
+
+
+
+
+
+
+
+
+
+
+
+ Tipo de classificação do Crédito Presumido IBS ZFM
+
+
+
+
+
+
+
+
+
+
+
+ Grupo de informações da Tributação da NFCom
+
+
+
+
+ Código Situação Tributária do IBS/CBS
+
+
+
+
+
+
+
+
+ Grupo de informações da Tributação da NF3e
+
+
+
+
+ Código Situação Tributária do IBS/CBS
+
+
+
+
+
+
+
+
+ Grupo de informações da Tributação do CTe
+
+
+
+
+ Código Situação Tributária do IBS/CBS
+
+
+
+
+
+
+
+
+ Grupo de informações da Tributação do BPe
+
+
+
+
+ Código Situação Tributária do IBS/CBS
+
+
+
+
+
+
+
+
+ Grupo de informações da Tributação da NFCe
+
+
+
+
+ Código Situação Tributária do IBS/CBS
+
+
+
+
+
+
+
+
+
+
+
+ Grupo de informações da Tributação da NFe
+
+
+
+
+ Código Situação Tributária do IBS/CBS
+
+
+
+
+
+
+
+ Informar essa opção da Choice para Monofasia
+
+
+
+
+ Informar essa opção da Choice para o CST 800
+
+
+
+
+
+ Classificação de acordo com o art. 450, § 1º, da LC 214/25 para o cálculo do crédito presumido na ZFM
+
+
+
+
+
+
+ Grupo de informações do Imposto Seletivo
+
+
+
+
+ Código Situação Tributária do Imposto Seletivo
+
+
+
+
+
+
+ Valor do BC
+
+
+
+
+ Alíquota do Imposto Seletivo (percentual)
+
+
+
+
+ Alíquota do Imposto Seletivo (por valor)
+
+
+
+
+
+ Unidade de medida apropriada especificada em Lei Ordinaria para fins de apuração do Imposto Seletivo
+
+
+
+
+
+
+
+
+
+
+ Quantidade com abse no campo uTrib informado
+
+
+
+
+
+ Valor do Imposto Seletivo calculado
+
+
+
+
+
+
+
+ Grupo de informações de totais do Imposto Seletivo
+
+
+
+
+ Valor Total do Imposto Seletivo
+
+
+
+
+
+
+ Grupo de informações de totais da CBS/IBS
+
+
+
+
+ Total Base de Calculo
+
+
+
+
+ Totalização do IBS
+
+
+
+
+
+ Totalização do IBS de competência da UF
+
+
+
+
+
+ Total do Diferimento
+
+
+
+
+ Total de devoluções de tributos
+
+
+
+
+ Valor total do IBS Estadual
+
+
+
+
+
+
+
+ Totalização do IBS de competência Municipal
+
+
+
+
+
+ Total do Diferimento
+
+
+
+
+ Total de devoluções de tributos
+
+
+
+
+ Valor total do IBS Municipal
+
+
+
+
+
+
+
+ Valor total do IBS
+
+
+
+
+ Total do Crédito Presumido
+
+
+
+
+ Total do Crédito Presumido Condição Suspensiva
+
+
+
+
+
+
+
+ Totalização da CBS
+
+
+
+
+
+ Total do Diferimento
+
+
+
+
+ Total de devoluções de tributos
+
+
+
+
+ Valor total da CBS
+
+
+
+
+ Total do Crédito Presumido
+
+
+
+
+ Total do Crédito Presumido Condição Suspensiva
+
+
+
+
+
+
+
+
+
+ Grupo de informações de totais da CBS/IBS com monofasia
+
+
+
+
+ Total Base de Calculo
+
+
+
+
+ Totalização do IBS
+
+
+
+
+
+ Totalização do IBS de competência da UF
+
+
+
+
+
+ Total do Diferimento
+
+
+
+
+ Total de devoluções de tributos
+
+
+
+
+ Valor total do IBS Estadual
+
+
+
+
+
+
+
+ Totalização do IBS de competência Municipal
+
+
+
+
+
+ Total do Diferimento
+
+
+
+
+ Total de devoluções de tributos
+
+
+
+
+ Valor total do IBS Municipal
+
+
+
+
+
+
+
+ Valor total do IBS
+
+
+
+
+ Total do Crédito Presumido
+
+
+
+
+ Total do Crédito Presumido Condição Suspensiva
+
+
+
+
+
+
+
+ Totalização da CBS
+
+
+
+
+
+ Total do Diferimento
+
+
+
+
+ Total de devoluções de tributos
+
+
+
+
+ Valor total da CBS
+
+
+
+
+ Total do Crédito Presumido
+
+
+
+
+ Total do Crédito Presumido Condição Suspensiva
+
+
+
+
+
+
+
+ Totais da Monofasia
+ Só deverá ser utilizado para DFe modelos 55 e 65
+
+
+
+
+
+ Valor total do IBS monofásico
+
+
+
+
+ Valor total da CBS monofásica
+
+
+
+
+ Valor total do IBS monofásico sujeito a retenção
+
+
+
+
+ Valor total da CBS monofásica sujeita a retenção
+
+
+
+
+ Valor do IBS monofásico retido anteriormente
+
+
+
+
+ Valor da CBS monofásica retida anteriormente
+
+
+
+
+
+
+
+
+
+ Tipo Monofasia
+
+
+
+ Monofasia
+
+
+
+ Grupo de informações da Tributação Monofásica padrão
+
+
+
+
+
+ Quantidade tributada na monofasia
+
+
+
+
+ Alíquota ad rem do IBS
+
+
+
+
+ Alíquota ad rem da CBS
+
+
+
+
+ Valor do IBS monofásico
+
+
+
+
+ Valor da CBS monofásica
+
+
+
+
+
+
+
+ Grupo de informações da Tributação Monofásica sujeita a retenção
+
+
+
+
+
+ Quantidade tributada sujeita a retenção.
+
+
+
+
+ Alíquota ad rem do IBS sujeito a retenção
+
+
+
+
+ Valor do IBS monofásico sujeito a retenção
+
+
+
+
+ Alíquota ad rem da CBS sujeita a retenção
+
+
+
+
+ Valor da CBS monofásica sujeita a retenção
+
+
+
+
+
+
+
+ Grupo de informações da Tributação Monofásica retida anteriormente
+
+
+
+
+
+ Quantidade tributada retida anteriormente
+
+
+
+
+ Alíquota ad rem do IBS retido anteriormente
+
+
+
+
+ Valor do IBS retido anteriormente
+
+
+
+
+ Alíquota ad rem da CBS retida anteriormente
+
+
+
+
+ Valor da CBS retida anteriormente
+
+
+
+
+
+
+
+ Grupo de informações do diferimento da Tributação Monofásica
+
+
+
+
+
+ Percentual do diferimento do imposto monofásico
+
+
+
+
+ Valor do IBS monofásico diferido
+
+
+
+
+ Percentual do diferimento do imposto monofásico
+
+
+
+
+ Valor da CBS monofásica diferida
+
+
+
+
+
+
+
+ Total de IBS monofásico do item
+
+
+
+
+ Total da CBS monofásica do item
+
+
+
+
+
+
+ Tipo CBS IBS Completo
+
+
+
+ IBS / CBS
+
+
+
+ Valor do BC
+
+
+
+
+
+ Grupo de informações do IBS na UF
+
+
+
+
+
+ Aliquota do IBS de competência das UF
+
+
+
+
+ Grupo de campos do Diferimento
+
+
+
+
+ Grupo de Informações da devolução de tributos
+
+
+
+
+ Grupo de campos da redução de aliquota
+
+
+
+
+ Valor do IBS de competência das UF
+
+
+
+
+
+
+
+ Grupo de Informações do IBS no Município
+
+
+
+
+
+ Aliquota do IBS Municipal
+
+
+
+
+ Grupo de campos do Diferimento
+
+
+
+
+ Grupo de Informações da devolução de tributos
+
+
+
+
+ Grupo de campos da redução de aliquota
+
+
+
+
+ Valor do IBS Municipal
+
+
+
+
+
+
+
+ Valor do IBS
+
+
+
+
+
+ Grupo de Tributação da CBS
+
+
+
+
+
+ Aliquota da CBS
+
+
+
+
+ Grupo de campos do Diferimento
+
+
+
+
+ Grupo de Informações da devolução de tributos
+
+
+
+
+ Grupo de campos da redução de aliquota
+
+
+
+
+ Valor da CBS
+
+
+
+
+
+
+
+ Grupo de informações da Tributação Regular. Informar como seria a tributação caso não cumprida a condição resolutória/suspensiva. Exemplo 1: Art. 442, §4. Operações com ZFM e ALC. Exemplo 2: Operações com suspensão do tributo.
+
+
+
+
+ Grupo de Informações do Crédito Presumido referente ao IBS, quando aproveitado pelo emitente do documento.
+
+
+
+
+ Grupo de Informações do Crédito Presumido referente a CBS, quando aproveitado pelo emitente do documento.
+
+
+
+
+ Grupo de informações da composição do valor do IBS e da CBS em compras governamental
+
+
+
+
+
+
+ Tipo Redução Base de Cálculo
+
+
+
+
+ Percentual de redução de aliquota do cClassTrib
+
+
+
+
+ Aliquota Efetiva que será aplicada a Base de Calculo
+
+
+
+
+
+
+ Tipo Crédito Presumido
+
+
+
+
+ Código de Classificação do Crédito Presumido do IBS e da CBS
+
+
+
+
+ Percentual do Crédito Presumido
+
+
+
+
+
+ Valor do Crédito Presumido
+
+
+
+
+ Valor do Crédito Presumido Condição Suspensiva, preencher apenas para cCredPres que possui indicação de Condição Suspensiva
+
+
+
+
+
+
+
+ Tipo Diferimento
+
+
+
+
+ Percentual do diferimento
+
+
+
+
+ Valor do diferimento
+
+
+
+
+
+
+ Tipo Devolução Tributo
+
+
+
+
+ Valor do tributo devolvido. No fornecimento de energia elétrica, água, esgoto e
+gás natural e em outras hipóteses definidas no regulamento
+
+
+
+
+
+
+ Tipo Tributação Regular
+
+
+
+
+ Código da Situação Tributária do IBS e CBS
+ Informar qual seria o CST caso não cumprida a condição resolutória/suspensiva
+
+
+
+
+ Informar qual seria o cClassTrib caso não cumprida a condição resolutória/suspensiva
+
+
+
+
+ Alíquota do IBS da UF
+ Informar como seria a Alíquota caso não cumprida a condição resolutória/suspensiva
+
+
+
+
+ Valor do IBS da UF
+ Informar como seria o valor do Tributo caso não cumprida a condição resolutória/suspensiva
+
+
+
+
+ Alíquota do IBS do Município
+ Informar como seria a Alíquota caso não cumprida a condição resolutória/suspensiva
+
+
+
+
+ Valor do IBS do Município
+ Informar como seria o valor do Tributo caso não cumprida a condição resolutória/suspensiva
+
+
+
+
+ Alíquota da CBS
+ Informar como seria a Alíquota caso não cumprida a condição resolutória/suspensiva
+
+
+
+
+ Valor da CBS
+ Informar como seria o valor do Tributo caso não cumprida a condição resolutória/suspensiva
+
+
+
+
+
+
+ Tipo Tributação Compra Governamental
+
+
+
+
+
+ Valor que seria devido a UF, sem aplicação do Art. 473. da LC 214/2025
+
+
+
+
+
+ Valor que seria devido ao município, sem aplicação do Art. 473. da LC 214/2025
+
+
+
+
+
+ Valor que seria devido a CBS, sem aplicação do Art. 473. da LC 214/2025
+
+
+
+
+
+
+ Tipo Compras Governamentais
+ Cada DFe que utilizar deverá utilizar esses tipo no grupo ide
+
+
+
+
+ Para administração pública direta e suas autarquias e fundações:
+1=União
+2=Estados
+3=Distrito Federal
+4=Municípios
+
+
+
+
+ Percentual de redução de aliquota em compra goverrnamental
+
+
+
+
+
+
+ Tipo Compras Governamentais
+ Cada DFe que utilizar deverá utilizar esses tipo no grupo ide
+
+
+
+
+ Para administração pública direta e suas autarquias e fundações:
+1=União
+2=Estados
+3=Distrito Federal
+4=Municípios
+
+
+
+
+ Percentual de redução de aliquota em compra goverrnamental
+
+
+
+
+ Tipo da operação com ente governamental:
+1 - Fornecimento
+2 - Recebimento do Pagamento
+
+
+
+
+
+
+ Tipo Transferência de Crédito
+
+
+
+
+ Valor do IBS a ser transferido
+
+
+
+
+ Valor da CBS a ser transferida
+
+
+
+
+
+
+ Tipo Informações do crédito presumido de IBS para fornecimentos a partir da ZFM
+
+
+
+
+ Classificação de acordo com o art. 450, § 1º, da LC 214/25 para o cálculo do crédito presumido na ZFM
+ 0 - Sem crédito presumido;
+1 - Bens de consumo final (55%);
+2 - Bens de capital (75%);
+3 - Bens intermediários (90,25%);
+4 - Bens de informática e outros definidos em legislação (100%).
+OBS: Percentuais definidos no art. 450, § 1º, da LC 214/25 para o cálculo do crédito presumido
+
+
+
+
+
+ Valor do crédito presumido calculado sobre o saldo devedor apurado
+
+
+
+
+
diff --git a/pynfe/data/XSDs/NF-e/leiauteNFe_v4.00.xsd b/pynfe/data/XSDs/NF-e/leiauteNFe_v4.00.xsd
index 8f0ccd22..77067626 100644
--- a/pynfe/data/XSDs/NF-e/leiauteNFe_v4.00.xsd
+++ b/pynfe/data/XSDs/NF-e/leiauteNFe_v4.00.xsd
@@ -1,5 +1,5 @@
-
+
@@ -17,10 +17,11 @@
-
+
+
Tipo Nota Fiscal Eletrônica
@@ -123,6 +124,12 @@ SCAN 900-999
Código do Município de Ocorrência do Fato Gerador (utilizar a tabela do IBGE)
+
+
+ Informar o município de ocorrência do fato gerador do fato gerador do IBS / CBS.
+Campo preenchido somente quando “indPres = 5 (Operação presencial, fora do estabelecimento) ”, e não tiver endereço do destinatário (Grupo: E05) ou local de entrega (Grupo: G01).
+
+
Formato de impressão do DANFE (0-sem DANFE;1-DANFe Retrato; 2-DANFe Paisagem;3-DANFe Simplificado;
@@ -190,7 +197,25 @@ SCAN 900-999
1 - NFe normal
2 - NFe complementar
3 - NFe de ajuste
-4 - Devolução/Retorno
+4 - Devolução/Retorno
+5 - Nota de crédito
+6 - Nota de débito
+
+
+
+
+ Tipo de Nota de Débito:
+01=Transferência de créditos para Cooperativas;
+02=Anulação de Crédito por Saídas Imunes/Isentas;
+03=Débitos de notas fiscais não processadas na apuração;
+04=Multa e juros;
+05=Transferência de crédito de sucessão.
+
+
+
+
+
+ Tipo de Nota de Crédito
@@ -466,6 +491,25 @@ Preencher com "2B", quando se tratar de Cupom Fiscal emitido por máqu
+
+
+ Grupo de Compras Governamentais
+
+
+
+
+ Informado para abater as parcelas de antecipação de pagamento, conforme Art. 10. § 4º
+
+
+
+
+
+ Chave de acesso da NF-e de antecipação de pagamento
+
+
+
+
+
@@ -1037,7 +1081,7 @@ Formato ”CFOP9999”.
- Valor unitário de tributação - - alterado para aceitar 0 a 10 casas decimais e 11 inteiros
+ Valor unitário de tributação - alterado para aceitar 0 a 10 casas decimais e 11 inteiros
@@ -1074,10 +1118,20 @@ Formato ”CFOP9999”.
+
+
+ Indicador de fornecimento de bem móvel usado: 1-Bem Móvel Usado
+
+
+
+
+
+
+
+
- Delcaração de Importação
-(NT 2011/004)
+ Declaração de Importação (NT 2011/004)
@@ -2041,7 +2095,7 @@ ambiente.
Valor estimado total de impostos federais, estaduais e municipais
-
+
@@ -5019,6 +5073,16 @@ Substituição Tributaria;
+
+
+ Grupo de informações do Imposto Seletivo
+
+
+
+
+ Grupo de informações dos tributos IBS, CBS e Imposto Seletivo
+
+
@@ -5117,6 +5181,36 @@ Substituição Tributaria;
+
+
+ Valor total do Item, correspondente à sua participação no total da nota. A soma dos itens deverá corresponder ao total da nota.
+
+
+
+
+ Referenciamento de item de outros DFe
+
+
+
+
+
+ Chave de Acesso do DFe referenciado
+
+
+
+
+ Número do item do documento referenciado. Corresponde ao atributo nItem do elemento det do documento original.
+
+
+
+
+
+
+
+
+
+
+
@@ -5415,6 +5509,21 @@ Substituição Tributaria;
+
+
+ Valores totais da NF com Imposto Seletivo
+
+
+
+
+ Valores totais da NF com IBS / CBS
+
+
+
+
+ Valor Total da NF considerando os impostos por fora IBS, CBS e IS
+
+
@@ -6292,7 +6401,7 @@ tipo de ato concessório:
-
+
Defensivo Agrícola / Agrotóxico
@@ -6303,8 +6412,8 @@ tipo de ato concessório:
Número do Receituário ou Receita do Defensivo / Agrotóxico
-
-
+
+
@@ -6340,7 +6449,7 @@ tipo de ato concessório:
-
+
Série da Guia
@@ -6403,9 +6512,18 @@ tipo de ato concessório:
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
@@ -7221,6 +7339,34 @@ alterado para tamanho variavel 1-4. (NT2011/004)
+
+
+
+
+
+
+ Tipo de Nota de Débito: 01=Transferência de créditos para Cooperativas; 02=Anulação de Crédito por Saídas Imunes/Isentas; 03=Débitos de notas fiscais não processadas na apuração; 04=Multa e juros; 05=Transferência de crédito de sucessão); 06=Pagamento antecipado; 07=Perda em estoque
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tipo de Nota de Crédito: 01=Multa e juros; 02=Apropriação de crédito presumido de IBS sobre o saldo devedor na ZFM (art. 450, § 1º, LC 214/25); 03=Retorno
+
+
+
+
+
+
@@ -7409,4 +7555,4 @@ alterado para tamanho variavel 1-4. (NT2011/004)
-
+
\ No newline at end of file
diff --git a/pynfe/utils/flags.py b/pynfe/utils/flags.py
index fe9b3449..589eab61 100644
--- a/pynfe/utils/flags.py
+++ b/pynfe/utils/flags.py
@@ -34,6 +34,12 @@
XSD_PD_CANCELAR_NFE = "procCancNFe_v1.07.xsd"
XSD_PD_INUTILIZAR_NFE = "procInutNFe_v1.07.xsd"
+XSD_NFE_LEIAUTE = "leiauteNFe_v4.00.xsd"
+XSD_NFE_TIPOS = "DFeTiposBasicos_v1.00.xsd"
+
+SCHEMA_FOLDER_NFE = "pynfe/data/SCHEMAs/NF-e"
+SCHEMA_NFE = "schemaNFe_v1.00.json"
+
XSD_FOLDER_MDFE = "pynfe/data/XSDs/MDF-e"
XSD_MDFE = "mdfe_v3.00.xsd"
XSD_MDFE_PROCESSADA = "procMDFe_v3.00.xsd"
@@ -43,15 +49,18 @@
("00", "ICMS 00 - Tributada integralmente"),
("02", "ICMS 02 - Tributação monofásica própria sobre combustíveis"),
("10", "ICMS 10 - Tributada com cobranca do ICMS por substituicao tributaria"),
- ("15", "ICMS 15 - Tributação monofásica própria e com responsabilidade pela retenção sobre combustíveis"),
- ("20", "ICMS 20 - Com reducao da base de calculo"),
(
- "30",
+ "15",
(
- "ICMS 30 - Isenta ou nao tributada e com cobranca do ICMS por substituicao"
- " tributaria"
+ "ICMS 15 - Tributação monofásica própria e com responsabilidade pela retenção sobre"
+ " combustíveis"
),
),
+ ("20", "ICMS 20 - Com reducao da base de calculo"),
+ (
+ "30",
+ "ICMS 30 - Isenta ou nao tributada e com cobranca do ICMS por substituicao tributaria",
+ ),
("40", "ICMS 40 - Isenta"),
("41", "ICMS 41 - Nao tributada"),
("50", "ICMS 50 - Suspensao"),
@@ -61,10 +70,7 @@
("61", "ICMS 61 - Tributação monofásica sobre combustíveis cobrada anteriormente"),
(
"70",
- (
- "ICMS 70 - Com reducao da base de calculo e cobranca do ICMS por"
- " substituicao tributaria"
- ),
+ "ICMS 70 - Com reducao da base de calculo e cobranca do ICMS por substituicao tributaria",
),
("90", "ICMS 90 - Outras"),
("101", "ICMS 101 - Tributação ICMS pelo Simples Nacional, CSOSN=101"),
@@ -106,10 +112,7 @@
),
(
5,
- (
- "Nacional, mercadoria ou bem com Conteúdo de Importação inferior ou igual a"
- " 40%. "
- ),
+ "Nacional, mercadoria ou bem com Conteúdo de Importação inferior ou igual a 40%. ",
),
(
6,
From 5581c25425a6aec98616ff9f83ff6a9764a55808 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Sat, 23 Aug 2025 22:37:07 -0300
Subject: [PATCH 037/175] fix: update version to 0.5.3
---
setup.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/setup.py b/setup.py
index d8524fea..12070ff4 100644
--- a/setup.py
+++ b/setup.py
@@ -6,7 +6,7 @@
setuptools.setup(
name="PyNFe",
- version="0.5.2",
+ version="0.5.3",
author="TadaSoftware",
author_email="tadasoftware@gmail.com",
description="Interface library with the Brazilian Electronic Invoice web services",
From 91c2b8c99eadcfc0d9bd0085886287cdce305a01 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Sat, 23 Aug 2025 23:33:14 -0300
Subject: [PATCH 038/175] fix: update version to 0.5.4 and add additional data
file types in package_data
---
setup.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/setup.py b/setup.py
index 12070ff4..543f6497 100644
--- a/setup.py
+++ b/setup.py
@@ -6,7 +6,7 @@
setuptools.setup(
name="PyNFe",
- version="0.5.3",
+ version="0.5.4",
author="TadaSoftware",
author_email="tadasoftware@gmail.com",
description="Interface library with the Brazilian Electronic Invoice web services",
@@ -27,7 +27,7 @@
],
packages=setuptools.find_packages(exclude=["tests"]),
package_data={
- "pynfe": ["data/**/*.txt"],
+ "pynfe": ["data/**/*.txt", "data/**/*.json", "data/**/*.xsd", "data/**/*.csv"],
},
install_requires=[
"pyopenssl>=23.0.0",
From 2b5794227cae70563a642c5f0c4f6932ea6b69a0 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 25 Aug 2025 15:17:24 -0300
Subject: [PATCH 039/175] feat: add valorIbs field to IBSCBS schema for
improved tax calculations
---
pynfe/data/SCHEMAs/NF-e/schemaNFe_v1.00.json | 2 ++
1 file changed, 2 insertions(+)
diff --git a/pynfe/data/SCHEMAs/NF-e/schemaNFe_v1.00.json b/pynfe/data/SCHEMAs/NF-e/schemaNFe_v1.00.json
index 44b0c686..4e6b7b95 100644
--- a/pynfe/data/SCHEMAs/NF-e/schemaNFe_v1.00.json
+++ b/pynfe/data/SCHEMAs/NF-e/schemaNFe_v1.00.json
@@ -774,6 +774,7 @@
},
"valor": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gIBSMun/vIBSMun"
},
+ "valorIbs": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/vIBS",
"cbs": {
"aliquota": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gCBS/pCBS",
"diferimento": {
@@ -825,6 +826,7 @@
"aliquotaAdRemCbs": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/adRemCBS",
"valorIbs": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/vIBSMono",
"valorCbs": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/vCBSMono",
+
"quantidadeRetencao": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/qBCMonoReten",
"aliquotaAdRemIbsRetencao": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/adRemIBSReten",
"valorIbsRetencao": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/vIBSMonoReten",
From 0f7d6249e3841fe691605f69bd57a63ccaf7fe5d Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 25 Aug 2025 16:35:14 -0300
Subject: [PATCH 040/175] fix: update version to 0.5.5 in setup.py
---
setup.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/setup.py b/setup.py
index 543f6497..922ca168 100644
--- a/setup.py
+++ b/setup.py
@@ -6,7 +6,7 @@
setuptools.setup(
name="PyNFe",
- version="0.5.4",
+ version="0.5.5",
author="TadaSoftware",
author_email="tadasoftware@gmail.com",
description="Interface library with the Brazilian Electronic Invoice web services",
From c1d0d8ec26c095ef848af32f4a39a9cc4aa4e9b6 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 26 Aug 2025 08:02:49 -0300
Subject: [PATCH 041/175] fix: ajusts NT 1.20
---
pynfe/data/SCHEMAs/NF-e/schemaNFe_v1.00.json | 44 ++++++++++----------
1 file changed, 23 insertions(+), 21 deletions(-)
diff --git a/pynfe/data/SCHEMAs/NF-e/schemaNFe_v1.00.json b/pynfe/data/SCHEMAs/NF-e/schemaNFe_v1.00.json
index 4e6b7b95..a919e674 100644
--- a/pynfe/data/SCHEMAs/NF-e/schemaNFe_v1.00.json
+++ b/pynfe/data/SCHEMAs/NF-e/schemaNFe_v1.00.json
@@ -821,28 +821,30 @@
"valorCbs": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gTribCompraGov/vTribCBS"
},
"monofasico": {
- "quantidade": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/qBCMono",
- "aliquotaAdRemIbs": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/adRemIBS",
- "aliquotaAdRemCbs": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/adRemCBS",
- "valorIbs": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/vIBSMono",
- "valorCbs": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/vCBSMono",
+ "quantidade": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/gMonoPadrao/qBCMono",
+ "aliquotaAdRemIbs": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/gMonoPadrao/adRemIBS",
+ "aliquotaAdRemCbs": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/gMonoPadrao/adRemCBS",
+ "valorIbs": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/gMonoPadrao/vIBSMono",
+ "valorCbs": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/gMonoPadrao/vCBSMono",
- "quantidadeRetencao": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/qBCMonoReten",
- "aliquotaAdRemIbsRetencao": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/adRemIBSReten",
- "valorIbsRetencao": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/vIBSMonoReten",
- "aliquotaAdRemCbsRetencao": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/adRemCBSReten",
- "valorCbsRetencao": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/vCBSMonoReten",
- "quantidadeRetida": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/qBCMonoRet",
- "aliquotaAdRemIbsRetida": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/adRemIBSRet",
- "valorIbsRetido": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/vIBSMonoRet",
- "aliquotaAdRemCbsRetida": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/adRemCBSRet",
- "valorCbsRetida": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/vCBSMonoRet",
- "aliquotaIbsDiferimento": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/pDifIBS",
- "valorIbsDiferimento": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/vIBSMonoDif",
- "aliquotaCbsDiferimento": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/pDifCBS",
- "valorCbsDiferimento": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/vCBSMonoDif",
- "valorTotalIbs": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/vTotIBSMonoItem",
- "valorTotalCbs": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/vTotCBSMonoItem"
+ "quantidadeRetencao": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/gMonoReten/qBCMonoReten",
+ "aliquotaAdRemIbsRetencao": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/gMonoReten/adRemIBSReten",
+ "valorIbsRetencao": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/gMonoReten/vIBSMonoReten",
+ "aliquotaAdRemCbsRetencao": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/gMonoReten/adRemCBSReten",
+ "valorCbsRetencao": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/gMonoReten/vCBSMonoReten",
+
+ "quantidadeRetida": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/gMonoRet/qBCMonoRet",
+ "aliquotaAdRemIbsRetida": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/gMonoRet/adRemIBSRet",
+ "valorIbsRetido": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/gMonoRet/vIBSMonoRet",
+ "aliquotaAdRemCbsRetida": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/gMonoRet/adRemCBSRet",
+ "valorCbsRetida": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/gMonoRet/vCBSMonoRet",
+
+ "aliquotaIbsDiferimento": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/gMonoDif/pDifIBS",
+ "valorIbsDiferimento": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/gMonoDif/vIBSMonoDif",
+ "aliquotaCbsDiferimento": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/gMonoDif/pDifCBS",
+ "valorCbsDiferimento": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/gMonoDif/vCBSMonoDif",
+ "valorTotalIbs": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/gMonoDif/vTotIBSMonoItem",
+ "valorTotalCbs": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/gMonoDif/vTotCBSMonoItem"
},
"transferenciaCredito": {
"valorIbs": "NFe/infNFe/det/imposto/IBSCBS/gTransfCred/vIBS",
From e18235b3fab1ad8199e4da89067446ffcbdf2def Mon Sep 17 00:00:00 2001
From: LucasBonna
Date: Mon, 1 Sep 2025 19:03:57 -0300
Subject: [PATCH 042/175] =?UTF-8?q?feat:=20add=20S=C3=A3o=20Paulo=20suppor?=
=?UTF-8?q?t=20for=20NFSe=20communication=20and=20methods?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 38 ++++++++++++++++++++++++++++++
pynfe/utils/webservices.py | 6 +++++
2 files changed, 44 insertions(+)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 713d4bc3..2ce17c81 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -628,6 +628,8 @@ def __init__(self, certificado, certificado_senha, autorizador, homologacao=Fals
elif self.autorizador == "BETHA":
self._namespace = NAMESPACE_BETHA
self._versao = "2.02"
+ elif self.autorizador == "SAO_PAULO":
+ self._namespace = "http://www.prefeitura.sp.gov.br/nfe"
else:
raise Exception("Autorizador não encontrado!")
@@ -770,6 +772,8 @@ def _get_url(self):
"""Retorna a url para comunicação com o webservice"""
if self._ambiente == 1:
ambiente = "HTTPS"
+ elif self._ambiente != 1 and self.autorizador == "SAO_PAULO":
+ raise Exception("São Paulo só opera em produção.")
else:
ambiente = "HOMOLOGACAO"
if self.autorizador in NFSE:
@@ -842,6 +846,40 @@ def _post_https(self, url, xml, metodo):
except Exception as e:
raise e
+ def enviar_sp(self, xml, operation):
+ url = self._get_url()
+ if self.autorizador == "SAO_PAULO":
+ return self._post_sp_https(url, xml, operation)
+ else:
+ raise Exception(f"Enviar RPS não implementado para {self.autorizador}")
+
+ def _post_sp_https(self, url, xml, metodo):
+ """Comunicação wsdl (https) utilizando certificado do usuário"""
+ # comunicacao wsdl
+ try:
+ from pynfe.utils.https_nfse import HttpAuthenticated
+ from suds.client import Client
+
+ certificadoA1 = CertificadoA1(self.certificado)
+ chave, cert = certificadoA1.separar_arquivo(self.certificado_senha, caminho=True)
+
+ cliente = Client(url, transport=HttpAuthenticated(key=chave, cert=cert, endereco=url))
+
+ # gerar nfse
+ if metodo == "enviar_rps":
+ return cliente.service.EnviarRPS(VersaoSchema=1, MensagemXML=xml)
+ if metodo == "consultar_rps":
+ return cliente.service.ConsultaNFe(VersaoSchema=1, MensagemXML=xml)
+ elif metodo == "cancelar":
+ return cliente.service.CancelamentoNFe(VersaoSchema=1, MensagemXML=xml)
+ # TODO outros metodos
+ else:
+ raise Exception(f"Método {metodo} não implementado no autorizador São Paulo.")
+ except Exception as e:
+ raise e
+ finally:
+ certificadoA1.excluir()
+
class ComunicacaoMDFe(Comunicacao):
MDFE_SITUACAO_JA_ENVIADO = ("100", "101", "132")
diff --git a/pynfe/utils/webservices.py b/pynfe/utils/webservices.py
index 17e96716..0dac820f 100644
--- a/pynfe/utils/webservices.py
+++ b/pynfe/utils/webservices.py
@@ -500,6 +500,12 @@
# Nfs-e
NFSE = {
#
+ "SAO_PAULO": {
+ "ENVIAR_RPS": "EnviarRps",
+ "CONSULTA_RPS": "ConsultaNFe",
+ "CANCELAR_NFSE": "CancelamentoNFe",
+ "HTTPS": "https://nfe.prefeitura.sp.gov.br/ws/lotenfe.asmx?wsdl"
+ },
"BETHA": {
"AUTORIZACAO": "GerarNfse",
"CANCELAR": "CancelarNfse",
From 0853ee68f43adab227a276d9494b3d6e405e1c3b Mon Sep 17 00:00:00 2001
From: LucasBonna
Date: Mon, 8 Sep 2025 22:00:58 -0300
Subject: [PATCH 043/175] wip
---
pynfe/processamento/comunicacao.py | 43 ++++++++++++++++++++++++++++++
pynfe/utils/webservices.py | 7 +++++
2 files changed, 50 insertions(+)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 2ce17c81..4a27ddd4 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -630,6 +630,10 @@ def __init__(self, certificado, certificado_senha, autorizador, homologacao=Fals
self._versao = "2.02"
elif self.autorizador == "SAO_PAULO":
self._namespace = "http://www.prefeitura.sp.gov.br/nfe"
+ self._versao = "2"
+ elif self.autorizador == "BARUERI":
+ self._namespace = "http://www.barueri.sp.gov.br/nfeservice"
+ self._versao = "1"
else:
raise Exception("Autorizador não encontrado!")
@@ -846,6 +850,45 @@ def _post_https(self, url, xml, metodo):
except Exception as e:
raise e
+ def enviar_barueri(self, xml, operation):
+ url = self._get_url()
+ if self.autorizador == "BARUERI":
+ return self._post_barueri_https(url, xml, operation)
+ else:
+ raise Exception(f"Enviar RPS não implementado para {self.autorizador}")
+
+ def _post_barueri_https(self, url, xml, metodo):
+ """Comunicação wsdl (https) utilizando certificado do usuário"""
+ # comunicacao wsdl
+ try:
+ from pynfe.utils.https_nfse import HttpAuthenticated
+ from suds.client import Client
+
+ certificadoA1 = CertificadoA1(self.certificado)
+ chave, cert = certificadoA1.separar_arquivo(self.certificado_senha, caminho=True)
+
+ cliente = Client(url, transport=HttpAuthenticated(key=chave, cert=cert, endereco=url))
+
+ # gerar nfse
+
+ if metodo == "enviar_rps":
+ return cliente.service.NFeLoteEnviarArquivo(VersaoSchema=1, MensagemXML=xml)
+ elif metodo == "consultar_rps":
+ return cliente.service.ConsultaNFe(VersaoSchema=1, MensagemXML=xml)
+ elif metodo == "listar_rps":
+ return cliente.service.NFeLoteListarArquivos(VersaoSchema=1, MensagemXML=xml)
+ elif metodo == "baixar_nfse":
+ return cliente.service.NFeLoteBaixarArquivo(VersaoSchema=1, MensagemXML=xml)
+ elif metodo == "cancelar":
+ return cliente.service.CancelamentoNFe(VersaoSchema=1, MensagemXML=xml)
+ # TODO outros metodos
+ else:
+ raise Exception(f"Método {metodo} não implementado no autorizador Barueri.")
+ except Exception as e:
+ raise e
+ finally:
+ certificadoA1.excluir()
+
def enviar_sp(self, xml, operation):
url = self._get_url()
if self.autorizador == "SAO_PAULO":
diff --git a/pynfe/utils/webservices.py b/pynfe/utils/webservices.py
index 0dac820f..4cccb546 100644
--- a/pynfe/utils/webservices.py
+++ b/pynfe/utils/webservices.py
@@ -506,6 +506,13 @@
"CANCELAR_NFSE": "CancelamentoNFe",
"HTTPS": "https://nfe.prefeitura.sp.gov.br/ws/lotenfe.asmx?wsdl"
},
+ "BARUERI": {
+ "ENVIAR_RPS": "EnviarRPS",
+ "CONSULTA_RPS": "ConsultaNFe",
+ "CANCELAR_NFSE": "CancelamentoNFe",
+ "HTTPS": "https://www.barueri.sp.gov.br/nfeservice/wsrps.asmx?WSDL",
+ "HOMOLOGACAO": "https://testeeiss.barueri.sp.gov.br/nfeservice/wsrps.asmx?WSDL"
+ },
"BETHA": {
"AUTORIZACAO": "GerarNfse",
"CANCELAR": "CancelarNfse",
From 5b299579ef02134dd1aac0ee716b990a5d8da4e4 Mon Sep 17 00:00:00 2001
From: LucasBonna
Date: Sat, 20 Sep 2025 14:30:45 -0300
Subject: [PATCH 044/175] fix: fix certificadoA1 initialization
---
pynfe/processamento/comunicacao.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 4a27ddd4..f6c2f04d 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -860,11 +860,12 @@ def enviar_barueri(self, xml, operation):
def _post_barueri_https(self, url, xml, metodo):
"""Comunicação wsdl (https) utilizando certificado do usuário"""
# comunicacao wsdl
+
+ certificadoA1 = CertificadoA1(self.certificado)
try:
from pynfe.utils.https_nfse import HttpAuthenticated
from suds.client import Client
- certificadoA1 = CertificadoA1(self.certificado)
chave, cert = certificadoA1.separar_arquivo(self.certificado_senha, caminho=True)
cliente = Client(url, transport=HttpAuthenticated(key=chave, cert=cert, endereco=url))
From f26517a7206e0987bf49caf0614770b743c8f8d2 Mon Sep 17 00:00:00 2001
From: LucasBonna
Date: Sat, 20 Sep 2025 14:35:28 -0300
Subject: [PATCH 045/175] fix: remove redundant certificadoA1 initialization in
ComunicacaoNfse class fix: add suds-jurko to main dependencies in setup.py
---
pynfe/processamento/comunicacao.py | 2 +-
setup.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index f6c2f04d..0167d0df 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -900,11 +900,11 @@ def enviar_sp(self, xml, operation):
def _post_sp_https(self, url, xml, metodo):
"""Comunicação wsdl (https) utilizando certificado do usuário"""
# comunicacao wsdl
+ certificadoA1 = CertificadoA1(self.certificado)
try:
from pynfe.utils.https_nfse import HttpAuthenticated
from suds.client import Client
- certificadoA1 = CertificadoA1(self.certificado)
chave, cert = certificadoA1.separar_arquivo(self.certificado_senha, caminho=True)
cliente = Client(url, transport=HttpAuthenticated(key=chave, cert=cert, endereco=url))
diff --git a/setup.py b/setup.py
index 922ca168..40113f38 100644
--- a/setup.py
+++ b/setup.py
@@ -34,10 +34,10 @@
"requests",
"lxml",
"signxml",
+ "suds-jurko",
],
extras_require={
"nfse": [
- "suds-jurko",
"pyxb==1.2.4",
],
},
From a608a34226f1c09359376584a5621e1a2b609c61 Mon Sep 17 00:00:00 2001
From: LucasBonna
Date: Sat, 20 Sep 2025 14:36:33 -0300
Subject: [PATCH 046/175] fix: update version to 0.6.0 in setup.py
---
setup.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/setup.py b/setup.py
index 40113f38..501d115b 100644
--- a/setup.py
+++ b/setup.py
@@ -6,7 +6,7 @@
setuptools.setup(
name="PyNFe",
- version="0.5.5",
+ version="0.6.0",
author="TadaSoftware",
author_email="tadasoftware@gmail.com",
description="Interface library with the Brazilian Electronic Invoice web services",
From 45034b734656ff897d85f33f6641f7fcfb66c4a3 Mon Sep 17 00:00:00 2001
From: LucasBonna
Date: Sat, 20 Sep 2025 14:42:12 -0300
Subject: [PATCH 047/175] fix: update suds-jurko to suds-py3 in setup.py
---
setup.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/setup.py b/setup.py
index 501d115b..7f4ed251 100644
--- a/setup.py
+++ b/setup.py
@@ -34,7 +34,7 @@
"requests",
"lxml",
"signxml",
- "suds-jurko",
+ "suds-py3",
],
extras_require={
"nfse": [
From 0136c79932d09dc08ed1c74a0b7bb0d833aec025 Mon Sep 17 00:00:00 2001
From: LucasBonna
Date: Sat, 20 Sep 2025 17:11:54 -0300
Subject: [PATCH 048/175] fix: update version to 0.6.1 in setup.py and correct
method call in ComunicacaoNfse class
---
pynfe/processamento/comunicacao.py | 2 +-
setup.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 0167d0df..844b0048 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -875,7 +875,7 @@ def _post_barueri_https(self, url, xml, metodo):
if metodo == "enviar_rps":
return cliente.service.NFeLoteEnviarArquivo(VersaoSchema=1, MensagemXML=xml)
elif metodo == "consultar_rps":
- return cliente.service.ConsultaNFe(VersaoSchema=1, MensagemXML=xml)
+ return cliente.service.NFeLoteStatusArquivo(VersaoSchema=1, MensagemXML=xml)
elif metodo == "listar_rps":
return cliente.service.NFeLoteListarArquivos(VersaoSchema=1, MensagemXML=xml)
elif metodo == "baixar_nfse":
diff --git a/setup.py b/setup.py
index 7f4ed251..17c35434 100644
--- a/setup.py
+++ b/setup.py
@@ -6,7 +6,7 @@
setuptools.setup(
name="PyNFe",
- version="0.6.0",
+ version="0.6.1",
author="TadaSoftware",
author_email="tadasoftware@gmail.com",
description="Interface library with the Brazilian Electronic Invoice web services",
From 0be3d4e873ea326094a6fa6b4d2acb7257d95654 Mon Sep 17 00:00:00 2001
From: LucasBonna
Date: Mon, 22 Sep 2025 18:59:48 -0300
Subject: [PATCH 049/175] fix: update version to 0.7.0 in setup.py and
implement new request-based communication method for Barueri in
ComunicacaoNfse class
---
pynfe/processamento/comunicacao.py | 50 ++++++++++++++++++++++++++++--
setup.py | 2 +-
2 files changed, 49 insertions(+), 3 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 844b0048..9e06f09e 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -853,12 +853,58 @@ def _post_https(self, url, xml, metodo):
def enviar_barueri(self, xml, operation):
url = self._get_url()
if self.autorizador == "BARUERI":
- return self._post_barueri_https(url, xml, operation)
+ return self._post_barueri_requests(url, xml, operation)
else:
raise Exception(f"Enviar RPS não implementado para {self.autorizador}")
+
+ def _post_barueri_requests(self, url, xml, operation):
+ """
+ Comunicação SOAP usando requests diretamente (como NFe)
+ Recebe o envelope SOAP completo já montado
+ """
+ import requests
+
+ certificado_a1 = CertificadoA1(self.certificado)
+ try:
+ chave, cert = certificado_a1.separar_arquivo(self.certificado_senha, caminho=True)
+ chave_cert = (cert, chave)
+
+ if operation == "enviar_rps":
+ soap_action = "http://www.barueri.sp.gov.br/nfe/NFeLoteEnviarArquivo"
+ elif operation == "consultar_rps":
+ soap_action = "http://www.barueri.sp.gov.br/nfe/NFeLoteStatusArquivo"
+ elif operation == "listar_rps":
+ soap_action = "http://www.barueri.sp.gov.br/nfe/NFeLoteListarArquivos"
+ elif operation == "baixar_nfse":
+ soap_action = "http://www.barueri.sp.gov.br/nfe/NFeLoteBaixarArquivo"
+ else:
+ raise Exception(f"Operação {operation} não implementada para Barueri.")
+
+ headers = {
+ 'Content-Type': 'text/xml; charset=utf-8',
+ 'SOAPAction': f'"{soap_action}"'
+ }
+
+ return requests.post(
+ url,
+ data=xml.encode('utf-8'),
+ headers=headers,
+ cert=chave_cert,
+ verify=False,
+ timeout=30
+ )
+
+ except requests.exceptions.RequestException as e:
+ raise e
+ finally:
+ certificado_a1.excluir()
def _post_barueri_https(self, url, xml, metodo):
- """Comunicação wsdl (https) utilizando certificado do usuário"""
+ """
+ LEGACY: Comunicação wsdl (https) utilizando certificado do usuário
+ Este método usa SUDS e não é mais usado pelo Barueri.
+ Usar _post_barueri_requests() para Barueri.
+ """
# comunicacao wsdl
certificadoA1 = CertificadoA1(self.certificado)
diff --git a/setup.py b/setup.py
index 17c35434..351c7a2b 100644
--- a/setup.py
+++ b/setup.py
@@ -6,7 +6,7 @@
setuptools.setup(
name="PyNFe",
- version="0.6.1",
+ version="0.7.0",
author="TadaSoftware",
author_email="tadasoftware@gmail.com",
description="Interface library with the Brazilian Electronic Invoice web services",
From 11bf5999126dae301df5b80bc35340bab8047185 Mon Sep 17 00:00:00 2001
From: LucasBonna
Date: Mon, 22 Sep 2025 23:37:37 -0300
Subject: [PATCH 050/175] fix: update version to 0.7.1 in setup.py and add
methods for RPS communication in ComunicacaoNfse class for Barueri
---
pynfe/processamento/comunicacao.py | 23 ++++++++++++++++++++---
setup.py | 2 +-
2 files changed, 21 insertions(+), 4 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 9e06f09e..ba0d7314 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -852,11 +852,28 @@ def _post_https(self, url, xml, metodo):
def enviar_barueri(self, xml, operation):
url = self._get_url()
- if self.autorizador == "BARUERI":
- return self._post_barueri_requests(url, xml, operation)
- else:
+
+ if not self.autorizador == "BARUERI":
raise Exception(f"Enviar RPS não implementado para {self.autorizador}")
+ return self._post_barueri_requests(url, xml, operation)
+
+ def consultar_rps_barueri(self, xml, operation):
+ url = self._get_url()
+
+ if not self.autorizador == "BARUERI":
+ raise Exception(f"Consultar RPS não implementado para {self.autorizador}")
+
+ return self._post_barueri_requests(url, xml, operation)
+
+ def baixar_rps_barueri(self, xml, operation):
+ url = self._get_url()
+
+ if not self.autorizador == "BARUERI":
+ raise Exception(f"Baixar RPS não implementado para {self.autorizador}")
+
+ return self._post_barueri_requests(url, xml, operation)
+
def _post_barueri_requests(self, url, xml, operation):
"""
Comunicação SOAP usando requests diretamente (como NFe)
diff --git a/setup.py b/setup.py
index 351c7a2b..0afd2750 100644
--- a/setup.py
+++ b/setup.py
@@ -6,7 +6,7 @@
setuptools.setup(
name="PyNFe",
- version="0.7.0",
+ version="0.7.1",
author="TadaSoftware",
author_email="tadasoftware@gmail.com",
description="Interface library with the Brazilian Electronic Invoice web services",
From 992e65a38d70702069df51584a3a82a72cfcfa3b Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Fri, 17 Oct 2025 09:21:35 -0300
Subject: [PATCH 051/175] feat: enhance NF-e schema with new fields for
improved tax calculations
---
pynfe/data/SCHEMAs/NF-e/schemaNFe_v1.00.json | 51 +-
.../data/XSDs/NF-e/DFeTiposBasicos_v1.00.xsd | 468 +++++++++++++-----
pynfe/data/XSDs/NF-e/leiauteNFe_v4.00.xsd | 39 +-
3 files changed, 396 insertions(+), 162 deletions(-)
diff --git a/pynfe/data/SCHEMAs/NF-e/schemaNFe_v1.00.json b/pynfe/data/SCHEMAs/NF-e/schemaNFe_v1.00.json
index a919e674..b0920da6 100644
--- a/pynfe/data/SCHEMAs/NF-e/schemaNFe_v1.00.json
+++ b/pynfe/data/SCHEMAs/NF-e/schemaNFe_v1.00.json
@@ -10,6 +10,7 @@
"dataEmissao": "NFe/infNFe/ide/dhEmi",
"dataSaidaEntradaTz": "NFe/infNFe/ide/dhSaiEnt",
"saida": "NFe/infNFe/ide/tpNF",
+ "dataPrevistaEntrega": "NFe/infNFe/ide/dhPrevEntrega",
"codigoIdentificacaoDestino": "NFe/infNFe/ide/idDest",
"codigoMunicipioFatoGerador": "NFe/infNFe/ide/cMunFG",
"codigoMunicipioFatoGeradorIBS": "NFe/infNFe/ide/cMunFGIBS",
@@ -203,6 +204,8 @@
"valorCbsMonoRetenencao": "NFe/infNFe/total/IBSCBSTot/gMono/vCBSMonoReten",
"valorIbsMonoRetido": "NFe/infNFe/total/IBSCBSTot/gMono/vIBSMonoRet",
"valorCbsMonoRetido": "NFe/infNFe/total/IBSCBSTot/gMono/vCBSMonoRet",
+ "valorIbsEstornado": "NFe/infNFe/total/IBSCBSTot/gEstornoCred/vIBSEstCred",
+ "valorCbsEstornado": "NFe/infNFe/total/IBSCBSTot/gEstornoCred/vCBSEstCred",
"valorIbsCbsIs": "NFe/infNFe/total/vNFTot"
},
"transporte": {
@@ -359,6 +362,7 @@
"valorDesconto": "NFe/infNFe/det/prod/vDesc",
"valorOutros": "NFe/infNFe/det/prod/vOutro",
"compoeTotal": "NFe/infNFe/det/prod/indTot",
+ "tipoCreditoPresumindoIbsZFM": "NFe/infNFe/det/prod/tpCredPresIBSZFM",
"indicadorBemMovelUsado": "NFe/infNFe/det/prod/indBemMovelUsado",
"numeroCompra": "NFe/infNFe/det/prod/xPed",
"pedidoCompra": "NFe/infNFe/det/prod/nItemPed",
@@ -743,6 +747,7 @@
"ibscbs": {
"cst": "NFe/infNFe/det/imposto/IBSCBS/CST",
"classificacao": "NFe/infNFe/det/imposto/IBSCBS/cClassTrib",
+ "indicadorDoacao": "NFe/infNFe/det/imposto/IBSCBS/indDoacao",
"baseCalculo": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/vBC",
"uf": {
"aliquota": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gIBSUF/pIBSUF",
@@ -800,18 +805,6 @@
"aliquota": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gTribRegular/pAliqEfetRegCBS",
"valor": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gTribRegular/vTribRegCBS"
},
- "ibsCreditoPresumido": {
- "codigo": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gIBSCredPres/cCredPres",
- "percentual": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gIBSCredPres/pCredPres",
- "valor": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gIBSCredPres/vCredPres",
- "valorSuspensivo": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gIBSCredPres/vCredPresCondSus"
- },
- "cbsCreditoPresumido": {
- "codigo": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gCBSCredPres/cCredPres",
- "percentual": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gCBSCredPres/pCredPres",
- "valor": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gCBSCredPres/vCredPres",
- "valorSuspensivo": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gCBSCredPres/vCredPresCondSus"
- },
"compraGovernamental": {
"aliquotaUF": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gTribCompraGov/pAliqIBSUF",
"valorUF": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gTribCompraGov/vTribIBSUF",
@@ -847,12 +840,36 @@
"valorTotalCbs": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBSMono/gMonoDif/vTotCBSMonoItem"
},
"transferenciaCredito": {
- "valorIbs": "NFe/infNFe/det/imposto/IBSCBS/gTransfCred/vIBS",
- "valorCbs": "NFe/infNFe/det/imposto/IBSCBS/gTransfCred/vCBS"
+ "valorIbs": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gTransfCred/vIBS",
+ "valorCbs": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gTransfCred/vCBS"
+ },
+ "ajusteCompetencia": {
+ "competencia": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gAjusteCompet/competApur",
+ "valorIbs": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gAjusteCompet/vIBS",
+ "valorCbs": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gAjusteCompet/vCBS"
+ },
+ "estornoCredito": {
+ "valorIbsEstornado": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gEstornoCred/vIBSEstCred",
+ "valorCbsEstornado": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gEstornoCred/vCBSEstCred"
+ },
+ "creditoPresumidoOperacao": {
+ "codigo": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gCredPresOper/cCredPres",
+ "baseCalculo": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gCredPresOper/vBCCredPres"
+ },
+ "ibsCreditoPresumido": {
+ "percentual": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gIBSCredPres/pCredPres",
+ "valor": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gIBSCredPres/vCredPres",
+ "valorSuspensivo": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gIBSCredPres/vCredPresCondSus"
+ },
+ "cbsCreditoPresumido": {
+ "percentual": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gCBSCredPres/pCredPres",
+ "valor": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gCBSCredPres/vCredPres",
+ "valorSuspensivo": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gCBSCredPres/vCredPresCondSus"
},
- "creditoPresumidoZfm": {
- "tipo": "NFe/infNFe/det/imposto/IBSCBS/gCredPresIBSZFM/tpCredPresIBSZFM",
- "valor": "NFe/infNFe/det/imposto/IBSCBS/gCredPresIBSZFM/vCredPresIBSZFM"
+ "creditoPresumidoZfm": {
+ "competencia": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gCredPresIBSZFM/competApur",
+ "tipo": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gCredPresIBSZFM/tpCredPresIBSZFM",
+ "valor": "NFe/infNFe/det/imposto/IBSCBS/gIBSCBS/gCredPresIBSZFM/vCredPresIBSZFM"
}
},
"ipi": {
diff --git a/pynfe/data/XSDs/NF-e/DFeTiposBasicos_v1.00.xsd b/pynfe/data/XSDs/NF-e/DFeTiposBasicos_v1.00.xsd
index 44e4ec49..a5051dd0 100644
--- a/pynfe/data/XSDs/NF-e/DFeTiposBasicos_v1.00.xsd
+++ b/pynfe/data/XSDs/NF-e/DFeTiposBasicos_v1.00.xsd
@@ -1,5 +1,5 @@
-
+
@@ -37,7 +37,7 @@
-
+
Tipo Decimal com 15 dígitos, sendo 11 de corpo e 4 decimais
@@ -46,7 +46,7 @@
-
+
Tipo Decimal com 11 inteiros, podendo ter 4 decimais (utilizado em tags opcionais)
@@ -55,7 +55,7 @@
-
+
Tipo Decimal com 15 dígitos, sendo 13 de corpo e 2 decimais
@@ -64,7 +64,7 @@
-
+
Tipo Decimal com até 3 dígitos inteiros, podendo ter de 2 até 4 decimais
@@ -107,6 +107,14 @@
+
+
+ Tipo Indicador de Doação
+
+
+
+
+
Grupo de informações da Tributação da NFCom
@@ -118,7 +126,17 @@
+
+
+ Indica se a operação é de doação
+
+
+
+
+ Informado conforme indicador no cClassTrib
+
+
@@ -132,7 +150,37 @@
+
+
+ Indica se a operação é de doação
+
+
+
+
+
+ Informado conforme indicador no cClassTrib
+
+
+
+
+
+
+ Grupo de informações da Tributação da NFAg
+
+
+
+
+ Código Situação Tributária do IBS/CBS
+
+
+
+
+
+
+ Informado conforme indicador no cClassTrib
+
+
@@ -146,7 +194,13 @@
+
+
+
+ Informado conforme indicador no cClassTrib
+
+
@@ -160,7 +214,13 @@
+
+
+
+ Informado conforme indicador no cClassTrib
+
+
@@ -174,6 +234,11 @@
+
+
+ Indica se a operação é de doação
+
+
@@ -191,11 +256,16 @@
+
+
+ Indica se a operação é de doação
+
+
- Informar essa opção da Choice para Monofasia
+ Informar essa opção da Choice para Monofasia (CST 620)
@@ -203,10 +273,54 @@
Informar essa opção da Choice para o CST 800
+
+
+ Informar essa opção da Choice para o CST 811
+
+
-
+
- Classificação de acordo com o art. 450, § 1º, da LC 214/25 para o cálculo do crédito presumido na ZFM
+ Informado conforme indicador no cClassTrib
+
+
+
+
+
+ Crédito Presumido da Operação. Informado conforme indicador no cClassTrib.
+
+
+
+
+ Classificação de acordo com o art. 450, § 1º, da LC 214/25 para o cálculo do crédito presumido na ZFM. Informado conforme indicador no cClassTrib.
+
+
+
+
+
+
+
+ Grupo de informações da Tributação da NFGas
+
+
+
+
+ Código Situação Tributária do IBS/CBS
+
+
+
+
+
+
+
+
+ Informar essa opção da Choice para Monofasia
+
+
+
+
+
+ Informado conforme indicador no cClassTrib
@@ -223,17 +337,17 @@
-
+
Valor do BC
-
+
Alíquota do Imposto Seletivo (percentual)
-
+
Alíquota do Imposto Seletivo (por valor)
@@ -250,13 +364,13 @@
-
+
Quantidade com abse no campo uTrib informado
-
+
Valor do Imposto Seletivo calculado
@@ -269,7 +383,7 @@
Grupo de informações de totais do Imposto Seletivo
-
+
Valor Total do Imposto Seletivo
@@ -281,7 +395,7 @@
Grupo de informações de totais da CBS/IBS
-
+
Total Base de Calculo
@@ -298,17 +412,17 @@
-
+
Total do Diferimento
-
+
Total de devoluções de tributos
-
+
Valor total do IBS Estadual
@@ -322,17 +436,17 @@
-
+
Total do Diferimento
-
+
Total de devoluções de tributos
-
+
Valor total do IBS Municipal
@@ -340,21 +454,11 @@
-
+
Valor total do IBS
-
-
- Total do Crédito Presumido
-
-
-
-
- Total do Crédito Presumido Condição Suspensiva
-
-
@@ -364,29 +468,38 @@
-
+
Total do Diferimento
-
+
Total de devoluções de tributos
-
+
Valor total da CBS
-
+
+
+
+
+
+ Totalização do estorno de crédito
+
+
+
+
- Total do Crédito Presumido
+ Valor total do IBS estornado
-
+
- Total do Crédito Presumido Condição Suspensiva
+ Valor total da CBS estornada
@@ -399,7 +512,7 @@
Grupo de informações de totais da CBS/IBS com monofasia
-
+
Total Base de Calculo
@@ -416,17 +529,17 @@
-
+
Total do Diferimento
-
+
Total de devoluções de tributos
-
+
Valor total do IBS Estadual
@@ -440,17 +553,17 @@
-
+
Total do Diferimento
-
+
Total de devoluções de tributos
-
+
Valor total do IBS Municipal
@@ -458,17 +571,17 @@
-
+
Valor total do IBS
-
+
Total do Crédito Presumido
-
+
Total do Crédito Presumido Condição Suspensiva
@@ -482,27 +595,27 @@
-
+
Total do Diferimento
-
+
Total de devoluções de tributos
-
+
Valor total da CBS
-
+
Total do Crédito Presumido
-
+
Total do Crédito Presumido Condição Suspensiva
@@ -517,32 +630,32 @@
-
+
Valor total do IBS monofásico
-
+
Valor total da CBS monofásica
-
+
Valor total do IBS monofásico sujeito a retenção
-
+
Valor total da CBS monofásica sujeita a retenção
-
+
Valor do IBS monofásico retido anteriormente
-
+
Valor da CBS monofásica retida anteriormente
@@ -550,6 +663,25 @@
+
+
+ Totalização do estorno de crédito
+
+
+
+
+
+ Valor total do IBS estornado
+
+
+
+
+ Valor total da CBS estornada
+
+
+
+
+
@@ -566,27 +698,27 @@
-
+
Quantidade tributada na monofasia
-
+
Alíquota ad rem do IBS
-
+
Alíquota ad rem da CBS
-
+
Valor do IBS monofásico
-
+
Valor da CBS monofásica
@@ -600,27 +732,27 @@
-
+
Quantidade tributada sujeita a retenção.
-
+
Alíquota ad rem do IBS sujeito a retenção
-
+
Valor do IBS monofásico sujeito a retenção
-
+
Alíquota ad rem da CBS sujeita a retenção
-
+
Valor da CBS monofásica sujeita a retenção
@@ -634,27 +766,27 @@
-
+
Quantidade tributada retida anteriormente
-
+
Alíquota ad rem do IBS retido anteriormente
-
+
Valor do IBS retido anteriormente
-
+
Alíquota ad rem da CBS retida anteriormente
-
+
Valor da CBS retida anteriormente
@@ -668,22 +800,22 @@
-
+
Percentual do diferimento do imposto monofásico
-
+
Valor do IBS monofásico diferido
-
+
Percentual do diferimento do imposto monofásico
-
+
Valor da CBS monofásica diferida
@@ -691,12 +823,12 @@
-
+
Total de IBS monofásico do item
-
+
Total da CBS monofásica do item
@@ -711,7 +843,7 @@
IBS / CBS
-
+
Valor do BC
@@ -723,9 +855,9 @@
-
+
- Aliquota do IBS de competência das UF
+ Aliquota do IBS de competência das UF (em percentual)
@@ -743,7 +875,7 @@
Grupo de campos da redução de aliquota
-
+
Valor do IBS de competência das UF
@@ -757,9 +889,9 @@
-
+
- Aliquota do IBS Municipal
+ Aliquota do IBS Municipal (em percentual)
@@ -777,7 +909,7 @@
Grupo de campos da redução de aliquota
-
+
Valor do IBS Municipal
@@ -785,7 +917,7 @@
-
+
Valor do IBS
@@ -797,9 +929,9 @@
-
+
- Aliquota da CBS
+ Aliquota da CBS (em percentual)
@@ -817,7 +949,7 @@
Grupo de campos da redução de aliquota
-
+
Valor da CBS
@@ -830,16 +962,6 @@
Grupo de informações da Tributação Regular. Informar como seria a tributação caso não cumprida a condição resolutória/suspensiva. Exemplo 1: Art. 442, §4. Operações com ZFM e ALC. Exemplo 2: Operações com suspensão do tributo.
-
-
- Grupo de Informações do Crédito Presumido referente ao IBS, quando aproveitado pelo emitente do documento.
-
-
-
-
- Grupo de Informações do Crédito Presumido referente a CBS, quando aproveitado pelo emitente do documento.
-
-
Grupo de informações da composição do valor do IBS e da CBS em compras governamental
@@ -852,14 +974,14 @@
Tipo Redução Base de Cálculo
-
+
Percentual de redução de aliquota do cClassTrib
-
+
- Aliquota Efetiva que será aplicada a Base de Calculo
+ Aliquota Efetiva que será aplicada a Base de Calculo (em percentual)
@@ -869,23 +991,18 @@
Tipo Crédito Presumido
-
-
- Código de Classificação do Crédito Presumido do IBS e da CBS
-
-
-
+
Percentual do Crédito Presumido
-
+
Valor do Crédito Presumido
-
+
Valor do Crédito Presumido Condição Suspensiva, preencher apenas para cCredPres que possui indicação de Condição Suspensiva
@@ -898,12 +1015,12 @@
Tipo Diferimento
-
+
Percentual do diferimento
-
+
Valor do diferimento
@@ -915,7 +1032,7 @@
Tipo Devolução Tributo
-
+
Valor do tributo devolvido. No fornecimento de energia elétrica, água, esgoto e
gás natural e em outras hipóteses definidas no regulamento
@@ -939,37 +1056,37 @@ gás natural e em outras hipóteses definidas no regulamento
Informar qual seria o cClassTrib caso não cumprida a condição resolutória/suspensiva
-
+
Alíquota do IBS da UF
Informar como seria a Alíquota caso não cumprida a condição resolutória/suspensiva
-
+
Valor do IBS da UF
Informar como seria o valor do Tributo caso não cumprida a condição resolutória/suspensiva
-
+
Alíquota do IBS do Município
Informar como seria a Alíquota caso não cumprida a condição resolutória/suspensiva
-
+
Valor do IBS do Município
Informar como seria o valor do Tributo caso não cumprida a condição resolutória/suspensiva
-
+
Alíquota da CBS
Informar como seria a Alíquota caso não cumprida a condição resolutória/suspensiva
-
+
Valor da CBS
Informar como seria o valor do Tributo caso não cumprida a condição resolutória/suspensiva
@@ -982,20 +1099,20 @@ gás natural e em outras hipóteses definidas no regulamento
Tipo Tributação Compra Governamental
-
-
+
+
Valor que seria devido a UF, sem aplicação do Art. 473. da LC 214/2025
-
-
+
+
Valor que seria devido ao município, sem aplicação do Art. 473. da LC 214/2025
-
-
+
+
Valor que seria devido a CBS, sem aplicação do Art. 473. da LC 214/2025
@@ -1017,9 +1134,9 @@ gás natural e em outras hipóteses definidas no regulamento
4=Municípios
-
+
- Percentual de redução de aliquota em compra goverrnamental
+ Percentual de redução de aliquota em compra governamental
@@ -1039,9 +1156,9 @@ gás natural e em outras hipóteses definidas no regulamento
4=Municípios
-
+
- Percentual de redução de aliquota em compra goverrnamental
+ Percentual de redução de aliquota em compra governamental
@@ -1058,23 +1175,102 @@ gás natural e em outras hipóteses definidas no regulamento
Tipo Transferência de Crédito
-
+
Valor do IBS a ser transferido
-
+
Valor da CBS a ser transferida
+
+
+ Tipo Estorno de Crédito
+
+
+
+
+ Valor do IBS a ser estornado
+
+
+
+
+ Valor da CBS a ser estornada
+
+
+
+
+
+
+ Ano e mês referência do período de apuração (AAAA-MM)
+
+
+
+
+
+
+
+ Tipo Ajuste de Competência
+
+
+
+
+ Ano e mês referência do período de apuração (AAAA-MM)
+
+
+
+
+ Valor do IBS
+
+
+
+
+ Valor da CBS
+
+
+
+
+
+
+ Tipo Crédito Presumido da Operação
+
+
+
+
+ Valor da Base de Cálculo do Crédito Presumido da Operação
+
+
+
+
+ Código de Classificação do Crédito Presumido do IBS e da CBS
+
+
+
+
+ Grupo de Informações do Crédito Presumido referente ao IBS, quando aproveitado pelo emitente do documento.
+
+
+
+
+ Grupo de Informações do Crédito Presumido referente a CBS, quando aproveitado pelo emitente do documento.
+
+
+
+
Tipo Informações do crédito presumido de IBS para fornecimentos a partir da ZFM
+
+
+ Ano e mês referência do período de apuração (AAAA-MM)
+
+
Classificação de acordo com o art. 450, § 1º, da LC 214/25 para o cálculo do crédito presumido na ZFM
@@ -1087,11 +1283,11 @@ OBS: Percentuais definidos no art. 450, § 1º, da LC 214/25 para o cálculo do
-
+
Valor do crédito presumido calculado sobre o saldo devedor apurado
-
+
\ No newline at end of file
diff --git a/pynfe/data/XSDs/NF-e/leiauteNFe_v4.00.xsd b/pynfe/data/XSDs/NF-e/leiauteNFe_v4.00.xsd
index 77067626..7d6fb69e 100644
--- a/pynfe/data/XSDs/NF-e/leiauteNFe_v4.00.xsd
+++ b/pynfe/data/XSDs/NF-e/leiauteNFe_v4.00.xsd
@@ -94,6 +94,11 @@ SCAN 900-999
Data e Hora da saída ou de entrada da mercadoria / produto (AAAA-MM-DDTHH:mm:ssTZD)
+
+
+ Data da previsão de entrega ou disponibilização do bem (AAAA-MM-DD)
+
+
Tipo do Documento Fiscal (0 - entrada; 1 - saída)
@@ -204,13 +209,7 @@ Campo preenchido somente quando “indPres = 5 (Operação presencial, fora do e
- Tipo de Nota de Débito:
-01=Transferência de créditos para Cooperativas;
-02=Anulação de Crédito por Saídas Imunes/Isentas;
-03=Débitos de notas fiscais não processadas na apuração;
-04=Multa e juros;
-05=Transferência de crédito de sucessão.
-
+ Tipo de Nota de Débito
@@ -993,6 +992,11 @@ Formato ”CFOP9999”.
+
+
+ Classificação para subapuração do IBS na ZFM
+
+
Código EX TIPI (3 posições)
@@ -7345,7 +7349,15 @@ alterado para tamanho variavel 1-4. (NT2011/004)
- Tipo de Nota de Débito: 01=Transferência de créditos para Cooperativas; 02=Anulação de Crédito por Saídas Imunes/Isentas; 03=Débitos de notas fiscais não processadas na apuração; 04=Multa e juros; 05=Transferência de crédito de sucessão); 06=Pagamento antecipado; 07=Perda em estoque
+ Tipo de Nota de Débito:
+ 01=Transferência de créditos para Cooperativas;
+ 02=Anulação de Crédito por Saídas Imunes/Isentas;
+ 03=Débitos de notas fiscais não processadas na apuração;
+ 04=Multa e juros;
+ 05=Transferência de crédito na sucessão;
+ 06=Pagamento antecipado;
+ 07=Perda em estoque;
+ 08=Desenquadramento do SN;
@@ -7356,17 +7368,26 @@ alterado para tamanho variavel 1-4. (NT2011/004)
+
- Tipo de Nota de Crédito: 01=Multa e juros; 02=Apropriação de crédito presumido de IBS sobre o saldo devedor na ZFM (art. 450, § 1º, LC 214/25); 03=Retorno
+ Tipo de Nota de Crédito:
+ 01=Multa e juros;
+ 02=Apropriação de crédito presumido de IBS sobre o saldo devedor na ZFM (art. 450, § 1º, LC 214/25);
+ 03=Retorno por recusa na entrega ou por não localização do destinatário na tentativa de entrega;
+ 04=Redução de valores;
+ 05=Transferência de crédito na sucessão;
+
+
+
From daecb573e19b2cf6c1e1cb013754aa0c2e0b0d45 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Sat, 15 Nov 2025 10:22:31 -0300
Subject: [PATCH 052/175] fix: update version to 0.5.6 in setup.py
---
pynfe/data/SCHEMAs/NF-e/schemaNFe_v1.00.json | 222 +++++++++----------
setup.py | 2 +-
2 files changed, 112 insertions(+), 112 deletions(-)
diff --git a/pynfe/data/SCHEMAs/NF-e/schemaNFe_v1.00.json b/pynfe/data/SCHEMAs/NF-e/schemaNFe_v1.00.json
index b0920da6..712b51cf 100644
--- a/pynfe/data/SCHEMAs/NF-e/schemaNFe_v1.00.json
+++ b/pynfe/data/SCHEMAs/NF-e/schemaNFe_v1.00.json
@@ -34,7 +34,7 @@
"tipoOperacao": "NFe/infNFe/ide/gCompraGov/tpOperGov"
},
"pagAntecipado": [{
- "chave": "NFe/infNFe/ide/gPagAntecipado/refNFe"
+ "chave": "NFe/infNFe/ide/gPagAntecipado/refNFe[]"
}],
"emitente": {
"cpfCnpj": "NFe/infNFe/emit/CNPJ",
@@ -236,19 +236,19 @@
"reboque": [{
"vagao": "NFe/infNFe/transp/vagao",
"balsa": "NFe/infNFe/transp/balsa",
- "placa": "NFe/infNFe/transp/reboque/placa",
- "uf": "NFe/infNFe/transp/reboque/UF",
- "rntc": "NFe/infNFe/transp/reboque/RNTC"
+ "placa": "NFe/infNFe/transp/reboque[]/placa",
+ "uf": "NFe/infNFe/transp/reboque[]/UF",
+ "rntc": "NFe/infNFe/transp/reboque[]/RNTC"
}],
"volumes": [{
- "quantidade": "NFe/infNFe/transp/vol/qVol",
- "especie": "NFe/infNFe/transp/vol/esp",
- "marca": "NFe/infNFe/transp/vol/marca",
- "numeracao": "NFe/infNFe/transp/vol/nVol",
- "pesoLiquido": "NFe/infNFe/transp/vol/pesoL",
- "pesoBruto": "NFe/infNFe/transp/vol/pesoB",
+ "quantidade": "NFe/infNFe/transp/vol[]/qVol",
+ "especie": "NFe/infNFe/transp/vol[]/esp",
+ "marca": "NFe/infNFe/transp/vol[]/marca",
+ "numeracao": "NFe/infNFe/transp/vol[]/nVol",
+ "pesoLiquido": "NFe/infNFe/transp/vol[]/pesoL",
+ "pesoBruto": "NFe/infNFe/transp/vol[]/pesoB",
"lacres": [{
- "numero": "NFe/infNFe/transp/vol/lacres/nLacre"
+ "numero": "NFe/infNFe/transp/vol[]/lacres[]/nLacre"
}]
}]
},
@@ -258,9 +258,9 @@
"valorDesconto": "NFe/infNFe/cobr/fat/vDesc",
"valorLiquido": "NFe/infNFe/cobr/fat/vLiq",
"parcelas": [{
- "numero": "NFe/infNFe/cobr/dup/nDup",
- "dataVencimento": "NFe/infNFe/cobr/dup/dVenc",
- "valor": "NFe/infNFe/cobr/dup/vDup"
+ "numero": "NFe/infNFe/cobr/dup[]/nDup",
+ "dataVencimento": "NFe/infNFe/cobr/dup[]/dVenc",
+ "valor": "NFe/infNFe/cobr/dup[]/vDup"
}]
},
"valorTroco": "NFe/infNFe/pag/vTroco",
@@ -279,51 +279,51 @@
"cana": {
"safra": "NFe/infNFe/cana/safra",
"dataReferencia": "NFe/infNFe/cana/ref",
+ "quantidadeMes": "NFe/infNFe/cana/qTotMes",
+ "quantidadeAnterior": "NFe/infNFe/cana/qTotAnt",
+ "quantidadeGeral": "NFe/infNFe/cana/qTotGer",
+ "valorFornecimentos": "NFe/infNFe/cana/vFor",
+ "valorTotal": "NFe/infNFe/cana/vTotDed",
+ "valorLiquidoFornecimento": "NFe/infNFe/cana/vLiqFor",
"fornecimentoDiario": [{
- "dia": "NFe/infNFe/cana/forDia/@dia",
- "quantidadeKg": "NFe/infNFe/cana/forDia/qtde",
- "quantidadeMes": "NFe/infNFe/cana/qTotMes",
- "quantidadeAnterior": "NFe/infNFe/cana/qTotAnt",
- "quantidadeGeral": "NFe/infNFe/cana/qTotGer"
+ "dia": "NFe/infNFe/cana/forDia[]/@dia",
+ "quantidadeKg": "NFe/infNFe/cana/forDia[]/qtde"
}]
},
"canaDeducoes": [{
- "descricao": "NFe/infNFe/cana/deduc/xDed",
- "valor": "NFe/infNFe/cana/deduc/vDed",
- "valorFornecimentos": "NFe/infNFe/cana/vFor",
- "valorTotal": "NFe/infNFe/cana/vTotDed",
- "valorLiquidoFornecimento": "NFe/infNFe/cana/vLiqFor"
+ "descricao": "NFe/infNFe/cana/deduc[]/xDed",
+ "valor": "NFe/infNFe/cana/deduc[]/vDed"
}],
"nfeReferenciada": [{
- "chave": "NFe/infNFe/ide/NFref/refNFe",
- "chaveSigilo": "NFe/infNFe/ide/NFref/refNFeSig",
+ "chave": "NFe/infNFe/ide/NFref[]/refNFe",
+ "chaveSigilo": "NFe/infNFe/ide/NFref[]/refNFeSig",
"nfePapel": {
- "estado": "NFe/infNFe/ide/NFref/refNF/cUF",
- "dataEmissao": "NFe/infNFe/ide/NFref/refNF/AAMM",
- "cpfCnpj": "NFe/infNFe/ide/NFref/refNF/CNPJ",
- "modelo": "NFe/infNFe/ide/NFref/refNF/mod",
- "serie": "NFe/infNFe/ide/NFref/refNF/serie",
- "numero": "NFe/infNFe/ide/NFref/refNF/nNF"
+ "estado": "NFe/infNFe/ide/NFref[]/refNF/cUF",
+ "dataEmissao": "NFe/infNFe/ide/NFref[]/refNF/AAMM",
+ "cpfCnpj": "NFe/infNFe/ide/NFref[]/refNF/CNPJ",
+ "modelo": "NFe/infNFe/ide/NFref[]/refNF/mod",
+ "serie": "NFe/infNFe/ide/NFref[]/refNF/serie",
+ "numero": "NFe/infNFe/ide/NFref[]/refNF/nNF"
},
"produtorRural": {
- "estado": "NFe/infNFe/ide/NFref/refNFP/cUF",
- "dataEmissao": "NFe/infNFe/ide/NFref/refNFP/AAMM",
- "cnpj": "NFe/infNFe/ide/NFref/refNFP/CNPJ",
- "cpf": "NFe/infNFe/ide/NFref/refNFP/CPF",
- "inscricaoEstadual": "NFe/infNFe/ide/NFref/refNFP/IE",
- "modelo": "NFe/infNFe/ide/NFref/refNFP/mod",
- "serie": "NFe/infNFe/ide/NFref/refNFP/serie",
- "numero": "NFe/infNFe/ide/NFref/refNFP/nNF"
+ "estado": "NFe/infNFe/ide/NFref[]/refNFP/cUF",
+ "dataEmissao": "NFe/infNFe/ide/NFref[]/refNFP/AAMM",
+ "cnpj": "NFe/infNFe/ide/NFref[]/refNFP/CNPJ",
+ "cpf": "NFe/infNFe/ide/NFref[]/refNFP/CPF",
+ "inscricaoEstadual": "NFe/infNFe/ide/NFref[]/refNFP/IE",
+ "modelo": "NFe/infNFe/ide/NFref[]/refNFP/mod",
+ "serie": "NFe/infNFe/ide/NFref[]/refNFP/serie",
+ "numero": "NFe/infNFe/ide/NFref[]/refNFP/nNF"
},
- "chaveCte": "NFe/infNFe/ide/NFref/refCTe",
+ "chaveCte": "NFe/infNFe/ide/NFref[]/refCTe",
"cupomFiscal": {
- "modelo": "NFe/infNFe/ide/NFref/refECF/mod",
- "numeroOrdemSequencia": "NFe/infNFe/ide/NFref/refECF/nECF",
- "numeroContador": "NFe/infNFe/ide/NFref/refECF/nCOO"
+ "modelo": "NFe/infNFe/ide/NFref[]/refECF/mod",
+ "numeroOrdemSequencia": "NFe/infNFe/ide/NFref[]/refECF/nECF",
+ "numeroContador": "NFe/infNFe/ide/NFref[]/refECF/nCOO"
}
}],
"responsavelAutorizado": [{
- "cpfCnpj": "NFe/infNFe/autXML/CNPJ"
+ "cpfCnpj": "NFe/infNFe/autXML[]/CNPJ"
}],
"itens": [{
"codigo": "NFe/infNFe/det/prod/cProd",
@@ -336,9 +336,9 @@
"cnpjFabricante": "NFe/infNFe/det/prod/CNPJFab",
"codigoBeneficioFiscal": "NFe/infNFe/det/prod/cBenef",
"creditoPresumido": [{
- "codigo": "NFe/infNFe/det/prod/gCred/cCredPresumido",
- "percentual": "NFe/infNFe/det/prod/gCred/pCredPresumido",
- "valor": "NFe/infNFe/det/prod/gCred/vCredPresumido"
+ "codigo": "NFe/infNFe/det/prod/gCred[]/cCredPresumido",
+ "percentual": "NFe/infNFe/det/prod/gCred[]/pCredPresumido",
+ "valor": "NFe/infNFe/det/prod/gCred[]/vCredPresumido"
}],
"exTipi": "NFe/infNFe/det/prod/EXTIPI",
"cfop": "NFe/infNFe/det/prod/CFOP",
@@ -394,9 +394,9 @@
"restricao": "NFe/infNFe/det/prod/veicProd/tpRest"
},
"medicamentos": [{
- "codigoAnvisa": "NFe/infNFe/det/prod/med/cProdANVISA",
- "motivoInsencaoAnvisa": "NFe/infNFe/det/prod/med/xMotivoIsencao",
- "valorMaximo": "NFe/infNFe/det/prod/med/vPMC"
+ "codigoAnvisa": "NFe/infNFe/det/prod/med[]/cProdANVISA",
+ "motivoInsencaoAnvisa": "NFe/infNFe/det/prod/med[]/xMotivoIsencao",
+ "valorMaximo": "NFe/infNFe/det/prod/med[]/vPMC"
}],
"combustivel": {
"codigoAnp": "NFe/infNFe/det/prod/comb/cProdANP",
@@ -422,9 +422,9 @@
"valorFinal": "NFe/infNFe/det/prod/comb/encerrante/vEncFin"
},
"origemCombustivel": [{
- "indicadorImportacao": "NFe/infNFe/det/prod/comb/origComb/indImport",
- "codigoUf": "NFe/infNFe/det/prod/comb/origComb/cUFOrig",
- "percentualOrigUf": "NFe/infNFe/det/prod/comb/origComb/pOrig"
+ "indicadorImportacao": "NFe/infNFe/det/prod/comb/origComb[]/indImport",
+ "codigoUf": "NFe/infNFe/det/prod/comb/origComb[]/cUFOrig",
+ "percentualOrigUf": "NFe/infNFe/det/prod/comb/origComb[]/pOrig"
}]
},
"papelImune": {
@@ -987,61 +987,61 @@
},
"informacoesComplementares": "NFe/infNFe/det/infAdProd",
"numero": "NFe/infNFe/det/@nItem",
- "nve": [{"numero": "NFe/infNFe/det/prod/NVE"}],
+ "nve": [{"numero": "NFe/infNFe/det/prod/NVE[]"}],
"importacao": [{
- "numero": "NFe/infNFe/det/prod/DI/nDI",
- "dataEmissao": "NFe/infNFe/det/prod/DI/dDI",
+ "numero": "NFe/infNFe/det/prod/DI[]/nDI",
+ "dataEmissao": "NFe/infNFe/det/prod/DI[]/dDI",
"desembaraco": {
- "local": "NFe/infNFe/det/prod/DI/xLocDesemb",
- "estado": "NFe/infNFe/det/prod/DI/UFDesemb",
- "data": "NFe/infNFe/det/prod/DI/dDesemb"
+ "local": "NFe/infNFe/det/prod/DI[]/xLocDesemb",
+ "estado": "NFe/infNFe/det/prod/DI[]/UFDesemb",
+ "data": "NFe/infNFe/det/prod/DI[]/dDesemb"
},
- "viaTransporte": "NFe/infNFe/det/prod/DI/tpViaTransp",
- "valorAfrmm": "NFe/infNFe/det/prod/DI/vAFRMM",
- "formaImportacao": "NFe/infNFe/det/prod/DI/tpIntermedio",
+ "viaTransporte": "NFe/infNFe/det/prod/DI[]/tpViaTransp",
+ "valorAfrmm": "NFe/infNFe/det/prod/DI[]/vAFRMM",
+ "formaImportacao": "NFe/infNFe/det/prod/DI[]/tpIntermedio",
"adquirente": {
- "cnpj": "NFe/infNFe/det/prod/DI/CNPJ",
- "cpf": "NFe/infNFe/det/prod/DI/CPF",
- "estado": "NFe/infNFe/det/prod/DI/UFTerceiro"
+ "cnpj": "NFe/infNFe/det/prod/DI[]/CNPJ",
+ "cpf": "NFe/infNFe/det/prod/DI[]/CPF",
+ "estado": "NFe/infNFe/det/prod/DI[]/UFTerceiro"
},
- "codigoExportador": "NFe/infNFe/det/prod/DI/cExportador",
+ "codigoExportador": "NFe/infNFe/det/prod/DI[]/cExportador",
"adicoes": [{
- "numero": "NFe/infNFe/det/prod/DI/adi/nAdicao",
- "numeroSequencia": "NFe/infNFe/det/prod/DI/adi/nSeqAdic",
- "codigoFabricante": "NFe/infNFe/det/prod/DI/adi/cFabricante",
- "valorDesconto": "NFe/infNFe/det/prod/DI/adi/vDescDI",
- "numeroDrawback": "NFe/infNFe/det/prod/DI/adi/nDraw"
+ "numero": "NFe/infNFe/det/prod/DI[]/adi[]/nAdicao",
+ "numeroSequencia": "NFe/infNFe/det/prod/DI[]/adi[]/nSeqAdic",
+ "codigoFabricante": "NFe/infNFe/det/prod/DI[]/adi[]/cFabricante",
+ "valorDesconto": "NFe/infNFe/det/prod/DI[]/adi[]/vDescDI",
+ "numeroDrawback": "NFe/infNFe/det/prod/DI[]/adi[]/nDraw"
}]
}],
"exportacao": [{
- "numeroDrawback": "NFe/infNFe/det/prod/detExport/nDraw",
+ "numeroDrawback": "NFe/infNFe/det/prod/detExport[]/nDraw",
"exportacaoIndireta": {
- "numero": "NFe/infNFe/det/prod/detExport/exportInd/nRE",
- "chave": "NFe/infNFe/det/prod/detExport/exportInd/chNFe",
- "quantidade": "NFe/infNFe/det/prod/detExport/exportInd/qExport"
+ "numero": "NFe/infNFe/det/prod/detExport[]/exportInd/nRE",
+ "chave": "NFe/infNFe/det/prod/detExport[]/exportInd/chNFe",
+ "quantidade": "NFe/infNFe/det/prod/detExport[]/exportInd/qExport"
}
}],
"rastreavel": [{
- "lote": "NFe/infNFe/det/prod/rastro/nLote",
- "quantidade": "NFe/infNFe/det/prod/rastro/qLote",
- "dataFabricacao": "NFe/infNFe/det/prod/rastro/dFab",
- "dataValidade": "NFe/infNFe/det/prod/rastro/dVal",
- "codigoAgregacao": "NFe/infNFe/det/prod/rastro/cAgreg"
+ "lote": "NFe/infNFe/det/prod/rastro[]/nLote",
+ "quantidade": "NFe/infNFe/det/prod/rastro[]/qLote",
+ "dataFabricacao": "NFe/infNFe/det/prod/rastro[]/dFab",
+ "dataValidade": "NFe/infNFe/det/prod/rastro[]/dVal",
+ "codigoAgregacao": "NFe/infNFe/det/prod/rastro[]/cAgreg"
}],
"armamentos": [{
- "tipo": "NFe/infNFe/det/prod/arma/tpArma",
- "numeroSerie": "NFe/infNFe/det/prod/arma/nSerie",
- "numeroSerieCano": "NFe/infNFe/det/prod/arma/nCano",
- "descricao": "NFe/infNFe/det/prod/arma/descr"
+ "tipo": "NFe/infNFe/det/prod/arma[]/tpArma",
+ "numeroSerie": "NFe/infNFe/det/prod/arma[]/nSerie",
+ "numeroSerieCano": "NFe/infNFe/det/prod/arma[]/nCano",
+ "descricao": "NFe/infNFe/det/prod/arma[]/descr"
}],
"observacoes": {
"contribuinte": [{
- "campo": "NFe/infNFe/det/obsItem/obsCont/@xCampo",
- "texto": "NFe/infNFe/det/obsItem/obsCont/xTexto"
+ "campo": "NFe/infNFe/det/obsItem/obsCont[]/@xCampo",
+ "texto": "NFe/infNFe/det/obsItem/obsCont[]/xTexto"
}],
"fisco": [{
- "texto": "NFe/infNFe/det/obsItem/obsFisco/@xCampo",
- "campo": "NFe/infNFe/det/obsItem/obsFisco/xTexto"
+ "texto": "NFe/infNFe/det/obsItem/obsFisco[]/@xCampo",
+ "campo": "NFe/infNFe/det/obsItem/obsFisco[]/xTexto"
}]
},
"valorTotal": "NFe/infNFe/det/vItem",
@@ -1051,24 +1051,24 @@
}
}],
"pagamentos": [{
- "aVista": "NFe/infNFe/pag/detPag/indPag",
- "meio": "NFe/infNFe/pag/detPag/tPag",
- "descricaoMeio": "NFe/infNFe/pag/detPag/xPag",
- "valor": "NFe/infNFe/pag/detPag/vPag",
+ "aVista": "NFe/infNFe/pag/detPag[]/indPag",
+ "meio": "NFe/infNFe/pag/detPag[]/tPag",
+ "descricaoMeio": "NFe/infNFe/pag/detPag[]/xPag",
+ "valor": "NFe/infNFe/pag/detPag[]/vPag",
"cartao": {
- "tipoIntegracao": "NFe/infNFe/pag/detPag/card/tpIntegra",
- "cnpjCredenciadora": "NFe/infNFe/pag/detPag/card/CNPJ",
- "bandeiraOperadora": "NFe/infNFe/pag/detPag/card/tBand",
- "numeroAutorizacao": "NFe/infNFe/pag/detPag/card/cAut"
+ "tipoIntegracao": "NFe/infNFe/pag/detPag[]/card/tpIntegra",
+ "cnpjCredenciadora": "NFe/infNFe/pag/detPag[]/card/CNPJ",
+ "bandeiraOperadora": "NFe/infNFe/pag/detPag[]/card/tBand",
+ "numeroAutorizacao": "NFe/infNFe/pag/detPag[]/card/cAut"
}
}],
"pagamento": {
- "data": "NFe/infNFe/pag/detPag/dPag",
- "cnpjTransacional": "NFe/infNFe/pag/detPag/CNPJPag",
- "ufTransacional": "NFe/infNFe/pag/detPag/UFPag",
+ "data": "NFe/infNFe/pag/detPag[]/dPag",
+ "cnpjTransacional": "NFe/infNFe/pag/detPag[]/CNPJPag",
+ "ufTransacional": "NFe/infNFe/pag/detPag[]/UFPag",
"cartao": {
- "cnpjBeneficiario": "NFe/infNFe/pag/detPag/card/CNPJReceb",
- "idTerminal": "NFe/infNFe/pag/detPag/card/idTermPag"
+ "cnpjBeneficiario": "NFe/infNFe/pag/detPag[]/card/CNPJReceb",
+ "idTerminal": "NFe/infNFe/pag/detPag[]/card/idTermPag"
}
},
"intermediadorTransacao": {
@@ -1077,18 +1077,18 @@
},
"observacoes": {
"contribuinte": [{
- "campo": "NFe/infNFe/infAdic/obsCont/@xCampo",
- "texto": "NFe/infNFe/infAdic/obsCont/xTexto"
+ "campo": "NFe/infNFe/infAdic/obsCont[]/@xCampo",
+ "texto": "NFe/infNFe/infAdic/obsCont[]/xTexto"
}],
"fisco": [{
- "texto": "NFe/infNFe/infAdic/obsFisco/xTexto",
- "campo": "NFe/infNFe/infAdic/obsFisco/@xCampo"
+ "texto": "NFe/infNFe/infAdic/obsFisco[]/xTexto",
+ "campo": "NFe/infNFe/infAdic/obsFisco[]/@xCampo"
}]
},
"processoReferenciado": [{
- "identificador": "NFe/infNFe/infAdic/procRef/nProc",
- "origem": "NFe/infNFe/infAdic/procRef/indProc",
- "tipo": "NFe/infNFe/infAdic/procRef/tpAto"
+ "identificador": "NFe/infNFe/infAdic/procRef[]/nProc",
+ "origem": "NFe/infNFe/infAdic/procRef[]/indProc",
+ "tipo": "NFe/infNFe/infAdic/procRef[]/tpAto"
}],
"responsavelTecnico": {
"cpfCnpj": "NFe/infNFe/infRespTec/CNPJ",
@@ -1100,8 +1100,8 @@
},
"agropecuario": {
"defensivo": [{
- "numeroReceituario": "NFe/infNFe/agropecuario/defensivo/nReceituario",
- "cpfResponsavelTecnico": "NFe/infNFe/agropecuario/defensivo/CPFRespTec"
+ "numeroReceituario": "NFe/infNFe/agropecuario/defensivo[]/nReceituario",
+ "cpfResponsavelTecnico": "NFe/infNFe/agropecuario/defensivo[]/CPFRespTec"
}],
"guiaTransito": {
"tipoGuia": "NFe/infNFe/agropecuario/guiaTransito/tpGuia",
diff --git a/setup.py b/setup.py
index 922ca168..21b209f7 100644
--- a/setup.py
+++ b/setup.py
@@ -6,7 +6,7 @@
setuptools.setup(
name="PyNFe",
- version="0.5.5",
+ version="0.5.6",
author="TadaSoftware",
author_email="tadasoftware@gmail.com",
description="Interface library with the Brazilian Electronic Invoice web services",
From b9a4502f089fb4ccb7c9efa93617f462959c6fb6 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Fri, 28 Nov 2025 14:06:27 -0300
Subject: [PATCH 053/175] =?UTF-8?q?fix:=20corrige=20nome=20do=20campo=20'v?=
=?UTF-8?q?alorIbsCreditoPresumindo'=20para=20'valorIbsCreditoPresumido'?=
=?UTF-8?q?=20no=20schema=20NF-e=20fix:=20atualiza=20vers=C3=A3o=20para=20?=
=?UTF-8?q?0.5.7=20no=20setup.py?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/data/SCHEMAs/NF-e/schemaNFe_v1.00.json | 2 +-
setup.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/pynfe/data/SCHEMAs/NF-e/schemaNFe_v1.00.json b/pynfe/data/SCHEMAs/NF-e/schemaNFe_v1.00.json
index 712b51cf..60af2dc9 100644
--- a/pynfe/data/SCHEMAs/NF-e/schemaNFe_v1.00.json
+++ b/pynfe/data/SCHEMAs/NF-e/schemaNFe_v1.00.json
@@ -191,7 +191,7 @@
"valorDevolucaoIbsMunicipio": "NFe/infNFe/total/IBSCBSTot/gIBS/gIBSMun/vDevTrib",
"valorIbsMunicipio": "NFe/infNFe/total/IBSCBSTot/gIBS/gIBSMun/vIBSMun",
"valorIbs": "NFe/infNFe/total/IBSCBSTot/gIBS/vIBS",
- "valorIbsCreditoPresumindo": "NFe/infNFe/total/IBSCBSTot/gIBS/vCredPres",
+ "valorIbsCreditoPresumido": "NFe/infNFe/total/IBSCBSTot/gIBS/vCredPres",
"valorIbsCreditoPresumidoSupensao": "NFe/infNFe/total/IBSCBSTot/gIBS/vCredPresCondSus",
"valorCbsDiferimento": "NFe/infNFe/total/IBSCBSTot/gCBS/vDif",
"valorCbsDevolucao": "NFe/infNFe/total/IBSCBSTot/gCBS/vDevTrib",
diff --git a/setup.py b/setup.py
index 21b209f7..804dd008 100644
--- a/setup.py
+++ b/setup.py
@@ -6,7 +6,7 @@
setuptools.setup(
name="PyNFe",
- version="0.5.6",
+ version="0.5.7",
author="TadaSoftware",
author_email="tadasoftware@gmail.com",
description="Interface library with the Brazilian Electronic Invoice web services",
From ff9b0976bc9b086cb616c90e7386d546ea597955 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Fri, 28 Nov 2025 14:15:54 -0300
Subject: [PATCH 054/175] fix: corrige nome do campo
'tipoCreditoPresumindoIbsZFM' para 'tipoCreditoPresumidoIbsZFM' no schema
NF-e
---
pynfe/data/SCHEMAs/NF-e/schemaNFe_v1.00.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pynfe/data/SCHEMAs/NF-e/schemaNFe_v1.00.json b/pynfe/data/SCHEMAs/NF-e/schemaNFe_v1.00.json
index 60af2dc9..10b3df7e 100644
--- a/pynfe/data/SCHEMAs/NF-e/schemaNFe_v1.00.json
+++ b/pynfe/data/SCHEMAs/NF-e/schemaNFe_v1.00.json
@@ -362,7 +362,7 @@
"valorDesconto": "NFe/infNFe/det/prod/vDesc",
"valorOutros": "NFe/infNFe/det/prod/vOutro",
"compoeTotal": "NFe/infNFe/det/prod/indTot",
- "tipoCreditoPresumindoIbsZFM": "NFe/infNFe/det/prod/tpCredPresIBSZFM",
+ "tipoCreditoPresumidoIbsZFM": "NFe/infNFe/det/prod/tpCredPresIBSZFM",
"indicadorBemMovelUsado": "NFe/infNFe/det/prod/indBemMovelUsado",
"numeroCompra": "NFe/infNFe/det/prod/xPed",
"pedidoCompra": "NFe/infNFe/det/prod/nItemPed",
From b8dea9da97fef98c2626cc0dcb7a0913442cdd6f Mon Sep 17 00:00:00 2001
From: LucasBonna
Date: Tue, 2 Dec 2025 22:33:56 -0300
Subject: [PATCH 055/175] wip
---
pynfe/processamento/comunicacao.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index ba0d7314..29cb1d4a 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -974,7 +974,9 @@ def _post_sp_https(self, url, xml, metodo):
# gerar nfse
if metodo == "enviar_rps":
- return cliente.service.EnviarRPS(VersaoSchema=1, MensagemXML=xml)
+ return cliente.service.EnvioRPS(VersaoSchema=1, MensagemXML=xml)
+ if metodo == "teste_envio_lote_rps":
+ return cliente.service.TesteEnvioLoteRPS(VersaoSchema=1, MensagemXML=xml)
if metodo == "consultar_rps":
return cliente.service.ConsultaNFe(VersaoSchema=1, MensagemXML=xml)
elif metodo == "cancelar":
From b82a696cb5c06b4ba63f739ac7ad2f7fd301f33a Mon Sep 17 00:00:00 2001
From: LucasBonna
Date: Fri, 12 Dec 2025 14:09:37 -0300
Subject: [PATCH 056/175] =?UTF-8?q?feat:=20enhance=20ComunicacaoNfse=20cla?=
=?UTF-8?q?ss=20for=20S=C3=A3o=20Paulo=20NFSe=20communication=20by=20addin?=
=?UTF-8?q?g=20schema=20version=20support=20and=20new=20methods=20for=20RP?=
=?UTF-8?q?S=20operations?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 49 ++++++++++++++++++++++--------
pynfe/utils/webservices.py | 6 +++-
2 files changed, 41 insertions(+), 14 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 29cb1d4a..369715e2 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -953,16 +953,37 @@ def _post_barueri_https(self, url, xml, metodo):
finally:
certificadoA1.excluir()
- def enviar_sp(self, xml, operation):
+ def enviar_sp(self, xml, operation, versao_schema=2):
+ """
+ Send XML to São Paulo NFS-e webservice.
+
+ Args:
+ xml: XML string to send
+ operation: Operation name (enviar_rps, teste_envio_lote_rps, envio_lote_rps, consultar_rps, cancelar)
+ versao_schema: Schema version (1 for v1, 2 for v2 - Reforma Tributária 2026)
+
+ Returns:
+ WebService response
+ """
url = self._get_url()
if self.autorizador == "SAO_PAULO":
- return self._post_sp_https(url, xml, operation)
+ return self._post_sp_https(url, xml, operation, versao_schema)
else:
raise Exception(f"Enviar RPS não implementado para {self.autorizador}")
- def _post_sp_https(self, url, xml, metodo):
- """Comunicação wsdl (https) utilizando certificado do usuário"""
- # comunicacao wsdl
+ def _post_sp_https(self, url, xml, metodo, versao_schema=2):
+ """
+ Comunicação wsdl (https) utilizando certificado do usuário.
+
+ According to São Paulo NFS-e manual v3.3.4:
+ - VersaoSchema=2: Schema version 2 (Reforma Tributária 2026)
+
+ Args:
+ url: WebService URL
+ xml: XML message string
+ metodo: Method name
+ versao_schema: Schema version (1 or 2)
+ """
certificadoA1 = CertificadoA1(self.certificado)
try:
from pynfe.utils.https_nfse import HttpAuthenticated
@@ -972,16 +993,18 @@ def _post_sp_https(self, url, xml, metodo):
cliente = Client(url, transport=HttpAuthenticated(key=chave, cert=cert, endereco=url))
- # gerar nfse
+ # São Paulo NFS-e WebService methods
+ # Manual v3.3.4 section 4.3.1: All methods receive VersaoSchema and MensagemXML
if metodo == "enviar_rps":
- return cliente.service.EnvioRPS(VersaoSchema=1, MensagemXML=xml)
- if metodo == "teste_envio_lote_rps":
- return cliente.service.TesteEnvioLoteRPS(VersaoSchema=1, MensagemXML=xml)
- if metodo == "consultar_rps":
- return cliente.service.ConsultaNFe(VersaoSchema=1, MensagemXML=xml)
+ return cliente.service.EnvioRPS(VersaoSchema=versao_schema, MensagemXML=xml)
+ elif metodo == "teste_envio_lote_rps":
+ return cliente.service.TesteEnvioLoteRPS(VersaoSchema=versao_schema, MensagemXML=xml)
+ elif metodo == "envio_lote_rps":
+ return cliente.service.EnvioLoteRPS(VersaoSchema=versao_schema, MensagemXML=xml)
+ elif metodo == "consultar_rps":
+ return cliente.service.ConsultaNFe(VersaoSchema=versao_schema, MensagemXML=xml)
elif metodo == "cancelar":
- return cliente.service.CancelamentoNFe(VersaoSchema=1, MensagemXML=xml)
- # TODO outros metodos
+ return cliente.service.CancelamentoNFe(VersaoSchema=versao_schema, MensagemXML=xml)
else:
raise Exception(f"Método {metodo} não implementado no autorizador São Paulo.")
except Exception as e:
diff --git a/pynfe/utils/webservices.py b/pynfe/utils/webservices.py
index 4cccb546..8c675737 100644
--- a/pynfe/utils/webservices.py
+++ b/pynfe/utils/webservices.py
@@ -502,9 +502,13 @@
#
"SAO_PAULO": {
"ENVIAR_RPS": "EnviarRps",
+ "ENVIO_LOTE_RPS": "EnvioLoteRPS",
+ "TESTE_ENVIO_LOTE_RPS": "TesteEnvioLoteRPS",
"CONSULTA_RPS": "ConsultaNFe",
"CANCELAR_NFSE": "CancelamentoNFe",
- "HTTPS": "https://nfe.prefeitura.sp.gov.br/ws/lotenfe.asmx?wsdl"
+ # New URL supports both v1 and v2 (Reforma Tributária 2026)
+ # Old URL (v1 only): https://nfe.prefeitura.sp.gov.br/ws/lotenfe.asmx?wsdl
+ "HTTPS": "https://nfews.prefeitura.sp.gov.br/lotenfe.asmx?WSDL"
},
"BARUERI": {
"ENVIAR_RPS": "EnviarRPS",
From f2cea7f996e942648a21c4546d28f46149d22a66 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Sat, 13 Dec 2025 18:50:02 -0300
Subject: [PATCH 057/175] =?UTF-8?q?feat:=20adiciona=20suporte=20ao=20autor?=
=?UTF-8?q?izador=20Osasco=20com=20m=C3=A9todos=20de=20consulta=20e=20canc?=
=?UTF-8?q?elamento?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 27 ++++++++++
pynfe/processamento/comunicacao.py | 69 ++++++++++++++++++++-----
pynfe/utils/webservices.py | 9 ++++
setup.py | 3 +-
4 files changed, 94 insertions(+), 14 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index 6184077e..fe6232e0 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -10,6 +10,33 @@ def consultar_rps(self):
def cancelar(self):
pass
+class SerializacaoOsasco:
+ def __init__(self, chave_autenticacao):
+ self.chave_autenticacao = chave_autenticacao
+
+ def _consultar(self, cnpj_tomador=None, cpf_tomador=None, data_inicial=None, data_final=None, numero_nota_inicial=None, numero_nota_final=None, numero_rps_inicial=None, numero_rps_final=None, numero_rps_unico=None):
+ return {
+ "ChaveAutenticacao": self.chave_autenticacao,
+ "CNPJTomador": cnpj_tomador,
+ "CPFTomador": cpf_tomador,
+ "DataInicial": data_inicial,
+ "DataFinal": data_final,
+ "NumeroNotaInicial": numero_nota_inicial,
+ "NumeroNotaFinal": numero_nota_final,
+ "NumeroReciboInicial": numero_rps_inicial,
+ "NumeroReciboFinal": numero_rps_final,
+ "NumeroReciboUnico": numero_rps_unico,
+ }
+
+ def consultar_periodo(self, data_inicial, data_final, cnpj_tomador=None, cpf_tomador=None):
+ return self._consultar(data_inicial=data_inicial, data_final=data_final, cnpj_tomador=cnpj_tomador, cpf_tomador=cpf_tomador)
+
+ def consultar_faixa(self,numero_nota_inicial=None, numero_nota_final=None, numero_rps_inicial=None, numero_rps_final=None, cnpj_tomador=None, cpf_tomador=None):
+ return self._consultar(numero_nota_inicial=numero_nota_inicial, numero_nota_final=numero_nota_final, numero_rps_inicial=numero_rps_inicial, numero_rps_final=numero_rps_final, cnpj_tomador=cnpj_tomador, cpf_tomador=cpf_tomador)
+
+ def consultar_nota(self, numero_nota, cnpj_tomador=None, cpf_tomador=None):
+ return self._consultar(numero_nota_inicial=numero_nota, numero_nota_final=numero_nota, cnpj_tomador=cnpj_tomador, cpf_tomador=cpf_tomador)
+
class SerializacaoBetha(InterfaceAutorizador):
def __init__(self):
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 713d4bc3..485b4d7c 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -610,14 +610,14 @@ def _post(self, url, xml, timeout=None):
finally:
certificado_a1.excluir()
-
class ComunicacaoNfse(Comunicacao):
"""Classe de comunicação que segue o padrão definido para as SEFAZ dos Municípios."""
_versao = ""
_namespace = ""
+
- def __init__(self, certificado, certificado_senha, autorizador, homologacao=False):
+ def __init__(self, autorizador, certificado=None, certificado_senha=None, homologacao=False):
self.certificado = certificado
self.certificado_senha = certificado_senha
self._ambiente = 2 if homologacao else 1
@@ -628,6 +628,9 @@ def __init__(self, certificado, certificado_senha, autorizador, homologacao=Fals
elif self.autorizador == "BETHA":
self._namespace = NAMESPACE_BETHA
self._versao = "2.02"
+ elif self.autorizador == "OSASCO":
+ self._namespace = ""
+ self._versao = "1"
else:
raise Exception("Autorizador não encontrado!")
@@ -653,16 +656,19 @@ def enviar_lote(self, xml):
else:
raise Exception("Este método só esta implementado no autorizador ginfes.")
- def consultar(self, xml):
+ def consultar(self, payload):
# url do serviço
url = self._get_url()
if self.autorizador == "GINFES":
# xml
- xml = '' + xml
+ payload = '' + payload
+ # comunica via wsdl
+ return self._post_https(url, payload, "consulta")
+ elif self.autorizador == "OSASCO":
# comunica via wsdl
- return self._post_https(url, xml, "consulta")
+ return self._zeep_client(url, payload, "ConsultarNotaCompleta")
else:
- raise Exception("Este método só esta implementado no autorizador ginfes.")
+ raise Exception("Este método não esta implementado para o autorizador.")
def consultar_rps(self, xml):
# url do serviço
@@ -672,9 +678,11 @@ def consultar_rps(self, xml):
return self._post(url, xml, "consultaRps")
elif self.autorizador == "GINFES":
return self._post_https(url, xml, "consultaRps")
- # TODO outros autorizadres
+ elif self.autorizador == "OSASCO":
+ # comunica via wsdl
+ return self._zeep_client(url, xml, "Consultar")
else:
- raise Exception("Autorizador não encontrado!")
+ raise Exception("Este método não esta implementado para o autorizador.")
def consultar_faixa(self, xml):
# url do serviço
@@ -682,8 +690,11 @@ def consultar_faixa(self, xml):
if self.autorizador == "BETHA":
# comunica via wsdl
return self._post(url, xml, "consultaFaixa")
+ elif self.autorizador == "OSASCO":
+ # comunica via wsdl
+ return self._zeep_client(url, xml, "Consultar")
else:
- raise Exception("Este método só esta implementado no autorizador betha.")
+ raise Exception("Este método não esta implementado para o autorizador.")
def consultar_lote(self, xml):
# url do serviço
@@ -694,7 +705,7 @@ def consultar_lote(self, xml):
# comunica via wsdl
return self._post_https(url, xml, "consulta_lote")
else:
- raise Exception("Este método só esta implementado no autorizador ginfes.")
+ raise Exception("Este método não esta implementado para o autorizador.")
def consultar_situacao_lote(self, xml):
# url do serviço
@@ -703,7 +714,7 @@ def consultar_situacao_lote(self, xml):
# comunica via wsdl
return self._post_https(url, xml, "consulta_situacao_lote")
else:
- raise Exception("Este método só esta implementado no autorizador ginfes.")
+ raise Exception("Este método não esta implementado para o autorizador.")
def cancelar(self, xml):
# url do serviço
@@ -716,9 +727,9 @@ def cancelar(self, xml):
elif self.autorizador == "GINFES":
# comunica via wsdl com certificado
return self._post_https(url, xml, "cancelar")
- # TODO outros autorizadres
+ # TODO outros autorizadores
else:
- raise Exception("Autorizador não encontrado!")
+ raise Exception("Este método não esta implementado para o autorizador.")
def _cabecalho(self, retorna_string=True):
"""Monta o XML do cabeçalho da requisição wsdl
@@ -841,7 +852,39 @@ def _post_https(self, url, xml, metodo):
raise Exception("Método não implementado no autorizador.")
except Exception as e:
raise e
+
+ def _zeep_client(self, wsdl, payload, metodo, wcf_compatibility=True):
+ """Comunicação wsdl utilizando a biblioteca zeep"""
+
+ # comunicacao wsdl
+ try:
+ from zeep import Client
+ from zeep.transports import Transport
+ from zeep.settings import Settings
+ session = requests.Session()
+
+ transport = Transport(
+ session=session,
+ timeout=60
+ )
+
+ settings = Settings(
+ strict=not wcf_compatibility, # IMPORTANTÍSSIMO p/ WCF
+ xml_huge_tree=True
+ )
+ client = Client(
+ wsdl=wsdl,
+ transport=transport,
+ settings=settings
+ )
+ if hasattr(client.service, metodo):
+ service = getattr(client.service, metodo)
+ return service(payload)
+ else:
+ raise Exception("Método não implementado no autorizador.")
+ except Exception as e:
+ raise e
class ComunicacaoMDFe(Comunicacao):
MDFE_SITUACAO_JA_ENVIADO = ("100", "101", "132")
diff --git a/pynfe/utils/webservices.py b/pynfe/utils/webservices.py
index 17e96716..358ba425 100644
--- a/pynfe/utils/webservices.py
+++ b/pynfe/utils/webservices.py
@@ -525,6 +525,15 @@
"HTTPS": "https://producao.ginfes.com.br/ServiceGinfesImpl?wsdl",
"HOMOLOGACAO": "https://homologacao.ginfes.com.br/ServiceGinfesImpl?wsdl",
},
+ "OSASCO": {
+ "AUTORIZACAO": "Emitir",
+ "AUTORIZACAO_LOTE": "EmitirEmLote",
+ "CANCELAR": "Cancelar",
+ "CANCELAR_LOTE": "CancelarNotaLote",
+ "CONSULTA": "Consultar",
+ "HTTPS": "https://nfe.osasco.sp.gov.br/EISSNFEWebServices/NotaFiscalEletronica.svc?wsdl",
+ "HOMOLOGACAO": "https://nfe.osasco.sp.gov.br/EISSNFEWebServices/NotaFiscalEletronica.svc?wsdl",
+ },
}
# MDF-e
diff --git a/setup.py b/setup.py
index 804dd008..2f6d6aa7 100644
--- a/setup.py
+++ b/setup.py
@@ -6,7 +6,7 @@
setuptools.setup(
name="PyNFe",
- version="0.5.7",
+ version="0.6.0",
author="TadaSoftware",
author_email="tadasoftware@gmail.com",
description="Interface library with the Brazilian Electronic Invoice web services",
@@ -34,6 +34,7 @@
"requests",
"lxml",
"signxml",
+ "zeep>=4.3.2",
],
extras_require={
"nfse": [
From c13460a6d58912970d9bcb08c1f5670481d54ac5 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Sat, 13 Dec 2025 20:03:09 -0300
Subject: [PATCH 058/175] =?UTF-8?q?feat:=20atualiza=20a=20classe=20Seriali?=
=?UTF-8?q?zacaoOsasco=20para=20renomear=20m=C3=A9todo=20de=20consulta=20e?=
=?UTF-8?q?=20adiciona=20novo=20m=C3=A9todo=20de=20consulta=20na=20classe?=
=?UTF-8?q?=20SerializacaoNfse=20fix:=20atualiza=20vers=C3=A3o=20para=200.?=
=?UTF-8?q?6.1=20no=20setup.py?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 12 +-----------
pynfe/processamento/serializacao.py | 11 ++++++++++-
setup.py | 2 +-
3 files changed, 12 insertions(+), 13 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index fe6232e0..1416ddc7 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -14,7 +14,7 @@ class SerializacaoOsasco:
def __init__(self, chave_autenticacao):
self.chave_autenticacao = chave_autenticacao
- def _consultar(self, cnpj_tomador=None, cpf_tomador=None, data_inicial=None, data_final=None, numero_nota_inicial=None, numero_nota_final=None, numero_rps_inicial=None, numero_rps_final=None, numero_rps_unico=None):
+ def consultar(self, cnpj_tomador=None, cpf_tomador=None, data_inicial=None, data_final=None, numero_nota_inicial=None, numero_nota_final=None, numero_rps_inicial=None, numero_rps_final=None, numero_rps_unico=None):
return {
"ChaveAutenticacao": self.chave_autenticacao,
"CNPJTomador": cnpj_tomador,
@@ -28,16 +28,6 @@ def _consultar(self, cnpj_tomador=None, cpf_tomador=None, data_inicial=None, dat
"NumeroReciboUnico": numero_rps_unico,
}
- def consultar_periodo(self, data_inicial, data_final, cnpj_tomador=None, cpf_tomador=None):
- return self._consultar(data_inicial=data_inicial, data_final=data_final, cnpj_tomador=cnpj_tomador, cpf_tomador=cpf_tomador)
-
- def consultar_faixa(self,numero_nota_inicial=None, numero_nota_final=None, numero_rps_inicial=None, numero_rps_final=None, cnpj_tomador=None, cpf_tomador=None):
- return self._consultar(numero_nota_inicial=numero_nota_inicial, numero_nota_final=numero_nota_final, numero_rps_inicial=numero_rps_inicial, numero_rps_final=numero_rps_final, cnpj_tomador=cnpj_tomador, cpf_tomador=cpf_tomador)
-
- def consultar_nota(self, numero_nota, cnpj_tomador=None, cpf_tomador=None):
- return self._consultar(numero_nota_inicial=numero_nota, numero_nota_final=numero_nota, cnpj_tomador=cnpj_tomador, cpf_tomador=cpf_tomador)
-
-
class SerializacaoBetha(InterfaceAutorizador):
def __init__(self):
# importa
diff --git a/pynfe/processamento/serializacao.py b/pynfe/processamento/serializacao.py
index 95cd329e..6a4294e0 100644
--- a/pynfe/processamento/serializacao.py
+++ b/pynfe/processamento/serializacao.py
@@ -2206,9 +2206,10 @@ def gerar_qrcode(self, token, csc, xml, return_qr=False, online=True):
class SerializacaoNfse(object):
- def __init__(self, autorizador):
+ def __init__(self, autorizador, chave_autenticacao=None):
"Recebe uma string com o nome do autorizador."
self.autorizador = autorizador
+ self.chave_autenticacao = chave_autenticacao
def gerar(self, nfse):
if self.autorizador.lower() == "betha":
@@ -2233,6 +2234,14 @@ def consultar_nfse(self, emitente, numero=None, inicio=None, fim=None):
return SerializacaoGinfes().consultar_nfse(emitente, numero, inicio, fim)
else:
raise Exception("Este método só esta implementado no autorizador ginfes.")
+
+ def consultar_nota_emitida(self, cnpj_tomador=None, cpf_tomador=None, data_inicial=None, data_final=None, numero_nota_inicial=None, numero_nota_final=None, numero_rps_inicial=None, numero_rps_final=None):
+ if self.autorizador.lower() == "osasco":
+ from pynfe.processamento.autorizador_nfse import SerializacaoOsasco
+
+ return SerializacaoOsasco(self.chave_autenticacao).consultar(cnpj_tomador=cnpj_tomador, cpf_tomador=cpf_tomador, data_inicial=data_inicial, data_final=data_final, numero_nota_inicial=numero_nota_inicial, numero_nota_final=numero_nota_final, numero_rps_inicial=numero_rps_inicial, numero_rps_final=numero_rps_final)
+ else:
+ raise Exception("Este método só esta implementado no autorizador Osasco.")
def consultar_lote(self, emitente, numero):
if self.autorizador.lower() == "ginfes":
diff --git a/setup.py b/setup.py
index 2f6d6aa7..c5f5caec 100644
--- a/setup.py
+++ b/setup.py
@@ -6,7 +6,7 @@
setuptools.setup(
name="PyNFe",
- version="0.6.0",
+ version="0.6.1",
author="TadaSoftware",
author_email="tadasoftware@gmail.com",
description="Interface library with the Brazilian Electronic Invoice web services",
From cdb844fe9d678d452b2bcb86f524cf614eeabf60 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Sun, 14 Dec 2025 13:39:03 -0300
Subject: [PATCH 059/175] =?UTF-8?q?feat:=20atualiza=20a=20vers=C3=A3o=20pa?=
=?UTF-8?q?ra=200.6.2=20no=20setup.py=20e=20refatora=20a=20classe=20Comuni?=
=?UTF-8?q?cacaoNfse=20para=20melhorar=20a=20legibilidade=20do=20c=C3=B3di?=
=?UTF-8?q?go?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 31 +++++++++++++-----------------
setup.py | 2 +-
2 files changed, 14 insertions(+), 19 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 485b4d7c..5dc1c4f8 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -610,12 +610,12 @@ def _post(self, url, xml, timeout=None):
finally:
certificado_a1.excluir()
+
class ComunicacaoNfse(Comunicacao):
"""Classe de comunicação que segue o padrão definido para as SEFAZ dos Municípios."""
_versao = ""
_namespace = ""
-
def __init__(self, autorizador, certificado=None, certificado_senha=None, homologacao=False):
self.certificado = certificado
@@ -852,40 +852,35 @@ def _post_https(self, url, xml, metodo):
raise Exception("Método não implementado no autorizador.")
except Exception as e:
raise e
-
+
def _zeep_client(self, wsdl, payload, metodo, wcf_compatibility=True):
"""Comunicação wsdl utilizando a biblioteca zeep"""
-
- # comunicacao wsdl
+
+ # comunicacao wsdl
try:
- from zeep import Client
- from zeep.transports import Transport
+ from zeep import Client
+ from zeep.helpers import serialize_object
from zeep.settings import Settings
+ from zeep.transports import Transport
+
session = requests.Session()
- transport = Transport(
- session=session,
- timeout=60
- )
+ transport = Transport(session=session, timeout=60)
settings = Settings(
- strict=not wcf_compatibility, # IMPORTANTÍSSIMO p/ WCF
- xml_huge_tree=True
+ strict=not wcf_compatibility, xml_huge_tree=True # IMPORTANTÍSSIMO p/ WCF
)
- client = Client(
- wsdl=wsdl,
- transport=transport,
- settings=settings
- )
+ client = Client(wsdl=wsdl, transport=transport, settings=settings)
if hasattr(client.service, metodo):
service = getattr(client.service, metodo)
- return service(payload)
+ return serialize_object(service(payload))
else:
raise Exception("Método não implementado no autorizador.")
except Exception as e:
raise e
+
class ComunicacaoMDFe(Comunicacao):
MDFE_SITUACAO_JA_ENVIADO = ("100", "101", "132")
diff --git a/setup.py b/setup.py
index c5f5caec..4a356cd4 100644
--- a/setup.py
+++ b/setup.py
@@ -6,7 +6,7 @@
setuptools.setup(
name="PyNFe",
- version="0.6.1",
+ version="0.6.2",
author="TadaSoftware",
author_email="tadasoftware@gmail.com",
description="Interface library with the Brazilian Electronic Invoice web services",
From 7361d854fa934846d40647e8db42374b15a54a47 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Wed, 24 Dec 2025 09:48:30 -0300
Subject: [PATCH 060/175] =?UTF-8?q?feat:=20adiciona=20suporte=20ao=20NFCOM?=
=?UTF-8?q?=20com=20m=C3=A9todos=20de=20consulta=20e=20atualiza=20a=20vers?=
=?UTF-8?q?=C3=A3o=20para=200.7.0=20no=20setup.py?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 68 ++++++++++++++++++++++++------
pynfe/utils/flags.py | 3 ++
pynfe/utils/webservices.py | 36 ++++++++++++++++
setup.py | 2 +-
4 files changed, 94 insertions(+), 15 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 5dc1c4f8..ece235a5 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -14,15 +14,18 @@
NAMESPACE_MDFE,
NAMESPACE_MDFE_METODO,
NAMESPACE_METODO,
+ NAMESPACE_NFCOM,
+ NAMESPACE_NFCOM_METODO,
NAMESPACE_NFE,
NAMESPACE_SOAP,
NAMESPACE_XSD,
NAMESPACE_XSI,
VERSAO_CTE,
VERSAO_MDFE,
+ VERSAO_NFCOM,
VERSAO_PADRAO,
)
-from pynfe.utils.webservices import CTE, MDFE, NFCE, NFE, NFSE
+from pynfe.utils.webservices import CTE, MDFE, NFCE, NFCOM, NFE, NFSE
from .assinatura import AssinaturaA1
@@ -164,13 +167,21 @@ def consulta_nota(self, modelo, chave, contingencia=False):
"""
# url do serviço
url = self._get_url(modelo=modelo, consulta="CHAVE", contingencia=contingencia)
- # Monta XML do corpo da requisição
- raiz = etree.Element("consSitNFe", versao=VERSAO_PADRAO, xmlns=NAMESPACE_NFE)
- etree.SubElement(raiz, "tpAmb").text = str(self._ambiente)
- etree.SubElement(raiz, "xServ").text = "CONSULTAR"
- etree.SubElement(raiz, "chNFe").text = chave
- # Monta XML para envio da requisição
- xml = self._construir_xml_soap("NFeConsultaProtocolo4", raiz)
+ if modelo == "nfcom":
+ raiz = etree.Element("consSitNfcom", versao=VERSAO_NFCOM, xmlns=NAMESPACE_NFCOM)
+ etree.SubElement(raiz, "tpAmb").text = str(self._ambiente)
+ etree.SubElement(raiz, "xServ").text = "CONSULTAR"
+ etree.SubElement(raiz, "chNfcom").text = chave
+
+ xml = self._construir_xml_soap("NFComConsulta", raiz)
+ else:
+ # Monta XML do corpo da requisição
+ raiz = etree.Element("consSitNFe", versao=VERSAO_PADRAO, xmlns=NAMESPACE_NFE)
+ etree.SubElement(raiz, "tpAmb").text = str(self._ambiente)
+ etree.SubElement(raiz, "xServ").text = "CONSULTAR"
+ etree.SubElement(raiz, "chNFe").text = chave
+ # Monta XML para envio da requisição
+ xml = self._construir_xml_soap("NFeConsultaProtocolo4", raiz)
return self._post(url, xml)
def consulta_distribuicao(
@@ -496,8 +507,14 @@ def _get_url(self, modelo, consulta, contingencia=False):
else:
# nfce Ex: https://homologacao.nfce.fazenda.pr.gov.br/nfce/NFeStatusServico3
self.url = NFCE[self.uf.upper()][ambiente] + NFCE[self.uf.upper()][consulta]
+ elif modelo == "nfcom":
+ if self.uf.upper() in ["MG", "MT", "MS"]:
+ self.url = NFCOM[self.uf.upper()][ambiente] + NFCOM[self.uf.upper()][consulta]
+ else:
+ self.url = NFCOM["SVRS"][ambiente] + NFCOM["SVRS"][consulta]
+
else:
- raise Exception('Modelo não encontrado! Defina modelo="nfe" ou "nfce"')
+ raise Exception('Modelo não encontrado! Defina modelo="nfe" ou "nfce" ou "nfcom"')
# Estados que utilizam outros ambientes
else:
lista_svrs = [
@@ -528,8 +545,12 @@ def _get_url(self, modelo, consulta, contingencia=False):
elif modelo == "nfce":
# nfce Ex: https://homologacao.nfce.fazenda.pr.gov.br/nfce/NFeStatusServico3
self.url = NFCE["SVRS"][ambiente] + NFCE["SVRS"][consulta]
+ elif modelo == "nfcom":
+ self.url = NFCOM["SVRS"][ambiente] + NFCOM["SVRS"][consulta]
else:
- raise Exception('Modelo não encontrado! Defina modelo="nfe" ou "nfce"')
+ raise Exception(
+ 'Modelo não encontrado! Defina modelo="nfe" ou "nfce" ou "nfcom"'
+ )
# unico UF que utiliza SVAN ainda para NF-e
# SVRS para NFC-e
elif self.uf.upper() == "MA":
@@ -543,28 +564,47 @@ def _get_url(self, modelo, consulta, contingencia=False):
elif modelo == "nfce":
# nfce Ex: https://homologacao.nfce.fazenda.pr.gov.br/nfce/NFeStatusServico3
self.url = NFCE["SVRS"][ambiente] + NFCE["SVRS"][consulta]
+ elif modelo == "nfcom":
+ self.url = NFCOM["SVRS"][ambiente] + NFCOM["SVRS"][consulta]
else:
- raise Exception('Modelo não encontrado! Defina modelo="nfe" ou "nfce"')
+ raise Exception(
+ 'Modelo não encontrado! Defina modelo="nfe" ou "nfce" ou "nfcom"'
+ )
else:
raise Exception(f"Url não encontrada para {modelo} e {consulta} {self.uf.upper()}")
return self.url
def _construir_xml_soap(self, metodo, dados, cabecalho=False):
- """Mota o XML para o envio via SOAP"""
+ """Monta o XML para o envio via SOAP"""
raiz = etree.Element(
"{%s}Envelope" % NAMESPACE_SOAP,
- nsmap={"xsi": NAMESPACE_XSI, "xsd": NAMESPACE_XSD, "soap": NAMESPACE_SOAP},
+ nsmap={
+ "xsi": NAMESPACE_XSI,
+ "xsd": NAMESPACE_XSD,
+ "soap": NAMESPACE_SOAP,
+ },
)
+
body = etree.SubElement(raiz, "{%s}Body" % NAMESPACE_SOAP)
- # distribuição tem um corpo de xml diferente
+
+ # === NFe Distribuição ===
if metodo == "NFeDistribuicaoDFe":
x = etree.SubElement(body, "nfeDistDFeInteresse", xmlns=NAMESPACE_METODO + metodo)
a = etree.SubElement(x, "nfeDadosMsg")
+
+ # === Cadastro MT ===
elif metodo == "CadConsultaCadastro4" and self.uf.upper() == "MT":
x = etree.SubElement(body, "consultaCadastro", xmlns=NAMESPACE_METODO + metodo)
a = etree.SubElement(x, "nfeDadosMsg")
+
+ # === NFCOM Consulta ===
+ elif metodo == "NFComConsulta":
+ a = etree.SubElement(body, "nfcomDadosMsg", xmlns=NAMESPACE_NFCOM_METODO + metodo)
+
+ # === Default (NFe / NFCe / CTe etc) ===
else:
a = etree.SubElement(body, "nfeDadosMsg", xmlns=NAMESPACE_METODO + metodo)
+
a.append(dados)
return raiz
diff --git a/pynfe/utils/flags.py b/pynfe/utils/flags.py
index 589eab61..35c87368 100644
--- a/pynfe/utils/flags.py
+++ b/pynfe/utils/flags.py
@@ -21,6 +21,9 @@
NAMESPACE_CTE_METODO = "http://www.portalfiscal.inf.br/cte/wsdl/"
VERSAO_CTE = "3.00"
+NAMESPACE_NFCOM = "http://www.portalfiscal.inf.br/nfcom"
+NAMESPACE_NFCOM_METODO = "http://www.portalfiscal.inf.br/nfcom/wsdl/"
+VERSAO_NFCOM = "1.00"
VERSAO_QRCODE = "2"
TIPOS_DOCUMENTO = (
diff --git a/pynfe/utils/webservices.py b/pynfe/utils/webservices.py
index 358ba425..b3bccee8 100644
--- a/pynfe/utils/webservices.py
+++ b/pynfe/utils/webservices.py
@@ -608,3 +608,39 @@
"HOMOLOGACAO": "https://homologacao.nfe.",
},
}
+
+# NFCOM
+NFCOM = {
+ "MG": {
+ "AUTORIZACAO": "fazenda.mg.gov.br/nfcom/services/NFComRecepcao?wsdl",
+ "CHAVE": "fazenda.mg.gov.br/nfcom/services/NFComConsulta?wsdl",
+ "EVENTOS": "fazenda.mg.gov.br/nfcom/services/NFComRecepcaoEvento?wsdl",
+ "STATUS": "fazenda.mg.gov.br/nfcom/services/NFComStatusServico?wsdl",
+ "HTTPS": "https://nfcom.",
+ "HOMOLOGACAO": "https://hnfcom.",
+ },
+ "MS": {
+ "AUTORIZACAO": "sefaz.ms.gov.br/ws/NFComRecepcao?wsdl",
+ "CHAVE": "sefaz.ms.gov.br/ws/NFComConsulta?wsdl",
+ "EVENTOS": "sefaz.ms.gov.br/ws/NFComRecepcaoEvento?wsdl",
+ "STATUS": "sefaz.ms.gov.br/ws/NFComStatusServico?wsdl",
+ "HTTPS": "https://nfcom.",
+ "HOMOLOGACAO": "https://hom.nfcom.",
+ },
+ "MT": {
+ "AUTORIZACAO": "sefaz.mt.gov.br/nfcom/services/NFComRecepcao?wsdl",
+ "CHAVE": "sefaz.mt.gov.br/nfcom/services/NFComConsulta?wsdl",
+ "EVENTOS": "sefaz.mt.gov.br/nfcom/services/NFComRecepcaoEvento?wsdl",
+ "STATUS": "sefaz.mt.gov.br/nfcom/services/NFComStatusServico?wsdl",
+ "HTTPS": "https://www.",
+ "HOMOLOGACAO": "https://homologacao.",
+ },
+ "SVRS": {
+ "AUTORIZACAO": "svrs.rs.gov.br/WS/NFComConsulta/NFComConsulta.asmx",
+ "CHAVE": "svrs.rs.gov.br/WS/NFComRecepcao/NFComRecepcao.asmx",
+ "EVENTOS": "svrs.rs.gov.br/WS/NFComRecepcaoEvento/NFComRecepcaoEvento.asmx",
+ "STATUS": "svrs.rs.gov.br/WS/NFComStatusServico/NFComStatusServico.asmx",
+ "HTTPS": "https://nfcom.",
+ "HOMOLOGACAO": "https://nfcom-homologacao.",
+ }
+}
\ No newline at end of file
diff --git a/setup.py b/setup.py
index 4a356cd4..8c5a63a6 100644
--- a/setup.py
+++ b/setup.py
@@ -6,7 +6,7 @@
setuptools.setup(
name="PyNFe",
- version="0.6.2",
+ version="0.7.0",
author="TadaSoftware",
author_email="tadasoftware@gmail.com",
description="Interface library with the Brazilian Electronic Invoice web services",
From 8b269910434655ba33b2e6874a7ada7de5ea1074 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Wed, 24 Dec 2025 11:39:49 -0300
Subject: [PATCH 061/175] =?UTF-8?q?feat:=20adiciona=20suporte=20ao=20SOAPA?=
=?UTF-8?q?ction=20na=20classe=20ComunicacaoSefaz=20para=20requisi=C3=A7?=
=?UTF-8?q?=C3=B5es=20NFCom?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 13 +++++++++----
setup.py | 2 +-
2 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index ece235a5..84605d5f 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -167,6 +167,7 @@ def consulta_nota(self, modelo, chave, contingencia=False):
"""
# url do serviço
url = self._get_url(modelo=modelo, consulta="CHAVE", contingencia=contingencia)
+ soap_action = None
if modelo == "nfcom":
raiz = etree.Element("consSitNfcom", versao=VERSAO_NFCOM, xmlns=NAMESPACE_NFCOM)
etree.SubElement(raiz, "tpAmb").text = str(self._ambiente)
@@ -174,6 +175,7 @@ def consulta_nota(self, modelo, chave, contingencia=False):
etree.SubElement(raiz, "chNfcom").text = chave
xml = self._construir_xml_soap("NFComConsulta", raiz)
+ soap_action = "nfcomConsultaNF"
else:
# Monta XML do corpo da requisição
raiz = etree.Element("consSitNFe", versao=VERSAO_PADRAO, xmlns=NAMESPACE_NFE)
@@ -182,7 +184,7 @@ def consulta_nota(self, modelo, chave, contingencia=False):
etree.SubElement(raiz, "chNFe").text = chave
# Monta XML para envio da requisição
xml = self._construir_xml_soap("NFeConsultaProtocolo4", raiz)
- return self._post(url, xml)
+ return self._post(url, xml, soap_action=soap_action)
def consulta_distribuicao(
self, cnpj=None, cpf=None, chave=None, nsu=0, consulta_nsu_especifico=False
@@ -608,7 +610,7 @@ def _construir_xml_soap(self, metodo, dados, cabecalho=False):
a.append(dados)
return raiz
- def _post_header(self):
+ def _post_header(self, soap_action=None):
"""Retorna um dicionário com os atributos para o cabeçalho da requisição HTTP"""
# PE é a única UF que exige SOAPAction no header
response = {
@@ -617,9 +619,12 @@ def _post_header(self):
}
if self.uf.upper() == "PE":
response["SOAPAction"] = ""
+
+ if soap_action:
+ response["SOAPAction"] = soap_action
return response
- def _post(self, url, xml, timeout=None):
+ def _post(self, url, xml, timeout=None, soap_action=None):
certificado_a1 = CertificadoA1(self.certificado)
chave, cert = certificado_a1.separar_arquivo(self.certificado_senha, caminho=True)
chave_cert = (cert, chave)
@@ -638,7 +643,7 @@ def _post(self, url, xml, timeout=None):
result = requests.post(
url,
xml,
- headers=self._post_header(),
+ headers=self._post_header(soap_action=soap_action),
cert=chave_cert,
verify=False,
timeout=timeout,
diff --git a/setup.py b/setup.py
index 8c5a63a6..32b57bce 100644
--- a/setup.py
+++ b/setup.py
@@ -6,7 +6,7 @@
setuptools.setup(
name="PyNFe",
- version="0.7.0",
+ version="0.7.1",
author="TadaSoftware",
author_email="tadasoftware@gmail.com",
description="Interface library with the Brazilian Electronic Invoice web services",
From 0c684f65e60e54d57f4560b8fe881dd30fde2bdc Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Wed, 24 Dec 2025 11:42:17 -0300
Subject: [PATCH 062/175] =?UTF-8?q?feat:=20adiciona=20logs=20de=20depura?=
=?UTF-8?q?=C3=A7=C3=A3o=20na=20classe=20ComunicacaoSefaz=20para=20facilit?=
=?UTF-8?q?ar=20o=20diagn=C3=B3stico=20de=20requisi=C3=A7=C3=B5es?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 84605d5f..32cb5d16 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -640,6 +640,9 @@ def _post(self, url, xml, timeout=None, soap_action=None):
)
xml = xml_declaration + xml
# Faz o request com o servidor
+ print(xml)
+ print(url)
+ print(self._post_header(soap_action=soap_action))
result = requests.post(
url,
xml,
From 43c5dcd92c6a8257724efea06dfb280ead3092d9 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Wed, 24 Dec 2025 11:45:55 -0300
Subject: [PATCH 063/175] =?UTF-8?q?feat:=20atualiza=20o=20cabe=C3=A7alho?=
=?UTF-8?q?=20da=20resposta=20SOAP=20para=20incluir=20o=20content-type=20c?=
=?UTF-8?q?om=20a=C3=A7=C3=A3o?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 32cb5d16..b5b94915 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -621,7 +621,7 @@ def _post_header(self, soap_action=None):
response["SOAPAction"] = ""
if soap_action:
- response["SOAPAction"] = soap_action
+ response["content-type"] = f"application/soap+xml; charset=utf-8; action={soap_action}"
return response
def _post(self, url, xml, timeout=None, soap_action=None):
From 29f50e77951443f8bdbb92872ea99dd84e284e9e Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Wed, 24 Dec 2025 12:03:42 -0300
Subject: [PATCH 064/175] feat: corrige elementos XML e remove uso de
SOAPAction na classe ComunicacaoSefaz
---
pynfe/processamento/comunicacao.py | 15 +++++----------
1 file changed, 5 insertions(+), 10 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index b5b94915..49621a6a 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -167,15 +167,13 @@ def consulta_nota(self, modelo, chave, contingencia=False):
"""
# url do serviço
url = self._get_url(modelo=modelo, consulta="CHAVE", contingencia=contingencia)
- soap_action = None
if modelo == "nfcom":
- raiz = etree.Element("consSitNfcom", versao=VERSAO_NFCOM, xmlns=NAMESPACE_NFCOM)
+ raiz = etree.Element("consSitNFCom", versao=VERSAO_NFCOM, xmlns=NAMESPACE_NFCOM)
etree.SubElement(raiz, "tpAmb").text = str(self._ambiente)
etree.SubElement(raiz, "xServ").text = "CONSULTAR"
- etree.SubElement(raiz, "chNfcom").text = chave
+ etree.SubElement(raiz, "chNFCom").text = chave
xml = self._construir_xml_soap("NFComConsulta", raiz)
- soap_action = "nfcomConsultaNF"
else:
# Monta XML do corpo da requisição
raiz = etree.Element("consSitNFe", versao=VERSAO_PADRAO, xmlns=NAMESPACE_NFE)
@@ -184,7 +182,7 @@ def consulta_nota(self, modelo, chave, contingencia=False):
etree.SubElement(raiz, "chNFe").text = chave
# Monta XML para envio da requisição
xml = self._construir_xml_soap("NFeConsultaProtocolo4", raiz)
- return self._post(url, xml, soap_action=soap_action)
+ return self._post(url, xml)
def consulta_distribuicao(
self, cnpj=None, cpf=None, chave=None, nsu=0, consulta_nsu_especifico=False
@@ -610,7 +608,7 @@ def _construir_xml_soap(self, metodo, dados, cabecalho=False):
a.append(dados)
return raiz
- def _post_header(self, soap_action=None):
+ def _post_header(self):
"""Retorna um dicionário com os atributos para o cabeçalho da requisição HTTP"""
# PE é a única UF que exige SOAPAction no header
response = {
@@ -620,8 +618,6 @@ def _post_header(self, soap_action=None):
if self.uf.upper() == "PE":
response["SOAPAction"] = ""
- if soap_action:
- response["content-type"] = f"application/soap+xml; charset=utf-8; action={soap_action}"
return response
def _post(self, url, xml, timeout=None, soap_action=None):
@@ -642,11 +638,10 @@ def _post(self, url, xml, timeout=None, soap_action=None):
# Faz o request com o servidor
print(xml)
print(url)
- print(self._post_header(soap_action=soap_action))
result = requests.post(
url,
xml,
- headers=self._post_header(soap_action=soap_action),
+ headers=self._post_header(),
cert=chave_cert,
verify=False,
timeout=timeout,
From 8ed27ede56fb68b4b6215e2d0e102cc670ca398f Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Wed, 24 Dec 2025 13:01:04 -0300
Subject: [PATCH 065/175] =?UTF-8?q?feat:=20adiciona=20m=C3=A9todo=20para?=
=?UTF-8?q?=20download=20de=20NF-e/NFC-e=20e=20atualiza=20URLs=20de=20down?=
=?UTF-8?q?load=20para=20NFCOM?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 64 ++++++++++++++++++++++++++++--
pynfe/utils/webservices.py | 5 ++-
2 files changed, 65 insertions(+), 4 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 49621a6a..05ad98c1 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
import datetime
import re
-
+import html
import requests
from pynfe.entidades.certificado import CertificadoA1
from pynfe.utils import etree, so_numeros
@@ -172,7 +172,6 @@ def consulta_nota(self, modelo, chave, contingencia=False):
etree.SubElement(raiz, "tpAmb").text = str(self._ambiente)
etree.SubElement(raiz, "xServ").text = "CONSULTAR"
etree.SubElement(raiz, "chNFCom").text = chave
-
xml = self._construir_xml_soap("NFComConsulta", raiz)
else:
# Monta XML do corpo da requisição
@@ -183,6 +182,65 @@ def consulta_nota(self, modelo, chave, contingencia=False):
# Monta XML para envio da requisição
xml = self._construir_xml_soap("NFeConsultaProtocolo4", raiz)
return self._post(url, xml)
+
+ def download_nota(self, modelo, chave, contingencia=False):
+ """
+ Este método oferece o download da NF-e/NFC-e na Base de Dados do Portal
+ da Secretaria de Fazenda Estadual.
+ :param modelo: Modelo da nota
+ :param chave: Chave da nota
+ :param contingencia: Indica se o envio é em contingência ou não
+ :return:
+ """
+ # url do serviço
+ url = self._get_url(modelo=modelo, consulta="DOWNLOAD", contingencia=contingencia)
+
+ if modelo == "nfcom":
+ certificado_a1 = CertificadoA1(self.certificado)
+ chave, cert = certificado_a1.separar_arquivo(self.certificado_senha, caminho=True)
+ chave_cert = (cert, chave)
+ # Abre a conexão HTTPS
+ try:
+ response = requests.post(
+ url,
+ data={
+ "sistema": "Nfcom",
+ "OrigemSite": "0",
+ "Ambiente": self._ambiente, # 1=Produção, 2=Homologação
+ "ChaveAcessoDfe": chave
+ },
+ headers={
+ "User-Agent": "Mozilla/5.0",
+ "Content-Type": "application/x-www-form-urlencoded",
+ "Referer": "https://dfe-portal.svrs.rs.gov.br/Nfcom",
+ },
+ cert=chave_cert,
+ verify=False,
+ timeout=30,
+ )
+
+ pattern = r'"xml"\s*:\s*"(.+?)"\s*\}'
+ match = re.search(pattern, response.text, re.DOTALL)
+
+ if not match:
+ raise ValueError("XML não encontrado no HTML")
+
+ xml_escaped = match.group(1)
+
+ # Remove escapes JavaScript
+ xml = xml_escaped.encode("utf-8").decode("unicode_escape")
+
+ # Converte entidades HTML (& etc)
+ xml = html.unescape(xml)
+ return xml.strip()
+ except requests.exceptions.RequestException as e:
+ raise e
+ finally:
+ certificado_a1.excluir()
+
+ else:
+ raise NotImplementedError("Download not implemented for this model yet.")
+
def consulta_distribuicao(
self, cnpj=None, cpf=None, chave=None, nsu=0, consulta_nsu_especifico=False
@@ -620,7 +678,7 @@ def _post_header(self):
return response
- def _post(self, url, xml, timeout=None, soap_action=None):
+ def _post(self, url, xml, timeout=None):
certificado_a1 = CertificadoA1(self.certificado)
chave, cert = certificado_a1.separar_arquivo(self.certificado_senha, caminho=True)
chave_cert = (cert, chave)
diff --git a/pynfe/utils/webservices.py b/pynfe/utils/webservices.py
index b3bccee8..8fb82640 100644
--- a/pynfe/utils/webservices.py
+++ b/pynfe/utils/webservices.py
@@ -609,9 +609,9 @@
},
}
-# NFCOM
NFCOM = {
"MG": {
+ "DOWNLOAD": "https://dfe-portal.svrs.rs.gov.br/NfcomSSL/DownloadXmlDfe",
"AUTORIZACAO": "fazenda.mg.gov.br/nfcom/services/NFComRecepcao?wsdl",
"CHAVE": "fazenda.mg.gov.br/nfcom/services/NFComConsulta?wsdl",
"EVENTOS": "fazenda.mg.gov.br/nfcom/services/NFComRecepcaoEvento?wsdl",
@@ -620,6 +620,7 @@
"HOMOLOGACAO": "https://hnfcom.",
},
"MS": {
+ "DOWNLOAD": "https://dfe-portal.svrs.rs.gov.br/NfcomSSL/DownloadXmlDfe",
"AUTORIZACAO": "sefaz.ms.gov.br/ws/NFComRecepcao?wsdl",
"CHAVE": "sefaz.ms.gov.br/ws/NFComConsulta?wsdl",
"EVENTOS": "sefaz.ms.gov.br/ws/NFComRecepcaoEvento?wsdl",
@@ -628,6 +629,7 @@
"HOMOLOGACAO": "https://hom.nfcom.",
},
"MT": {
+ "DOWNLOAD": "https://dfe-portal.svrs.rs.gov.br/NfcomSSL/DownloadXmlDfe",
"AUTORIZACAO": "sefaz.mt.gov.br/nfcom/services/NFComRecepcao?wsdl",
"CHAVE": "sefaz.mt.gov.br/nfcom/services/NFComConsulta?wsdl",
"EVENTOS": "sefaz.mt.gov.br/nfcom/services/NFComRecepcaoEvento?wsdl",
@@ -636,6 +638,7 @@
"HOMOLOGACAO": "https://homologacao.",
},
"SVRS": {
+ "DOWNLOAD": "https://dfe-portal.svrs.rs.gov.br/NfcomSSL/DownloadXmlDfe",
"AUTORIZACAO": "svrs.rs.gov.br/WS/NFComConsulta/NFComConsulta.asmx",
"CHAVE": "svrs.rs.gov.br/WS/NFComRecepcao/NFComRecepcao.asmx",
"EVENTOS": "svrs.rs.gov.br/WS/NFComRecepcaoEvento/NFComRecepcaoEvento.asmx",
From b43aa7d56abaa515865f0f0a8c0547de629ca4f4 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Wed, 24 Dec 2025 13:04:30 -0300
Subject: [PATCH 066/175] =?UTF-8?q?feat:=20atualiza=20URLs=20de=20download?=
=?UTF-8?q?=20para=20NFCOM=20e=20ajusta=20l=C3=B3gica=20de=20consulta=20na?=
=?UTF-8?q?=20classe=20ComunicacaoSefaz?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 9 ++++++---
pynfe/utils/webservices.py | 3 ---
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 05ad98c1..63bae5cf 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -566,10 +566,13 @@ def _get_url(self, modelo, consulta, contingencia=False):
# nfce Ex: https://homologacao.nfce.fazenda.pr.gov.br/nfce/NFeStatusServico3
self.url = NFCE[self.uf.upper()][ambiente] + NFCE[self.uf.upper()][consulta]
elif modelo == "nfcom":
- if self.uf.upper() in ["MG", "MT", "MS"]:
- self.url = NFCOM[self.uf.upper()][ambiente] + NFCOM[self.uf.upper()][consulta]
+ if consulta == "DOWNLOAD":
+ self.url = NFCOM["SVRS"][consulta]
else:
- self.url = NFCOM["SVRS"][ambiente] + NFCOM["SVRS"][consulta]
+ if self.uf.upper() in ["MG", "MT", "MS"]:
+ self.url = NFCOM[self.uf.upper()][ambiente] + NFCOM[self.uf.upper()][consulta]
+ else:
+ self.url = NFCOM["SVRS"][ambiente] + NFCOM["SVRS"][consulta]
else:
raise Exception('Modelo não encontrado! Defina modelo="nfe" ou "nfce" ou "nfcom"')
diff --git a/pynfe/utils/webservices.py b/pynfe/utils/webservices.py
index 8fb82640..68256b22 100644
--- a/pynfe/utils/webservices.py
+++ b/pynfe/utils/webservices.py
@@ -611,7 +611,6 @@
NFCOM = {
"MG": {
- "DOWNLOAD": "https://dfe-portal.svrs.rs.gov.br/NfcomSSL/DownloadXmlDfe",
"AUTORIZACAO": "fazenda.mg.gov.br/nfcom/services/NFComRecepcao?wsdl",
"CHAVE": "fazenda.mg.gov.br/nfcom/services/NFComConsulta?wsdl",
"EVENTOS": "fazenda.mg.gov.br/nfcom/services/NFComRecepcaoEvento?wsdl",
@@ -620,7 +619,6 @@
"HOMOLOGACAO": "https://hnfcom.",
},
"MS": {
- "DOWNLOAD": "https://dfe-portal.svrs.rs.gov.br/NfcomSSL/DownloadXmlDfe",
"AUTORIZACAO": "sefaz.ms.gov.br/ws/NFComRecepcao?wsdl",
"CHAVE": "sefaz.ms.gov.br/ws/NFComConsulta?wsdl",
"EVENTOS": "sefaz.ms.gov.br/ws/NFComRecepcaoEvento?wsdl",
@@ -629,7 +627,6 @@
"HOMOLOGACAO": "https://hom.nfcom.",
},
"MT": {
- "DOWNLOAD": "https://dfe-portal.svrs.rs.gov.br/NfcomSSL/DownloadXmlDfe",
"AUTORIZACAO": "sefaz.mt.gov.br/nfcom/services/NFComRecepcao?wsdl",
"CHAVE": "sefaz.mt.gov.br/nfcom/services/NFComConsulta?wsdl",
"EVENTOS": "sefaz.mt.gov.br/nfcom/services/NFComRecepcaoEvento?wsdl",
From ded80996739114d5ad10cc76d7f5d1f0f1c03c0e Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Wed, 24 Dec 2025 13:06:16 -0300
Subject: [PATCH 067/175] =?UTF-8?q?feat:=20adiciona=20logs=20de=20depura?=
=?UTF-8?q?=C3=A7=C3=A3o=20na=20classe=20ComunicacaoSefaz=20para=20facilit?=
=?UTF-8?q?ar=20o=20diagn=C3=B3stico=20de=20erros?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 63bae5cf..fcbb771d 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -223,6 +223,7 @@ def download_nota(self, modelo, chave, contingencia=False):
match = re.search(pattern, response.text, re.DOTALL)
if not match:
+ print(response.text) # DEBUG
raise ValueError("XML não encontrado no HTML")
xml_escaped = match.group(1)
@@ -697,8 +698,6 @@ def _post(self, url, xml, timeout=None):
)
xml = xml_declaration + xml
# Faz o request com o servidor
- print(xml)
- print(url)
result = requests.post(
url,
xml,
From 89c3955399e0788bd5fd4d3875ef7770a69f79ba Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Wed, 24 Dec 2025 13:16:13 -0300
Subject: [PATCH 068/175] =?UTF-8?q?feat:=20implementa=20l=C3=B3gica=20de?=
=?UTF-8?q?=20retry=20na=20consulta=20de=20download=20na=20classe=20Comuni?=
=?UTF-8?q?cacaoSefaz?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 47 +++++++++++++++++-------------
1 file changed, 27 insertions(+), 20 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index fcbb771d..751b1d9b 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
import datetime
+import time
import re
import html
import requests
@@ -201,26 +202,32 @@ def download_nota(self, modelo, chave, contingencia=False):
chave_cert = (cert, chave)
# Abre a conexão HTTPS
try:
- response = requests.post(
- url,
- data={
- "sistema": "Nfcom",
- "OrigemSite": "0",
- "Ambiente": self._ambiente, # 1=Produção, 2=Homologação
- "ChaveAcessoDfe": chave
- },
- headers={
- "User-Agent": "Mozilla/5.0",
- "Content-Type": "application/x-www-form-urlencoded",
- "Referer": "https://dfe-portal.svrs.rs.gov.br/Nfcom",
- },
- cert=chave_cert,
- verify=False,
- timeout=30,
- )
-
- pattern = r'"xml"\s*:\s*"(.+?)"\s*\}'
- match = re.search(pattern, response.text, re.DOTALL)
+ session = requests.Session()
+ for _ in range(3):
+ response = session.post(
+ url,
+ data={
+ "sistema": "Nfcom",
+ "OrigemSite": "0",
+ "Ambiente": self._ambiente, # 1=Produção, 2=Homologação
+ "ChaveAcessoDfe": chave
+ },
+ headers={
+ "User-Agent": "Mozilla/5.0",
+ "Content-Type": "application/x-www-form-urlencoded",
+ "Referer": "https://dfe-portal.svrs.rs.gov.br/Nfcom",
+ },
+ cert=chave_cert,
+ verify=False,
+ timeout=30,
+ )
+
+ pattern = r'"xml"\s*:\s*"(.+?)"\s*\}'
+ match = re.search(pattern, response.text, re.DOTALL)
+ if not match:
+ print(response.text) # DEBUG
+ print("Retrying download...") # DEBUG
+ time.sleep(2) # Wait before retrying
if not match:
print(response.text) # DEBUG
From 794fa82d05674dc50d4412c746387c1a2ebcaa2e Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Wed, 24 Dec 2025 13:41:26 -0300
Subject: [PATCH 069/175] =?UTF-8?q?feat:=20implementa=20download=20da=20NF?=
=?UTF-8?q?Com=20via=20Portal=20SVRS=20com=20valida=C3=A7=C3=A3o=20de=20ch?=
=?UTF-8?q?ave=20e=20tratamento=20de=20bloqueio=20por=20IP?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 131 ++++++++++++++++-------------
1 file changed, 72 insertions(+), 59 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 751b1d9b..346ee080 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -186,69 +186,82 @@ def consulta_nota(self, modelo, chave, contingencia=False):
def download_nota(self, modelo, chave, contingencia=False):
"""
- Este método oferece o download da NF-e/NFC-e na Base de Dados do Portal
- da Secretaria de Fazenda Estadual.
- :param modelo: Modelo da nota
- :param chave: Chave da nota
- :param contingencia: Indica se o envio é em contingência ou não
- :return:
+ Download da NFCom via Portal SVRS (HTML + extração do XML via JS).
"""
- # url do serviço
+
url = self._get_url(modelo=modelo, consulta="DOWNLOAD", contingencia=contingencia)
-
- if modelo == "nfcom":
- certificado_a1 = CertificadoA1(self.certificado)
- chave, cert = certificado_a1.separar_arquivo(self.certificado_senha, caminho=True)
- chave_cert = (cert, chave)
- # Abre a conexão HTTPS
- try:
- session = requests.Session()
- for _ in range(3):
- response = session.post(
- url,
- data={
- "sistema": "Nfcom",
- "OrigemSite": "0",
- "Ambiente": self._ambiente, # 1=Produção, 2=Homologação
- "ChaveAcessoDfe": chave
- },
- headers={
- "User-Agent": "Mozilla/5.0",
- "Content-Type": "application/x-www-form-urlencoded",
- "Referer": "https://dfe-portal.svrs.rs.gov.br/Nfcom",
- },
- cert=chave_cert,
- verify=False,
- timeout=30,
- )
-
- pattern = r'"xml"\s*:\s*"(.+?)"\s*\}'
- match = re.search(pattern, response.text, re.DOTALL)
- if not match:
- print(response.text) # DEBUG
- print("Retrying download...") # DEBUG
- time.sleep(2) # Wait before retrying
-
- if not match:
- print(response.text) # DEBUG
- raise ValueError("XML não encontrado no HTML")
-
- xml_escaped = match.group(1)
-
- # Remove escapes JavaScript
- xml = xml_escaped.encode("utf-8").decode("unicode_escape")
-
- # Converte entidades HTML (& etc)
- xml = html.unescape(xml)
- return xml.strip()
- except requests.exceptions.RequestException as e:
- raise e
- finally:
- certificado_a1.excluir()
-
- else:
+
+ if modelo != "nfcom":
raise NotImplementedError("Download not implemented for this model yet.")
+ # validação da chave
+ if not chave or not chave.isdigit() or len(chave) != 44:
+ raise ValueError("Chave NFCom inválida (esperado 44 dígitos numéricos)")
+
+ certificado_a1 = CertificadoA1(self.certificado)
+
+ try:
+ key_path, cert_path = certificado_a1.separar_arquivo(
+ self.certificado_senha,
+ caminho=True
+ )
+ cert = (cert_path, key_path)
+
+ session = requests.Session()
+
+ response = session.post(
+ url,
+ files={
+ "sistema": (None, "Nfcom"),
+ "OrigemSite": (None, "0"),
+ "Ambiente": (None, str(self._ambiente)),
+ "ChaveAcessoDfe": (None, chave),
+ },
+ headers={
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
+ "Referer": "https://dfe-portal.svrs.rs.gov.br/Nfcom",
+ },
+ cert=cert,
+ verify=False,
+ timeout=30,
+ )
+
+ html_body = response.text
+
+ # 🚫 BLOQUEIO POR IP (rate limit)
+ if (
+ 'textoErro' in html_body and
+ 'IP não autorizado' in html_body
+ ):
+ raise PermissionError(
+ "SVRS bloqueou o IP por múltiplas consultas simultâneas. "
+ "Aguarde liberação ou utilize outro IP."
+ )
+
+ # 🔍 extrai o XML do JS
+ pattern = r'var\s+stringJson\s*=\s*\{\s*"xml"\s*:\s*"(.+?)"\s*\};'
+ match = re.search(pattern, html_body, re.DOTALL)
+
+ if not match:
+ raise ValueError(
+ "XML não encontrado no HTML retornado pelo portal SVRS. "
+ "Pode ser chave inexistente, ambiente incorreto ou NFCom sem permissão."
+ )
+
+ xml_js = match.group(1)
+
+ # remove escapes JavaScript
+ xml = bytes(xml_js, "utf-8").decode("unicode_escape")
+
+ # converte entidades HTML (& etc)
+ xml = html.unescape(xml)
+
+ return xml.strip()
+
+ finally:
+ certificado_a1.excluir()
+
+
def consulta_distribuicao(
self, cnpj=None, cpf=None, chave=None, nsu=0, consulta_nsu_especifico=False
From 759334a42e4c260f38ff5fd0a6e4574572a1a94f Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Wed, 24 Dec 2025 14:00:50 -0300
Subject: [PATCH 070/175] =?UTF-8?q?feat:=20refatora=20m=C3=A9todo=20de=20d?=
=?UTF-8?q?ownload=20da=20NFCom=20para=20melhorar=20a=20legibilidade=20e?=
=?UTF-8?q?=20tratamento=20de=20erros?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 22 ++++++++++------------
1 file changed, 10 insertions(+), 12 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 346ee080..61d5293c 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
import datetime
-import time
-import re
import html
+import re
+
import requests
from pynfe.entidades.certificado import CertificadoA1
from pynfe.utils import etree, so_numeros
@@ -183,7 +183,7 @@ def consulta_nota(self, modelo, chave, contingencia=False):
# Monta XML para envio da requisição
xml = self._construir_xml_soap("NFeConsultaProtocolo4", raiz)
return self._post(url, xml)
-
+
def download_nota(self, modelo, chave, contingencia=False):
"""
Download da NFCom via Portal SVRS (HTML + extração do XML via JS).
@@ -202,8 +202,7 @@ def download_nota(self, modelo, chave, contingencia=False):
try:
key_path, cert_path = certificado_a1.separar_arquivo(
- self.certificado_senha,
- caminho=True
+ self.certificado_senha, caminho=True
)
cert = (cert_path, key_path)
@@ -229,10 +228,7 @@ def download_nota(self, modelo, chave, contingencia=False):
html_body = response.text
# 🚫 BLOQUEIO POR IP (rate limit)
- if (
- 'textoErro' in html_body and
- 'IP não autorizado' in html_body
- ):
+ if "textoErro" in html_body and "IP não autorizado" in html_body:
raise PermissionError(
"SVRS bloqueou o IP por múltiplas consultas simultâneas. "
"Aguarde liberação ou utilize outro IP."
@@ -261,8 +257,6 @@ def download_nota(self, modelo, chave, contingencia=False):
finally:
certificado_a1.excluir()
-
-
def consulta_distribuicao(
self, cnpj=None, cpf=None, chave=None, nsu=0, consulta_nsu_especifico=False
):
@@ -591,7 +585,9 @@ def _get_url(self, modelo, consulta, contingencia=False):
self.url = NFCOM["SVRS"][consulta]
else:
if self.uf.upper() in ["MG", "MT", "MS"]:
- self.url = NFCOM[self.uf.upper()][ambiente] + NFCOM[self.uf.upper()][consulta]
+ self.url = (
+ NFCOM[self.uf.upper()][ambiente] + NFCOM[self.uf.upper()][consulta]
+ )
else:
self.url = NFCOM["SVRS"][ambiente] + NFCOM["SVRS"][consulta]
@@ -717,6 +713,8 @@ def _post(self, url, xml, timeout=None):
etree.tostring(xml, encoding="unicode").replace("\n", ""),
)
xml = xml_declaration + xml
+ print(xml)
+ print("URL:", url)
# Faz o request com o servidor
result = requests.post(
url,
From 66cc0ae80baca42db11542bb8718f043b226d5ca Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Wed, 24 Dec 2025 14:10:41 -0300
Subject: [PATCH 071/175] =?UTF-8?q?refatora=20URLs=20de=20servi=C3=A7os=20?=
=?UTF-8?q?NFE=20e=20NFCOM=20para=20melhorar=20a=20legibilidade=20e=20cons?=
=?UTF-8?q?ist=C3=AAncia?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/utils/webservices.py | 80 ++++++++++++--------------------------
1 file changed, 24 insertions(+), 56 deletions(-)
diff --git a/pynfe/utils/webservices.py b/pynfe/utils/webservices.py
index 68256b22..66cb32c9 100644
--- a/pynfe/utils/webservices.py
+++ b/pynfe/utils/webservices.py
@@ -1,5 +1,5 @@
"""
- @author: Junior Tada, Leonardo Tada
+@author: Junior Tada, Leonardo Tada
"""
# http://nfce.encat.org/desenvolvedor/qrcode/
@@ -299,9 +299,7 @@
NFE = {
# Alguns serviços são disponibilizados apenas pelo ambiente nacional
"AN": {
- "EVENTOS": (
- "nfe.fazenda.gov.br/NFeRecepcaoEvento4/NFeRecepcaoEvento4.asmx"
- ), # versao: 4.00
+ "EVENTOS": "nfe.fazenda.gov.br/NFeRecepcaoEvento4/NFeRecepcaoEvento4.asmx", # versao: 4.00
"DISTRIBUICAO": "nfe.fazenda.gov.br/NFeDistribuicaoDFe/NFeDistribuicaoDFe.asmx",
"HTTPS": "https://www",
"HOMOLOGACAO": "https://hom1",
@@ -317,11 +315,7 @@
"HTTPS": "https://",
"HOMOLOGACAO": "https://hom",
},
- "MA": {
- "CADASTRO": (
- "https://sistemas.sefaz.ma.gov.br/wscadastro/CadConsultaCadastro2?wsdl"
- )
- },
+ "MA": {"CADASTRO": "https://sistemas.sefaz.ma.gov.br/wscadastro/CadConsultaCadastro2?wsdl"},
"PE": {
"STATUS": "sefaz.pe.gov.br/nfe-service/services/NFeStatusServico4",
"AUTORIZACAO": "sefaz.pe.gov.br/nfe-service/services/NFeAutorizacao4",
@@ -334,24 +328,12 @@
"HOMOLOGACAO": "https://nfehomolog.",
},
"BA": {
- "STATUS": (
- "nfe.sefaz.ba.gov.br/webservices/NFeStatusServico4/NFeStatusServico4.asmx"
- ),
- "AUTORIZACAO": (
- "nfe.sefaz.ba.gov.br/webservices/NFeAutorizacao4/NFeAutorizacao4.asmx"
- ),
- "RECIBO": (
- "nfe.sefaz.ba.gov.br/webservices/NFeRetAutorizacao4/NFeRetAutorizacao4.asmx"
- ),
- "CHAVE": (
- "nfe.sefaz.ba.gov.br/webservices/NFeConsultaProtocolo4/NFeConsultaProtocolo4.asmx"
- ),
- "INUTILIZACAO": (
- "nfe.sefaz.ba.gov.br/webservices/NFeInutilizacao4/NFeInutilizacao4.asmx"
- ),
- "EVENTOS": (
- "nfe.sefaz.ba.gov.br/webservices/NFeRecepcaoEvento4/NFeRecepcaoEvento4.asmx"
- ),
+ "STATUS": "nfe.sefaz.ba.gov.br/webservices/NFeStatusServico4/NFeStatusServico4.asmx",
+ "AUTORIZACAO": "nfe.sefaz.ba.gov.br/webservices/NFeAutorizacao4/NFeAutorizacao4.asmx",
+ "RECIBO": "nfe.sefaz.ba.gov.br/webservices/NFeRetAutorizacao4/NFeRetAutorizacao4.asmx",
+ "CHAVE": "nfe.sefaz.ba.gov.br/webservices/NFeConsultaProtocolo4/NFeConsultaProtocolo4.asmx",
+ "INUTILIZACAO": "nfe.sefaz.ba.gov.br/webservices/NFeInutilizacao4/NFeInutilizacao4.asmx",
+ "EVENTOS": "nfe.sefaz.ba.gov.br/webservices/NFeRecepcaoEvento4/NFeRecepcaoEvento4.asmx",
"CADASTRO": (
"nfe.sefaz.ba.gov.br/webservices/CadConsultaCadastro4/CadConsultaCadastro4.asmx"
),
@@ -381,14 +363,10 @@
"HOMOLOGACAO": "https://homologacao.",
},
"PR": {
- "STATUS": (
- "nfe.sefa.pr.gov.br/nfe/NFeStatusServico4"
- ), # CONSULTA STATUS DO SERVICO
+ "STATUS": "nfe.sefa.pr.gov.br/nfe/NFeStatusServico4", # CONSULTA STATUS DO SERVICO
"AUTORIZACAO": "nfe.sefa.pr.gov.br/nfe/NFeAutorizacao4", # AUTORIZACAO
"RECIBO": "nfe.sefa.pr.gov.br/nfe/NFeRetAutorizacao4", # CONSULTA RECIBO
- "CHAVE": (
- "nfe.sefa.pr.gov.br/nfe/NFeConsultaProtocolo4"
- ), # CONSULTA CHAVE DE ACESSO
+ "CHAVE": "nfe.sefa.pr.gov.br/nfe/NFeConsultaProtocolo4", # CONSULTA CHAVE DE ACESSO
"INUTILIZACAO": "nfe.sefa.pr.gov.br/nfe/NFeInutilizacao4", # INUTILIZAÇAO
"EVENTOS": "nfe.sefa.pr.gov.br/nfe/NFeRecepcaoEvento4", # REGISTRO DE EVENTOS
"CADASTRO": "nfe.sefa.pr.gov.br/nfe/CadConsultaCadastro4", # CONSULTA CADASTRO
@@ -445,22 +423,12 @@
"HOMOLOGACAO": "https://homolog.",
},
"SVAN": {
- "STATUS": (
- "sefazvirtual.fazenda.gov.br/NFeStatusServico4/NFeStatusServico4.asmx"
- ),
- "AUTORIZACAO": (
- "sefazvirtual.fazenda.gov.br/NFeAutorizacao4/NFeAutorizacao4.asmx"
- ),
- "RECIBO": (
- "sefazvirtual.fazenda.gov.br/NFeRetAutorizacao4/NFeRetAutorizacao4.asmx"
- ),
+ "STATUS": "sefazvirtual.fazenda.gov.br/NFeStatusServico4/NFeStatusServico4.asmx",
+ "AUTORIZACAO": "sefazvirtual.fazenda.gov.br/NFeAutorizacao4/NFeAutorizacao4.asmx",
+ "RECIBO": "sefazvirtual.fazenda.gov.br/NFeRetAutorizacao4/NFeRetAutorizacao4.asmx",
"CHAVE": "sefazvirtual.fazenda.gov.br/NFeConsultaProtocolo4/NFeConsultaProtocolo4.asmx",
- "INUTILIZACAO": (
- "sefazvirtual.fazenda.gov.br/NFeInutilizacao4/NFeInutilizacao4.asmx"
- ),
- "EVENTOS": (
- "sefazvirtual.fazenda.gov.br/NFeRecepcaoEvento4/NFeRecepcaoEvento4.asmx"
- ),
+ "INUTILIZACAO": "sefazvirtual.fazenda.gov.br/NFeInutilizacao4/NFeInutilizacao4.asmx",
+ "EVENTOS": "sefazvirtual.fazenda.gov.br/NFeRecepcaoEvento4/NFeRecepcaoEvento4.asmx",
"DOWNLOAD": "sefazvirtual.fazenda.gov.br/NfeDownloadNF/NfeDownloadNF.asmx",
"HTTPS": "https://www.",
"HOMOLOGACAO": "https://hom.",
@@ -509,9 +477,7 @@
"CONSULTA_SERVICO_TOMADO": "ConsultarNfseServicoTomado",
"SUBSTITUIR": "SubstituirNfse",
"HTTPS": "http://e-gov.betha.com.br/e-nota-contribuinte-ws/nfseWS?wsdl",
- "HOMOLOGACAO": (
- "http://e-gov.betha.com.br/e-nota-contribuinte-test-ws/nfseWS?wsdl"
- ),
+ "HOMOLOGACAO": "http://e-gov.betha.com.br/e-nota-contribuinte-test-ws/nfseWS?wsdl",
},
#
"GINFES": {
@@ -532,7 +498,9 @@
"CANCELAR_LOTE": "CancelarNotaLote",
"CONSULTA": "Consultar",
"HTTPS": "https://nfe.osasco.sp.gov.br/EISSNFEWebServices/NotaFiscalEletronica.svc?wsdl",
- "HOMOLOGACAO": "https://nfe.osasco.sp.gov.br/EISSNFEWebServices/NotaFiscalEletronica.svc?wsdl",
+ "HOMOLOGACAO": (
+ "https://nfe.osasco.sp.gov.br/EISSNFEWebServices/NotaFiscalEletronica.svc?wsdl"
+ ),
},
}
@@ -636,11 +604,11 @@
},
"SVRS": {
"DOWNLOAD": "https://dfe-portal.svrs.rs.gov.br/NfcomSSL/DownloadXmlDfe",
- "AUTORIZACAO": "svrs.rs.gov.br/WS/NFComConsulta/NFComConsulta.asmx",
- "CHAVE": "svrs.rs.gov.br/WS/NFComRecepcao/NFComRecepcao.asmx",
+ "AUTORIZACAO": "svrs.rs.gov.br/WS/NFComRecepcao/NFComRecepcao.asmx",
+ "CHAVE": "svrs.rs.gov.br/WS/NFComConsulta/NFComConsulta.asmx",
"EVENTOS": "svrs.rs.gov.br/WS/NFComRecepcaoEvento/NFComRecepcaoEvento.asmx",
"STATUS": "svrs.rs.gov.br/WS/NFComStatusServico/NFComStatusServico.asmx",
"HTTPS": "https://nfcom.",
"HOMOLOGACAO": "https://nfcom-homologacao.",
- }
-}
\ No newline at end of file
+ },
+}
From f905fb062300d30d71e30e796238922b740a8aa8 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 29 Dec 2025 18:00:40 -0300
Subject: [PATCH 072/175] =?UTF-8?q?corrige=20verifica=C3=A7=C3=A3o=20de=20?=
=?UTF-8?q?refer=C3=AAncia=20na=20assinatura=20XML=20para=20evitar=20erros?=
=?UTF-8?q?=20de=20atributo=20None?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/assinatura.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pynfe/processamento/assinatura.py b/pynfe/processamento/assinatura.py
index 50c5e263..b057078d 100644
--- a/pynfe/processamento/assinatura.py
+++ b/pynfe/processamento/assinatura.py
@@ -29,7 +29,7 @@ def __init__(self, certificado, senha):
def assinar(self, xml: etree._Element, retorna_string=False) -> Union[str, etree._Element]:
# busca tag que tem id(reference_uri), logo nao importa se tem namespace
- reference = xml.find(".//*[@Id]").attrib["Id"]
+ reference = xml.find(".//*[@Id]").attrib["Id"] if xml.find(".//*[@Id]") is not None else None
# retira acentos
xml_str = remover_acentos(etree.tostring(xml, encoding="unicode", pretty_print=False))
From c81d59030556041237e5b425ca6604b354cf9a12 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 29 Dec 2025 18:06:23 -0300
Subject: [PATCH 073/175] =?UTF-8?q?altera=20m=C3=A9todos=20de=20comunica?=
=?UTF-8?q?=C3=A7=C3=A3o=20da=20NFS-e=20para=20vers=C3=A3o=203?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 14 +++++---------
1 file changed, 5 insertions(+), 9 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index aca316a6..446b1190 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -959,28 +959,24 @@ def _post_https(self, url, xml, metodo):
if metodo == "gerar":
return cliente.service.GerarNfse(cabecalho, xml)
elif metodo == "enviar_lote":
- return cliente.service.RecepcionarLoteRpsV3(cabecalho, xml)
+ return cliente.service.RecepcionarLoteRps(cabecalho, xml)
elif metodo == "consulta":
- return cliente.service.ConsultarNfseV3(cabecalho, xml)
+ return cliente.service.ConsultarNfse(cabecalho, xml)
elif metodo == "consulta_lote":
- return cliente.service.ConsultarLoteRpsV3(cabecalho, xml)
+ return cliente.service.ConsultarLoteRps(cabecalho, xml)
elif metodo == "consulta_situacao_lote":
- return cliente.service.ConsultarSituacaoLoteRpsV3(cabecalho, xml)
+ return cliente.service.ConsultarSituacaoLoteRps(cabecalho, xml)
elif metodo == "consultaRps":
- return cliente.service.ConsultarNfsePorRpsV3(cabecalho, xml)
+ return cliente.service.ConsultarNfsePorRps(cabecalho, xml)
elif metodo == "consultaFaixa":
return cliente.service.ConsultarNfseFaixa(cabecalho, xml)
elif metodo == "cancelar":
- # versão 2
return cliente.service.CancelarNfse(xml)
- # versão 3
- # return cliente.service.CancelarNfseV3(cabecalho, xml)
# TODO outros metodos
else:
raise Exception("Método não implementado no autorizador.")
except Exception as e:
raise e
-
def enviar_barueri(self, xml, operation):
url = self._get_url()
From 26923a62707e409f163a09d7c04e831fee7ffef3 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 29 Dec 2025 18:12:30 -0300
Subject: [PATCH 074/175] =?UTF-8?q?atualiza=20m=C3=A9todos=20de=20comunica?=
=?UTF-8?q?=C3=A7=C3=A3o=20da=20NFS-e=20para=20vers=C3=A3o=203=20e=20remov?=
=?UTF-8?q?e=20m=C3=A9todos=20obsoletos?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 25 +++++++++----------------
pynfe/utils/webservices.py | 9 ++-------
2 files changed, 11 insertions(+), 23 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 446b1190..75b9708f 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -959,24 +959,28 @@ def _post_https(self, url, xml, metodo):
if metodo == "gerar":
return cliente.service.GerarNfse(cabecalho, xml)
elif metodo == "enviar_lote":
- return cliente.service.RecepcionarLoteRps(cabecalho, xml)
+ return cliente.service.RecepcionarLoteRpsV3(cabecalho, xml)
elif metodo == "consulta":
- return cliente.service.ConsultarNfse(cabecalho, xml)
+ return cliente.service.ConsultarNfseV3(cabecalho, xml)
elif metodo == "consulta_lote":
- return cliente.service.ConsultarLoteRps(cabecalho, xml)
+ return cliente.service.ConsultarLoteRpsV3(cabecalho, xml)
elif metodo == "consulta_situacao_lote":
- return cliente.service.ConsultarSituacaoLoteRps(cabecalho, xml)
+ return cliente.service.ConsultarSituacaoLoteRpsV3(cabecalho, xml)
elif metodo == "consultaRps":
- return cliente.service.ConsultarNfsePorRps(cabecalho, xml)
+ return cliente.service.ConsultarNfsePorRpsV3(cabecalho, xml)
elif metodo == "consultaFaixa":
return cliente.service.ConsultarNfseFaixa(cabecalho, xml)
elif metodo == "cancelar":
+ # versão 2
return cliente.service.CancelarNfse(xml)
+ # versão 3
+ # return cliente.service.CancelarNfseV3(cabecalho, xml)
# TODO outros metodos
else:
raise Exception("Método não implementado no autorizador.")
except Exception as e:
raise e
+
def enviar_barueri(self, xml, operation):
url = self._get_url()
@@ -1520,17 +1524,6 @@ def consulta_distribuicao(
xml = self._construir_xml_soap("CTeDistribuicaoDFe", raiz)
return self._post(url, xml)
- def consulta(self, chave):
- url = self._get_url("CONSULTA")
- # Monta XML do corpo da requisição
- raiz = etree.Element("consSitCTe", versao=self._versao, xmlns=NAMESPACE_CTE)
- etree.SubElement(raiz, "tpAmb").text = str(self._ambiente)
- etree.SubElement(raiz, "xServ").text = "CONSULTAR"
- etree.SubElement(raiz, "chCTe").text = chave
- # Monta XML para envio da requisição
- xml = self._construir_xml_soap("cteConsultaCT", raiz)
- return self._post(url, xml)
-
def _get_url_an(self, consulta):
ambiente = "https://www1." # produção
if self._ambiente == 2: # homologacao
diff --git a/pynfe/utils/webservices.py b/pynfe/utils/webservices.py
index 6e406ab5..0c79fe17 100644
--- a/pynfe/utils/webservices.py
+++ b/pynfe/utils/webservices.py
@@ -500,13 +500,8 @@
},
#
"GINFES": {
- "AUTORIZACAO": "GerarNfse",
- "CANCELAR": "CancelarNfse",
- "CONSULTA_RPS": "ConsultarNfsePorRps",
- "CONSULTA_FAIXA": "ConsultarNfseFaixa",
- "CONSULTA_SERVICO": "ConsultarNfseServicoPrestado",
- "CONSULTA_SERVICO_TOMADO": "ConsultarNfseServicoTomado",
- "SUBSTITUIR": "SubstituirNfse",
+ "CONSULTA": "ConsultarNfseV3",
+ "CONSULTA_RPS": "ConsultarNfsePorRpsV3",
"HTTPS": "https://producao.ginfes.com.br/ServiceGinfesImpl?wsdl",
"HOMOLOGACAO": "https://homologacao.ginfes.com.br/ServiceGinfesImpl?wsdl",
},
From e812e5851ba6d120f390a2981a5c0d6e7d4d95fc Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 29 Dec 2025 18:14:55 -0300
Subject: [PATCH 075/175] =?UTF-8?q?atualiza=20URLs=20de=20servi=C3=A7o=20d?=
=?UTF-8?q?a=20GINFES=20para=20remover=20a=20extens=C3=A3o=20WSDL?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/utils/webservices.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pynfe/utils/webservices.py b/pynfe/utils/webservices.py
index 0c79fe17..2da93dc0 100644
--- a/pynfe/utils/webservices.py
+++ b/pynfe/utils/webservices.py
@@ -502,8 +502,8 @@
"GINFES": {
"CONSULTA": "ConsultarNfseV3",
"CONSULTA_RPS": "ConsultarNfsePorRpsV3",
- "HTTPS": "https://producao.ginfes.com.br/ServiceGinfesImpl?wsdl",
- "HOMOLOGACAO": "https://homologacao.ginfes.com.br/ServiceGinfesImpl?wsdl",
+ "HTTPS": "https://producao.ginfes.com.br/ServiceGinfesImpl",
+ "HOMOLOGACAO": "https://homologacao.ginfes.com.br/ServiceGinfesImpl",
},
"OSASCO": {
"AUTORIZACAO": "Emitir",
From cd4741fc76526a1205265b88eaa802c311e2e0da Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 29 Dec 2025 18:21:58 -0300
Subject: [PATCH 076/175] =?UTF-8?q?atualiza=20m=C3=A9todos=20de=20comunica?=
=?UTF-8?q?=C3=A7=C3=A3o=20da=20NFS-e=20para=20utilizar=20a=20biblioteca?=
=?UTF-8?q?=20zeep=20e=20ajusta=20URLs=20de=20servi=C3=A7o=20da=20GINFES?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 37 ++++++++++++++++--------------
pynfe/utils/webservices.py | 4 ++--
2 files changed, 22 insertions(+), 19 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 75b9708f..9a4dc477 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -803,7 +803,7 @@ def consultar_rps(self, xml):
# comunica via wsdl
return self._post(url, xml, "consultaRps")
elif self.autorizador == "GINFES":
- return self._post_https(url, xml, "consultaRps")
+ return self._zeep_client(url, xml, "consultaRps")
elif self.autorizador == "OSASCO":
# comunica via wsdl
return self._zeep_client(url, xml, "Consultar")
@@ -961,6 +961,9 @@ def _post_https(self, url, xml, metodo):
elif metodo == "enviar_lote":
return cliente.service.RecepcionarLoteRpsV3(cabecalho, xml)
elif metodo == "consulta":
+ print("URL:", url)
+ print("Cabecalho:", cabecalho)
+ print("XML:", xml)
return cliente.service.ConsultarNfseV3(cabecalho, xml)
elif metodo == "consulta_lote":
return cliente.service.ConsultarLoteRpsV3(cabecalho, xml)
@@ -1011,7 +1014,7 @@ def _post_barueri_requests(self, url, xml, operation):
Recebe o envelope SOAP completo já montado
"""
import requests
-
+
certificado_a1 = CertificadoA1(self.certificado)
try:
chave, cert = certificado_a1.separar_arquivo(self.certificado_senha, caminho=True)
@@ -1027,26 +1030,23 @@ def _post_barueri_requests(self, url, xml, operation):
soap_action = "http://www.barueri.sp.gov.br/nfe/NFeLoteBaixarArquivo"
else:
raise Exception(f"Operação {operation} não implementada para Barueri.")
-
- headers = {
- 'Content-Type': 'text/xml; charset=utf-8',
- 'SOAPAction': f'"{soap_action}"'
- }
-
+
+ headers = {"Content-Type": "text/xml; charset=utf-8", "SOAPAction": f'"{soap_action}"'}
+
return requests.post(
url,
- data=xml.encode('utf-8'),
+ data=xml.encode("utf-8"),
headers=headers,
cert=chave_cert,
verify=False,
- timeout=30
+ timeout=30,
)
-
+
except requests.exceptions.RequestException as e:
raise e
finally:
certificado_a1.excluir()
-
+
def _post_barueri_https(self, url, xml, metodo):
"""
LEGACY: Comunicação wsdl (https) utilizando certificado do usuário
@@ -1087,12 +1087,12 @@ def _post_barueri_https(self, url, xml, metodo):
def enviar_sp(self, xml, operation, versao_schema=2):
"""
Send XML to São Paulo NFS-e webservice.
-
+
Args:
xml: XML string to send
operation: Operation name (enviar_rps, teste_envio_lote_rps, envio_lote_rps, consultar_rps, cancelar)
versao_schema: Schema version (1 for v1, 2 for v2 - Reforma Tributária 2026)
-
+
Returns:
WebService response
"""
@@ -1105,10 +1105,10 @@ def enviar_sp(self, xml, operation, versao_schema=2):
def _post_sp_https(self, url, xml, metodo, versao_schema=2):
"""
Comunicação wsdl (https) utilizando certificado do usuário.
-
+
According to São Paulo NFS-e manual v3.3.4:
- VersaoSchema=2: Schema version 2 (Reforma Tributária 2026)
-
+
Args:
url: WebService URL
xml: XML message string
@@ -1129,7 +1129,9 @@ def _post_sp_https(self, url, xml, metodo, versao_schema=2):
if metodo == "enviar_rps":
return cliente.service.EnvioRPS(VersaoSchema=versao_schema, MensagemXML=xml)
elif metodo == "teste_envio_lote_rps":
- return cliente.service.TesteEnvioLoteRPS(VersaoSchema=versao_schema, MensagemXML=xml)
+ return cliente.service.TesteEnvioLoteRPS(
+ VersaoSchema=versao_schema, MensagemXML=xml
+ )
elif metodo == "envio_lote_rps":
return cliente.service.EnvioLoteRPS(VersaoSchema=versao_schema, MensagemXML=xml)
elif metodo == "consultar_rps":
@@ -1142,6 +1144,7 @@ def _post_sp_https(self, url, xml, metodo, versao_schema=2):
raise e
finally:
certificadoA1.excluir()
+
def _zeep_client(self, wsdl, payload, metodo, wcf_compatibility=True):
"""Comunicação wsdl utilizando a biblioteca zeep"""
diff --git a/pynfe/utils/webservices.py b/pynfe/utils/webservices.py
index 2da93dc0..0c79fe17 100644
--- a/pynfe/utils/webservices.py
+++ b/pynfe/utils/webservices.py
@@ -502,8 +502,8 @@
"GINFES": {
"CONSULTA": "ConsultarNfseV3",
"CONSULTA_RPS": "ConsultarNfsePorRpsV3",
- "HTTPS": "https://producao.ginfes.com.br/ServiceGinfesImpl",
- "HOMOLOGACAO": "https://homologacao.ginfes.com.br/ServiceGinfesImpl",
+ "HTTPS": "https://producao.ginfes.com.br/ServiceGinfesImpl?wsdl",
+ "HOMOLOGACAO": "https://homologacao.ginfes.com.br/ServiceGinfesImpl?wsdl",
},
"OSASCO": {
"AUTORIZACAO": "Emitir",
From 8bee3a0f80b2696c199c83ef6b8681a5fa34e9f4 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 29 Dec 2025 18:24:01 -0300
Subject: [PATCH 077/175] =?UTF-8?q?remove=20extens=C3=A3o=20=3Fwsdl=20da?=
=?UTF-8?q?=20URL=20do=20cliente=20e=20ajusta=20a=20cria=C3=A7=C3=A3o=20do?=
=?UTF-8?q?=20objeto=20Client?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 9a4dc477..d4c0c2bc 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -953,7 +953,20 @@ def _post_https(self, url, xml, metodo):
certificadoA1 = CertificadoA1(self.certificado)
chave, cert = certificadoA1.separar_arquivo(self.certificado_senha, caminho=True)
- cliente = Client(url, transport=HttpAuthenticated(key=chave, cert=cert, endereco=url))
+ wsdl = url # ?wsdl
+ endpoint = url.replace("?wsdl", "") # REMOVE ?wsdl
+
+ print("WSDL:", wsdl)
+ print("ENDPOINT:", endpoint)
+
+ cliente = Client(
+ wsdl,
+ transport=HttpAuthenticated(
+ key=chave,
+ cert=cert,
+ endereco=endpoint # ✅ endpoint correto
+ )
+ )
# gerar nfse
if metodo == "gerar":
From 6b6ab35e0500afffc3c0223328d4ba6caff6749e Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 29 Dec 2025 18:34:17 -0300
Subject: [PATCH 078/175] =?UTF-8?q?ajusta=20m=C3=A9todos=20de=20comunica?=
=?UTF-8?q?=C3=A7=C3=A3o=20da=20NFS-e=20para=20incluir=20consulta=20comple?=
=?UTF-8?q?ta=20e=20modifica=20a=20implementa=C3=A7=C3=A3o=20para=20usar?=
=?UTF-8?q?=20a=20biblioteca=20zeep?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 122 +++++++++++++++++------------
pynfe/utils/webservices.py | 1 +
2 files changed, 74 insertions(+), 49 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index d4c0c2bc..e300f592 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -6,26 +6,14 @@
import requests
from pynfe.entidades.certificado import CertificadoA1
from pynfe.utils import etree, so_numeros
-from pynfe.utils.flags import (
- CODIGOS_ESTADOS,
- MODELO_MDFE,
- NAMESPACE_BETHA,
- NAMESPACE_CTE,
- NAMESPACE_CTE_METODO,
- NAMESPACE_MDFE,
- NAMESPACE_MDFE_METODO,
- NAMESPACE_METODO,
- NAMESPACE_NFCOM,
- NAMESPACE_NFCOM_METODO,
- NAMESPACE_NFE,
- NAMESPACE_SOAP,
- NAMESPACE_XSD,
- NAMESPACE_XSI,
- VERSAO_CTE,
- VERSAO_MDFE,
- VERSAO_NFCOM,
- VERSAO_PADRAO,
-)
+from pynfe.utils.flags import (CODIGOS_ESTADOS, MODELO_MDFE, NAMESPACE_BETHA,
+ NAMESPACE_CTE, NAMESPACE_CTE_METODO,
+ NAMESPACE_MDFE, NAMESPACE_MDFE_METODO,
+ NAMESPACE_METODO, NAMESPACE_NFCOM,
+ NAMESPACE_NFCOM_METODO, NAMESPACE_NFE,
+ NAMESPACE_SOAP, NAMESPACE_XSD, NAMESPACE_XSI,
+ VERSAO_CTE, VERSAO_MDFE, VERSAO_NFCOM,
+ VERSAO_PADRAO)
from pynfe.utils.webservices import CTE, MDFE, NFCE, NFCOM, NFE, NFSE
from .assinatura import AssinaturaA1
@@ -782,17 +770,19 @@ def enviar_lote(self, xml):
else:
raise Exception("Este método só esta implementado no autorizador ginfes.")
- def consultar(self, payload):
+ def consultar(self, xml):
# url do serviço
url = self._get_url()
+
if self.autorizador == "GINFES":
- # xml
- payload = '' + payload
+ cabecalho = self._cabecalho_ginfes()
+ xml = '' + xml
# comunica via wsdl
- return self._post_https(url, payload, "consulta")
+ return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA"],cabecalho, xml)
+
elif self.autorizador == "OSASCO":
# comunica via wsdl
- return self._zeep_client(url, payload, "ConsultarNotaCompleta")
+ return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA_COMPLETA"], xml)
else:
raise Exception("Este método não esta implementado para o autorizador.")
@@ -803,10 +793,12 @@ def consultar_rps(self, xml):
# comunica via wsdl
return self._post(url, xml, "consultaRps")
elif self.autorizador == "GINFES":
- return self._zeep_client(url, xml, "consultaRps")
+ cabecalho = self._cabecalho_ginfes()
+ xml = '' + xml
+ return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA_RPS"],cabecalho, xml)
elif self.autorizador == "OSASCO":
# comunica via wsdl
- return self._zeep_client(url, xml, "Consultar")
+ return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA"], xml)
else:
raise Exception("Este método não esta implementado para o autorizador.")
@@ -818,7 +810,7 @@ def consultar_faixa(self, xml):
return self._post(url, xml, "consultaFaixa")
elif self.autorizador == "OSASCO":
# comunica via wsdl
- return self._zeep_client(url, xml, "Consultar")
+ return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA"], xml)
else:
raise Exception("Este método não esta implementado para o autorizador.")
@@ -953,7 +945,7 @@ def _post_https(self, url, xml, metodo):
certificadoA1 = CertificadoA1(self.certificado)
chave, cert = certificadoA1.separar_arquivo(self.certificado_senha, caminho=True)
- wsdl = url # ?wsdl
+ wsdl = url # ?wsdl
endpoint = url.replace("?wsdl", "") # REMOVE ?wsdl
print("WSDL:", wsdl)
@@ -962,10 +954,8 @@ def _post_https(self, url, xml, metodo):
cliente = Client(
wsdl,
transport=HttpAuthenticated(
- key=chave,
- cert=cert,
- endereco=endpoint # ✅ endpoint correto
- )
+ key=chave, cert=cert, endereco=endpoint # ✅ endpoint correto
+ ),
)
# gerar nfse
@@ -1158,32 +1148,66 @@ def _post_sp_https(self, url, xml, metodo, versao_schema=2):
finally:
certificadoA1.excluir()
- def _zeep_client(self, wsdl, payload, metodo, wcf_compatibility=True):
- """Comunicação wsdl utilizando a biblioteca zeep"""
-
- # comunicacao wsdl
+ def _post_zeep(self, wsdl, metodo, *args, wcf_compatibility=True):
+ """
+ Comunicação wsdl utilizando a biblioteca zeep (GINFES compatível)
+
+ Ex:
+ _post_zeep(
+ wsdl,
+ "ConsultarNfseV3",
+ cabecalho_xml,
+ xml_consulta
+ )
+ """
try:
+ import requests
from zeep import Client
from zeep.helpers import serialize_object
from zeep.settings import Settings
from zeep.transports import Transport
-
+
session = requests.Session()
-
- transport = Transport(session=session, timeout=60)
+ session.verify = False
+
+ # certificado A1
+ if self.certificado:
+ certificadoA1 = CertificadoA1(self.certificado)
+ chave, cert = certificadoA1.separar_arquivo(self.certificado_senha, caminho=True)
+ session.cert = (cert, chave)
+
+ transport = Transport(
+ session=session,
+ timeout=60
+ )
settings = Settings(
- strict=not wcf_compatibility, xml_huge_tree=True # IMPORTANTÍSSIMO p/ WCF
+ strict=not wcf_compatibility,
+ xml_huge_tree=True
)
- client = Client(wsdl=wsdl, transport=transport, settings=settings)
- if hasattr(client.service, metodo):
- service = getattr(client.service, metodo)
- return serialize_object(service(payload))
- else:
- raise Exception("Método não implementado no autorizador.")
- except Exception as e:
- raise e
+ client = Client(
+ wsdl=wsdl,
+ transport=transport,
+ settings=settings
+ )
+
+ # DEBUG ÚTIL
+ print("SOAP endpoint:", client.service._binding_options["address"])
+
+ if not hasattr(client.service, metodo):
+ raise Exception(f"Método {metodo} não existe no WSDL")
+
+ service = getattr(client.service, metodo)
+
+ # chama com N parâmetros (GINFES usa 2)
+ response = service(*args)
+
+ # GINFES retorna string XML
+ return serialize_object(response)
+
+ finally:
+ certificadoA1.excluir()
class ComunicacaoMDFe(Comunicacao):
diff --git a/pynfe/utils/webservices.py b/pynfe/utils/webservices.py
index 0c79fe17..c1294151 100644
--- a/pynfe/utils/webservices.py
+++ b/pynfe/utils/webservices.py
@@ -511,6 +511,7 @@
"CANCELAR": "Cancelar",
"CANCELAR_LOTE": "CancelarNotaLote",
"CONSULTA": "Consultar",
+ "CONSULTA_COMPLETA": "ConsultarNotaCompleta",
"HTTPS": "https://nfe.osasco.sp.gov.br/EISSNFEWebServices/NotaFiscalEletronica.svc?wsdl",
"HOMOLOGACAO": (
"https://nfe.osasco.sp.gov.br/EISSNFEWebServices/NotaFiscalEletronica.svc?wsdl"
From 41a3131367f6d1258e3109db12d37c38e2d02b70 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 29 Dec 2025 18:37:47 -0300
Subject: [PATCH 079/175] =?UTF-8?q?adiciona=20logs=20de=20depura=C3=A7?=
=?UTF-8?q?=C3=A3o=20para=20o=20m=C3=A9todo=20de=20comunica=C3=A7=C3=A3o?=
=?UTF-8?q?=20da=20NFS-e?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index e300f592..68df9d9e 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -1194,10 +1194,14 @@ def _post_zeep(self, wsdl, metodo, *args, wcf_compatibility=True):
# DEBUG ÚTIL
print("SOAP endpoint:", client.service._binding_options["address"])
-
+
+
if not hasattr(client.service, metodo):
raise Exception(f"Método {metodo} não existe no WSDL")
-
+
+ print("Chamando método:", metodo)
+ print("Parâmetros:", args)
+
service = getattr(client.service, metodo)
# chama com N parâmetros (GINFES usa 2)
From 3917d178a3f04d1ca3d56388116f3484c9118282 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 29 Dec 2025 18:46:11 -0300
Subject: [PATCH 080/175] =?UTF-8?q?remove=20cabe=C3=A7alho=20XML=20desnece?=
=?UTF-8?q?ss=C3=A1rio=20e=20logs=20de=20depura=C3=A7=C3=A3o=20na=20classe?=
=?UTF-8?q?=20ComunicacaoNfse?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 7 -------
1 file changed, 7 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 68df9d9e..6940d0d5 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -776,7 +776,6 @@ def consultar(self, xml):
if self.autorizador == "GINFES":
cabecalho = self._cabecalho_ginfes()
- xml = '' + xml
# comunica via wsdl
return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA"],cabecalho, xml)
@@ -794,7 +793,6 @@ def consultar_rps(self, xml):
return self._post(url, xml, "consultaRps")
elif self.autorizador == "GINFES":
cabecalho = self._cabecalho_ginfes()
- xml = '' + xml
return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA_RPS"],cabecalho, xml)
elif self.autorizador == "OSASCO":
# comunica via wsdl
@@ -948,8 +946,6 @@ def _post_https(self, url, xml, metodo):
wsdl = url # ?wsdl
endpoint = url.replace("?wsdl", "") # REMOVE ?wsdl
- print("WSDL:", wsdl)
- print("ENDPOINT:", endpoint)
cliente = Client(
wsdl,
@@ -964,9 +960,6 @@ def _post_https(self, url, xml, metodo):
elif metodo == "enviar_lote":
return cliente.service.RecepcionarLoteRpsV3(cabecalho, xml)
elif metodo == "consulta":
- print("URL:", url)
- print("Cabecalho:", cabecalho)
- print("XML:", xml)
return cliente.service.ConsultarNfseV3(cabecalho, xml)
elif metodo == "consulta_lote":
return cliente.service.ConsultarLoteRpsV3(cabecalho, xml)
From 5e6a2d99ec000e05a904f061c7ebab543bb068ce Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 29 Dec 2025 18:51:27 -0300
Subject: [PATCH 081/175] =?UTF-8?q?adiciona=20codifica=C3=A7=C3=A3o=20UTF-?=
=?UTF-8?q?8=20nas=20chamadas=20de=20toxml=20para=20serializa=C3=A7=C3=A3o?=
=?UTF-8?q?=20de=20NFS-e?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 24 ++++++++++++------------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index 4bf16c76..e96c168a 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -102,7 +102,7 @@ def gerar(self, nfse):
gnfse.Rps = declaracao_servico
gnfse = (
- gnfse.toxml(element_name="GerarNfseEnvio")
+ gnfse.toxml(encoding="utf-8", element_name="GerarNfseEnvio")
.replace("ns1:", "")
.replace(":ns1", "")
.replace('', "")
@@ -130,7 +130,7 @@ def consultar_rps(self, nfse):
consulta.Prestador = id_prestador
consulta = (
- consulta.toxml(element_name="ConsultarNfseRpsEnvio")
+ consulta.toxml(encoding="utf-8", element_name="ConsultarNfseRpsEnvio")
.replace("ns1:", "")
.replace(":ns1", "")
.replace('', "")
@@ -156,7 +156,7 @@ def consultar_faixa(self, emitente, inicio, fim, pagina):
consulta.Faixa.NumeroNfseFinal = fim
consulta = (
- consulta.toxml(element_name="ConsultarNfseFaixaEnvio")
+ consulta.toxml(encoding="utf-8", element_name="ConsultarNfseFaixaEnvio")
.replace("ns1:", "")
.replace(":ns1", "")
.replace('', "")
@@ -189,7 +189,7 @@ def cancelar(self, nfse):
cancelar = nfse_schema.CancelarNfseEnvio()
cancelar.Pedido = pedido
- return cancelar.toxml(element_name="CancelarNfseEnvio")
+ return cancelar.toxml(encoding="utf-8", element_name="CancelarNfseEnvio")
def serializar_lote_sincrono(self, nfse):
"""Retorna string de um XML gerado a partir do
@@ -268,7 +268,7 @@ def serializar_lote_sincrono(self, nfse):
gnfse = nfse_schema.EnviarLoteRpsSincronoEnvio()
gnfse.LoteRps = lote
- return gnfse.toxml(element_name="EnviarLoteRpsSincronoEnvio")
+ return gnfse.toxml(encoding="utf-8", element_name="EnviarLoteRpsSincronoEnvio")
class SerializacaoGinfes(InterfaceAutorizador):
@@ -321,7 +321,7 @@ def consultar_rps(self, emitente, numero, serie, tipo):
consulta.IdentificacaoRps = id_rps
consulta.Prestador = id_prestador
- return consulta.toxml(element_name="ns1:ConsultarNfseRpsEnvio")
+ return consulta.toxml(encoding="utf-8", element_name="ns1:ConsultarNfseRpsEnvio")
def consultar_nfse(self, emitente, numero=None, inicio=None, fim=None):
# Prestador
@@ -340,7 +340,7 @@ def consultar_nfse(self, emitente, numero=None, inicio=None, fim=None):
consulta.PeriodoEmissao.DataInicial = inicio
consulta.PeriodoEmissao.DataFinal = fim
- return consulta.toxml(element_name="ns1:ConsultarNfseEnvio")
+ return consulta.toxml(encoding="utf-8", element_name="ns1:ConsultarNfseEnvio" )
def consultar_lote(self, emitente, numero):
# Prestador
@@ -352,7 +352,7 @@ def consultar_lote(self, emitente, numero):
consulta.Prestador = id_prestador
consulta.Protocolo = str(numero)
- return consulta.toxml(element_name="ns1:ConsultarLoteRpsEnvio")
+ return consulta.toxml(encoding="utf-8", element_name="ns1:ConsultarLoteRpsEnvio")
def consultar_situacao_lote(self, emitente, numero):
"Serializa lote de envio, baseado no servico_consultar_situacao_lote_rps_envio_v03.xsd"
@@ -365,7 +365,7 @@ def consultar_situacao_lote(self, emitente, numero):
consulta.Prestador = id_prestador
consulta.Protocolo = str(numero)
- return consulta.toxml(element_name="ns1:ConsultarSituacaoLoteRpsEnvio")
+ return consulta.toxml(encoding="utf-8", element_name="ns1:ConsultarSituacaoLoteRpsEnvio")
def serializar_lote_assincrono(self, nfse):
"Serializa lote de envio, baseado no servico_enviar_lote_rps_envio_v03.xsd"
@@ -504,7 +504,7 @@ def serializar_lote_assincrono(self, nfse):
enviarLote = servico_enviar_lote_rps_envio_v03.EnviarLoteRpsEnvio()
enviarLote.LoteRps = lote
- return enviarLote.toxml(element_name="ns1:EnviarLoteRpsEnvio")
+ return enviarLote.toxml(encoding="utf-8", element_name="ns1:EnviarLoteRpsEnvio")
def cancelar(self, nfse, codigo):
"""Retorna string de um XML gerado a partir do
@@ -530,7 +530,7 @@ def cancelar(self, nfse, codigo):
cancelar = servico_cancelar_nfse_envio_v03.CancelarNfseEnvio()
cancelar.Pedido = pedido
- return cancelar.toxml(element_name="ns1:CancelarNfseEnvio")
+ return cancelar.toxml(encoding="utf-8", element_name="ns1:CancelarNfseEnvio")
def cancelar_v2(self, nfse):
# serialização utilizando lxml
@@ -552,4 +552,4 @@ def cabecalho(self):
cabecalho = cabecalho_v03.cabecalho()
cabecalho.versao = "3"
cabecalho.versaoDados = "3"
- return cabecalho.toxml(element_name="ns2:cabecalho")
+ return cabecalho.toxml(encoding="utf-8", element_name="ns2:cabecalho")
From 0f420dc38b21cda344b05a32b922753d736dac94 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 29 Dec 2025 18:56:59 -0300
Subject: [PATCH 082/175] =?UTF-8?q?adiciona=20cabe=C3=A7alho=20e=20corpo?=
=?UTF-8?q?=20XML=20para=20consulta=20de=20NFS-e=20no=20m=C3=A9todo=20de?=
=?UTF-8?q?=20comunica=C3=A7=C3=A3o=20da=20classe=20ComunicacaoNfse?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 25 ++++++++++++++++++++++++-
1 file changed, 24 insertions(+), 1 deletion(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 6940d0d5..e5f7b0cf 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -775,7 +775,30 @@ def consultar(self, xml):
url = self._get_url()
if self.autorizador == "GINFES":
- cabecalho = self._cabecalho_ginfes()
+ cabecalho = """
+
+ 3
+
+ """.strip()
+
+ xml = """
+
+
+
+ 13743550000819
+ 4073347
+
+
+
+ 2024-01-01
+ 2024-01-31
+
+
+
+ """.strip()
+
# comunica via wsdl
return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA"],cabecalho, xml)
From 1c3a33c7664302e16c527aef9345a9f41e87b99e Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 29 Dec 2025 19:04:04 -0300
Subject: [PATCH 083/175] =?UTF-8?q?substitui=20cabe=C3=A7alho=20e=20corpo?=
=?UTF-8?q?=20XML=20fixos=20por=20m=C3=A9todo=20para=20gera=C3=A7=C3=A3o?=
=?UTF-8?q?=20do=20cabe=C3=A7alho=20na=20classe=20ComunicacaoNfse?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 25 +------------------------
1 file changed, 1 insertion(+), 24 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index e5f7b0cf..6940d0d5 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -775,30 +775,7 @@ def consultar(self, xml):
url = self._get_url()
if self.autorizador == "GINFES":
- cabecalho = """
-
- 3
-
- """.strip()
-
- xml = """
-
-
-
- 13743550000819
- 4073347
-
-
-
- 2024-01-01
- 2024-01-31
-
-
-
- """.strip()
-
+ cabecalho = self._cabecalho_ginfes()
# comunica via wsdl
return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA"],cabecalho, xml)
From 5f4a642691f711634baaec6a6570454ae0386d08 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 29 Dec 2025 22:21:51 -0300
Subject: [PATCH 084/175] =?UTF-8?q?adiciona=20namespace=20ao=20cabe=C3=A7a?=
=?UTF-8?q?lho=20XML=20na=20serializa=C3=A7=C3=A3o=20da=20classe=20Seriali?=
=?UTF-8?q?zacaoGinfes?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index e96c168a..42771e91 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -552,4 +552,8 @@ def cabecalho(self):
cabecalho = cabecalho_v03.cabecalho()
cabecalho.versao = "3"
cabecalho.versaoDados = "3"
- return cabecalho.toxml(encoding="utf-8", element_name="ns2:cabecalho")
+ return cabecalho.toxml(
+ encoding="utf-8",
+ element_name="cabecalho",
+ namespace="http://www.ginfes.com.br/tipos_v03.xsd"
+ )
From 98b1a0fb734c679743f2505d6f6c3c701338a909 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 29 Dec 2025 22:25:45 -0300
Subject: [PATCH 085/175] =?UTF-8?q?remove=20namespace=20do=20cabe=C3=A7alh?=
=?UTF-8?q?o=20XML=20na=20serializa=C3=A7=C3=A3o=20da=20classe=20Serializa?=
=?UTF-8?q?caoGinfes?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index 42771e91..0e43d9a7 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -554,6 +554,5 @@ def cabecalho(self):
cabecalho.versaoDados = "3"
return cabecalho.toxml(
encoding="utf-8",
- element_name="cabecalho",
- namespace="http://www.ginfes.com.br/tipos_v03.xsd"
+ element_name="cabecalho"
)
From d4524462cc9e3f11282ab48e4f5b5e3308cc9092 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 29 Dec 2025 22:33:34 -0300
Subject: [PATCH 086/175] =?UTF-8?q?remove=20verifica=C3=A7=C3=A3o=20desnec?=
=?UTF-8?q?ess=C3=A1ria=20ao=20buscar=20refer=C3=AAncia=20no=20m=C3=A9todo?=
=?UTF-8?q?=20assinar=20da=20classe=20AssinaturaA1=20e=20adiciona=20gera?=
=?UTF-8?q?=C3=A7=C3=A3o=20de=20UUID=20na=20consulta=20de=20NFS-e=20na=20c?=
=?UTF-8?q?lasse=20SerializacaoGinfes?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/assinatura.py | 2 +-
pynfe/processamento/autorizador_nfse.py | 4 +++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/pynfe/processamento/assinatura.py b/pynfe/processamento/assinatura.py
index b057078d..50c5e263 100644
--- a/pynfe/processamento/assinatura.py
+++ b/pynfe/processamento/assinatura.py
@@ -29,7 +29,7 @@ def __init__(self, certificado, senha):
def assinar(self, xml: etree._Element, retorna_string=False) -> Union[str, etree._Element]:
# busca tag que tem id(reference_uri), logo nao importa se tem namespace
- reference = xml.find(".//*[@Id]").attrib["Id"] if xml.find(".//*[@Id]") is not None else None
+ reference = xml.find(".//*[@Id]").attrib["Id"]
# retira acentos
xml_str = remover_acentos(etree.tostring(xml, encoding="unicode", pretty_print=False))
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index 0e43d9a7..ac083e0d 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -1,6 +1,6 @@
from pyxb import BIND
from importlib import import_module
-
+import uuid
class InterfaceAutorizador:
# TODO Colocar raise Exception Not Implemented nos metodos
@@ -331,6 +331,8 @@ def consultar_nfse(self, emitente, numero=None, inicio=None, fim=None):
consulta = servico_consultar_nfse_envio_v03.ConsultarNfseEnvio()
consulta.Prestador = id_prestador
+
+ consulta.Id = str(uuid.uuid4())
# Consulta por Numero
if numero is not None:
consulta.NumeroNfse = numero
From bcc4c4d6c7678b77bef4a7d8ec399a142461c7cb Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 29 Dec 2025 22:43:29 -0300
Subject: [PATCH 087/175] =?UTF-8?q?adiciona=20atributo=20Id=20na=20classe?=
=?UTF-8?q?=20CTD=5FANON=20e=20ajusta=20a=20gera=C3=A7=C3=A3o=20do=20XML?=
=?UTF-8?q?=20na=20classe=20SerializacaoGinfes?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 5 ++---
.../nfse/ginfes/servico_consultar_nfse_envio_v03.py | 10 ++++++++++
2 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index ac083e0d..391e6d93 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -331,8 +331,7 @@ def consultar_nfse(self, emitente, numero=None, inicio=None, fim=None):
consulta = servico_consultar_nfse_envio_v03.ConsultarNfseEnvio()
consulta.Prestador = id_prestador
-
- consulta.Id = str(uuid.uuid4())
+ consulta.Id = str(uuid.uuid4())
# Consulta por Numero
if numero is not None:
consulta.NumeroNfse = numero
@@ -342,7 +341,7 @@ def consultar_nfse(self, emitente, numero=None, inicio=None, fim=None):
consulta.PeriodoEmissao.DataInicial = inicio
consulta.PeriodoEmissao.DataFinal = fim
- return consulta.toxml(encoding="utf-8", element_name="ns1:ConsultarNfseEnvio" )
+ return consulta.toxml(encoding="utf-8", element_name="ConsultarNfseEnvio" )
def consultar_lote(self, emitente, numero):
# Prestador
diff --git a/pynfe/utils/nfse/ginfes/servico_consultar_nfse_envio_v03.py b/pynfe/utils/nfse/ginfes/servico_consultar_nfse_envio_v03.py
index 06e1d8fb..517a04dc 100644
--- a/pynfe/utils/nfse/ginfes/servico_consultar_nfse_envio_v03.py
+++ b/pynfe/utils/nfse/ginfes/servico_consultar_nfse_envio_v03.py
@@ -233,7 +233,17 @@ class CTD_ANON_(pyxb.binding.basis.complexTypeDefinition):
"/workspaces/PyNFe/pynfe/data/XSDs/NFS-e/Ginfes/servico_consultar_nfse_envio_v03.xsd", 12, 5
)
_ElementMap = {}
+ __Id = pyxb.binding.content.AttributeUse(
+ pyxb.namespace.ExpandedName(None, "Id"),
+ "Id",
+ "__httpwww_ginfes_com_brservico_consultar_nfse_envio_v03_xsd_CTD_ANON_Id",
+ pyxb.binding.datatypes.ID,
+ required=False,
+ )
+
+ Id = property(__Id.value, __Id.set, None, None)
_AttributeMap = {}
+ _AttributeMap.update({__Id.name(): __Id})
# Base type is pyxb.binding.datatypes.anyType
# Element {http://www.ginfes.com.br/servico_consultar_nfse_envio_v03.xsd}DataInicial uses Python identifier DataInicial
From 5878e0afbe136e483003c04c3e7f9b30f8c0c2af Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 29 Dec 2025 22:47:16 -0300
Subject: [PATCH 088/175] =?UTF-8?q?substitui=20busca=20de=20atributo=20Id?=
=?UTF-8?q?=20na=20classe=20AssinaturaA1=20para=20uso=20de=20xpath=20e=20a?=
=?UTF-8?q?justa=20formata=C3=A7=C3=A3o=20do=20retorno=20na=20classe=20Ser?=
=?UTF-8?q?ializacaoOsasco?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/assinatura.py | 2 +-
pynfe/processamento/autorizador_nfse.py | 60 +++++++++++++++----------
2 files changed, 37 insertions(+), 25 deletions(-)
diff --git a/pynfe/processamento/assinatura.py b/pynfe/processamento/assinatura.py
index 50c5e263..70b3b856 100644
--- a/pynfe/processamento/assinatura.py
+++ b/pynfe/processamento/assinatura.py
@@ -29,7 +29,7 @@ def __init__(self, certificado, senha):
def assinar(self, xml: etree._Element, retorna_string=False) -> Union[str, etree._Element]:
# busca tag que tem id(reference_uri), logo nao importa se tem namespace
- reference = xml.find(".//*[@Id]").attrib["Id"]
+ reference = xml.xpath('//*[@Id]')[0].attrib['Id']
# retira acentos
xml_str = remover_acentos(etree.tostring(xml, encoding="unicode", pretty_print=False))
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index 391e6d93..2ae6c978 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -1,6 +1,8 @@
-from pyxb import BIND
-from importlib import import_module
import uuid
+from importlib import import_module
+
+from pyxb import BIND
+
class InterfaceAutorizador:
# TODO Colocar raise Exception Not Implemented nos metodos
@@ -10,23 +12,36 @@ def consultar_rps(self):
def cancelar(self):
pass
+
class SerializacaoOsasco:
def __init__(self, chave_autenticacao):
self.chave_autenticacao = chave_autenticacao
-
- def consultar(self, cnpj_tomador=None, cpf_tomador=None, data_inicial=None, data_final=None, numero_nota_inicial=None, numero_nota_final=None, numero_rps_inicial=None, numero_rps_final=None, numero_rps_unico=None):
+
+ def consultar(
+ self,
+ cnpj_tomador=None,
+ cpf_tomador=None,
+ data_inicial=None,
+ data_final=None,
+ numero_nota_inicial=None,
+ numero_nota_final=None,
+ numero_rps_inicial=None,
+ numero_rps_final=None,
+ numero_rps_unico=None,
+ ):
return {
- "ChaveAutenticacao": self.chave_autenticacao,
- "CNPJTomador": cnpj_tomador,
- "CPFTomador": cpf_tomador,
- "DataInicial": data_inicial,
- "DataFinal": data_final,
- "NumeroNotaInicial": numero_nota_inicial,
- "NumeroNotaFinal": numero_nota_final,
- "NumeroReciboInicial": numero_rps_inicial,
- "NumeroReciboFinal": numero_rps_final,
- "NumeroReciboUnico": numero_rps_unico,
- }
+ "ChaveAutenticacao": self.chave_autenticacao,
+ "CNPJTomador": cnpj_tomador,
+ "CPFTomador": cpf_tomador,
+ "DataInicial": data_inicial,
+ "DataFinal": data_final,
+ "NumeroNotaInicial": numero_nota_inicial,
+ "NumeroNotaFinal": numero_nota_final,
+ "NumeroReciboInicial": numero_rps_inicial,
+ "NumeroReciboFinal": numero_rps_final,
+ "NumeroReciboUnico": numero_rps_unico,
+ }
+
class SerializacaoBetha(InterfaceAutorizador):
def __init__(self):
@@ -340,8 +355,8 @@ def consultar_nfse(self, emitente, numero=None, inicio=None, fim=None):
consulta.PeriodoEmissao = BIND()
consulta.PeriodoEmissao.DataInicial = inicio
consulta.PeriodoEmissao.DataFinal = fim
-
- return consulta.toxml(encoding="utf-8", element_name="ConsultarNfseEnvio" )
+ print("ID no objeto:", consulta.Id)
+ return consulta.toxml(encoding="utf-8", element_name="ns1:ConsultarNfseEnvio")
def consultar_lote(self, emitente, numero):
# Prestador
@@ -542,9 +557,9 @@ def cancelar_v2(self, nfse):
raiz = etree.Element("{%s}CancelarNfseEnvio" % ns1, nsmap={"ns1": ns1, "ns2": ns2})
prestador = etree.SubElement(raiz, "{%s}Prestador" % ns1)
etree.SubElement(prestador, "{%s}Cnpj" % ns2).text = nfse.emitente.cnpj
- etree.SubElement(
- prestador, "{%s}InscricaoMunicipal" % ns2
- ).text = nfse.emitente.inscricao_municipal
+ etree.SubElement(prestador, "{%s}InscricaoMunicipal" % ns2).text = (
+ nfse.emitente.inscricao_municipal
+ )
etree.SubElement(raiz, "{%s}NumeroNfse" % ns1).text = nfse.identificador
return etree.tostring(raiz, encoding="unicode")
@@ -553,7 +568,4 @@ def cabecalho(self):
cabecalho = cabecalho_v03.cabecalho()
cabecalho.versao = "3"
cabecalho.versaoDados = "3"
- return cabecalho.toxml(
- encoding="utf-8",
- element_name="cabecalho"
- )
+ return cabecalho.toxml(encoding="utf-8", element_name="cabecalho")
From f621a9c5ba974424f7b6d543f93d0085867f5bec Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 29 Dec 2025 22:48:04 -0300
Subject: [PATCH 089/175] =?UTF-8?q?remove=20o=20nome=20do=20elemento=20no?=
=?UTF-8?q?=20retorno=20da=20serializa=C3=A7=C3=A3o=20na=20classe=20Serial?=
=?UTF-8?q?izacaoGinfes?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index 2ae6c978..a14141cd 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -356,7 +356,7 @@ def consultar_nfse(self, emitente, numero=None, inicio=None, fim=None):
consulta.PeriodoEmissao.DataInicial = inicio
consulta.PeriodoEmissao.DataFinal = fim
print("ID no objeto:", consulta.Id)
- return consulta.toxml(encoding="utf-8", element_name="ns1:ConsultarNfseEnvio")
+ return consulta.toxml(encoding="utf-8")
def consultar_lote(self, emitente, numero):
# Prestador
From f5ea5a4e451d9ebdb4988622e7846c8fa3509959 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 29 Dec 2025 22:50:09 -0300
Subject: [PATCH 090/175] adiciona atributo Id no elemento ConsultarNfseEnvio
para suporte a XMLDSig
---
.../nfse/ginfes/servico_consultar_nfse_envio_v03.py | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/pynfe/utils/nfse/ginfes/servico_consultar_nfse_envio_v03.py b/pynfe/utils/nfse/ginfes/servico_consultar_nfse_envio_v03.py
index 517a04dc..395166e7 100644
--- a/pynfe/utils/nfse/ginfes/servico_consultar_nfse_envio_v03.py
+++ b/pynfe/utils/nfse/ginfes/servico_consultar_nfse_envio_v03.py
@@ -293,7 +293,18 @@ class CTD_ANON_(pyxb.binding.basis.complexTypeDefinition):
Namespace.addCategoryObject(
"elementBinding", ConsultarNfseEnvio.name().localName(), ConsultarNfseEnvio
)
+# === Atributo Id no ELEMENTO (obrigatório para XMLDSig) ===
+ConsultarNfseEnvio._AttributeMap = getattr(ConsultarNfseEnvio, "_AttributeMap", {})
+
+__Id = pyxb.binding.content.AttributeUse(
+ pyxb.namespace.ExpandedName(None, "Id"),
+ "Id",
+ "__httpwww_ginfes_com_brservico_consultar_nfse_envio_v03_xsd_ConsultarNfseEnvio_Id",
+ pyxb.binding.datatypes.ID,
+ required=False,
+)
+ConsultarNfseEnvio._AttributeMap.update({__Id.name(): __Id})
CTD_ANON._AddElement(
pyxb.binding.basis.element(
From 1a3f63cf97d44d4f9f2bbb66a1f7d641dfe2652d Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 29 Dec 2025 22:52:14 -0300
Subject: [PATCH 091/175] =?UTF-8?q?adiciona=20gera=C3=A7=C3=A3o=20de=20UUI?=
=?UTF-8?q?D=20no=20construtor=20de=20ConsultarNfseEnvio=20na=20classe=20S?=
=?UTF-8?q?erializacaoGinfes?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index a14141cd..1d731d32 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -344,9 +344,8 @@ def consultar_nfse(self, emitente, numero=None, inicio=None, fim=None):
id_prestador.Cnpj = emitente.cnpj
id_prestador.InscricaoMunicipal = emitente.inscricao_municipal
- consulta = servico_consultar_nfse_envio_v03.ConsultarNfseEnvio()
+ consulta = servico_consultar_nfse_envio_v03.ConsultarNfseEnvio(Id=str(uuid.uuid4()))
consulta.Prestador = id_prestador
- consulta.Id = str(uuid.uuid4())
# Consulta por Numero
if numero is not None:
consulta.NumeroNfse = numero
From 93f98c9ede9b2a0fa1548b80760c8e9d0610fb90 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 29 Dec 2025 22:55:28 -0300
Subject: [PATCH 092/175] =?UTF-8?q?ajusta=20a=20gera=C3=A7=C3=A3o=20do=20X?=
=?UTF-8?q?ML=20na=20classe=20SerializacaoGinfes=20para=20incluir=20atribu?=
=?UTF-8?q?to=20Id=20com=20valor=20=C3=BAnico?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 16 +++++++++++---
.../servico_consultar_nfse_envio_v03.py | 21 -------------------
2 files changed, 13 insertions(+), 24 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index 1d731d32..30548982 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -1,6 +1,6 @@
import uuid
from importlib import import_module
-
+from lxml import etree
from pyxb import BIND
@@ -344,7 +344,7 @@ def consultar_nfse(self, emitente, numero=None, inicio=None, fim=None):
id_prestador.Cnpj = emitente.cnpj
id_prestador.InscricaoMunicipal = emitente.inscricao_municipal
- consulta = servico_consultar_nfse_envio_v03.ConsultarNfseEnvio(Id=str(uuid.uuid4()))
+ consulta = servico_consultar_nfse_envio_v03.ConsultarNfseEnvio()
consulta.Prestador = id_prestador
# Consulta por Numero
if numero is not None:
@@ -355,7 +355,17 @@ def consultar_nfse(self, emitente, numero=None, inicio=None, fim=None):
consulta.PeriodoEmissao.DataInicial = inicio
consulta.PeriodoEmissao.DataFinal = fim
print("ID no objeto:", consulta.Id)
- return consulta.toxml(encoding="utf-8")
+
+ xml = consulta.toxml(encoding="utf-8", element_name="ns1:ConsultarNfseEnvio")
+ root = etree.fromstring(xml)
+ root.attrib["Id"] = f"CNFSE{uuid.uuid4().hex.upper()}"
+
+ xml = etree.tostring(
+ root,
+ encoding="utf-8",
+ xml_declaration=True
+ )
+ return xml
def consultar_lote(self, emitente, numero):
# Prestador
diff --git a/pynfe/utils/nfse/ginfes/servico_consultar_nfse_envio_v03.py b/pynfe/utils/nfse/ginfes/servico_consultar_nfse_envio_v03.py
index 395166e7..06e1d8fb 100644
--- a/pynfe/utils/nfse/ginfes/servico_consultar_nfse_envio_v03.py
+++ b/pynfe/utils/nfse/ginfes/servico_consultar_nfse_envio_v03.py
@@ -233,17 +233,7 @@ class CTD_ANON_(pyxb.binding.basis.complexTypeDefinition):
"/workspaces/PyNFe/pynfe/data/XSDs/NFS-e/Ginfes/servico_consultar_nfse_envio_v03.xsd", 12, 5
)
_ElementMap = {}
- __Id = pyxb.binding.content.AttributeUse(
- pyxb.namespace.ExpandedName(None, "Id"),
- "Id",
- "__httpwww_ginfes_com_brservico_consultar_nfse_envio_v03_xsd_CTD_ANON_Id",
- pyxb.binding.datatypes.ID,
- required=False,
- )
-
- Id = property(__Id.value, __Id.set, None, None)
_AttributeMap = {}
- _AttributeMap.update({__Id.name(): __Id})
# Base type is pyxb.binding.datatypes.anyType
# Element {http://www.ginfes.com.br/servico_consultar_nfse_envio_v03.xsd}DataInicial uses Python identifier DataInicial
@@ -293,18 +283,7 @@ class CTD_ANON_(pyxb.binding.basis.complexTypeDefinition):
Namespace.addCategoryObject(
"elementBinding", ConsultarNfseEnvio.name().localName(), ConsultarNfseEnvio
)
-# === Atributo Id no ELEMENTO (obrigatório para XMLDSig) ===
-ConsultarNfseEnvio._AttributeMap = getattr(ConsultarNfseEnvio, "_AttributeMap", {})
-
-__Id = pyxb.binding.content.AttributeUse(
- pyxb.namespace.ExpandedName(None, "Id"),
- "Id",
- "__httpwww_ginfes_com_brservico_consultar_nfse_envio_v03_xsd_ConsultarNfseEnvio_Id",
- pyxb.binding.datatypes.ID,
- required=False,
-)
-ConsultarNfseEnvio._AttributeMap.update({__Id.name(): __Id})
CTD_ANON._AddElement(
pyxb.binding.basis.element(
From af265ba675cdf1a9c600bc68ad2f90228db63e65 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 29 Dec 2025 22:55:56 -0300
Subject: [PATCH 093/175] adiciona atributo Id com UUID no elemento
ConsultarNfseEnvio na classe SerializacaoGinfes
---
pynfe/processamento/autorizador_nfse.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index 30548982..2ee72c7f 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -354,8 +354,7 @@ def consultar_nfse(self, emitente, numero=None, inicio=None, fim=None):
consulta.PeriodoEmissao = BIND()
consulta.PeriodoEmissao.DataInicial = inicio
consulta.PeriodoEmissao.DataFinal = fim
- print("ID no objeto:", consulta.Id)
-
+
xml = consulta.toxml(encoding="utf-8", element_name="ns1:ConsultarNfseEnvio")
root = etree.fromstring(xml)
root.attrib["Id"] = f"CNFSE{uuid.uuid4().hex.upper()}"
From 7e4255c585223ef594cf6dde8213b6c805e28705 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 29 Dec 2025 23:08:40 -0300
Subject: [PATCH 094/175] =?UTF-8?q?adiciona=20m=C3=A9todo=20consultar=5Fnf?=
=?UTF-8?q?se=5Ffaixa=20na=20classe=20SerializacaoGinfes=20para=20consulta?=
=?UTF-8?q?=20de=20NFSe=20por=20faixa=20de=20n=C3=BAmeros?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 52 +++++++++++++++----------
1 file changed, 31 insertions(+), 21 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index 2ee72c7f..6e3ef94f 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -338,33 +338,43 @@ def consultar_rps(self, emitente, numero, serie, tipo):
return consulta.toxml(encoding="utf-8", element_name="ns1:ConsultarNfseRpsEnvio")
- def consultar_nfse(self, emitente, numero=None, inicio=None, fim=None):
+ def consultar_nfse_faixa(emitente, numero_inicial, numero_final, pagina=1):
+ NS = "http://www.ginfes.com.br/servico_consultar_nfse_faixa_envio_v03.xsd"
+ DS = "http://www.w3.org/2000/09/xmldsig#"
+
+ nsmap = {
+ None: NS,
+ "ds": DS
+ }
+
+ root = etree.Element(
+ f"{{{NS}}}ConsultarNfseFaixaEnvio",
+ nsmap=nsmap
+ )
+
+ # Id obrigatório (ANTES da assinatura)
+ root.attrib["Id"] = f"CNFSEFAIXA{uuid.uuid4().hex.upper()}"
+
# Prestador
- id_prestador = _tipos.tcIdentificacaoPrestador()
- id_prestador.Cnpj = emitente.cnpj
- id_prestador.InscricaoMunicipal = emitente.inscricao_municipal
+ prestador = etree.SubElement(root, f"{{{NS}}}Prestador")
+ cpf_cnpj = etree.SubElement(prestador, f"{{{NS}}}CpfCnpj")
+ etree.SubElement(cpf_cnpj, f"{{{NS}}}Cnpj").text = emitente.cnpj
+ etree.SubElement(prestador, f"{{{NS}}}InscricaoMunicipal").text = emitente.inscricao_municipal
- consulta = servico_consultar_nfse_envio_v03.ConsultarNfseEnvio()
- consulta.Prestador = id_prestador
- # Consulta por Numero
- if numero is not None:
- consulta.NumeroNfse = numero
- else:
- # consulta por Data
- consulta.PeriodoEmissao = BIND()
- consulta.PeriodoEmissao.DataInicial = inicio
- consulta.PeriodoEmissao.DataFinal = fim
-
- xml = consulta.toxml(encoding="utf-8", element_name="ns1:ConsultarNfseEnvio")
- root = etree.fromstring(xml)
- root.attrib["Id"] = f"CNFSE{uuid.uuid4().hex.upper()}"
-
- xml = etree.tostring(
+ # Faixa
+ faixa = etree.SubElement(root, f"{{{NS}}}Faixa")
+ etree.SubElement(faixa, f"{{{NS}}}NumeroNfseInicial").text = str(numero_inicial)
+ etree.SubElement(faixa, f"{{{NS}}}NumeroNfseFinal").text = str(numero_final)
+
+ # Página
+ etree.SubElement(root, f"{{{NS}}}Pagina").text = str(pagina)
+
+ return etree.tostring(
root,
encoding="utf-8",
xml_declaration=True
)
- return xml
+
def consultar_lote(self, emitente, numero):
# Prestador
From cdd9d4310499a266b4442f292e4558871b008ae8 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 29 Dec 2025 23:09:28 -0300
Subject: [PATCH 095/175] =?UTF-8?q?corrige=20assinatura=20do=20m=C3=A9todo?=
=?UTF-8?q?=20consultar=5Fnfse=5Ffaixa=20na=20classe=20SerializacaoGinfes?=
=?UTF-8?q?=20para=20incluir=20'self'?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index 6e3ef94f..993d15e9 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -338,7 +338,7 @@ def consultar_rps(self, emitente, numero, serie, tipo):
return consulta.toxml(encoding="utf-8", element_name="ns1:ConsultarNfseRpsEnvio")
- def consultar_nfse_faixa(emitente, numero_inicial, numero_final, pagina=1):
+ def consultar_nfse_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
NS = "http://www.ginfes.com.br/servico_consultar_nfse_faixa_envio_v03.xsd"
DS = "http://www.w3.org/2000/09/xmldsig#"
From 95dd8eb4da07282f40bef1412d01135fa6db27b2 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 29 Dec 2025 23:11:36 -0300
Subject: [PATCH 096/175] =?UTF-8?q?renomeia=20m=C3=A9todo=20consultar=5Fnf?=
=?UTF-8?q?se=20para=20consultar=5Ffaixa=20na=20classe=20SerializacaoGinfe?=
=?UTF-8?q?s=20e=20ajusta=20chamada=20na=20classe=20SerializacaoNfse?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 2 +-
pynfe/processamento/serializacao.py | 10 +++++-----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index 993d15e9..348faf15 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -338,7 +338,7 @@ def consultar_rps(self, emitente, numero, serie, tipo):
return consulta.toxml(encoding="utf-8", element_name="ns1:ConsultarNfseRpsEnvio")
- def consultar_nfse_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
+ def consultar_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
NS = "http://www.ginfes.com.br/servico_consultar_nfse_faixa_envio_v03.xsd"
DS = "http://www.w3.org/2000/09/xmldsig#"
diff --git a/pynfe/processamento/serializacao.py b/pynfe/processamento/serializacao.py
index bd7d7e4a..1d5f221f 100644
--- a/pynfe/processamento/serializacao.py
+++ b/pynfe/processamento/serializacao.py
@@ -2167,14 +2167,14 @@ def gerar_lote(self, nfse):
return SerializacaoGinfes().serializar_lote_assincrono(nfse)
else:
raise Exception("Este método só esta implementado no autorizador ginfes.")
-
- def consultar_nfse(self, emitente, numero=None, inicio=None, fim=None):
+
+ def consultar_faixa(self, cnpj_prestador, numero_nfse_inicial, numero_nfse_final):
if self.autorizador.lower() == "ginfes":
from pynfe.processamento.autorizador_nfse import SerializacaoGinfes
-
- return SerializacaoGinfes().consultar_nfse(emitente, numero, inicio, fim)
+
+ return SerializacaoGinfes().consultar_faixa(cnpj_prestador=cnpj_prestador, numero_nfse_inicial=numero_nfse_inicial, numero_nfse_final=numero_nfse_final)
else:
- raise Exception("Este método só esta implementado no autorizador ginfes.")
+ raise Exception("Este método só esta implementado no autorizador Osasco.")
def consultar_nota_emitida(self, cnpj_tomador=None, cpf_tomador=None, data_inicial=None, data_final=None, numero_nota_inicial=None, numero_nota_final=None, numero_rps_inicial=None, numero_rps_final=None):
if self.autorizador.lower() == "osasco":
From 5faa0f5e03b2c292684887256e0e85ddd11f8da0 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 29 Dec 2025 23:13:13 -0300
Subject: [PATCH 097/175] =?UTF-8?q?ajusta=20m=C3=A9todo=20consultar=5Ffaix?=
=?UTF-8?q?a=20na=20classe=20SerializacaoNfse=20para=20aceitar=20novos=20p?=
=?UTF-8?q?ar=C3=A2metros=20e=20atualizar=20chamada=20na=20classe=20Serial?=
=?UTF-8?q?izacaoGinfes?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/serializacao.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pynfe/processamento/serializacao.py b/pynfe/processamento/serializacao.py
index 1d5f221f..f9711636 100644
--- a/pynfe/processamento/serializacao.py
+++ b/pynfe/processamento/serializacao.py
@@ -2168,11 +2168,11 @@ def gerar_lote(self, nfse):
else:
raise Exception("Este método só esta implementado no autorizador ginfes.")
- def consultar_faixa(self, cnpj_prestador, numero_nfse_inicial, numero_nfse_final):
+ def consultar_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
if self.autorizador.lower() == "ginfes":
from pynfe.processamento.autorizador_nfse import SerializacaoGinfes
- return SerializacaoGinfes().consultar_faixa(cnpj_prestador=cnpj_prestador, numero_nfse_inicial=numero_nfse_inicial, numero_nfse_final=numero_nfse_final)
+ return SerializacaoGinfes().consultar_faixa(emitente, numero_inicial, numero_final, pagina=1)
else:
raise Exception("Este método só esta implementado no autorizador Osasco.")
From 096647cf81579ea1b2e6b9f9d267a040b8c752ab Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 29 Dec 2025 23:26:47 -0300
Subject: [PATCH 098/175] =?UTF-8?q?ajusta=20m=C3=A9todos=20de=20consulta?=
=?UTF-8?q?=20na=20classe=20SerializacaoGinfes=20para=20incluir=20novos=20?=
=?UTF-8?q?servi=C3=A7os=20e=20par=C3=A2metros?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 308 ++++--------------------
pynfe/processamento/comunicacao.py | 7 +-
pynfe/processamento/serializacao.py | 60 +----
pynfe/utils/webservices.py | 10 +-
4 files changed, 64 insertions(+), 321 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index 348faf15..90343ffa 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -1,5 +1,6 @@
import uuid
from importlib import import_module
+
from lxml import etree
from pyxb import BIND
@@ -288,69 +289,44 @@ def serializar_lote_sincrono(self, nfse):
class SerializacaoGinfes(InterfaceAutorizador):
def __init__(self):
- # importa
- global _tipos, servico_consultar_nfse_envio_v03
- global servico_enviar_lote_rps_envio_v03, cabecalho_v03
- global servico_cancelar_nfse_envio_v03
- global servico_consultar_lote_rps_envio_v03
- global servico_consultar_situacao_lote_rps_envio_v03
- global servico_consultar_nfse_rps_envio_v03
- _tipos = import_module("pynfe.utils.nfse.ginfes._tipos")
- servico_consultar_nfse_envio_v03 = import_module(
- "pynfe.utils.nfse.ginfes.servico_consultar_nfse_envio_v03"
- )
- servico_cancelar_nfse_envio_v03 = import_module(
- "pynfe.utils.nfse.ginfes.servico_cancelar_nfse_envio_v03"
- )
- servico_enviar_lote_rps_envio_v03 = import_module(
- "pynfe.utils.nfse.ginfes.servico_enviar_lote_rps_envio_v03"
- )
- cabecalho_v03 = import_module("pynfe.utils.nfse.ginfes.cabecalho_v03")
- servico_consultar_lote_rps_envio_v03 = import_module(
- "pynfe.utils.nfse.ginfes.servico_consultar_lote_rps_envio_v03"
- )
- servico_consultar_situacao_lote_rps_envio_v03 = import_module(
- "pynfe.utils.nfse.ginfes.servico_consultar_situacao_lote_rps_envio_v03"
- )
- servico_consultar_nfse_rps_envio_v03 = import_module(
- "pynfe.utils.nfse.ginfes.servico_consultar_nfse_rps_envio_v03"
- )
+ pass
+
+ def consultar_servico_prestado(self, emitente, data_inicio, data_fim, pagina=1):
+ NS = "http://www.ginfes.com.br/servico_consultar_nfse_servico_prestado_envio_v03.xsd"
+ DS = "http://www.w3.org/2000/09/xmldsig#"
- def consultar_rps(self, emitente, numero, serie, tipo):
- """Retorna string de um XML de consulta por Rps gerado a partir do
- XML Schema (XSD). Binding gerado pelo modulo PyXB.
- servico_consultar_nfse_rps_envio_v03.xsd
- """
- # Rps
- id_rps = _tipos.tcIdentificacaoRps()
- id_rps.Numero = numero
- id_rps.Serie = serie
- id_rps.Tipo = tipo
+ nsmap = {None: NS, "ds": DS}
+
+ root = etree.Element(f"{{{NS}}}ConsultarNfseServicoPrestadoEnvio", nsmap=nsmap)
+
+ # ID obrigatório (antes da assinatura)
+ root.attrib["Id"] = f"CNFSESP{uuid.uuid4().hex.upper()}"
# Prestador
- id_prestador = _tipos.tcIdentificacaoPrestador()
- id_prestador.Cnpj = emitente.cnpj
- id_prestador.InscricaoMunicipal = emitente.inscricao_municipal
+ prestador = etree.SubElement(root, f"{{{NS}}}Prestador")
+ cpf_cnpj = etree.SubElement(prestador, f"{{{NS}}}CpfCnpj")
+ etree.SubElement(cpf_cnpj, f"{{{NS}}}Cnpj").text = emitente.cnpj
+ etree.SubElement(prestador, f"{{{NS}}}InscricaoMunicipal").text = (
+ emitente.inscricao_municipal
+ )
- consulta = servico_consultar_nfse_rps_envio_v03.ConsultarNfseRpsEnvio()
- consulta.IdentificacaoRps = id_rps
- consulta.Prestador = id_prestador
+ # Período
+ periodo = etree.SubElement(root, f"{{{NS}}}PeriodoEmissao")
+ etree.SubElement(periodo, f"{{{NS}}}DataInicial").text = data_inicio
+ etree.SubElement(periodo, f"{{{NS}}}DataFinal").text = data_fim
+
+ # Página
+ etree.SubElement(root, f"{{{NS}}}Pagina").text = str(pagina)
- return consulta.toxml(encoding="utf-8", element_name="ns1:ConsultarNfseRpsEnvio")
+ return etree.tostring(root, encoding="utf-8", xml_declaration=True)
def consultar_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
NS = "http://www.ginfes.com.br/servico_consultar_nfse_faixa_envio_v03.xsd"
DS = "http://www.w3.org/2000/09/xmldsig#"
- nsmap = {
- None: NS,
- "ds": DS
- }
+ nsmap = {None: NS, "ds": DS}
- root = etree.Element(
- f"{{{NS}}}ConsultarNfseFaixaEnvio",
- nsmap=nsmap
- )
+ root = etree.Element(f"{{{NS}}}ConsultarNfseFaixaEnvio", nsmap=nsmap)
# Id obrigatório (ANTES da assinatura)
root.attrib["Id"] = f"CNFSEFAIXA{uuid.uuid4().hex.upper()}"
@@ -359,7 +335,9 @@ def consultar_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
prestador = etree.SubElement(root, f"{{{NS}}}Prestador")
cpf_cnpj = etree.SubElement(prestador, f"{{{NS}}}CpfCnpj")
etree.SubElement(cpf_cnpj, f"{{{NS}}}Cnpj").text = emitente.cnpj
- etree.SubElement(prestador, f"{{{NS}}}InscricaoMunicipal").text = emitente.inscricao_municipal
+ etree.SubElement(prestador, f"{{{NS}}}InscricaoMunicipal").text = (
+ emitente.inscricao_municipal
+ )
# Faixa
faixa = etree.SubElement(root, f"{{{NS}}}Faixa")
@@ -369,221 +347,17 @@ def consultar_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
# Página
etree.SubElement(root, f"{{{NS}}}Pagina").text = str(pagina)
- return etree.tostring(
- root,
- encoding="utf-8",
- xml_declaration=True
- )
-
-
- def consultar_lote(self, emitente, numero):
- # Prestador
- id_prestador = _tipos.tcIdentificacaoPrestador()
- id_prestador.Cnpj = emitente.cnpj
- id_prestador.InscricaoMunicipal = emitente.inscricao_municipal
-
- consulta = servico_consultar_lote_rps_envio_v03.ConsultarLoteRpsEnvio()
- consulta.Prestador = id_prestador
- consulta.Protocolo = str(numero)
-
- return consulta.toxml(encoding="utf-8", element_name="ns1:ConsultarLoteRpsEnvio")
+ return etree.tostring(root, encoding="utf-8", xml_declaration=True)
- def consultar_situacao_lote(self, emitente, numero):
- "Serializa lote de envio, baseado no servico_consultar_situacao_lote_rps_envio_v03.xsd"
- # Prestador
- id_prestador = _tipos.tcIdentificacaoPrestador()
- id_prestador.Cnpj = emitente.cnpj
- id_prestador.InscricaoMunicipal = emitente.inscricao_municipal
-
- consulta = servico_consultar_situacao_lote_rps_envio_v03.ConsultarSituacaoLoteRpsEnvio()
- consulta.Prestador = id_prestador
- consulta.Protocolo = str(numero)
-
- return consulta.toxml(encoding="utf-8", element_name="ns1:ConsultarSituacaoLoteRpsEnvio")
-
- def serializar_lote_assincrono(self, nfse):
- "Serializa lote de envio, baseado no servico_enviar_lote_rps_envio_v03.xsd"
-
- servico = _tipos.tcDadosServico()
- valores_servico = _tipos.tcValores()
- valores_servico.ValorServicos = nfse.servico.valor_servico
- # valores_servico.ValorServicos = str(Decimal(
- # nfse.servico.valor_servico.quantize(Decimal('.01'), rounding=ROUND_HALF_UP)))
- valores_servico.IssRetido = nfse.servico.iss_retido
- # Dados opcionais
- if nfse.servico.valor_deducoes:
- valores_servico.ValorDeducoes = nfse.servico.valor_deducoes
- if nfse.servico.valor_pis:
- valores_servico.ValorPis = nfse.servico.valor_pis
- if nfse.servico.valor_confins:
- valores_servico.ValorCofins = nfse.servico.valor_confins
- if nfse.servico.valor_inss:
- valores_servico.ValorInss = nfse.servico.valor_inss
- if nfse.servico.valor_ir:
- valores_servico.ValorIr = nfse.servico.valor_ir
- if nfse.servico.valor_csll:
- valores_servico.ValorCsll = nfse.servico.valor_csll
- if nfse.servico.valor_iss:
- valores_servico.ValorIss = nfse.servico.valor_iss
- if nfse.servico.valor_iss_retido:
- valores_servico.ValorIssRetido = nfse.servico.valor_iss_retido
- if nfse.servico.valor_liquido:
- valores_servico.ValorLiquidoNfse = nfse.servico.valor_liquido
- if nfse.servico.outras_retencoes:
- valores_servico.OutrasRetencoes = nfse.servico.outras_retencoes
- if nfse.servico.base_calculo:
- valores_servico.BaseCalculo = nfse.servico.base_calculo
- if nfse.servico.aliquota:
- valores_servico.Aliquota = nfse.servico.aliquota
- if nfse.servico.desconto_incondicionado:
- valores_servico.DescontoIncondicionado = nfse.servico.desconto_incondicionado
- if nfse.servico.desconto_condicionado:
- valores_servico.DescontoCondicionado = nfse.servico.desconto_condicionado
-
- servico.Valores = valores_servico
- servico.ItemListaServico = nfse.servico.item_lista
- # opcionais
- if nfse.servico.codigo_cnae:
- servico.CodigoCnae = nfse.servico.codigo_cnae
- if nfse.servico.codigo_tributacao_municipio:
- servico.CodigoTributacaoMunicipio = nfse.servico.codigo_tributacao_municipio
- # obrigatórios
- servico.Discriminacao = nfse.servico.discriminacao
- servico.CodigoMunicipio = nfse.servico.codigo_municipio
-
- # endereco tomador
- endereco_tomador = _tipos.tcEndereco()
- endereco_tomador.Endereco = nfse.cliente.endereco_logradouro
- if nfse.cliente.endereco_complemento:
- endereco_tomador.Complemento = nfse.cliente.endereco_complemento
- endereco_tomador.Numero = nfse.cliente.endereco_numero
- endereco_tomador.Bairro = nfse.cliente.endereco_bairro
- if nfse.cliente.endereco_cod_municipio:
- endereco_tomador.CodigoMunicipio = nfse.cliente.endereco_cod_municipio
- endereco_tomador.Uf = nfse.cliente.endereco_uf
- endereco_tomador.Cep = nfse.cliente.endereco_cep
- # identificacao Tomador
- id_tomador = _tipos.tcIdentificacaoTomador()
- id_tomador.CpfCnpj = nfse.cliente.numero_documento
- if nfse.cliente.inscricao_municipal:
- id_tomador.InscricaoMunicipal = nfse.cliente.inscricao_municipal
- # Tomador
- tomador = _tipos.tcDadosTomador()
- tomador.IdentificacaoTomador = id_tomador
- tomador.RazaoSocial = nfse.cliente.razao_social
- tomador.Endereco = endereco_tomador
- # opcional
- if nfse.cliente.endereco_telefone or nfse.cliente.email:
- tomador.Contato = _tipos.tcContato()
- if nfse.cliente.endereco_telefone:
- tomador.Contato.Telefone = nfse.cliente.endereco_telefone
- if nfse.cliente.email:
- tomador.Contato.Email = nfse.cliente.email
-
- # Prestador
- id_prestador = _tipos.tcIdentificacaoPrestador()
- id_prestador.Cnpj = nfse.emitente.cnpj
- id_prestador.InscricaoMunicipal = nfse.emitente.inscricao_municipal
-
- # identificacao rps
- id_rps = _tipos.tcIdentificacaoRps()
- id_rps.Numero = nfse.identificador
- id_rps.Serie = nfse.serie
- id_rps.Tipo = nfse.tipo
- # inf rps
- inf_rps = _tipos.tcInfRps()
- inf_rps.IdentificacaoRps = id_rps
- inf_rps.DataEmissao = nfse.data_emissao.strftime("%Y-%m-%dT%H:%M:%S")
- # Natureza da Operação
- # 1 – Tributação no município
- # 2 - Tributação fora do município
- # 3 - Isenção
- # 4 - Imune
- # 5 –Exigibilidade suspensa por decisão judicial
- # 6 – Exigibilidade suspensa por procedimento administrativo
- inf_rps.NaturezaOperacao = nfse.natureza_operacao
- # Regime Especial de Tributação
- # 1 – Microempresa municipal
- # 2 - Estimativa
- # 3 – Sociedade de profissionais
- # 4 – Cooperativa
- # 5 - Microempresário Individual (MEI)
- # 6 - Microempresário e Empresa de Pequeno Porte (ME EPP)
- if nfse.regime_especial:
- inf_rps.RegimeEspecialTributacao = nfse.regime_especial
- inf_rps.OptanteSimplesNacional = nfse.simples # 1-sim 2-nao
- inf_rps.IncentivadorCultural = nfse.incentivo # 1-sim 2-nao
- # Código de status da NFS-e
- # 1-Normal 2-Cancelado (sempre 1, nota não pode ser enviada como cancelada)
- inf_rps.Status = 1
- inf_rps.RpsSubstituido = None # opcional
- inf_rps.Servico = servico
- inf_rps.Prestador = id_prestador
- inf_rps.Tomador = tomador
- inf_rps.IntermediarioServico = None # opcional
- inf_rps.ConstrucaoCivil = None # opcional
- inf_rps.Id = nfse.identificador
-
- rps = _tipos.tcRps()
- rps.InfRps = inf_rps
-
- lote = _tipos.tcLoteRps()
- lote.NumeroLote = 1
- lote.Id = 1
- lote.Cnpj = nfse.emitente.cnpj
- lote.InscricaoMunicipal = nfse.emitente.inscricao_municipal
- lote.QuantidadeRps = 1
- lote.ListaRps = BIND()
- lote.ListaRps.append(rps)
-
- enviarLote = servico_enviar_lote_rps_envio_v03.EnviarLoteRpsEnvio()
- enviarLote.LoteRps = lote
- return enviarLote.toxml(encoding="utf-8", element_name="ns1:EnviarLoteRpsEnvio")
-
- def cancelar(self, nfse, codigo):
- """Retorna string de um XML gerado a partir do
- XML Schema (XSD). Binding gerado pelo modulo PyXB."""
- # id nfse
- id_nfse = _tipos.tcIdentificacaoNfse()
- id_nfse.Numero = nfse.identificador
- id_nfse.Cnpj = nfse.emitente.cnpj
- id_nfse.InscricaoMunicipal = nfse.emitente.inscricao_municipal
- id_nfse.CodigoMunicipio = nfse.emitente.endereco_cod_municipio
-
- # Info Pedido de cancelamento
- info_pedido = _tipos.tcInfPedidoCancelamento()
- info_pedido.Id = "1"
- info_pedido.IdentificacaoNfse = id_nfse
- info_pedido.CodigoCancelamento = codigo
-
- # Pedido
- pedido = _tipos.tcPedidoCancelamento()
- pedido.InfPedidoCancelamento = info_pedido
-
- # Cancelamento
- cancelar = servico_cancelar_nfse_envio_v03.CancelarNfseEnvio()
- cancelar.Pedido = pedido
+ def cabecalho(self):
+ NS = "http://www.ginfes.com.br/cabecalho_v03.xsd"
- return cancelar.toxml(encoding="utf-8", element_name="ns1:CancelarNfseEnvio")
+ nsmap = {None: NS}
- def cancelar_v2(self, nfse):
- # serialização utilizando lxml
- from lxml import etree
+ cabecalho = etree.Element(f"{{{NS}}}cabecalho", nsmap=nsmap)
+ cabecalho.attrib["versao"] = "3"
+ versao_dados = etree.SubElement(cabecalho, f"{{{NS}}}versaoDados")
+ versao_dados.text = "3"
- ns1 = "http://www.ginfes.com.br/servico_cancelar_nfse_envio"
- ns2 = "http://www.ginfes.com.br/tipos"
- raiz = etree.Element("{%s}CancelarNfseEnvio" % ns1, nsmap={"ns1": ns1, "ns2": ns2})
- prestador = etree.SubElement(raiz, "{%s}Prestador" % ns1)
- etree.SubElement(prestador, "{%s}Cnpj" % ns2).text = nfse.emitente.cnpj
- etree.SubElement(prestador, "{%s}InscricaoMunicipal" % ns2).text = (
- nfse.emitente.inscricao_municipal
- )
- etree.SubElement(raiz, "{%s}NumeroNfse" % ns1).text = nfse.identificador
- return etree.tostring(raiz, encoding="unicode")
-
- def cabecalho(self):
- # info
- cabecalho = cabecalho_v03.cabecalho()
- cabecalho.versao = "3"
- cabecalho.versaoDados = "3"
- return cabecalho.toxml(encoding="utf-8", element_name="cabecalho")
+ return etree.tostring(cabecalho, encoding="utf-8", xml_declaration=True)
+
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 6940d0d5..732ddb91 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -777,7 +777,7 @@ def consultar(self, xml):
if self.autorizador == "GINFES":
cabecalho = self._cabecalho_ginfes()
# comunica via wsdl
- return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA"],cabecalho, xml)
+ return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA_SERVICO"],cabecalho, xml)
elif self.autorizador == "OSASCO":
# comunica via wsdl
@@ -806,9 +806,12 @@ def consultar_faixa(self, xml):
if self.autorizador == "BETHA":
# comunica via wsdl
return self._post(url, xml, "consultaFaixa")
+ elif self.autorizador == "GINFES":
+ cabecalho = self._cabecalho_ginfes()
+ return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA_FAIXA"],cabecalho, xml)
elif self.autorizador == "OSASCO":
# comunica via wsdl
- return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA"], xml)
+ return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA"], xml)
else:
raise Exception("Este método não esta implementado para o autorizador.")
diff --git a/pynfe/processamento/serializacao.py b/pynfe/processamento/serializacao.py
index f9711636..f454d5db 100644
--- a/pynfe/processamento/serializacao.py
+++ b/pynfe/processamento/serializacao.py
@@ -3,29 +3,15 @@
import hashlib
import re
import warnings
-
from datetime import datetime
import pynfe.utils.xml_writer as xmlw
from pynfe.entidades import Manifesto, NotaFiscal
-from pynfe.utils import (
- etree,
- obter_codigo_por_municipio,
- obter_municipio_por_codigo,
- obter_pais_por_codigo,
- so_numeros,
-)
-from pynfe.utils.flags import (
- CODIGOS_ESTADOS,
- NAMESPACE_CTE,
- NAMESPACE_MDFE,
- NAMESPACE_NFE,
- NAMESPACE_SIG,
- VERSAO_CTE,
- VERSAO_MDFE,
- VERSAO_PADRAO,
- VERSAO_QRCODE,
-)
+from pynfe.utils import (etree, obter_codigo_por_municipio,
+ obter_municipio_por_codigo, obter_pais_por_codigo,
+ so_numeros)
+from pynfe.utils.flags import (CODIGOS_ESTADOS, NAMESPACE_CTE, NAMESPACE_MDFE,
+ NAMESPACE_NFE, NAMESPACE_SIG, VERSAO_MDFE, VERSAO_PADRAO, VERSAO_QRCODE)
from pynfe.utils.webservices import MDFE, NFCE
@@ -2160,21 +2146,21 @@ def gerar(self, nfse):
else:
raise Exception("Este método só esta implementado no autorizador Betha.")
- def gerar_lote(self, nfse):
+ def consultar_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
if self.autorizador.lower() == "ginfes":
from pynfe.processamento.autorizador_nfse import SerializacaoGinfes
-
- return SerializacaoGinfes().serializar_lote_assincrono(nfse)
+
+ return SerializacaoGinfes().consultar_faixa(emitente, numero_inicial, numero_final, pagina=1)
else:
raise Exception("Este método só esta implementado no autorizador ginfes.")
- def consultar_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
+ def consultar_servico_prestado(self, emitente, data_inicio, data_fim, pagina=1):
if self.autorizador.lower() == "ginfes":
from pynfe.processamento.autorizador_nfse import SerializacaoGinfes
- return SerializacaoGinfes().consultar_faixa(emitente, numero_inicial, numero_final, pagina=1)
+ return SerializacaoGinfes().consultar_servico_prestado(emitente, data_inicio, data_fim, pagina=1)
else:
- raise Exception("Este método só esta implementado no autorizador Osasco.")
+ raise Exception("Este método só esta implementado no autorizador ginfes.")
def consultar_nota_emitida(self, cnpj_tomador=None, cpf_tomador=None, data_inicial=None, data_final=None, numero_nota_inicial=None, numero_nota_final=None, numero_rps_inicial=None, numero_rps_final=None):
if self.autorizador.lower() == "osasco":
@@ -2192,31 +2178,9 @@ def consultar_lote(self, emitente, numero):
else:
raise Exception("Este método só esta implementado no autorizador ginfes.")
- def consultar_rps(self, emitente, numero, serie, tipo):
- if self.autorizador.lower() == "ginfes":
- from pynfe.processamento.autorizador_nfse import SerializacaoGinfes
-
- return SerializacaoGinfes().consultar_rps(emitente, numero, serie, tipo)
- else:
- raise Exception("Este método só esta implementado no autorizador ginfes.")
-
- def consultar_situacao_lote(self, emitente, numero):
- if self.autorizador.lower() == "ginfes":
- from pynfe.processamento.autorizador_nfse import SerializacaoGinfes
-
- return SerializacaoGinfes().consultar_situacao_lote(emitente, numero)
- else:
- raise Exception("Este método só esta implementado no autorizador ginfes.")
def cancelar(self, nfse):
- if self.autorizador.lower() == "ginfes":
- from pynfe.processamento.autorizador_nfse import SerializacaoGinfes
-
- # versao 3
- # return SerializacaoGinfes().cancelar(nfse)
- # versao 2
- return SerializacaoGinfes().cancelar_v2(nfse)
- elif self.autorizador.lower() == "betha":
+ if self.autorizador.lower() == "betha":
from pynfe.processamento.autorizador_nfse import SerializacaoBetha
return SerializacaoBetha().cancelar(nfse)
diff --git a/pynfe/utils/webservices.py b/pynfe/utils/webservices.py
index c1294151..c9929a28 100644
--- a/pynfe/utils/webservices.py
+++ b/pynfe/utils/webservices.py
@@ -500,16 +500,18 @@
},
#
"GINFES": {
- "CONSULTA": "ConsultarNfseV3",
- "CONSULTA_RPS": "ConsultarNfsePorRpsV3",
+ "AUTORIZACAO": "GerarNfse",
+ "CANCELAR": "CancelarNfse",
+ "CONSULTA_RPS": "consultarNfsePorRps",
+ "CONSULTA_FAIXA": "ConsultarNfseFaixa",
+ "CONSULTA_SERVICO": "ConsultarNfseServicoPrestado",
+ "CONSULTA_SERVICO_TOMADO": "ConsultarNfseServicoTomado",
"HTTPS": "https://producao.ginfes.com.br/ServiceGinfesImpl?wsdl",
"HOMOLOGACAO": "https://homologacao.ginfes.com.br/ServiceGinfesImpl?wsdl",
},
"OSASCO": {
"AUTORIZACAO": "Emitir",
- "AUTORIZACAO_LOTE": "EmitirEmLote",
"CANCELAR": "Cancelar",
- "CANCELAR_LOTE": "CancelarNotaLote",
"CONSULTA": "Consultar",
"CONSULTA_COMPLETA": "ConsultarNotaCompleta",
"HTTPS": "https://nfe.osasco.sp.gov.br/EISSNFEWebServices/NotaFiscalEletronica.svc?wsdl",
From a368abdc370a4a519d6942536343ffd037920a11 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 29 Dec 2025 23:49:53 -0300
Subject: [PATCH 099/175] =?UTF-8?q?adiciona=20suporte=20ao=20autorizador?=
=?UTF-8?q?=20Campinas=20com=20m=C3=A9todos=20de=20consulta=20e=20configur?=
=?UTF-8?q?a=C3=A7=C3=A3o=20de=20namespace?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 108 +++++++++++++++++++++++-
pynfe/processamento/comunicacao.py | 89 ++++++-------------
pynfe/processamento/serializacao.py | 50 ++++-------
pynfe/utils/webservices.py | 10 +++
4 files changed, 157 insertions(+), 100 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index 90343ffa..0f4175a5 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -286,7 +286,7 @@ def serializar_lote_sincrono(self, nfse):
return gnfse.toxml(encoding="utf-8", element_name="EnviarLoteRpsSincronoEnvio")
-
+
class SerializacaoGinfes(InterfaceAutorizador):
def __init__(self):
pass
@@ -360,4 +360,108 @@ def cabecalho(self):
versao_dados.text = "3"
return etree.tostring(cabecalho, encoding="utf-8", xml_declaration=True)
-
+
+
+class SerializacaoCampinas(InterfaceAutorizador):
+
+ NS = "http://www.abrasf.org.br/nfse.xsd"
+ DS = "http://www.w3.org/2000/09/xmldsig#"
+
+ def consultar_periodo(self, emitente, data_inicio, data_fim, pagina=1):
+ nsmap = {
+ None: self.NS,
+ "ds": self.DS,
+ }
+
+ root = etree.Element(
+ f"{{{self.NS}}}ConsultarNfseServicoPrestadoEnvio",
+ nsmap=nsmap
+ )
+
+ # ID é OPCIONAL no XSD, mas Campinas aceita
+ root.attrib["Id"] = f"CNFSESP{uuid.uuid4().hex}"
+
+ # Prestador
+ prestador = etree.SubElement(root, f"{{{self.NS}}}Prestador")
+
+ cpf_cnpj = etree.SubElement(prestador, f"{{{self.NS}}}CpfCnpj")
+ etree.SubElement(cpf_cnpj, f"{{{self.NS}}}Cnpj").text = emitente.cnpj
+
+ etree.SubElement(
+ prestador,
+ f"{{{self.NS}}}InscricaoMunicipal"
+ ).text = emitente.inscricao_municipal
+
+ # Período de emissão
+ periodo = etree.SubElement(root, f"{{{self.NS}}}PeriodoEmissao")
+ etree.SubElement(periodo, f"{{{self.NS}}}DataInicial").text = data_inicio
+ etree.SubElement(periodo, f"{{{self.NS}}}DataFinal").text = data_fim
+
+ # Página (mínimo 1)
+ etree.SubElement(root, f"{{{self.NS}}}Pagina").text = str(pagina)
+
+ # Signature OBRIGATÓRIA no XSD
+ etree.SubElement(root, f"{{{self.DS}}}Signature")
+
+ return etree.tostring(
+ root,
+ encoding="utf-8",
+ xml_declaration=True
+ )
+ def consultar_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
+ nsmap = {
+ None: self.NS,
+ "ds": self.DS,
+ }
+
+ root = etree.Element(
+ f"{{{self.NS}}}ConsultarNfseFaixaEnvio",
+ nsmap=nsmap
+ )
+
+ root.attrib["Id"] = f"CNFSEFAIXA{uuid.uuid4().hex}"
+
+ prestador = etree.SubElement(root, f"{{{self.NS}}}Prestador")
+ cpf_cnpj = etree.SubElement(prestador, f"{{{self.NS}}}CpfCnpj")
+ etree.SubElement(cpf_cnpj, f"{{{self.NS}}}Cnpj").text = emitente.cnpj
+ etree.SubElement(
+ prestador,
+ f"{{{self.NS}}}InscricaoMunicipal"
+ ).text = emitente.inscricao_municipal
+
+ faixa = etree.SubElement(root, f"{{{self.NS}}}Faixa")
+ etree.SubElement(
+ faixa,
+ f"{{{self.NS}}}NumeroNfseInicial"
+ ).text = str(numero_inicial)
+
+ if numero_final:
+ etree.SubElement(
+ faixa,
+ f"{{{self.NS}}}NumeroNfseFinal"
+ ).text = str(numero_final)
+
+ etree.SubElement(root, f"{{{self.NS}}}Pagina").text = str(pagina)
+
+ etree.SubElement(root, f"{{{self.DS}}}Signature")
+
+ return etree.tostring(
+ root,
+ encoding="utf-8",
+ xml_declaration=True
+ )
+ def cabecalho(self):
+ NS = "http://www.abrasf.org.br/nfse.xsd"
+ nsmap = {None: NS}
+
+ cabecalho = etree.Element("cabecalho", nsmap=nsmap)
+ cabecalho.attrib["versao"] = "2.03"
+
+ versao_dados = etree.SubElement(cabecalho, "versaoDados")
+ versao_dados.text = "2.03"
+
+ return etree.tostring(
+ cabecalho,
+ encoding="utf-8",
+ xml_declaration=False
+ )
\ No newline at end of file
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 732ddb91..aef65ce6 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -745,41 +745,17 @@ def __init__(self, autorizador, certificado=None, certificado_senha=None, homolo
elif self.autorizador == "OSASCO":
self._namespace = ""
self._versao = "1"
+ elif self.autorizador == "CAMPINAS":
+ self._namespace = "http://www.abrasf.org.br/nfse.xsd"
+ self._versao = "2"
else:
raise Exception("Autorizador não encontrado!")
- def autorizacao(self, nota):
+ def consultar_nfse(self, xml):
# url do serviço
url = self._get_url()
- if self.autorizador == "BETHA":
- # xml
- xml = etree.tostring(nota, encoding="unicode", pretty_print=False)
- # comunica via wsdl
- return self._post(url, xml, "gerar")
- else:
- raise Exception("Este método só esta implementado no autorizador betha.")
- def enviar_lote(self, xml):
- # url do serviço
- url = self._get_url()
- if self.autorizador == "GINFES":
- # xml
- xml = '' + xml
- # comunica via wsdl
- return self._post_https(url, xml, "enviar_lote")
- else:
- raise Exception("Este método só esta implementado no autorizador ginfes.")
-
- def consultar(self, xml):
- # url do serviço
- url = self._get_url()
-
- if self.autorizador == "GINFES":
- cabecalho = self._cabecalho_ginfes()
- # comunica via wsdl
- return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA_SERVICO"],cabecalho, xml)
-
- elif self.autorizador == "OSASCO":
+ if self.autorizador == "OSASCO":
# comunica via wsdl
return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA_COMPLETA"], xml)
else:
@@ -788,12 +764,10 @@ def consultar(self, xml):
def consultar_rps(self, xml):
# url do serviço
url = self._get_url()
- if self.autorizador == "BETHA":
- # comunica via wsdl
- return self._post(url, xml, "consultaRps")
- elif self.autorizador == "GINFES":
- cabecalho = self._cabecalho_ginfes()
- return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA_RPS"],cabecalho, xml)
+ if self.autorizador == "CAMPINAS":
+ from pynfe.processamento.autorizador_nfse import SerializacaoCampinas
+ cabecalho = SerializacaoCampinas().cabecalho()
+ return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA_RPS"], cabecalho, xml)
elif self.autorizador == "OSASCO":
# comunica via wsdl
return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA"], xml)
@@ -803,11 +777,9 @@ def consultar_rps(self, xml):
def consultar_faixa(self, xml):
# url do serviço
url = self._get_url()
- if self.autorizador == "BETHA":
- # comunica via wsdl
- return self._post(url, xml, "consultaFaixa")
- elif self.autorizador == "GINFES":
- cabecalho = self._cabecalho_ginfes()
+ if self.autorizador == "CAMPINAS":
+ from pynfe.processamento.autorizador_nfse import SerializacaoCampinas
+ cabecalho = SerializacaoCampinas().cabecalho()
return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA_FAIXA"],cabecalho, xml)
elif self.autorizador == "OSASCO":
# comunica via wsdl
@@ -815,40 +787,27 @@ def consultar_faixa(self, xml):
else:
raise Exception("Este método não esta implementado para o autorizador.")
- def consultar_lote(self, xml):
+ def consultar_periodo(self, xml):
# url do serviço
url = self._get_url()
- if self.autorizador == "GINFES":
- # xml
- xml = '' + xml
+ if self.autorizador == "CAMPINAS":
+ from pynfe.processamento.autorizador_nfse import SerializacaoCampinas
+ cabecalho = SerializacaoCampinas().cabecalho()
+ return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA_SERVICO"],cabecalho, xml)
+ elif self.autorizador == "OSASCO":
# comunica via wsdl
- return self._post_https(url, xml, "consulta_lote")
+ return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA"], xml)
else:
raise Exception("Este método não esta implementado para o autorizador.")
+ def consultar_lote(self, xml):
+ raise Exception("Este método não esta implementado para o autorizador.")
+
def consultar_situacao_lote(self, xml):
- # url do serviço
- url = self._get_url()
- if self.autorizador == "GINFES":
- # comunica via wsdl
- return self._post_https(url, xml, "consulta_situacao_lote")
- else:
- raise Exception("Este método não esta implementado para o autorizador.")
+ raise Exception("Este método não esta implementado para o autorizador.")
def cancelar(self, xml):
- # url do serviço
- url = self._get_url()
- # Betha
- if self.autorizador == "BETHA":
- # comunica via wsdl
- return self._post(url, xml, "cancelar")
- # Ginfes
- elif self.autorizador == "GINFES":
- # comunica via wsdl com certificado
- return self._post_https(url, xml, "cancelar")
- # TODO outros autorizadores
- else:
- raise Exception("Este método não esta implementado para o autorizador.")
+ raise Exception("Este método não esta implementado para o autorizador.")
def _cabecalho(self, retorna_string=True):
"""Monta o XML do cabeçalho da requisição wsdl
diff --git a/pynfe/processamento/serializacao.py b/pynfe/processamento/serializacao.py
index f454d5db..756aad25 100644
--- a/pynfe/processamento/serializacao.py
+++ b/pynfe/processamento/serializacao.py
@@ -2138,54 +2138,38 @@ def __init__(self, autorizador, chave_autenticacao=None):
self.autorizador = autorizador
self.chave_autenticacao = chave_autenticacao
- def gerar(self, nfse):
- if self.autorizador.lower() == "betha":
- from pynfe.processamento.autorizador_nfse import SerializacaoBetha
-
- return SerializacaoBetha().gerar(nfse)
- else:
- raise Exception("Este método só esta implementado no autorizador Betha.")
-
def consultar_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
- if self.autorizador.lower() == "ginfes":
+ if self.autorizador.lower() == "campinas":
from pynfe.processamento.autorizador_nfse import SerializacaoGinfes
return SerializacaoGinfes().consultar_faixa(emitente, numero_inicial, numero_final, pagina=1)
+ elif self.autorizador.lower() == "osasco":
+ from pynfe.processamento.autorizador_nfse import SerializacaoOsasco
+ return SerializacaoOsasco(self.chave_autenticacao).consultar(cnpj_tomador=emitente.cnpj, numero_nota_inicial=numero_inicial, numero_nota_final=numero_final)
else:
- raise Exception("Este método só esta implementado no autorizador ginfes.")
+ raise Exception(f"Este método não esta implementado para o autorizador {self.autorizador.upper()}")
- def consultar_servico_prestado(self, emitente, data_inicio, data_fim, pagina=1):
- if self.autorizador.lower() == "ginfes":
- from pynfe.processamento.autorizador_nfse import SerializacaoGinfes
+ def consultar_periodo(self, emitente, data_inicio, data_fim, pagina=1):
+ if self.autorizador.lower() == "campinas":
+ from pynfe.processamento.autorizador_nfse import SerializacaoCampinas
- return SerializacaoGinfes().consultar_servico_prestado(emitente, data_inicio, data_fim, pagina=1)
- else:
- raise Exception("Este método só esta implementado no autorizador ginfes.")
-
- def consultar_nota_emitida(self, cnpj_tomador=None, cpf_tomador=None, data_inicial=None, data_final=None, numero_nota_inicial=None, numero_nota_final=None, numero_rps_inicial=None, numero_rps_final=None):
- if self.autorizador.lower() == "osasco":
+ return SerializacaoCampinas().consultar_periodo(emitente, data_inicio, data_fim, pagina=1)
+ elif self.autorizador.lower() == "osasco":
from pynfe.processamento.autorizador_nfse import SerializacaoOsasco
- return SerializacaoOsasco(self.chave_autenticacao).consultar(cnpj_tomador=cnpj_tomador, cpf_tomador=cpf_tomador, data_inicial=data_inicial, data_final=data_final, numero_nota_inicial=numero_nota_inicial, numero_nota_final=numero_nota_final, numero_rps_inicial=numero_rps_inicial, numero_rps_final=numero_rps_final)
+ return SerializacaoOsasco(self.chave_autenticacao).consultar(cnpj_tomador=emitente.cnpj, data_inicial=data_inicio, data_final=data_fim)
else:
- raise Exception("Este método só esta implementado no autorizador Osasco.")
+ raise Exception(f"Este método não esta implementado para o autorizador {self.autorizador.upper()}")
- def consultar_lote(self, emitente, numero):
- if self.autorizador.lower() == "ginfes":
- from pynfe.processamento.autorizador_nfse import SerializacaoGinfes
- return SerializacaoGinfes().consultar_lote(emitente, numero)
+ def consultar_nfse(self, emitente, numero_nfse):
+ if self.autorizador.lower() == "osasco":
+ from pynfe.processamento.autorizador_nfse import SerializacaoOsasco
+ return SerializacaoOsasco(self.chave_autenticacao).consultar(cnpj_tomador=emitente.cnpj, numero_nota_inicial=numero_nfse, numero_nota_final=numero_nfse)
else:
- raise Exception("Este método só esta implementado no autorizador ginfes.")
-
+ raise Exception(f"Este método não esta implementado para o autorizador {self.autorizador.upper()}")
- def cancelar(self, nfse):
- if self.autorizador.lower() == "betha":
- from pynfe.processamento.autorizador_nfse import SerializacaoBetha
- return SerializacaoBetha().cancelar(nfse)
- else:
- raise Exception("Autorizador não suportado para cancelamento!")
class SerializacaoQrcodeMDFe(object):
diff --git a/pynfe/utils/webservices.py b/pynfe/utils/webservices.py
index c9929a28..a97cada4 100644
--- a/pynfe/utils/webservices.py
+++ b/pynfe/utils/webservices.py
@@ -519,6 +519,16 @@
"https://nfe.osasco.sp.gov.br/EISSNFEWebServices/NotaFiscalEletronica.svc?wsdl"
),
},
+ "CAMPINAS": {
+ "AUTORIZACAO": "GerarNfse",
+ "CANCELAR": "CancelarNfse",
+ "CONSULTA_RPS": "consultarNfsePorRps",
+ "CONSULTA_FAIXA": "ConsultarNfseFaixa",
+ "CONSULTA_SERVICO": "ConsultarNfseServicoPrestado",
+ "CONSULTA_SERVICO_TOMADO": "ConsultarNfseServicoTomado",
+ "HTTPS": "https://novanfse.campinas.sp.gov.br/notafiscal-abrasfv203-ws/NotaFiscalSoap?wsdl",
+ "HOMOLOGACAO": "https://homol-rps.ima.sp.gov.br/notafiscal-abrasfv203-ws/NotaFiscalSoap?wsdl",
+ },
}
# MDF-e
From 7ab16b27af31f83bb5cdcb1aed392b08c56cde2a Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 29 Dec 2025 23:56:53 -0300
Subject: [PATCH 100/175] =?UTF-8?q?remove=20cabe=C3=A7alho=20das=20chamada?=
=?UTF-8?q?s=20de=20consulta=20para=20o=20autorizador=20Campinas=20na=20cl?=
=?UTF-8?q?asse=20ComunicacaoNfse?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index aef65ce6..2a707dc2 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -767,7 +767,7 @@ def consultar_rps(self, xml):
if self.autorizador == "CAMPINAS":
from pynfe.processamento.autorizador_nfse import SerializacaoCampinas
cabecalho = SerializacaoCampinas().cabecalho()
- return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA_RPS"], cabecalho, xml)
+ return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA_RPS"], xml)
elif self.autorizador == "OSASCO":
# comunica via wsdl
return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA"], xml)
@@ -780,7 +780,7 @@ def consultar_faixa(self, xml):
if self.autorizador == "CAMPINAS":
from pynfe.processamento.autorizador_nfse import SerializacaoCampinas
cabecalho = SerializacaoCampinas().cabecalho()
- return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA_FAIXA"],cabecalho, xml)
+ return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA_FAIXA"], xml)
elif self.autorizador == "OSASCO":
# comunica via wsdl
return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA"], xml)
From 0e912d5e6d4b2cbf2d461902b7932fafa0917270 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 29 Dec 2025 23:59:24 -0300
Subject: [PATCH 101/175] =?UTF-8?q?ajusta=20cabe=C3=A7alho=20nas=20chamada?=
=?UTF-8?q?s=20de=20consulta=20para=20o=20autorizador=20Campinas=20na=20cl?=
=?UTF-8?q?asse=20ComunicacaoNfse?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 13 +++++--------
1 file changed, 5 insertions(+), 8 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 2a707dc2..24bbc720 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -767,7 +767,7 @@ def consultar_rps(self, xml):
if self.autorizador == "CAMPINAS":
from pynfe.processamento.autorizador_nfse import SerializacaoCampinas
cabecalho = SerializacaoCampinas().cabecalho()
- return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA_RPS"], xml)
+ return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA_RPS"], cabecalho, xml)
elif self.autorizador == "OSASCO":
# comunica via wsdl
return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA"], xml)
@@ -780,7 +780,7 @@ def consultar_faixa(self, xml):
if self.autorizador == "CAMPINAS":
from pynfe.processamento.autorizador_nfse import SerializacaoCampinas
cabecalho = SerializacaoCampinas().cabecalho()
- return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA_FAIXA"], xml)
+ return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA_FAIXA"],cabecalho, xml)
elif self.autorizador == "OSASCO":
# comunica via wsdl
return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA"], xml)
@@ -1103,7 +1103,7 @@ def _post_sp_https(self, url, xml, metodo, versao_schema=2):
finally:
certificadoA1.excluir()
- def _post_zeep(self, wsdl, metodo, *args, wcf_compatibility=True):
+ def _post_zeep(self, wsdl, metodo, xml, wcf_compatibility=True):
"""
Comunicação wsdl utilizando a biblioteca zeep (GINFES compatível)
@@ -1155,14 +1155,11 @@ def _post_zeep(self, wsdl, metodo, *args, wcf_compatibility=True):
raise Exception(f"Método {metodo} não existe no WSDL")
print("Chamando método:", metodo)
- print("Parâmetros:", args)
+ print("Parâmetros:", xml)
service = getattr(client.service, metodo)
- # chama com N parâmetros (GINFES usa 2)
- response = service(*args)
-
- # GINFES retorna string XML
+ response = service(xml)
return serialize_object(response)
finally:
From 37278bed90458091ac2cca9fc713506f7393b631 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 00:06:15 -0300
Subject: [PATCH 102/175] =?UTF-8?q?remove=20convers=C3=A3o=20para=20string?=
=?UTF-8?q?=20em=20m=C3=A9todos=20da=20classe=20SerializacaoCampinas=20e?=
=?UTF-8?q?=20adiciona=20logs=20de=20servi=C3=A7o=20na=20classe=20Comunica?=
=?UTF-8?q?caoNfse?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 18 +++---------------
pynfe/processamento/comunicacao.py | 3 +++
2 files changed, 6 insertions(+), 15 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index 0f4175a5..31ef21b2 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -403,11 +403,7 @@ def consultar_periodo(self, emitente, data_inicio, data_fim, pagina=1):
# Signature OBRIGATÓRIA no XSD
etree.SubElement(root, f"{{{self.DS}}}Signature")
- return etree.tostring(
- root,
- encoding="utf-8",
- xml_declaration=True
- )
+ return root
def consultar_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
nsmap = {
None: self.NS,
@@ -445,11 +441,7 @@ def consultar_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
etree.SubElement(root, f"{{{self.DS}}}Signature")
- return etree.tostring(
- root,
- encoding="utf-8",
- xml_declaration=True
- )
+ return root
def cabecalho(self):
NS = "http://www.abrasf.org.br/nfse.xsd"
nsmap = {None: NS}
@@ -460,8 +452,4 @@ def cabecalho(self):
versao_dados = etree.SubElement(cabecalho, "versaoDados")
versao_dados.text = "2.03"
- return etree.tostring(
- cabecalho,
- encoding="utf-8",
- xml_declaration=False
- )
\ No newline at end of file
+ return cabecalho
\ No newline at end of file
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 24bbc720..9590ce66 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -1156,6 +1156,9 @@ def _post_zeep(self, wsdl, metodo, xml, wcf_compatibility=True):
print("Chamando método:", metodo)
print("Parâmetros:", xml)
+ print(client.wsdl.services)
+ print(client.wsdl.services[0].ports[0].operations)
+ print(client.service._binding._operations)
service = getattr(client.service, metodo)
From 5aa172c7802df55eb68247b378ff90ea3d7feb35 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 00:09:24 -0300
Subject: [PATCH 103/175] =?UTF-8?q?remove=20cabe=C3=A7alho=5Fxml=20das=20c?=
=?UTF-8?q?hamadas=20no=20m=C3=A9todo=20de=20consulta=20da=20classe=20Comu?=
=?UTF-8?q?nicacaoNfse?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 9590ce66..3b519891 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -1111,8 +1111,7 @@ def _post_zeep(self, wsdl, metodo, xml, wcf_compatibility=True):
_post_zeep(
wsdl,
"ConsultarNfseV3",
- cabecalho_xml,
- xml_consulta
+ xml_consulta ou payload,
)
"""
try:
@@ -1157,7 +1156,6 @@ def _post_zeep(self, wsdl, metodo, xml, wcf_compatibility=True):
print("Chamando método:", metodo)
print("Parâmetros:", xml)
print(client.wsdl.services)
- print(client.wsdl.services[0].ports[0].operations)
print(client.service._binding._operations)
service = getattr(client.service, metodo)
From 6151a1b8618dd67e023ef6a08d5562203e9648f3 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 00:16:14 -0300
Subject: [PATCH 104/175] =?UTF-8?q?adiciona=20m=C3=A9todos=20de=20consulta?=
=?UTF-8?q?=20na=20classe=20SerializacaoCampinas=20e=20ajusta=20chamadas?=
=?UTF-8?q?=20na=20classe=20ComunicacaoNfse?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 121 ++++++------------------
pynfe/processamento/comunicacao.py | 114 ++++++++++------------
2 files changed, 78 insertions(+), 157 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index 31ef21b2..49ed69ae 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -43,6 +43,36 @@ def consultar(
"NumeroReciboUnico": numero_rps_unico,
}
+class SerializacaoCampinas(InterfaceAutorizador):
+ def consultar_periodo(self, emitente, data_inicio, data_fim, pagina=1):
+ return {
+ "Prestador": {
+ "CpfCnpj": {
+ "Cnpj": emitente.cnpj
+ },
+ "InscricaoMunicipal": emitente.inscricao_municipal
+ },
+ "PeriodoEmissao": {
+ "DataInicial": data_inicio,
+ "DataFinal": data_fim
+ },
+ "Pagina": pagina
+ }
+ def consultar_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
+ return {
+ "Prestador": {
+ "CpfCnpj": {
+ "Cnpj": emitente.cnpj
+ },
+ "InscricaoMunicipal": emitente.inscricao_municipal
+ },
+ "Faixa": {
+ "NumeroNfseInicial": numero_inicial,
+ "NumeroNfseFinal": numero_final
+ },
+ "Pagina": pagina
+ }
+
class SerializacaoBetha(InterfaceAutorizador):
def __init__(self):
@@ -362,94 +392,3 @@ def cabecalho(self):
return etree.tostring(cabecalho, encoding="utf-8", xml_declaration=True)
-class SerializacaoCampinas(InterfaceAutorizador):
-
- NS = "http://www.abrasf.org.br/nfse.xsd"
- DS = "http://www.w3.org/2000/09/xmldsig#"
-
- def consultar_periodo(self, emitente, data_inicio, data_fim, pagina=1):
- nsmap = {
- None: self.NS,
- "ds": self.DS,
- }
-
- root = etree.Element(
- f"{{{self.NS}}}ConsultarNfseServicoPrestadoEnvio",
- nsmap=nsmap
- )
-
- # ID é OPCIONAL no XSD, mas Campinas aceita
- root.attrib["Id"] = f"CNFSESP{uuid.uuid4().hex}"
-
- # Prestador
- prestador = etree.SubElement(root, f"{{{self.NS}}}Prestador")
-
- cpf_cnpj = etree.SubElement(prestador, f"{{{self.NS}}}CpfCnpj")
- etree.SubElement(cpf_cnpj, f"{{{self.NS}}}Cnpj").text = emitente.cnpj
-
- etree.SubElement(
- prestador,
- f"{{{self.NS}}}InscricaoMunicipal"
- ).text = emitente.inscricao_municipal
-
- # Período de emissão
- periodo = etree.SubElement(root, f"{{{self.NS}}}PeriodoEmissao")
- etree.SubElement(periodo, f"{{{self.NS}}}DataInicial").text = data_inicio
- etree.SubElement(periodo, f"{{{self.NS}}}DataFinal").text = data_fim
-
- # Página (mínimo 1)
- etree.SubElement(root, f"{{{self.NS}}}Pagina").text = str(pagina)
-
- # Signature OBRIGATÓRIA no XSD
- etree.SubElement(root, f"{{{self.DS}}}Signature")
-
- return root
- def consultar_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
- nsmap = {
- None: self.NS,
- "ds": self.DS,
- }
-
- root = etree.Element(
- f"{{{self.NS}}}ConsultarNfseFaixaEnvio",
- nsmap=nsmap
- )
-
- root.attrib["Id"] = f"CNFSEFAIXA{uuid.uuid4().hex}"
-
- prestador = etree.SubElement(root, f"{{{self.NS}}}Prestador")
- cpf_cnpj = etree.SubElement(prestador, f"{{{self.NS}}}CpfCnpj")
- etree.SubElement(cpf_cnpj, f"{{{self.NS}}}Cnpj").text = emitente.cnpj
- etree.SubElement(
- prestador,
- f"{{{self.NS}}}InscricaoMunicipal"
- ).text = emitente.inscricao_municipal
-
- faixa = etree.SubElement(root, f"{{{self.NS}}}Faixa")
- etree.SubElement(
- faixa,
- f"{{{self.NS}}}NumeroNfseInicial"
- ).text = str(numero_inicial)
-
- if numero_final:
- etree.SubElement(
- faixa,
- f"{{{self.NS}}}NumeroNfseFinal"
- ).text = str(numero_final)
-
- etree.SubElement(root, f"{{{self.NS}}}Pagina").text = str(pagina)
-
- etree.SubElement(root, f"{{{self.DS}}}Signature")
-
- return root
- def cabecalho(self):
- NS = "http://www.abrasf.org.br/nfse.xsd"
- nsmap = {None: NS}
-
- cabecalho = etree.Element("cabecalho", nsmap=nsmap)
- cabecalho.attrib["versao"] = "2.03"
-
- versao_dados = etree.SubElement(cabecalho, "versaoDados")
- versao_dados.text = "2.03"
-
- return cabecalho
\ No newline at end of file
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 3b519891..c337306b 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -6,14 +6,25 @@
import requests
from pynfe.entidades.certificado import CertificadoA1
from pynfe.utils import etree, so_numeros
-from pynfe.utils.flags import (CODIGOS_ESTADOS, MODELO_MDFE, NAMESPACE_BETHA,
- NAMESPACE_CTE, NAMESPACE_CTE_METODO,
- NAMESPACE_MDFE, NAMESPACE_MDFE_METODO,
- NAMESPACE_METODO, NAMESPACE_NFCOM,
- NAMESPACE_NFCOM_METODO, NAMESPACE_NFE,
- NAMESPACE_SOAP, NAMESPACE_XSD, NAMESPACE_XSI,
- VERSAO_CTE, VERSAO_MDFE, VERSAO_NFCOM,
- VERSAO_PADRAO)
+from pynfe.utils.flags import (
+ CODIGOS_ESTADOS,
+ MODELO_MDFE,
+ NAMESPACE_CTE,
+ NAMESPACE_CTE_METODO,
+ NAMESPACE_MDFE,
+ NAMESPACE_MDFE_METODO,
+ NAMESPACE_METODO,
+ NAMESPACE_NFCOM,
+ NAMESPACE_NFCOM_METODO,
+ NAMESPACE_NFE,
+ NAMESPACE_SOAP,
+ NAMESPACE_XSD,
+ NAMESPACE_XSI,
+ VERSAO_CTE,
+ VERSAO_MDFE,
+ VERSAO_NFCOM,
+ VERSAO_PADRAO,
+)
from pynfe.utils.webservices import CTE, MDFE, NFCE, NFCOM, NFE, NFSE
from .assinatura import AssinaturaA1
@@ -731,13 +742,7 @@ def __init__(self, autorizador, certificado=None, certificado_senha=None, homolo
self.certificado_senha = certificado_senha
self._ambiente = 2 if homologacao else 1
self.autorizador = autorizador.upper()
- if self.autorizador == "GINFES":
- self._namespace = "http://www.ginfes.com.br/cabecalho_v03.xsd"
- self._versao = "3"
- elif self.autorizador == "BETHA":
- self._namespace = NAMESPACE_BETHA
- self._versao = "2.02"
- elif self.autorizador == "SAO_PAULO":
+ if self.autorizador == "SAO_PAULO":
self._namespace = "http://www.prefeitura.sp.gov.br/nfe"
self._versao = "2"
elif self.autorizador == "BARUERI":
@@ -751,62 +756,59 @@ def __init__(self, autorizador, certificado=None, certificado_senha=None, homolo
else:
raise Exception("Autorizador não encontrado!")
- def consultar_nfse(self, xml):
+ def consultar_nfse(self, payload):
# url do serviço
url = self._get_url()
if self.autorizador == "OSASCO":
# comunica via wsdl
- return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA_COMPLETA"], xml)
+ return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA_COMPLETA"], payload)
else:
raise Exception("Este método não esta implementado para o autorizador.")
- def consultar_rps(self, xml):
+ def consultar_rps(self, payload):
# url do serviço
url = self._get_url()
if self.autorizador == "CAMPINAS":
from pynfe.processamento.autorizador_nfse import SerializacaoCampinas
+
cabecalho = SerializacaoCampinas().cabecalho()
- return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA_RPS"], cabecalho, xml)
+ return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA_RPS"], cabecalho, payload)
elif self.autorizador == "OSASCO":
# comunica via wsdl
- return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA"], xml)
+ return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA"], payload)
else:
raise Exception("Este método não esta implementado para o autorizador.")
- def consultar_faixa(self, xml):
+ def consultar_faixa(self, payload):
# url do serviço
url = self._get_url()
if self.autorizador == "CAMPINAS":
- from pynfe.processamento.autorizador_nfse import SerializacaoCampinas
- cabecalho = SerializacaoCampinas().cabecalho()
- return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA_FAIXA"],cabecalho, xml)
+ return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA_FAIXA"], payload)
elif self.autorizador == "OSASCO":
# comunica via wsdl
- return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA"], xml)
+ return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA"], payload)
else:
raise Exception("Este método não esta implementado para o autorizador.")
- def consultar_periodo(self, xml):
+ def consultar_periodo(self, payload):
# url do serviço
url = self._get_url()
if self.autorizador == "CAMPINAS":
- from pynfe.processamento.autorizador_nfse import SerializacaoCampinas
- cabecalho = SerializacaoCampinas().cabecalho()
- return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA_SERVICO"],cabecalho, xml)
+ return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA_SERVICO"], payload)
elif self.autorizador == "OSASCO":
# comunica via wsdl
- return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA"], xml)
+ return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA"], payloadpayload)
else:
raise Exception("Este método não esta implementado para o autorizador.")
- def consultar_lote(self, xml):
+ def consultar_lote(self, payload):
raise Exception("Este método não esta implementado para o autorizador.")
- def consultar_situacao_lote(self, xml):
+ def consultar_situacao_lote(self, payload):
raise Exception("Este método não esta implementado para o autorizador.")
- def cancelar(self, xml):
+ def cancelar(self, payload):
raise Exception("Este método não esta implementado para o autorizador.")
def _cabecalho(self, retorna_string=True):
@@ -908,7 +910,6 @@ def _post_https(self, url, xml, metodo):
wsdl = url # ?wsdl
endpoint = url.replace("?wsdl", "") # REMOVE ?wsdl
-
cliente = Client(
wsdl,
transport=HttpAuthenticated(
@@ -1103,16 +1104,10 @@ def _post_sp_https(self, url, xml, metodo, versao_schema=2):
finally:
certificadoA1.excluir()
- def _post_zeep(self, wsdl, metodo, xml, wcf_compatibility=True):
+ def _post_zeep(self, wsdl, metodo, payload, wcf_compatibility=True):
"""
- Comunicação wsdl utilizando a biblioteca zeep (GINFES compatível)
-
- Ex:
- _post_zeep(
- wsdl,
- "ConsultarNfseV3",
- xml_consulta ou payload,
- )
+ Comunicação wsdl utilizando a biblioteca zeep )
+ Recebe o wsdl, o método a ser chamado e o payload (XML ou objeto)
"""
try:
import requests
@@ -1120,47 +1115,34 @@ def _post_zeep(self, wsdl, metodo, xml, wcf_compatibility=True):
from zeep.helpers import serialize_object
from zeep.settings import Settings
from zeep.transports import Transport
-
+
session = requests.Session()
session.verify = False
-
+
# certificado A1
if self.certificado:
certificadoA1 = CertificadoA1(self.certificado)
chave, cert = certificadoA1.separar_arquivo(self.certificado_senha, caminho=True)
session.cert = (cert, chave)
- transport = Transport(
- session=session,
- timeout=60
- )
+ transport = Transport(session=session, timeout=60)
- settings = Settings(
- strict=not wcf_compatibility,
- xml_huge_tree=True
- )
+ settings = Settings(strict=not wcf_compatibility, xml_huge_tree=True)
- client = Client(
- wsdl=wsdl,
- transport=transport,
- settings=settings
- )
+ client = Client(wsdl=wsdl, transport=transport, settings=settings)
# DEBUG ÚTIL
print("SOAP endpoint:", client.service._binding_options["address"])
-
-
+
if not hasattr(client.service, metodo):
raise Exception(f"Método {metodo} não existe no WSDL")
-
+
print("Chamando método:", metodo)
- print("Parâmetros:", xml)
- print(client.wsdl.services)
- print(client.service._binding._operations)
-
+ print("payload:", payload)
+
service = getattr(client.service, metodo)
- response = service(xml)
+ response = service(payload)
return serialize_object(response)
finally:
From 2e1f5052a0a98eaa5118d432764b90ca7ac1605b Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 00:18:57 -0300
Subject: [PATCH 105/175] =?UTF-8?q?altera=20importa=C3=A7=C3=A3o=20na=20cl?=
=?UTF-8?q?asse=20SerializacaoNfse=20para=20utilizar=20SerializacaoCampina?=
=?UTF-8?q?s=20na=20consulta=20de=20faixa?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/serializacao.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pynfe/processamento/serializacao.py b/pynfe/processamento/serializacao.py
index 756aad25..92622b7e 100644
--- a/pynfe/processamento/serializacao.py
+++ b/pynfe/processamento/serializacao.py
@@ -2140,9 +2140,9 @@ def __init__(self, autorizador, chave_autenticacao=None):
def consultar_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
if self.autorizador.lower() == "campinas":
- from pynfe.processamento.autorizador_nfse import SerializacaoGinfes
+ from pynfe.processamento.autorizador_nfse import SerializacaoCampinas
- return SerializacaoGinfes().consultar_faixa(emitente, numero_inicial, numero_final, pagina=1)
+ return SerializacaoCampinas().consultar_faixa(emitente, numero_inicial, numero_final, pagina=1)
elif self.autorizador.lower() == "osasco":
from pynfe.processamento.autorizador_nfse import SerializacaoOsasco
return SerializacaoOsasco(self.chave_autenticacao).consultar(cnpj_tomador=emitente.cnpj, numero_nota_inicial=numero_inicial, numero_nota_final=numero_final)
From dc714313b94b08b7f82bc9f540be3775c5a6c67c Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 00:30:19 -0300
Subject: [PATCH 106/175] =?UTF-8?q?adiciona=20m=C3=A9todos=20de=20consulta?=
=?UTF-8?q?=20na=20classe=20SerializacaoCampinas=20e=20ajusta=20chamadas?=
=?UTF-8?q?=20na=20classe=20ComunicacaoNfse=20para=20utilizar=20comunica?=
=?UTF-8?q?=C3=A7=C3=A3o=20HTTPS?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 73 ++++++++++++++++---------
pynfe/processamento/comunicacao.py | 45 ++++-----------
2 files changed, 57 insertions(+), 61 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index 49ed69ae..7396526f 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -43,35 +43,56 @@ def consultar(
"NumeroReciboUnico": numero_rps_unico,
}
+from lxml import etree
+from pynfe.processamento.autorizador_nfse import InterfaceAutorizador
+
+
class SerializacaoCampinas(InterfaceAutorizador):
+ """
+ Serialização ABRASF v2.03 – Campinas
+ Retorna XML SEM assinatura (assinatura deve ser aplicada depois).
+ """
+
+ NS_FAIXA = "http://www.ginfes.com.br/servico_consultar_nfse_faixa_envio_v03.xsd"
+ NS_PERIODO = "http://www.ginfes.com.br/servico_consultar_nfse_servico_envio_v03.xsd"
+
def consultar_periodo(self, emitente, data_inicio, data_fim, pagina=1):
- return {
- "Prestador": {
- "CpfCnpj": {
- "Cnpj": emitente.cnpj
- },
- "InscricaoMunicipal": emitente.inscricao_municipal
- },
- "PeriodoEmissao": {
- "DataInicial": data_inicio,
- "DataFinal": data_fim
- },
- "Pagina": pagina
- }
+ raiz = etree.Element(
+ "ConsultarNfseServicoPrestadoEnvio",
+ xmlns=self.NS_PERIODO
+ )
+
+ prestador = etree.SubElement(raiz, "Prestador")
+ cpf_cnpj = etree.SubElement(prestador, "CpfCnpj")
+ etree.SubElement(cpf_cnpj, "Cnpj").text = emitente.cnpj
+ etree.SubElement(prestador, "InscricaoMunicipal").text = emitente.inscricao_municipal
+
+ periodo = etree.SubElement(raiz, "PeriodoEmissao")
+ etree.SubElement(periodo, "DataInicial").text = data_inicio
+ etree.SubElement(periodo, "DataFinal").text = data_fim
+
+ etree.SubElement(raiz, "Pagina").text = str(pagina)
+
+ return raiz
+
def consultar_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
- return {
- "Prestador": {
- "CpfCnpj": {
- "Cnpj": emitente.cnpj
- },
- "InscricaoMunicipal": emitente.inscricao_municipal
- },
- "Faixa": {
- "NumeroNfseInicial": numero_inicial,
- "NumeroNfseFinal": numero_final
- },
- "Pagina": pagina
- }
+ raiz = etree.Element(
+ "ConsultarNfseFaixaEnvio",
+ xmlns=self.NS_FAIXA
+ )
+
+ prestador = etree.SubElement(raiz, "Prestador")
+ cpf_cnpj = etree.SubElement(prestador, "CpfCnpj")
+ etree.SubElement(cpf_cnpj, "Cnpj").text = emitente.cnpj
+ etree.SubElement(prestador, "InscricaoMunicipal").text = emitente.inscricao_municipal
+
+ faixa = etree.SubElement(raiz, "Faixa")
+ etree.SubElement(faixa, "NumeroNfseInicial").text = str(numero_inicial)
+ etree.SubElement(faixa, "NumeroNfseFinal").text = str(numero_final)
+
+ etree.SubElement(raiz, "Pagina").text = str(pagina)
+
+ return raiz
class SerializacaoBetha(InterfaceAutorizador):
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index c337306b..e6f5b5dc 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -773,7 +773,7 @@ def consultar_rps(self, payload):
from pynfe.processamento.autorizador_nfse import SerializacaoCampinas
cabecalho = SerializacaoCampinas().cabecalho()
- return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA_RPS"], cabecalho, payload)
+ return self._post_https(url, NFSE[self.autorizador]["CONSULTA_RPS"], cabecalho, payload)
elif self.autorizador == "OSASCO":
# comunica via wsdl
return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA"], payload)
@@ -784,7 +784,7 @@ def consultar_faixa(self, payload):
# url do serviço
url = self._get_url()
if self.autorizador == "CAMPINAS":
- return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA_FAIXA"], payload)
+ return self._post_https(url, NFSE[self.autorizador]["CONSULTA_FAIXA"], payload)
elif self.autorizador == "OSASCO":
# comunica via wsdl
return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA"], payload)
@@ -795,10 +795,10 @@ def consultar_periodo(self, payload):
# url do serviço
url = self._get_url()
if self.autorizador == "CAMPINAS":
- return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA_SERVICO"], payload)
+ return self._post_https(url, NFSE[self.autorizador]["CONSULTA_SERVICO"], payload)
elif self.autorizador == "OSASCO":
# comunica via wsdl
- return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA"], payloadpayload)
+ return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA"], payload)
else:
raise Exception("Este método não esta implementado para o autorizador.")
@@ -895,7 +895,7 @@ def _post(self, url, xml, metodo):
except Exception as e:
raise e
- def _post_https(self, url, xml, metodo):
+ def _post_https(self, url, metodo, xml):
"""Comunicação wsdl (https) utilizando certificado do usuário"""
# cabecalho
cabecalho = self._cabecalho()
@@ -904,40 +904,15 @@ def _post_https(self, url, xml, metodo):
from pynfe.utils.https_nfse import HttpAuthenticated
from suds.client import Client
- certificadoA1 = CertificadoA1(self.certificado)
- chave, cert = certificadoA1.separar_arquivo(self.certificado_senha, caminho=True)
+ certificado_a1 = CertificadoA1(self.certificado)
- wsdl = url # ?wsdl
- endpoint = url.replace("?wsdl", "") # REMOVE ?wsdl
+ chave, cert = certificado_a1.separar_arquivo(self.certificado_senha, caminho=True)
- cliente = Client(
- wsdl,
- transport=HttpAuthenticated(
- key=chave, cert=cert, endereco=endpoint # ✅ endpoint correto
- ),
- )
+ cliente = Client(url, transport=HttpAuthenticated(key=chave, cert=cert, endereco=url))
# gerar nfse
- if metodo == "gerar":
- return cliente.service.GerarNfse(cabecalho, xml)
- elif metodo == "enviar_lote":
- return cliente.service.RecepcionarLoteRpsV3(cabecalho, xml)
- elif metodo == "consulta":
- return cliente.service.ConsultarNfseV3(cabecalho, xml)
- elif metodo == "consulta_lote":
- return cliente.service.ConsultarLoteRpsV3(cabecalho, xml)
- elif metodo == "consulta_situacao_lote":
- return cliente.service.ConsultarSituacaoLoteRpsV3(cabecalho, xml)
- elif metodo == "consultaRps":
- return cliente.service.ConsultarNfsePorRpsV3(cabecalho, xml)
- elif metodo == "consultaFaixa":
- return cliente.service.ConsultarNfseFaixa(cabecalho, xml)
- elif metodo == "cancelar":
- # versão 2
- return cliente.service.CancelarNfse(xml)
- # versão 3
- # return cliente.service.CancelarNfseV3(cabecalho, xml)
- # TODO outros metodos
+ if metodo == "ConsultarNfseServicoPrestado":
+ return cliente.service.ConsultarNfseServicoPrestado(cabecalho, xml)
else:
raise Exception("Método não implementado no autorizador.")
except Exception as e:
From 341f9b142c3f5e31f8ced787447a1ec64613ba20 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 00:32:22 -0300
Subject: [PATCH 107/175] =?UTF-8?q?remove=20importa=C3=A7=C3=B5es=20desnec?=
=?UTF-8?q?ess=C3=A1rias=20e=20adiciona=20m=C3=A9todo=20para=20gerar=20ID?=
=?UTF-8?q?=20nas=20classes=20de=20serializa=C3=A7=C3=A3o=20de=20Campinas?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index 7396526f..bc239db5 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -43,10 +43,6 @@ def consultar(
"NumeroReciboUnico": numero_rps_unico,
}
-from lxml import etree
-from pynfe.processamento.autorizador_nfse import InterfaceAutorizador
-
-
class SerializacaoCampinas(InterfaceAutorizador):
"""
Serialização ABRASF v2.03 – Campinas
@@ -56,10 +52,15 @@ class SerializacaoCampinas(InterfaceAutorizador):
NS_FAIXA = "http://www.ginfes.com.br/servico_consultar_nfse_faixa_envio_v03.xsd"
NS_PERIODO = "http://www.ginfes.com.br/servico_consultar_nfse_servico_envio_v03.xsd"
+ def _gerar_id(self, prefixo):
+ # padrão aceito por Campinas / GINFES
+ return f"{prefixo}{uuid.uuid4().hex.upper()}"
+
def consultar_periodo(self, emitente, data_inicio, data_fim, pagina=1):
raiz = etree.Element(
"ConsultarNfseServicoPrestadoEnvio",
- xmlns=self.NS_PERIODO
+ xmlns=self.NS_PERIODO,
+ Id=self._gerar_id("CNFSEPERIODO")
)
prestador = etree.SubElement(raiz, "Prestador")
@@ -78,7 +79,8 @@ def consultar_periodo(self, emitente, data_inicio, data_fim, pagina=1):
def consultar_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
raiz = etree.Element(
"ConsultarNfseFaixaEnvio",
- xmlns=self.NS_FAIXA
+ xmlns=self.NS_FAIXA,
+ Id=self._gerar_id("CNFSEFAIXA")
)
prestador = etree.SubElement(raiz, "Prestador")
@@ -94,7 +96,6 @@ def consultar_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
return raiz
-
class SerializacaoBetha(InterfaceAutorizador):
def __init__(self):
# importa
From 0c043de964b724a740007b7a6401b89ecddcb73f Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 00:34:44 -0300
Subject: [PATCH 108/175] =?UTF-8?q?ajusta=20tratamento=20de=20exce=C3=A7?=
=?UTF-8?q?=C3=B5es=20na=20classe=20ComunicacaoNfse=20para=20verificar=20a?=
=?UTF-8?q?=20disponibilidade=20do=20m=C3=A9todo=20antes=20da=20chamada?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index e6f5b5dc..51adf0ea 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -911,10 +911,11 @@ def _post_https(self, url, metodo, xml):
cliente = Client(url, transport=HttpAuthenticated(key=chave, cert=cert, endereco=url))
# gerar nfse
- if metodo == "ConsultarNfseServicoPrestado":
- return cliente.service.ConsultarNfseServicoPrestado(cabecalho, xml)
- else:
- raise Exception("Método não implementado no autorizador.")
+ try:
+ service = getattr(cliente.service, metodo)
+ except AttributeError:
+ raise ValueError(f"Método '{metodo}' não disponível para {self.autorizador}.")
+ return service(cabecalho, xml)
except Exception as e:
raise e
From 48c3606351dd6abc619ec55b89bbf4e6ee29a1a3 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 00:35:49 -0300
Subject: [PATCH 109/175] =?UTF-8?q?ajusta=20chamada=20do=20m=C3=A9todo=20n?=
=?UTF-8?q?a=20classe=20ComunicacaoNfse=20para=20remover=20o=20par=C3=A2me?=
=?UTF-8?q?tro=20desnecess=C3=A1rio?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 51adf0ea..06725d2b 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -915,7 +915,7 @@ def _post_https(self, url, metodo, xml):
service = getattr(cliente.service, metodo)
except AttributeError:
raise ValueError(f"Método '{metodo}' não disponível para {self.autorizador}.")
- return service(cabecalho, xml)
+ return service(xml)
except Exception as e:
raise e
From 14b93b0eb19a46a2bc78bc2a66932cc6fb1918c0 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 00:42:21 -0300
Subject: [PATCH 110/175] =?UTF-8?q?ajusta=20a=20classe=20ComunicacaoNfse?=
=?UTF-8?q?=20para=20utilizar=20comunica=C3=A7=C3=A3o=20SOAP=20em=20vez=20?=
=?UTF-8?q?de=20HTTPS=20para=20o=20autorizador=20CAMPINAS?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 06725d2b..57b99be3 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -770,10 +770,7 @@ def consultar_rps(self, payload):
# url do serviço
url = self._get_url()
if self.autorizador == "CAMPINAS":
- from pynfe.processamento.autorizador_nfse import SerializacaoCampinas
-
- cabecalho = SerializacaoCampinas().cabecalho()
- return self._post_https(url, NFSE[self.autorizador]["CONSULTA_RPS"], cabecalho, payload)
+ return self._post_soap_raw(url, payload)
elif self.autorizador == "OSASCO":
# comunica via wsdl
return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA"], payload)
@@ -784,7 +781,7 @@ def consultar_faixa(self, payload):
# url do serviço
url = self._get_url()
if self.autorizador == "CAMPINAS":
- return self._post_https(url, NFSE[self.autorizador]["CONSULTA_FAIXA"], payload)
+ return self._post_soap_raw(url, payload)
elif self.autorizador == "OSASCO":
# comunica via wsdl
return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA"], payload)
@@ -795,7 +792,7 @@ def consultar_periodo(self, payload):
# url do serviço
url = self._get_url()
if self.autorizador == "CAMPINAS":
- return self._post_https(url, NFSE[self.autorizador]["CONSULTA_SERVICO"], payload)
+ return self._post_soap_raw(url, payload)
elif self.autorizador == "OSASCO":
# comunica via wsdl
return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA"], payload)
@@ -894,6 +891,14 @@ def _post(self, url, xml, metodo):
raise Exception("Método não implementado no autorizador.")
except Exception as e:
raise e
+ def _post_soap_raw(self, url, soap_xml):
+ return requests.post(
+ url,
+ data=soap_xml.encode("utf-8"),
+ cert=(cert, key),
+ verify=False,
+ headers={"Content-Type": "text/xml; charset=utf-8"}
+ )
def _post_https(self, url, metodo, xml):
"""Comunicação wsdl (https) utilizando certificado do usuário"""
From b8c2ed6170f6116a7cdd42156eb27589316cb1fb Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 00:43:22 -0300
Subject: [PATCH 111/175] =?UTF-8?q?adiciona=20separa=C3=A7=C3=A3o=20de=20a?=
=?UTF-8?q?rquivo=20de=20certificado=20na=20classe=20ComunicacaoNfse=20par?=
=?UTF-8?q?a=20uso=20em=20requisi=C3=A7=C3=B5es=20SOAP?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 57b99be3..effc6b78 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -892,6 +892,8 @@ def _post(self, url, xml, metodo):
except Exception as e:
raise e
def _post_soap_raw(self, url, soap_xml):
+ certificado_a1 = CertificadoA1(self.certificado)
+ key, cert = certificado_a1.separar_arquivo(self.certificado_senha, caminho=True)
return requests.post(
url,
data=soap_xml.encode("utf-8"),
From 518140d45cfbbd55261108f74a6187b94718423e Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 00:48:01 -0300
Subject: [PATCH 112/175] =?UTF-8?q?adiciona=20m=C3=A9todos=20para=20gerar?=
=?UTF-8?q?=20cabe=C3=A7alho=20e=20envelope=20SOAP=20na=20classe=20Seriali?=
=?UTF-8?q?zacaoCampinas?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 48 +++++++++++++++++++++----
1 file changed, 42 insertions(+), 6 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index bc239db5..286cc09c 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -42,20 +42,46 @@ def consultar(
"NumeroReciboFinal": numero_rps_final,
"NumeroReciboUnico": numero_rps_unico,
}
-
class SerializacaoCampinas(InterfaceAutorizador):
"""
Serialização ABRASF v2.03 – Campinas
- Retorna XML SEM assinatura (assinatura deve ser aplicada depois).
+ Retorna SOAP XML (SEM assinatura).
+ Assinatura e envio ficam fora.
"""
NS_FAIXA = "http://www.ginfes.com.br/servico_consultar_nfse_faixa_envio_v03.xsd"
NS_PERIODO = "http://www.ginfes.com.br/servico_consultar_nfse_servico_envio_v03.xsd"
def _gerar_id(self, prefixo):
- # padrão aceito por Campinas / GINFES
return f"{prefixo}{uuid.uuid4().hex.upper()}"
+ def _cabecalho(self):
+ return """
+
+ 2.03
+
+ """.strip()
+
+ def _soap_envelope(self, metodo, xml_envio):
+ """
+ Envolve o XML de envio no SOAP 1.1 correto
+ """
+ return f"""
+
+
+
+
+ {self._cabecalho()}
+ {xml_envio}
+
+
+
+ """.strip()
+
+ # -------------------------
+ # CONSULTAR POR PERÍODO
+ # -------------------------
def consultar_periodo(self, emitente, data_inicio, data_fim, pagina=1):
raiz = etree.Element(
"ConsultarNfseServicoPrestadoEnvio",
@@ -74,8 +100,15 @@ def consultar_periodo(self, emitente, data_inicio, data_fim, pagina=1):
etree.SubElement(raiz, "Pagina").text = str(pagina)
- return raiz
+ xml_envio = etree.tostring(raiz, encoding="utf-8").decode()
+ return self._soap_envelope(
+ "ConsultarNfseServicoPrestado",
+ xml_envio
+ )
+ # -------------------------
+ # CONSULTAR POR FAIXA
+ # -------------------------
def consultar_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
raiz = etree.Element(
"ConsultarNfseFaixaEnvio",
@@ -94,8 +127,11 @@ def consultar_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
etree.SubElement(raiz, "Pagina").text = str(pagina)
- return raiz
-
+ xml_envio = etree.tostring(raiz, encoding="utf-8").decode()
+ return self._soap_envelope(
+ "ConsultarNfseFaixa",
+ xml_envio
+ )
class SerializacaoBetha(InterfaceAutorizador):
def __init__(self):
# importa
From 64fdf69ca189c08e438217b542a066c16389b77a Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 00:49:14 -0300
Subject: [PATCH 113/175] =?UTF-8?q?ajusta=20a=20busca=20da=20refer=C3=AAnc?=
=?UTF-8?q?ia=20na=20fun=C3=A7=C3=A3o=20assinar=20da=20classe=20Assinatura?=
=?UTF-8?q?A1=20para=20utilizar=20find=20em=20vez=20de=20xpath?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/assinatura.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pynfe/processamento/assinatura.py b/pynfe/processamento/assinatura.py
index 70b3b856..50c5e263 100644
--- a/pynfe/processamento/assinatura.py
+++ b/pynfe/processamento/assinatura.py
@@ -29,7 +29,7 @@ def __init__(self, certificado, senha):
def assinar(self, xml: etree._Element, retorna_string=False) -> Union[str, etree._Element]:
# busca tag que tem id(reference_uri), logo nao importa se tem namespace
- reference = xml.xpath('//*[@Id]')[0].attrib['Id']
+ reference = xml.find(".//*[@Id]").attrib["Id"]
# retira acentos
xml_str = remover_acentos(etree.tostring(xml, encoding="unicode", pretty_print=False))
From 866a655f2ae88f1d97931fde4cc4db2e968dd46b Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 01:05:44 -0300
Subject: [PATCH 114/175] =?UTF-8?q?altera=20m=C3=A9todo=20=5Fsoap=5Fenvelo?=
=?UTF-8?q?pe=20para=20soap=5Fenvelope=20na=20classe=20SerializacaoCampina?=
=?UTF-8?q?s=20e=20atualiza=20chamadas=20na=20classe=20ComunicacaoNfse=20p?=
=?UTF-8?q?ara=20usar=20o=20novo=20m=C3=A9todo?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 2 +-
pynfe/processamento/comunicacao.py | 12 +++++++++---
2 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index 286cc09c..920e22b1 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -62,7 +62,7 @@ def _cabecalho(self):
""".strip()
- def _soap_envelope(self, metodo, xml_envio):
+ def soap_envelope(self, metodo, xml_envio):
"""
Envolve o XML de envio no SOAP 1.1 correto
"""
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index effc6b78..57ae2658 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -770,7 +770,9 @@ def consultar_rps(self, payload):
# url do serviço
url = self._get_url()
if self.autorizador == "CAMPINAS":
- return self._post_soap_raw(url, payload)
+ from pynfe.processamento.autorizador_nfse import SerializacaoCampinas
+ soup_xml = SerializacaoCampinas().soap_envelope(NFSE[self.autorizador]["CONSULTA_RPS"], payload)
+ return self._post_soap_raw(url, soup_xml)
elif self.autorizador == "OSASCO":
# comunica via wsdl
return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA"], payload)
@@ -781,7 +783,9 @@ def consultar_faixa(self, payload):
# url do serviço
url = self._get_url()
if self.autorizador == "CAMPINAS":
- return self._post_soap_raw(url, payload)
+ from pynfe.processamento.autorizador_nfse import SerializacaoCampinas
+ soup_xml = SerializacaoCampinas().soap_envelope(NFSE[self.autorizador]["CONSULTA_FAIXA"], payload)
+ return self._post_soap_raw(url, soup_xml)
elif self.autorizador == "OSASCO":
# comunica via wsdl
return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA"], payload)
@@ -792,7 +796,9 @@ def consultar_periodo(self, payload):
# url do serviço
url = self._get_url()
if self.autorizador == "CAMPINAS":
- return self._post_soap_raw(url, payload)
+ from pynfe.processamento.autorizador_nfse import SerializacaoCampinas
+ soup_xml = SerializacaoCampinas().soap_envelope(NFSE[self.autorizador]["CONSULTA_SERVICO"], payload)
+ return self._post_soap_raw(url, soup_xml)
elif self.autorizador == "OSASCO":
# comunica via wsdl
return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA"], payload)
From ce9c264fcb92988d4f338b6d4da8fc0158386377 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 01:06:47 -0300
Subject: [PATCH 115/175] =?UTF-8?q?remove=20chamadas=20ao=20m=C3=A9todo=20?=
=?UTF-8?q?=5Fsoap=5Fenvelope=20nas=20fun=C3=A7=C3=B5es=20consultar=5Fperi?=
=?UTF-8?q?odo=20e=20consultar=5Ffaixa=20da=20classe=20SerializacaoCampina?=
=?UTF-8?q?s,=20retornando=20diretamente=20o=20XML=20gerado?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 26 ++++++++++---------------
1 file changed, 10 insertions(+), 16 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index 920e22b1..e5e9999d 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -42,6 +42,8 @@ def consultar(
"NumeroReciboFinal": numero_rps_final,
"NumeroReciboUnico": numero_rps_unico,
}
+
+
class SerializacaoCampinas(InterfaceAutorizador):
"""
Serialização ABRASF v2.03 – Campinas
@@ -86,7 +88,7 @@ def consultar_periodo(self, emitente, data_inicio, data_fim, pagina=1):
raiz = etree.Element(
"ConsultarNfseServicoPrestadoEnvio",
xmlns=self.NS_PERIODO,
- Id=self._gerar_id("CNFSEPERIODO")
+ Id=self._gerar_id("CNFSEPERIODO"),
)
prestador = etree.SubElement(raiz, "Prestador")
@@ -101,19 +103,14 @@ def consultar_periodo(self, emitente, data_inicio, data_fim, pagina=1):
etree.SubElement(raiz, "Pagina").text = str(pagina)
xml_envio = etree.tostring(raiz, encoding="utf-8").decode()
- return self._soap_envelope(
- "ConsultarNfseServicoPrestado",
- xml_envio
- )
+ return xml_envio
# -------------------------
# CONSULTAR POR FAIXA
# -------------------------
def consultar_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
raiz = etree.Element(
- "ConsultarNfseFaixaEnvio",
- xmlns=self.NS_FAIXA,
- Id=self._gerar_id("CNFSEFAIXA")
+ "ConsultarNfseFaixaEnvio", xmlns=self.NS_FAIXA, Id=self._gerar_id("CNFSEFAIXA")
)
prestador = etree.SubElement(raiz, "Prestador")
@@ -128,10 +125,9 @@ def consultar_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
etree.SubElement(raiz, "Pagina").text = str(pagina)
xml_envio = etree.tostring(raiz, encoding="utf-8").decode()
- return self._soap_envelope(
- "ConsultarNfseFaixa",
- xml_envio
- )
+ return xml_envio
+
+
class SerializacaoBetha(InterfaceAutorizador):
def __init__(self):
# importa
@@ -374,11 +370,11 @@ def serializar_lote_sincrono(self, nfse):
return gnfse.toxml(encoding="utf-8", element_name="EnviarLoteRpsSincronoEnvio")
-
+
class SerializacaoGinfes(InterfaceAutorizador):
def __init__(self):
pass
-
+
def consultar_servico_prestado(self, emitente, data_inicio, data_fim, pagina=1):
NS = "http://www.ginfes.com.br/servico_consultar_nfse_servico_prestado_envio_v03.xsd"
DS = "http://www.w3.org/2000/09/xmldsig#"
@@ -448,5 +444,3 @@ def cabecalho(self):
versao_dados.text = "3"
return etree.tostring(cabecalho, encoding="utf-8", xml_declaration=True)
-
-
From d74fe39c43edfa05f7c01f6d844a7b46571d2fad Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 01:11:03 -0300
Subject: [PATCH 116/175] =?UTF-8?q?remove=20convers=C3=A3o=20para=20string?=
=?UTF-8?q?=20no=20retorno=20das=20fun=C3=A7=C3=B5es=20consultar=5Fperiodo?=
=?UTF-8?q?=20e=20consultar=5Ffaixa=20da=20classe=20SerializacaoCampinas,?=
=?UTF-8?q?=20retornando=20o=20objeto=20XML=20diretamente?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index e5e9999d..afd2f541 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -102,8 +102,7 @@ def consultar_periodo(self, emitente, data_inicio, data_fim, pagina=1):
etree.SubElement(raiz, "Pagina").text = str(pagina)
- xml_envio = etree.tostring(raiz, encoding="utf-8").decode()
- return xml_envio
+ return raiz
# -------------------------
# CONSULTAR POR FAIXA
@@ -124,8 +123,7 @@ def consultar_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
etree.SubElement(raiz, "Pagina").text = str(pagina)
- xml_envio = etree.tostring(raiz, encoding="utf-8").decode()
- return xml_envio
+ return raiz
class SerializacaoBetha(InterfaceAutorizador):
From ca001e08f0154d078e83db0b8629e3d2da7a0910 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 01:12:42 -0300
Subject: [PATCH 117/175] =?UTF-8?q?altera=20busca=20da=20refer=C3=AAncia?=
=?UTF-8?q?=20na=20fun=C3=A7=C3=A3o=20assinar=20da=20classe=20AssinaturaA1?=
=?UTF-8?q?=20para=20utilizar=20xpath=20em=20vez=20de=20find?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/assinatura.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pynfe/processamento/assinatura.py b/pynfe/processamento/assinatura.py
index 50c5e263..70b3b856 100644
--- a/pynfe/processamento/assinatura.py
+++ b/pynfe/processamento/assinatura.py
@@ -29,7 +29,7 @@ def __init__(self, certificado, senha):
def assinar(self, xml: etree._Element, retorna_string=False) -> Union[str, etree._Element]:
# busca tag que tem id(reference_uri), logo nao importa se tem namespace
- reference = xml.find(".//*[@Id]").attrib["Id"]
+ reference = xml.xpath('//*[@Id]')[0].attrib['Id']
# retira acentos
xml_str = remover_acentos(etree.tostring(xml, encoding="unicode", pretty_print=False))
From f9909129eaecaf660e436d5364fd2f4e7488f8f0 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 01:15:52 -0300
Subject: [PATCH 118/175] =?UTF-8?q?adiciona=20m=C3=A9todo=20=5Fcorrigir=5F?=
=?UTF-8?q?prefixo=5Fds=20na=20classe=20SerializacaoCampinas=20para=20corr?=
=?UTF-8?q?igir=20namespaces=20e=20assinar=20XML?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 29 ++++++++++++++++++++++++-
1 file changed, 28 insertions(+), 1 deletion(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index afd2f541..4bc2e088 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -53,6 +53,7 @@ class SerializacaoCampinas(InterfaceAutorizador):
NS_FAIXA = "http://www.ginfes.com.br/servico_consultar_nfse_faixa_envio_v03.xsd"
NS_PERIODO = "http://www.ginfes.com.br/servico_consultar_nfse_servico_envio_v03.xsd"
+ DS_NS = "http://www.w3.org/2000/09/xmldsig#"
def _gerar_id(self, prefixo):
return f"{prefixo}{uuid.uuid4().hex.upper()}"
@@ -63,6 +64,32 @@ def _cabecalho(self):
2.03
""".strip()
+
+ def _corrigir_prefixo_ds(self, xml_str: str) -> str:
+ parser = etree.XMLParser(remove_blank_text=True)
+ root = etree.fromstring(xml_str.encode(), parser)
+
+ nsmap = root.nsmap.copy()
+ if "ds" not in nsmap:
+ nsmap["ds"] = self.DS_NS
+
+ signature = root.find(f".//{{{self.DS_NS}}}Signature")
+ if signature is None:
+ raise ValueError("Signature não encontrada")
+
+ signature.tag = f"{{{self.DS_NS}}}Signature"
+ for elem in signature.iter():
+ if elem.tag.startswith("{"):
+ ns, local = elem.tag[1:].split("}")
+ elem.tag = f"{{{ns}}}{local}"
+
+ etree.cleanup_namespaces(root)
+
+ return etree.tostring(
+ root,
+ encoding="utf-8",
+ xml_declaration=False
+ ).decode()
def soap_envelope(self, metodo, xml_envio):
"""
@@ -75,7 +102,7 @@ def soap_envelope(self, metodo, xml_envio):
{self._cabecalho()}
- {xml_envio}
+ {self._corrigir_prefixo_ds(xml_envio)}
From 4f748d1bbe3e30ce9207530cd00bf32faadd5c7f Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 01:24:46 -0300
Subject: [PATCH 119/175] =?UTF-8?q?altera=20m=C3=A9todo=20=5Fcorrigir=5Fpr?=
=?UTF-8?q?efixo=5Fds=20para=20=5Fajustar=5Fassinatura=20na=20classe=20Ser?=
=?UTF-8?q?ializacaoCampinas,=20ajustando=20a=20assinatura=20XML=20para=20?=
=?UTF-8?q?o=20namespace=20correto?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 41 ++++++++++++-------------
1 file changed, 20 insertions(+), 21 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index 4bc2e088..453cefb6 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -65,32 +65,31 @@ def _cabecalho(self):
""".strip()
- def _corrigir_prefixo_ds(self, xml_str: str) -> str:
- parser = etree.XMLParser(remove_blank_text=True)
- root = etree.fromstring(xml_str.encode(), parser)
-
- nsmap = root.nsmap.copy()
- if "ds" not in nsmap:
- nsmap["ds"] = self.DS_NS
+ def _ajustar_assinatura(self, xml_assinado: etree.Element) -> etree.Element:
+ """
+ Move para nfse:Signature
+ Mantém SignedInfo / Reference / etc em ds
+ """
+ ns = {"ds": self.DS_NS}
- signature = root.find(f".//{{{self.DS_NS}}}Signature")
+ signature = xml_assinado.find(".//ds:Signature", namespaces=ns)
if signature is None:
- raise ValueError("Signature não encontrada")
+ raise ValueError("Signature não encontrada no XML assinado")
- signature.tag = f"{{{self.DS_NS}}}Signature"
- for elem in signature.iter():
- if elem.tag.startswith("{"):
- ns, local = elem.tag[1:].split("}")
- elem.tag = f"{{{ns}}}{local}"
+ parent = signature.getparent()
+ parent.remove(signature)
- etree.cleanup_namespaces(root)
+ nfse_signature = etree.Element(
+ f"{{{self.NFSE_NS}}}Signature",
+ nsmap={"ds": self.DS_NS}
+ )
- return etree.tostring(
- root,
- encoding="utf-8",
- xml_declaration=False
- ).decode()
+ for child in signature:
+ nfse_signature.append(child)
+ parent.append(nfse_signature)
+ return etree.tostring(xml_assinado, encoding="unicode", pretty_print=False)
+
def soap_envelope(self, metodo, xml_envio):
"""
Envolve o XML de envio no SOAP 1.1 correto
@@ -102,7 +101,7 @@ def soap_envelope(self, metodo, xml_envio):
{self._cabecalho()}
- {self._corrigir_prefixo_ds(xml_envio)}
+ {self._ajustar_assinatura(xml_envio)}
From a70db63a652211d544d2a4a119137a3c2b3b37f7 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 01:27:07 -0300
Subject: [PATCH 120/175] adiciona namespace NFSE na classe
SerializacaoCampinas e corrige busca da assinatura no XML
---
pynfe/processamento/autorizador_nfse.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index 453cefb6..201cd3af 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -54,6 +54,7 @@ class SerializacaoCampinas(InterfaceAutorizador):
NS_FAIXA = "http://www.ginfes.com.br/servico_consultar_nfse_faixa_envio_v03.xsd"
NS_PERIODO = "http://www.ginfes.com.br/servico_consultar_nfse_servico_envio_v03.xsd"
DS_NS = "http://www.w3.org/2000/09/xmldsig#"
+ NFSE_NS = "http://nfse.abrasf.org.br"
def _gerar_id(self, prefixo):
return f"{prefixo}{uuid.uuid4().hex.upper()}"
@@ -72,7 +73,7 @@ def _ajustar_assinatura(self, xml_assinado: etree.Element) -> etree.Element:
"""
ns = {"ds": self.DS_NS}
- signature = xml_assinado.find(".//ds:Signature", namespaces=ns)
+ signature = xml_assinado.find(".//ds:Signature", ns)
if signature is None:
raise ValueError("Signature não encontrada no XML assinado")
From 7b8c966b5c718827887a063256e8faab7c4349d7 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 01:28:57 -0300
Subject: [PATCH 121/175] =?UTF-8?q?ajusta=20a=20assinatura=20XML=20na=20cl?=
=?UTF-8?q?asse=20SerializacaoCampinas,=20garantindo=20a=20convers=C3=A3o?=
=?UTF-8?q?=20de=20string=20para=20Element=20e=20atualizando=20o=20namespa?=
=?UTF-8?q?ce?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index 201cd3af..990a0104 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -71,7 +71,11 @@ def _ajustar_assinatura(self, xml_assinado: etree.Element) -> etree.Element:
Move para nfse:Signature
Mantém SignedInfo / Reference / etc em ds
"""
- ns = {"ds": self.DS_NS}
+ ns = {"ds": "http://www.w3.org/2000/09/xmldsig#"}
+
+ # 🔴 GARANTIA: converter string → Element
+ if isinstance(xml_assinado, str):
+ xml_assinado = etree.fromstring(xml_assinado.encode("utf-8"))
signature = xml_assinado.find(".//ds:Signature", ns)
if signature is None:
@@ -82,14 +86,19 @@ def _ajustar_assinatura(self, xml_assinado: etree.Element) -> etree.Element:
nfse_signature = etree.Element(
f"{{{self.NFSE_NS}}}Signature",
- nsmap={"ds": self.DS_NS}
+ nsmap={"ds": ns["ds"]}
)
for child in signature:
nfse_signature.append(child)
parent.append(nfse_signature)
- return etree.tostring(xml_assinado, encoding="unicode", pretty_print=False)
+
+ return etree.tostring(
+ xml_assinado,
+ encoding="utf-8",
+ xml_declaration=False
+ ).decode()
def soap_envelope(self, metodo, xml_envio):
"""
From a13604bf827306e689fbe7b444bf53c1fa743b19 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 01:32:50 -0300
Subject: [PATCH 122/175] =?UTF-8?q?adiciona=20impress=C3=A3o=20do=20XML=20?=
=?UTF-8?q?gerado=20na=20classe=20ComunicacaoNfse=20para=20depura=C3=A7?=
=?UTF-8?q?=C3=A3o?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 57ae2658..398a5519 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -785,6 +785,7 @@ def consultar_faixa(self, payload):
if self.autorizador == "CAMPINAS":
from pynfe.processamento.autorizador_nfse import SerializacaoCampinas
soup_xml = SerializacaoCampinas().soap_envelope(NFSE[self.autorizador]["CONSULTA_FAIXA"], payload)
+ print(soup_xml)
return self._post_soap_raw(url, soup_xml)
elif self.autorizador == "OSASCO":
# comunica via wsdl
@@ -798,6 +799,7 @@ def consultar_periodo(self, payload):
if self.autorizador == "CAMPINAS":
from pynfe.processamento.autorizador_nfse import SerializacaoCampinas
soup_xml = SerializacaoCampinas().soap_envelope(NFSE[self.autorizador]["CONSULTA_SERVICO"], payload)
+ print(soup_xml)
return self._post_soap_raw(url, soup_xml)
elif self.autorizador == "OSASCO":
# comunica via wsdl
From d0b2474c721b8ea6cd0f6a09d1caabba2576e79f Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 01:35:13 -0300
Subject: [PATCH 123/175] =?UTF-8?q?ajusta=20m=C3=A9todo=20=5Fajustar=5Fass?=
=?UTF-8?q?inatura=20na=20classe=20SerializacaoCampinas=20para=20converter?=
=?UTF-8?q?=20a=20assinatura=20XML=20para=20o=20namespace=20NFSE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 45 +++++++++++++++++++------
1 file changed, 34 insertions(+), 11 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index 990a0104..a17dd1b8 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -66,36 +66,59 @@ def _cabecalho(self):
""".strip()
- def _ajustar_assinatura(self, xml_assinado: etree.Element) -> etree.Element:
+ def _ajustar_assinatura(self, xml_assinado) -> str:
"""
- Move para nfse:Signature
- Mantém SignedInfo / Reference / etc em ds
+ Converte:
+ ...
+
+ Para:
+
+
+
+
+
"""
- ns = {"ds": "http://www.w3.org/2000/09/xmldsig#"}
- # 🔴 GARANTIA: converter string → Element
+ NFSE_NS = "http://nfse.abrasf.org.br"
+ DS_NS = "http://www.w3.org/2000/09/xmldsig#"
+
+ ns = {
+ "ds": DS_NS,
+ "nfse": NFSE_NS,
+ }
+
+ # garante Element
if isinstance(xml_assinado, str):
- xml_assinado = etree.fromstring(xml_assinado.encode("utf-8"))
+ root = etree.fromstring(xml_assinado.encode("utf-8"))
+ else:
+ root = xml_assinado
- signature = xml_assinado.find(".//ds:Signature", ns)
+ # acha ds:Signature
+ signature = root.find(".//ds:Signature", namespaces=ns)
if signature is None:
- raise ValueError("Signature não encontrada no XML assinado")
+ raise ValueError("ds:Signature não encontrada")
parent = signature.getparent()
parent.remove(signature)
+ # cria nfse:Signature EXPLÍCITO
nfse_signature = etree.Element(
- f"{{{self.NFSE_NS}}}Signature",
- nsmap={"ds": ns["ds"]}
+ f"{{{NFSE_NS}}}Signature",
+ nsmap={
+ "nfse": NFSE_NS,
+ "ds": DS_NS,
+ }
)
+ # move filhos ds:* para dentro
for child in signature:
nfse_signature.append(child)
+ # adiciona no MESMO ponto do XML
parent.append(nfse_signature)
return etree.tostring(
- xml_assinado,
+ root,
encoding="utf-8",
xml_declaration=False
).decode()
From 65679dce5bfdc5c2a06b86345d0293fda5ec178e Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 01:39:14 -0300
Subject: [PATCH 124/175] =?UTF-8?q?remove=20m=C3=A9todo=20=5Fajustar=5Fass?=
=?UTF-8?q?inatura=20da=20classe=20SerializacaoCampinas=20e=20ajusta=20cha?=
=?UTF-8?q?mada=20no=20m=C3=A9todo=20soap=5Fenvelope?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 59 +------------------------
1 file changed, 1 insertion(+), 58 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index a17dd1b8..7f7f825d 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -65,64 +65,7 @@ def _cabecalho(self):
2.03
""".strip()
-
- def _ajustar_assinatura(self, xml_assinado) -> str:
- """
- Converte:
- ...
-
- Para:
-
-
-
-
-
- """
-
- NFSE_NS = "http://nfse.abrasf.org.br"
- DS_NS = "http://www.w3.org/2000/09/xmldsig#"
-
- ns = {
- "ds": DS_NS,
- "nfse": NFSE_NS,
- }
-
- # garante Element
- if isinstance(xml_assinado, str):
- root = etree.fromstring(xml_assinado.encode("utf-8"))
- else:
- root = xml_assinado
-
- # acha ds:Signature
- signature = root.find(".//ds:Signature", namespaces=ns)
- if signature is None:
- raise ValueError("ds:Signature não encontrada")
-
- parent = signature.getparent()
- parent.remove(signature)
-
- # cria nfse:Signature EXPLÍCITO
- nfse_signature = etree.Element(
- f"{{{NFSE_NS}}}Signature",
- nsmap={
- "nfse": NFSE_NS,
- "ds": DS_NS,
- }
- )
-
- # move filhos ds:* para dentro
- for child in signature:
- nfse_signature.append(child)
-
- # adiciona no MESMO ponto do XML
- parent.append(nfse_signature)
- return etree.tostring(
- root,
- encoding="utf-8",
- xml_declaration=False
- ).decode()
-
def soap_envelope(self, metodo, xml_envio):
"""
Envolve o XML de envio no SOAP 1.1 correto
@@ -134,7 +77,7 @@ def soap_envelope(self, metodo, xml_envio):
{self._cabecalho()}
- {self._ajustar_assinatura(xml_envio)}
+ {xml_envio}
From 028b653ddfea628c763ee6e00638545429d49421 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 10:39:08 -0300
Subject: [PATCH 125/175] =?UTF-8?q?ajusta=20vers=C3=B5es=20das=20depend?=
=?UTF-8?q?=C3=AAncias=20lxml,=20signxml=20e=20suds-py3=20no=20setup.py?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
setup.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/setup.py b/setup.py
index c9a8171b..73ec0be0 100644
--- a/setup.py
+++ b/setup.py
@@ -32,9 +32,9 @@
install_requires=[
"pyopenssl>=23.0.0",
"requests",
- "lxml",
- "signxml",
- "suds-py3",
+ "lxml==6.0.2",
+ "signxml==3.1.0",
+ "suds-py3==1.4.5.0",
"zeep>=4.3.2",
],
extras_require={
From 77018b56c124efd51c5f1b31bf34f48285e0cee8 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 11:51:11 -0300
Subject: [PATCH 126/175] =?UTF-8?q?adiciona=20m=C3=A9todo=20=5Fsign=5Fxml?=
=?UTF-8?q?=20na=20classe=20SerializacaoCampinas=20para=20assinar=20XML=20?=
=?UTF-8?q?e=20atualiza=20m=C3=A9todo=20soap=5Fenvelope=20para=20incluir?=
=?UTF-8?q?=20assinatura?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 172 +++++++++++++++++++++---
pynfe/processamento/comunicacao.py | 6 +-
2 files changed, 160 insertions(+), 18 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index 7f7f825d..1cbe79af 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -65,23 +65,165 @@ def _cabecalho(self):
2.03
""".strip()
+ def _sign_xml(
+ self,
+ xml_element: etree._Element,
+ certificate_path: str,
+ certificate_password: str,
+ ) -> str:
+ DSIG_NS = "http://www.w3.org/2000/09/xmldsig#"
+
+ C14N_ALG = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"
+ SIGNATURE_ALG = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
+ DIGEST_ALG = "http://www.w3.org/2000/09/xmldsig#sha1"
+ ENVELOPED_ALG = "http://www.w3.org/2000/09/xmldsig#enveloped-signature"
+
+ # Garante que existe Id
+ element_id = xml_element.get("Id")
+ if not element_id:
+ raise ValueError("Elemento raiz precisa ter atributo Id para assinatura")
+
+ # Carrega certificado
+ with open(certificate_path, "rb") as f:
+ cert_data = f.read()
+
+ password = certificate_password.encode()
+ private_key, certificate, _ = pkcs12.load_key_and_certificates(
+ cert_data, password
+ )
+
+ if not private_key or not certificate:
+ raise ValueError("Falha ao carregar certificado")
+
+ cert_b64 = base64.b64encode(
+ certificate.public_bytes(Encoding.DER)
+ ).decode()
+
+ # Canonicaliza XML SEM assinatura
+ xml_c14n = etree.tostring(
+ xml_element, method="c14n", exclusive=False, with_comments=False
+ )
+
+ digest_value = base64.b64encode(
+ hashlib.sha1(xml_c14n).digest()
+ ).decode()
+
+ # ---------- SignedInfo ----------
+ signed_info = etree.Element(
+ "SignedInfo",
+ nsmap={None: DSIG_NS}
+ )
+
+ etree.SubElement(
+ signed_info,
+ "CanonicalizationMethod",
+ Algorithm=C14N_ALG
+ )
+
+ etree.SubElement(
+ signed_info,
+ "SignatureMethod",
+ Algorithm=SIGNATURE_ALG
+ )
+
+ reference = etree.SubElement(
+ signed_info,
+ "Reference",
+ URI=f"#{element_id}"
+ )
+
+ transforms = etree.SubElement(reference, "Transforms")
+
+ etree.SubElement(
+ transforms,
+ "Transform",
+ Algorithm=ENVELOPED_ALG
+ )
+
+ etree.SubElement(
+ transforms,
+ "Transform",
+ Algorithm=C14N_ALG
+ )
+
+ etree.SubElement(
+ reference,
+ "DigestMethod",
+ Algorithm=DIGEST_ALG
+ )
+
+ etree.SubElement(
+ reference,
+ "DigestValue"
+ ).text = digest_value
+
+ # Assina SignedInfo
+ signed_info_c14n = etree.tostring(
+ signed_info, method="c14n", exclusive=False, with_comments=False
+ )
+
+ signature_value = base64.b64encode(
+ private_key.sign(
+ signed_info_c14n,
+ padding.PKCS1v15(),
+ hashes.SHA1()
+ )
+ ).decode()
+
+ # ---------- Signature ----------
+ signature = etree.Element(
+ "Signature",
+ nsmap={None: DSIG_NS}
+ )
+
+ signature.append(signed_info)
+
+ etree.SubElement(
+ signature,
+ "SignatureValue"
+ ).text = signature_value
+
+ key_info = etree.SubElement(signature, "KeyInfo")
+ x509_data = etree.SubElement(key_info, "X509Data")
+ etree.SubElement(
+ x509_data,
+ "X509Certificate"
+ ).text = cert_b64
+
+ # Insere assinatura no XML
+ xml_element.append(signature)
+
+ return etree.tostring(
+ xml_element, encoding="unicode", pretty_print=False
+ )
+
+
+ def soap_envelope(
+ self,
+ metodo,
+ xml_envio_element,
+ certificate_path,
+ certificate_password,
+ ):
+ xml_assinado = self._sign_xml(
+ xml_envio_element,
+ certificate_path,
+ certificate_password,
+ )
- def soap_envelope(self, metodo, xml_envio):
- """
- Envolve o XML de envio no SOAP 1.1 correto
- """
return f"""
-
-
-
-
- {self._cabecalho()}
- {xml_envio}
-
-
-
- """.strip()
+
+
+
+
+ {self._cabecalho()}
+ {xml_assinado}
+
+
+
+ """.strip()
+
# -------------------------
# CONSULTAR POR PERÍODO
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 398a5519..f55d2b99 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -771,7 +771,7 @@ def consultar_rps(self, payload):
url = self._get_url()
if self.autorizador == "CAMPINAS":
from pynfe.processamento.autorizador_nfse import SerializacaoCampinas
- soup_xml = SerializacaoCampinas().soap_envelope(NFSE[self.autorizador]["CONSULTA_RPS"], payload)
+ soup_xml = SerializacaoCampinas().soap_envelope(NFSE[self.autorizador]["CONSULTA_RPS"], payload, self.certificado, self.certificado_senha)
return self._post_soap_raw(url, soup_xml)
elif self.autorizador == "OSASCO":
# comunica via wsdl
@@ -784,7 +784,7 @@ def consultar_faixa(self, payload):
url = self._get_url()
if self.autorizador == "CAMPINAS":
from pynfe.processamento.autorizador_nfse import SerializacaoCampinas
- soup_xml = SerializacaoCampinas().soap_envelope(NFSE[self.autorizador]["CONSULTA_FAIXA"], payload)
+ soup_xml = SerializacaoCampinas().soap_envelope(NFSE[self.autorizador]["CONSULTA_FAIXA"], payload, self.certificado, self.certificado_senha)
print(soup_xml)
return self._post_soap_raw(url, soup_xml)
elif self.autorizador == "OSASCO":
@@ -798,7 +798,7 @@ def consultar_periodo(self, payload):
url = self._get_url()
if self.autorizador == "CAMPINAS":
from pynfe.processamento.autorizador_nfse import SerializacaoCampinas
- soup_xml = SerializacaoCampinas().soap_envelope(NFSE[self.autorizador]["CONSULTA_SERVICO"], payload)
+ soup_xml = SerializacaoCampinas().soap_envelope(NFSE[self.autorizador]["CONSULTA_SERVICO"], payload, self.certificado, self.certificado_senha)
print(soup_xml)
return self._post_soap_raw(url, soup_xml)
elif self.autorizador == "OSASCO":
From b52687235569c4f3c848e2e073ac466d8c337131 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 11:52:25 -0300
Subject: [PATCH 127/175] =?UTF-8?q?adiciona=20importa=C3=A7=C3=B5es=20de?=
=?UTF-8?q?=20base64=20e=20hashlib=20para=20suporte=20a=20opera=C3=A7?=
=?UTF-8?q?=C3=B5es=20de=20assinatura?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index 1cbe79af..c3dbe833 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -3,6 +3,12 @@
from lxml import etree
from pyxb import BIND
+import base64
+import hashlib
+
+from cryptography.hazmat.primitives import hashes
+from cryptography.hazmat.primitives.asymmetric import padding
+from cryptography.hazmat.primitives.serialization import Encoding, pkcs12
class InterfaceAutorizador:
From 6e8a300596b9f9821469ecc94708eee225533bf2 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 11:54:18 -0300
Subject: [PATCH 128/175] =?UTF-8?q?ajusta=20m=C3=A9todo=20=5Fsign=5Fxml=20?=
=?UTF-8?q?na=20classe=20SerializacaoCampinas=20para=20normalizar=20entrad?=
=?UTF-8?q?a=20e=20organiza=20coment=C3=A1rios?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 42 +++++++++++++++----------
1 file changed, 26 insertions(+), 16 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index c3dbe833..826814a1 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -71,9 +71,10 @@ def _cabecalho(self):
2.03
""".strip()
+
def _sign_xml(
self,
- xml_element: etree._Element,
+ xml_input,
certificate_path: str,
certificate_password: str,
) -> str:
@@ -84,12 +85,22 @@ def _sign_xml(
DIGEST_ALG = "http://www.w3.org/2000/09/xmldsig#sha1"
ENVELOPED_ALG = "http://www.w3.org/2000/09/xmldsig#enveloped-signature"
- # Garante que existe Id
+ # --------------------------------
+ # Normaliza entrada (str → Element)
+ # --------------------------------
+ if isinstance(xml_input, str):
+ parser = etree.XMLParser(remove_blank_text=True)
+ xml_element = etree.fromstring(xml_input.encode("utf-8"), parser)
+ else:
+ xml_element = xml_input
+
element_id = xml_element.get("Id")
if not element_id:
raise ValueError("Elemento raiz precisa ter atributo Id para assinatura")
+ # --------------------------------
# Carrega certificado
+ # --------------------------------
with open(certificate_path, "rb") as f:
cert_data = f.read()
@@ -105,7 +116,9 @@ def _sign_xml(
certificate.public_bytes(Encoding.DER)
).decode()
- # Canonicaliza XML SEM assinatura
+ # --------------------------------
+ # Digest
+ # --------------------------------
xml_c14n = etree.tostring(
xml_element, method="c14n", exclusive=False, with_comments=False
)
@@ -114,11 +127,10 @@ def _sign_xml(
hashlib.sha1(xml_c14n).digest()
).decode()
- # ---------- SignedInfo ----------
- signed_info = etree.Element(
- "SignedInfo",
- nsmap={None: DSIG_NS}
- )
+ # --------------------------------
+ # SignedInfo
+ # --------------------------------
+ signed_info = etree.Element("SignedInfo", nsmap={None: DSIG_NS})
etree.SubElement(
signed_info,
@@ -163,7 +175,6 @@ def _sign_xml(
"DigestValue"
).text = digest_value
- # Assina SignedInfo
signed_info_c14n = etree.tostring(
signed_info, method="c14n", exclusive=False, with_comments=False
)
@@ -176,12 +187,10 @@ def _sign_xml(
)
).decode()
- # ---------- Signature ----------
- signature = etree.Element(
- "Signature",
- nsmap={None: DSIG_NS}
- )
-
+ # --------------------------------
+ # Signature
+ # --------------------------------
+ signature = etree.Element("Signature", nsmap={None: DSIG_NS})
signature.append(signed_info)
etree.SubElement(
@@ -196,7 +205,7 @@ def _sign_xml(
"X509Certificate"
).text = cert_b64
- # Insere assinatura no XML
+ # Insere assinatura
xml_element.append(signature)
return etree.tostring(
@@ -204,6 +213,7 @@ def _sign_xml(
)
+
def soap_envelope(
self,
metodo,
From 2ac11943af3480e80b8617cb209548e4de36745c Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 12:00:15 -0300
Subject: [PATCH 129/175] =?UTF-8?q?refatora=20m=C3=A9todo=20=5Fsign=5Fxml?=
=?UTF-8?q?=20na=20classe=20SerializacaoCampinas=20para=20melhorar=20a=20o?=
=?UTF-8?q?rganiza=C3=A7=C3=A3o=20do=20c=C3=B3digo=20e=20adicionar=20comen?=
=?UTF-8?q?t=C3=A1rios=20explicativos?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 144 ++++++++++++++++--------
1 file changed, 100 insertions(+), 44 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index 826814a1..25db04ea 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -78,16 +78,35 @@ def _sign_xml(
certificate_path: str,
certificate_password: str,
) -> str:
+ from lxml import etree
+ from cryptography.hazmat.primitives.serialization import pkcs12, Encoding
+ from cryptography.hazmat.primitives.asymmetric import padding
+ from cryptography.hazmat.primitives import hashes
+ import base64
+ import hashlib
+
+ # =========================
+ # Namespaces
+ # =========================
+ NFSE_NS = "http://nfse.abrasf.org.br"
DSIG_NS = "http://www.w3.org/2000/09/xmldsig#"
+ NSMAP = {
+ "nfse": NFSE_NS,
+ "xd": DSIG_NS,
+ }
+
+ # =========================
+ # Algoritmos
+ # =========================
C14N_ALG = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"
SIGNATURE_ALG = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
DIGEST_ALG = "http://www.w3.org/2000/09/xmldsig#sha1"
ENVELOPED_ALG = "http://www.w3.org/2000/09/xmldsig#enveloped-signature"
- # --------------------------------
- # Normaliza entrada (str → Element)
- # --------------------------------
+ # =========================
+ # Normaliza entrada
+ # =========================
if isinstance(xml_input, str):
parser = etree.XMLParser(remove_blank_text=True)
xml_element = etree.fromstring(xml_input.encode("utf-8"), parser)
@@ -98,15 +117,15 @@ def _sign_xml(
if not element_id:
raise ValueError("Elemento raiz precisa ter atributo Id para assinatura")
- # --------------------------------
- # Carrega certificado
- # --------------------------------
+ # =========================
+ # Certificado
+ # =========================
with open(certificate_path, "rb") as f:
cert_data = f.read()
- password = certificate_password.encode()
private_key, certificate, _ = pkcs12.load_key_and_certificates(
- cert_data, password
+ cert_data,
+ certificate_password.encode(),
)
if not private_key or not certificate:
@@ -116,100 +135,137 @@ def _sign_xml(
certificate.public_bytes(Encoding.DER)
).decode()
- # --------------------------------
- # Digest
- # --------------------------------
+ # =========================
+ # Digest do XML (sem assinatura)
+ # =========================
xml_c14n = etree.tostring(
- xml_element, method="c14n", exclusive=False, with_comments=False
+ xml_element,
+ method="c14n",
+ exclusive=False,
+ with_comments=False,
)
digest_value = base64.b64encode(
hashlib.sha1(xml_c14n).digest()
).decode()
- # --------------------------------
- # SignedInfo
- # --------------------------------
- signed_info = etree.Element("SignedInfo", nsmap={None: DSIG_NS})
+ # =========================
+ # nfse:Signature
+ # =========================
+ signature = etree.Element(
+ etree.QName(NFSE_NS, "Signature"),
+ nsmap=NSMAP,
+ )
+
+ # =========================
+ # xd:SignedInfo
+ # =========================
+ signed_info = etree.SubElement(
+ signature,
+ etree.QName(DSIG_NS, "SignedInfo"),
+ Id=f"SI-{element_id}",
+ )
etree.SubElement(
signed_info,
- "CanonicalizationMethod",
- Algorithm=C14N_ALG
+ etree.QName(DSIG_NS, "CanonicalizationMethod"),
+ Algorithm=C14N_ALG,
)
etree.SubElement(
signed_info,
- "SignatureMethod",
- Algorithm=SIGNATURE_ALG
+ etree.QName(DSIG_NS, "SignatureMethod"),
+ Algorithm=SIGNATURE_ALG,
)
reference = etree.SubElement(
signed_info,
- "Reference",
- URI=f"#{element_id}"
+ etree.QName(DSIG_NS, "Reference"),
+ URI=f"#{element_id}",
)
- transforms = etree.SubElement(reference, "Transforms")
+ transforms = etree.SubElement(
+ reference,
+ etree.QName(DSIG_NS, "Transforms"),
+ )
etree.SubElement(
transforms,
- "Transform",
- Algorithm=ENVELOPED_ALG
+ etree.QName(DSIG_NS, "Transform"),
+ Algorithm=ENVELOPED_ALG,
)
etree.SubElement(
transforms,
- "Transform",
- Algorithm=C14N_ALG
+ etree.QName(DSIG_NS, "Transform"),
+ Algorithm=C14N_ALG,
)
etree.SubElement(
reference,
- "DigestMethod",
- Algorithm=DIGEST_ALG
+ etree.QName(DSIG_NS, "DigestMethod"),
+ Algorithm=DIGEST_ALG,
)
etree.SubElement(
reference,
- "DigestValue"
+ etree.QName(DSIG_NS, "DigestValue"),
).text = digest_value
+ # =========================
+ # Assina SignedInfo
+ # =========================
signed_info_c14n = etree.tostring(
- signed_info, method="c14n", exclusive=False, with_comments=False
+ signed_info,
+ method="c14n",
+ exclusive=False,
+ with_comments=False,
)
signature_value = base64.b64encode(
private_key.sign(
signed_info_c14n,
padding.PKCS1v15(),
- hashes.SHA1()
+ hashes.SHA1(),
)
).decode()
- # --------------------------------
- # Signature
- # --------------------------------
- signature = etree.Element("Signature", nsmap={None: DSIG_NS})
- signature.append(signed_info)
-
+ # =========================
+ # xd:SignatureValue
+ # =========================
etree.SubElement(
signature,
- "SignatureValue"
+ etree.QName(DSIG_NS, "SignatureValue"),
+ Id=f"SV-{element_id}",
).text = signature_value
- key_info = etree.SubElement(signature, "KeyInfo")
- x509_data = etree.SubElement(key_info, "X509Data")
+ # =========================
+ # xd:KeyInfo (EndCertOnly)
+ # =========================
+ key_info = etree.SubElement(
+ signature,
+ etree.QName(DSIG_NS, "KeyInfo"),
+ )
+
+ x509_data = etree.SubElement(
+ key_info,
+ etree.QName(DSIG_NS, "X509Data"),
+ )
+
etree.SubElement(
x509_data,
- "X509Certificate"
+ etree.QName(DSIG_NS, "X509Certificate"),
).text = cert_b64
- # Insere assinatura
+ # =========================
+ # Anexa assinatura ao XML
+ # =========================
xml_element.append(signature)
return etree.tostring(
- xml_element, encoding="unicode", pretty_print=False
+ xml_element,
+ encoding="unicode",
+ pretty_print=False,
)
From 44fc055e63838c4a201bb3ac34c86e88a11e743e Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 12:06:55 -0300
Subject: [PATCH 130/175] =?UTF-8?q?ajusta=20m=C3=A9todo=20=5Fsign=5Fxml=20?=
=?UTF-8?q?na=20classe=20SerializacaoCampinas=20para=20remover=20assinatur?=
=?UTF-8?q?as=20existentes=20antes=20de=20calcular=20o=20digest=20do=20XML?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index 25db04ea..e072db5f 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -136,10 +136,20 @@ def _sign_xml(
).decode()
# =========================
- # Digest do XML (sem assinatura)
+ # Digest SEM a Signature
# =========================
+ xml_clone = etree.fromstring(
+ etree.tostring(xml_element)
+ )
+
+ # Remove qualquer Signature existente (segurança)
+ for sig in xml_clone.xpath(
+ ".//*[local-name()='Signature']"
+ ):
+ sig.getparent().remove(sig)
+
xml_c14n = etree.tostring(
- xml_element,
+ xml_clone,
method="c14n",
exclusive=False,
with_comments=False,
From 359cbdaa6daef99d846c69d7c86dcc074bbdc5df Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 12:18:19 -0300
Subject: [PATCH 131/175] =?UTF-8?q?refatora=20m=C3=A9todo=20=5Fsign=5Fxml?=
=?UTF-8?q?=20na=20classe=20SerializacaoCampinas=20para=20melhorar=20a=20l?=
=?UTF-8?q?egibilidade=20e=20remover=20coment=C3=A1rios=20desnecess=C3=A1r?=
=?UTF-8?q?ios?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 24 +++++++-----------------
1 file changed, 7 insertions(+), 17 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index e072db5f..702130ac 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -3,12 +3,6 @@
from lxml import etree
from pyxb import BIND
-import base64
-import hashlib
-
-from cryptography.hazmat.primitives import hashes
-from cryptography.hazmat.primitives.asymmetric import padding
-from cryptography.hazmat.primitives.serialization import Encoding, pkcs12
class InterfaceAutorizador:
@@ -97,7 +91,7 @@ def _sign_xml(
}
# =========================
- # Algoritmos
+ # Algoritmos (GINFES)
# =========================
C14N_ALG = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"
SIGNATURE_ALG = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
@@ -115,7 +109,7 @@ def _sign_xml(
element_id = xml_element.get("Id")
if not element_id:
- raise ValueError("Elemento raiz precisa ter atributo Id para assinatura")
+ raise ValueError("Elemento raiz precisa ter atributo Id")
# =========================
# Certificado
@@ -136,16 +130,14 @@ def _sign_xml(
).decode()
# =========================
- # Digest SEM a Signature
+ # Digest (SEM Signature)
# =========================
xml_clone = etree.fromstring(
etree.tostring(xml_element)
)
- # Remove qualquer Signature existente (segurança)
- for sig in xml_clone.xpath(
- ".//*[local-name()='Signature']"
- ):
+ # remove qualquer Signature existente
+ for sig in xml_clone.xpath(".//*[local-name()='Signature']"):
sig.getparent().remove(sig)
xml_c14n = etree.tostring(
@@ -240,9 +232,6 @@ def _sign_xml(
)
).decode()
- # =========================
- # xd:SignatureValue
- # =========================
etree.SubElement(
signature,
etree.QName(DSIG_NS, "SignatureValue"),
@@ -268,7 +257,7 @@ def _sign_xml(
).text = cert_b64
# =========================
- # Anexa assinatura ao XML
+ # Anexa assinatura
# =========================
xml_element.append(signature)
@@ -280,6 +269,7 @@ def _sign_xml(
+
def soap_envelope(
self,
metodo,
From 68d3a13317389a94f0eb944b4fb2b252c6954a80 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 12:20:51 -0300
Subject: [PATCH 132/175] =?UTF-8?q?ajusta=20namespace=20da=20assinatura=20?=
=?UTF-8?q?no=20m=C3=A9todo=20=5Fsign=5Fxml=20da=20classe=20SerializacaoCa?=
=?UTF-8?q?mpinas?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index 702130ac..b0f9a012 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -155,8 +155,8 @@ def _sign_xml(
# nfse:Signature
# =========================
signature = etree.Element(
- etree.QName(NFSE_NS, "Signature"),
- nsmap=NSMAP,
+ etree.QName(DSIG_NS, "Signature"),
+ nsmap={None: DSIG_NS},
)
# =========================
From 64cbddbde076dd28dacc5d9fcfd99a455bd1fdc4 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 12:22:23 -0300
Subject: [PATCH 133/175] =?UTF-8?q?remove=20URI=20parameter=20na=20cria?=
=?UTF-8?q?=C3=A7=C3=A3o=20do=20elemento=20Reference=20no=20m=C3=A9todo=20?=
=?UTF-8?q?=5Fsign=5Fxml=20da=20classe=20SerializacaoCampinas?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index b0f9a012..605ff4c4 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -183,7 +183,6 @@ def _sign_xml(
reference = etree.SubElement(
signed_info,
etree.QName(DSIG_NS, "Reference"),
- URI=f"#{element_id}",
)
transforms = etree.SubElement(
From 569f8a6f4a74506238e9acb0f84779e48bf59da2 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 12:25:06 -0300
Subject: [PATCH 134/175] =?UTF-8?q?remove=20par=C3=A2metro=20Id=20na=20cri?=
=?UTF-8?q?a=C3=A7=C3=A3o=20do=20elemento=20ConsultarNfseServicoPrestadoEn?=
=?UTF-8?q?vio=20e=20ConsultarNfseFaixaEnvio=20na=20classe=20SerializacaoC?=
=?UTF-8?q?ampinas?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index 605ff4c4..88726acc 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -303,7 +303,6 @@ def consultar_periodo(self, emitente, data_inicio, data_fim, pagina=1):
raiz = etree.Element(
"ConsultarNfseServicoPrestadoEnvio",
xmlns=self.NS_PERIODO,
- Id=self._gerar_id("CNFSEPERIODO"),
)
prestador = etree.SubElement(raiz, "Prestador")
@@ -324,7 +323,7 @@ def consultar_periodo(self, emitente, data_inicio, data_fim, pagina=1):
# -------------------------
def consultar_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
raiz = etree.Element(
- "ConsultarNfseFaixaEnvio", xmlns=self.NS_FAIXA, Id=self._gerar_id("CNFSEFAIXA")
+ "ConsultarNfseFaixaEnvio", xmlns=self.NS_FAIXA
)
prestador = etree.SubElement(raiz, "Prestador")
From c42fc8185df2685b07c05f87df5bdaa0d568dcab Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 12:28:40 -0300
Subject: [PATCH 135/175] =?UTF-8?q?ajusta=20tratamento=20do=20atributo=20I?=
=?UTF-8?q?d=20no=20m=C3=A9todo=20=5Fsign=5Fxml=20da=20classe=20Serializac?=
=?UTF-8?q?aoCampinas=20para=20permitir=20valores=20nulos?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index 88726acc..47072b2c 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -108,8 +108,6 @@ def _sign_xml(
xml_element = xml_input
element_id = xml_element.get("Id")
- if not element_id:
- raise ValueError("Elemento raiz precisa ter atributo Id")
# =========================
# Certificado
@@ -165,7 +163,7 @@ def _sign_xml(
signed_info = etree.SubElement(
signature,
etree.QName(DSIG_NS, "SignedInfo"),
- Id=f"SI-{element_id}",
+ Id=f"SI-{element_id}" if element_id else None,
)
etree.SubElement(
@@ -234,7 +232,7 @@ def _sign_xml(
etree.SubElement(
signature,
etree.QName(DSIG_NS, "SignatureValue"),
- Id=f"SV-{element_id}",
+ Id=f"SV-{element_id}" if element_id else None,
).text = signature_value
# =========================
From 96231c8f2f276d6c7e95f8d5bcb0b5eaca7c5390 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 12:30:08 -0300
Subject: [PATCH 136/175] =?UTF-8?q?ajusta=20tratamento=20do=20atributo=20I?=
=?UTF-8?q?d=20no=20m=C3=A9todo=20=5Fsign=5Fxml=20da=20classe=20Serializac?=
=?UTF-8?q?aoCampinas=20para=20evitar=20valores=20nulos?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index 47072b2c..fcd5db50 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -163,7 +163,7 @@ def _sign_xml(
signed_info = etree.SubElement(
signature,
etree.QName(DSIG_NS, "SignedInfo"),
- Id=f"SI-{element_id}" if element_id else None,
+ Id=f"SI-{element_id}" if element_id else "",
)
etree.SubElement(
@@ -232,7 +232,7 @@ def _sign_xml(
etree.SubElement(
signature,
etree.QName(DSIG_NS, "SignatureValue"),
- Id=f"SV-{element_id}" if element_id else None,
+ Id=f"SV-{element_id}" if element_id else "",
).text = signature_value
# =========================
From 469d6d4b5fc2db9235644ab74de68c275e08d405 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 12:37:12 -0300
Subject: [PATCH 137/175] =?UTF-8?q?adiciona=20gera=C3=A7=C3=A3o=20de=20ID?=
=?UTF-8?q?=20no=20m=C3=A9todo=20=5Fsign=5Fxml=20da=20classe=20Serializaca?=
=?UTF-8?q?oCampinas=20para=20tratar=20valores=20nulos?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index fcd5db50..dca4444d 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -108,6 +108,8 @@ def _sign_xml(
xml_element = xml_input
element_id = xml_element.get("Id")
+ if not element_id:
+ element_id = self._gerar_id("ID")
# =========================
# Certificado
@@ -264,9 +266,6 @@ def _sign_xml(
pretty_print=False,
)
-
-
-
def soap_envelope(
self,
metodo,
From 5c3f4522d993f19b7fe454799927a3a303349ae8 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 12:38:07 -0300
Subject: [PATCH 138/175] =?UTF-8?q?ajusta=20gera=C3=A7=C3=A3o=20de=20IDs?=
=?UTF-8?q?=20no=20m=C3=A9todo=20=5Fsign=5Fxml=20da=20classe=20Serializaca?=
=?UTF-8?q?oCampinas=20para=20garantir=20valores=20consistentes?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index dca4444d..b701d2d4 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -108,8 +108,6 @@ def _sign_xml(
xml_element = xml_input
element_id = xml_element.get("Id")
- if not element_id:
- element_id = self._gerar_id("ID")
# =========================
# Certificado
@@ -165,7 +163,7 @@ def _sign_xml(
signed_info = etree.SubElement(
signature,
etree.QName(DSIG_NS, "SignedInfo"),
- Id=f"SI-{element_id}" if element_id else "",
+ Id=self._gerar_id("SI"),
)
etree.SubElement(
@@ -234,7 +232,7 @@ def _sign_xml(
etree.SubElement(
signature,
etree.QName(DSIG_NS, "SignatureValue"),
- Id=f"SV-{element_id}" if element_id else "",
+ Id=self._gerar_id("SV"),
).text = signature_value
# =========================
From 0bdf163714e354752694d8ff883886bde0908a8c Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 12:39:56 -0300
Subject: [PATCH 139/175] =?UTF-8?q?remove=20uso=20do=20atributo=20Id=20no?=
=?UTF-8?q?=20m=C3=A9todo=20=5Fsign=5Fxml=20da=20classe=20SerializacaoCamp?=
=?UTF-8?q?inas?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 4 ----
1 file changed, 4 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index b701d2d4..c9920c31 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -107,8 +107,6 @@ def _sign_xml(
else:
xml_element = xml_input
- element_id = xml_element.get("Id")
-
# =========================
# Certificado
# =========================
@@ -163,7 +161,6 @@ def _sign_xml(
signed_info = etree.SubElement(
signature,
etree.QName(DSIG_NS, "SignedInfo"),
- Id=self._gerar_id("SI"),
)
etree.SubElement(
@@ -232,7 +229,6 @@ def _sign_xml(
etree.SubElement(
signature,
etree.QName(DSIG_NS, "SignatureValue"),
- Id=self._gerar_id("SV"),
).text = signature_value
# =========================
From 043786f2098d6cc9ac634d7e7dd007c24c7e034c Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 12:45:08 -0300
Subject: [PATCH 140/175] =?UTF-8?q?adiciona=20normaliza=C3=A7=C3=A3o=20de?=
=?UTF-8?q?=20XML=20para=20GINFES=20no=20m=C3=A9todo=20=5Fsign=5Fxml=20da?=
=?UTF-8?q?=20classe=20SerializacaoCampinas?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 76 ++++++++++++++-----------
1 file changed, 44 insertions(+), 32 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index c9920c31..59b28a8c 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -43,7 +43,12 @@ def consultar(
"NumeroReciboUnico": numero_rps_unico,
}
-
+def normalize_xml_for_ginfes(elem):
+ for e in elem.iter():
+ if e.text:
+ e.text = e.text.strip()
+ if e.tail:
+ e.tail = None
class SerializacaoCampinas(InterfaceAutorizador):
"""
Serialização ABRASF v2.03 – Campinas
@@ -79,37 +84,40 @@ def _sign_xml(
import base64
import hashlib
- # =========================
+ # =====================================================
# Namespaces
- # =========================
- NFSE_NS = "http://nfse.abrasf.org.br"
+ # =====================================================
DSIG_NS = "http://www.w3.org/2000/09/xmldsig#"
- NSMAP = {
- "nfse": NFSE_NS,
- "xd": DSIG_NS,
- }
-
- # =========================
+ # =====================================================
# Algoritmos (GINFES)
- # =========================
+ # =====================================================
C14N_ALG = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"
SIGNATURE_ALG = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
DIGEST_ALG = "http://www.w3.org/2000/09/xmldsig#sha1"
ENVELOPED_ALG = "http://www.w3.org/2000/09/xmldsig#enveloped-signature"
- # =========================
+ # =====================================================
+ # Helper: normalização GINFES (OBRIGATÓRIA)
+ # =====================================================
+ def _normalize_xml_ginfes(elem):
+ for e in elem.iter():
+ if e.text is not None:
+ e.text = e.text.strip()
+ e.tail = None
+
+ # =====================================================
# Normaliza entrada
- # =========================
+ # =====================================================
if isinstance(xml_input, str):
parser = etree.XMLParser(remove_blank_text=True)
xml_element = etree.fromstring(xml_input.encode("utf-8"), parser)
else:
xml_element = xml_input
- # =========================
+ # =====================================================
# Certificado
- # =========================
+ # =====================================================
with open(certificate_path, "rb") as f:
cert_data = f.read()
@@ -125,9 +133,9 @@ def _sign_xml(
certificate.public_bytes(Encoding.DER)
).decode()
- # =========================
+ # =====================================================
# Digest (SEM Signature)
- # =========================
+ # =====================================================
xml_clone = etree.fromstring(
etree.tostring(xml_element)
)
@@ -136,6 +144,9 @@ def _sign_xml(
for sig in xml_clone.xpath(".//*[local-name()='Signature']"):
sig.getparent().remove(sig)
+ # 🔥 PASSO CRÍTICO PARA GINFES
+ _normalize_xml_ginfes(xml_clone)
+
xml_c14n = etree.tostring(
xml_clone,
method="c14n",
@@ -147,17 +158,17 @@ def _sign_xml(
hashlib.sha1(xml_c14n).digest()
).decode()
- # =========================
- # nfse:Signature
- # =========================
+ # =====================================================
+ #
+ # =====================================================
signature = etree.Element(
etree.QName(DSIG_NS, "Signature"),
nsmap={None: DSIG_NS},
)
- # =========================
- # xd:SignedInfo
- # =========================
+ # =====================================================
+ #
+ # =====================================================
signed_info = etree.SubElement(
signature,
etree.QName(DSIG_NS, "SignedInfo"),
@@ -208,9 +219,9 @@ def _sign_xml(
etree.QName(DSIG_NS, "DigestValue"),
).text = digest_value
- # =========================
- # Assina SignedInfo
- # =========================
+ # =====================================================
+ # Assina o SignedInfo
+ # =====================================================
signed_info_c14n = etree.tostring(
signed_info,
method="c14n",
@@ -231,9 +242,9 @@ def _sign_xml(
etree.QName(DSIG_NS, "SignatureValue"),
).text = signature_value
- # =========================
- # xd:KeyInfo (EndCertOnly)
- # =========================
+ # =====================================================
+ #
+ # =====================================================
key_info = etree.SubElement(
signature,
etree.QName(DSIG_NS, "KeyInfo"),
@@ -249,9 +260,9 @@ def _sign_xml(
etree.QName(DSIG_NS, "X509Certificate"),
).text = cert_b64
- # =========================
- # Anexa assinatura
- # =========================
+ # =====================================================
+ # Anexa assinatura AO ELEMENTO RAIZ DO ENVIO
+ # =====================================================
xml_element.append(signature)
return etree.tostring(
@@ -260,6 +271,7 @@ def _sign_xml(
pretty_print=False,
)
+
def soap_envelope(
self,
metodo,
From a1b1d999abc569eee2acfe4e480fba82a5a152c6 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 12:50:54 -0300
Subject: [PATCH 141/175] =?UTF-8?q?refatora=20m=C3=A9todo=20=5Fsign=5Fxml?=
=?UTF-8?q?=20da=20classe=20SerializacaoCampinas=20para=20melhorar=20a=20l?=
=?UTF-8?q?egibilidade=20e=20garantir=20a=20presen=C3=A7a=20do=20atributo?=
=?UTF-8?q?=20Id=20no=20elemento=20raiz?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 90 ++++++++++++-------------
1 file changed, 44 insertions(+), 46 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index 59b28a8c..4a4e9465 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -84,40 +84,40 @@ def _sign_xml(
import base64
import hashlib
- # =====================================================
+ # =========================
# Namespaces
- # =====================================================
+ # =========================
DSIG_NS = "http://www.w3.org/2000/09/xmldsig#"
- # =====================================================
+ # =========================
# Algoritmos (GINFES)
- # =====================================================
+ # =========================
C14N_ALG = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"
SIGNATURE_ALG = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
DIGEST_ALG = "http://www.w3.org/2000/09/xmldsig#sha1"
ENVELOPED_ALG = "http://www.w3.org/2000/09/xmldsig#enveloped-signature"
- # =====================================================
- # Helper: normalização GINFES (OBRIGATÓRIA)
- # =====================================================
- def _normalize_xml_ginfes(elem):
- for e in elem.iter():
- if e.text is not None:
- e.text = e.text.strip()
- e.tail = None
-
- # =====================================================
- # Normaliza entrada
- # =====================================================
+ # =========================
+ # Parse XML
+ # =========================
if isinstance(xml_input, str):
parser = etree.XMLParser(remove_blank_text=True)
xml_element = etree.fromstring(xml_input.encode("utf-8"), parser)
else:
xml_element = xml_input
- # =====================================================
- # Certificado
- # =====================================================
+ # =========================
+ # Id do elemento raiz (OBRIGATÓRIO)
+ # =========================
+ element_id = xml_element.get("Id")
+ if not element_id:
+ raise ValueError(
+ "Elemento raiz não possui atributo Id (obrigatório para assinatura GINFES)"
+ )
+
+ # =========================
+ # Carrega certificado
+ # =========================
with open(certificate_path, "rb") as f:
cert_data = f.read()
@@ -133,20 +133,17 @@ def _normalize_xml_ginfes(elem):
certificate.public_bytes(Encoding.DER)
).decode()
- # =====================================================
- # Digest (SEM Signature)
- # =====================================================
- xml_clone = etree.fromstring(
- etree.tostring(xml_element)
- )
+ # =========================
+ # Digest (remove Signature)
+ # =========================
+ xml_clone = etree.fromstring(etree.tostring(xml_element))
- # remove qualquer Signature existente
- for sig in xml_clone.xpath(".//*[local-name()='Signature']"):
+ for sig in xml_clone.xpath(
+ ".//*[local-name()='Signature' and namespace-uri()=$ns]",
+ ns=DSIG_NS,
+ ):
sig.getparent().remove(sig)
- # 🔥 PASSO CRÍTICO PARA GINFES
- _normalize_xml_ginfes(xml_clone)
-
xml_c14n = etree.tostring(
xml_clone,
method="c14n",
@@ -158,17 +155,17 @@ def _normalize_xml_ginfes(elem):
hashlib.sha1(xml_c14n).digest()
).decode()
- # =====================================================
- #
- # =====================================================
+ # =========================
+ #
+ # =========================
signature = etree.Element(
etree.QName(DSIG_NS, "Signature"),
nsmap={None: DSIG_NS},
)
- # =====================================================
+ # =========================
#
- # =====================================================
+ # =========================
signed_info = etree.SubElement(
signature,
etree.QName(DSIG_NS, "SignedInfo"),
@@ -189,6 +186,7 @@ def _normalize_xml_ginfes(elem):
reference = etree.SubElement(
signed_info,
etree.QName(DSIG_NS, "Reference"),
+ URI=f"#{element_id}",
)
transforms = etree.SubElement(
@@ -219,9 +217,9 @@ def _normalize_xml_ginfes(elem):
etree.QName(DSIG_NS, "DigestValue"),
).text = digest_value
- # =====================================================
- # Assina o SignedInfo
- # =====================================================
+ # =========================
+ # Assina SignedInfo
+ # =========================
signed_info_c14n = etree.tostring(
signed_info,
method="c14n",
@@ -242,9 +240,9 @@ def _normalize_xml_ginfes(elem):
etree.QName(DSIG_NS, "SignatureValue"),
).text = signature_value
- # =====================================================
- #
- # =====================================================
+ # =========================
+ #
+ # =========================
key_info = etree.SubElement(
signature,
etree.QName(DSIG_NS, "KeyInfo"),
@@ -260,9 +258,9 @@ def _normalize_xml_ginfes(elem):
etree.QName(DSIG_NS, "X509Certificate"),
).text = cert_b64
- # =====================================================
- # Anexa assinatura AO ELEMENTO RAIZ DO ENVIO
- # =====================================================
+ # =========================
+ # Anexa Signature
+ # =========================
xml_element.append(signature)
return etree.tostring(
@@ -271,7 +269,6 @@ def _normalize_xml_ginfes(elem):
pretty_print=False,
)
-
def soap_envelope(
self,
metodo,
@@ -306,6 +303,7 @@ def consultar_periodo(self, emitente, data_inicio, data_fim, pagina=1):
raiz = etree.Element(
"ConsultarNfseServicoPrestadoEnvio",
xmlns=self.NS_PERIODO,
+ Id=self._gerar_id("CNFSESP")
)
prestador = etree.SubElement(raiz, "Prestador")
@@ -326,7 +324,7 @@ def consultar_periodo(self, emitente, data_inicio, data_fim, pagina=1):
# -------------------------
def consultar_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
raiz = etree.Element(
- "ConsultarNfseFaixaEnvio", xmlns=self.NS_FAIXA
+ "ConsultarNfseFaixaEnvio", xmlns=self.NS_FAIXA, Id=self._gerar_id("CNFSEFAIXA")
)
prestador = etree.SubElement(raiz, "Prestador")
From 8a602a01814208d1ae817bb3c1182fbc72c79374 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 12:56:30 -0300
Subject: [PATCH 142/175] =?UTF-8?q?adiciona=20m=C3=A9todo=20=5Fsign=5Fxml?=
=?UTF-8?q?=5F2=20na=20classe=20SerializacaoCampinas=20para=20assinatura?=
=?UTF-8?q?=20de=20documentos=20XML=20conforme=20manual=20NFS-e=20de=20S?=
=?UTF-8?q?=C3=A3o=20Paulo?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 168 +++++++++++++++++++++++-
1 file changed, 167 insertions(+), 1 deletion(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index 4a4e9465..73815021 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -70,6 +70,172 @@ def _cabecalho(self):
2.03
""".strip()
+ def _sign_xml_2(
+ self,
+ xml_str: str,
+ certificate_path: str,
+ certificate_password: str,
+ ) -> str:
+ """
+ Sign XML document using XML Digital Signature (Enveloped) according to São Paulo NFS-e manual v3.3.4.
+
+ According to section 3.2.3 of the manual:
+ - Padrão de assinatura: XML Digital Signature, formato Enveloped
+ - Certificado digital: ICP-Brasil (X509Data)
+ - Cadeia de Certificação: EndCertOnly (apenas certificado do usuário final)
+ - Função criptográfica: RSA (rsa-sha1)
+ - Função message digest: SHA-1
+ - Codificação: Base64
+ - Transformações: Enveloped e C14N
+
+ Args:
+ xml_str: XML string to sign (must have a Signature placeholder element)
+ certificate_path: Path to the PFX/P12 certificate file
+ certificate_password: Certificate password
+
+ Returns:
+ Signed XML string
+ """
+ from lxml import etree
+ from cryptography.hazmat.primitives.serialization import pkcs12, Encoding
+ from cryptography.hazmat.primitives.asymmetric import padding
+ from cryptography.hazmat.primitives import hashes
+ import base64
+ import hashlib
+ C14N_ALG = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"
+ SIGNATURE_ALG = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
+ DIGEST_ALG = "http://www.w3.org/2000/09/xmldsig#sha1"
+ ENVELOPED_ALG = "http://www.w3.org/2000/09/xmldsig#enveloped-signature"
+ DSIG_NS = "http://www.w3.org/2000/09/xmldsig#"
+
+ # Parse the XML
+ parser = etree.XMLParser(remove_blank_text=True)
+ root = etree.fromstring(xml_str.encode('utf-8'), parser)
+
+ # Find and remove the Signature placeholder
+ ns = {'ds': DSIG_NS}
+ signature_elem = root.find('.//ds:Signature', ns)
+
+ if signature_elem is None:
+ raise ValueError("XML must contain a ds:Signature placeholder element")
+
+ signature_parent = signature_elem.getparent()
+ signature_index = list(signature_parent).index(signature_elem)
+ signature_parent.remove(signature_elem)
+
+ # Load certificate
+ with open(certificate_path, 'rb') as cert_file:
+ cert_data = cert_file.read()
+
+ password = certificate_password.encode() if isinstance(certificate_password, str) else certificate_password
+ private_key, certificate, _ = pkcs12.load_key_and_certificates(cert_data, password)
+
+ if private_key is None or certificate is None:
+ raise ValueError("Could not load private key or certificate from file")
+
+ # Get certificate in DER format for X509Certificate element
+ cert_der = certificate.public_bytes(Encoding.DER)
+ cert_b64 = base64.b64encode(cert_der).decode('ascii')
+
+ # Step 1: Canonicalize the document (without signature) for DigestValue
+ # Using C14N as per manual: http://www.w3.org/TR/2001/REC-xml-c14n-20010315
+ xml_c14n = etree.tostring(root, method='c14n', exclusive=False, with_comments=False)
+ digest_b64 = base64.b64encode(hashlib.sha1(xml_c14n).digest()).decode('ascii')
+
+ # Step 2: Build SignedInfo as a standalone element with explicit namespace
+ # CRITICAL: SignedInfo must have the namespace declaration for proper C14N
+ signed_info = etree.Element(
+ 'SignedInfo',
+ nsmap={None: DSIG_NS} # Default namespace, no prefix
+ )
+
+ canon_method = etree.SubElement(signed_info, 'CanonicalizationMethod')
+ canon_method.set('Algorithm', C14N_ALG)
+
+ sig_method = etree.SubElement(signed_info, 'SignatureMethod')
+ sig_method.set('Algorithm', SIGNATURE_ALG)
+
+ reference = etree.SubElement(signed_info, 'Reference')
+ reference.set('URI', '')
+
+ transforms = etree.SubElement(reference, 'Transforms')
+
+ transform1 = etree.SubElement(transforms, 'Transform')
+ transform1.set('Algorithm', ENVELOPED_ALG)
+
+ transform2 = etree.SubElement(transforms, 'Transform')
+ transform2.set('Algorithm', C14N_ALG)
+
+ digest_method = etree.SubElement(reference, 'DigestMethod')
+ digest_method.set('Algorithm', DIGEST_ALG)
+
+ digest_value_elem = etree.SubElement(reference, 'DigestValue')
+ digest_value_elem.text = digest_b64
+
+ # Step 3: Canonicalize SignedInfo for signing
+ # The namespace declaration MUST be included in the canonicalized form
+ signed_info_c14n = etree.tostring(signed_info, method='c14n', exclusive=False, with_comments=False)
+
+ # Step 4: Sign the canonicalized SignedInfo with RSA-SHA1
+ from cryptography.hazmat.primitives.asymmetric import rsa
+ if not isinstance(private_key, rsa.RSAPrivateKey):
+ raise ValueError("Certificate must contain an RSA private key")
+
+ signature_value_bytes = private_key.sign(
+ signed_info_c14n,
+ padding.PKCS1v15(),
+ hashes.SHA1()
+ )
+ signature_value_b64 = base64.b64encode(signature_value_bytes).decode('ascii')
+
+ # Step 5: Build complete Signature element
+ new_signature = etree.Element(
+ 'Signature',
+ nsmap={None: DSIG_NS} # Default namespace, no prefix
+ )
+
+ # Append SignedInfo (recreate without standalone namespace for proper nesting)
+ new_signed_info = etree.SubElement(new_signature, 'SignedInfo')
+
+ new_canon = etree.SubElement(new_signed_info, 'CanonicalizationMethod')
+ new_canon.set('Algorithm', C14N_ALG)
+
+ new_sig_method = etree.SubElement(new_signed_info, 'SignatureMethod')
+ new_sig_method.set('Algorithm', SIGNATURE_ALG)
+
+ new_ref = etree.SubElement(new_signed_info, 'Reference')
+ new_ref.set('URI', '')
+
+ new_transforms = etree.SubElement(new_ref, 'Transforms')
+ new_t1 = etree.SubElement(new_transforms, 'Transform')
+ new_t1.set('Algorithm', ENVELOPED_ALG)
+ new_t2 = etree.SubElement(new_transforms, 'Transform')
+ new_t2.set('Algorithm', C14N_ALG)
+
+ new_digest_method = etree.SubElement(new_ref, 'DigestMethod')
+ new_digest_method.set('Algorithm', DIGEST_ALG)
+
+ new_digest_value = etree.SubElement(new_ref, 'DigestValue')
+ new_digest_value.text = digest_b64
+
+ # SignatureValue
+ sig_value = etree.SubElement(new_signature, 'SignatureValue')
+ sig_value.text = signature_value_b64
+
+ # KeyInfo with only X509Certificate (EndCertOnly as per manual)
+ key_info = etree.SubElement(new_signature, 'KeyInfo')
+ x509_data = etree.SubElement(key_info, 'X509Data')
+ x509_cert = etree.SubElement(x509_data, 'X509Certificate')
+ x509_cert.text = cert_b64
+
+ # Insert signature into document
+ signature_parent.insert(signature_index, new_signature)
+
+ # Return signed XML
+ signed_xml = etree.tostring(root, encoding='unicode', pretty_print=False)
+
+ return signed_xml
+
def _sign_xml(
self,
@@ -276,7 +442,7 @@ def soap_envelope(
certificate_path,
certificate_password,
):
- xml_assinado = self._sign_xml(
+ xml_assinado = self._sign_xml_2(
xml_envio_element,
certificate_path,
certificate_password,
From 86c5a2981476fed57bbb92aa7b1ab3e952f3e61a Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 13:02:49 -0300
Subject: [PATCH 143/175] =?UTF-8?q?remove=20m=C3=A9todo=20=5Fsign=5Fxml=5F?=
=?UTF-8?q?2=20da=20classe=20SerializacaoCampinas=20e=20ajusta=20implement?=
=?UTF-8?q?a=C3=A7=C3=A3o=20de=20=5Fsign=5Fxml=20para=20assinatura=20de=20?=
=?UTF-8?q?documentos=20XML=20conforme=20manual=20NFS-e=20de=20Campinas?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 426 ++++++------------------
1 file changed, 101 insertions(+), 325 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index 73815021..e3f3f94c 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -70,176 +70,10 @@ def _cabecalho(self):
2.03
""".strip()
- def _sign_xml_2(
- self,
- xml_str: str,
- certificate_path: str,
- certificate_password: str,
- ) -> str:
- """
- Sign XML document using XML Digital Signature (Enveloped) according to São Paulo NFS-e manual v3.3.4.
-
- According to section 3.2.3 of the manual:
- - Padrão de assinatura: XML Digital Signature, formato Enveloped
- - Certificado digital: ICP-Brasil (X509Data)
- - Cadeia de Certificação: EndCertOnly (apenas certificado do usuário final)
- - Função criptográfica: RSA (rsa-sha1)
- - Função message digest: SHA-1
- - Codificação: Base64
- - Transformações: Enveloped e C14N
-
- Args:
- xml_str: XML string to sign (must have a Signature placeholder element)
- certificate_path: Path to the PFX/P12 certificate file
- certificate_password: Certificate password
-
- Returns:
- Signed XML string
- """
- from lxml import etree
- from cryptography.hazmat.primitives.serialization import pkcs12, Encoding
- from cryptography.hazmat.primitives.asymmetric import padding
- from cryptography.hazmat.primitives import hashes
- import base64
- import hashlib
- C14N_ALG = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"
- SIGNATURE_ALG = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
- DIGEST_ALG = "http://www.w3.org/2000/09/xmldsig#sha1"
- ENVELOPED_ALG = "http://www.w3.org/2000/09/xmldsig#enveloped-signature"
- DSIG_NS = "http://www.w3.org/2000/09/xmldsig#"
-
- # Parse the XML
- parser = etree.XMLParser(remove_blank_text=True)
- root = etree.fromstring(xml_str.encode('utf-8'), parser)
-
- # Find and remove the Signature placeholder
- ns = {'ds': DSIG_NS}
- signature_elem = root.find('.//ds:Signature', ns)
-
- if signature_elem is None:
- raise ValueError("XML must contain a ds:Signature placeholder element")
-
- signature_parent = signature_elem.getparent()
- signature_index = list(signature_parent).index(signature_elem)
- signature_parent.remove(signature_elem)
-
- # Load certificate
- with open(certificate_path, 'rb') as cert_file:
- cert_data = cert_file.read()
-
- password = certificate_password.encode() if isinstance(certificate_password, str) else certificate_password
- private_key, certificate, _ = pkcs12.load_key_and_certificates(cert_data, password)
-
- if private_key is None or certificate is None:
- raise ValueError("Could not load private key or certificate from file")
-
- # Get certificate in DER format for X509Certificate element
- cert_der = certificate.public_bytes(Encoding.DER)
- cert_b64 = base64.b64encode(cert_der).decode('ascii')
-
- # Step 1: Canonicalize the document (without signature) for DigestValue
- # Using C14N as per manual: http://www.w3.org/TR/2001/REC-xml-c14n-20010315
- xml_c14n = etree.tostring(root, method='c14n', exclusive=False, with_comments=False)
- digest_b64 = base64.b64encode(hashlib.sha1(xml_c14n).digest()).decode('ascii')
-
- # Step 2: Build SignedInfo as a standalone element with explicit namespace
- # CRITICAL: SignedInfo must have the namespace declaration for proper C14N
- signed_info = etree.Element(
- 'SignedInfo',
- nsmap={None: DSIG_NS} # Default namespace, no prefix
- )
-
- canon_method = etree.SubElement(signed_info, 'CanonicalizationMethod')
- canon_method.set('Algorithm', C14N_ALG)
-
- sig_method = etree.SubElement(signed_info, 'SignatureMethod')
- sig_method.set('Algorithm', SIGNATURE_ALG)
-
- reference = etree.SubElement(signed_info, 'Reference')
- reference.set('URI', '')
-
- transforms = etree.SubElement(reference, 'Transforms')
-
- transform1 = etree.SubElement(transforms, 'Transform')
- transform1.set('Algorithm', ENVELOPED_ALG)
-
- transform2 = etree.SubElement(transforms, 'Transform')
- transform2.set('Algorithm', C14N_ALG)
-
- digest_method = etree.SubElement(reference, 'DigestMethod')
- digest_method.set('Algorithm', DIGEST_ALG)
-
- digest_value_elem = etree.SubElement(reference, 'DigestValue')
- digest_value_elem.text = digest_b64
-
- # Step 3: Canonicalize SignedInfo for signing
- # The namespace declaration MUST be included in the canonicalized form
- signed_info_c14n = etree.tostring(signed_info, method='c14n', exclusive=False, with_comments=False)
-
- # Step 4: Sign the canonicalized SignedInfo with RSA-SHA1
- from cryptography.hazmat.primitives.asymmetric import rsa
- if not isinstance(private_key, rsa.RSAPrivateKey):
- raise ValueError("Certificate must contain an RSA private key")
-
- signature_value_bytes = private_key.sign(
- signed_info_c14n,
- padding.PKCS1v15(),
- hashes.SHA1()
- )
- signature_value_b64 = base64.b64encode(signature_value_bytes).decode('ascii')
-
- # Step 5: Build complete Signature element
- new_signature = etree.Element(
- 'Signature',
- nsmap={None: DSIG_NS} # Default namespace, no prefix
- )
-
- # Append SignedInfo (recreate without standalone namespace for proper nesting)
- new_signed_info = etree.SubElement(new_signature, 'SignedInfo')
-
- new_canon = etree.SubElement(new_signed_info, 'CanonicalizationMethod')
- new_canon.set('Algorithm', C14N_ALG)
-
- new_sig_method = etree.SubElement(new_signed_info, 'SignatureMethod')
- new_sig_method.set('Algorithm', SIGNATURE_ALG)
-
- new_ref = etree.SubElement(new_signed_info, 'Reference')
- new_ref.set('URI', '')
-
- new_transforms = etree.SubElement(new_ref, 'Transforms')
- new_t1 = etree.SubElement(new_transforms, 'Transform')
- new_t1.set('Algorithm', ENVELOPED_ALG)
- new_t2 = etree.SubElement(new_transforms, 'Transform')
- new_t2.set('Algorithm', C14N_ALG)
-
- new_digest_method = etree.SubElement(new_ref, 'DigestMethod')
- new_digest_method.set('Algorithm', DIGEST_ALG)
-
- new_digest_value = etree.SubElement(new_ref, 'DigestValue')
- new_digest_value.text = digest_b64
-
- # SignatureValue
- sig_value = etree.SubElement(new_signature, 'SignatureValue')
- sig_value.text = signature_value_b64
-
- # KeyInfo with only X509Certificate (EndCertOnly as per manual)
- key_info = etree.SubElement(new_signature, 'KeyInfo')
- x509_data = etree.SubElement(key_info, 'X509Data')
- x509_cert = etree.SubElement(x509_data, 'X509Certificate')
- x509_cert.text = cert_b64
-
- # Insert signature into document
- signature_parent.insert(signature_index, new_signature)
-
- # Return signed XML
- signed_xml = etree.tostring(root, encoding='unicode', pretty_print=False)
-
- return signed_xml
-
def _sign_xml(
self,
- xml_input,
+ xml_input: str,
certificate_path: str,
certificate_password: str,
) -> str:
@@ -250,68 +84,42 @@ def _sign_xml(
import base64
import hashlib
- # =========================
- # Namespaces
- # =========================
- DSIG_NS = "http://www.w3.org/2000/09/xmldsig#"
-
- # =========================
- # Algoritmos (GINFES)
- # =========================
+ # Algoritmos exigidos pelo GINFES Campinas
C14N_ALG = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"
- SIGNATURE_ALG = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
+ SIGN_ALG = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
DIGEST_ALG = "http://www.w3.org/2000/09/xmldsig#sha1"
ENVELOPED_ALG = "http://www.w3.org/2000/09/xmldsig#enveloped-signature"
- # =========================
- # Parse XML
- # =========================
- if isinstance(xml_input, str):
- parser = etree.XMLParser(remove_blank_text=True)
- xml_element = etree.fromstring(xml_input.encode("utf-8"), parser)
- else:
- xml_element = xml_input
-
- # =========================
- # Id do elemento raiz (OBRIGATÓRIO)
- # =========================
- element_id = xml_element.get("Id")
- if not element_id:
- raise ValueError(
- "Elemento raiz não possui atributo Id (obrigatório para assinatura GINFES)"
- )
+ parser = etree.XMLParser(remove_blank_text=True)
+ root = etree.fromstring(xml_input.encode("utf-8"), parser)
- # =========================
- # Carrega certificado
- # =========================
+ # === LOCAL CORRETO ===
+ envio = root.xpath("//*[local-name()='ConsultarNfseServicoPrestadoEnvio']")
+ if not envio:
+ raise ValueError("ConsultarNfseServicoPrestadoEnvio não encontrado")
+
+ envio = envio[0]
+
+ # Remove qualquer assinatura anterior
+ for s in envio.xpath("./*[local-name()='Signature']"):
+ envio.remove(s)
+
+ # === CARREGA CERTIFICADO ===
with open(certificate_path, "rb") as f:
- cert_data = f.read()
+ pfx = f.read()
- private_key, certificate, _ = pkcs12.load_key_and_certificates(
- cert_data,
+ private_key, cert, _ = pkcs12.load_key_and_certificates(
+ pfx,
certificate_password.encode(),
)
- if not private_key or not certificate:
- raise ValueError("Falha ao carregar certificado")
-
cert_b64 = base64.b64encode(
- certificate.public_bytes(Encoding.DER)
+ cert.public_bytes(Encoding.DER)
).decode()
- # =========================
- # Digest (remove Signature)
- # =========================
- xml_clone = etree.fromstring(etree.tostring(xml_element))
-
- for sig in xml_clone.xpath(
- ".//*[local-name()='Signature' and namespace-uri()=$ns]",
- ns=DSIG_NS,
- ):
- sig.getparent().remove(sig)
-
+ # === DIGEST DO XML SEM SIGNATURE ===
xml_c14n = etree.tostring(
- xml_clone,
+ envio,
method="c14n",
exclusive=False,
with_comments=False,
@@ -321,71 +129,51 @@ def _sign_xml(
hashlib.sha1(xml_c14n).digest()
).decode()
- # =========================
- #
- # =========================
- signature = etree.Element(
- etree.QName(DSIG_NS, "Signature"),
- nsmap={None: DSIG_NS},
- )
+ # === SIGNATURE (SEM NAMESPACE) ===
+ signature = etree.Element("Signature")
- # =========================
- #
- # =========================
- signed_info = etree.SubElement(
- signature,
- etree.QName(DSIG_NS, "SignedInfo"),
- )
+ signed_info = etree.SubElement(signature, "SignedInfo")
etree.SubElement(
signed_info,
- etree.QName(DSIG_NS, "CanonicalizationMethod"),
+ "CanonicalizationMethod",
Algorithm=C14N_ALG,
)
etree.SubElement(
signed_info,
- etree.QName(DSIG_NS, "SignatureMethod"),
- Algorithm=SIGNATURE_ALG,
+ "SignatureMethod",
+ Algorithm=SIGN_ALG,
)
- reference = etree.SubElement(
- signed_info,
- etree.QName(DSIG_NS, "Reference"),
- URI=f"#{element_id}",
- )
+ reference = etree.SubElement(signed_info, "Reference")
- transforms = etree.SubElement(
- reference,
- etree.QName(DSIG_NS, "Transforms"),
- )
+ transforms = etree.SubElement(reference, "Transforms")
etree.SubElement(
transforms,
- etree.QName(DSIG_NS, "Transform"),
+ "Transform",
Algorithm=ENVELOPED_ALG,
)
etree.SubElement(
transforms,
- etree.QName(DSIG_NS, "Transform"),
+ "Transform",
Algorithm=C14N_ALG,
)
etree.SubElement(
reference,
- etree.QName(DSIG_NS, "DigestMethod"),
+ "DigestMethod",
Algorithm=DIGEST_ALG,
)
etree.SubElement(
reference,
- etree.QName(DSIG_NS, "DigestValue"),
+ "DigestValue",
).text = digest_value
- # =========================
- # Assina SignedInfo
- # =========================
+ # === ASSINA SIGNEDINFO ===
signed_info_c14n = etree.tostring(
signed_info,
method="c14n",
@@ -403,108 +191,96 @@ def _sign_xml(
etree.SubElement(
signature,
- etree.QName(DSIG_NS, "SignatureValue"),
+ "SignatureValue",
).text = signature_value
- # =========================
- #
- # =========================
- key_info = etree.SubElement(
- signature,
- etree.QName(DSIG_NS, "KeyInfo"),
- )
-
- x509_data = etree.SubElement(
- key_info,
- etree.QName(DSIG_NS, "X509Data"),
- )
-
+ # === KEYINFO (END CERT ONLY) ===
+ key_info = etree.SubElement(signature, "KeyInfo")
+ x509_data = etree.SubElement(key_info, "X509Data")
etree.SubElement(
x509_data,
- etree.QName(DSIG_NS, "X509Certificate"),
+ "X509Certificate",
).text = cert_b64
- # =========================
- # Anexa Signature
- # =========================
- xml_element.append(signature)
+ # === ANEXA NO FINAL DO ENVIO ===
+ envio.append(signature)
return etree.tostring(
- xml_element,
+ root,
encoding="unicode",
pretty_print=False,
)
- def soap_envelope(
- self,
- metodo,
- xml_envio_element,
- certificate_path,
- certificate_password,
- ):
- xml_assinado = self._sign_xml_2(
+ def soap_envelope(
+ self,
+ metodo,
xml_envio_element,
certificate_path,
certificate_password,
- )
+ ):
+ xml_assinado = self._sign_xml(
+ xml_envio_element,
+ certificate_path,
+ certificate_password,
+ )
- return f"""
-
-
-
-
- {self._cabecalho()}
- {xml_assinado}
-
-
-
- """.strip()
-
-
- # -------------------------
- # CONSULTAR POR PERÍODO
- # -------------------------
- def consultar_periodo(self, emitente, data_inicio, data_fim, pagina=1):
- raiz = etree.Element(
- "ConsultarNfseServicoPrestadoEnvio",
- xmlns=self.NS_PERIODO,
- Id=self._gerar_id("CNFSESP")
- )
+ return f"""
+
+
+
+
+ {self._cabecalho()}
+ {xml_assinado}
+
+
+
+ """.strip()
- prestador = etree.SubElement(raiz, "Prestador")
- cpf_cnpj = etree.SubElement(prestador, "CpfCnpj")
- etree.SubElement(cpf_cnpj, "Cnpj").text = emitente.cnpj
- etree.SubElement(prestador, "InscricaoMunicipal").text = emitente.inscricao_municipal
- periodo = etree.SubElement(raiz, "PeriodoEmissao")
- etree.SubElement(periodo, "DataInicial").text = data_inicio
- etree.SubElement(periodo, "DataFinal").text = data_fim
+ # -------------------------
+ # CONSULTAR POR PERÍODO
+ # -------------------------
+ def consultar_periodo(self, emitente, data_inicio, data_fim, pagina=1):
+ raiz = etree.Element(
+ "ConsultarNfseServicoPrestadoEnvio",
+ xmlns=self.NS_PERIODO,
+ Id=self._gerar_id("CNFSESP")
+ )
- etree.SubElement(raiz, "Pagina").text = str(pagina)
+ prestador = etree.SubElement(raiz, "Prestador")
+ cpf_cnpj = etree.SubElement(prestador, "CpfCnpj")
+ etree.SubElement(cpf_cnpj, "Cnpj").text = emitente.cnpj
+ etree.SubElement(prestador, "InscricaoMunicipal").text = emitente.inscricao_municipal
- return raiz
+ periodo = etree.SubElement(raiz, "PeriodoEmissao")
+ etree.SubElement(periodo, "DataInicial").text = data_inicio
+ etree.SubElement(periodo, "DataFinal").text = data_fim
- # -------------------------
- # CONSULTAR POR FAIXA
- # -------------------------
- def consultar_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
- raiz = etree.Element(
- "ConsultarNfseFaixaEnvio", xmlns=self.NS_FAIXA, Id=self._gerar_id("CNFSEFAIXA")
- )
+ etree.SubElement(raiz, "Pagina").text = str(pagina)
+
+ return raiz
+
+ # -------------------------
+ # CONSULTAR POR FAIXA
+ # -------------------------
+ def consultar_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
+ raiz = etree.Element(
+ "ConsultarNfseFaixaEnvio", xmlns=self.NS_FAIXA, Id=self._gerar_id("CNFSEFAIXA")
+ )
- prestador = etree.SubElement(raiz, "Prestador")
- cpf_cnpj = etree.SubElement(prestador, "CpfCnpj")
- etree.SubElement(cpf_cnpj, "Cnpj").text = emitente.cnpj
- etree.SubElement(prestador, "InscricaoMunicipal").text = emitente.inscricao_municipal
+ prestador = etree.SubElement(raiz, "Prestador")
+ cpf_cnpj = etree.SubElement(prestador, "CpfCnpj")
+ etree.SubElement(cpf_cnpj, "Cnpj").text = emitente.cnpj
+ etree.SubElement(prestador, "InscricaoMunicipal").text = emitente.inscricao_municipal
- faixa = etree.SubElement(raiz, "Faixa")
- etree.SubElement(faixa, "NumeroNfseInicial").text = str(numero_inicial)
- etree.SubElement(faixa, "NumeroNfseFinal").text = str(numero_final)
+ faixa = etree.SubElement(raiz, "Faixa")
+ etree.SubElement(faixa, "NumeroNfseInicial").text = str(numero_inicial)
+ etree.SubElement(faixa, "NumeroNfseFinal").text = str(numero_final)
- etree.SubElement(raiz, "Pagina").text = str(pagina)
+ etree.SubElement(raiz, "Pagina").text = str(pagina)
- return raiz
+ return raiz
class SerializacaoBetha(InterfaceAutorizador):
From bbd17cf51d9233d4bbbb112d320c3f2534eef619 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 13:04:27 -0300
Subject: [PATCH 144/175] =?UTF-8?q?refatora=20m=C3=A9todo=20soap=5Fenvelop?=
=?UTF-8?q?e=20da=20classe=20SerializacaoCampinas=20para=20melhorar=20a=20?=
=?UTF-8?q?legibilidade=20e=20garantir=20a=20correta=20formata=C3=A7=C3=A3?=
=?UTF-8?q?o=20do=20XML?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 114 ++++++++++++------------
1 file changed, 57 insertions(+), 57 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index e3f3f94c..0e1d6c4a 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -211,76 +211,76 @@ def _sign_xml(
pretty_print=False,
)
- def soap_envelope(
- self,
- metodo,
+ def soap_envelope(
+ self,
+ metodo,
+ xml_envio_element,
+ certificate_path,
+ certificate_password,
+ ):
+ xml_assinado = self._sign_xml(
xml_envio_element,
certificate_path,
certificate_password,
- ):
- xml_assinado = self._sign_xml(
- xml_envio_element,
- certificate_path,
- certificate_password,
- )
-
- return f"""
-
-
-
-
- {self._cabecalho()}
- {xml_assinado}
-
-
-
- """.strip()
-
+ )
- # -------------------------
- # CONSULTAR POR PERÍODO
- # -------------------------
- def consultar_periodo(self, emitente, data_inicio, data_fim, pagina=1):
- raiz = etree.Element(
- "ConsultarNfseServicoPrestadoEnvio",
- xmlns=self.NS_PERIODO,
- Id=self._gerar_id("CNFSESP")
- )
+ return f"""
+
+
+
+
+ {self._cabecalho()}
+ {xml_assinado}
+
+
+
+ """.strip()
+
+
+ # -------------------------
+ # CONSULTAR POR PERÍODO
+ # -------------------------
+ def consultar_periodo(self, emitente, data_inicio, data_fim, pagina=1):
+ raiz = etree.Element(
+ "ConsultarNfseServicoPrestadoEnvio",
+ xmlns=self.NS_PERIODO,
+ Id=self._gerar_id("CNFSESP")
+ )
- prestador = etree.SubElement(raiz, "Prestador")
- cpf_cnpj = etree.SubElement(prestador, "CpfCnpj")
- etree.SubElement(cpf_cnpj, "Cnpj").text = emitente.cnpj
- etree.SubElement(prestador, "InscricaoMunicipal").text = emitente.inscricao_municipal
+ prestador = etree.SubElement(raiz, "Prestador")
+ cpf_cnpj = etree.SubElement(prestador, "CpfCnpj")
+ etree.SubElement(cpf_cnpj, "Cnpj").text = emitente.cnpj
+ etree.SubElement(prestador, "InscricaoMunicipal").text = emitente.inscricao_municipal
- periodo = etree.SubElement(raiz, "PeriodoEmissao")
- etree.SubElement(periodo, "DataInicial").text = data_inicio
- etree.SubElement(periodo, "DataFinal").text = data_fim
+ periodo = etree.SubElement(raiz, "PeriodoEmissao")
+ etree.SubElement(periodo, "DataInicial").text = data_inicio
+ etree.SubElement(periodo, "DataFinal").text = data_fim
- etree.SubElement(raiz, "Pagina").text = str(pagina)
+ etree.SubElement(raiz, "Pagina").text = str(pagina)
- return raiz
+ return raiz
- # -------------------------
- # CONSULTAR POR FAIXA
- # -------------------------
- def consultar_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
- raiz = etree.Element(
- "ConsultarNfseFaixaEnvio", xmlns=self.NS_FAIXA, Id=self._gerar_id("CNFSEFAIXA")
- )
+ # -------------------------
+ # CONSULTAR POR FAIXA
+ # -------------------------
+ def consultar_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
+ raiz = etree.Element(
+ "ConsultarNfseFaixaEnvio", xmlns=self.NS_FAIXA, Id=self._gerar_id("CNFSEFAIXA")
+ )
- prestador = etree.SubElement(raiz, "Prestador")
- cpf_cnpj = etree.SubElement(prestador, "CpfCnpj")
- etree.SubElement(cpf_cnpj, "Cnpj").text = emitente.cnpj
- etree.SubElement(prestador, "InscricaoMunicipal").text = emitente.inscricao_municipal
+ prestador = etree.SubElement(raiz, "Prestador")
+ cpf_cnpj = etree.SubElement(prestador, "CpfCnpj")
+ etree.SubElement(cpf_cnpj, "Cnpj").text = emitente.cnpj
+ etree.SubElement(prestador, "InscricaoMunicipal").text = emitente.inscricao_municipal
- faixa = etree.SubElement(raiz, "Faixa")
- etree.SubElement(faixa, "NumeroNfseInicial").text = str(numero_inicial)
- etree.SubElement(faixa, "NumeroNfseFinal").text = str(numero_final)
+ faixa = etree.SubElement(raiz, "Faixa")
+ etree.SubElement(faixa, "NumeroNfseInicial").text = str(numero_inicial)
+ etree.SubElement(faixa, "NumeroNfseFinal").text = str(numero_final)
- etree.SubElement(raiz, "Pagina").text = str(pagina)
+ etree.SubElement(raiz, "Pagina").text = str(pagina)
- return raiz
+ return raiz
class SerializacaoBetha(InterfaceAutorizador):
From cb1f2751c0647ba5863b2a2da201b103dfbb3427 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 13:07:28 -0300
Subject: [PATCH 145/175] =?UTF-8?q?adiciona=20verifica=C3=A7=C3=A3o=20de?=
=?UTF-8?q?=20tipo=20para=20xml=5Finput=20no=20m=C3=A9todo=20=5Fsign=5Fxml?=
=?UTF-8?q?=20da=20classe=20SerializacaoCampinas?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index 0e1d6c4a..9f58596e 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -91,7 +91,12 @@ def _sign_xml(
ENVELOPED_ALG = "http://www.w3.org/2000/09/xmldsig#enveloped-signature"
parser = etree.XMLParser(remove_blank_text=True)
- root = etree.fromstring(xml_input.encode("utf-8"), parser)
+ if isinstance(xml_input, etree._Element):
+ root = xml_input
+ elif isinstance(xml_input, (str, bytes)):
+ root = etree.fromstring(xml_input.encode("utf-8"), parser)
+ else:
+ raise TypeError("xml_input deve ser str, bytes ou lxml.etree._Element")
# === LOCAL CORRETO ===
envio = root.xpath("//*[local-name()='ConsultarNfseServicoPrestadoEnvio']")
From 729f69dde2de092845efa85e715a534dd5a0dd96 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 17:15:44 -0300
Subject: [PATCH 146/175] =?UTF-8?q?ajusta=20m=C3=A9todo=20assinar=20da=20c?=
=?UTF-8?q?lasse=20AssinaturaA1=20para=20converter=20string=20em=20element?=
=?UTF-8?q?o=20XML=20e=20trata=20caso=20onde=20n=C3=A3o=20h=C3=A1=20atribu?=
=?UTF-8?q?to=20Id?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/assinatura.py | 5 ++++-
setup.py | 6 +++---
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/pynfe/processamento/assinatura.py b/pynfe/processamento/assinatura.py
index 70b3b856..fa2c98cc 100644
--- a/pynfe/processamento/assinatura.py
+++ b/pynfe/processamento/assinatura.py
@@ -28,8 +28,11 @@ def __init__(self, certificado, senha):
self.key, self.cert = CertificadoA1(certificado).separar_arquivo(senha)
def assinar(self, xml: etree._Element, retorna_string=False) -> Union[str, etree._Element]:
+ if isinstance(xml, str):
+ xml = etree.fromstring(xml.encode('utf-8'))
+
# busca tag que tem id(reference_uri), logo nao importa se tem namespace
- reference = xml.xpath('//*[@Id]')[0].attrib['Id']
+ reference = xml.xpath('//*[@Id]')[0].attrib['Id'] if xml.xpath('//*[@Id]') else None
# retira acentos
xml_str = remover_acentos(etree.tostring(xml, encoding="unicode", pretty_print=False))
diff --git a/setup.py b/setup.py
index 73ec0be0..c9a8171b 100644
--- a/setup.py
+++ b/setup.py
@@ -32,9 +32,9 @@
install_requires=[
"pyopenssl>=23.0.0",
"requests",
- "lxml==6.0.2",
- "signxml==3.1.0",
- "suds-py3==1.4.5.0",
+ "lxml",
+ "signxml",
+ "suds-py3",
"zeep>=4.3.2",
],
extras_require={
From 362e3a8c27d1b61fde828d713f7d16f362c68cd8 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 22:31:01 -0300
Subject: [PATCH 147/175] =?UTF-8?q?adiciona=20atributo=20Id=20ao=20element?=
=?UTF-8?q?o=20Signature=20no=20m=C3=A9todo=20=5Fsign=5Fxml=20da=20classe?=
=?UTF-8?q?=20SerializacaoCampinas?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index 9f58596e..15a0a347 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -135,7 +135,7 @@ def _sign_xml(
).decode()
# === SIGNATURE (SEM NAMESPACE) ===
- signature = etree.Element("Signature")
+ signature = etree.Element("Signature", Id=f"Signature-{envio.attrib['Id']}")
signed_info = etree.SubElement(signature, "SignedInfo")
@@ -171,6 +171,7 @@ def _sign_xml(
reference,
"DigestMethod",
Algorithm=DIGEST_ALG,
+ URI="#" + envio.attrib["Id"],
)
etree.SubElement(
From 1a747ae8e20ba140f7885ff9f45c0e3de5c66e44 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 23:49:02 -0300
Subject: [PATCH 148/175] =?UTF-8?q?refatora=20m=C3=A9todo=20=5Fsign=5Fxml?=
=?UTF-8?q?=20da=20classe=20SerializacaoCampinas=20para=20melhorar=20a=20l?=
=?UTF-8?q?egibilidade=20e=20reorganiza=20importa=C3=A7=C3=B5es;=20remove?=
=?UTF-8?q?=20m=C3=A9todo=20=5Fcabecalho=20e=20ajusta=20elementos=20XML=20?=
=?UTF-8?q?nas=20fun=C3=A7=C3=B5es=20consultar=5Fperiodo=20e=20consultar?=
=?UTF-8?q?=5Ffaixa?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 39 ++++++++-----------------
1 file changed, 12 insertions(+), 27 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index 15a0a347..ba1a7417 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -43,12 +43,15 @@ def consultar(
"NumeroReciboUnico": numero_rps_unico,
}
+
def normalize_xml_for_ginfes(elem):
for e in elem.iter():
if e.text:
e.text = e.text.strip()
if e.tail:
e.tail = None
+
+
class SerializacaoCampinas(InterfaceAutorizador):
"""
Serialização ABRASF v2.03 – Campinas
@@ -64,26 +67,20 @@ class SerializacaoCampinas(InterfaceAutorizador):
def _gerar_id(self, prefixo):
return f"{prefixo}{uuid.uuid4().hex.upper()}"
- def _cabecalho(self):
- return """
-
- 2.03
-
- """.strip()
-
def _sign_xml(
self,
xml_input: str,
certificate_path: str,
certificate_password: str,
) -> str:
- from lxml import etree
- from cryptography.hazmat.primitives.serialization import pkcs12, Encoding
- from cryptography.hazmat.primitives.asymmetric import padding
- from cryptography.hazmat.primitives import hashes
import base64
import hashlib
+ from cryptography.hazmat.primitives import hashes
+ from cryptography.hazmat.primitives.asymmetric import padding
+ from cryptography.hazmat.primitives.serialization import Encoding, pkcs12
+ from lxml import etree
+
# Algoritmos exigidos pelo GINFES Campinas
C14N_ALG = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"
SIGN_ALG = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
@@ -118,9 +115,7 @@ def _sign_xml(
certificate_password.encode(),
)
- cert_b64 = base64.b64encode(
- cert.public_bytes(Encoding.DER)
- ).decode()
+ cert_b64 = base64.b64encode(cert.public_bytes(Encoding.DER)).decode()
# === DIGEST DO XML SEM SIGNATURE ===
xml_c14n = etree.tostring(
@@ -130,9 +125,7 @@ def _sign_xml(
with_comments=False,
)
- digest_value = base64.b64encode(
- hashlib.sha1(xml_c14n).digest()
- ).decode()
+ digest_value = base64.b64encode(hashlib.sha1(xml_c14n).digest()).decode()
# === SIGNATURE (SEM NAMESPACE) ===
signature = etree.Element("Signature", Id=f"Signature-{envio.attrib['Id']}")
@@ -236,23 +229,17 @@ def soap_envelope(
- {self._cabecalho()}
{xml_assinado}
""".strip()
-
# -------------------------
# CONSULTAR POR PERÍODO
# -------------------------
def consultar_periodo(self, emitente, data_inicio, data_fim, pagina=1):
- raiz = etree.Element(
- "ConsultarNfseServicoPrestadoEnvio",
- xmlns=self.NS_PERIODO,
- Id=self._gerar_id("CNFSESP")
- )
+ raiz = etree.Element("ConsultarNfseServicoPrestadoEnvio", xmlns=self.NS_PERIODO)
prestador = etree.SubElement(raiz, "Prestador")
cpf_cnpj = etree.SubElement(prestador, "CpfCnpj")
@@ -271,9 +258,7 @@ def consultar_periodo(self, emitente, data_inicio, data_fim, pagina=1):
# CONSULTAR POR FAIXA
# -------------------------
def consultar_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
- raiz = etree.Element(
- "ConsultarNfseFaixaEnvio", xmlns=self.NS_FAIXA, Id=self._gerar_id("CNFSEFAIXA")
- )
+ raiz = etree.Element("ConsultarNfseFaixaEnvio", xmlns=self.NS_FAIXA)
prestador = etree.SubElement(raiz, "Prestador")
cpf_cnpj = etree.SubElement(prestador, "CpfCnpj")
From c6f5ec717a54ef5b81e76a2c0c502b3c431e5d61 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 30 Dec 2025 23:53:14 -0300
Subject: [PATCH 149/175] =?UTF-8?q?remove=20namespace=20declaration=20nos?=
=?UTF-8?q?=20m=C3=A9todos=20consultar=5Fperiodo=20e=20consultar=5Ffaixa?=
=?UTF-8?q?=20da=20classe=20SerializacaoCampinas?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index ba1a7417..d7707a76 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -239,7 +239,7 @@ def soap_envelope(
# CONSULTAR POR PERÍODO
# -------------------------
def consultar_periodo(self, emitente, data_inicio, data_fim, pagina=1):
- raiz = etree.Element("ConsultarNfseServicoPrestadoEnvio", xmlns=self.NS_PERIODO)
+ raiz = etree.Element("ConsultarNfseServicoPrestadoEnvio")
prestador = etree.SubElement(raiz, "Prestador")
cpf_cnpj = etree.SubElement(prestador, "CpfCnpj")
@@ -258,7 +258,7 @@ def consultar_periodo(self, emitente, data_inicio, data_fim, pagina=1):
# CONSULTAR POR FAIXA
# -------------------------
def consultar_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
- raiz = etree.Element("ConsultarNfseFaixaEnvio", xmlns=self.NS_FAIXA)
+ raiz = etree.Element("ConsultarNfseFaixaEnvio")
prestador = etree.SubElement(raiz, "Prestador")
cpf_cnpj = etree.SubElement(prestador, "CpfCnpj")
From c27bb3c1c48f18f66be7844d866faf63bcfe46be Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Wed, 31 Dec 2025 09:23:38 -0300
Subject: [PATCH 150/175] =?UTF-8?q?remove=20par=C3=A2metros=20de=20certifi?=
=?UTF-8?q?cado=20do=20m=C3=A9todo=20soap=5Fenvelope=20da=20classe=20Seria?=
=?UTF-8?q?lizacaoCampinas?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 196 +++---------------------
pynfe/processamento/comunicacao.py | 6 +-
2 files changed, 25 insertions(+), 177 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index d7707a76..7c3278c6 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -51,7 +51,6 @@ def normalize_xml_for_ginfes(elem):
if e.tail:
e.tail = None
-
class SerializacaoCampinas(InterfaceAutorizador):
"""
Serialização ABRASF v2.03 – Campinas
@@ -59,185 +58,36 @@ class SerializacaoCampinas(InterfaceAutorizador):
Assinatura e envio ficam fora.
"""
- NS_FAIXA = "http://www.ginfes.com.br/servico_consultar_nfse_faixa_envio_v03.xsd"
- NS_PERIODO = "http://www.ginfes.com.br/servico_consultar_nfse_servico_envio_v03.xsd"
- DS_NS = "http://www.w3.org/2000/09/xmldsig#"
- NFSE_NS = "http://nfse.abrasf.org.br"
-
def _gerar_id(self, prefixo):
return f"{prefixo}{uuid.uuid4().hex.upper()}"
- def _sign_xml(
- self,
- xml_input: str,
- certificate_path: str,
- certificate_password: str,
- ) -> str:
- import base64
- import hashlib
-
- from cryptography.hazmat.primitives import hashes
- from cryptography.hazmat.primitives.asymmetric import padding
- from cryptography.hazmat.primitives.serialization import Encoding, pkcs12
- from lxml import etree
-
- # Algoritmos exigidos pelo GINFES Campinas
- C14N_ALG = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"
- SIGN_ALG = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
- DIGEST_ALG = "http://www.w3.org/2000/09/xmldsig#sha1"
- ENVELOPED_ALG = "http://www.w3.org/2000/09/xmldsig#enveloped-signature"
-
- parser = etree.XMLParser(remove_blank_text=True)
- if isinstance(xml_input, etree._Element):
- root = xml_input
- elif isinstance(xml_input, (str, bytes)):
- root = etree.fromstring(xml_input.encode("utf-8"), parser)
- else:
- raise TypeError("xml_input deve ser str, bytes ou lxml.etree._Element")
-
- # === LOCAL CORRETO ===
- envio = root.xpath("//*[local-name()='ConsultarNfseServicoPrestadoEnvio']")
- if not envio:
- raise ValueError("ConsultarNfseServicoPrestadoEnvio não encontrado")
-
- envio = envio[0]
-
- # Remove qualquer assinatura anterior
- for s in envio.xpath("./*[local-name()='Signature']"):
- envio.remove(s)
-
- # === CARREGA CERTIFICADO ===
- with open(certificate_path, "rb") as f:
- pfx = f.read()
-
- private_key, cert, _ = pkcs12.load_key_and_certificates(
- pfx,
- certificate_password.encode(),
- )
-
- cert_b64 = base64.b64encode(cert.public_bytes(Encoding.DER)).decode()
-
- # === DIGEST DO XML SEM SIGNATURE ===
- xml_c14n = etree.tostring(
- envio,
- method="c14n",
- exclusive=False,
- with_comments=False,
- )
-
- digest_value = base64.b64encode(hashlib.sha1(xml_c14n).digest()).decode()
-
- # === SIGNATURE (SEM NAMESPACE) ===
- signature = etree.Element("Signature", Id=f"Signature-{envio.attrib['Id']}")
-
- signed_info = etree.SubElement(signature, "SignedInfo")
-
- etree.SubElement(
- signed_info,
- "CanonicalizationMethod",
- Algorithm=C14N_ALG,
- )
-
- etree.SubElement(
- signed_info,
- "SignatureMethod",
- Algorithm=SIGN_ALG,
- )
-
- reference = etree.SubElement(signed_info, "Reference")
-
- transforms = etree.SubElement(reference, "Transforms")
-
- etree.SubElement(
- transforms,
- "Transform",
- Algorithm=ENVELOPED_ALG,
- )
-
- etree.SubElement(
- transforms,
- "Transform",
- Algorithm=C14N_ALG,
- )
-
- etree.SubElement(
- reference,
- "DigestMethod",
- Algorithm=DIGEST_ALG,
- URI="#" + envio.attrib["Id"],
- )
-
- etree.SubElement(
- reference,
- "DigestValue",
- ).text = digest_value
-
- # === ASSINA SIGNEDINFO ===
- signed_info_c14n = etree.tostring(
- signed_info,
- method="c14n",
- exclusive=False,
- with_comments=False,
- )
-
- signature_value = base64.b64encode(
- private_key.sign(
- signed_info_c14n,
- padding.PKCS1v15(),
- hashes.SHA1(),
- )
- ).decode()
-
- etree.SubElement(
- signature,
- "SignatureValue",
- ).text = signature_value
-
- # === KEYINFO (END CERT ONLY) ===
- key_info = etree.SubElement(signature, "KeyInfo")
- x509_data = etree.SubElement(key_info, "X509Data")
- etree.SubElement(
- x509_data,
- "X509Certificate",
- ).text = cert_b64
-
- # === ANEXA NO FINAL DO ENVIO ===
- envio.append(signature)
-
- return etree.tostring(
- root,
- encoding="unicode",
- pretty_print=False,
- )
-
def soap_envelope(
self,
metodo,
- xml_envio_element,
- certificate_path,
- certificate_password,
+ xml_assinado,
):
- xml_assinado = self._sign_xml(
- xml_envio_element,
- certificate_path,
- certificate_password,
+ NAMESPACE_SOAP = "http://schemas.xmlsoap.org/soap/envelope/"
+ NAMESPACE_XSI = "http://www.w3.org/2001/XMLSchema-instance"
+ NAMESPACE_XSD = "http://www.w3.org/2001/XMLSchema"
+ NAMESPACE_ABRASF = "http://nfse.abrasf.org.br"
+
+ xml_metodo = etree.Element("{%s}" % NAMESPACE_ABRASF + metodo)
+ xml_metodo.append(xml_assinado)
+ raiz = etree.Element(
+ "{%s}Envelope" % NAMESPACE_SOAP,
+ nsmap={
+ "xsi": NAMESPACE_XSI,
+ "xsd": NAMESPACE_XSD,
+ "soap": NAMESPACE_SOAP,
+ "nfse": NAMESPACE_ABRASF,
+ },
)
+ body = etree.SubElement(raiz, "{%s}Body" % NAMESPACE_SOAP)
+ body.append(xml_metodo)
+
+ return etree.tostring(raiz, pretty_print=True).decode()
+
- return f"""
-
-
-
-
- {xml_assinado}
-
-
-
- """.strip()
-
- # -------------------------
- # CONSULTAR POR PERÍODO
- # -------------------------
def consultar_periodo(self, emitente, data_inicio, data_fim, pagina=1):
raiz = etree.Element("ConsultarNfseServicoPrestadoEnvio")
@@ -254,9 +104,7 @@ def consultar_periodo(self, emitente, data_inicio, data_fim, pagina=1):
return raiz
- # -------------------------
- # CONSULTAR POR FAIXA
- # -------------------------
+
def consultar_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
raiz = etree.Element("ConsultarNfseFaixaEnvio")
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index f55d2b99..398a5519 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -771,7 +771,7 @@ def consultar_rps(self, payload):
url = self._get_url()
if self.autorizador == "CAMPINAS":
from pynfe.processamento.autorizador_nfse import SerializacaoCampinas
- soup_xml = SerializacaoCampinas().soap_envelope(NFSE[self.autorizador]["CONSULTA_RPS"], payload, self.certificado, self.certificado_senha)
+ soup_xml = SerializacaoCampinas().soap_envelope(NFSE[self.autorizador]["CONSULTA_RPS"], payload)
return self._post_soap_raw(url, soup_xml)
elif self.autorizador == "OSASCO":
# comunica via wsdl
@@ -784,7 +784,7 @@ def consultar_faixa(self, payload):
url = self._get_url()
if self.autorizador == "CAMPINAS":
from pynfe.processamento.autorizador_nfse import SerializacaoCampinas
- soup_xml = SerializacaoCampinas().soap_envelope(NFSE[self.autorizador]["CONSULTA_FAIXA"], payload, self.certificado, self.certificado_senha)
+ soup_xml = SerializacaoCampinas().soap_envelope(NFSE[self.autorizador]["CONSULTA_FAIXA"], payload)
print(soup_xml)
return self._post_soap_raw(url, soup_xml)
elif self.autorizador == "OSASCO":
@@ -798,7 +798,7 @@ def consultar_periodo(self, payload):
url = self._get_url()
if self.autorizador == "CAMPINAS":
from pynfe.processamento.autorizador_nfse import SerializacaoCampinas
- soup_xml = SerializacaoCampinas().soap_envelope(NFSE[self.autorizador]["CONSULTA_SERVICO"], payload, self.certificado, self.certificado_senha)
+ soup_xml = SerializacaoCampinas().soap_envelope(NFSE[self.autorizador]["CONSULTA_SERVICO"], payload)
print(soup_xml)
return self._post_soap_raw(url, soup_xml)
elif self.autorizador == "OSASCO":
From 2afbffed207a8adb08d395aa462805fd6ab31ebd Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Wed, 31 Dec 2025 09:30:34 -0300
Subject: [PATCH 151/175] =?UTF-8?q?ajusta=20m=C3=A9todos=20da=20classe=20C?=
=?UTF-8?q?omunicacaoNfse=20para=20assinar=20payloads=20antes=20de=20envia?=
=?UTF-8?q?r=20e=20melhora=20a=20formata=C3=A7=C3=A3o=20do=20XML=20retorna?=
=?UTF-8?q?do=20na=20classe=20SerializacaoCampinas?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 4 ++--
pynfe/processamento/comunicacao.py | 23 +++++++++--------------
2 files changed, 11 insertions(+), 16 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index 7c3278c6..2fe38110 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -102,7 +102,7 @@ def consultar_periodo(self, emitente, data_inicio, data_fim, pagina=1):
etree.SubElement(raiz, "Pagina").text = str(pagina)
- return raiz
+ return etree.tostring(raiz, pretty_print=True).decode()
def consultar_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
@@ -119,7 +119,7 @@ def consultar_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
etree.SubElement(raiz, "Pagina").text = str(pagina)
- return raiz
+ return etree.tostring(raiz, pretty_print=True).decode()
class SerializacaoBetha(InterfaceAutorizador):
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 398a5519..46362c59 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -771,8 +771,9 @@ def consultar_rps(self, payload):
url = self._get_url()
if self.autorizador == "CAMPINAS":
from pynfe.processamento.autorizador_nfse import SerializacaoCampinas
- soup_xml = SerializacaoCampinas().soap_envelope(NFSE[self.autorizador]["CONSULTA_RPS"], payload)
- return self._post_soap_raw(url, soup_xml)
+ xml_assinado = AssinaturaA1(self.certificado, self.certificado_senha).assinar(payload)
+ envelope_xml = SerializacaoCampinas().soap_envelope(NFSE[self.autorizador]["CONSULTA_RPS"], xml_assinado)
+ return self._post_soap_raw(url, envelope_xml)
elif self.autorizador == "OSASCO":
# comunica via wsdl
return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA"], payload)
@@ -784,9 +785,9 @@ def consultar_faixa(self, payload):
url = self._get_url()
if self.autorizador == "CAMPINAS":
from pynfe.processamento.autorizador_nfse import SerializacaoCampinas
- soup_xml = SerializacaoCampinas().soap_envelope(NFSE[self.autorizador]["CONSULTA_FAIXA"], payload)
- print(soup_xml)
- return self._post_soap_raw(url, soup_xml)
+ xml_assinado = AssinaturaA1(self.certificado, self.certificado_senha).assinar(payload)
+ envelope_xml = SerializacaoCampinas().soap_envelope(NFSE[self.autorizador]["CONSULTA_FAIXA"], xml_assinado)
+ return self._post_soap_raw(url, envelope_xml)
elif self.autorizador == "OSASCO":
# comunica via wsdl
return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA"], payload)
@@ -798,9 +799,9 @@ def consultar_periodo(self, payload):
url = self._get_url()
if self.autorizador == "CAMPINAS":
from pynfe.processamento.autorizador_nfse import SerializacaoCampinas
- soup_xml = SerializacaoCampinas().soap_envelope(NFSE[self.autorizador]["CONSULTA_SERVICO"], payload)
- print(soup_xml)
- return self._post_soap_raw(url, soup_xml)
+ xml_assinado = AssinaturaA1(self.certificado, self.certificado_senha).assinar(payload)
+ envelope_xml = SerializacaoCampinas().soap_envelope(NFSE[self.autorizador]["CONSULTA_SERVICO"], xml_assinado)
+ return self._post_soap_raw(url, envelope_xml)
elif self.autorizador == "OSASCO":
# comunica via wsdl
return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA"], payload)
@@ -856,12 +857,6 @@ def _cabecalho2(self, retorna_string=True):
else:
return raiz
- def _cabecalho_ginfes(self):
- """Retorna o XML do cabeçalho gerado pelo xsd"""
- from pynfe.processamento.autorizador_nfse import SerializacaoGinfes
-
- return SerializacaoGinfes().cabecalho()
-
def _get_url(self):
"""Retorna a url para comunicação com o webservice"""
if self._ambiente == 1:
From b7a7ebcd33f7d6f832e14a13c6c3588d4974a1bd Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Wed, 31 Dec 2025 10:21:28 -0300
Subject: [PATCH 152/175] =?UTF-8?q?adiciona=20verifica=C3=A7=C3=A3o=20para?=
=?UTF-8?q?=20garantir=20que=20o=20certificado=20seja=20exclu=C3=ADdo=20ap?=
=?UTF-8?q?enas=20se=20estiver=20presente=20na=20classe=20ComunicacaoNfse?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 46362c59..90061f71 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -1132,7 +1132,8 @@ def _post_zeep(self, wsdl, metodo, payload, wcf_compatibility=True):
return serialize_object(response)
finally:
- certificadoA1.excluir()
+ if self.certificado:
+ certificadoA1.excluir()
class ComunicacaoMDFe(Comunicacao):
From 695143569ffb237d7f54c89b68861afec2d5cc04 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Wed, 31 Dec 2025 10:31:43 -0300
Subject: [PATCH 153/175] =?UTF-8?q?remove=20par=C3=A2metro=20cnpj=5Ftomado?=
=?UTF-8?q?r=20das=20chamadas=20ao=20m=C3=A9todo=20consultar=20na=20classe?=
=?UTF-8?q?=20SerializacaoNfse?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/serializacao.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/pynfe/processamento/serializacao.py b/pynfe/processamento/serializacao.py
index 92622b7e..760186a4 100644
--- a/pynfe/processamento/serializacao.py
+++ b/pynfe/processamento/serializacao.py
@@ -2145,7 +2145,7 @@ def consultar_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
return SerializacaoCampinas().consultar_faixa(emitente, numero_inicial, numero_final, pagina=1)
elif self.autorizador.lower() == "osasco":
from pynfe.processamento.autorizador_nfse import SerializacaoOsasco
- return SerializacaoOsasco(self.chave_autenticacao).consultar(cnpj_tomador=emitente.cnpj, numero_nota_inicial=numero_inicial, numero_nota_final=numero_final)
+ return SerializacaoOsasco(self.chave_autenticacao).consultar(numero_nota_inicial=numero_inicial, numero_nota_final=numero_final)
else:
raise Exception(f"Este método não esta implementado para o autorizador {self.autorizador.upper()}")
@@ -2157,7 +2157,7 @@ def consultar_periodo(self, emitente, data_inicio, data_fim, pagina=1):
elif self.autorizador.lower() == "osasco":
from pynfe.processamento.autorizador_nfse import SerializacaoOsasco
- return SerializacaoOsasco(self.chave_autenticacao).consultar(cnpj_tomador=emitente.cnpj, data_inicial=data_inicio, data_final=data_fim)
+ return SerializacaoOsasco(self.chave_autenticacao).consultar(data_inicial=data_inicio, data_final=data_fim)
else:
raise Exception(f"Este método não esta implementado para o autorizador {self.autorizador.upper()}")
@@ -2165,7 +2165,7 @@ def consultar_periodo(self, emitente, data_inicio, data_fim, pagina=1):
def consultar_nfse(self, emitente, numero_nfse):
if self.autorizador.lower() == "osasco":
from pynfe.processamento.autorizador_nfse import SerializacaoOsasco
- return SerializacaoOsasco(self.chave_autenticacao).consultar(cnpj_tomador=emitente.cnpj, numero_nota_inicial=numero_nfse, numero_nota_final=numero_nfse)
+ return SerializacaoOsasco(self.chave_autenticacao).consultar(numero_nota_inicial=numero_nfse, numero_nota_final=numero_nfse)
else:
raise Exception(f"Este método não esta implementado para o autorizador {self.autorizador.upper()}")
From 998a352376b8a9e089ceec05608641575cd42986 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Fri, 2 Jan 2026 16:56:28 -0300
Subject: [PATCH 154/175] =?UTF-8?q?adiciona=20suporte=20=C3=A0=20serializa?=
=?UTF-8?q?=C3=A7=C3=A3o=20para=20Maracana=C3=BA=20e=20integra=20ao=20flux?=
=?UTF-8?q?o=20de=20comunica=C3=A7=C3=A3o?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 65 ++++++++++++++++++++++---
pynfe/processamento/comunicacao.py | 4 ++
pynfe/utils/webservices.py | 5 ++
3 files changed, 67 insertions(+), 7 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index 2fe38110..e1077677 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -44,13 +44,6 @@ def consultar(
}
-def normalize_xml_for_ginfes(elem):
- for e in elem.iter():
- if e.text:
- e.text = e.text.strip()
- if e.tail:
- e.tail = None
-
class SerializacaoCampinas(InterfaceAutorizador):
"""
Serialização ABRASF v2.03 – Campinas
@@ -121,6 +114,64 @@ def consultar_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
return etree.tostring(raiz, pretty_print=True).decode()
+class SerializacaoMaracanau(InterfaceAutorizador):
+ """
+ Serialização ABRASF v1.00 – Maracanaú
+ """
+ def _cabecalho(self):
+ cabecalho_xml = """1""".strip()
+ return cabecalho_xml
+
+ def soap_envelope(
+ self,
+ metodo,
+ xml_envio,
+ ):
+ NAMESPACE_SOAP = "http://schemas.xmlsoap.org/soap/envelope/"
+ NAMESPACE_ABRASF = "http://www.abrasf.org.br/ABRASF/arquivos/nfse.xsd"
+
+ ns_metodo = {
+ "ConsultarNfse": "http://www.abrasf.org.br/ABRASF/arquivos/nfse.xsd",
+ }
+
+ envelope = etree.Element(
+ "{http://schemas.xmlsoap.org/soap/envelope/}Envelope",
+ nsmap={
+ "soapenv": NAMESPACE_SOAP,
+ "nfse": NAMESPACE_ABRASF,
+ "consult": ns_metodo[metodo],
+ },
+ )
+ etree.SubElement(envelope, "{http://schemas.xmlsoap.org/soap/envelope/}Header")
+ body = etree.SubElement(envelope, "{http://schemas.xmlsoap.org/soap/envelope/}Body")
+
+ consultar_nfse = etree.SubElement(
+ body,
+ "{%s}" % ns_metodo[metodo] + metodo
+ )
+
+ header = etree.SubElement(consultar_nfse, "header")
+ header.text = etree.CDATA(self._cabecalho())
+
+ parameters = etree.SubElement(consultar_nfse, "parameters")
+ parameters.text = etree.CDATA(xml_envio)
+
+ return etree.tostring(envelope, pretty_print=True).decode()
+
+
+ def consultar_periodo(self, emitente, data_inicio, data_fim):
+ raiz = etree.Element("ConsultarNfse")
+
+ prestador = etree.SubElement(raiz, "Prestador")
+ etree.SubElement(prestador, "Cnpj").text = emitente.cnpj
+ etree.SubElement(prestador, "InscricaoMunicipal").text = emitente.inscricao_municipal
+
+ periodo = etree.SubElement(raiz, "PeriodoEmissao")
+ etree.SubElement(periodo, "DataInicial").text = data_inicio
+ etree.SubElement(periodo, "DataFinal").text = data_fim
+
+ return etree.tostring(raiz, pretty_print=True).decode()
+
class SerializacaoBetha(InterfaceAutorizador):
def __init__(self):
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 90061f71..4ba1b386 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -802,6 +802,10 @@ def consultar_periodo(self, payload):
xml_assinado = AssinaturaA1(self.certificado, self.certificado_senha).assinar(payload)
envelope_xml = SerializacaoCampinas().soap_envelope(NFSE[self.autorizador]["CONSULTA_SERVICO"], xml_assinado)
return self._post_soap_raw(url, envelope_xml)
+ elif self.autorizador == "MARACANAU":
+ from pynfe.processamento.autorizador_nfse import SerializacaoMaracanau
+ envelope_xml = SerializacaoMaracanau().soap_envelope(NFSE[self.autorizador]["CONSULTA_SERVICO"], payload)
+ return self._post_soap_raw(url, envelope_xml)
elif self.autorizador == "OSASCO":
# comunica via wsdl
return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA"], payload)
diff --git a/pynfe/utils/webservices.py b/pynfe/utils/webservices.py
index a97cada4..0336633e 100644
--- a/pynfe/utils/webservices.py
+++ b/pynfe/utils/webservices.py
@@ -529,6 +529,11 @@
"HTTPS": "https://novanfse.campinas.sp.gov.br/notafiscal-abrasfv203-ws/NotaFiscalSoap?wsdl",
"HOMOLOGACAO": "https://homol-rps.ima.sp.gov.br/notafiscal-abrasfv203-ws/NotaFiscalSoap?wsdl",
},
+ "MARACANAU": {
+ "CONSULTA_SERVICO": "ConsultarNfse",
+ "HTTPS": "https://speedgov.com.br/wsmar/Nfes?wsdl",
+ "HOMOLOGACAO": "",
+ },
}
# MDF-e
From 6534b1add3b306faff9d037db9b2a30cf79493bc Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Fri, 2 Jan 2026 17:02:51 -0300
Subject: [PATCH 155/175] =?UTF-8?q?adiciona=20suporte=20=C3=A0=20serializa?=
=?UTF-8?q?=C3=A7=C3=A3o=20para=20Maracana=C3=BA=20na=20classe=20Comunicac?=
=?UTF-8?q?aoNfse?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 4ba1b386..4aa91c61 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -753,6 +753,9 @@ def __init__(self, autorizador, certificado=None, certificado_senha=None, homolo
elif self.autorizador == "CAMPINAS":
self._namespace = "http://www.abrasf.org.br/nfse.xsd"
self._versao = "2"
+ elif self.autorizador == "MARACANAU":
+ self._namespace = "http://www.abrasf.org.br/ABRASF/arquivos/nfse.xsd"
+ self._versao = "1.00"
else:
raise Exception("Autorizador não encontrado!")
From 15260e18dea31afdd2c41c19b31a66db80c8d348 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Fri, 2 Jan 2026 17:09:41 -0300
Subject: [PATCH 156/175] ajusta namespaces e estrutura do XML na classe
SerializacaoMaracanau
---
pynfe/processamento/autorizador_nfse.py | 23 ++++++++++++-----------
1 file changed, 12 insertions(+), 11 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index e1077677..9e27a885 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -63,7 +63,7 @@ def soap_envelope(
NAMESPACE_XSI = "http://www.w3.org/2001/XMLSchema-instance"
NAMESPACE_XSD = "http://www.w3.org/2001/XMLSchema"
NAMESPACE_ABRASF = "http://nfse.abrasf.org.br"
-
+
xml_metodo = etree.Element("{%s}" % NAMESPACE_ABRASF + metodo)
xml_metodo.append(xml_assinado)
raiz = etree.Element(
@@ -80,7 +80,6 @@ def soap_envelope(
return etree.tostring(raiz, pretty_print=True).decode()
-
def consultar_periodo(self, emitente, data_inicio, data_fim, pagina=1):
raiz = etree.Element("ConsultarNfseServicoPrestadoEnvio")
@@ -97,7 +96,6 @@ def consultar_periodo(self, emitente, data_inicio, data_fim, pagina=1):
return etree.tostring(raiz, pretty_print=True).decode()
-
def consultar_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
raiz = etree.Element("ConsultarNfseFaixaEnvio")
@@ -114,10 +112,12 @@ def consultar_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
return etree.tostring(raiz, pretty_print=True).decode()
+
class SerializacaoMaracanau(InterfaceAutorizador):
"""
Serialização ABRASF v1.00 – Maracanaú
"""
+
def _cabecalho(self):
cabecalho_xml = """1""".strip()
return cabecalho_xml
@@ -129,9 +129,9 @@ def soap_envelope(
):
NAMESPACE_SOAP = "http://schemas.xmlsoap.org/soap/envelope/"
NAMESPACE_ABRASF = "http://www.abrasf.org.br/ABRASF/arquivos/nfse.xsd"
-
+
ns_metodo = {
- "ConsultarNfse": "http://www.abrasf.org.br/ABRASF/arquivos/nfse.xsd",
+ "ConsultarNfse": "http://ws.speedgov.com.br/consultar_nfse_envio_v1.xsd",
}
envelope = etree.Element(
@@ -145,10 +145,7 @@ def soap_envelope(
etree.SubElement(envelope, "{http://schemas.xmlsoap.org/soap/envelope/}Header")
body = etree.SubElement(envelope, "{http://schemas.xmlsoap.org/soap/envelope/}Body")
- consultar_nfse = etree.SubElement(
- body,
- "{%s}" % ns_metodo[metodo] + metodo
- )
+ consultar_nfse = etree.SubElement(body, "{%s}" % NAMESPACE_ABRASF + metodo)
header = etree.SubElement(consultar_nfse, "header")
header.text = etree.CDATA(self._cabecalho())
@@ -158,9 +155,13 @@ def soap_envelope(
return etree.tostring(envelope, pretty_print=True).decode()
-
def consultar_periodo(self, emitente, data_inicio, data_fim):
- raiz = etree.Element("ConsultarNfse")
+ NAMESPACE_SPEEDGOV_CONSULTAR_NFSE_ENVIO = (
+ "http://ws.speedgov.com.br/consultar_nfse_envio_v1.xsd"
+ )
+ raiz = etree.Element(
+ "{%s}ConsultarNfseEnvio" % NAMESPACE_SPEEDGOV_CONSULTAR_NFSE_ENVIO,
+ )
prestador = etree.SubElement(raiz, "Prestador")
etree.SubElement(prestador, "Cnpj").text = emitente.cnpj
From 467879d3dfebc0dad8ed6c089d49174c61ccd663 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Sun, 4 Jan 2026 10:31:23 -0300
Subject: [PATCH 157/175] =?UTF-8?q?adiciona=20suporte=20=C3=A0=20serializa?=
=?UTF-8?q?=C3=A7=C3=A3o=20para=20GISS=20na=20classe=20SerializacaoGiss=20?=
=?UTF-8?q?e=20integra=20ao=20fluxo=20de=20comunica=C3=A7=C3=A3o=20na=20cl?=
=?UTF-8?q?asse=20ComunicacaoNfse?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 72 +++++++++++++++++++++++++
pynfe/processamento/comunicacao.py | 56 ++++++++++++++-----
pynfe/utils/webservices.py | 5 ++
3 files changed, 120 insertions(+), 13 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index 9e27a885..e31faf67 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -174,6 +174,78 @@ def consultar_periodo(self, emitente, data_inicio, data_fim):
return etree.tostring(raiz, pretty_print=True).decode()
+class SerializacaoGiss(InterfaceAutorizador):
+ """
+ Serialização ABRASF v2.04 – GISS
+ """
+
+ NAMESPACE_SOAP = "http://schemas.xmlsoap.org/soap/envelope/"
+ NAMESPACE_XSI = "http://www.w3.org/2001/XMLSchema-instance"
+ NAMESPACE_XSD = "http://www.w3.org/2001/XMLSchema"
+ NAMESPACE_ABRASF = "http://nfse.abrasf.org.br"
+ NAMESPACE_METODO = "http://www.giss.com.br/consultar-nfse-servico-prestado-envio-v2_04.xsd"
+ NAMESPACE_TIPOS = "http://www.giss.com.br/tipos-v2_04.xsd"
+ NAMESPACE_CABECALHO = "http://www.giss.com.br/cabecalho-v2_04.xsd"
+
+ def _cabecalho(self):
+ cabecalho_xml = f"""2.04""".strip()
+ return cabecalho_xml
+
+ def soap_envelope(
+ self,
+ metodo,
+ xml_assinado,
+ ):
+ NAMESPACE_SOAP = "http://schemas.xmlsoap.org/soap/envelope/"
+ NAMESPACE_XSI = "http://www.w3.org/2001/XMLSchema-instance"
+ NAMESPACE_XSD = "http://www.w3.org/2001/XMLSchema"
+ NAMESPACE_ABRASF = "http://nfse.abrasf.org.br"
+
+ envelope = etree.Element(
+ f"{{{self.NAMESPACE_SOAP}}}Envelope",
+ nsmap={
+ "xsi": NAMESPACE_XSI,
+ "xsd": NAMESPACE_XSD,
+ "soap": NAMESPACE_SOAP,
+ "nfse": NAMESPACE_ABRASF,
+ },
+ )
+ body = etree.SubElement(envelope, f"{{{self.NAMESPACE_SOAP}}}Body")
+
+ consultar_nfse = etree.SubElement(
+ body, f"{{{self.NAMESPACE_ABRASF}}}{metodo}Request"
+ )
+
+ header = etree.SubElement(consultar_nfse, "nfseCabecMsg")
+ header.text = etree.CDATA(self._cabecalho())
+
+ parameters = etree.SubElement(consultar_nfse, "nfseDadosMsg")
+ parameters.text = etree.CDATA(xml_assinado)
+
+ return (
+ ''
+ + etree.tostring(envelope, pretty_print=True).decode()
+ )
+
+ def consultar_periodo(self, emitente, data_inicio, data_fim, pagina=1):
+ return f"""
+
+
+
+ {emitente.cnpj}
+
+ {emitente.inscricao_municipal}
+
+
+ {data_inicio}
+ {data_fim}
+
+ {pagina}
+ """.strip()
+
+
class SerializacaoBetha(InterfaceAutorizador):
def __init__(self):
# importa
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 4aa91c61..a6f143c3 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -5,7 +5,7 @@
import requests
from pynfe.entidades.certificado import CertificadoA1
-from pynfe.utils import etree, so_numeros
+from pynfe.utils import etree, obter_municipio_por_codigo, so_numeros
from pynfe.utils.flags import (
CODIGOS_ESTADOS,
MODELO_MDFE,
@@ -737,7 +737,9 @@ class ComunicacaoNfse(Comunicacao):
_versao = ""
_namespace = ""
- def __init__(self, autorizador, certificado=None, certificado_senha=None, homologacao=False):
+ def __init__(
+ self, autorizador, certificado=None, certificado_senha=None, homologacao=False, **kwargs
+ ):
self.certificado = certificado
self.certificado_senha = certificado_senha
self._ambiente = 2 if homologacao else 1
@@ -748,14 +750,17 @@ def __init__(self, autorizador, certificado=None, certificado_senha=None, homolo
elif self.autorizador == "BARUERI":
self._namespace = "http://www.barueri.sp.gov.br/nfeservice"
elif self.autorizador == "OSASCO":
- self._namespace = ""
- self._versao = "1"
+ pass
elif self.autorizador == "CAMPINAS":
- self._namespace = "http://www.abrasf.org.br/nfse.xsd"
- self._versao = "2"
+ pass
elif self.autorizador == "MARACANAU":
- self._namespace = "http://www.abrasf.org.br/ABRASF/arquivos/nfse.xsd"
- self._versao = "1.00"
+ pass
+ elif self.autorizador == "GISS":
+ if not kwargs.get("municipio_codigo"):
+ raise Exception(
+ "Para o autorizador GISS é necessário informar o código do município."
+ )
+ self.municipio_codigo = kwargs.get("municipio_codigo")
else:
raise Exception("Autorizador não encontrado!")
@@ -774,8 +779,11 @@ def consultar_rps(self, payload):
url = self._get_url()
if self.autorizador == "CAMPINAS":
from pynfe.processamento.autorizador_nfse import SerializacaoCampinas
+
xml_assinado = AssinaturaA1(self.certificado, self.certificado_senha).assinar(payload)
- envelope_xml = SerializacaoCampinas().soap_envelope(NFSE[self.autorizador]["CONSULTA_RPS"], xml_assinado)
+ envelope_xml = SerializacaoCampinas().soap_envelope(
+ NFSE[self.autorizador]["CONSULTA_RPS"], xml_assinado
+ )
return self._post_soap_raw(url, envelope_xml)
elif self.autorizador == "OSASCO":
# comunica via wsdl
@@ -788,8 +796,11 @@ def consultar_faixa(self, payload):
url = self._get_url()
if self.autorizador == "CAMPINAS":
from pynfe.processamento.autorizador_nfse import SerializacaoCampinas
+
xml_assinado = AssinaturaA1(self.certificado, self.certificado_senha).assinar(payload)
- envelope_xml = SerializacaoCampinas().soap_envelope(NFSE[self.autorizador]["CONSULTA_FAIXA"], xml_assinado)
+ envelope_xml = SerializacaoCampinas().soap_envelope(
+ NFSE[self.autorizador]["CONSULTA_FAIXA"], xml_assinado
+ )
return self._post_soap_raw(url, envelope_xml)
elif self.autorizador == "OSASCO":
# comunica via wsdl
@@ -802,12 +813,25 @@ def consultar_periodo(self, payload):
url = self._get_url()
if self.autorizador == "CAMPINAS":
from pynfe.processamento.autorizador_nfse import SerializacaoCampinas
+
xml_assinado = AssinaturaA1(self.certificado, self.certificado_senha).assinar(payload)
- envelope_xml = SerializacaoCampinas().soap_envelope(NFSE[self.autorizador]["CONSULTA_SERVICO"], xml_assinado)
+ envelope_xml = SerializacaoCampinas().soap_envelope(
+ NFSE[self.autorizador]["CONSULTA_SERVICO"], xml_assinado
+ )
return self._post_soap_raw(url, envelope_xml)
elif self.autorizador == "MARACANAU":
from pynfe.processamento.autorizador_nfse import SerializacaoMaracanau
- envelope_xml = SerializacaoMaracanau().soap_envelope(NFSE[self.autorizador]["CONSULTA_SERVICO"], payload)
+
+ envelope_xml = SerializacaoMaracanau().soap_envelope(
+ NFSE[self.autorizador]["CONSULTA_SERVICO"], payload
+ )
+ return self._post_soap_raw(url, envelope_xml)
+ elif self.autorizador == "MARACANAU":
+ from pynfe.processamento.autorizador_nfse import SerializacaoGiss
+
+ envelope_xml = SerializacaoGiss().soap_envelope(
+ NFSE[self.autorizador]["CONSULTA_SERVICO"], payload
+ )
return self._post_soap_raw(url, envelope_xml)
elif self.autorizador == "OSASCO":
# comunica via wsdl
@@ -874,6 +898,11 @@ def _get_url(self):
ambiente = "HOMOLOGACAO"
if self.autorizador in NFSE:
self.url = NFSE[self.autorizador][ambiente]
+ if self.autorizador == "GISS":
+ municipio = obter_municipio_por_codigo(
+ self.municipio_codigo, uf=self.municipio_codigo[:2], normalizado=True
+ )
+ self.url = self.url.replace("{municipio}", str(municipio.lower()))
else:
raise Exception("Autorizador nao encontrado!")
return self.url
@@ -901,6 +930,7 @@ def _post(self, url, xml, metodo):
raise Exception("Método não implementado no autorizador.")
except Exception as e:
raise e
+
def _post_soap_raw(self, url, soap_xml):
certificado_a1 = CertificadoA1(self.certificado)
key, cert = certificado_a1.separar_arquivo(self.certificado_senha, caminho=True)
@@ -909,7 +939,7 @@ def _post_soap_raw(self, url, soap_xml):
data=soap_xml.encode("utf-8"),
cert=(cert, key),
verify=False,
- headers={"Content-Type": "text/xml; charset=utf-8"}
+ headers={"Content-Type": "text/xml; charset=utf-8"},
)
def _post_https(self, url, metodo, xml):
diff --git a/pynfe/utils/webservices.py b/pynfe/utils/webservices.py
index 0336633e..9fa84ca7 100644
--- a/pynfe/utils/webservices.py
+++ b/pynfe/utils/webservices.py
@@ -534,6 +534,11 @@
"HTTPS": "https://speedgov.com.br/wsmar/Nfes?wsdl",
"HOMOLOGACAO": "",
},
+ "GISS": {
+ "CONSULTA_SERVICO": "ConsultarNfseServicoPrestado",
+ "HTTPS": "https://ws-{municipio}.giss.com.br/service-ws/nf/nfse-ws?wsdl",
+ "HOMOLOGACAO": "",
+ },
}
# MDF-e
From c0a50ebe19514f39c0707346a7abb81587d59992 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Sun, 4 Jan 2026 20:49:03 -0300
Subject: [PATCH 158/175] =?UTF-8?q?altera=20autorizador=20na=20classe=20Co?=
=?UTF-8?q?municacaoNfse=20de=20Maracana=C3=BA=20para=20GISS?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index a6f143c3..ade2bd1d 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -826,7 +826,7 @@ def consultar_periodo(self, payload):
NFSE[self.autorizador]["CONSULTA_SERVICO"], payload
)
return self._post_soap_raw(url, envelope_xml)
- elif self.autorizador == "MARACANAU":
+ elif self.autorizador == "GISS":
from pynfe.processamento.autorizador_nfse import SerializacaoGiss
envelope_xml = SerializacaoGiss().soap_envelope(
From 86f78cad778bd32df0ed36674a81a7afbb3274f1 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Sun, 4 Jan 2026 21:54:26 -0300
Subject: [PATCH 159/175] adiciona assinatura digital ao payload na classe
ComunicacaoNfse para o autorizador GISS
---
pynfe/processamento/comunicacao.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index ade2bd1d..864a4e8a 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -828,9 +828,10 @@ def consultar_periodo(self, payload):
return self._post_soap_raw(url, envelope_xml)
elif self.autorizador == "GISS":
from pynfe.processamento.autorizador_nfse import SerializacaoGiss
+ xml_assinado = AssinaturaA1(self.certificado, self.certificado_senha).assinar(payload)
envelope_xml = SerializacaoGiss().soap_envelope(
- NFSE[self.autorizador]["CONSULTA_SERVICO"], payload
+ NFSE[self.autorizador]["CONSULTA_SERVICO"], xml_assinado
)
return self._post_soap_raw(url, envelope_xml)
elif self.autorizador == "OSASCO":
From 799f1931881f54857e6fc0e97361085194669a68 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Sun, 4 Jan 2026 22:03:22 -0300
Subject: [PATCH 160/175] =?UTF-8?q?altera=20nome=20do=20par=C3=A2metro=20d?=
=?UTF-8?q?e=20'municipio=5Fcodigo'=20para=20'codigo=5Fmunicipio'=20na=20c?=
=?UTF-8?q?lasse=20ComunicacaoNfse?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 864a4e8a..8d99a46a 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -756,11 +756,11 @@ def __init__(
elif self.autorizador == "MARACANAU":
pass
elif self.autorizador == "GISS":
- if not kwargs.get("municipio_codigo"):
+ if not kwargs.get("codigo_municipio"):
raise Exception(
"Para o autorizador GISS é necessário informar o código do município."
)
- self.municipio_codigo = kwargs.get("municipio_codigo")
+ self.codigo_municipio = kwargs.get("codigo_municipio")
else:
raise Exception("Autorizador não encontrado!")
@@ -901,7 +901,7 @@ def _get_url(self):
self.url = NFSE[self.autorizador][ambiente]
if self.autorizador == "GISS":
municipio = obter_municipio_por_codigo(
- self.municipio_codigo, uf=self.municipio_codigo[:2], normalizado=True
+ self.codigo_municipio, uf=self.codigo_municipio[:2], normalizado=True
)
self.url = self.url.replace("{municipio}", str(municipio.lower()))
else:
From 464325f294106bbff10f236a902e6e98632241a2 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Sun, 4 Jan 2026 22:05:03 -0300
Subject: [PATCH 161/175] =?UTF-8?q?altera=20m=C3=A9todo=20de=20assinatura?=
=?UTF-8?q?=20na=20classe=20ComunicacaoNfse=20para=20retornar=20string?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 8d99a46a..967e9064 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -828,7 +828,7 @@ def consultar_periodo(self, payload):
return self._post_soap_raw(url, envelope_xml)
elif self.autorizador == "GISS":
from pynfe.processamento.autorizador_nfse import SerializacaoGiss
- xml_assinado = AssinaturaA1(self.certificado, self.certificado_senha).assinar(payload)
+ xml_assinado = AssinaturaA1(self.certificado, self.certificado_senha).assinar(payload, retornar_string=True)
envelope_xml = SerializacaoGiss().soap_envelope(
NFSE[self.autorizador]["CONSULTA_SERVICO"], xml_assinado
From 3fa99374466c013c63430a2ed96bc860831d3a50 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Sun, 4 Jan 2026 22:05:47 -0300
Subject: [PATCH 162/175] =?UTF-8?q?altera=20par=C3=A2metro=20'retornar=5Fs?=
=?UTF-8?q?tring'=20para=20'retorna=5Fstring'=20no=20m=C3=A9todo=20de=20as?=
=?UTF-8?q?sinatura=20da=20classe=20ComunicacaoNfse?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 967e9064..8af9b634 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -828,7 +828,7 @@ def consultar_periodo(self, payload):
return self._post_soap_raw(url, envelope_xml)
elif self.autorizador == "GISS":
from pynfe.processamento.autorizador_nfse import SerializacaoGiss
- xml_assinado = AssinaturaA1(self.certificado, self.certificado_senha).assinar(payload, retornar_string=True)
+ xml_assinado = AssinaturaA1(self.certificado, self.certificado_senha).assinar(payload, retorna_string=True)
envelope_xml = SerializacaoGiss().soap_envelope(
NFSE[self.autorizador]["CONSULTA_SERVICO"], xml_assinado
From d488cf47f36196b3ef601d02d06374fa3674a396 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 5 Jan 2026 10:44:20 -0300
Subject: [PATCH 163/175] =?UTF-8?q?altera=20classe=20SerializacaoMaracanau?=
=?UTF-8?q?=20para=20SerializacaoSpeedgov=20e=20ajusta=20l=C3=B3gica=20de?=
=?UTF-8?q?=20autoriza=C3=A7=C3=A3o=20na=20classe=20ComunicacaoNfse?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 4 +-
pynfe/processamento/comunicacao.py | 23 +++++++---
pynfe/utils/webservices.py | 59 ++++++++++++++-----------
3 files changed, 53 insertions(+), 33 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index e31faf67..b982d40f 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -113,9 +113,9 @@ def consultar_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
return etree.tostring(raiz, pretty_print=True).decode()
-class SerializacaoMaracanau(InterfaceAutorizador):
+class SerializacaoSpeedgov(InterfaceAutorizador):
"""
- Serialização ABRASF v1.00 – Maracanaú
+ Serialização ABRASF v1.00 – Speedgov
"""
def _cabecalho(self):
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 8af9b634..7090749b 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -753,8 +753,12 @@ def __init__(
pass
elif self.autorizador == "CAMPINAS":
pass
- elif self.autorizador == "MARACANAU":
- pass
+ elif self.autorizador == "SPEEDGOV":
+ if not kwargs.get("codigo_municipio"):
+ raise Exception(
+ "Para o autorizador SPEEDGOV é necessário informar o código do município."
+ )
+ self.codigo_municipio = kwargs.get("codigo_municipio")
elif self.autorizador == "GISS":
if not kwargs.get("codigo_municipio"):
raise Exception(
@@ -819,17 +823,19 @@ def consultar_periodo(self, payload):
NFSE[self.autorizador]["CONSULTA_SERVICO"], xml_assinado
)
return self._post_soap_raw(url, envelope_xml)
- elif self.autorizador == "MARACANAU":
- from pynfe.processamento.autorizador_nfse import SerializacaoMaracanau
+ elif self.autorizador == "SPEEDGOV":
+ from pynfe.processamento.autorizador_nfse import SerializacaoSpeedgov
- envelope_xml = SerializacaoMaracanau().soap_envelope(
+ envelope_xml = SerializacaoSpeedgov().soap_envelope(
NFSE[self.autorizador]["CONSULTA_SERVICO"], payload
)
return self._post_soap_raw(url, envelope_xml)
elif self.autorizador == "GISS":
from pynfe.processamento.autorizador_nfse import SerializacaoGiss
- xml_assinado = AssinaturaA1(self.certificado, self.certificado_senha).assinar(payload, retorna_string=True)
+ xml_assinado = AssinaturaA1(self.certificado, self.certificado_senha).assinar(
+ payload, retorna_string=True
+ )
envelope_xml = SerializacaoGiss().soap_envelope(
NFSE[self.autorizador]["CONSULTA_SERVICO"], xml_assinado
)
@@ -904,6 +910,11 @@ def _get_url(self):
self.codigo_municipio, uf=self.codigo_municipio[:2], normalizado=True
)
self.url = self.url.replace("{municipio}", str(municipio.lower()))
+ if self.autorizador == "SPEEDGOV":
+ self.url = self.url.replace(
+ "{suffix_municipio}",
+ NFSE[self.autorizador]["SUFFIX_MUNICIPIO"][str(self.codigo_municipio)],
+ )
else:
raise Exception("Autorizador nao encontrado!")
return self.url
diff --git a/pynfe/utils/webservices.py b/pynfe/utils/webservices.py
index 9fa84ca7..1b2f72e3 100644
--- a/pynfe/utils/webservices.py
+++ b/pynfe/utils/webservices.py
@@ -315,7 +315,7 @@
"HTTPS": "https://",
"HOMOLOGACAO": "https://hom",
},
- "MA": {"CADASTRO": ("https://sistemas.sefaz.ma.gov.br/wscadastro/CadConsultaCadastro2?wsdl")},
+ "MA": {"CADASTRO": "https://sistemas.sefaz.ma.gov.br/wscadastro/CadConsultaCadastro2?wsdl"},
"PE": {
"STATUS": "sefaz.pe.gov.br/nfe-service/services/NFeStatusServico4",
"AUTORIZACAO": "sefaz.pe.gov.br/nfe-service/services/NFeAutorizacao4",
@@ -328,14 +328,12 @@
"HOMOLOGACAO": "https://nfehomolog.",
},
"BA": {
- "STATUS": ("nfe.sefaz.ba.gov.br/webservices/NFeStatusServico4/NFeStatusServico4.asmx"),
- "AUTORIZACAO": ("nfe.sefaz.ba.gov.br/webservices/NFeAutorizacao4/NFeAutorizacao4.asmx"),
- "RECIBO": ("nfe.sefaz.ba.gov.br/webservices/NFeRetAutorizacao4/NFeRetAutorizacao4.asmx"),
- "CHAVE": (
- "nfe.sefaz.ba.gov.br/webservices/NFeConsultaProtocolo4/NFeConsultaProtocolo4.asmx"
- ),
- "INUTILIZACAO": ("nfe.sefaz.ba.gov.br/webservices/NFeInutilizacao4/NFeInutilizacao4.asmx"),
- "EVENTOS": ("nfe.sefaz.ba.gov.br/webservices/NFeRecepcaoEvento4/NFeRecepcaoEvento4.asmx"),
+ "STATUS": "nfe.sefaz.ba.gov.br/webservices/NFeStatusServico4/NFeStatusServico4.asmx",
+ "AUTORIZACAO": "nfe.sefaz.ba.gov.br/webservices/NFeAutorizacao4/NFeAutorizacao4.asmx",
+ "RECIBO": "nfe.sefaz.ba.gov.br/webservices/NFeRetAutorizacao4/NFeRetAutorizacao4.asmx",
+ "CHAVE": "nfe.sefaz.ba.gov.br/webservices/NFeConsultaProtocolo4/NFeConsultaProtocolo4.asmx",
+ "INUTILIZACAO": "nfe.sefaz.ba.gov.br/webservices/NFeInutilizacao4/NFeInutilizacao4.asmx",
+ "EVENTOS": "nfe.sefaz.ba.gov.br/webservices/NFeRecepcaoEvento4/NFeRecepcaoEvento4.asmx",
"CADASTRO": (
"nfe.sefaz.ba.gov.br/webservices/CadConsultaCadastro4/CadConsultaCadastro4.asmx"
),
@@ -365,10 +363,10 @@
"HOMOLOGACAO": "https://homologacao.",
},
"PR": {
- "STATUS": ("nfe.sefa.pr.gov.br/nfe/NFeStatusServico4"), # CONSULTA STATUS DO SERVICO
+ "STATUS": "nfe.sefa.pr.gov.br/nfe/NFeStatusServico4", # CONSULTA STATUS DO SERVICO
"AUTORIZACAO": "nfe.sefa.pr.gov.br/nfe/NFeAutorizacao4", # AUTORIZACAO
"RECIBO": "nfe.sefa.pr.gov.br/nfe/NFeRetAutorizacao4", # CONSULTA RECIBO
- "CHAVE": ("nfe.sefa.pr.gov.br/nfe/NFeConsultaProtocolo4"), # CONSULTA CHAVE DE ACESSO
+ "CHAVE": "nfe.sefa.pr.gov.br/nfe/NFeConsultaProtocolo4", # CONSULTA CHAVE DE ACESSO
"INUTILIZACAO": "nfe.sefa.pr.gov.br/nfe/NFeInutilizacao4", # INUTILIZAÇAO
"EVENTOS": "nfe.sefa.pr.gov.br/nfe/NFeRecepcaoEvento4", # REGISTRO DE EVENTOS
"CADASTRO": "nfe.sefa.pr.gov.br/nfe/CadConsultaCadastro4", # CONSULTA CADASTRO
@@ -425,12 +423,12 @@
"HOMOLOGACAO": "https://homolog.",
},
"SVAN": {
- "STATUS": ("sefazvirtual.fazenda.gov.br/NFeStatusServico4/NFeStatusServico4.asmx"),
- "AUTORIZACAO": ("sefazvirtual.fazenda.gov.br/NFeAutorizacao4/NFeAutorizacao4.asmx"),
- "RECIBO": ("sefazvirtual.fazenda.gov.br/NFeRetAutorizacao4/NFeRetAutorizacao4.asmx"),
+ "STATUS": "sefazvirtual.fazenda.gov.br/NFeStatusServico4/NFeStatusServico4.asmx",
+ "AUTORIZACAO": "sefazvirtual.fazenda.gov.br/NFeAutorizacao4/NFeAutorizacao4.asmx",
+ "RECIBO": "sefazvirtual.fazenda.gov.br/NFeRetAutorizacao4/NFeRetAutorizacao4.asmx",
"CHAVE": "sefazvirtual.fazenda.gov.br/NFeConsultaProtocolo4/NFeConsultaProtocolo4.asmx",
- "INUTILIZACAO": ("sefazvirtual.fazenda.gov.br/NFeInutilizacao4/NFeInutilizacao4.asmx"),
- "EVENTOS": ("sefazvirtual.fazenda.gov.br/NFeRecepcaoEvento4/NFeRecepcaoEvento4.asmx"),
+ "INUTILIZACAO": "sefazvirtual.fazenda.gov.br/NFeInutilizacao4/NFeInutilizacao4.asmx",
+ "EVENTOS": "sefazvirtual.fazenda.gov.br/NFeRecepcaoEvento4/NFeRecepcaoEvento4.asmx",
"DOWNLOAD": "sefazvirtual.fazenda.gov.br/NfeDownloadNF/NfeDownloadNF.asmx",
"HTTPS": "https://www.",
"HOMOLOGACAO": "https://hom.",
@@ -478,14 +476,14 @@
"CANCELAR_NFSE": "CancelamentoNFe",
# New URL supports both v1 and v2 (Reforma Tributária 2026)
# Old URL (v1 only): https://nfe.prefeitura.sp.gov.br/ws/lotenfe.asmx?wsdl
- "HTTPS": "https://nfews.prefeitura.sp.gov.br/lotenfe.asmx?WSDL"
+ "HTTPS": "https://nfews.prefeitura.sp.gov.br/lotenfe.asmx?WSDL",
},
"BARUERI": {
"ENVIAR_RPS": "EnviarRPS",
"CONSULTA_RPS": "ConsultaNFe",
"CANCELAR_NFSE": "CancelamentoNFe",
"HTTPS": "https://www.barueri.sp.gov.br/nfeservice/wsrps.asmx?WSDL",
- "HOMOLOGACAO": "https://testeeiss.barueri.sp.gov.br/nfeservice/wsrps.asmx?WSDL"
+ "HOMOLOGACAO": "https://testeeiss.barueri.sp.gov.br/nfeservice/wsrps.asmx?WSDL",
},
"BETHA": {
"AUTORIZACAO": "GerarNfse",
@@ -496,7 +494,7 @@
"CONSULTA_SERVICO_TOMADO": "ConsultarNfseServicoTomado",
"SUBSTITUIR": "SubstituirNfse",
"HTTPS": "http://e-gov.betha.com.br/e-nota-contribuinte-ws/nfseWS?wsdl",
- "HOMOLOGACAO": ("http://e-gov.betha.com.br/e-nota-contribuinte-test-ws/nfseWS?wsdl"),
+ "HOMOLOGACAO": "http://e-gov.betha.com.br/e-nota-contribuinte-test-ws/nfseWS?wsdl",
},
#
"GINFES": {
@@ -515,9 +513,8 @@
"CONSULTA": "Consultar",
"CONSULTA_COMPLETA": "ConsultarNotaCompleta",
"HTTPS": "https://nfe.osasco.sp.gov.br/EISSNFEWebServices/NotaFiscalEletronica.svc?wsdl",
- "HOMOLOGACAO": (
- "https://nfe.osasco.sp.gov.br/EISSNFEWebServices/NotaFiscalEletronica.svc?wsdl"
- ),
+ "HOMOLOGACAO": "",
+ "DOWNLOAD": "https://nfe.osasco.sp.gov.br/EissnfeWebApp/Sistema/Prestador/VisualizarNFENew.aspx?Id={identificador}",
},
"CAMPINAS": {
"AUTORIZACAO": "GerarNfse",
@@ -527,17 +524,29 @@
"CONSULTA_SERVICO": "ConsultarNfseServicoPrestado",
"CONSULTA_SERVICO_TOMADO": "ConsultarNfseServicoTomado",
"HTTPS": "https://novanfse.campinas.sp.gov.br/notafiscal-abrasfv203-ws/NotaFiscalSoap?wsdl",
- "HOMOLOGACAO": "https://homol-rps.ima.sp.gov.br/notafiscal-abrasfv203-ws/NotaFiscalSoap?wsdl",
+ "HOMOLOGACAO": "",
+ "DOWNLOAD": (
+ "https://novanfse.campinas.sp.gov.br/notafiscal-ws/servico/notafiscal/autenticacao/cpfCnpj/{cpf_cnpj}/inscricaoMunicipal/{im}/numeroNota/{numero_nfse}/codigoVerificacao/{codigo_verificacao}"
+ ),
},
- "MARACANAU": {
+ "SPEEDGOV": {
"CONSULTA_SERVICO": "ConsultarNfse",
- "HTTPS": "https://speedgov.com.br/wsmar/Nfes?wsdl",
+ "HTTPS": "https://speedgov.com.br/ws{suffix_municipio}/Nfes?wsdl",
"HOMOLOGACAO": "",
+ "DOWNLOAD": (
+ "https://speedgov.com.br/sat{suffix_municipio}/servlet//com.satweb.aratb177e?1,1,1,1,{im},{numero_nfse},{codigo_verificacao}"
+ ),
+ "SUFFIX_MUNICIPIO": {
+ "2307650":"mar"
+ },
},
"GISS": {
"CONSULTA_SERVICO": "ConsultarNfseServicoPrestado",
"HTTPS": "https://ws-{municipio}.giss.com.br/service-ws/nf/nfse-ws?wsdl",
"HOMOLOGACAO": "",
+ "DOWNLOAD": (
+ "https://gissv2-{codigo_ibge}.eiconbrasil.com.br/service-relatorio/api/relatorio/nota-autenticacao/{tipo_doc}/{codigo_ibge}/{identificador}/codigo-verificacao/{codigo_verificacao}"
+ ),
},
}
From 893fe3bd0f9785e097e3354f48a4180fd820b0ef Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 5 Jan 2026 12:08:58 -0300
Subject: [PATCH 164/175] adiciona suporte para novos autorizadores GISS e
Speedgov na classe SerializacaoNfse
---
pynfe/processamento/serializacao.py | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/pynfe/processamento/serializacao.py b/pynfe/processamento/serializacao.py
index 760186a4..46a5056a 100644
--- a/pynfe/processamento/serializacao.py
+++ b/pynfe/processamento/serializacao.py
@@ -2158,6 +2158,14 @@ def consultar_periodo(self, emitente, data_inicio, data_fim, pagina=1):
from pynfe.processamento.autorizador_nfse import SerializacaoOsasco
return SerializacaoOsasco(self.chave_autenticacao).consultar(data_inicial=data_inicio, data_final=data_fim)
+ elif self.autorizador.lower() == "giss":
+ from pynfe.processamento.autorizador_nfse import SerializacaoGiss
+
+ return SerializacaoGiss(self.chave_autenticacao).consultar_periodo(emitente, data_inicio, data_fim, pagina=1)
+ elif self.autorizador.lower() == "speedgov":
+ from pynfe.processamento.autorizador_nfse import SerializacaoSpeedgov
+
+ return SerializacaoSpeedgov(self.chave_autenticacao).consultar_periodo(emitente, data_inicio, data_fim)
else:
raise Exception(f"Este método não esta implementado para o autorizador {self.autorizador.upper()}")
From fdaeafacd864872fa0e385c1e4d124f4ec8312a0 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 5 Jan 2026 12:59:34 -0300
Subject: [PATCH 165/175] =?UTF-8?q?corrige=20inst=C3=A2ncia=20de=20Seriali?=
=?UTF-8?q?zacaoGiss=20e=20SerializacaoSpeedgov=20na=20classe=20Serializac?=
=?UTF-8?q?aoNfse?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/serializacao.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pynfe/processamento/serializacao.py b/pynfe/processamento/serializacao.py
index 46a5056a..ec42071f 100644
--- a/pynfe/processamento/serializacao.py
+++ b/pynfe/processamento/serializacao.py
@@ -2161,11 +2161,11 @@ def consultar_periodo(self, emitente, data_inicio, data_fim, pagina=1):
elif self.autorizador.lower() == "giss":
from pynfe.processamento.autorizador_nfse import SerializacaoGiss
- return SerializacaoGiss(self.chave_autenticacao).consultar_periodo(emitente, data_inicio, data_fim, pagina=1)
+ return SerializacaoGiss().consultar_periodo(emitente, data_inicio, data_fim, pagina=1)
elif self.autorizador.lower() == "speedgov":
from pynfe.processamento.autorizador_nfse import SerializacaoSpeedgov
- return SerializacaoSpeedgov(self.chave_autenticacao).consultar_periodo(emitente, data_inicio, data_fim)
+ return SerializacaoSpeedgov().consultar_periodo(emitente, data_inicio, data_fim)
else:
raise Exception(f"Este método não esta implementado para o autorizador {self.autorizador.upper()}")
From d110d60c6ba3ae6f2c58f9c920057da6dc04b002 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 5 Jan 2026 16:09:38 -0300
Subject: [PATCH 166/175] =?UTF-8?q?corrige=20convers=C3=A3o=20de=20c=C3=B3?=
=?UTF-8?q?digo=20municipal=20para=20string=20na=20classe=20ComunicacaoNfs?=
=?UTF-8?q?e?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 7090749b..b5111744 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -907,7 +907,7 @@ def _get_url(self):
self.url = NFSE[self.autorizador][ambiente]
if self.autorizador == "GISS":
municipio = obter_municipio_por_codigo(
- self.codigo_municipio, uf=self.codigo_municipio[:2], normalizado=True
+ str(self.codigo_municipio), uf=str(self.codigo_municipio)[:2], normalizado=True
)
self.url = self.url.replace("{municipio}", str(municipio.lower()))
if self.autorizador == "SPEEDGOV":
From e778aa376f20a18d549107a61a95488136bea8fb Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Tue, 6 Jan 2026 18:15:07 -0300
Subject: [PATCH 167/175] =?UTF-8?q?ajusta=20passagem=20do=20par=C3=A2metro?=
=?UTF-8?q?=20'pagina'=20nos=20m=C3=A9todos=20de=20consulta=20da=20classe?=
=?UTF-8?q?=20SerializacaoNfse?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/serializacao.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/pynfe/processamento/serializacao.py b/pynfe/processamento/serializacao.py
index ec42071f..08c456b6 100644
--- a/pynfe/processamento/serializacao.py
+++ b/pynfe/processamento/serializacao.py
@@ -2142,7 +2142,7 @@ def consultar_faixa(self, emitente, numero_inicial, numero_final, pagina=1):
if self.autorizador.lower() == "campinas":
from pynfe.processamento.autorizador_nfse import SerializacaoCampinas
- return SerializacaoCampinas().consultar_faixa(emitente, numero_inicial, numero_final, pagina=1)
+ return SerializacaoCampinas().consultar_faixa(emitente, numero_inicial, numero_final, pagina=pagina)
elif self.autorizador.lower() == "osasco":
from pynfe.processamento.autorizador_nfse import SerializacaoOsasco
return SerializacaoOsasco(self.chave_autenticacao).consultar(numero_nota_inicial=numero_inicial, numero_nota_final=numero_final)
@@ -2153,7 +2153,7 @@ def consultar_periodo(self, emitente, data_inicio, data_fim, pagina=1):
if self.autorizador.lower() == "campinas":
from pynfe.processamento.autorizador_nfse import SerializacaoCampinas
- return SerializacaoCampinas().consultar_periodo(emitente, data_inicio, data_fim, pagina=1)
+ return SerializacaoCampinas().consultar_periodo(emitente, data_inicio, data_fim, pagina=pagina)
elif self.autorizador.lower() == "osasco":
from pynfe.processamento.autorizador_nfse import SerializacaoOsasco
@@ -2161,7 +2161,7 @@ def consultar_periodo(self, emitente, data_inicio, data_fim, pagina=1):
elif self.autorizador.lower() == "giss":
from pynfe.processamento.autorizador_nfse import SerializacaoGiss
- return SerializacaoGiss().consultar_periodo(emitente, data_inicio, data_fim, pagina=1)
+ return SerializacaoGiss().consultar_periodo(emitente, data_inicio, data_fim, pagina=pagina)
elif self.autorizador.lower() == "speedgov":
from pynfe.processamento.autorizador_nfse import SerializacaoSpeedgov
From 0feaf9a7e3710e8534b4b3ea117b4b3d69b360f8 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 12 Jan 2026 08:19:04 -0300
Subject: [PATCH 168/175] =?UTF-8?q?adiciona=20suporte=20para=20o=20autoriz?=
=?UTF-8?q?ador=20GINFES=20na=20classe=20ComunicacaoNfse=20e=20renomeia=20?=
=?UTF-8?q?m=C3=A9todo=20de=20consulta=20na=20classe=20SerializacaoGinfes?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/autorizador_nfse.py | 3 ++-
pynfe/processamento/comunicacao.py | 10 +++++++++-
2 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/pynfe/processamento/autorizador_nfse.py b/pynfe/processamento/autorizador_nfse.py
index b982d40f..7a8a5747 100644
--- a/pynfe/processamento/autorizador_nfse.py
+++ b/pynfe/processamento/autorizador_nfse.py
@@ -492,8 +492,9 @@ def serializar_lote_sincrono(self, nfse):
class SerializacaoGinfes(InterfaceAutorizador):
def __init__(self):
pass
+
- def consultar_servico_prestado(self, emitente, data_inicio, data_fim, pagina=1):
+ def consultar_periodo(self, emitente, data_inicio, data_fim, pagina=1):
NS = "http://www.ginfes.com.br/servico_consultar_nfse_servico_prestado_envio_v03.xsd"
DS = "http://www.w3.org/2000/09/xmldsig#"
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index b5111744..d2ddc279 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -744,7 +744,10 @@ def __init__(
self.certificado_senha = certificado_senha
self._ambiente = 2 if homologacao else 1
self.autorizador = autorizador.upper()
- if self.autorizador == "SAO_PAULO":
+ if self.autorizador == "GINFES":
+ self._namespace = "http://www.ginfes.com.br/cabecalho_v03.xsd"
+ self._versao = "3"
+ elif self.autorizador == "SAO_PAULO":
self._namespace = "http://www.prefeitura.sp.gov.br/nfe"
self._versao = "2"
elif self.autorizador == "BARUERI":
@@ -843,6 +846,11 @@ def consultar_periodo(self, payload):
elif self.autorizador == "OSASCO":
# comunica via wsdl
return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA"], payload)
+ elif self.autorizador == "GINFES":
+ # xml
+ xml = '' + xml
+ # comunica via wsdl
+ return self._post_https(url, xml, "ConsultarNfseV3")
else:
raise Exception("Este método não esta implementado para o autorizador.")
From 901d91ded2a838a067351a0d9831ce887bfb98cc Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 12 Jan 2026 08:21:49 -0300
Subject: [PATCH 169/175] adiciona suporte para o autorizador GINFES na classe
SerializacaoNfse
---
pynfe/processamento/serializacao.py | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/pynfe/processamento/serializacao.py b/pynfe/processamento/serializacao.py
index 08c456b6..fe3033ba 100644
--- a/pynfe/processamento/serializacao.py
+++ b/pynfe/processamento/serializacao.py
@@ -2166,6 +2166,10 @@ def consultar_periodo(self, emitente, data_inicio, data_fim, pagina=1):
from pynfe.processamento.autorizador_nfse import SerializacaoSpeedgov
return SerializacaoSpeedgov().consultar_periodo(emitente, data_inicio, data_fim)
+ elif self.autorizador.lower() == "ginfes":
+ from pynfe.processamento.autorizador_nfse import SerializacaoGinfes
+
+ return SerializacaoGinfes().consultar_periodo(emitente, data_inicio, data_fim, pagina=pagina)
else:
raise Exception(f"Este método não esta implementado para o autorizador {self.autorizador.upper()}")
From 2cbc954707acacc1034cd26f60f6eb5a885fed52 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 12 Jan 2026 08:28:19 -0300
Subject: [PATCH 170/175] =?UTF-8?q?corrige=20constru=C3=A7=C3=A3o=20do=20X?=
=?UTF-8?q?ML=20na=20classe=20ComunicacaoNfse=20para=20usar=20o=20payload?=
=?UTF-8?q?=20correto?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index d2ddc279..2ce99eff 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -848,7 +848,7 @@ def consultar_periodo(self, payload):
return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA"], payload)
elif self.autorizador == "GINFES":
# xml
- xml = '' + xml
+ xml = '' + payload
# comunica via wsdl
return self._post_https(url, xml, "ConsultarNfseV3")
else:
From a11b78bd17c76b413fd9ce1fd28a60211b7725e3 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 12 Jan 2026 08:30:42 -0300
Subject: [PATCH 171/175] =?UTF-8?q?corrige=20codifica=C3=A7=C3=A3o=20do=20?=
=?UTF-8?q?payload=20na=20classe=20ComunicacaoNfse=20para=20UTF-8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 2ce99eff..c5289d71 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -848,7 +848,7 @@ def consultar_periodo(self, payload):
return self._post_zeep(url, NFSE[self.autorizador]["CONSULTA"], payload)
elif self.autorizador == "GINFES":
# xml
- xml = '' + payload
+ xml = '' + payload.decode("utf-8")
# comunica via wsdl
return self._post_https(url, xml, "ConsultarNfseV3")
else:
From 0b083993e50d2f7c4dda2cdd5379c067307dbfc2 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 12 Jan 2026 08:32:47 -0300
Subject: [PATCH 172/175] =?UTF-8?q?ajusta=20ordem=20dos=20par=C3=A2metros?=
=?UTF-8?q?=20no=20m=C3=A9todo=20=5Fpost=5Fhttps=20da=20classe=20Comunicac?=
=?UTF-8?q?aoNfse?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index c5289d71..2723b686 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -850,7 +850,7 @@ def consultar_periodo(self, payload):
# xml
xml = '' + payload.decode("utf-8")
# comunica via wsdl
- return self._post_https(url, xml, "ConsultarNfseV3")
+ return self._post_https(url, "ConsultarNfseV3", xml)
else:
raise Exception("Este método não esta implementado para o autorizador.")
From 033b28696a20085cb39e596b20127dad668be67c Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Mon, 12 Jan 2026 08:54:24 -0300
Subject: [PATCH 173/175] =?UTF-8?q?ajusta=20m=C3=A9todo=20=5Fpost=5Fhttps?=
=?UTF-8?q?=20na=20classe=20ComunicacaoNfse=20para=20aceitar=20par=C3=A2me?=
=?UTF-8?q?tros=20na=20ordem=20correta=20e=20implementa=20l=C3=B3gica=20pa?=
=?UTF-8?q?ra=20diferentes=20tipos=20de=20chamadas?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 37 ++++++++++++++++++++++--------
1 file changed, 27 insertions(+), 10 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index 2723b686..c2befd66 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -850,7 +850,7 @@ def consultar_periodo(self, payload):
# xml
xml = '' + payload.decode("utf-8")
# comunica via wsdl
- return self._post_https(url, "ConsultarNfseV3", xml)
+ return self._post_https(url, xml, "consulta")
else:
raise Exception("Este método não esta implementado para o autorizador.")
@@ -962,7 +962,7 @@ def _post_soap_raw(self, url, soap_xml):
headers={"Content-Type": "text/xml; charset=utf-8"},
)
- def _post_https(self, url, metodo, xml):
+ def _post_https(self, url, xml, metodo):
"""Comunicação wsdl (https) utilizando certificado do usuário"""
# cabecalho
cabecalho = self._cabecalho()
@@ -971,21 +971,38 @@ def _post_https(self, url, metodo, xml):
from pynfe.utils.https_nfse import HttpAuthenticated
from suds.client import Client
- certificado_a1 = CertificadoA1(self.certificado)
-
- chave, cert = certificado_a1.separar_arquivo(self.certificado_senha, caminho=True)
+ certificadoA1 = CertificadoA1(self.certificado)
+ chave, cert = certificadoA1.separar_arquivo(self.certificado_senha, caminho=True)
cliente = Client(url, transport=HttpAuthenticated(key=chave, cert=cert, endereco=url))
# gerar nfse
- try:
- service = getattr(cliente.service, metodo)
- except AttributeError:
- raise ValueError(f"Método '{metodo}' não disponível para {self.autorizador}.")
- return service(xml)
+ if metodo == "gerar":
+ return cliente.service.GerarNfse(cabecalho, xml)
+ elif metodo == "enviar_lote":
+ return cliente.service.RecepcionarLoteRpsV3(cabecalho, xml)
+ elif metodo == "consulta":
+ return cliente.service.ConsultarNfseV3(cabecalho, xml)
+ elif metodo == "consulta_lote":
+ return cliente.service.ConsultarLoteRpsV3(cabecalho, xml)
+ elif metodo == "consulta_situacao_lote":
+ return cliente.service.ConsultarSituacaoLoteRpsV3(cabecalho, xml)
+ elif metodo == "consultaRps":
+ return cliente.service.ConsultarNfsePorRpsV3(cabecalho, xml)
+ elif metodo == "consultaFaixa":
+ return cliente.service.ConsultarNfseFaixa(cabecalho, xml)
+ elif metodo == "cancelar":
+ # versão 2
+ return cliente.service.CancelarNfse(xml)
+ # versão 3
+ # return cliente.service.CancelarNfseV3(cabecalho, xml)
+ # TODO outros metodos
+ else:
+ raise Exception("Método não implementado no autorizador.")
except Exception as e:
raise e
+
def enviar_barueri(self, xml, operation):
url = self._get_url()
From 059d069181c03d032700af0db456a5d04a53b240 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Fri, 30 Jan 2026 11:43:50 -0300
Subject: [PATCH 174/175] =?UTF-8?q?atualiza=20lista=20de=20estados=20para?=
=?UTF-8?q?=20conting=C3=AAncia=20no=20m=C3=A9todo=20=5Fget=5Furl=20da=20c?=
=?UTF-8?q?lasse=20ComunicacaoSefaz?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index c2befd66..e43f4efc 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -508,7 +508,7 @@ def _get_url_an(self, consulta):
def _get_url(self, modelo, consulta, contingencia=False):
"""Retorna a url para comunicação com o webservice"""
if contingencia:
- contingencia_svrs = ["AM", "BA", "CE", "GO", "MA", "MS", "MT", "PE", "PR"]
+ contingencia_svrs = ["SP", "AM", "BA", "CE", "GO", "MA", "MS", "MT", "PE", "PR"]
contingencia_svan = [
"AC",
"AL",
@@ -526,7 +526,6 @@ def _get_url(self, modelo, consulta, contingencia=False):
"RS",
"SC",
"SE",
- "SP",
"TO",
]
From bba39386a8574839da4554890dc537540bde71c9 Mon Sep 17 00:00:00 2001
From: Lucas Svizzero Ribeiro
Date: Fri, 30 Jan 2026 11:45:59 -0300
Subject: [PATCH 175/175] =?UTF-8?q?adiciona=20estado=20SP=20=C3=A0=20lista?=
=?UTF-8?q?=20de=20conting=C3=AAncia=20no=20m=C3=A9todo=20=5Fget=5Furl=20d?=
=?UTF-8?q?a=20classe=20ComunicacaoSefaz?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pynfe/processamento/comunicacao.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/pynfe/processamento/comunicacao.py b/pynfe/processamento/comunicacao.py
index e43f4efc..c2befd66 100644
--- a/pynfe/processamento/comunicacao.py
+++ b/pynfe/processamento/comunicacao.py
@@ -508,7 +508,7 @@ def _get_url_an(self, consulta):
def _get_url(self, modelo, consulta, contingencia=False):
"""Retorna a url para comunicação com o webservice"""
if contingencia:
- contingencia_svrs = ["SP", "AM", "BA", "CE", "GO", "MA", "MS", "MT", "PE", "PR"]
+ contingencia_svrs = ["AM", "BA", "CE", "GO", "MA", "MS", "MT", "PE", "PR"]
contingencia_svan = [
"AC",
"AL",
@@ -526,6 +526,7 @@ def _get_url(self, modelo, consulta, contingencia=False):
"RS",
"SC",
"SE",
+ "SP",
"TO",
]