From 9a6145254135886449f92d231febe0b5dff63219 Mon Sep 17 00:00:00 2001 From: jguenat Date: Thu, 20 Apr 2023 17:54:25 +0200 Subject: [PATCH] [MIG] stock_picking_invoicing: Migration to 16.0 --- stock_picking_invoicing/__manifest__.py | 4 +- stock_picking_invoicing/models/stock_move.py | 39 ++-- .../models/stock_picking.py | 6 +- .../tests/test_picking_invoicing.py | 110 ++---------- stock_picking_invoicing/views/stock_move.xml | 2 + .../views/stock_picking.xml | 46 ++--- .../views/stock_picking_type.xml | 6 +- .../wizards/stock_invoice_onshipping.py | 169 ++++++++++-------- 8 files changed, 153 insertions(+), 229 deletions(-) diff --git a/stock_picking_invoicing/__manifest__.py b/stock_picking_invoicing/__manifest__.py index d620c7cdb5a..076a6c684ba 100644 --- a/stock_picking_invoicing/__manifest__.py +++ b/stock_picking_invoicing/__manifest__.py @@ -2,12 +2,12 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). { "name": "Stock Picking Invoicing", - "version": "14.0.1.0.2", + "version": "16.0.1.0.0", "category": "Warehouse Management", "author": "Agile Business Group,Odoo Community Association (OCA)", "website": "https://github.com/OCA/account-invoicing", "license": "AGPL-3", - "depends": ["stock", "account", "stock_picking_invoice_link"], + "depends": ["stock", "account", "stock_picking_invoice_link", "base_view_inheritance_extension"], "data": [ "security/ir.model.access.csv", "wizards/stock_invoice_onshipping_view.xml", diff --git a/stock_picking_invoicing/models/stock_move.py b/stock_picking_invoicing/models/stock_move.py index 384958787a6..a579ca84efe 100644 --- a/stock_picking_invoicing/models/stock_move.py +++ b/stock_picking_invoicing/models/stock_move.py @@ -11,22 +11,22 @@ class StockMove(models.Model): "stock.invoice.state.mixin", ] - def _get_taxes(self, fiscal_position, inv_type): - """ - Map product taxes based on given fiscal position - :param fiscal_position: account.fiscal.position recordset - :param inv_type: string - :return: account.tax recordset - """ - product = self.mapped("product_id") - product.ensure_one() - if inv_type in ("out_invoice", "out_refund"): - taxes = product.taxes_id - else: - taxes = product.supplier_taxes_id - company_id = self.env.context.get("force_company", self.env.company.id) - my_taxes = taxes.filtered(lambda r: r.company_id.id == company_id) - return fiscal_position.map_tax(my_taxes) + # def _get_taxes(self, fiscal_position, inv_type): + # """ + # Map product taxes based on given fiscal position + # :param fiscal_position: account.fiscal.position recordset + # :param inv_type: string + # :return: account.tax recordset + # """ + # product = self.mapped("product_id") + # product.ensure_one() + # if inv_type in ("out_invoice", "out_refund"): + # taxes = product.taxes_id + # else: + # taxes = product.supplier_taxes_id + # company_id = self.env.context.get("force_company", self.env.company.id) + # my_taxes = taxes.filtered(lambda r: r.company_id.id == company_id) + # return fiscal_position.map_tax(my_taxes) @api.model def _get_account(self, fiscal_position, account): @@ -49,9 +49,10 @@ def _get_price_unit_invoice(self, inv_type, partner, qty=1): product = self.mapped("product_id") product.ensure_one() if inv_type in ("in_invoice", "in_refund"): - result = product.price + # TODO get supplier price + result = product.standard_price else: - # If partner given, search price in its sale pricelist + # TODO refactor If partner given, search price in its sale pricelist if partner and partner.property_product_pricelist: product = product.with_context( partner=partner.id, @@ -59,7 +60,7 @@ def _get_price_unit_invoice(self, inv_type, partner, qty=1): pricelist=partner.property_product_pricelist.id, uom=fields.first(self).product_uom.id, ) - result = product.price + result = product.lst_price else: result = product.lst_price return result diff --git a/stock_picking_invoicing/models/stock_picking.py b/stock_picking_invoicing/models/stock_picking.py index 9f6ff29a4a9..3745a574bc7 100644 --- a/stock_picking_invoicing/models/stock_picking.py +++ b/stock_picking_invoicing/models/stock_picking.py @@ -24,7 +24,7 @@ def _set_as_2binvoiced(self): Inherit to also update related moves. :return: bool """ - self.mapped("move_lines")._set_as_2binvoiced() + self.mapped("move_ids")._set_as_2binvoiced() return super()._set_as_2binvoiced() def _set_as_invoiced(self): @@ -32,7 +32,7 @@ def _set_as_invoiced(self): Inherit to also update related moves. :return: bool """ - self.mapped("move_lines")._set_as_invoiced() + self.mapped("move_ids")._set_as_invoiced() return super()._set_as_invoiced() def _get_partner_to_invoice(self): @@ -42,6 +42,6 @@ def _get_partner_to_invoice(self): def action_assign(self): """If any stock move is to be invoiced, picking status is updated""" - if any(m.invoice_state == "2binvoiced" for m in self.mapped("move_lines")): + if any(m.invoice_state == "2binvoiced" for m in self.mapped("move_ids")): self.write({"invoice_state": "2binvoiced"}) return super().action_assign() diff --git a/stock_picking_invoicing/tests/test_picking_invoicing.py b/stock_picking_invoicing/tests/test_picking_invoicing.py index 8e8bde56990..afba2e209ce 100644 --- a/stock_picking_invoicing/tests/test_picking_invoicing.py +++ b/stock_picking_invoicing/tests/test_picking_invoicing.py @@ -2,11 +2,11 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from odoo import exceptions -from odoo.tests import Form, SavepointCase, tagged +from odoo.tests import Form, TransactionCase, tagged @tagged("post_install", "-at_install") -class TestPickingInvoicing(SavepointCase): +class TestPickingInvoicing(TransactionCase): @classmethod def setUpClass(cls): super().setUpClass() @@ -38,22 +38,11 @@ def setUpClass(cls): cls.fiscal_position_model = cls.env["account.fiscal.position"] cls.fiscal_position_tax_model = cls.env["account.fiscal.position.tax"] cls.fiscal_position_account_model = cls.env["account.fiscal.position.account"] - cls.account_user_type = cls.env.ref("account.data_account_type_revenue") cls.account_model = cls.env["account.account"] cls.tax_model = cls.env["account.tax"] cls.product_tmpl_model = cls.env["product.template"] - cls.account_receivable = cls.env["account.account"].search( - [ - ( - "user_type_id", - "=", - cls.env.ref("account.data_account_type_receivable").id, - ) - ], - limit=1, - ) cls.account_revenue = cls.env["account.account"].search( - [("user_type_id", "=", cls.account_user_type.id)], limit=1 + [("account_type", "=", "income")], limit=1 ) cls.tax_sale_1 = cls.tax_model.create( @@ -116,7 +105,6 @@ def test_0_picking_out_invoicing(self): "product_uom": self.product_test_1.uom_id.id, } new_move = self.move_model.create(move_vals) - new_move.onchange_product_id() picking.set_to_be_invoiced() picking.action_confirm() # Check product availability @@ -174,8 +162,7 @@ def test_1_picking_out_invoicing(self): "product_uom_qty": 2, "product_uom": self.product_test_1.uom_id.id, } - new_move = self.move_model.create(move_vals) - new_move.onchange_product_id() + self.move_model.create(move_vals) picking.action_confirm() # Check product availability picking.action_assign() @@ -221,7 +208,6 @@ def test_2_picking_out_invoicing(self): "product_uom": self.product_test_1.uom_id.id, } new_move = self.move_model.create(move_vals) - new_move.onchange_product_id() picking.set_to_be_invoiced() picking.action_confirm() # Check product availability @@ -285,7 +271,6 @@ def test_3_picking_out_invoicing(self): "product_uom": self.product_test_1.uom_id.id, } new_move = self.move_model.create(move_vals) - new_move.onchange_product_id() picking.set_to_be_invoiced() picking.action_confirm() # Check product availability @@ -351,7 +336,6 @@ def test_4_picking_out_invoicing_backorder(self): "product_uom": self.product_test_1.uom_id.id, } new_move = self.move_model.create(move_vals) - new_move.onchange_product_id() picking.set_to_be_invoiced() picking.action_confirm() # Check product availability @@ -426,8 +410,7 @@ def test_picking_cancel(self): "product_uom_qty": 2, "product_uom": self.product_test_1.uom_id.id, } - new_move = self.move_model.create(move_vals) - new_move.onchange_product_id() + self.move_model.create(move_vals) picking.set_to_be_invoiced() picking.action_confirm() # Check product availability @@ -461,65 +444,6 @@ def test_picking_cancel(self): nb_invoice_after = self.invoice_model.search_count([]) self.assertEqual(nb_invoice_before, nb_invoice_after - len(invoice)) - def test_picking_invoice_refund(self): - """ - Ensure that a refund keep the link to the picking - :return: - """ - nb_invoice_before = self.invoice_model.search_count([]) - self.partner.write({"type": "invoice"}) - picking = self.picking_model.create( - { - "partner_id": self.partner2.id, - "picking_type_id": self.pick_type_out.id, - "location_id": self.stock_location.id, - "location_dest_id": self.customers_location.id, - } - ) - move_vals = { - "product_id": self.product_test_1.id, - "picking_id": picking.id, - "location_dest_id": self.customers_location.id, - "location_id": self.stock_location.id, - "name": self.product_test_1.name, - "product_uom_qty": 2, - "product_uom": self.product_test_1.uom_id.id, - } - new_move = self.move_model.create(move_vals) - new_move.onchange_product_id() - picking.set_to_be_invoiced() - picking.action_confirm() - # Check product availability - picking.action_assign() - # Force product availability - for move in picking.move_ids_without_package: - move.quantity_done = move.product_uom_qty - picking.button_validate() - self.assertEqual(picking.state, "done") - wizard_obj = self.invoice_wizard.with_context( - active_ids=picking.ids, - active_model=picking._name, - active_id=picking.id, - ) - fields_list = wizard_obj.fields_get().keys() - wizard_values = wizard_obj.default_get(fields_list) - wizard_values.update({"group": "partner"}) - wizard = wizard_obj.create(wizard_values) - wizard.onchange_group() - wizard.action_generate() - domain = [("picking_ids", "=", picking.id)] - invoice = self.invoice_model.search(domain) - self.assertEqual(picking.invoice_state, "invoiced") - self.assertEqual(invoice.partner_id, self.partner) - self.assertIn(invoice, picking.invoice_ids) - self.assertIn(picking, invoice.picking_ids) - invoice.action_post() - refund = invoice._reverse_moves(cancel=True) - self.assertEqual(picking.invoice_state, "invoiced") - self.assertIn(picking, refund.picking_ids) - nb_invoice_after = self.invoice_model.search_count([]) - self.assertEqual(nb_invoice_before, nb_invoice_after - len(invoice | refund)) - def test_picking_invoicing_by_product1(self): """ Test the invoice generation grouped by partner/product with 1 @@ -545,7 +469,7 @@ def test_picking_invoicing_by_product1(self): "product_uom_qty": 1, "product_uom": self.product_test_1.uom_id.id, } - new_move = self.move_model.create(move_vals) + self.move_model.create(move_vals) move_vals2 = { "product_id": self.product_test_2.id, "picking_id": picking.id, @@ -555,9 +479,7 @@ def test_picking_invoicing_by_product1(self): "product_uom_qty": 1, "product_uom": self.product_test_2.uom_id.id, } - new_move2 = self.move_model.create(move_vals2) - new_move.onchange_product_id() - new_move2.onchange_product_id() + self.move_model.create(move_vals2) picking.set_to_be_invoiced() picking.action_confirm() # Check product availability @@ -619,7 +541,7 @@ def test_picking_invoicing_by_product2(self): "product_uom_qty": 1, "product_uom": self.product_test_1.uom_id.id, } - new_move = self.move_model.create(move_vals) + self.move_model.create(move_vals) picking2 = picking.copy() move_vals2 = { "product_id": self.product_test_1.id, @@ -630,9 +552,7 @@ def test_picking_invoicing_by_product2(self): "product_uom_qty": 1, "product_uom": self.product_test_1.uom_id.id, } - new_move2 = self.move_model.create(move_vals2) - new_move.onchange_product_id() - new_move2.onchange_product_id() + self.move_model.create(move_vals2) picking.set_to_be_invoiced() picking.action_confirm() # Check product availability @@ -714,7 +634,7 @@ def test_picking_invoicing_by_product3(self): "product_uom_qty": 1, "product_uom": self.product_test_1.uom_id.id, } - new_move = self.move_model.create(move_vals) + self.move_model.create(move_vals) picking2 = picking.copy({"partner_id": self.partner3.id}) move_vals2 = { "product_id": self.product_test_2.id, @@ -725,9 +645,7 @@ def test_picking_invoicing_by_product3(self): "product_uom_qty": 1, "product_uom": self.product_test_2.uom_id.id, } - new_move2 = self.move_model.create(move_vals2) - new_move.onchange_product_id() - new_move2.onchange_product_id() + self.move_model.create(move_vals2) picking.set_to_be_invoiced() picking.action_confirm() # Check product availability @@ -834,7 +752,7 @@ def test_return_customer_picking(self): ) self.assertEqual(picking_devolution.invoice_state, "2binvoiced") - for line in picking_devolution.move_lines: + for line in picking_devolution.move_ids: self.assertEqual(line.invoice_state, "2binvoiced") picking_devolution.action_confirm() @@ -872,6 +790,8 @@ def test_return_supplier_picking(self): """ Test Return Supplier Picking and Invoice created. """ + grp_multi_loc = self.env.ref('stock.group_stock_multi_locations') + self.env.user.write({'groups_id': [(4, grp_multi_loc.id, 0)]}) picking = self.env.ref("stock_picking_invoicing.stock_picking_invoicing_7") # Force product availability for move in picking.move_ids_without_package: @@ -912,7 +832,7 @@ def test_return_supplier_picking(self): ) self.assertEqual(picking_devolution.invoice_state, "2binvoiced") - for line in picking_devolution.move_lines: + for line in picking_devolution.move_ids: self.assertEqual(line.invoice_state, "2binvoiced") picking_devolution.action_confirm() diff --git a/stock_picking_invoicing/views/stock_move.xml b/stock_picking_invoicing/views/stock_move.xml index 26c7a1241ff..50ab801dcd4 100644 --- a/stock_picking_invoicing/views/stock_move.xml +++ b/stock_picking_invoicing/views/stock_move.xml @@ -7,6 +7,7 @@ + + stock.picking.form.inherit stock.picking - - + - - - - - - - - - - - - - - - - + + + + + + + + + + + + - - {'default_invoice_state': invoice_state, - 'address_in_id': partner_id, - 'form_view_ref':'stock.view_move_picking_form', - 'tree_view_ref':'stock.view_move_picking_tree', - 'default_picking_type_id': picking_type_id, - 'default_picking_id': id, - 'default_location_id': location_id, - 'default_location_dest_id': location_dest_id} + + { + 'default_invoice_state': invoice_state, + } +
- diff --git a/stock_picking_invoicing/wizards/stock_invoice_onshipping.py b/stock_picking_invoicing/wizards/stock_invoice_onshipping.py index 2387cd26a7b..8e4f6525886 100644 --- a/stock_picking_invoicing/wizards/stock_invoice_onshipping.py +++ b/stock_picking_invoicing/wizards/stock_invoice_onshipping.py @@ -36,10 +36,10 @@ def _get_journal_type(self): active_ids = active_ids[0] pick_obj = self.env["stock.picking"] picking = pick_obj.browse(active_ids) - if not picking or not picking.move_lines: + if not picking or not picking.move_ids: return "sale" pick_type_code = picking.picking_type_id.code - line = fields.first(picking.move_lines) + line = fields.first(picking.move_ids) if pick_type_code == "incoming": usage = line.location_id.usage else: @@ -111,7 +111,7 @@ def get_partner_sum(self, pickings, partner, inv_type, picking_type, usage): pickings = pickings.filtered( lambda x: x.picking_type_id.code == picking_type and x.partner_id == partner ) - lines = pickings.mapped("move_lines") + lines = pickings.mapped("move_ids") if picking_type == "outgoing": moves = lines.filtered(lambda x: x.location_dest_id.usage == usage) else: @@ -174,19 +174,19 @@ def get_split_pickings_nogrouped(self, pickings): first = fields.first sale_pickings = pickings.filtered( lambda x: x.picking_type_id.code == "outgoing" - and first(x.move_lines).location_dest_id.usage == "customer" + and first(x.move_ids).location_dest_id.usage == "customer" ) sale_refund_pickings = pickings.filtered( lambda x: x.picking_type_id.code == "incoming" - and first(x.move_lines).location_id.usage == "customer" + and first(x.move_ids).location_id.usage == "customer" ) purchase_pickings = pickings.filtered( lambda x: x.picking_type_id.code == "incoming" - and first(x.move_lines).location_id.usage == "supplier" + and first(x.move_ids).location_id.usage == "supplier" ) purchase_refund_pickings = pickings.filtered( lambda x: x.picking_type_id.code == "outgoing" - and first(x.move_lines).location_dest_id.usage == "supplier" + and first(x.move_ids).location_dest_id.usage == "supplier" ) return ( @@ -355,10 +355,10 @@ def _build_invoice_values_from_pickings(self, pickings): partner_id = picking._get_partner_to_invoice() partner = self.env["res.partner"].browse(partner_id) inv_type = self._get_invoice_type() - if inv_type in ("out_invoice", "out_refund"): - payment_term = partner.property_payment_term_id.id - else: - payment_term = partner.property_supplier_payment_term_id.id + # if inv_type in ("out_invoice", "out_refund"): + # payment_term = partner.property_payment_term_id.id + # else: + # payment_term = partner.property_supplier_payment_term_id.id company = self.env.company currency = company.currency_id if partner: @@ -366,25 +366,38 @@ def _build_invoice_values_from_pickings(self, pickings): if partner.property_product_pricelist and code == "outgoing": currency = partner.property_product_pricelist.currency_id journal = self._get_journal() - invoice_obj = self.env["account.move"] - values = invoice_obj.default_get(invoice_obj.fields_get().keys()) - values.update( - { - "invoice_origin": ", ".join(pickings.mapped("name")), - "user_id": self.env.user.id, - "partner_id": partner_id, - "invoice_payment_term_id": payment_term, - "move_type": inv_type, - "fiscal_position_id": partner.property_account_position_id.id, - "company_id": company.id, - "currency_id": currency.id, - "journal_id": journal.id, - "picking_ids": [(4, p.id, False) for p in pickings], - } - ) - - invoice, values = self._simulate_invoice_onchange(values) - return invoice, values + # invoice_obj = self.env["account.move"] + # values = invoice_obj.default_get(invoice_obj.fields_get().keys()) + # values.update( + # { + # "invoice_origin": ", ".join(pickings.mapped("name")), + # "user_id": self.env.user.id, + # "partner_id": partner_id, + # # "invoice_payment_term_id": payment_term, + # "move_type": inv_type, + # # "fiscal_position_id": partner.property_account_position_id.id, + # "company_id": company.id, + # "currency_id": currency.id, + # "journal_id": journal.id, + # "picking_ids": [(4, p.id, False) for p in pickings], + # } + # ) + values = { + "invoice_origin": ", ".join(pickings.mapped("name")), + "user_id": self.env.user.id, + "partner_id": partner_id, + # "invoice_payment_term_id": payment_term, + "move_type": inv_type, + # "fiscal_position_id": partner.property_account_position_id.id, + "company_id": company.id, + "currency_id": currency.id, + "journal_id": journal.id, + "picking_ids": [(4, p.id, False) for p in pickings], + } + + # invoice, values = self._simulate_invoice_onchange(values) + # return invoice, values + return values def _get_move_key(self, move): """ @@ -412,22 +425,23 @@ def _group_moves(self, moves): grouped_moves.update({key: move_grouped}) return grouped_moves.values() - def _simulate_invoice_line_onchange(self, values, price_unit=None): - """ - Simulate onchange for invoice line - :param values: dict - :return: dict - """ - line = self.env["account.move.line"].new(values.copy()) - line._onchange_product_id() - new_values = line._convert_to_write(line._cache) - if price_unit: - new_values["price_unit"] = price_unit - # Ensure basic values are not updated - values.update(new_values) - return values - - def _get_invoice_line_values(self, moves, invoice_values, invoice): + # def _simulate_invoice_line_onchange(self, values, price_unit=None): + # """ + # Simulate onchange for invoice line + # :param values: dict + # :return: dict + # """ + # line = self.env["account.move.line"].new(values.copy()) + # # TODO : investigate + # # line._onchange_product_id() + # new_values = line._convert_to_write(line._cache) + # if price_unit: + # new_values["price_unit"] = price_unit + # # Ensure basic values are not updated + # values.update(new_values) + # return values + + def _get_invoice_line_values(self, moves, invoice_values): """ Create invoice line values from given moves :param moves: stock.move @@ -437,21 +451,21 @@ def _get_invoice_line_values(self, moves, invoice_values, invoice): name = ", ".join(moves.mapped("name")) move = fields.first(moves) product = move.product_id - fiscal_position = self.env["account.fiscal.position"].browse( - invoice_values["fiscal_position_id"] - ) - partner_id = self.env["res.partner"].browse(invoice_values["partner_id"]) - categ = product.categ_id + # fiscal_position = self.env["account.fiscal.position"].browse( + # invoice_values["fiscal_position_id"] + # ) + # partner_id = self.env["res.partner"].browse(invoice_values["partner_id"]) + # categ = product.categ_id inv_type = invoice_values["move_type"] - if inv_type in ("out_invoice", "out_refund"): - account = product.property_account_income_id - if not account: - account = categ.property_account_income_categ_id - else: - account = product.property_account_expense_id - if not account: - account = categ.property_account_expense_categ_id - account = move._get_account(fiscal_position, account) + # if inv_type in ("out_invoice", "out_refund"): + # account = product.property_account_income_id + # if not account: + # account = categ.property_account_income_categ_id + # else: + # account = product.property_account_expense_id + # if not account: + # account = categ.property_account_expense_categ_id + # account = move._get_account(fiscal_position, account) quantity = 0 move_line_ids = [] for move in moves: @@ -469,25 +483,25 @@ def _get_invoice_line_values(self, moves, invoice_values, invoice): qty *= -1 quantity += qty move_line_ids.append((4, move.id, False)) - taxes = moves._get_taxes(fiscal_position, inv_type) - price = moves._get_price_unit_invoice(inv_type, partner_id, quantity) + # taxes = moves._get_taxes(fiscal_position, inv_type) + # price = moves._get_price_unit_invoice(inv_type, partner_id, quantity) line_obj = self.env["account.move.line"] values = line_obj.default_get(line_obj.fields_get().keys()) values.update( { "name": name, - "account_id": account.id, + # "account_id": account.id, "product_id": product.id, - "product_uom_id": product.uom_id.id, + # "product_uom_id": product.uom_id.id, "quantity": quantity, - "price_unit": price, - "tax_ids": [(6, 0, taxes.ids)], + # "price_unit": price, + # "tax_ids": [(6, 0, taxes.ids)], "move_line_ids": move_line_ids, - "move_id": invoice.id, + # "move_id": invoice.id, } ) - values = self._simulate_invoice_line_onchange(values, price_unit=price) - values.update({"name": name}) + # values = self._simulate_invoice_line_onchange(values, price_unit=price) + # values.update({"name": name}) return values def _update_picking_invoice_status(self, pickings): @@ -526,30 +540,29 @@ def _action_generate_invoices(self): pick_list = self._group_pickings(pickings) invoices = self.env["account.move"].browse() for pickings in pick_list: - moves = pickings.mapped("move_lines") + moves = pickings.mapped("move_ids") grouped_moves_list = self._group_moves(moves) parts = self.ungroup_moves(grouped_moves_list) for moves_list in parts: - invoice, invoice_values = self._build_invoice_values_from_pickings( + # invoice, invoice_values = self._build_invoice_values_from_pickings( + # pickings + # ) + invoice_values = self._build_invoice_values_from_pickings( pickings ) lines = [(5, 0, {})] line_values = False for moves in moves_list: line_values = self._get_invoice_line_values( - moves, invoice_values, invoice + moves, invoice_values ) if line_values: lines.append((0, 0, line_values)) if line_values: # Only create the invoice if it has lines invoice_values["invoice_line_ids"] = lines invoice_values["invoice_date"] = self.invoice_date - # this is needed otherwise invoice_line_ids are removed - # in _move_autocomplete_invoice_lines_create - # and no invoice line is created - invoice_values.pop("line_ids") invoice = self._create_invoice(invoice_values) - invoice._onchange_invoice_line_ids() - invoice._compute_amount() + # invoice._compute_amount() invoices |= invoice + invoices.filtered(lambda m: m.amount_total < 0).action_switch_invoice_into_refund_credit_note() return invoices