Skip to main content

Geração e envio de GNRE a partir de NF-e, com suporte a webservices e certificado PFX.

Project description

gnre-automacao

Biblioteca em Python para geração e envio de GNRE a partir de dados de NF-e, incluindo:

  • construção de XML do lote
  • montagem de envelopes SOAP
  • comunicação com os webservices oficiais (produção e teste)
  • parsing das respostas com extração de recibo, situação, linha digitável, valor, data de vencimento e PDF (base64)
  • suporte a certificados em formato PFX

Instalação

pip install gnre-automacao

Requisitos

  • Python >= 3.10
  • cryptography >= 41.0.0

Uso rápido

Para as UFs PE, RJ, RO e SC, quando há mais de um tributo a recolher (ex.: DIFAL + FCP), emit_gnre_receipt envia automaticamente todos os tributos em uma única guia de múltiplas receitas. Para as demais UFs, cada tributo é enviado em uma guia separada. Use needs_multiplas_receitas para adaptar o fluxo:

from pathlib import Path
import base64
from datetime import date
from gnre_automacao import (
    parse_nfe_xml_bytes, evaluate_gnre_need,
    needs_multiplas_receitas, emit_gnre_receipt, consult_gnre_receipt,
    GNREError,
)

pfx_bytes = Path("certificado.pfx").read_bytes()
pfx_password = "SENHA_DO_CERTIFICADO"
nfe_bytes = Path("nfe.xml").read_bytes()
AMBIENTE = "1"  # "1" = produção, "2" = teste

dados = parse_nfe_xml_bytes(nfe_bytes)
need = evaluate_gnre_need(dados, receita=None)

if need.get("necessario") == "N":
    print("GNRE não necessária")
elif need.get("necessario") == "M":
    print("GNRE manual necessária (SP/ES)")
else:
    venc = date.today().isoformat()
    guias = need.get("guias") or []
    recibos = []

    if needs_multiplas_receitas(dados):
        # PE, RJ, RO, SC com 2+ tributos: um único envio com todas as receitas
        r = emit_gnre_receipt(dados, AMBIENTE, guias[0]["receita"], venc, venc, pfx_bytes, pfx_password)
        print("múltiplas receitas:", r.get("multiplas_receitas"), "| recibo:", r.get("recibo") or r.get("error"))
        recibos.append(r)
    else:
        # Demais UFs: uma guia por receita
        for guia in guias:
            r = emit_gnre_receipt(dados, AMBIENTE, guia["receita"], venc, venc, pfx_bytes, pfx_password)
            print("receita:", guia["receita"], "| recibo:", r.get("recibo") or r.get("error"))
            recibos.append(r)

    for r in recibos:
        if not r.get("recibo"):
            continue
        result = consult_gnre_receipt(AMBIENTE, r["recibo"], pfx_bytes, pfx_password, incluir_pdf=True, incluir_arquivo_pagamento=True)
        status = result.get("status") or {}
        print(status.get("numeroRecibo"), status.get("codigo"), status.get("descricao"))
        print("Linha digitável:", result.get("linhaDigitavel"))
        print("Valor:", result.get("valor"), "| Vencimento:", result.get("dataVencimento"))
        if result.get("pdfBase64"):
            Path(f"gnre_{r['recibo']}.pdf").write_bytes(base64.b64decode(result["pdfBase64"]))

Retornos e cenários

evaluate_gnre_need

  • Sucesso (quando há guias necessárias):
{
  "receita": "100102",
  "valor_principal": "27.62",
  "valor_fcp": "1.92",
  "valor_total_item": "29.54",
  "necessario": "S",
  "guias": [
    { "receita": "100102", "valor": "27.62" },
    { "receita": "100129", "valor": "1.92" }
  ]
  "taxes": {
    "icms": "0.00",
    "icms_difal": "27.62",
    "icms_st": "0.00",
    "fcp": "1.92",
    "ipi": "0.00",
    "pis": "0.00",
    "cofins": "0.00",
    "ibs": "0.00",
    "cbs": "0.00",
    "total_taxes_estimation": "29.54"
  }
}
  • Sem necessidade:
{
  "receita": null,
  "valor_principal": "0.00",
  "valor_fcp": "0.00",
  "valor_total_item": "0.00",
  "necessario": "N",
  "guias": [],
  "taxes": {
    "icms": "0.00",
    "icms_difal": "0.00",
    "icms_st": "0.00",
    "fcp": "0.00",
    "ipi": "0.00",
    "pis": "0.00",
    "cofins": "0.00",
    "ibs": "0.00",
    "cbs": "0.00",
    "total_taxes_estimation": "0.00"
  }
}
  • Necessário mas manual (SP/ES com operação interestadual):
{
  "receita": null,
  "valor_principal": "27.62",
  "valor_fcp": "1.92",
  "valor_total_item": "29.54",
  "necessario": "M",
  "guias": [
    { "receita": "100102", "valor": "27.62" },
    { "receita": "100129", "valor": "1.92" }
  ],
  "taxes": {
    "icms": "0.00",
    "icms_difal": "27.62",
    "icms_st": "0.00",
    "fcp": "1.92",
    "ipi": "0.00",
    "pis": "0.00",
    "cofins": "0.00",
    "ibs": "0.00",
    "cbs": "0.00",
    "total_taxes_estimation": "29.54"
  }
}

emit_gnre_receipt

  • Sucesso (guia única):
{ "receita": "100102", "recibo": "26000045455789", "multiplas_receitas": false }
  • Sucesso (múltiplas receitas — PE/RJ/RO/SC com 2+ tributos):
{ "receita": "100102", "recibo": "26000045455790", "multiplas_receitas": true }
  • Falha de recepção (ex.: conteúdo inválido):
{
  "receita": "100129",
  "recibo": null,
  "multiplas_receitas": false,
  "error": "Falha ao obter recibo de recepção",
  "recepcao_xml": "<soapenv:Envelope>...</soapenv:Envelope>"
}
  • Exceção de validação (GNREError) com detalhes:
{
  "receita": "100129",
  "multiplas_receitas": false,
  "error": "ufFavorecida é obrigatória",
  "details": { "uf_favorecida": "" }
}

consult_gnre_receipt

  • Sucesso (processado):
{
  "recibo": "26000045455789",
  "status": { "numeroRecibo": "26000045455789", "codigo": "402", "descricao": "Lote Processado com sucesso" },
  "linhaDigitavel": "8587...4007",
  "valor": "1.92",
  "dataVencimento": "2026-02-02",
  "pdfBase64": "JVBERi0xLjQKJeLjz9MK..."
}
  • Em processamento:
{
  "recibo": "26000045455789",
  "status_error": "Guia não processada com sucesso | codigo=401 | descricao=Lote em Processamento | recibo=26000045455789 | ...",
  "resultado": {
    "numeroRecibo": "26000045455789",
    "situacao": { "codigo": "401", "descricao": "Lote em Processamento" },
    "guias": [],
    "pdfGuias": null,
    "arquivoPagamento": null
  }
}
  • Processado com pendências (ex.: requer detalhamento):
{
  "recibo": "260000...",
  "status_error": "Guia não processada com sucesso | codigo=403 | descricao=Lote Processado com pendências | ...",
  "resultado": {
    "numeroRecibo": "260000...",
    "situacao": { "codigo": "403", "descricao": "Lote Processado com pendências" },
    "guias": [ /* motivos e detalhes da pendência */ ]
  }
}

## Principais funções
- `parse_nfe_xml_bytes(bytes)` — extrai dados relevantes da NF-e
- `evaluate_gnre_need(dados, receita=None)` — avalia necessidade de GNRE; quando a UF do emitente for diferente da UF do destinatário e a UF de destino for SP ou ES, retorna `necessario = "M"` (manual) somente se houver valor > 0; caso valor seja zero, retorna `necessario = "N"`
- `needs_multiplas_receitas(dados)` — retorna `True` se a NF-e deve usar o formato de múltiplas receitas (destinatário em PE/RJ/RO/SC com 2 ou mais tributos a recolher)
- `emit_gnre_receipt(dados, ambiente, receita, data_vencimento, data_pagamento, pfx_bytes, pfx_password, ...)` — emite a guia; para PE/RJ/RO/SC com 2+ tributos, combina automaticamente todas as receitas em uma única guia e retorna `"multiplas_receitas": true`
- `consult_gnre_receipt(ambiente, recibo, pfx_bytes, pfx_password, ...)` — consulta o resultado de um recibo
- `build_lote_xml_with_config(...)` — monta o XML do lote GNRE consultando regras da UF e aplicando campos extras automaticamente
- `build_lote_xml(...)` — versão manual para montar o XML do lote GNRE (guia única)
- `build_lote_xml_multiplas_receitas(dados, uf_favorecida, guias, data_vencimento, data_pagamento, ...)` — monta o XML com múltiplas receitas num único `TDadosGNRE`; `guias` é uma lista de `{"receita": "100102", "valor": "27.62"}`
- `MULTIPLAS_RECEITAS_UFS` — `frozenset` com as UFs que usam múltiplas receitas: `{"PE", "RJ", "RO", "SC"}`
- `build_soap_envelope_tlote(xml)` — envelope SOAP para recepção de lote
- `post_soap(url, envelope_xml, ...)` — envia requisição SOAP com certificado
- `parse_tr_ret_lote(soap_xml)` — extrai número de recibo do retorno da recepção
- `build_consulta_resultado_xml(ambiente, recibo, incluir_pdf=True, incluir_arquivo_pagamento=True)` — XML de consulta de resultado
- `parse_result_status(soap_xml)` — valida situação do processamento do lote
- `extract_linha_digitavel_and_pdf(soap_xml)` — retorna `linhaDigitavel`, `valor`, `dataVencimento`, `pdfBase64`, `numeroRecibo`
- `get_endpoints(ambiente)` — URLs dos webservices para `producao` ou `teste`
- `GNREError` — exceção com `codigo`, `descricao` e `recibo` quando aplicável

## Endpoints e ambientes
Use `get_endpoints("producao")` ou `get_endpoints("teste")` para obter as URLs corretas dos serviços.

## Certificados PFX
Você pode informar `pfx_bytes` e `pfx_password` diretamente para as chamadas de webservice. O certificado e a chave são temporariamente materializados em PEM durante a sessão e limpos em seguida.

## Licença
MIT. Veja o arquivo `LICENSE`.

## Dicas de depuração

Para inspecionar como o XML de um lote deve ser estruturado para uma determinada UF e receita, use o gerador oficial do portal GNRE:

https://www.gnre.pe.gov.br:444/gnre/v/lote/gerar#

Preencha os campos manualmente, gere a guia e inspecione o XML resultante. Isso é útil para comparar com o XML produzido pela biblioteca e identificar divergências de estrutura (campos obrigatórios, tipos de documento, presença ou ausência de `<referencia>`, etc.).

## Avisos
- Não comite senhas ou certificados no repositório.
- Os serviços GNRE podem ter regras específicas por UF e receita; sempre valide no ambiente de teste antes de ir para produção.
- Não funciona para as UFs SP e ES via webservice desta biblioteca.
- Para as UFs RJ e RO com múltiplos tributos, `emit_gnre_receipt` envia uma única guia com todas as receitas combinadas. Chame-a **uma única vez** (não em loop por guia), pois internamente já inclui todos os tributos detectados.
- É obrigatório cadastrar o CNPJ no portal GNRE antes de utilizar os serviços: https://www.gnre.pe.gov.br:444/gnre/portal/GNRE_Principal.jsp

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

gnre_automacao-2.0.0.tar.gz (21.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

gnre_automacao-2.0.0-py3-none-any.whl (20.0 kB view details)

Uploaded Python 3

File details

Details for the file gnre_automacao-2.0.0.tar.gz.

File metadata

  • Download URL: gnre_automacao-2.0.0.tar.gz
  • Upload date:
  • Size: 21.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for gnre_automacao-2.0.0.tar.gz
Algorithm Hash digest
SHA256 d6f36d3fa96f8f5bd1213e1f688f34bd1a3ed96115a7ef407ab5cce352fbee95
MD5 a3ef9c1f811dd31801e8156bfb608439
BLAKE2b-256 f1c9af7e5aa76ace7bc9dece7b55f774d8a6f70e609d9f7a4e88e5e3cef5d8b3

See more details on using hashes here.

Provenance

The following attestation bundles were made for gnre_automacao-2.0.0.tar.gz:

Publisher: python-publish.yml on heitorforner/gnre-automacao

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file gnre_automacao-2.0.0-py3-none-any.whl.

File metadata

  • Download URL: gnre_automacao-2.0.0-py3-none-any.whl
  • Upload date:
  • Size: 20.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for gnre_automacao-2.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 566bb214b729ae14bb1412b16148cc1c2de8ef42cb5630ab1ef4cbf9baa844ce
MD5 83c9111d736d61daaee2f0f872671dbe
BLAKE2b-256 e374f69e66b81e9070367dc4adb1c69f27aa5cd28efb53f7a3ee657daa4dcb12

See more details on using hashes here.

Provenance

The following attestation bundles were made for gnre_automacao-2.0.0-py3-none-any.whl:

Publisher: python-publish.yml on heitorforner/gnre-automacao

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page