diff --git a/addons/account_edi_ubl_cii/models/account_edi_common.py b/addons/account_edi_ubl_cii/models/account_edi_common.py
index 70e6242dc45..11100bd3c4a 100644
--- a/addons/account_edi_ubl_cii/models/account_edi_common.py
+++ b/addons/account_edi_ubl_cii/models/account_edi_common.py
@@ -327,6 +327,16 @@ class AccountEdiCommon(models.AbstractModel):
return True
+ def _import_retrieve_and_fill_partner(self, invoice, name, phone, mail, vat):
+ """ Retrieve the partner, if no matching partner is found, create it
+ """
+ invoice.partner_id = self.env['res.partner']._retrieve_partner(name=name, phone=phone, mail=mail, vat=vat)
+ if not invoice.partner_id and name:
+ invoice.partner_id = self.env['res.partner'].create({'name': name, 'email': mail, 'phone': phone})
+ country_code = invoice.partner_id.commercial_partner_id.country_code
+ if vat and self.env['res.partner']._run_vat_test(vat, country_code, invoice.partner_id.is_company):
+ invoice.partner_id.vat = vat
+
def _import_fill_invoice_allowance_charge(self, tree, invoice, qty_factor):
logs = []
if '{urn:oasis:names:specification:ubl:schema:xsd' in tree.tag:
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 11671e21803..55f70d7598c 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
@@ -220,15 +220,12 @@ class AccountEdiXmlCII(models.AbstractModel):
# ==== partner_id ====
- partner_type = 'SellerTradeParty' if invoice.journal_id.type == 'purchase' else 'BuyerTradeParty'
- invoice.partner_id = self.env['res.partner']._retrieve_partner(
- name=_find_value(f"//ram:{partner_type}/ram:Name"),
- mail=_find_value(f"//ram:{partner_type}//ram:URIID[@schemeID='SMTP']"),
- vat=_find_value(f"//ram:{partner_type}/ram:SpecifiedTaxRegistration/ram:ID"),
- company=invoice.company_id,
- )
- if not invoice.partner_id:
- logs.append(_("Could not retrieve the %s.", _("customer") if invoice.is_sale_document() else _("vendor")))
+ role = invoice.journal_id.type == 'purchase' and 'SellerTradeParty' or 'BuyerTradeParty'
+ name = _find_value(f"//ram:{role}/ram:Name")
+ mail = _find_value(f"//ram:{role}//ram:URIID[@schemeID='SMTP']")
+ vat = _find_value(f"//ram:{role}/ram:SpecifiedTaxRegistration/ram:ID")
+ phone = _find_value(f"//ram:{role}/ram:DefinedTradeContact/ram:TelephoneUniversalCommunication/ram:CompleteNumber")
+ self._import_retrieve_and_fill_partner(invoice, name=name, phone=phone, mail=mail, vat=vat)
# ==== currency_id ====
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 e8cda8b4e28..c0b766b08d0 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
@@ -2,7 +2,7 @@
from odoo import models, _
from odoo.osv import expression
-from odoo.tools import html2plaintext, cleanup_xml_node
+from odoo.tools import html2plaintext, cleanup_xml_node, find_xml_value
from lxml import etree
@@ -466,6 +466,12 @@ class AccountEdiXmlUBL20(models.AbstractModel):
# -------------------------------------------------------------------------
def _import_fill_invoice_form(self, invoice, tree, qty_factor):
+
+ def _find_value(xpath, element=tree):
+ # avoid 'TypeError: empty namespace prefix is not supported in XPath'
+ nsmap = {k: v for k, v in tree.nsmap.items() if k is not None}
+ return find_xml_value(xpath, element, nsmap)
+
logs = []
if qty_factor == -1:
@@ -473,11 +479,12 @@ class AccountEdiXmlUBL20(models.AbstractModel):
# ==== partner_id ====
- partner = self._import_retrieve_partner(tree, invoice)
- if partner:
- invoice.partner_id = partner
- else:
- logs.append(_("Could not retrieve the %s.", _("customer") if invoice.is_sale_document() else _("vendor")))
+ role = "Customer" if invoice.journal_id.type == 'sale' else "Supplier"
+ vat = _find_value(f'//cac:Accounting{role}Party/cac:Party//cbc:CompanyID')
+ phone = _find_value(f'//cac:Accounting{role}Party/cac:Party//cbc:Telephone')
+ mail = _find_value(f'//cac:Accounting{role}Party/cac:Party//cbc:ElectronicMail')
+ name = _find_value(f'//cac:Accounting{role}Party/cac:Party//cbc:Name')
+ self._import_retrieve_and_fill_partner(invoice, name=name, phone=phone, mail=mail, vat=vat)
# ==== currency_id ====
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 ea199df5822..44269f62490 100644
--- a/addons/l10n_account_edi_ubl_cii_tests/tests/common.py
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/common.py
@@ -95,6 +95,19 @@ class TestUBLCommon(AccountTestInvoicingCommon):
self.assertTrue(new_invoice)
self.assert_same_invoice(invoice, new_invoice)
+ def _update_invoice_from_file(self, module_name, subfolder, filename, invoice):
+ """ Create an attachment from a file and post it on the invoice
+ """
+ file_path = get_module_resource(module_name, subfolder, filename)
+ with misc.file_open(file_path, 'rb') as file:
+ attachment = self.env['ir.attachment'].create({
+ 'name': filename,
+ 'datas': base64.encodebytes(file.read()),
+ 'res_id': invoice.id,
+ 'res_model': 'account.move',
+ })
+ invoice.message_post(attachment_ids=[attachment.id])
+
def _assert_imported_invoice_from_file(self, subfolder, filename, amount_total, amount_tax, list_line_subtotals,
list_line_price_unit=None, list_line_discount=None, list_line_taxes=None,
move_type='in_invoice', currency_id=None):
@@ -116,16 +129,12 @@ class TestUBLCommon(AccountTestInvoicingCommon):
invoice_count = len(self.env['account.move'].search([]))
- # Import the file to fill the empty invoice
- file_path = get_module_resource('l10n_account_edi_ubl_cii_tests', subfolder, filename)
- with misc.file_open(file_path, 'rb') as file:
- attachment = self.env['ir.attachment'].create({
- 'name': filename,
- 'datas': base64.encodebytes(file.read()),
- 'res_id': invoice.id,
- 'res_model': 'account.move',
- })
- invoice.message_post(attachment_ids=[attachment.id])
+ self._update_invoice_from_file(
+ module_name='l10n_account_edi_ubl_cii_tests',
+ subfolder=subfolder,
+ filename=filename,
+ invoice=invoice,
+ )
# Checks
self.assertEqual(len(self.env['account.move'].search([])), invoice_count)
diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/facturx_test_import_partner.xml b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/facturx_test_import_partner.xml
new file mode 100644
index 00000000000..1be1f994a64
--- /dev/null
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/facturx_test_import_partner.xml
@@ -0,0 +1,127 @@
+
+
+
+
+ urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended
+
+
+
+ INV/2017/01/0001
+ 380
+
+ 20170101
+
+
+ test narration
+
+
+
+
+
+ 1
+
+
+ product_a
+
+
+
+ 0.00
+
+
+ 0.00
+
+
+
+ 1.0
+
+
+
+ 0.00
+
+
+
+
+
+ partner_1
+
+ partner_1
+
+ +1 (650) 555-0111
+
+
+ partner1@yourcompany.com
+
+
+
+ 75000
+ Rue Jean Jaurès, 42
+ Paris
+ FR
+
+
+ FR05677404089
+
+
+
+ Buyer
+
+ Buyer
+
+ 1111
+
+
+ buyer@yahoo.com
+
+
+
+ FR89215010646
+
+
+
+ INV/2017/01/0001
+
+
+
+
+ Buyer
+
+ Buyer
+
+ 1111
+
+
+ buyer@yahoo.com
+
+
+
+
+
+ 20170101
+
+
+
+
+ INV/2017/01/0001
+ USD
+
+ 42
+
+ FR15001559627230
+
+
+
+ 30% Advance End of Following Month
+
+
+ 0.00
+ 0.00
+ 0.00
+ 0.00
+ 0.00
+ 0.00
+
+
+
+
diff --git a/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/ubl_test_import_partner.xml b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/ubl_test_import_partner.xml
new file mode 100644
index 00000000000..17d7e0fa18d
--- /dev/null
+++ b/addons/l10n_account_edi_ubl_cii_tests/tests/test_files/from_odoo/ubl_test_import_partner.xml
@@ -0,0 +1,102 @@
+
+
+ 2.1
+ urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0
+
+ urn:fdc:peppol.eu:2017:poacc:billing:01:1.0
+ INV/2017/01/0002
+ 2017-01-01
+ 380
+ test narration
+ USD
+ Buyer
+
+ test invoice origin
+
+
+
+ BE0202239951
+
+ partner_1
+
+
+ Chaussée de Namur 40
+ Ramillies
+ 1367
+
+ BE
+
+
+
+ BE0202239951
+
+ VAT
+
+
+
+ partner_1
+ BE0202239951
+
+
+ partner_1
+
+
+
+
+
+ BE980737405
+
+ Buyer
+
+
+ BE980737405
+
+ VAT
+
+
+
+ Buyer
+ BE980737405
+
+
+ Buyer
+ 1111
+ buyer@yahoo.com
+
+
+
+
+ 30
+ +++000/0000/08282+++
+
+ BE15001559627230
+
+
+
+ 30% Advance End of Following Month
+
+
+ -0.00
+
+
+ 0.00
+ 0.00
+ 0.00
+ 0.00
+ 0.00
+
+
+ 259
+ 1.0
+ 0.00
+
+ product_a
+ product_a
+
+
+ 0.00
+
+
+
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 86f3c5914eb..1d97e7e73ae 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
@@ -304,6 +304,34 @@ class TestCIIFR(TestUBLCommon):
)
self._test_import_partner(invoice.ubl_cii_xml_id, self.partner_1, self.partner_2)
+ def test_import_and_create_partner_facturx(self):
+ """ Tests whether the partner is created at import if no match is found when decoding the EDI attachment
+ """
+ partner_vals = {
+ 'name': "Buyer",
+ 'mail': "buyer@yahoo.com",
+ 'phone': "1111",
+ 'vat': "FR89215010646",
+ }
+ # assert there is no matching partner
+ partner_match = self.env['res.partner']._retrieve_partner(**partner_vals)
+ self.assertFalse(partner_match)
+
+ # Import attachment as an invoice
+ invoice = self.env['account.move'].create({
+ 'move_type': 'out_invoice',
+ 'journal_id': self.company_data['default_journal_sale'].id,
+ })
+ self._update_invoice_from_file(
+ module_name='l10n_account_edi_ubl_cii_tests',
+ subfolder='tests/test_files/from_odoo',
+ filename='facturx_test_import_partner.xml',
+ invoice=invoice)
+
+ # assert a new partner has been created
+ partner_vals['email'] = partner_vals.pop('mail')
+ self.assertRecordValues(invoice.partner_id, [partner_vals])
+
def test_import_tax_included(self):
"""
Tests whether the tax included / tax excluded are correctly decoded when
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 580c50d50ba..f12513fb60f 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
@@ -219,6 +219,34 @@ class TestUBLBE(TestUBLCommon):
)
self._test_import_partner(invoice.ubl_cii_xml_id, self.partner_1, self.partner_2)
+ def test_import_and_create_partner_ubl(self):
+ """ Tests whether the partner is created at import if no match is found when decoding the EDI attachment
+ """
+ partner_vals = {
+ 'name': "Buyer",
+ 'mail': "buyer@yahoo.com",
+ 'phone': "1111",
+ 'vat': "BE980737405",
+ }
+ # assert there is no matching partner
+ partner_match = self.env['res.partner']._retrieve_partner(**partner_vals)
+ self.assertFalse(partner_match)
+
+ # Import attachment as an invoice
+ invoice = self.env['account.move'].create({
+ 'move_type': 'out_invoice',
+ 'journal_id': self.company_data['default_journal_sale'].id,
+ })
+ self._update_invoice_from_file(
+ module_name='l10n_account_edi_ubl_cii_tests',
+ subfolder='tests/test_files/from_odoo',
+ filename='ubl_test_import_partner.xml',
+ invoice=invoice)
+
+ # assert a new partner has been created
+ partner_vals['email'] = partner_vals.pop('mail')
+ self.assertRecordValues(invoice.partner_id, [partner_vals])
+
def test_import_export_invoice_xml(self):
"""
Test whether the elements only specific to ubl_be are correctly exported