From fdb0079e901cf3ba4cdc704bed6507c8bfa31ad0 Mon Sep 17 00:00:00 2001 From: Julien Van Roy Date: Wed, 7 Sep 2022 09:39:49 +0000 Subject: [PATCH] [IMP] account_edi_ubl_cii: always generate Factur-X silently Always generate a Factur-X xml and embed it when a PDF is created. But no edi.document is created, no warnings will be displayed on the invoice, and the PDF is not PDF/A-3. The only purpose here is the Odoo interoperability. Rename the 'Factur-X' option to 'Factur-X PDF/A-3' and make it only visible for FR and DE companies. This 'Factur-X PDF/A-3' option will trigger the regular account.edi flow: create an edi.document and show warnings on the move if errors are detected. When a PDF is printed, embed the Factur-X xml and make the PDF a PDF/A-3. Thus, it can be used on Chorus Pro. task-2957808 closes odoo/odoo#102311 X-original-commit: 25d4635d544a0a48ac937b35c996f2cbdb8073ec Related: odoo/enterprise#32344 Related: odoo/documentation#2789 Signed-off-by: Laurent Smet Signed-off-by: Julien Van Roy --- addons/account_edi_ubl_cii/__manifest__.py | 6 +-- .../data/account_edi_data.xml | 9 +---- .../models/account_edi_format.py | 27 ++++++++++---- .../models/ir_actions_report.py | 37 +++++++++++++++++++ 4 files changed, 60 insertions(+), 19 deletions(-) diff --git a/addons/account_edi_ubl_cii/__manifest__.py b/addons/account_edi_ubl_cii/__manifest__.py index 2bc14653388..c1654b838c7 100644 --- a/addons/account_edi_ubl_cii/__manifest__.py +++ b/addons/account_edi_ubl_cii/__manifest__.py @@ -18,9 +18,9 @@ Note that E-FFF, NLCIUS and XRechnung (UBL) are only available for Belgian, Dutc respectively. UBL Bis 3 is only available for companies which country is present in the `EAS list `_. -Note also that you need to activate PDF A in order to be able to submit a Factur-X pdf on Chorus Pro: -go to Settings > Technical (debug mode) > System Parameters > select/create one with Key: edi.use_pdfa, Value: true. -With this setting, Chorus Pro will automatically detect the "PDF/A-3 (Factur-X)" format. +Note also that in order for Chorus Pro to automatically detect the "PDF/A-3 (Factur-X)" format, you need to activate +the "Factur-X PDF/A-3" option on the journal. This option will also validate the xml against the Factur-X and Chorus +Pro rules and show the errors. """, 'depends': ['account_edi'], 'data': [ diff --git a/addons/account_edi_ubl_cii/data/account_edi_data.xml b/addons/account_edi_ubl_cii/data/account_edi_data.xml index 2432ad25df5..f1821a3c3e6 100644 --- a/addons/account_edi_ubl_cii/data/account_edi_data.xml +++ b/addons/account_edi_ubl_cii/data/account_edi_data.xml @@ -1,17 +1,10 @@ - Factur-X (FR) + Factur-X (PDF/A-3) facturx_1_0_05 - - - edi.use_pdfa - false - - - NLCIUS (Netherlands) nlcius_1 diff --git a/addons/account_edi_ubl_cii/models/account_edi_format.py b/addons/account_edi_ubl_cii/models/account_edi_format.py index 7bfdae7aee0..d3f0acf219f 100644 --- a/addons/account_edi_ubl_cii/models/account_edi_format.py +++ b/addons/account_edi_ubl_cii/models/account_edi_format.py @@ -2,7 +2,6 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo import models, fields, _ -from odoo.tools import str2bool from odoo.addons.account_edi_ubl_cii.models.account_edi_common import COUNTRY_EAS import logging @@ -48,7 +47,9 @@ class AccountEdiFormat(models.Model): def _get_xml_builder(self, company): # see https://communaute.chorus-pro.gouv.fr/wp-content/uploads/2017/08/20170630_Solution-portail_Dossier_Specifications_Fournisseurs_Chorus_Facture_V.1.pdf # page 45 -> ubl 2.1 for France seems also supported - if self.code == 'facturx_1_0_05': + # Only show the Factur-X option for DE and FR companies. When generating the PDF, add a Factur-X xml if there + # isn't an existing one. So there's always a Factur-X in the PDF, even without the option. + if self.code == 'facturx_1_0_05' and company.country_id.code in ['DE', 'FR']: return self.env['account.edi.xml.cii'] # if the company's country is not in the EAS mapping, nothing is generated # 'NO' has to be present in COUNTRY_EAS @@ -84,11 +85,10 @@ class AccountEdiFormat(models.Model): def _is_enabled_by_default_on_journal(self, journal): # EXTENDS account_edi - # only facturx is enabled by default, the other formats aren't self.ensure_one() if self.code not in FORMAT_CODES: return super()._is_enabled_by_default_on_journal(journal) - return self.code == 'facturx_1_0_05' + return False def _ubl_cii_post_invoice(self, invoice): # EXTENDS account_edi @@ -96,7 +96,7 @@ class AccountEdiFormat(models.Model): builder = self._get_xml_builder(invoice.company_id) # For now, the errors are not displayed anywhere, don't want to annoy the user - xml_content, _ = builder._export_invoice(invoice) + xml_content, errors = builder._export_invoice(invoice) # DEBUG: send directly to the test platform (the one used by ecosio) #response = self.env['account.edi.common']._check_xml_ecosio(invoice, xml_content, builder._export_invoice_ecosio_schematrons()) @@ -112,7 +112,19 @@ class AccountEdiFormat(models.Model): attachment_create_vals.update({'res_id': invoice.id, 'res_model': 'account.move'}) attachment = self.env['ir.attachment'].create(attachment_create_vals) - return {invoice: {'success': True, 'attachment': attachment}} + + res = {invoice: {'attachment': attachment}} + if errors and self.code == 'facturx_1_0_05': + res[invoice].update({ + 'success': False, + 'error': _("Errors occured while creating the EDI document (format: %s). The receiver " + "might refuse it.", builder._description) + + '

  • ' + "
  • ".join(errors) + '
  • ', + 'blocking_level': 'info', + }) + else: + res[invoice]['success'] = True + return res def _get_move_applicability(self, move): # EXTENDS account_edi @@ -140,8 +152,7 @@ class AccountEdiFormat(models.Model): return pdf_writer.embed_odoo_attachment(edi_document.attachment_id, subtype='text/xml') - if not pdf_writer.is_pdfa and str2bool( - self.env['ir.config_parameter'].sudo().get_param('edi.use_pdfa', 'False')): + if not pdf_writer.is_pdfa: try: pdf_writer.convert_to_pdfa() except Exception as e: diff --git a/addons/account_edi_ubl_cii/models/ir_actions_report.py b/addons/account_edi_ubl_cii/models/ir_actions_report.py index 7b3529f8d1a..ddca3dd8292 100644 --- a/addons/account_edi_ubl_cii/models/ir_actions_report.py +++ b/addons/account_edi_ubl_cii/models/ir_actions_report.py @@ -3,10 +3,12 @@ from odoo import models from odoo.tools import cleanup_xml_node +from odoo.tools.pdf import OdooPdfFileReader, OdooPdfFileWriter from lxml import etree import base64 from xml.sax.saxutils import escape, quoteattr +import io class IrActionsReport(models.Model): @@ -62,4 +64,39 @@ class IrActionsReport(models.Model): invoice = self.env['account.move'].browse(res_id) self._add_pdf_into_invoice_xml(invoice, stream_data) + # If Factur-X isn't already generated, generate and embed it inside the PDF + if len(res_ids) == 1: + invoice = self.env['account.move'].browse(res_ids) + edi_doc_codes = invoice.edi_document_ids.edi_format_id.mapped('code') + # If Factur-X hasn't been generated, generate and embed it anyway + if invoice.is_sale_document() \ + and invoice.state == 'posted' \ + and 'facturx_1_0_05' not in edi_doc_codes \ + and self.env.ref('account_edi_ubl_cii.edi_facturx_1_0_05', raise_if_not_found=False): + # Add the attachments to the pdf file + pdf_stream = collected_streams[invoice.id]['stream'] + + # Read pdf content. + pdf_content = pdf_stream.getvalue() + reader_buffer = io.BytesIO(pdf_content) + reader = OdooPdfFileReader(reader_buffer, strict=False) + + # Post-process and embed the additional files. + writer = OdooPdfFileWriter() + writer.cloneReaderDocumentRoot(reader) + + # Generate and embed Factur-X + xml_content, _errors = self.env['account.edi.xml.cii']._export_invoice(invoice) + writer.addAttachment( + name=self.env['account.edi.xml.cii']._export_invoice_filename(invoice), + data=xml_content, + subtype='text/xml', + ) + + # Replace the current content. + pdf_stream.close() + new_pdf_stream = io.BytesIO() + writer.write(new_pdf_stream) + collected_streams[invoice.id]['stream'] = new_pdf_stream + return collected_streams