From cfabf596cb354cc6434d727dbcd1f6d8c95c335e Mon Sep 17 00:00:00 2001
From: Julien Van Roy <juvr@odoo.com>
Date: Thu, 1 Dec 2022 16:55:47 +0000
Subject: [PATCH] [FIX] account_edi_ubl_cii: prepend encoding to xml

Prepend the encoding `<?xml version="1.0" encoding="utf-8"?>` to every xml
in the account_edi_ubl_cii module.

The absence of this tag was causing a 'Document format not supported.' error on myguichet.lu.

closes odoo/odoo#107118

X-original-commit: 6823ffcc7e0b27abdff670d53e4a5f885f218f79
Signed-off-by: Nicolas Viseur (vin) <vin@odoo.com>
Signed-off-by: Julien Van Roy <juvr@odoo.com>
---
 .../models/account_edi_xml_cii_facturx.py     |  3 ++-
 .../models/account_edi_xml_ubl_20.py          |  3 ++-
 .../tests/common.py                           | 19 +++++++++++++++++--
 .../test_files/from_odoo/bis3_out_invoice.xml |  1 +
 .../test_files/from_odoo/bis3_out_refund.xml  |  1 +
 .../from_odoo/facturx_out_invoice.xml         |  1 +
 .../facturx_out_invoice_tax_incl.xml          |  1 +
 .../from_odoo/facturx_out_refund.xml          |  1 +
 .../from_odoo/nlcius_out_invoice.xml          |  1 +
 .../from_odoo/nlcius_out_refund.xml           |  1 +
 .../from_odoo/xrechnung_ubl_out_invoice.xml   |  1 +
 .../from_odoo/xrechnung_ubl_out_refund.xml    |  1 +
 .../tests/test_xml_cii_fr.py                  |  3 +++
 .../tests/test_xml_ubl_be.py                  |  3 +++
 14 files changed, 36 insertions(+), 4 deletions(-)

diff --git a/addons/account_edi_ubl_cii/models/account_edi_xml_cii_facturx.py b/addons/account_edi_ubl_cii/models/account_edi_xml_cii_facturx.py
index 9ccb35f92f71..e99de773036b 100644
--- a/addons/account_edi_ubl_cii/models/account_edi_xml_cii_facturx.py
+++ b/addons/account_edi_ubl_cii/models/account_edi_xml_cii_facturx.py
@@ -198,7 +198,8 @@ class AccountEdiXmlCII(models.AbstractModel):
         vals = self._export_invoice_vals(invoice)
         errors = [constraint for constraint in self._export_invoice_constraints(invoice, vals).values() if constraint]
         xml_content = self.env['ir.qweb']._render('account_edi_ubl_cii.account_invoice_facturx_export_22', vals)
-        return etree.tostring(cleanup_xml_node(xml_content)), set(errors)
+        xml_content = b"<?xml version='1.0' encoding='UTF-8'?>\n" + etree.tostring(cleanup_xml_node(xml_content))
+        return xml_content, set(errors)
 
     # -------------------------------------------------------------------------
     # IMPORT
diff --git a/addons/account_edi_ubl_cii/models/account_edi_xml_ubl_20.py b/addons/account_edi_ubl_cii/models/account_edi_xml_ubl_20.py
index 509ce5910484..6f7149e3be37 100644
--- a/addons/account_edi_ubl_cii/models/account_edi_xml_ubl_20.py
+++ b/addons/account_edi_ubl_cii/models/account_edi_xml_ubl_20.py
@@ -450,7 +450,8 @@ class AccountEdiXmlUBL20(models.AbstractModel):
         vals = self._export_invoice_vals(invoice)
         errors = [constraint for constraint in self._export_invoice_constraints(invoice, vals).values() if constraint]
         xml_content = self.env['ir.qweb']._render(vals['main_template'], vals)
-        return etree.tostring(cleanup_xml_node(xml_content)), set(errors)
+        xml_content = b"<?xml version='1.0' encoding='UTF-8'?>\n" + etree.tostring(cleanup_xml_node(xml_content))
+        return xml_content, set(errors)
 
     # -------------------------------------------------------------------------
     # IMPORT
diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/common.py b/addons/l10n_account_edi_ubl_cii_tests/tests/common.py
index 74b572c6697c..3959dcbdf1e3 100644
--- a/addons/l10n_account_edi_ubl_cii_tests/tests/common.py
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/common.py
@@ -6,8 +6,8 @@ from freezegun import freeze_time
 from odoo.addons.account_edi.tests.common import AccountEdiTestCommon
 from odoo import fields
 from odoo.modules.module import get_resource_path
-from odoo.tools.misc import file_open
 from odoo.tests import tagged
+from lxml import etree
 
 
 @tagged('post_install_l10n', 'post_install', '-at_install')
@@ -175,7 +175,7 @@ class TestUBLCommon(AccountEdiTestCommon):
         xml_etree = self.get_xml_tree_from_string(xml_content)
 
         expected_file_path = get_resource_path('l10n_account_edi_ubl_cii_tests', 'tests/test_files', expected_file)
-        expected_etree = self.get_xml_tree_from_string(file_open(expected_file_path, "r").read())
+        expected_etree = etree.parse(expected_file_path).getroot()
 
         modified_etree = self.with_applied_xpath(
             expected_etree,
@@ -223,3 +223,18 @@ class TestUBLCommon(AccountEdiTestCommon):
                 [('type', '=', 'purchase'), ('company_id', '=', self.env.company.id)], limit=1)
         )
         self.assertEqual(self.partner_1, new_invoice.partner_id)
+
+    def _test_encoding_in_attachment(self, edi_code, filename):
+        """
+        Generate an invoice, assert that the tag '<?xml version='1.0' encoding='UTF-8'?>' is present in the attachment
+        """
+        invoice = self._generate_move(
+            seller=self.partner_1,
+            buyer=self.partner_2,
+            move_type='out_invoice',
+            invoice_line_ids=[{'product_id': self.product_a.id}],
+        )
+        edi_attachment = invoice.edi_document_ids.filtered(
+            lambda doc: doc.edi_format_id.code == edi_code).attachment_id
+        self.assertEqual(edi_attachment.name, filename)
+        self.assertIn(b"<?xml version='1.0' encoding='UTF-8'?>", edi_attachment.raw)
diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/bis3_out_invoice.xml b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/bis3_out_invoice.xml
index cc8f76ab1365..aebecfec20c0 100644
--- a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/bis3_out_invoice.xml
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/bis3_out_invoice.xml
@@ -1,3 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
 <Invoice xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">
   <cbc:UBLVersionID>2.1</cbc:UBLVersionID>
   <cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0</cbc:CustomizationID>
diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/bis3_out_refund.xml b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/bis3_out_refund.xml
index 0e6618c3df19..321d1705fa3d 100644
--- a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/bis3_out_refund.xml
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/bis3_out_refund.xml
@@ -1,3 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
 <CreditNote xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns="urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2">
   <cbc:UBLVersionID>2.1</cbc:UBLVersionID>
   <cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0</cbc:CustomizationID>
diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/facturx_out_invoice.xml b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/facturx_out_invoice.xml
index 7fa151c8f3e6..9d394905a948 100644
--- a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/facturx_out_invoice.xml
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/facturx_out_invoice.xml
@@ -1,3 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
 <rsm:CrossIndustryInvoice xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100" xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100" xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100">
   <rsm:ExchangedDocumentContext>
     <ram:GuidelineSpecifiedDocumentContextParameter>
diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/facturx_out_invoice_tax_incl.xml b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/facturx_out_invoice_tax_incl.xml
index ae2eef40989f..22a1905f5d5f 100644
--- a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/facturx_out_invoice_tax_incl.xml
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/facturx_out_invoice_tax_incl.xml
@@ -1,3 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
 <rsm:CrossIndustryInvoice xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100" xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100" xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100">
   <rsm:ExchangedDocumentContext>
     <ram:GuidelineSpecifiedDocumentContextParameter>
diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/facturx_out_refund.xml b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/facturx_out_refund.xml
index 1c4ed46bcbd0..b8555d2fec60 100644
--- a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/facturx_out_refund.xml
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/facturx_out_refund.xml
@@ -1,3 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
 <rsm:CrossIndustryInvoice xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100" xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100" xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100">
   <rsm:ExchangedDocumentContext>
     <ram:GuidelineSpecifiedDocumentContextParameter>
diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/nlcius_out_invoice.xml b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/nlcius_out_invoice.xml
index e867d4b2377f..49ab54b6795e 100644
--- a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/nlcius_out_invoice.xml
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/nlcius_out_invoice.xml
@@ -1,3 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
 <Invoice xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2">
   <cbc:UBLVersionID>2.1</cbc:UBLVersionID>
   <cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:fdc:nen.nl:nlcius:v1.0</cbc:CustomizationID>
diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/nlcius_out_refund.xml b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/nlcius_out_refund.xml
index 8f24448d3a6f..798103575cee 100644
--- a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/nlcius_out_refund.xml
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/nlcius_out_refund.xml
@@ -1,3 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
 <CreditNote xmlns="urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2">
   <cbc:UBLVersionID>2.1</cbc:UBLVersionID>
   <cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:fdc:nen.nl:nlcius:v1.0</cbc:CustomizationID>
diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/xrechnung_ubl_out_invoice.xml b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/xrechnung_ubl_out_invoice.xml
index 42e464bf2543..80bd4508720f 100644
--- a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/xrechnung_ubl_out_invoice.xml
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/xrechnung_ubl_out_invoice.xml
@@ -1,3 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
 <Invoice xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2">
   <cbc:UBLVersionID>2.1</cbc:UBLVersionID>
   <cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.2#conformant#urn:xoev-de:kosit:extension:xrechnung_2.2</cbc:CustomizationID>
diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/xrechnung_ubl_out_refund.xml b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/xrechnung_ubl_out_refund.xml
index c9a8d7b158df..345bc26dc7ac 100644
--- a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/xrechnung_ubl_out_refund.xml
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/xrechnung_ubl_out_refund.xml
@@ -1,3 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
 <CreditNote xmlns="urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2">
   <cbc:UBLVersionID>2.1</cbc:UBLVersionID>
   <cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.2#conformant#urn:xoev-de:kosit:extension:xrechnung_2.2</cbc:CustomizationID>
diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_xml_cii_fr.py b/addons/l10n_account_edi_ubl_cii_tests/tests/test_xml_cii_fr.py
index bd961895553b..1d72a9f026db 100644
--- a/addons/l10n_account_edi_ubl_cii_tests/tests/test_xml_cii_fr.py
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_xml_cii_fr.py
@@ -283,6 +283,9 @@ class TestCIIFR(TestUBLCommon):
             expected_file='from_odoo/facturx_out_invoice_tax_incl.xml'
         )
 
+    def test_encoding_in_attachment_facturx(self):
+        self._test_encoding_in_attachment('facturx_1_0_05', 'factur-x.xml')
+
     ####################################################
     # Test import
     ####################################################
diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_xml_ubl_be.py b/addons/l10n_account_edi_ubl_cii_tests/tests/test_xml_ubl_be.py
index 7a168ed145df..da431c0d754f 100644
--- a/addons/l10n_account_edi_ubl_cii_tests/tests/test_xml_ubl_be.py
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_xml_ubl_be.py
@@ -213,6 +213,9 @@ class TestUBLBE(TestUBLCommon):
         self.assertEqual(xml_filename[-12:], "ubl_bis3.xml")
         self._assert_imported_invoice_from_etree(refund, xml_etree, xml_filename)
 
+    def test_encoding_in_attachment_ubl(self):
+        self._test_encoding_in_attachment('ubl_bis3', 'INV_2017_01_0002_ubl_bis3.xml')
+
     ####################################################
     # Test import
     ####################################################
-- 
GitLab