Skip to content
This repository was archived by the owner on May 22, 2026. It is now read-only.

Repository files navigation

PyTrustNFe

Biblioteca Python que tem por objetivo enviar NFe, NFCe e NFSe no Brasil

Coverage StatusCode HealthBuild StatusPyPI version

Empacotamento Loggi (Poetry — Python 3.8 / política moderna)

Este fork usa Python >=3.8.1,<3.9 e Poetry 1.8.5 como fonte de verdade (pyproject.toml + poetry.lock). Use Docker, comandos locais e/ou GitHub Actions (.github/workflows/publish-python.yaml) que publicam no AWS CodeArtifact (mesmo padrão que o pacote Python do monorepo xproto).

Versões (publicação Loggi):CalVerYYYYMMDD.X sem zero à esquerda após o ponto — ex.: 20260515.1, 20260515.2 (esse é o formato a usar em pyproject.toml, tags e workflows; evite 20260515.01). Builds snapshot no CI ganham sufixo local -dev+<git short sha>.

Notas de versão das libs: faixas altas compatíveis com 3.8 (por exemplo urllib3 2.x, zeep 4.x, lxml 5.x); cryptography fica >=42,<47 enquanto o signxml atual referencia curvas ECC legadas removidas no 47; reportlab fica <4 para evitar md5(..., usedforsecurity=False) incompatível com alguns backends hashlib quando OpenSSL está no processo.

Empilhamento lxml / xmlsec: rodas públicas podem causar lxml & xmlsec libxml2 library version mismatch. O Dockerfile usa bookworm, reinstala lxml e xmlsecdo código-fonte contra as libs do sistema. Em hosts sem esse alinhamento, use o mesmo comando no venv ou confie na imagem:

poetry run python - <<'PY'import subprocess, sysfrom pkg_resources import get_distributionlv = get_distribution("lxml").versionxv = get_distribution("xmlsec").versionsubprocess.check_call( [sys.executable, "-m", "pip", "install", "--no-cache-dir", "--force-reinstall", "--no-binary=lxml", "--no-binary=xmlsec", f"lxml=={lv}", f"xmlsec=={xv}"])PY

Cache Poetry / hashes reportlab: se um wheel falhar no hash verificado, limpe ~/.cache/pypoetry/artifacts e rode poetry install de novo.

Comandos úteis (máquina local)

Python 3.8.1+ e Poetry 1.8.5 (pipx install poetry==1.8.5):

poetry install --with dev
poetry run pytest

Imagem Docker (Debian bookworm; falha no build se pytest falhar):

make build # ou: docker build -t pytrustnfe-build .
make test

Gerar wheel + sdist no host (copia para ./dist):

make dist # antes: make build ; gera .whl e .tar.gz alinhados ao version do pyproject.toml

Publicação:AWS CodeArtifact (repositório PyPI loggi, URL alinhada ao xproto: pyproject.toml + poetry.toml). O token vem de aws codeartifact get-authorization-token; o Poetry usa usuário aws e a senha igual ao token (POETRY_HTTP_BASIC_LOGGI_*).

Makefile (build em ./dist → publicar no CodeArtifact):

make aws-sso # aws sso login --profile platform-prod-sso (quando precisar)
make build # Update the image and the latest changes
make dist # wheel + sdist em ./dist (imagem Docker)
make publish-ca # publica só o que já está em ./dist# ou um único comando (equivale a `poetry publish --build`):
make publish-ca-build

Bump de versão (CalVer) + build + upload (equivale ao que o CI faz):

make publish-release VERSION=20260515.1

Ou só publicar o que já está versionado / em ./dist: use make publish-ca / make publish-ca-build acima.

Variáveis opcionais Make/shell: AWS_PROFILE, CODEARTIFACT_* (ver ops/publish-codeartifact.sh).

CI:.github/workflows/publish-python.yaml (workflow_dispatch ou workflow_call) — mesmo fluxo que make publish-release (poetry version + poetry publish --build --repository loggi). Secrets AWS_ACCESS_KEY_ID_CODE_ARTIFACT, AWS_SECRET_ACCESS_KEY_CODE_ARTIFACT, AWS_REGION_CODE_ARTIFACT, AWS_DOMAIN_OWNER_CODE_ARTIFACT (iguais ao workflow Python do xproto).

Depois de publicar no CodeArtifact: atualize consumidores (loggi-web, nfe-sp, etc.) para a versão pinada e rode poetry lock onde couber.


Dependências (resumo — detalhes em pyproject.toml):

  • PyXmlSec / xmlsec
  • lxml
  • signxml
  • suds-community
  • suds-requests4
  • reportlab
  • Jinja2

NFSe - Cidades atendidas

  • Paulistana - São Paulo/SP
  • Nota Carioca - Rio de Janeiro/RJ
  • Imperial - Petrópolis/RH
  • Susesu - 3 cidades atendidas
  • Simpliss - 18 cidade atendidas
  • GINFES - 79 cidades atendidas
  • DSF - 7 cidades atendidas

Roadmap

Teste unitários

Implementar novos provedores de NFSe

Exemplos de uso da NFe

Consulta Cadastro por CNPJ:

frompytrustnfe.nfeimportconsulta_cadastrofrompytrustnfe.certificadoimportCertificadocertificado=open("/path/certificado.pfx", "r").read()
certificado=Certificado(certificado, 'senha_pfx')
obj= {'cnpj': '12345678901234', 'estado': '42'}
resposta=consulta_cadastro(certificado, obj=obj, ambiente=1, estado='42')

Consulta Distribuição NF-e sem Validação de Esquema:

frompytrustnfe.certificadoimportCertificadofrompytrustnfe.nfeimportconsulta_distribuicao_nfe, xml_consulta_distribuicao_nfecertificado=open("/path/certificado.pfx", "r").read()
certificado=Certificado(certificado, 'senha_pfx')
# Gerando xml e enviado consulta por Ultimo NSUresponse1=consulta_distribuicao_nfe(
certificado,
ambiente=1,
estado='42',
modelo='55',
cnpj_cpf='12345678901234',
ultimo_nsu='123456789101213'
)
# Gerando xml e enviado consulta por Chaveresponse2=consulta_distribuicao_nfe(
certificado,
ambiente=1,
estado='42',
modelo='55',
cnpj_cpf='12345678901234',
chave_nfe='012345678901234567890123456789012345678912'
)
# Gerando xml e enviado consulta por NSUresponse3=consulta_distribuicao_nfe(
certificado,
ambiente=1,
estado='42',
modelo='55',
cnpj_cpf='12345678901234',
nsu='123456789101213'
)

Consulta Distribuição NF-e com Validação de Esquema:

frompytrustnfe.certificadoimportCertificadofrompytrustnfe.nfeimportconsulta_distribuicao_nfe, xml_consulta_distribuicao_nfefrompytrustnfe.xml.validateimportvalida_nfe, SCHEMA_DFEcertificado=open("/path/certificado.pfx", "r").read()
certificado=Certificado(certificado, 'senha_pfx')
# Gerando XML para Consulta por Ultimo NSUxml1=xml_consulta_distribuicao_nfe(
certificado,
ambiente=1,
estado='42',
cnpj_cpf='12345678901234',
ultimo_nsu='123456789101213'
)
# Validando o XML com Esquemaifvalida_nfe(xml1, SCHEMA_DFE):
Warning("Erro na validação do esquema")
# Gerando XML para Consulta por Chavexml2=xml_consulta_distribuicao_nfe(
certificado,
ambiente=1,
estado='42',
cnpj_cpf='12345678901234',
chave_nfe='012345678901234567890123456789012345678912'
)
# Validando o XML com Esquemaifvalida_nfe(xml2, SCHEMA_DFE):
Warning("Erro na validação do esquema")
# Gerando XML para Consulta por NSUxml3=xml_consulta_distribuicao_nfe(
certificado,
ambiente=1,
estado='42',
cnpj_cpf='12345678901234',
nsu='123456789101213'
)
# Validando o XML com Esquemaifvalida_nfe(xml3, SCHEMA_DFE):
Warning("Erro na validação do esquema")
# Enviando xml de consulta para sefazresponse=consulta_distribuicao_nfe(
certificado,
ambiente=1,
estado='42',
modelo='55',
xml=xml1
)

Exemplo de uso da NFSe Paulistana

Envio de RPS por lote

certificado=open('/path/certificado.pfx', 'r').read()
certificado=Certificado(certificado, '123456')
# Necessário criar um dicionário com os dados, validação dos dados deve# ser feita pela aplicação que está utilizando a librps= [
{
'assinatura': '123',
'serie': '1',
'numero': '1',
'data_emissao': '2016-08-29',
'codigo_atividade': '07498',
'valor_servico': '2.00',
'valor_deducao': '3.00',
'prestador': {
'inscricao_municipal': '123456'
},
'tomador': {
'tipo_cpfcnpj': '1',
'cpf_cnpj': '12345678923256',
'inscricao_municipal': '123456',
'razao_social': 'Trustcode',
'tipo_logradouro': '1',
'logradouro': 'Vinicius de Moraes, 42',
'numero': '42',
'bairro': 'Corrego',
'cidade': '4205407', # Código da cidade, de acordo com o IBGE'uf': 'SC',
'cep': '88037240',
},
'codigo_atividade': '07498',
'aliquota_atividade': '5.00',
'descricao': 'Venda de servico'
}
]
nfse= {
'cpf_cnpj': '12345678901234',
'data_inicio': '2016-08-29',
'data_fim': '2016-08-29',
'total_servicos': '2.00',
'total_deducoes': '3.00',
'lista_rps': rps
}
retorno=envio_lote_rps(certificado, nfse=nfse)
# retorno é um dicionário { 'received_xml':'', 'sent_xml':'', 'object': object() }printretorno['received_xml']
printretorno['sent_xml']
# retorno['object'] é um objeto python criado apartir do xml de respostaprintretorno['object'].Cabecalho.Sucessoprintretorno['object'].ChaveNFeRPS.ChaveNFe.NumeroNFeprintretorno['object'].ChaveNFeRPS.ChaveRPS.NumeroRPS

Cancelamento de NFSe:

frompytrustnfe.certificadoimportCertificadofrompytrustnfe.nfse.paulistanaimportcancelamento_nfecertificado=open('/path/certificado.pfx', 'r').read()
certificado=Certificado(certificado, '123456')
cancelamento= {
'cnpj_remetente': '123',
'assinatura': 'assinatura',
'numero_nfse': '456',
'inscricao_municipal': '654',
'codigo_verificacao': '789',
}
retorno=cancelamento_nfe(certificado, cancelamento=cancelamento)
# retorno é um dicionário { 'received_xml':'', 'sent_xml':'', 'object': object() }printretorno['received_xml']
printretorno['sent_xml']
# retorno['object'] é um objeto python criado apartir do xml de respostaprintretorno['object'].Cabecalho.Sucessoifnotretorno['object'].Cabecalho.Sucesso: # Cancelamento com erroprintretorno['object'].Erro.Codigoprintretorno['object'].Erro.Descricao

About

Módulo NF-e Python

Resources

Stars

1 star

Watchers

41 watching

Forks

Releases

Packages

Contributors

Languages