Skip to content

Commit

Permalink
[IMP] l10n_br_mdfe: add damdfe report
Browse files Browse the repository at this point in the history
  • Loading branch information
marcelsavegnago committed Nov 25, 2024
1 parent 37c48ac commit 951d9e4
Show file tree
Hide file tree
Showing 8 changed files with 349 additions and 2 deletions.
3 changes: 2 additions & 1 deletion l10n_br_mdfe/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
from . import models
from .hooks import post_init_hook
from . import models
from . import report
9 changes: 8 additions & 1 deletion l10n_br_mdfe/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@
"spec_driven_model",
],
"data": [
"security/ir.model.access.csv",
# Data
"data/ir_config_parameter.xml",
# Security
"security/ir.model.access.csv",
# Views
"views/document.xml",
"views/mdfe_action.xml",
"views/mdfe_menu.xml",
Expand All @@ -30,6 +33,10 @@
"views/modal/modal_aquaviario.xml",
"views/modal/modal_rodoviario.xml",
"views/modal/modal_ferroviario.xml",
# Report
"report/reports.xml",
"report/damdfe_mdfe.xml",
"report/damdfe_report.xml",
],
"demo": [
"demo/fiscal_document_demo.xml",
Expand Down
21 changes: 21 additions & 0 deletions l10n_br_mdfe/models/document.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Copyright 2023 KMEE
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

import base64
import re
import string
from enum import Enum
Expand Down Expand Up @@ -914,3 +915,23 @@ def _validate_xml(self, xml_file):
erros = Mdfe.schema_validation(xml_file)
erros = "\n".join(erros)
self.write({"xml_error_message": erros or False})

def make_pdf(self):
if not self.filtered(filtered_processador_edoc_mdfe):
return super().make_pdf()

attachment_data = {
"name": self.document_key + ".pdf",
"res_model": self._name,
"res_id": self.id,
"mimetype": "application/pdf",
"type": "binary",
}
report = self.env.ref("l10n_br_mdfe.report_damdfe")
pdf_data = report._render_qweb_pdf(self.fiscal_line_ids.document_id.ids)
attachment_data["datas"] = base64.b64encode(pdf_data[0])
file_pdf = self.file_report_id
self.file_report_id = False
file_pdf.unlink()

self.file_report_id = self.env["ir.attachment"].create(attachment_data)
1 change: 1 addition & 0 deletions l10n_br_mdfe/report/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import ir_actions_report
165 changes: 165 additions & 0 deletions l10n_br_mdfe/report/damdfe_mdfe.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<template id="report_damdfe_mdfe">
<t t-call="web.html_container">
<div style="font-size: 12px; max-width: 90mm; margin-top: 2mm;">
<div style="text-align: center; margin: 0 auto">
<h2
style="text-transform: uppercase; font-size: 18px; font-weight: bold;"
><t t-esc="company_legal_name" /></h2>
<div style="max-width: 20.5em; text-align: center; margin: 0 auto;">
<p style="margin-bottom: 0;"><t t-esc="company_street" />, <t
t-esc="company_district"
/>, <t t-esc="company_city" /> - <t
t-esc="company_state"
/></p>
</div>
<div
style="display: flex; justify-content: space-between; max-width: 20em; margin: 0 auto;"
>
<p style="margin-bottom: 0; padding: 0;">CNPJ: <t
t-esc="company_cnpj"
/></p>
<p style="margin-bottom: 0; padding: 0;">IE: <t
t-esc="company_ie"
/></p>
</div>
<div>
<p
class="text-transform: uppercase; margin-bottom: 0;"
>Documento Auxiliar do Manifesto de Transporte</p>
</div>
<t t-if="contingency">
<hr />
<div>
<p style="margin-bottom: 0;">Emitida em Contingência</p>
<p style="margin-bottom: 0;">Pendente de Autorização</p>
</div>
</t>
<hr />
<t t-if="homologation_environment">
<div style="text-transform: uppercase; ">
<p
style="margin-bottom: 0; font-size: 14px;"
>EMITIDA EM AMBIENTE DE HOMOLOGAÇÃO - SEM VALOR FISCAL</p>
</div>
<hr />
</t>
</div>
<div>
<p
style="font-size: 11px;"
># | COD | DESCRICAO | QUANTIDADE | UN | VL UNIT | VL TOTAL</p>
<t t-foreach="lines" t-as="line" t-key="line.id">
<p style="margin-bottom: 0;"><t
t-esc="line['product_index']"
/> <t t-esc="line['product_name']" /> <t
t-esc="line['product_quantity']"
/><t t-esc="line['product_uom']" /> X <t
t-esc="line['product_unit_value']"
/> <t t-esc="line['product_unit_total']" /> </p>
</t>
</div>
<hr />
<div>
<div
style="display: flex; justify-content: space-between; align-items: center;"
>
<p style="margin-bottom: 0;">Qtd total itens</p>
<p style="margin-bottom: 0;"><t
t-esc="total_product_quantity"
/></p>
</div>
<t t-if="unformatted_amount_discount_value">
<div
style="display: flex; justify-content: space-between; align-items: center;"
>
<p style="margin-bottom: 0;">Desconto</p>
<p style="margin-bottom: 0;"><t
t-esc="unformatted_amount_discount_value"
/></p>
</div>
</t>
<div
style="display: flex; justify-content: space-between; align-items: center;"
>
<p
style="text-transform: uppercase; font-weight: bold; margin-bottom: 0"
>Valor total</p>
<p style="margin-bottom: 0;"><t t-esc="amount_total" /></p>
</div>
</div>
<div
style="display: flex; justify-content: space-between; align-items: center;"
>
<t t-foreach="payments" t-as="payment">
<p style="margin-bottom: 0;"><t t-esc="payment['method']" /></p>
<p style="margin-bottom: 0;"><t t-esc="payment['value']" /></p>
</t>
</div>
<t t-if="amount_change">
<div
style="display: flex; justify-content: space-between; align-items: center;"
>
<p style="margin-bottom: 0;">TROCO</p>
<p style="margin-bottom: 0;"><t t-esc="amount_change" /></p>
</div>
</t>
<hr />
<div style="text-align: center;">
<p style="margin-bottom: 0;">Consulte pela chave de acesso em:</p>
<p style="margin-bottom: 0;"><t t-esc="nfce_url" /></p>
<p style="font-size: 13px; margin-bottom: 0;"><t
t-esc="document_key"
/></p>
</div>
<div
style="display: flex; flex-direction: row-reverse; align-items: center; justify-content: space-between; margin: 10px 0;"
>
<div>
<div>
<!-- TODO: Quando o consumidor for identificado deve haver o CPF ou CNPJ-->
<p
style="text-transform: uppercase; text-align: left; fonti-size: 18px; margin: 2px auto;"
>Consumidor Nao Identificado</p>
</div>

<div>
<p style="margin-bottom: 0;">Numero: <t
t-esc="document_number"
/></p>
<p style="margin-bottom: 0;">Serie: <t
t-esc="document_serie"
/></p>
<p style="margin-bottom: 0;">Emissao: <t
t-esc="document_date"
/></p>
</div>

<div>
<t t-if="contingency">
<p style="margin-bottom: 0;">Emitida em Contingencia</p>
<p style="margin-bottom: 0;">Pendente de Autorizacao</p>
</t>
<t t-else="">
<p style="margin-bottom: 0;">Protocolo: <t
t-esc="authorization_protocol"
/></p>
<p style="margin-bottom: 0;">Autorizacao: <t
t-esc="document_date"
/></p>
</t>
</div>
</div>

<div>
<t t-set="qr_code" t-value="document_qrcode" />
<img
t-att-src="'/report/barcode/?type=%s&amp;value=%s&amp;width=%s&amp;height=%s'%('QR', qr_code, 150, 150)"
/>
</div>
</div>
</div>
</t>
</template>
</odoo>
12 changes: 12 additions & 0 deletions l10n_br_mdfe/report/damdfe_report.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<odoo>
<record id="report_damdfe" model="ir.actions.report">
<field name="name">DAMDFE</field>
<field name="model">l10n_br_fiscal.document</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">main_template_damdfe</field>
<field name="report_file">main_template_damdfe</field>
<field name="print_report_name">'%s' % (object.document_key)</field>
<field name="binding_model_id" ref="model_l10n_br_fiscal_document" />
<field name="binding_type">report</field>
</record>
</odoo>
111 changes: 111 additions & 0 deletions l10n_br_mdfe/report/ir_actions_report.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# Copyright 2024 Engenere.one
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
import base64
import logging
from io import BytesIO

from brazilfiscalreport.dacte import Dacte, DacteConfig, Margins
from erpbrasil.edoc.pdf import base
from lxml import etree

from odoo import _, api, models
from odoo.exceptions import UserError

_logger = logging.getLogger(__name__)


class IrActionsReport(models.Model):
_inherit = "ir.actions.report"

def temp_xml_autorizacao(self, xml_string):
"""TODO: Migrate-me to erpbrasil.edoc.pdf ASAP"""
root = etree.fromstring(xml_string)
ns = {None: "http://www.portalfiscal.inf.br/cte"}
new_root = etree.Element("cteProc", nsmap=ns)

protCTe_node = etree.Element("protCTe")
infProt = etree.SubElement(protCTe_node, "infProt")
etree.SubElement(infProt, "tpAmb").text = "2"
etree.SubElement(infProt, "verAplic").text = ""
etree.SubElement(infProt, "dhRecbto").text = None
etree.SubElement(infProt, "nProt").text = ""
etree.SubElement(infProt, "digVal").text = ""
etree.SubElement(infProt, "cStat").text = ""
etree.SubElement(infProt, "xMotivo").text = ""

new_root.append(root)
new_root.append(protCTe_node)
return etree.tostring(new_root)

def _render_qweb_html(self, res_ids, data=None):
if self.report_name == "main_template_dacte":
return

return super()._render_qweb_html(res_ids, data=data)

def _render_qweb_pdf(self, res_ids, data=None):
if self.report_name not in ["main_template_dacte"]:
return super()._render_qweb_pdf(res_ids, data=data)

cte = self.env["l10n_br_fiscal.document"].search([("id", "in", res_ids)])

return self._render_dacte(cte)

def _render_dacte(self, cte):
if cte.document_type != "57":
raise UserError(_("You can only print a DACTE of a NFe(57)."))

cte_xml = False
if cte.authorization_file_id:
cte_xml = base64.b64decode(cte.authorization_file_id.datas)
elif cte.send_file_id:
cte_xml = base64.b64decode(cte.send_file_id.datas)

if not cte_xml:
raise UserError(_("No xml file was found."))

return self.render_dacte_brazilfiscalreport(cte, cte_xml)

def render_dacte_brazilfiscalreport(self, cte, cte_xml):
logo = False
if cte.issuer == "company" and cte.company_id.logo:
logo = base64.b64decode(cte.company_id.logo)
elif cte.issuer != "company" and cte.company_id.logo_web:
logo = base64.b64decode(cte.company_id.logo_web)

if logo:
tmpLogo = BytesIO()
tmpLogo.write(logo)
tmpLogo.seek(0)
else:
tmpLogo = False
config = self._get_dacte_config(tmpLogo, cte.company_id)

dacte = Dacte(xml=cte_xml, config=config)

tmpDacte = BytesIO()
dacte.output(tmpDacte)
dacte_file = tmpDacte.getvalue()
tmpDacte.close()

return dacte_file, "pdf"

@api.model
def _get_dacte_config(self, tmpLogo, company):
margins = Margins(
top=company.dacte_margin_top,
right=company.dacte_margin_right,
bottom=company.dacte_margin_bottom,
left=company.dacte_margin_left,
)
dacte_config = {
"logo": tmpLogo,
"margins": margins,
}
return DacteConfig(**dacte_config)

def render_dacte_erpbrasil(self, cte_xml):
pdf = base.ImprimirXml.imprimir(
string_xml=cte_xml,
)
return pdf, "pdf"
29 changes: 29 additions & 0 deletions l10n_br_mdfe/report/reports.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>

<record id="damdfe_mdfe_qweb_paperformat" model="report.paperformat">
<field name="name">DAMDFE MDFE-e qweb paper format</field>
<field name="default" eval="True" />
<field name="format">custom</field>
<field name="page_height">297</field>
<field name="page_width">56</field>
<field name="orientation">Portrait</field>
<field name="margin_top">0.5</field>
<field name="margin_bottom">0.5</field>
<field name="margin_left">0.5</field>
<field name="margin_right">0.5</field>
<field name="header_line" eval="False" />
<field name="header_spacing">10</field>
<field name="dpi">110</field>
</record>

<record id="action_print_damdfe_mdfe" model="ir.actions.report">
<field name="name">DAMDFE MDF-e</field>
<field name="model">account.move</field>
<field name="report_type">qweb-html</field>
<field name="report_name">l10n_br_mdfe.report_damdfe_mdfe</field>
<field name="report_file">l10n_br_mdfe.damdfe_mdfe</field>
<field name="paperformat_id" ref="damdfe_mdfe_qweb_paperformat" />
</record>

</odoo>

0 comments on commit 951d9e4

Please sign in to comment.