From 4774c58dbe1faff4855bd33ba8d29742a53d072b Mon Sep 17 00:00:00 2001 From: Ivan Yelizariev Date: Tue, 25 May 2021 15:22:38 +0000 Subject: [PATCH] [FIX] sale: fix search "invoices is not set" for sale.order Previous attempt #70343 of fixing was incorrect. Check code comments for details. --- opw-2516124 closes odoo/odoo#71547 X-original-commit: 9b64e523dfdbc82099c1de5b47ed13d6d6f75fe5 Signed-off-by: Ivan Yelizariev // IEL --- addons/sale/models/sale_order.py | 18 +++++++++++++-- addons/sale/tests/test_sale_to_invoice.py | 28 +++++++++++++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/addons/sale/models/sale_order.py b/addons/sale/models/sale_order.py index 6759be18198..e526e87cb6b 100644 --- a/addons/sale/models/sale_order.py +++ b/addons/sale/models/sale_order.py @@ -138,8 +138,22 @@ class SaleOrder(models.Model): """, (list(value),)) so_ids = self.env.cr.fetchone()[0] or [] return [('id', 'in', so_ids)] - if operator == '=' and not value: - return [('order_line.invoice_lines', '=', False)] + elif operator == '=' and not value: + # special case for [('invoice_ids', '=', False)], i.e. "Invoices is not set" + # + # We cannot just search [('order_line.invoice_lines', '=', False)] + # because it returns orders with uninvoiced lines, which is not + # same "Invoices is not set" (some lines may have invoices and some + # doesn't) + # + # A solution is making inverted search first ("orders with invoiced + # lines") and then invert results ("get all other orders") + # + # Domain below returns subset of ('order_line.invoice_lines', '!=', False) + order_ids = self._search([ + ('order_line.invoice_lines.move_id.move_type', 'in', ('out_invoice', 'out_refund')) + ]) + return [('id', 'not in', order_ids)] return ['&', ('order_line.invoice_lines.move_id.move_type', 'in', ('out_invoice', 'out_refund')), ('order_line.invoice_lines.move_id', operator, value)] name = fields.Char(string='Order Reference', required=True, copy=False, readonly=True, states={'draft': [('readonly', False)]}, index=True, default=lambda self: _('New')) diff --git a/addons/sale/tests/test_sale_to_invoice.py b/addons/sale/tests/test_sale_to_invoice.py index 06247d827ce..7c6a87d1898 100644 --- a/addons/sale/tests/test_sale_to_invoice.py +++ b/addons/sale/tests/test_sale_to_invoice.py @@ -66,12 +66,37 @@ class TestSaleToInvoice(TestSaleCommon): 'default_journal_id': cls.company_data['default_journal_sale'].id, } + def _check_order_search(self, orders, domain, expected_result): + domain += [('id', 'in', orders.ids)] + result = self.env['sale.order'].search(domain) + self.assertEqual(result, expected_result, "Unexpected result on search orders") + + def test_search_invoice_ids(self): + """Test searching on computed fields invoice_ids""" + + # Make qty zero to have a line without invoices + self.sol_prod_order.product_uom_qty = 0 + self.sale_order.action_confirm() + + # Tests before creating an invoice + self._check_order_search(self.sale_order, [('invoice_ids', '=', False)], self.sale_order) + self._check_order_search(self.sale_order, [('invoice_ids', '!=', False)], self.env['sale.order']) + + # Create invoice + moves = self.sale_order._create_invoices() + + # Tests after creating the invoice + self._check_order_search(self.sale_order, [('invoice_ids', 'in', moves.ids)], self.sale_order) + self._check_order_search(self.sale_order, [('invoice_ids', '=', False)], self.env['sale.order']) + self._check_order_search(self.sale_order, [('invoice_ids', '!=', False)], self.sale_order) + def test_downpayment(self): """ Test invoice with a way of downpayment and check downpayment's SO line is created and also check a total amount of invoice is equal to a respective sale order's total amount """ # Confirm the SO self.sale_order.action_confirm() + self._check_order_search(self.sale_order, [('invoice_ids', '=', False)], self.sale_order) # Let's do an invoice for a deposit of 100 payment = self.env['sale.advance.payment.inv'].with_context(self.context).create({ 'advance_payment_method': 'fixed', @@ -79,6 +104,7 @@ class TestSaleToInvoice(TestSaleCommon): 'deposit_account_id': self.company_data['default_account_revenue'].id }) payment.create_invoices() + self._check_order_search(self.sale_order, [('invoice_ids', '=', False)], self.env['sale.order']) self.assertEqual(len(self.sale_order.invoice_ids), 1, 'Invoice should be created for the SO') downpayment_line = self.sale_order.order_line.filtered(lambda l: l.is_downpayment) @@ -161,7 +187,9 @@ class TestSaleToInvoice(TestSaleCommon): payment = self.env['sale.advance.payment.inv'].with_context(self.context).create({ 'advance_payment_method': 'delivered' }) + self._check_order_search(self.sale_order, [('invoice_ids', '=', False)], self.sale_order) payment.create_invoices() + self._check_order_search(self.sale_order, [('invoice_ids', '=', False)], self.env['sale.order']) invoice = self.sale_order.invoice_ids[0] invoice.action_post()