diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 8118de9..8165714 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -28,7 +28,7 @@ jobs: run: sudo apt-get update --allow-releaseinfo-change && sudo apt-get install qpdf - name: Install dependencies run: | - python -m pip install --upgrade pip setuptools fpdf2 phonenumbers python-barcode pytest pytest-cov + python -m pip install --upgrade pip setuptools fpdf2 phonenumbers python-barcode pytest qrcode pytest-cov - name: Test run: | pytest --cov=./brazilfiscalreport --cov-report=xml --cov-branch --doctest-glob="docs/*.md" diff --git a/README.md b/README.md index 9d911db..ea9c2e5 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ Python library for generating Brazilian auxiliary fiscal documents in PDF from X - DANFE - Documento Auxiliar da Nota Fiscal Eletrônica (NF-e) - DACCe - Documento Auxiliar da Carta de Correção Eletrônica (CC-e ) +- DACTE - Documento Auxiliar do Conhecimento de Transporte Eletrônico (CT-e) ## Beta Stage Notice 🚧 @@ -22,6 +23,7 @@ This library is currently in the beta stage of development. While it has many of - [FPDF2](https://github.com/py-pdf/fpdf2) - PDF creation library for Python - phonenumbers - python-barcode +- qrcode ## To install 🔧 @@ -67,6 +69,25 @@ cce = DaCCe(xml=xml_content) cce.output('cce.pdf') ``` +### DACTE + +```python +from brazilfiscalreport.dacte import Dacte + +# Path to the XML file +xml_file_path = 'dacte.xml' + +# Load XML Content +with open(xml_file_path, "r", encoding="utf8") as file: + xml_content = file.read() + +# Instantiate the DACTE object with the loaded XML content +dacte = Dacte(xml=xml_content) + +# Save the generated PDF to a file +dacte.output('dacte.pdf') +``` + ## Samples 📝 Some sample PDFs generated by our unit tests are available for viewing in the [tests/generated](https://github.com/Engenere/BrazilFiscalReport/tree/main/tests/generated) directory. @@ -199,6 +220,75 @@ danfe = Danfe(xml_content, config=config) danfe.output('output_danfe.pdf') ``` +## Customizing DACTE + +This section describes how to customize the PDF output of the DACTE using the DacteConfig class. You can adjust various settings such as margins, fonts, and tax configurations according to your needs. + +### Configuration Options + +Here is a breakdown of all the configuration options available in ``DanfeConfig``: + +1. **Logo** + - **Type**: ``str``, ``BytesIO``, or ``bytes`` + - **Description**: Path to the logo file or binary image data to be included in the PDF. You can use a file path string or pass image data directly. + - **Example**: + ```python + config.logo = "path/to/logo.jpg" # Using a file path + ``` + - **Default**: No logo. + + +2. **Margins** + - **Type**: ``Margins`` + - **Fields**: ``top``, ``right``, ``bottom``, ``left`` (all of type ``Number``) + - **Description**: Sets the page margins for the PDF document. + - **Example**: + ```python + config.margins = Margins(top=5, right=5, bottom=5, left=5) + ``` + - **Default**: top, right, bottom and left is 2 mm. + +3. **Font Type** + - **Type**: ``FontType`` (Enum) + - **Values**: ``COURIER``, ``TIMES`` + - **Description**: Font style used throughout the PDF document. + - **Example**:: + ```python + config.font_type = FontType.COURIER + ``` + - **Default**: ``TIMES`` + +### Usage Example with Customization + +Here’s how to set up a DacteConfig object with a full set of customizations: + +```python +from brazilfiscalreport.dacte import ( + Dacte, + DacteConfig, + FontType, + Margins, +) + +# Path to the XML file +xml_file_path = 'cte.xml' + +# Load XML Content +with open(xml_file_path, "r", encoding="utf8") as file: + xml_content = file.read() + +# Create a configuration instance +config = DacteConfig( + logo='path/to/logo.png', + margins=Margins(top=10, right=10, bottom=10, left=10), + font_type=FontType.TIMES +) + +# Use this config when creating a Dacte instance +dacte = Dacte(xml_content, config=config) +dacte.output('output_dacte.pdf') +``` + ## Credits 🙌 This is a fork of the [nfe_utils](https://github.com/edsonbernar/nfe_utils) project, originally created by [Edson Bernardino](https://github.com/edsonbernar). diff --git a/brazilfiscalreport/dacte/__init__.py b/brazilfiscalreport/dacte/__init__.py new file mode 100644 index 0000000..9fb813e --- /dev/null +++ b/brazilfiscalreport/dacte/__init__.py @@ -0,0 +1,17 @@ +from .config import ( + DacteConfig, + DecimalConfig, + FontType, + Margins, + ReceiptPosition, +) +from .dacte import Dacte + +__all__ = [ + "Dacte", + "DacteConfig", + "DecimalConfig", + "FontType", + "Margins", + "ReceiptPosition", +] diff --git a/brazilfiscalreport/dacte/config.py b/brazilfiscalreport/dacte/config.py new file mode 100644 index 0000000..076295d --- /dev/null +++ b/brazilfiscalreport/dacte/config.py @@ -0,0 +1,39 @@ +from dataclasses import dataclass, field +from enum import Enum +from io import BytesIO +from numbers import Number +from typing import Union + + +class FontType(Enum): + COURIER = "Courier" + TIMES = "Times" + + +@dataclass +class Margins: + top: Number = 2 + right: Number = 2 + bottom: Number = 2 + left: Number = 2 + + +@dataclass +class DecimalConfig: + price_precision: int = 4 + quantity_precision: int = 4 + + +class ReceiptPosition(Enum): + TOP = "top" + BOTTOM = "bottom" + LEFT = "left" + + +@dataclass +class DacteConfig: + logo: Union[str, BytesIO, bytes] = None + margins: Margins = field(default_factory=Margins) + receipt_pos: ReceiptPosition = ReceiptPosition.TOP + decimal_config: DecimalConfig = field(default_factory=DecimalConfig) + font_type: FontType = FontType.TIMES diff --git a/brazilfiscalreport/dacte/dacte.py b/brazilfiscalreport/dacte/dacte.py new file mode 100644 index 0000000..2f2dec9 --- /dev/null +++ b/brazilfiscalreport/dacte/dacte.py @@ -0,0 +1,1627 @@ +# Copyright (C) 2024 Engenere - Cristiano Mafra Junior + +import re +import xml.etree.ElementTree as ET +from io import BytesIO +from xml.etree.ElementTree import Element + +import qrcode +from barcode import Code128 +from barcode.writer import SVGWriter + +from ..utils import ( + format_cep, + format_cpf_cnpj, + format_number, + format_phone, + get_date_utc, + get_tag_text, +) +from ..xfpdf import xFPDF +from .config import DacteConfig, ReceiptPosition +from .dacte_conf import URL + +tp_modal = { + "01": "RODOVIÁRIO", + "02": "AÉREO", + "03": "AQUAVIÁRIO", + "04": "FERROVIÁRIO", + "05": "DUTOVIÁRIO", + "06": "MULTIMODAL", +} +tp_tomador = { + "0": "REMETENTE", + "1": "EXPEDIDOR", + "2": "RECEBEDOR", + "3": "DESTINATÁRIO", + "4": "OUTRO", +} + +tp_cte = { + "0": "NORMAL", + "1": "COMPLEMENTAR", + "2": "ANULADO", + "3": "SUSBTITUTO", +} + +tp_servico = { + "0": "NORMAL", + "1": "SUBCONTRATAÇÃO", + "2": "REDESPACHO", + "3": "REDESPACHO INTERMEDIÁRIO", +} + +tp_codigo_medida = { + "00": "M3", + "01": "KG", + "02": "TON", + "03": "UNIDADE", + "04": "LITROS", + "05": "MMBTU", +} + + +def extract_text(node: Element, tag: str) -> str: + return get_tag_text(node, URL, tag) + + +class Dacte(xFPDF): + def __init__(self, xml, config: DacteConfig = None): + super().__init__(unit="mm", format="A4") + config = config if config is not None else DacteConfig() + self.set_margins( + left=config.margins.left, top=config.margins.top, right=config.margins.right + ) + self.set_auto_page_break(auto=False, margin=config.margins.bottom) + self.set_title("DACTE") + self.logo_image = config.logo + self.receipt_pos = config.receipt_pos + self.default_font = config.font_type.value + self.price_precision = config.decimal_config.price_precision + self.quantity_precision = config.decimal_config.quantity_precision + + root = ET.fromstring(xml) + self.inf_cte = root.find(f"{URL}infCte") + self.prot_cte = root.find(f"{URL}protCTe") + self.emit = root.find(f"{URL}emit") + self.ide = root.find(f"{URL}ide") + self.dest = root.find(f"{URL}dest") + self.exped = root.find(f"{URL}exped") + self.receb = root.find(f"{URL}receb") + self.rem = root.find(f"{URL}rem") + self.inf_prot = root.find(f"{URL}infProt") + self.inf_cte_supl = root.find(f"{URL}infCTeSupl") + self.tomador = root.find(f"{URL}toma3") + self.inf_carga = root.find(f"{URL}infCarga") + self.inf_doc = root.find(f"{URL}infDoc") + self.v_prest = root.find(f"{URL}vPrest") + self.inf_modal = root.find(f"{URL}infModal") + self.imp = root.find(f"{URL}imp") + self.compl = root.find(f"{URL}compl") + + self.obs_dacte_list = [] + for obs in self.compl: + self.x_texto = extract_text(obs, "xTexto") + self.x_texto = " ".join( + re.split(r"\s+", self.x_texto.strip(), flags=re.UNICODE) + ) + self.obs_dacte_list.append(self.x_texto) + + self.inf_carga_list = [] + for infQ in self.inf_carga: + self.c_unid = extract_text(infQ, "cUnid") + self.tp_media = extract_text(infQ, "tpMed") + self.q_carga = extract_text(infQ, "qCarga") + self.inf_carga_list.append((self.c_unid, self.tp_media, self.q_carga)) + + self.inf_doc_list = [] + for chave in self.inf_doc: + self.chave = extract_text(chave, "chave") + self.inf_doc_list.append(self.chave) + + self.comp_list = [] + for comp in self.v_prest: + self.xNome = extract_text(comp, "xNome") + self.vComp = extract_text(comp, "vComp") + self.comp_list.append((self.xNome, self.vComp)) + + self.total_receipt_height = 19 # TODO need compute + + # extract orientation + tpImp = extract_text(self.ide, "tpImp") + if tpImp == "1": + self.orientation = "P" + else: + self.orientation = "L" + # force receipt position + # landscape support only left receipt + self.receipt_pos = ReceiptPosition.LEFT + + # Emit. CNPJ/CPF + self.emit_cnpj_cpf = extract_text(self.emit, "CNPJ") + self.emit_id_label = "CNPJ" + + # Dest. CNPJ/CPF + self.dest_cnpj_cpf = extract_text(self.dest, "CNPJ") + self.dest_id_label = "CNPJ" + + self.recibo_text = self._get_receipt_text() + self.nr_dacte = extract_text(self.ide, "nCT") + self.serie_cte = extract_text(self.ide, "serie") + self.key_cte = self.inf_cte.attrib.get("Id")[3:] + self.tp_cte = tp_cte[extract_text(self.ide, "tpCTe")] + self.tp_serv = tp_servico[extract_text(self.ide, "tpServ")] + self.prot_uso = self._get_usage_protocol() + self.mod = extract_text(self.ide, "mod") + self.nct = extract_text(self.ide, "nCT") + self.toma = tp_tomador[extract_text(self.tomador, "toma")] + self.cfop = extract_text(self.ide, "CFOP") + self.nat_op = extract_text(self.ide, "natOp") + + self.add_page(orientation=self.orientation) + self._draw_receipt() + self._draw_header() + self._draw_recipient_sender(config) + self._draw_service_recipient(config) + self._draw_service_fee_value() + self._draw_documents_obs() + self._draw_specific_data(config) + self._draw_void_watermark() + self._add_new_page() + + def _get_usage_protocol(self): + dt, hr = get_date_utc(extract_text(self.prot_cte, "dhRecbto")) + protocol = extract_text(self.prot_cte, "nProt") + prot_text = f"{protocol} - {dt} {hr}" + return prot_text + + def _get_receipt_text(self): + return ( + "DECLARO QUE RECEBI OS VOLUMES DESTE CONHECIMENTO " + "EM PERFEITO ESTADO PELO QUE DOU POR " + "CUMPRIDO O PRESENTE CONTRATO DE TRANSPORTE" + ) + + def _draw_void_watermark(self): + if extract_text(self.ide, "tpAmb") == "2": + self.set_font(self.default_font, "B", 60) + watermark_text = "SEM VALOR FISCAL" + width = self.get_string_width(watermark_text) + self.set_text_color(r=220, g=150, b=150) + height = 15 + page_width = self.w + page_height = self.h + x_center = (page_width - width) / 2 + y_center = (page_height + height) / 2 + with self.rotation(55, x_center + (width / 2), y_center - (height / 2)): + self.text(x_center, y_center, watermark_text) + self.set_text_color(r=0, g=0, b=0) + + def _draw_dashed_line(self, distance): + self.set_dash_pattern(dash=0.2, gap=0.8) + if self.orientation == "P": + self.line( + x1=self.l_margin, + y1=distance, + x2=self.w - self.r_margin, + y2=distance, + ) + else: + self.line( + x1=distance, + y1=self.t_margin, + x2=distance, + y2=self.h - self.b_margin, + ) + self.set_dash_pattern(dash=0, gap=0) + + def _draw_receipt(self): + x_margin = self.l_margin + y_margin = self.y + page_width = self.epw + w_date_field = 40 + line_height = 8 + cell_height = -5 + + def draw_vertical_lines(start_y, end_y): + col_width = page_width / 4 + x_line1 = x_margin + col_width + x_line2 = x_margin + 2 * col_width + x_line3 = x_margin + 3 * col_width + + self.line(x1=x_line1, x2=x_line1, y1=start_y, y2=end_y) + self.line(x1=x_line2, x2=x_line2, y1=start_y, y2=end_y) + self.line(x1=x_line3, x2=x_line3, y1=start_y, y2=end_y) + + return x_line1, x_line2, x_line3 + + self._draw_dashed_line(distance=y_margin + 21) + self.set_dash_pattern(dash=0, gap=0) + + self.rect(x=x_margin, y=y_margin, w=page_width - 0.5, h=3, style="") + + self.set_font(self.default_font, "", 7) + self.set_xy(x=x_margin, y=y_margin) + self.cell( + w=page_width - 2 * x_margin, h=3, text=self.recibo_text, border=0, align="L" + ) + + h_recibo = 17 + self.rect( + x=x_margin, y=y_margin + 3.5, w=page_width - 0.5, h=h_recibo, style="" + ) + + x_line1, x_line2, x_line3 = draw_vertical_lines( + y_margin + 3.5, y_margin + h_recibo + 3.5 + ) + + y_start = y_margin + 10 + self.line(x1=x_margin, x2=x_line1, y1=y_start + 2, y2=y_start + 2) + + self.set_font(self.default_font, "B", 8) + self.set_xy(x=x_margin + 2, y=y_start) + self.cell(w=w_date_field, h=cell_height, text="NOME", border=0, align="L") + + self.set_xy(x=x_margin + 2, y=y_start + line_height) + self.cell(w=w_date_field, h=cell_height, text="RG", border=0, align="L") + + self.set_xy(x=x_line1 + 7.5, y=y_start + 11) + self.cell( + w=w_date_field, + h=cell_height, + text="ASSINATURA / CARIMBO", + border=0, + align="L", + ) + + self.set_xy(x=x_line2 + 10, y=y_start) + self.cell( + w=w_date_field, h=cell_height, text="CHEGADA DATA/HORA", border=0, align="L" + ) + + self.set_xy(x=x_line2 + 10, y=y_start + line_height) + self.cell( + w=w_date_field, h=cell_height, text="SAÍDA DATA/HORA", border=0, align="L" + ) + + self.set_xy(x=x_line3 + 23, y=y_start - 2) + self.set_font(self.default_font, "B", 10) + self.cell(w=w_date_field, h=cell_height, text="CT-E", border=0, align="L") + + self.set_xy(x=x_line3 + 5, y=y_start + 2) + self.set_font(self.default_font, "", 7) + self.cell( + w=w_date_field, h=cell_height, text="NRO. DOCUMENTO", border=0, align="L" + ) + + self.set_xy(x=x_line3 + 5, y=y_start + line_height) + self.cell(w=w_date_field, h=cell_height, text="SÉRIE", border=0, align="L") + + self.set_xy(x=x_line3 + 35, y=y_start + 2) + self.set_font(self.default_font, "B", 7) + self.cell( + w=w_date_field, h=cell_height, text=self.nr_dacte, border=0, align="L" + ) + + self.set_xy(x=x_line3 + 38, y=y_start + line_height) + self.cell( + w=w_date_field, h=cell_height, text=self.serie_cte, border=0, align="L" + ) + + def draw_qr_code(self, y_margin_ret): + self.qr_code = extract_text(self.inf_cte_supl, "qrCodCTe") + qr = qrcode.QRCode( + version=1, + error_correction=qrcode.constants.ERROR_CORRECT_L, + box_size=10, + border=1, + ) + qr.add_data(self.qr_code) + qr.make(fit=True) + + qr_img = qr.make_image(fill_color="black", back_color="white") + qr_img_bytes = qr_img.get_image() + + num_x = y_margin_ret + 88 + num_y = self.t_margin + 32 + num_w = 40 + num_h = 40 + self.image(qr_img_bytes, x=num_x + 1, y=num_y + 1, w=num_w - 2, h=num_h - 2) + + def _draw_header(self): + x_margin = self.l_margin + y_margin = self.y + section_start_y = y_margin + 4 + w_rect = (self.epw / 2) - 33 + h_rect = 27 + emit_name = extract_text(self.emit, "xNome") + self.cep = format_cep(extract_text(self.emit, "CEP")) + self.fone = format_phone(extract_text(self.emit, "fone")) + self.modal = tp_modal[extract_text(self.ide, "modal")] + self.mod = extract_text(self.ide, "mod") + self.serie = extract_text(self.ide, "serie") + self.nct = extract_text(self.ide, "nCT") + self.dt, self.hr = get_date_utc(extract_text(self.ide, "dhEmi")) + self.protocol = extract_text(self.prot_cte, "nProt") + self.dh_recebto, hr_recebto = get_date_utc( + extract_text(self.prot_cte, "dhRecbto") + ) + address = ( + f"{extract_text(self.emit, 'xLgr')}, " + f"{extract_text(self.emit, 'nro')}\n" + f"{extract_text(self.emit, 'xBairro')}\n" + f"{extract_text(self.emit, 'xMun')} - " + f"{extract_text(self.emit, 'UF')}\n" + f"{self.cep}\nFone: {self.fone}" + ) + self.rect(x=x_margin, y=section_start_y, w=(self.epw / 2) - 33, h=h_rect) + h_logo = 8 + w_logo = 8 + y_logo = y_margin + if self.logo_image: + self.image( + name=self.logo_image, + x=x_margin, + y=y_logo + 10, + w=w_logo + 10, + h=h_logo + 10, + keep_aspect_ratio=True, + ) + x_text = x_margin + 4 + y_text = y_logo + 6 + w_text = w_rect + else: + x_text = x_margin + 2 + y_text = y_margin + 6 + w_text = w_rect - 4 + self.set_font(self.default_font, "B", 9) + self.set_xy(x=x_text, y=y_text) + self.multi_cell(w=w_text, h=5, text=emit_name, border=0, align="C") + self.set_font(self.default_font, "", 8) + self.set_xy(x=x_text - 3, y=y_text + 10) + self.multi_cell(w=w_text + 10, h=3, text=address, border=0, align="C") + + y_margin = self.l_margin + 22 + y_start = self.y + 4 + y_margin_ret = self.l_margin + (self.epw / 2) - 33 + w_rect = 53 + h_rect = 11 + + self.rect(x=y_margin_ret, y=section_start_y, w=w_rect, h=h_rect) + self.set_font(self.default_font, "B", 10) + self.set_xy(x=y_margin_ret - 9, y=y_start - 29) + self.multi_cell(w=y_margin_ret, h=4, text="DACTE", align="C", border=0) + self.set_font(self.default_font, "", 6) + self.set_xy(x=y_margin_ret - 9, y=y_start - 25) + self.multi_cell( + w=y_margin_ret, + h=2, + text="DOCUMENTO AUXILIAR DO CONHECIMENTO\nDE TRANSPORTE ELETRÔNICO", + align="C", + ) + + self.rect(x=y_margin_ret + w_rect, y=section_start_y, w=31, h=11, style="") + + self.set_font(self.default_font, "", 8) + self.set_xy(y_margin_ret + 55, section_start_y + 2) + self.multi_cell(w=31 - 4, h=1, text="MODAL", align="C") + self.set_xy(y_margin_ret + 55, section_start_y + 2) + self.set_font(self.default_font, "B", 8) + self.multi_cell(w=31 - 4, h=11, text=self.modal, align="C") + + section_start_y += 11 + + self.rect(x=y_margin_ret, y=section_start_y, w=84, h=11, style="") + + col_width = (206 - (x_margin + 112)) / 5 + x_line_1 = x_margin + 70 + col_width + x_line_2 = x_margin + 70 + 2 * col_width + x_line_3 = x_margin + 70 + 3 * col_width + x_line_4 = x_margin + 70 + 4 * col_width + x_line_5 = x_margin + 70 + 4 * col_width + self.line( + x1=x_line_1 - 5, + x2=x_line_1 - 5, + y1=section_start_y, + y2=section_start_y + 11, + ) + self.line( + x1=x_line_2 - 5, + x2=x_line_2 - 5, + y1=section_start_y, + y2=section_start_y + 11, + ) + self.line( + x1=x_line_3 - 8, + x2=x_line_3 - 8, + y1=section_start_y, + y2=section_start_y + 11, + ) + self.line(x1=x_line_4, x2=x_line_4, y1=section_start_y, y2=section_start_y + 11) + self.line(x1=x_line_5, x2=x_line_5, y1=section_start_y, y2=section_start_y + 11) + + self.set_font(self.default_font, "", 7) + self.set_xy(x_line_1 - 25, section_start_y + 2) + self.multi_cell(w=31 - 4, h=1, text="MODELO", align="C") + self.set_xy(x_line_1 - 25, section_start_y + 2) + self.set_font(self.default_font, "B", 7) + self.multi_cell(w=31 - 4, h=11, text=self.mod, align="C") + + self.set_font(self.default_font, "", 7) + self.set_xy(x_line_2 - 28, section_start_y + 2) + self.multi_cell(w=31 - 4, h=1, text="SÉRIE", align="C") + self.set_xy(x_line_2 - 28, section_start_y + 2) + self.set_font(self.default_font, "B", 7) + self.multi_cell(w=31 - 4, h=11, text=self.serie, align="C") + + self.set_font(self.default_font, "", 7) + self.set_xy(x_line_3 - 29, section_start_y + 2) + self.multi_cell(w=31 - 4, h=1, text="NÚMERO", align="C") + self.set_xy(x_line_3 - 29, section_start_y + 2) + self.set_font(self.default_font, "B", 7) + self.multi_cell(w=31 - 4, h=11, text=self.nct, align="C") + + self.set_font(self.default_font, "", 7) + self.set_xy(x_line_4 - 27, section_start_y + 2) + self.multi_cell(w=31 - 4, h=2.5, text="DATA E HORA\nDE EMISSÃO", align="C") + self.set_xy(x_line_4 - 27, section_start_y + 2) + self.set_font(self.default_font, "B", 7) + self.multi_cell(w=31 - 4, h=13, text=f"{self.dt} {self.hr}", align="C") + + self.set_font(self.default_font, "", 7) + self.set_xy(x_line_5 - 9, section_start_y + 2) + self.multi_cell(w=31 - 4, h=2, text="FL", align="C") + self.set_xy(x_line_5 - 9, section_start_y + 2) + self.set_font(self.default_font, "B", 7) + self.multi_cell(w=31 - 1, h=11, text=f"{self.page_no()}/{{nb}}", align="C") + + section_start_y += 11 + y = section_start_y + 0.5 + w = 82 + h = 11.5 + self.rect(x=y_margin_ret, y=section_start_y, w=84, h=10, style="") + svg_img_bytes = BytesIO() + Code128(self.key_cte, writer=SVGWriter()).write(svg_img_bytes) + self.image(svg_img_bytes, x=y_margin_ret + 1, y=y, w=w, h=h) + + section_start_y += 10 + + self.set_font(self.default_font, "", 8) + self.rect(x=y_margin_ret, y=section_start_y, w=84, h=10, style="") + self.set_xy(x_line_5 - 55, section_start_y + 2) + self.multi_cell(w=45, h=0, text="CHAVE DE ACESSO", align="C") + self.set_xy(x_line_5 - 70, section_start_y + 2) + self.set_font(self.default_font, "B", 8) + self.multi_cell(w=75, h=11, text=self.key_cte, align="C") + section_start_y += 10 + + self.rect(x=y_margin_ret, y=section_start_y, w=84, h=9, style="") + self.set_xy(x=y_margin_ret, y=section_start_y) + self.multi_cell( + w=85, h=10, text="CONSULTA EM http://www.cte.fazenda.gov.br", align="C" + ) + section_start_y += 9 + + self.set_font(self.default_font, "", 8) + self.rect(x=y_margin_ret, y=section_start_y, w=84, h=10, style="") + self.set_xy(x=y_margin_ret, y=section_start_y) + self.multi_cell(w=85, h=4, text="PROTOCOLO DE AUTORIZAÇÃO DE USO", align="C") + self.set_xy(x=y_margin_ret, y=section_start_y) + self.set_font(self.default_font, "B", 8) + self.multi_cell( + w=86, + h=14, + text=f"{self.protocol} {self.dh_recebto} {hr_recebto}", + align="C", + ) + + section_start_y += 10 + self.set_font(self.default_font, "", 8) + self.rect( + x=self.l_margin, + y=section_start_y - 34, + w=(self.epw / 2) - 33, + h=8, + style="", + ) + self.set_xy(x=self.l_margin, y=section_start_y - 34) + self.multi_cell(w=85, h=4, text="TIPO DO CT-E", align="L") + self.set_xy(x=self.l_margin, y=section_start_y - 34) + self.set_font(self.default_font, "B", 8) + self.multi_cell(w=85, h=10, text=self.tp_cte, align="L") + + section_start_y += 8 + + self.set_font(self.default_font, "", 8) + self.rect( + x=self.l_margin, + y=section_start_y - 34, + w=(self.epw / 2) - 33, + h=8, + style="", + ) + self.set_xy(x=self.l_margin, y=section_start_y - 34) + self.multi_cell(w=85, h=4, text="TIPO DO SERVIÇO", align="L") + self.set_xy(x=self.l_margin, y=section_start_y - 34) + self.set_font(self.default_font, "B", 8) + self.multi_cell(w=85, h=10, text=self.tp_serv, align="L") + + section_start_y += 8 + + self.set_font(self.default_font, "", 8) + self.rect( + x=self.l_margin, + y=section_start_y - 34, + w=(self.epw / 2) - 33, + h=9, + style="", + ) + self.set_xy(x=self.l_margin, y=section_start_y - 34) + self.multi_cell(w=85, h=4, text="TOMADOR DO SERVIÇO", align="L") + self.set_xy(x=self.l_margin, y=section_start_y - 34) + self.set_font(self.default_font, "B", 8) + self.multi_cell(w=85, h=10, text=self.toma, align="L") + + section_start_y += 9 + + self.set_font(self.default_font, "", 8) + self.rect( + x=self.l_margin, + y=section_start_y - 34, + w=(self.epw / 2) - 33, + h=9, + style="", + ) + self.set_xy(x=self.l_margin, y=section_start_y - 34) + self.multi_cell(w=85, h=4, text="CFOP - NATUREZA DA PRESTAÇÃO", align="L") + self.set_xy(x=self.l_margin, y=section_start_y - 34) + self.set_font(self.default_font, "B", 8) + self.multi_cell(w=85, h=10, text=f"{self.cfop} - {self.nat_op}", align="L") + + self.draw_qr_code(y_margin_ret) + + def _draw_recipient_sender(self, config): + self.mun_ini = extract_text(self.ide, "xMunIni") + self.mun_fim = extract_text(self.ide, "xMunFim") + self.est_inico = extract_text(self.ide, "UFIni") + self.est_fim = extract_text(self.ide, "UFFim") + + # Inf do Remetente + self.rem_nome = extract_text(self.rem, "xNome") + self.rem_loga = extract_text(self.rem, "xLgr") + self.rem_nro = extract_text(self.rem, "nro") + self.rem_bairro = extract_text(self.rem, "xBairro") + self.rem_mun = extract_text(self.rem, "xMun") + self.rem_cnpj = format_cpf_cnpj(extract_text(self.rem, "CNPJ")) + self.rem_pais = extract_text(self.rem, "xPais") + self.rem_cep = format_cep(extract_text(self.rem, "CEP")) + self.rem_ie = extract_text(self.rem, "IE") + self.rem_fone = format_phone(extract_text(self.rem, "fone")) + self.rem_uf = extract_text(self.rem, "UF") + + # Inf Destinatario + self.dest_nome = extract_text(self.dest, "xNome") + self.dest_loga = extract_text(self.dest, "xLgr") + self.dest_nro = extract_text(self.dest, "nro") + self.dest_bairro = extract_text(self.dest, "xBairro") + self.dest_mun = extract_text(self.dest, "xMun") + self.dest_cnpj = format_cpf_cnpj(extract_text(self.dest, "CNPJ")) + self.dest_pais = extract_text(self.dest, "xPais") + self.dest_cep = format_cep(extract_text(self.dest, "CEP")) + self.dest_ie = extract_text(self.dest, "IE") + self.dest_fone = format_phone(extract_text(self.dest, "fone")) + + # Inf Expedidor + self.exped_nome = extract_text(self.exped, "xNome") + self.exped_loga = extract_text(self.exped, "xLgr") + self.exped_nro = extract_text(self.exped, "nro") + self.exped_bairro = extract_text(self.exped, "xBairro") + self.exped_mun = extract_text(self.exped, "xMun") + self.exped_cnpj = format_cpf_cnpj(extract_text(self.exped, "CNPJ")) + self.exped_pais = extract_text(self.exped, "xPais") + self.exped_cep = format_cep(extract_text(self.exped, "CEP")) + self.exped_ie = extract_text(self.exped, "IE") + self.exped_fone = format_phone(extract_text(self.exped, "fone")) + + # Inf Recebedor + self.receb_nome = extract_text(self.receb, "xNome") + self.receb_loga = extract_text(self.receb, "xLgr") + self.receb_nro = extract_text(self.receb, "nro") + self.receb_bairro = extract_text(self.receb, "xBairro") + self.receb_mun = extract_text(self.receb, "xMun") + self.receb_cnpj = format_cpf_cnpj(extract_text(self.receb, "CNPJ")) + self.receb_pais = extract_text(self.receb, "xPais") + self.receb_cep = format_cep(extract_text(self.receb, "CEP")) + self.receb_ie = extract_text(self.receb, "IE") + self.receb_fone = format_phone(extract_text(self.receb, "fone")) + + x_margin = self.l_margin + y_margin = 75 + page_width = 155 + + # TODO - TESTE + self.set_margins( + left=config.margins.left, top=config.margins.top, right=config.margins.right + ) + margins_to_y = { + 2: y_margin + 10, + 3: y_margin + 11, + 4: y_margin + 12, + 5: y_margin + 13, + 6: y_margin + 14, + 7: y_margin + 15, + 8: y_margin + 16, + 9: y_margin + 17, + 10: y_margin + 18, + } + section_start_y = margins_to_y[config.margins.left] + + self.rect( + x=x_margin, y=section_start_y, w=self.epw - 0.1 * x_margin, h=7, style="" + ) + col_width = (page_width - x_margin) / 2 + x_line_middle = x_margin + col_width + 20 + + self.line( + x1=x_line_middle, + x2=x_line_middle, + y1=section_start_y + 7, + y2=section_start_y, + ) + + self.set_font(self.default_font, "", 8) + self.set_xy(x=self.l_margin, y=section_start_y + 2) + self.multi_cell(w=0, h=0, text="INÍCIO DA PRESTAÇÃO", align="L") + self.set_xy(x=self.l_margin, y=section_start_y + 2) + self.set_font(self.default_font, "B", 8) + self.multi_cell(w=0, h=6, text=f"{self.mun_ini} - {self.est_inico}", align="L") + + self.set_font(self.default_font, "", 8) + self.set_xy(x_line_middle, section_start_y + 2) + self.multi_cell(w=0, h=0, text="TÉRMINO DA PRESTAÇÃO", align="L") + self.set_xy(x_line_middle, section_start_y + 2) + self.set_font(self.default_font, "B", 8) + self.multi_cell(w=0, h=6, text=f"{self.mun_fim} - {self.est_fim}", align="L") + + self.rect( + x=x_margin, y=section_start_y, w=self.epw - 0.1 * x_margin, h=24, style="" + ) + col_width = (page_width - x_margin) / 2 + x_line_middle = x_margin + col_width + 20 + self.line( + x1=x_line_middle, + x2=x_line_middle, + y1=section_start_y + 48, + y2=section_start_y, + ) + + # Remetente + self.set_font(self.default_font, "", 7) + self.set_xy(x=self.l_margin, y=section_start_y + 2) + self.multi_cell(w=0, h=15, text="REMETENTE ", align="L") + + self.set_font(self.default_font, "B", 7) + self.set_xy(x=self.l_margin + 16, y=section_start_y + 2) + self.multi_cell(w=0, h=15, text=f"{self.rem_nome}", align="L") + + self.set_font(self.default_font, "", 7) + self.set_xy(x=self.l_margin, y=section_start_y + 2) + self.multi_cell( + w=0, + h=21, + text="ENDEREÇO ", + align="L", + ) + + self.set_font(self.default_font, "B", 7) + self.set_xy(x=self.l_margin + 16, y=section_start_y + 2) + self.multi_cell( + w=0, + h=21, + text=f"{self.rem_loga}, {self.rem_bairro}, {self.rem_nro}", + align="L", + ) + + self.set_font(self.default_font, "", 7) + self.set_xy(x=self.l_margin, y=section_start_y + 2) + self.multi_cell(w=0, h=28, text="MUNICÍPIO ", align="L") + + self.set_font(self.default_font, "B", 7) + self.set_xy(x=self.l_margin + 16, y=section_start_y + 2) + self.multi_cell(w=0, h=28, text=f"{self.rem_mun}", align="L") + + self.set_font(self.default_font, "", 7) + self.set_xy(x=self.l_margin, y=section_start_y + 2) + self.multi_cell(w=0, h=35, text="CNPJ/CPF ", align="L") + + self.set_font(self.default_font, "B", 7) + self.set_xy(x=self.l_margin + 16, y=section_start_y + 2) + self.multi_cell(w=0, h=35, text=f"{self.rem_cnpj}", align="L") + + self.set_font(self.default_font, "", 7) + self.set_xy(x=self.l_margin, y=section_start_y + 2) + self.multi_cell(w=0, h=41, text="PAÍS ", align="L") + + self.set_font(self.default_font, "B", 7) + self.set_xy(x=self.l_margin + 16, y=section_start_y + 2) + self.multi_cell(w=0, h=41, text=f"{self.rem_pais}", align="L") + + self.set_font(self.default_font, "", 7) + self.set_xy(x_line_middle - 25, section_start_y + 2) + self.multi_cell(w=0, h=25, text="CEP ", align="L") + + self.set_font(self.default_font, "B", 7) + self.set_xy(x_line_middle - 18, section_start_y + 2) + if len(self.rem_cep.strip()) == 9: + self.multi_cell(w=0, h=25, text=f"{self.rem_cep}", align="L") + + self.set_font(self.default_font, "", 7) + self.set_xy(x_line_middle - 25, section_start_y + 2) + self.multi_cell(w=0, h=31, text="IE ", align="L") + + self.set_font(self.default_font, "B", 7) + self.set_xy(x_line_middle - 20, section_start_y + 2) + self.multi_cell(w=0, h=31, text=f"{self.rem_ie}", align="L") + + self.set_font(self.default_font, "", 7) + self.set_xy(x_line_middle - 29, section_start_y + 2) + self.multi_cell(w=0, h=38, text="FONE ", align="L") + + self.set_font(self.default_font, "B", 7) + self.set_xy(x_line_middle - 20, section_start_y + 2) + self.multi_cell(w=0, h=38, text=f"{self.rem_fone}", align="L") + + self.set_font(self.default_font, "", 7) + self.set_xy(x_line_middle, section_start_y + 2) + self.multi_cell(w=0, h=15, text="DESTINATÁRIO ", align="L") + + self.set_font(self.default_font, "B", 7) + self.set_xy(x_line_middle + 22, section_start_y + 2) + self.multi_cell(w=0, h=15, text=f"{self.dest_nome}", align="L") + + self.set_font(self.default_font, "", 7) + self.set_xy(x_line_middle, section_start_y + 2) + self.multi_cell( + w=0, + h=21, + text="ENDEREÇO ", + align="L", + ) + + self.set_font(self.default_font, "B", 7) + self.set_xy(x_line_middle + 22, section_start_y + 2) + self.multi_cell( + w=0, + h=21, + text=f"{self.dest_loga}, {self.dest_bairro}, {self.dest_nro}", + align="L", + ) + + self.set_font(self.default_font, "", 7) + self.set_xy(x_line_middle, section_start_y + 2) + self.multi_cell(w=0, h=28, text="MUNICÍPIO ", align="L") + + self.set_font(self.default_font, "B", 7) + self.set_xy(x_line_middle + 22, section_start_y + 2) + self.multi_cell(w=0, h=28, text=f"{self.dest_mun}", align="L") + + self.set_font(self.default_font, "", 7) + self.set_xy(x_line_middle, section_start_y + 2) + self.multi_cell(w=0, h=35, text="CNPJ/CPF ", align="L") + + self.set_font(self.default_font, "B", 7) + self.set_xy(x_line_middle + 22, section_start_y + 2) + self.multi_cell(w=0, h=35, text=f"{self.dest_cnpj}", align="L") + + self.set_font(self.default_font, "", 7) + self.set_xy(x_line_middle, section_start_y + 2) + self.multi_cell(w=0, h=41, text="PAÍS ", align="L") + + self.set_font(self.default_font, "B", 7) + self.set_xy(x_line_middle + 22, section_start_y + 2) + self.multi_cell(w=0, h=41, text=f"{self.dest_pais}", align="L") + + self.set_font(self.default_font, "", 7) + self.set_xy(x_line_middle + 70, section_start_y + 2) + self.multi_cell(w=0, h=25, text="CEP ", align="L") + + self.set_font(self.default_font, "B", 7) + self.set_xy(x_line_middle + 77, section_start_y + 2) + if len(self.dest_cep.strip()) == 9: + self.multi_cell(w=0, h=25, text=f"{self.dest_cep}", align="L") + + self.set_font(self.default_font, "", 7) + self.set_xy(x_line_middle + 70, section_start_y + 2) + self.multi_cell(w=0, h=31, text="IE ", align="L") + + self.set_font(self.default_font, "B", 7) + self.set_xy(x_line_middle + 75, section_start_y + 2) + self.multi_cell(w=0, h=31, text=f"{self.dest_ie}", align="L") + + self.set_font(self.default_font, "", 7) + self.set_xy(x_line_middle + 60, section_start_y + 2) + self.multi_cell(w=0, h=38, text="FONE ", align="L") + + self.set_font(self.default_font, "B", 7) + self.set_xy(x_line_middle + 67, section_start_y + 2) + self.multi_cell(w=0, h=38, text=f"{self.dest_fone}", align="L") + + section_start_y += 24 + + self.rect( + x=x_margin, y=section_start_y, w=self.epw - 0.1 * x_margin, h=24, style="" + ) + self.set_font(self.default_font, "", 7) + self.set_xy(x_line_middle, section_start_y + 2) + self.multi_cell(w=0, h=3, text="RECEBEDOR", align="L") + self.set_font(self.default_font, "B", 7) + self.set_xy(x_line_middle + 20, section_start_y + 2) + self.multi_cell(w=0, h=3, text=f"{self.receb_nome}", align="L") + + self.set_font(self.default_font, "", 7) + self.set_xy(x_line_middle, section_start_y + 2) + self.multi_cell(w=0, h=10, text="ENDEREÇO", align="L") + self.set_font(self.default_font, "B", 7) + self.set_xy(x_line_middle + 20, section_start_y + 2) + self.multi_cell( + w=0, + h=10.6, + text=f"{self.receb_loga} {self.receb_bairro} {self.receb_nro}", + align="L", + ) + + self.set_font(self.default_font, "", 7) + self.set_xy(x_line_middle, section_start_y + 2) + self.multi_cell(w=0, h=17, text="MUNICÍPIO", align="L") + self.set_font(self.default_font, "B", 7) + self.set_xy(x_line_middle + 20, section_start_y + 2) + self.multi_cell(w=0, h=18.2, text=f"{self.receb_mun}", align="L") + + self.set_font(self.default_font, "", 7) + self.set_xy(x_line_middle, section_start_y + 2) + self.multi_cell(w=0, h=25, text="CNPJ/CPF", align="L") + self.set_font(self.default_font, "B", 7) + self.set_xy(x_line_middle + 20, section_start_y + 2) + self.multi_cell(w=0, h=25.8, text=f"{self.receb_cnpj}", align="L") + + self.set_font(self.default_font, "", 7) + self.set_xy(x_line_middle, section_start_y + 2) + self.multi_cell(w=0, h=32, text="PAÍS", align="L") + self.set_font(self.default_font, "B", 7) + self.set_xy(x_line_middle + 20, section_start_y + 2) + self.multi_cell(w=0, h=33.4, text=f"{self.receb_pais}", align="L") + + self.set_font(self.default_font, "", 7) + self.set_xy(x_line_middle + 70, section_start_y + 2) + self.multi_cell(w=0, h=20, text="CEP", align="L") + self.set_font(self.default_font, "B", 7) + self.set_xy(x_line_middle + 77, section_start_y + 2) + if len(self.receb_cep.strip()) == 9: + self.multi_cell(w=0, h=20, text=f"{self.receb_cep}", align="L") + + self.set_font(self.default_font, "", 7) + self.set_xy(x_line_middle + 70, section_start_y + 2) + self.multi_cell(w=0, h=27, text="IE", align="L") + self.set_font(self.default_font, "B", 7) + self.set_xy(x_line_middle + 75, section_start_y + 2) + self.multi_cell(w=0, h=26.6, text=f"{self.receb_ie}", align="L") + + self.set_font(self.default_font, "", 7) + self.set_xy(x_line_middle + 60, section_start_y + 2) + self.multi_cell(w=0, h=34, text="FONE", align="L") + self.set_font(self.default_font, "B", 7) + self.set_xy(x_line_middle + 67, section_start_y + 2) + self.multi_cell(w=0, h=34, text=f"{self.receb_fone}", align="L") + + self.set_font(self.default_font, "", 7) + self.set_xy(x=self.l_margin, y=section_start_y + 2) + self.multi_cell(w=0, h=3, text="EXPEDIDOR", align="L") + self.set_font(self.default_font, "B", 7) + self.set_xy(x=self.l_margin + 16, y=section_start_y + 2) + self.multi_cell(w=0, h=3, text=f"{self.exped_nome}", align="L") + + self.set_font(self.default_font, "", 7) + self.set_xy(x=self.l_margin, y=section_start_y + 2) + self.multi_cell(w=0, h=10, text="ENDEREÇO", align="L") + self.set_font(self.default_font, "B", 7) + self.set_xy(x=self.l_margin + 16, y=section_start_y + 2) + self.multi_cell( + w=0, + h=10.6, + text=f"{self.exped_loga} {self.exped_bairro} {self.exped_nro}", + align="L", + ) + + self.set_font(self.default_font, "", 7) + self.set_xy(x=self.l_margin, y=section_start_y + 2) + self.multi_cell(w=0, h=17, text="MUNICÍPIO", align="L") + self.set_font(self.default_font, "B", 7) + self.set_xy(x=self.l_margin + 16, y=section_start_y + 2) + self.multi_cell(w=0, h=18.2, text=f"{self.exped_mun}", align="L") + + self.set_font(self.default_font, "", 7) + self.set_xy(x=self.l_margin, y=section_start_y + 2) + self.multi_cell(w=0, h=25, text="CNPJ/CPF", align="L") + self.set_font(self.default_font, "B", 7) + self.set_xy(x=self.l_margin + 16, y=section_start_y + 2) + self.multi_cell(w=0, h=25.8, text=f"{self.exped_cnpj}", align="L") + + self.set_font(self.default_font, "", 7) + self.set_xy(x=self.l_margin, y=section_start_y + 2) + self.multi_cell(w=0, h=32, text="PAÍS", align="L") + self.set_font(self.default_font, "B", 7) + self.set_xy(x=self.l_margin + 16, y=section_start_y + 2) + self.multi_cell(w=0, h=33.4, text=f"{self.exped_pais}", align="L") + + self.set_font(self.default_font, "", 7) + self.set_xy(x_line_middle - 25, section_start_y + 2) + self.multi_cell(w=0, h=20, text="CEP", align="L") + self.set_font(self.default_font, "B", 7) + self.set_xy(x_line_middle - 18, section_start_y + 2) + if len(self.exped_cep.strip()) == 9: + self.multi_cell(w=0, h=20, text=f"{self.exped_cep}", align="L") + + self.set_font(self.default_font, "", 7) + self.set_xy(x_line_middle - 25, section_start_y + 2) + self.multi_cell(w=0, h=27, text="IE", align="L") + self.set_font(self.default_font, "B", 7) + self.set_xy(x_line_middle - 20, section_start_y + 2) + self.multi_cell(w=0, h=27, text=f"{self.exped_ie}", align="L") + + self.set_font(self.default_font, "", 7) + self.set_xy(x_line_middle - 29, section_start_y + 2) + self.multi_cell(w=0, h=34, text="FONE", align="L") + self.set_font(self.default_font, "B", 7) + self.set_xy(x_line_middle - 20, section_start_y + 2) + self.multi_cell(w=0, h=34, text=f"{self.exped_fone}", align="L") + + def _draw_service_recipient(self, config): + self.inf_carga_nome = extract_text(self.inf_carga, "proPred") + self.inf_carga_car = extract_text(self.inf_carga, "xOutCat") + self.inf_carga_valor = format_number( + extract_text(self.inf_carga, "vCarga"), precision=2 + ) + self.inf_carga_peso = format_number( + extract_text(self.inf_carga, "qCarga"), precision=2 + ) + + self.inf_unid = extract_text(self.inf_carga, "cUnid") + + self.inf_carga_q = extract_text(self.inf_carga, "qCarga") + + x_margin = self.l_margin + y_margin = 123 + page_width = self.epw + + # TODO - TESTE + self.set_margins( + left=config.margins.left, top=config.margins.top, right=config.margins.right + ) + margins_to_y = { + 2: y_margin + 10, + 3: y_margin + 11, + 4: y_margin + 12, + 5: y_margin + 13, + 6: y_margin + 14, + 7: y_margin + 15, + 8: y_margin + 16, + 9: y_margin + 17, + 10: y_margin + 18, + } + section_start_y = margins_to_y[config.margins.left] + + self.rect( + x=x_margin, y=section_start_y, w=page_width - 0.1 * x_margin, h=10, style="" + ) + + self.set_font(self.default_font, "", 7.6) + self.set_xy(x_margin, section_start_y) + self.multi_cell(w=0, h=4, text="TOMADOR DO SERVIÇO ", align="L") + + self.set_font(self.default_font, "B", 7.6) + self.set_xy(x_margin + 32, section_start_y) + self.multi_cell(w=0, h=4, text=f"{self.rem_nome}", align="L") + + self.set_font(self.default_font, "", 7.6) + self.set_xy(x_margin, section_start_y) + self.multi_cell(w=0, h=10, text="ENDEREÇO ", align="L") + + self.set_font(self.default_font, "B", 7.6) + self.set_xy(x_margin + 16, section_start_y) + self.multi_cell( + w=0, + h=10, + text=f"{self.rem_loga} {self.rem_nro} {self.rem_bairro}", + align="L", + ) + + self.set_font(self.default_font, "", 7.6) + self.set_xy(x_margin, section_start_y) + self.multi_cell(w=0, h=16, text="CNPJ/CPF ", align="L") + + self.set_font(self.default_font, "B", 7.6) + self.set_xy(x_margin + 14, section_start_y) + self.multi_cell(w=0, h=16, text=f"{self.rem_cnpj}", align="L") + + self.set_font(self.default_font, "", 7.6) + self.set_xy(x_margin + 85, section_start_y) + self.multi_cell(w=0, h=16, text="IE ", align="L") + + self.set_font(self.default_font, "B", 7.6) + self.set_xy(x_margin + 89, section_start_y) + self.multi_cell(w=0, h=16, text=f"{self.rem_ie}", align="L") + + self.set_font(self.default_font, "", 7.6) + self.set_xy(x_margin + 115, section_start_y) + self.multi_cell(w=0, h=16, text="PAÍS ", align="L") + + self.set_font(self.default_font, "B", 7.6) + self.set_xy(x_margin + 122, section_start_y) + self.multi_cell(w=0, h=16, text=f"{self.rem_pais}", align="L") + + self.set_font(self.default_font, "", 7.6) + self.set_xy(x_margin + 150, section_start_y) + self.multi_cell(w=0, h=16, text="FONE ", align="L") + + self.set_font(self.default_font, "B", 7.6) + self.set_xy(x_margin + 158, section_start_y) + self.multi_cell(w=0, h=16, text=f"{self.rem_fone}", align="L") + + self.set_font(self.default_font, "", 7.6) + self.set_xy(x_margin + 100, section_start_y) + self.multi_cell(w=0, h=4, text="MUNICÍPIO ", align="L") + + self.set_font(self.default_font, "B", 7.6) + self.set_xy(x_margin + 116, section_start_y) + self.multi_cell(w=0, h=4, text=f"{self.rem_mun}", align="L") + + self.set_font(self.default_font, "", 7.6) + self.set_xy(x_margin + 150, section_start_y) + self.multi_cell(w=0, h=4, text="UF ", align="L") + + self.set_font(self.default_font, "B", 7.6) + self.set_xy(x_margin + 154, section_start_y) + self.multi_cell(w=0, h=4, text=f"{self.rem_uf}", align="L") + + self.set_font(self.default_font, "", 7.6) + self.set_xy(x_margin + 160, section_start_y) + self.multi_cell(w=0, h=4, text="CEP ", align="L") + + self.set_font(self.default_font, "B", 7.6) + self.set_xy(x_margin + 166, section_start_y) + self.multi_cell(w=0, h=4, text=f"{self.rem_cep}", align="L") + + section_start_y += 10 + + self.rect( + x=x_margin, y=section_start_y, w=page_width - 0.1 * x_margin, h=10, style="" + ) + col_width = (page_width - (x_margin - 20)) / 2 + x_line_1 = x_margin - 53 + col_width + x_line_2 = (x_margin - 53 + 2 * col_width) - 10 + x_line_3 = x_margin - 53 + 3 * col_width + self.line( + x1=x_line_1 + 30, + x2=x_line_1 + 30, + y1=section_start_y, + y2=section_start_y + 10, + ) + self.line(x1=x_line_2, x2=x_line_2, y1=section_start_y, y2=section_start_y + 10) + self.line(x1=x_line_3, x2=x_line_3, y1=section_start_y, y2=section_start_y + 10) + + self.set_xy(x_margin, section_start_y) + self.set_font(self.default_font, "", 7) + self.multi_cell(w=0, h=4, text="PRODUTO PREDOMINANTE", align="L") + self.set_xy(x_margin, section_start_y) + self.set_font(self.default_font, "B", 7) + self.multi_cell(w=0, h=14, text=self.inf_carga_nome, align="L") + + self.set_xy(x_line_1 + 30, section_start_y) + self.set_font(self.default_font, "", 7) + self.multi_cell(w=0, h=4, text="OUTRAS CARACTERÍSTICAS DA CARGA", align="L") + self.set_xy(x_line_1 + 30, section_start_y) + self.set_font(self.default_font, "B", 7) + self.multi_cell(w=0, h=14, text=self.inf_carga_car, align="L") + + self.set_xy(x_line_2, section_start_y) + self.set_font(self.default_font, "", 7) + self.multi_cell(w=0, h=4, text="VALOR TOTAL DA MERCADORIA", align="L") + self.set_xy(x_line_2, section_start_y) + self.set_font(self.default_font, "B", 7) + self.multi_cell(w=0, h=14, text=self.inf_carga_valor, align="L") + + section_start_y += 10 + + self.rect( + x=x_margin, y=section_start_y, w=page_width - 0.1 * x_margin, h=10, style="" + ) + col_width = (page_width - (x_margin + 2)) / 4 + x_line_1 = x_margin - 55 + col_width + x_line_2 = x_margin - 30 + 2 * col_width + x_line_3 = x_margin - 40 + 3 * col_width + x_line_4 = x_margin - 40 + 4 * col_width + self.line( + x1=x_line_1 + 34, + x2=x_line_1 + 34, + y1=section_start_y, + y2=section_start_y + 10, + ) + self.line(x1=x_line_2, x2=x_line_2, y1=section_start_y, y2=section_start_y + 10) + self.line(x1=x_line_3, x2=x_line_3, y1=section_start_y, y2=section_start_y + 10) + self.line(x1=x_line_4, x2=x_line_4, y1=section_start_y, y2=section_start_y + 10) + + # TODO TESTE + x_positions = [0, x_line_1 + 34, x_line_2, x_line_3, x_line_4] + titles = [ + "PESO (Kg)", + "TP MED /UN. MED", + "TP MED /UN. MED", + "CUBAGEM (M³)", + "QUANTIDADE DE VOLUMES", + ] + + for i, title in enumerate(titles): + self.set_xy(self.l_margin + x_positions[i], section_start_y) + self.set_font(self.default_font, "", 7.6) + self.multi_cell(w=0, h=4, text=title, align="L") + section_start_y += 5 + for item in self.inf_carga_list: + c_unid, tp_media, q_carga = item + if c_unid == "01" and q_carga > "0": + value_index = 0 + elif c_unid == "03" and tp_media.strip().upper() == "PARES": + value_index = 1 + elif c_unid == "00" and q_carga > "0": + value_index = 2 + elif c_unid == "00" and tp_media in ["M3", "m3"]: + value_index = 3 + elif c_unid == "03" and q_carga > "0": + value_index = 4 + else: + continue + + self.set_xy(self.l_margin + x_positions[value_index], section_start_y) + self.set_font(self.default_font, "B", 7) + self.multi_cell( + w=0, h=4, text=f"{q_carga} {tp_codigo_medida[c_unid]}", align="L" + ) + + def draw_section(self, y, height, text, align="C"): + self.rect(x=self.l_margin, y=y, w=self.epw - 0.1 * self.l_margin, h=3, style="") + self.set_xy(x=self.l_margin, y=y + 3) + self.cell(w=self.epw - 2 * self.l_margin, h=-3, text=text, align=align) + return y + height + + def _draw_service_fee_value(self): + x_margin = self.l_margin + y_margin = self.y + page_width = self.epw + self.cst = extract_text(self.imp, "CST") + self.vbc = format_number(extract_text(self.imp, "vBC"), precision=2) + self.p_icms = format_number(extract_text(self.imp, "pICMS"), precision=2) + self.v_icms = format_number(extract_text(self.imp, "vICMS"), precision=2) + self.v_icms_st = format_number(extract_text(self.imp, "vICMS"), precision=2) + self.p_red_bc = format_number(extract_text(self.imp, "pRedBC"), precision=2) + self.rntrc = extract_text(self.inf_modal, "RNTRC") + self.x_obs = extract_text(self.compl, "compl") + self.v_tpprest = format_number( + extract_text(self.v_prest, "vTPrest"), precision=2 + ) + self.v_rec = format_number(extract_text(self.v_prest, "vRec"), precision=2) + + section_start_y = y_margin + 1 + + self.set_font(self.default_font, "", 6.5) + section_start_y = self.draw_section( + section_start_y, 3, "COMPONENTES DO VALOR DA PRESTAÇÃO DO SERVIÇO" + ) + self.rect( + x=x_margin, y=section_start_y, w=page_width - 0.1 * x_margin, h=18, style="" + ) + + col_width = (page_width - 2 * x_margin) / 4 + for i in range(1, 4): + x_line = x_margin + i * col_width + self.line(x1=x_line, x2=x_line, y1=section_start_y, y2=section_start_y + 18) + + self.set_font(self.default_font, "", 8) + titles = ["NOME", "VALOR"] + for col in range( + 2 + ): # TODO Arrumar a sopreposição do title: NOME E VALOR SOBRE o FPESO + self.set_xy(x_margin + col * col_width, section_start_y - 6) + self.multi_cell(w=col_width / 2, h=16, text=titles[0], align="L") + self.set_xy(x_margin + col * col_width + col_width / 2, section_start_y - 6) + self.multi_cell(w=col_width / 2, h=16, text=titles[1], align="L") + + for row, (xNome, vComp) in enumerate(self.comp_list): + col = row % 3 + actual_row = row // 3 + self.set_xy(x_margin + col * col_width, section_start_y + (actual_row * 6)) + self.multi_cell(w=col_width / 2, h=4, text=xNome, align="L") + self.set_xy( + x_margin + col * col_width + col_width / 2, + section_start_y + (actual_row * 6), + ) + self.set_font(self.default_font, "B", 8) + self.multi_cell(w=col_width / 2, h=4, text=vComp, align="L") + self.set_font(self.default_font, "", 8) + + self.set_font(self.default_font, "", 8) + self.set_xy(x_margin + 3 * col_width, section_start_y) + self.multi_cell(w=col_width, h=4, text="VALOR TOTAL DO SERVIÇO", align="L") + self.set_font(self.default_font, "B", 8) + self.set_xy(x_margin + 3 * col_width, section_start_y + 4) + self.multi_cell(w=col_width, h=4, text=self.v_tpprest, align="L") + + self.line( + x1=x_margin + 3 * col_width, + x2=self.w - self.r_margin - 1, + y1=section_start_y + 10, + y2=section_start_y + 10, + ) + + self.set_font(self.default_font, "", 8) + self.set_xy(x_margin + 3 * col_width, section_start_y + 9) + self.multi_cell(w=col_width, h=8, text="VALOR TOTAL A RECEBER", align="L") + self.set_font(self.default_font, "B", 8) + self.set_xy(x_margin + 3 * col_width, section_start_y + 13) + self.multi_cell(w=col_width, h=7, text=self.v_rec, align="L") + + section_start_y += 18 + + self.set_font(self.default_font, "", 6.5) + section_start_y = self.draw_section( + section_start_y, 18, "INFORMAÇÕES RELATIVAS AO IMPOSTO" + ) + self.rect( + x=x_margin, + y=section_start_y - 15, + w=page_width - 0.1 * x_margin, + h=15, + style="", + ) + + col_width = (page_width - 2 * x_margin) / 6 + for i in range(1, 6): + x_line = x_margin + i * col_width + self.line(x1=x_line, x2=x_line, y1=section_start_y - 15, y2=section_start_y) + + tax_titles = [ + "SITUAÇÃO TRIBUTÁRIA", + "BASE DE CALCULO", + "ALÍQ ICMS", + "VALOR ICMS", + "% RED. BC ICMS", + "ICMS ST", + ] + tax_values = [ + f"{self.cst} - TRIBUTAÇÃO NORMAL DO ICMS", + f"{self.vbc}", + f"{self.p_icms}", + f"{self.v_icms}", + f"{self.p_red_bc}", + f"{self.v_icms_st}", + ] + + for i, (title, value) in enumerate(zip(tax_titles, tax_values)): + self.set_xy(x_margin + i * col_width, section_start_y - 15) + self.multi_cell(w=col_width, h=4, text=title, align="L") + self.set_font(self.default_font, "B", 6) + self.set_xy(x_margin + i * col_width, section_start_y - 11) + self.multi_cell(w=col_width, h=4, text=value, align="L") + self.set_font(self.default_font, "", 6) + + def _draw_documents_obs(self): + x_margin = self.l_margin + page_width = self.epw + self.set_font(self.default_font, "", 7) + section_start_y = self.get_y() + 7 + section_start_y = self.draw_section( + section_start_y, 43, "DOCUMENTOS ORIGINÁRIOS" + ) + self.rect( + x=x_margin, + y=section_start_y - 40, + w=page_width - 0.1 * x_margin, + h=40, + style="", + ) + col_width = (page_width - 2 * x_margin) / 2 + half_col_width = col_width / 3 + x_line_middle = x_margin + col_width + + self.line( + x1=x_line_middle, + x2=x_line_middle, + y1=section_start_y - 40, + y2=section_start_y, + ) + + self.set_font(self.default_font, "", 6) + self.set_xy(x_margin, section_start_y - 37) + self.multi_cell(w=half_col_width, h=0, text="TIPO DOC", align="L") + self.set_xy(x_margin + half_col_width - 18, section_start_y - 37) + self.multi_cell(w=half_col_width, h=0, text="CNPJ/CHAVE", align="L") + self.set_xy(x_margin + 2 * half_col_width, section_start_y - 37) + self.set_font(self.default_font, "", 5.5) + self.multi_cell(w=half_col_width, h=0, text="SÉRIE/NRO. DOCUMENTO", align="L") + + self.set_font(self.default_font, "", 6) + self.set_xy(x_line_middle, section_start_y - 37) + self.multi_cell(w=half_col_width, h=0, text="TIPO DOC", align="L") + self.set_xy(x_line_middle + half_col_width - 20, section_start_y - 37) + self.multi_cell(w=half_col_width, h=0, text="CNPJ/CHAVE", align="L") + self.set_xy(x_line_middle + 2 * half_col_width, section_start_y - 37) + self.set_font(self.default_font, "", 5.5) + self.multi_cell(w=half_col_width, h=0, text="SÉRIE/NRO. DOCUMENTO", align="L") + + y_offset_left = section_start_y - 33 + y_offset_right = section_start_y - 33 + lines_per_block = 7 + self.max_lines_per_page = 14 + current_line_left = 0 + current_line_right = 0 + in_right_block = False + + for index, chave in enumerate(self.inf_doc_list): + self.page_lines = index + if self.page_lines >= self.max_lines_per_page: + break + + if current_line_left == lines_per_block: + current_line_left = 0 + in_right_block = True + self.set_xy(x_line_middle, y_offset_right) + + if in_right_block: + x_start = x_line_middle + y_offset = y_offset_right + else: + x_start = x_margin + y_offset = y_offset_left + + self.set_xy(x_start, y_offset) + self.set_font(self.default_font, "B", 6) + self.multi_cell(w=half_col_width, h=4, text="NFE", align="L") + + self.set_xy(x_start + half_col_width - 20, y_offset) + self.multi_cell(w=half_col_width + 23, h=4, text=chave, align="L") + + key_nfe_1 = chave[22:25] + key_nfe_2 = chave[25:34] + key_nfe_format = f"{key_nfe_1}/{key_nfe_2}" + + self.set_font(self.default_font, "B", 6) + self.set_xy(x_start + 2 * half_col_width + 5, y_offset) + self.multi_cell(w=half_col_width, h=4, text=key_nfe_format, align="L") + + y_offset += 5 + if in_right_block: + current_line_right += 1 + y_offset_right = y_offset + else: + current_line_left += 1 + y_offset_left = y_offset + + if ( + not in_right_block + and current_line_left == 0 + and self.page_lines == lines_per_block + ): + y_offset_right = section_start_y - 33 + + self.set_font(self.default_font, "", 7) + text_width = page_width - 0.1 * x_margin + max_characters = 350 + combined_obs = " ".join(self.obs_dacte_list) + section_start_y = self.draw_section(section_start_y, 18, "OBSERVAÇÕES") + initial_y = section_start_y - 15 + + self.set_xy(x_margin, initial_y) + text_to_draw = combined_obs[:max_characters] + self.remaining_text = combined_obs[max_characters:] + self.text_exceeds_limit = len(combined_obs) > max_characters + + self.multi_cell(w=text_width, h=3, text=text_to_draw, align="L") + calculated_height = self.get_y() - initial_y + + rectangle_height = max(calculated_height, 10) + self.set_xy(x_margin, initial_y) + self.rect(x=x_margin, y=initial_y, w=text_width, h=rectangle_height) + + def _draw_specific_data(self, config): + x_margin = self.l_margin + page_width = self.epw + section_start_y = self.get_y() + 7 + section_start_y = self.draw_section( + section_start_y, + 13, + "DADOS ESPECÍFICOS DO MODAL RODOVIÁRIO - CARGA FRACIONADA", + ) + self.rect( + x=x_margin, + y=section_start_y - 10, + w=page_width - 0.1 * x_margin, + h=10, + style="", + ) + + col_width = (page_width - 2 * x_margin) / 4 + for i in range(1, 4): + x_line = x_margin + i * col_width + self.line(x1=x_line, x2=x_line, y1=section_start_y - 10, y2=section_start_y) + + self.set_font(self.default_font, "", 7) + road_titles = [ + "RNTRC DA EMPRESA", + "CIOT", + "DATA PREVISTA DE ENTREGA", + "ESTE CONHECIMENTO DE TRANSPORTE ATENDE" + "À LEGISLAÇÃO DE TRANSPORTE RODOVIÁRIO EM VIGOR", + ] + + road_values = [ + f"{self.rntrc}", + "", + "", + "", + ] + + for i, (title, value) in enumerate(zip(road_titles, road_values)): + self.set_xy(x_margin + i * col_width, section_start_y - 10) + self.multi_cell(w=col_width, h=3, text=title, align="L") + self.set_font(self.default_font, "B", 7) + self.set_xy(x_margin + i * col_width, section_start_y - 7) + self.multi_cell(w=col_width, h=3, text=value, align="L") + self.set_font(self.default_font, "", 6) + + self.set_font(self.default_font, "", 7) + section_start_y = self.draw_section( + section_start_y, 18, "USO EXCLUSIVO DO EMISSOR DO CT-E" + ) + # TODO TESTE + self.set_margins( + left=config.margins.left, top=config.margins.top, right=config.margins.right + ) + margins_to_height = { + 2: 13, + 3: 9, + 4: 10, + 5: 11, + 6: 11, + 7: 10, + 8: 9, + 9: 8, + 10: 7, + } + rect_height = margins_to_height[config.margins.left] + + self.rect( + x=x_margin, + y=section_start_y - 15, + w=page_width - 0.1 * x_margin, + h=rect_height, + style="", + ) + + # Adicionando outra pag + def _add_new_page(self): + x_margin = self.l_margin + page_width = self.epw + line_height = 4 + if self.page_lines > 0 and self.page_lines % self.max_lines_per_page == 0: + self.add_page(orientation=self.orientation) + self._draw_receipt() + self._draw_header() + + section_start_y = self.get_y() - 1 + section_start_y = self.draw_section( + section_start_y, 43, "DOCUMENTOS ORIGINÁRIOS" + ) + y_offset_left = section_start_y - 33 + y_offset_right = section_start_y - 33 + current_line_left = 0 + current_line_right = 0 + in_right_block = False + + self.set_font(self.default_font, "", 7) + col_width = (page_width - 2 * x_margin) / 2 + half_col_width = col_width / 3 + x_line_middle = x_margin + col_width + + total_documents = len(self.inf_doc_list) - self.page_lines + lines_per_column = (total_documents + 1) // 2 + rectangle_height = total_documents * line_height // 2 + self.rect( + x=x_margin, + y=section_start_y - 40, + w=page_width - 0.1 * x_margin, + h=rectangle_height + 8, + ) + self.line( + x1=x_line_middle, + x2=x_line_middle, + y1=section_start_y - 40, + y2=section_start_y - 32 + rectangle_height, + ) + + self.set_font(self.default_font, "", 6) + self.set_xy(x_margin, section_start_y - 37) + self.multi_cell(w=half_col_width, h=0, text="TIPO DOC", align="L") + self.set_xy(x_margin + half_col_width - 18, section_start_y - 37) + self.multi_cell(w=half_col_width, h=0, text="CNPJ/CHAVE", align="L") + self.set_xy(x_margin + 2 * half_col_width, section_start_y - 37) + self.set_font(self.default_font, "", 5.5) + self.multi_cell( + w=half_col_width, h=0, text="SÉRIE/NRO. DOCUMENTO", align="L" + ) + + self.set_font(self.default_font, "", 6) + self.set_xy(x_line_middle, section_start_y - 37) + self.multi_cell(w=half_col_width, h=0, text="TIPO DOC", align="L") + self.set_xy(x_line_middle + half_col_width - 20, section_start_y - 37) + self.multi_cell(w=half_col_width, h=0, text="CNPJ/CHAVE", align="L") + self.set_xy(x_line_middle + 2 * half_col_width, section_start_y - 37) + self.set_font(self.default_font, "", 5.5) + self.multi_cell( + w=half_col_width, h=0, text="SÉRIE/NRO. DOCUMENTO", align="L" + ) + + for i, chave in enumerate(self.inf_doc_list): + if i < self.page_lines: + continue + + if current_line_left == lines_per_column: + current_line_left = 0 + in_right_block = True + self.set_xy(x_line_middle, y_offset_right) + + if in_right_block: + x_start = x_line_middle + y_offset = y_offset_right + else: + x_start = x_margin + y_offset = y_offset_left + + self.set_xy(x_start, y_offset) + self.set_font(self.default_font, "B", 6) + self.multi_cell(w=half_col_width, h=line_height, text="NFE", align="L") + + self.set_xy(x_start + half_col_width - 20, y_offset) + self.multi_cell( + w=half_col_width + 23, h=line_height, text=chave, align="L" + ) + + key_nfe_1 = chave[22:25] + key_nfe_2 = chave[25:34] + key_nfe_format = f"{key_nfe_1}/{key_nfe_2}" + + self.set_font(self.default_font, "B", 6) + self.set_xy(x_start + 2 * half_col_width + 5, y_offset) + self.multi_cell( + w=half_col_width, h=line_height, text=key_nfe_format, align="L" + ) + + y_offset += line_height + if in_right_block: + current_line_right += 1 + y_offset_right = y_offset + else: + current_line_left += 1 + y_offset_left = y_offset + if self.text_exceeds_limit: + section_start_y = self.get_y() + 1 + self.set_font(self.default_font, "", 7) + text_width = page_width - 0.1 * x_margin + section_start_y = self.draw_section(section_start_y, 18, "OBSERVAÇÕES") + initial_y = section_start_y - 15 + + self.set_xy(x_margin, initial_y) + + self.multi_cell(w=text_width, h=3, text=self.remaining_text, align="L") + + self.set_xy(x_margin, initial_y) + self.rect( + x=x_margin, y=initial_y, w=text_width, h=self.eph - section_start_y + ) diff --git a/brazilfiscalreport/dacte/dacte_conf.py b/brazilfiscalreport/dacte/dacte_conf.py new file mode 100644 index 0000000..085c881 --- /dev/null +++ b/brazilfiscalreport/dacte/dacte_conf.py @@ -0,0 +1 @@ +URL = ".//{http://www.portalfiscal.inf.br/cte}" diff --git a/tests/fixtures/dacte_test_1.xml b/tests/fixtures/dacte_test_1.xml new file mode 100644 index 0000000..71ffa9e --- /dev/null +++ b/tests/fixtures/dacte_test_1.xml @@ -0,0 +1,204 @@ + + + + + + 01 + 0111111 + 6353 + PRESTACAO DE SERVICO + 57 + 2 + 99203223 + 2024-03-27T00:00:00-03:00 + 1 + 1 + 3 + 1 + 0 + 0 + 4.0 + 4216305 + SAO JOAO BATISTA + SC + 01 + 0 + 4216305 + SAO JOAO BATISTA + SC + 3556453 + VARGEM GRANDE PAULISTA + SP + 1 + 1 + + 0 + + + + + + 0 + + + 0 + + + + O valor aproximado de tributos incidentes sobre o preco deste servico e de R$ 56,40 + + + + 92382301841312 + 232412442 + FANTASMA TRANSPORTES LTDA + FANTASMA TRANSPORTES LTDA + + RUA TESTE FANTASMA + 0099 + FANTASMA + 4216305 + SAO JOAO BATISTA + 88240000 + SC + 489999009 + + 1 + + + 23924902942209 + 224242421 + INDUSTRIA FANTASMA DE TESTE + INDUSTRIA FANTASMA DE TESTE + 47232332239 + + RODOVIA SC FANTASMA + 122 + TESTE + 4216305 + SAO JOAO BATISTA + 88240000 + SC + 1058 + BRASIL + + + + 02394820392092 + 224242421 + EMPRESA DE TESTE + 23424242442 + + TESTE L.A + 21 + AO LADO DE EMPRESA FANTASMA + TESTE + 3556453 + VARGEM GRANDE PAULISTA + 06730000 + SP + 1058 + BRASIL + + + + 221.19 + 221.19 + + FPESO + 117.78 + + + FVALOR + 4.24 + + + PEDAGIO + 13.11 + + + TAXAS + 79.64 + + + GRIS + 3.15 + + + TAS + 3.27 + + + + + + 00 + 221.19 + 12.00 + 26.54 + + + 56.40 + + + + 3016.92 + FITA GOMADA SEMI-KRAFT 80MM C/REFORCO CADEADO + + 03 + UNIDADE + 14 + + + 03 + PARES + 0 + + + 00 + M3 + 0.0000 + + + 01 + PESO REAL + 209.8000 + + + 01 + PESO BASE DE CALCULO + 209.8000 + + 3016.92 + + + + 02394910232349239234934138491040891884149930 + + + + + 23920392 + + + + + + + https://dfe-portal.svrs.rs.gov.br/cte/qrCode?chCTe=42240302484555000343570020003396861081562222&tpAmb=1 + + + + + + 1 + RS20240222155212 + 4224030248244242523254224232424242 + 2024-03-27T20:17:16-03:00 + 2324240111249023 + UCtDCEsja/Ljq5GjpftJHAK3oHI= + 100 + Autorizado o uso do CT-e + + + diff --git a/tests/fixtures/dacte_test_overload.xml b/tests/fixtures/dacte_test_overload.xml new file mode 100644 index 0000000..9baa70d --- /dev/null +++ b/tests/fixtures/dacte_test_overload.xml @@ -0,0 +1,311 @@ + + + + + + 01 + 0111111 + 6353 + PRESTACAO DE SERVICO + 57 + 2 + 99203223 + 2024-03-27T00:00:00-03:00 + 1 + 1 + 3 + 1 + 0 + 0 + 4.0 + 4216305 + SAO JOAO BATISTA + SC + 01 + 0 + 4216305 + SAO JOAO BATISTA + SC + 3556453 + VARGEM GRANDE PAULISTA + SP + 1 + 1 + + 0 + + + + + + 2 + 2024-07-18 + + + 0 + + + Texto fictício para teste: Informação exemplo 1 - Seguradora: 12345678901234 + + Texto fictício para teste: Informação exemplo 2 - Seguradora: 12345678901234 + + + Texto fictício para teste: Informação exemplo 3 + + + Texto fictício para teste: Informação exemplo 4 - ROTA: ABCD/EFGH - TARIF: 123 - TIPO + MERCAD: EXEMPLO + + + Texto fictício para teste: Tratamento de dados exemplo (Art. X, Y). + + Texto fictício para teste: Informação exemplo 1 - Seguradora: 12345678901234 + + Texto fictício para teste: Informação exemplo 2 - Seguradora: 12345678901234 + + + Texto fictício para teste: Informação exemplo 3 + + + Texto fictício para teste: Informação exemplo 4 - ROTA: ABCD/EFGH - TARIF: 123 - TIPO + MERCAD: EXEMPLO + + + Texto fictício para teste: Tratamento de dados exemplo (Art. X, Y). + + + + 92382301841312 + 232412442 + FANTASMA TRANSPORTES LTDA + FANTASMA TRANSPORTES LTDA + + RUA TESTE FANTASMA + 0099 + FANTASMA + 4216305 + SAO JOAO BATISTA + 88240000 + SC + 489999009 + + 1 + + + 23924902942209 + 224242421 + INDUSTRIA FANTASMA DE TESTE + INDUSTRIA FANTASMA DE TESTE + 47232332239 + + RODOVIA SC FANTASMA + 122 + TESTE + 4216305 + SAO JOAO BATISTA + 88240000 + SC + 1058 + BRASIL + + + + 23924902942209 + 224242421 + CTE EMITIDO EM AMBIENTE DE TESTE + 47232332239 + + RODOVIA SC FANTASMA + 122 + Teste + 4216305 + Joinville + 89212210 + SC + 1058 + Brasil + + + + 03364555000100 + 254409377 + CTE EMITIDO EM AMBIENTE DE TESTE + 47232332239 + + RODOVIA SC FANTASMA + 200 + Cobre + 4216305 + SAO JOAO BATISTA + 88122035 + SC + 1058 + Brasil + + + + 02394820392092 + 224242421 + EMPRESA DE TESTE + 23424242442 + + TESTE L.A + 21 + AO LADO DE EMPRESA FANTASMA + TESTE + 3556453 + VARGEM GRANDE PAULISTA + 06730000 + SP + 1058 + BRASIL + + + + 221.19 + 221.19 + + FPESO + 117.78 + + + FVALOR + 4.24 + + + PEDAGIO + 13.11 + + + TAXAS + 79.64 + + + GRIS + 3.15 + + + TAS + 3.27 + + + + + + 00 + 221.19 + 12.00 + 26.54 + 20.00 + 10.00 + + + 56.40 + + + + 3016.92 + FITA GOMADA SEMI-KRAFT 80MM C/REFORCO CADEADO + + 03 + UNIDADE + 14 + + + 03 + PARES + 0 + + + 00 + M3 + 0.0000 + + + 01 + PESO REAL + 209.8000 + + + 01 + PESO BASE DE CALCULO + 209.8000 + + 3016.92 + + + + 62367248427294724924247484294724947224924724 + + + 26647257237588237892912038492427378248782474 + + + 26647257237588237892912038492427378248782474 + + + 21421432123787842376346723647623767432762367 + + + 26467762782874893612467784782478278782684286 + + + 27146726719120087166248234671990472672849217 + + + 23432423747432562783672839271638578534746644 + + + 27146726719120087166248234671990472672849217 + + + 23432423747432562783672839271638578534746644 + + + 21421432123787842376346723647623767432762367 + + + 42232387690480348792673297204795735037539474 + + + 21421432123787842376346723647623767432762367 + + + 42232387690480348792673297204795735037539474 + + + 42232387690480348792673297204795735037539474 + + + 21421432123787842376346723647623767432762367 + + + 42232387690480348792673297204795735037539474 + + + + + 23920392 + + + + + + + https://dfe-portal.svrs.rs.gov.br/cte/qrCode?chCTe=42240302484555000343570020003396861081562222&tpAmb=1 + + + + + + 1 + RS20240222155212 + 4224030248244242523254224232429098 + 2024-03-27T20:17:16-03:00 + 2324240111249023 + UCtDCEsja/Ljq5GjpftJHAK3oHI= + 100 + Autorizado o uso do CT-e + + + diff --git a/tests/generated/dacte/dacte_default.pdf b/tests/generated/dacte/dacte_default.pdf new file mode 100644 index 0000000..d1de559 Binary files /dev/null and b/tests/generated/dacte/dacte_default.pdf differ diff --git a/tests/generated/dacte/dacte_default_logo.pdf b/tests/generated/dacte/dacte_default_logo.pdf new file mode 100644 index 0000000..feb9224 Binary files /dev/null and b/tests/generated/dacte/dacte_default_logo.pdf differ diff --git a/tests/generated/dacte/dacte_overload.pdf b/tests/generated/dacte/dacte_overload.pdf new file mode 100644 index 0000000..36e1ac0 Binary files /dev/null and b/tests/generated/dacte/dacte_overload.pdf differ diff --git a/tests/test_dacte.py b/tests/test_dacte.py new file mode 100644 index 0000000..617e77e --- /dev/null +++ b/tests/test_dacte.py @@ -0,0 +1,50 @@ +import pytest + +from brazilfiscalreport.dacte import ( + Dacte, + DacteConfig, + Margins, + ReceiptPosition, +) +from tests.conftest import assert_pdf_equal, get_pdf_output_path + + +@pytest.fixture +def load_dacte(load_xml): + def _load_dacte(filename, config=None): + xml_content = load_xml(filename) + return Dacte(xml=xml_content, config=config) + + return _load_dacte + + +@pytest.fixture(scope="module") +def default_dacte_config(logo_path): + config = DacteConfig( + margins=Margins(top=2, right=2, bottom=2, left=2), + logo=logo_path, + receipt_pos=ReceiptPosition.TOP, + ) + return config + + +def test_dacte_default(tmp_path, load_dacte): + dacte = load_dacte("dacte_test_1.xml") + pdf_path = get_pdf_output_path("dacte", "dacte_default") + assert_pdf_equal(dacte, pdf_path, tmp_path) + + +def test_dacte_overload(tmp_path, load_dacte): + dacte_config = DacteConfig(margins=Margins(top=10, right=10, bottom=10, left=10)) + dacte = load_dacte("dacte_test_overload.xml", config=dacte_config) + pdf_path = get_pdf_output_path("dacte", "dacte_overload") + assert_pdf_equal(dacte, pdf_path, tmp_path) + + +def test_dacte_default_logo(tmp_path, load_dacte, logo_path): + dacte_config = DacteConfig( + logo=logo_path, + ) + dacte = load_dacte("dacte_test_1.xml", config=dacte_config) + pdf_path = get_pdf_output_path("dacte", "dacte_default_logo") + assert_pdf_equal(dacte, pdf_path, tmp_path)