From 7ee8520bfbd9d1c9d9f2a912f7bfbb786b6909c9 Mon Sep 17 00:00:00 2001 From: "Benjamin Frantzen (bfr)" Date: Fri, 2 Jul 2021 10:28:24 +0000 Subject: [PATCH] [IMP] l10n_it_edi: added support to import p7m files Before this commit, only files coming through ir_server_mail where parsed. The goal of this commit is to allow upload of p7m files. closes odoo/odoo#73337 X-original-commit: 13ff9b488d28da5dceec22e1c26f448796ca30c0 Signed-off-by: Josse Colpaert Signed-off-by: bfr-o --- .../account_edi/models/account_edi_format.py | 18 +++++---- .../l10n_it_edi/models/account_edi_format.py | 37 ++++++++++++++++++- 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/addons/account_edi/models/account_edi_format.py b/addons/account_edi/models/account_edi_format.py index 4cf85a90bd2..dbfbcaab6d4 100644 --- a/addons/account_edi/models/account_edi_format.py +++ b/addons/account_edi/models/account_edi_format.py @@ -258,22 +258,25 @@ class AccountEdiFormat(models.Model): self.ensure_one() return self.env['account.move'] - def _create_invoice_from_binary(self, filename, content): + def _create_invoice_from_binary(self, filename, content, extension): """ Create a new invoice with the data inside a binary file. - :param filename: The name of the file. - :param content: The content of the binary file. - :returns: The created invoice. + :param filename: The name of the file. + :param content: The content of the binary file. + :param extension: The extensions as a string. + :returns: The created invoice. """ # TO OVERRIDE self.ensure_one() return self.env['account.move'] - def _update_invoice_from_binary(self, filename, content, invoice): + def _update_invoice_from_binary(self, filename, content, extension, invoice): """ Update an existing invoice with the data inside a binary file. :param filename: The name of the file. :param content: The content of the binary file. + :param extension: The extensions as a string. + :param invoice: The invoice to update. :returns: The updated invoice. """ # TO OVERRIDE @@ -382,6 +385,7 @@ class AccountEdiFormat(models.Model): def _decode_binary(self, filename, content): """Decodes any file into a list of one dictionary representing an attachment. + This is a fallback for all files that are not decoded by other methods. :param filename: The name of the file. :param content: The bytes representing the file. @@ -392,7 +396,7 @@ class AccountEdiFormat(models.Model): """ return [{ 'filename': filename, - 'extension': pathlib.Path(filename).suffixes, + 'extension': ''.join(pathlib.Path(filename).suffixes), 'content': content, 'type': 'binary', }] @@ -435,7 +439,7 @@ class AccountEdiFormat(models.Model): elif file_data['type'] == 'pdf': res = edi_format.with_company(self.env.company)._create_invoice_from_pdf_reader(file_data['filename'], file_data['pdf_reader']) file_data['pdf_reader'].stream.close() - else: # file_data['type'] == 'binary' + else: res = edi_format._create_invoice_from_binary(file_data['filename'], file_data['content'], file_data['extension']) except Exception as e: _logger.exception("Error importing attachment \"%s\" as invoice with format \"%s\"", file_data['filename'], edi_format.name, str(e)) diff --git a/addons/l10n_it_edi/models/account_edi_format.py b/addons/l10n_it_edi/models/account_edi_format.py index 419720157e3..9492c9defc6 100644 --- a/addons/l10n_it_edi/models/account_edi_format.py +++ b/addons/l10n_it_edi/models/account_edi_format.py @@ -5,9 +5,11 @@ from odoo import api, models, fields, _ from odoo.tests.common import Form from odoo.exceptions import UserError from odoo.tools import float_repr +from odoo.addons.l10n_it_edi.tools.remove_signature import remove_signature -import re +from lxml import etree from datetime import date, datetime +import re import logging import base64 @@ -196,6 +198,39 @@ class AccountEdiFormat(models.Model): return self._import_fattura_pa(tree, invoice) return super()._update_invoice_from_xml_tree(filename, tree, invoice) + def _decode_p7m_to_xml(self, filename, content): + decoded_content = remove_signature(content) + if not decoded_content: + return None + + try: + # Some malformed XML are accepted by FatturaPA, this expends compatibility + parser = etree.XMLParser(recover=True) + xml_tree = etree.fromstring(decoded_content, parser) + except Exception as e: + _logger.exception("Error when converting the xml content to etree: %s", e) + return None + if xml_tree is None or len(xml_tree) == 0: + return None + + return xml_tree + + def _create_invoice_from_binary(self, filename, content, extension): + self.ensure_one() + if extension.lower() == '.xml.p7m': + decoded_content = self._decode_p7m_to_xml(filename, content) + if decoded_content is not None and self._is_fattura_pa(filename, decoded_content): + return self._import_fattura_pa(decoded_content, self.env['account.move']) + return super()._create_invoice_from_binary(filename, content, extension) + + def _update_invoice_from_binary(self, filename, content, extension, invoice): + self.ensure_one() + if extension.lower() == '.xml.p7m': + decoded_content = self._decode_p7m_to_xml(filename, content) + if decoded_content is not None and self._is_fattura_pa(filename, decoded_content): + return self._import_fattura_pa(decoded_content, invoice) + return super()._update_invoice_from_binary(filename, content, extension, invoice) + def _import_fattura_pa(self, tree, invoice): """ Decodes a fattura_pa invoice into an invoice.