Downloads
Os downloads da NFS-e devolvem bytes, prontos para gravar em disco, anexar num e-mail ou enviar
para um bucket.
| Método | Conteúdo |
|---|---|
service_invoices.download_pdf(company_id, invoice_id) | PDF da nota (DANFSE). |
service_invoices.download_xml(company_id, invoice_id) | XML da nota, sem alteração. |
service_invoices.download_cancellation_xml(company_id, invoice_id) | XML do cancelamento. |
from pathlib import Path
from nfeio import NfeClient
client = NfeClient()
company_id = "ID_DA_EMPRESA"
invoice_id = "ID_DA_NOTA"
Path("nota.pdf").write_bytes(client.service_invoices.download_pdf(company_id, invoice_id))
Path("nota.xml").write_bytes(client.service_invoices.download_xml(company_id, invoice_id))
Baixe depois que a nota chegar a Issued (ou Cancelled, para o XML de cancelamento). Com
create_and_wait, isso já está garantido quando o método retorna.
Redirecionamento sem a chave
A API não devolve o arquivo direto: ela responde 302 para uma URL temporária e pré-assinada, em
outro host. O SDK segue esse redirecionamento por você, com três cuidados:
- a requisição para a URL temporária sai sem o cabeçalho
Authorization. A URL já carrega a própria autorização, e a sua chave nunca é enviada a um host para onde foi redirecionada; - só redirecionamentos
httpssão seguidos, até três saltos; - só os downloads seguem redirecionamento. Em qualquer outra chamada, um
3xxviraUnexpectedResponseError.
O limite de tamanho de resposta (max_response_bytes, 10 MiB por padrão) vale também para os
arquivos.
XML
O XML volta intocado. O da NFS-e costuma começar direto em <Nfse>, sem o prólogo <?xml ...?>. Se
for interpretar o XML, use um parser protegido contra entidades maliciosas, como o
defusedxml (o SDK não depende dele):
from defusedxml.ElementTree import fromstring
from nfeio import NfeClient
client = NfeClient()
xml = client.service_invoices.download_xml("ID_DA_EMPRESA", "ID_DA_NOTA")
raiz = fromstring(xml)
print(raiz.tag)
XML de cancelamento
Só alguns provedores geram o XML de cancelamento (o Ambiente Nacional, por exemplo). Nos outros, a
API responde 404, e o método levanta NotFoundError:
from nfeio import NfeClient, NotFoundError
client = NfeClient()
try:
xml_cancelamento = client.service_invoices.download_cancellation_xml(
"ID_DA_EMPRESA", "ID_DA_NOTA"
)
except NotFoundError as erro:
print("sem XML de cancelamento para este provedor:", erro.message)
No cliente assíncrono
Os mesmos métodos, com await:
import asyncio
from pathlib import Path
from nfeio import AsyncNfeClient
async def main() -> None:
async with AsyncNfeClient() as client:
pdf = await client.service_invoices.download_pdf("ID_DA_EMPRESA", "ID_DA_NOTA")
Path("nota.pdf").write_bytes(pdf)
asyncio.run(main())
Reenvio por e-mail
Para reenviar a nota por e-mail ao tomador, sem baixar nada:
from nfeio import NfeClient
client = NfeClient()
client.service_invoices.send_email("ID_DA_EMPRESA", "ID_DA_NOTA")