diff --git a/addons/account/models/product.py b/addons/account/models/product.py index ff809bf3210..628443ab727 100644 --- a/addons/account/models/product.py +++ b/addons/account/models/product.py @@ -245,17 +245,21 @@ class ProductProduct(models.Model): # cut Sales Description from the name name = name.split('\n')[0] domains = [] - for value, domain in ( - (name, ('name', 'ilike', name)), - (default_code, ('default_code', '=', default_code)), - (barcode, ('barcode', '=', barcode)), - ): - if value is not None: - domains.append([domain]) + if default_code: + domains.append([('default_code', '=', default_code)]) + if barcode: + domains.append([('barcode', '=', barcode)]) - domain = expression.AND([ - expression.OR(domains), - self.env['product.product']._check_company_domain(company), - extra_domain, - ]) - return self.env['product.product'].search(domain, limit=1) + # Search for the product with the exact name, then ilike the name + name_domains = [('name', '=', name)], [('name', 'ilike', name)] if name else [] + for name_domain in name_domains: + product = self.env['product.product'].search( + expression.AND([ + expression.OR(domains + [name_domain]), + self.env['product.product']._check_company_domain(company), + ]), + limit=1, + ) + if product: + return product + return self.env['product.product'] 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 6443ad8a3bf..d8138151b2d 100644 --- a/addons/account_edi_ubl_cii/models/account_edi_common.py +++ b/addons/account_edi_ubl_cii/models/account_edi_common.py @@ -685,10 +685,16 @@ class AccountEdiCommon(models.AbstractModel): # Set the values on the line_form invoice_line.quantity = inv_line_vals['quantity'] - if inv_line_vals.get('product_uom_id'): + if not inv_line_vals.get('product_uom_id'): + logs.append( + _("Could not retrieve the unit of measure for line with label '%s'.", invoice_line.name)) + elif not invoice_line.product_id: + # no product set on the line, no need to check uom compatibility invoice_line.product_uom_id = inv_line_vals['product_uom_id'] - else: - logs.append(_("Could not retrieve the unit of measure for line with label '%s'.", invoice_line.name)) + elif inv_line_vals['product_uom_id'].category_id == invoice_line.product_id.product_tmpl_id.uom_id.category_id: + # needed to check that the uom is compatible with the category of the product + invoice_line.product_uom_id = inv_line_vals['product_uom_id'] + invoice_line.price_unit = inv_line_vals['price_unit'] invoice_line.discount = inv_line_vals['discount'] invoice_line.tax_ids = inv_line_vals['taxes'] diff --git a/addons/account_edi_ubl_cii/tests/__init__.py b/addons/account_edi_ubl_cii/tests/__init__.py index 5b6a56d0275..7a94876bd45 100644 --- a/addons/account_edi_ubl_cii/tests/__init__.py +++ b/addons/account_edi_ubl_cii/tests/__init__.py @@ -1,3 +1,4 @@ # -*- coding: utf-8 -*- from . import test_partner_peppol_fields +from . import test_ubl_cii diff --git a/addons/account_edi_ubl_cii/tests/test_ubl_cii.py b/addons/account_edi_ubl_cii/tests/test_ubl_cii.py new file mode 100644 index 00000000000..c5f8875da8e --- /dev/null +++ b/addons/account_edi_ubl_cii/tests/test_ubl_cii.py @@ -0,0 +1,96 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from lxml import etree +from odoo import Command +from odoo.addons.account.tests.common import AccountTestInvoicingCommon +from odoo.tests import tagged + + +@tagged('post_install', '-at_install') +class TestAccountEdiUblCii(AccountTestInvoicingCommon): + + @classmethod + def setUpClass(cls, chart_template_ref=None): + super().setUpClass(chart_template_ref=chart_template_ref) + + cls.uom_units = cls.env.ref('uom.product_uom_unit') + cls.uom_dozens = cls.env.ref('uom.product_uom_dozen') + + cls.displace_prdct = cls.env['product.product'].create({ + 'name': 'Displacement', + 'uom_id': cls.uom_units.id, + 'standard_price': 90.0, + }) + + cls.place_prdct = cls.env['product.product'].create({ + 'name': 'Placement', + 'uom_id': cls.uom_units.id, + 'standard_price': 80.0, + }) + + def test_import_product(self): + line_vals = [ + { + 'product_id': self.place_prdct.id, + 'product_uom_id': self.uom_units.id, + 'tax_ids': [self.company_data_2['default_tax_sale'].id] + }, { + 'product_id': self.displace_prdct.id, + 'product_uom_id': self.uom_units.id, + 'tax_ids': [self.company_data_2['default_tax_sale'].id] + }, { + 'product_id': self.displace_prdct.id, + 'product_uom_id': self.uom_units.id, + 'tax_ids': [self.company_data_2['default_tax_sale'].id] + }, { + 'product_id': self.displace_prdct.id, + 'product_uom_id': self.uom_dozens.id, + 'tax_ids': [self.company_data_2['default_tax_sale'].id] + } + ] + company = self.company_data_2['company'] + company.country_id = self.env['res.country'].search([('code', '=', 'FR')]) + company.vat = 'FR23334175221' + company.email = 'company@site.ext' + company.phone = '+33499999999' + company.zip = '78440' + + company.partner_id.ubl_cii_format = 'facturx' + company.partner_id.bank_ids = [Command.create({ + 'acc_number': '999999', + 'partner_id': company.partner_id.id, + 'acc_holder_name': 'The Chosen One' + })] + + invoice = self.env['account.move'].create({ + 'company_id': company.id, + 'partner_id': company.partner_id.id, + 'move_type': 'out_invoice', + 'journal_id': self.company_data_2['default_journal_sale'].id, + 'invoice_line_ids': [Command.create(vals) for vals in line_vals], + }) + invoice.action_post() + + template = self.env.ref('account.email_template_edi_invoice', raise_if_not_found=False) + print_wiz = self.env['account.move.send'].create({ + 'move_ids': invoice.ids, + 'mail_template_id': template.id + }) + print_wiz.checkbox_download = False + print_wiz.checkbox_send_mail = False + print_wiz.checkbox_send_by_post = False + print_wiz.checkbox_ubl_cii_xml = True + print_wiz.action_send_and_print() + + facturx_attachment = invoice.ubl_cii_xml_id + xml_tree = etree.fromstring(facturx_attachment.raw) + + # Testing the case where a product on the invoice has a UoM with a different category than the one in the DB + wrong_uom_line = xml_tree.findall('./{*}SupplyChainTradeTransaction/{*}IncludedSupplyChainTradeLineItem')[1] + wrong_uom_line.find('./{*}SpecifiedLineTradeDelivery/{*}BilledQuantity').attrib['unitCode'] = 'HUR' + + facturx_attachment.raw = etree.tostring(xml_tree) + new_invoice = invoice.journal_id._create_document_from_attachment(facturx_attachment.ids) + + self.assertRecordValues(new_invoice.invoice_line_ids, line_vals)