From 52d55ee3f3c019ef0e00bf9ac22f87a90526d941 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Valyi?= Date: Sun, 31 Mar 2024 22:39:59 -0300 Subject: [PATCH] add to_pdf helper --- nfelib/__init__.py | 50 +++++++++++++++++++++++++++++++++++++++++-- setup.cfg | 1 + tests/nfe/test_nfe.py | 16 ++++++++++++++ 3 files changed, 65 insertions(+), 2 deletions(-) diff --git a/nfelib/__init__.py b/nfelib/__init__.py index 4a604c6d..7d6a5f3f 100644 --- a/nfelib/__init__.py +++ b/nfelib/__init__.py @@ -3,7 +3,7 @@ import os from os import environ from pathlib import Path -from typing import Any, Dict, List, Optional +from typing import Any, List, Optional from lxml import etree from xsdata.formats.dataclass.parsers import XmlParser @@ -124,6 +124,36 @@ def sign_xml( xml_etree = etree.fromstring(xml.encode("utf-8")) return Assinatura(certificate).assina_xml2(xml_etree, doc_id) + @classmethod + def xmls_to_pdf( + self, + xml_list: List, + engine: str = "brazilfiscalreport", + image: Optional[str] = None, # (base64 image) + cfg_layout: str = "ICMS_IPI", + receipt_pos: str = "top", + ) -> bytes: + """Serialize a list of xmls strings (usually only one) to a pdf.""" + xml_bytes_list = [ + xml.encode() if isinstance(xml, str) else xml for xml in xml_list + ] + if engine == "brazilfiscalreport": + try: + from brazilfiscalreport.pdf_docs import Danfe + except ImportError: + raise (RuntimeError("brazilfiscalreport package is not installed!")) + return bytes(Danfe( + xmls=xml_bytes_list, + image=image, + cfg_layout=cfg_layout, + receipt_pos=receipt_pos, + ).output(dest="S")) + try: + from erpbrasil.edoc.pdf import base + except ImportError: + raise (RuntimeError("erpbrasil.edoc.pdf package is not installed!")) + return base.ImprimirXml.imprimir(string_xml=xml_bytes_list[0]) + def to_xml( self, pretty_print: str = True, @@ -143,7 +173,7 @@ def to_xml( package = self._get_package() ns_map = {None: f"http://www.portalfiscal.inf.br/{package}"} xml = serializer.render(obj=self, ns_map=ns_map) - if doc_id: + if pkcs12_data: return self.sign_xml(self, xml, pkcs12_data, pkcs12_password, doc_id=doc_id) return xml @@ -152,6 +182,22 @@ def validate_xml(self, schema_path: Optional[str] = None) -> List: xml = self.to_xml() return self.schema_validation(xml, schema_path) + def to_pdf( + self, + engine: str = "brazilfiscalreport", + image: Optional[str] = None, # (base64 image) + cfg_layout: str = "ICMS_IPI", + receipt_pos: str = "top", + pkcs12_data: Optional[bytes] = None, + pkcs12_password: Optional[str] = None, + doc_id: Optional[str] = None, + ) -> bytes: + """Serialize binding into pdf bytes.""" + xml = self.to_xml() + if pkcs12_data: + xml = self.sign_xml(xml, pkcs12_data, pkcs12_password, doc_id) + return self.xmls_to_pdf([xml.encode()], engine, image, cfg_layout, receipt_pos) + # this was an attempt to keep the signature inside the # binding before serializing it again. But at the moment it fails # because xsdata will serialize the Signature elements with their namespaces. diff --git a/setup.cfg b/setup.cfg index 437ce822..0b3d27c4 100644 --- a/setup.cfg +++ b/setup.cfg @@ -45,6 +45,7 @@ test = requests beautifulsoup4 erpbrasil.assinatura + brazilfiscalreport [flake8] exclude = tests/* diff --git a/tests/nfe/test_nfe.py b/tests/nfe/test_nfe.py index a15df38e..beb15790 100644 --- a/tests/nfe/test_nfe.py +++ b/tests/nfe/test_nfe.py @@ -67,6 +67,22 @@ def test_sign(self): # signed_xml2 = signed_nfe.to_xml(pretty_print=False) # self.assertEqual(signed_xml, signed_xml2) + pdf_bytes = nfe.to_pdf( + pkcs12_data=cert_data, + pkcs12_password=cert_password, + doc_id=nfe.NFe.infNFe.Id, + ) + self.assertEqual(type(pdf_bytes), bytes) + + def test_pdf(self): + path = os.path.join("nfelib", "nfe", "samples", "v4_0", "leiauteNFe") + filename = "42210775277525000178550030000266631762885493-procNFe.xml" + input_file = os.path.join(path, filename) + parser = XmlParser() + nfe = parser.from_path(Path(input_file)) + pdf_bytes = nfe.to_pdf() + self.assertEqual(type(pdf_bytes), bytes) + def test_in_out_leiauteNFe(self): path = os.path.join("nfelib", "nfe", "samples", "v4_0", "leiauteNFe") for filename in os.listdir(path):