diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index 190deeedc53..a9f35b6a604 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -2074,10 +2074,10 @@ class AccountMove(models.Model): ''' self.ensure_one() - for line in self.line_ids: - # Do something only on invoice lines. - if line.exclude_from_invoice_tab: - continue + invoice_lines = self.line_ids.filtered(lambda x: not x.exclude_from_invoice_tab and not x.display_type and not x._origin) + cached_vals_list = [dict(x._cache) for x in invoice_lines] + + for cached_vals, line in zip(cached_vals_list, invoice_lines): # Shortcut to load the demo data. # Doing line.account_id triggers a default_get(['account_id']) that could returns a result. @@ -2096,10 +2096,15 @@ class AccountMove(models.Model): # Ensure related fields are well copied. if line.partner_id != self.partner_id.commercial_partner_id: line.partner_id = self.partner_id.commercial_partner_id + line.date = self.date line.recompute_tax_line = True line.currency_id = self.currency_id + for k, v in cached_vals.items(): + field = line._fields[k] + if field.compute and not field.readonly: + line[k] = v self.line_ids._onchange_price_subtotal() self._recompute_dynamic_lines(recompute_all_taxes=True) @@ -2174,7 +2179,12 @@ class AccountMove(models.Model): vals['line_ids'] = vals.pop('invoice_line_ids') for invoice in self: - invoice_new = invoice.with_context(default_move_type=invoice.move_type, default_journal_id=invoice.journal_id.id).new(origin=invoice) + invoice_new = invoice.with_context( + default_move_type=invoice.move_type, + default_journal_id=invoice.journal_id.id, + default_partner_id=invoice.partner_id.id, + default_currency_id=invoice.currency_id.id, + ).new(origin=invoice) invoice_new.update(vals) values = invoice_new._move_autocomplete_invoice_lines_values() values.pop('invoice_line_ids', None) diff --git a/addons/account/tests/test_account_move_in_invoice.py b/addons/account/tests/test_account_move_in_invoice.py index a7d1da55164..a624c44c7d3 100644 --- a/addons/account/tests/test_account_move_in_invoice.py +++ b/addons/account/tests/test_account_move_in_invoice.py @@ -4,7 +4,7 @@ from freezegun import freeze_time from odoo.addons.account.tests.common import AccountTestInvoicingCommon from odoo.tests.common import Form from odoo.tests import tagged -from odoo import fields +from odoo import fields, Command from odoo.exceptions import UserError, ValidationError @@ -1396,9 +1396,19 @@ class TestAccountMoveInInvoiceOnchanges(AccountTestInvoicingCommon): 'currency_id': self.currency_data['currency'].id, 'invoice_payment_term_id': self.pay_terms_a.id, 'invoice_line_ids': [ - (0, None, self.product_line_vals_1), - (0, None, self.product_line_vals_2), - ] + Command.create({ + 'product_id': self.product_line_vals_1['product_id'], + 'product_uom_id': self.product_line_vals_1['product_uom_id'], + 'price_unit': self.product_line_vals_1['price_unit'], + 'tax_ids': [Command.set(self.product_line_vals_1['tax_ids'])], + }), + Command.create({ + 'product_id': self.product_line_vals_2['product_id'], + 'product_uom_id': self.product_line_vals_2['product_uom_id'], + 'price_unit': self.product_line_vals_2['price_unit'], + 'tax_ids': [Command.set(self.product_line_vals_2['tax_ids'])], + }), + ], }) self.assertInvoiceValues(move, [ @@ -1446,13 +1456,23 @@ class TestAccountMoveInInvoiceOnchanges(AccountTestInvoicingCommon): 'currency_id': self.currency_data['currency'].id, 'invoice_payment_term_id': self.pay_terms_a.id, 'invoice_line_ids': [ - (0, None, self.product_line_vals_1), - ] + Command.create({ + 'product_id': self.product_line_vals_1['product_id'], + 'product_uom_id': self.product_line_vals_1['product_uom_id'], + 'price_unit': self.product_line_vals_1['price_unit'], + 'tax_ids': [Command.set(self.product_line_vals_1['tax_ids'])], + }), + ], }) move.write({ 'invoice_line_ids': [ - (0, None, self.product_line_vals_2), - ] + Command.create({ + 'product_id': self.product_line_vals_2['product_id'], + 'product_uom_id': self.product_line_vals_2['product_uom_id'], + 'price_unit': self.product_line_vals_2['price_unit'], + 'tax_ids': [Command.set(self.product_line_vals_2['tax_ids'])], + }), + ], }) self.assertInvoiceValues(move, [ @@ -1508,9 +1528,19 @@ class TestAccountMoveInInvoiceOnchanges(AccountTestInvoicingCommon): 'currency_id': self.currency_data['currency'].id, 'invoice_payment_term_id': self.pay_terms_a.id, 'invoice_line_ids': [ - (0, None, self.product_line_vals_1), - (0, None, self.product_line_vals_2), - ] + Command.create({ + 'product_id': self.product_line_vals_1['product_id'], + 'product_uom_id': self.product_line_vals_1['product_uom_id'], + 'price_unit': self.product_line_vals_1['price_unit'], + 'tax_ids': [Command.set(self.product_line_vals_1['tax_ids'])], + }), + Command.create({ + 'product_id': self.product_line_vals_2['product_id'], + 'product_uom_id': self.product_line_vals_2['product_uom_id'], + 'price_unit': self.product_line_vals_2['price_unit'], + 'tax_ids': [Command.set(self.product_line_vals_2['tax_ids'])], + }), + ], }) move.action_switch_invoice_into_refund_credit_note() @@ -1558,10 +1588,6 @@ class TestAccountMoveInInvoiceOnchanges(AccountTestInvoicingCommon): def test_in_invoice_switch_in_refund_2(self): # Test creating an account_move with an in_invoice_type and switch it in an in_refund and a negative quantity. - modified_product_line_vals_1 = self.product_line_vals_1.copy() - modified_product_line_vals_1.update({'quantity': -modified_product_line_vals_1['quantity']}) - modified_product_line_vals_2 = self.product_line_vals_2.copy() - modified_product_line_vals_2.update({'quantity': -modified_product_line_vals_2['quantity']}) move = self.env['account.move'].create({ 'move_type': 'in_invoice', 'partner_id': self.partner_a.id, @@ -1569,9 +1595,21 @@ class TestAccountMoveInInvoiceOnchanges(AccountTestInvoicingCommon): 'currency_id': self.currency_data['currency'].id, 'invoice_payment_term_id': self.pay_terms_a.id, 'invoice_line_ids': [ - (0, None, modified_product_line_vals_1), - (0, None, modified_product_line_vals_2), - ] + Command.create({ + 'product_id': self.product_line_vals_1['product_id'], + 'product_uom_id': self.product_line_vals_1['product_uom_id'], + 'price_unit': self.product_line_vals_1['price_unit'], + 'quantity': -self.product_line_vals_1['quantity'], + 'tax_ids': [Command.set(self.product_line_vals_1['tax_ids'])], + }), + Command.create({ + 'product_id': self.product_line_vals_2['product_id'], + 'product_uom_id': self.product_line_vals_2['product_uom_id'], + 'price_unit': self.product_line_vals_2['price_unit'], + 'quantity': -self.product_line_vals_2['quantity'], + 'tax_ids': [Command.set(self.product_line_vals_2['tax_ids'])], + }), + ], }) self.assertInvoiceValues(move, [ diff --git a/addons/account/tests/test_account_move_in_refund.py b/addons/account/tests/test_account_move_in_refund.py index 5897c5e32b1..54a498bc412 100644 --- a/addons/account/tests/test_account_move_in_refund.py +++ b/addons/account/tests/test_account_move_in_refund.py @@ -3,7 +3,7 @@ from odoo.addons.account.tests.common import AccountTestInvoicingCommon from odoo.tests.common import Form from odoo.tests import tagged -from odoo import fields +from odoo import fields, Command @tagged('post_install', '-at_install') @@ -844,9 +844,19 @@ class TestAccountMoveInRefundOnchanges(AccountTestInvoicingCommon): 'currency_id': self.currency_data['currency'].id, 'invoice_payment_term_id': self.pay_terms_a.id, 'invoice_line_ids': [ - (0, None, self.product_line_vals_1), - (0, None, self.product_line_vals_2), - ] + Command.create({ + 'product_id': self.product_line_vals_1['product_id'], + 'product_uom_id': self.product_line_vals_1['product_uom_id'], + 'price_unit': self.product_line_vals_1['price_unit'], + 'tax_ids': [Command.set(self.product_line_vals_1['tax_ids'])], + }), + Command.create({ + 'product_id': self.product_line_vals_2['product_id'], + 'product_uom_id': self.product_line_vals_2['product_uom_id'], + 'price_unit': self.product_line_vals_2['price_unit'], + 'tax_ids': [Command.set(self.product_line_vals_2['tax_ids'])], + }), + ], }) self.assertInvoiceValues(move, [ @@ -894,13 +904,23 @@ class TestAccountMoveInRefundOnchanges(AccountTestInvoicingCommon): 'currency_id': self.currency_data['currency'].id, 'invoice_payment_term_id': self.pay_terms_a.id, 'invoice_line_ids': [ - (0, None, self.product_line_vals_1), - ] + Command.create({ + 'product_id': self.product_line_vals_1['product_id'], + 'product_uom_id': self.product_line_vals_1['product_uom_id'], + 'price_unit': self.product_line_vals_1['price_unit'], + 'tax_ids': [Command.set(self.product_line_vals_1['tax_ids'])], + }), + ], }) move.write({ 'invoice_line_ids': [ - (0, None, self.product_line_vals_2), - ] + Command.create({ + 'product_id': self.product_line_vals_2['product_id'], + 'product_uom_id': self.product_line_vals_2['product_uom_id'], + 'price_unit': self.product_line_vals_2['price_unit'], + 'tax_ids': [Command.set(self.product_line_vals_2['tax_ids'])], + }), + ], }) self.assertInvoiceValues(move, [ diff --git a/addons/account/tests/test_account_move_out_invoice.py b/addons/account/tests/test_account_move_out_invoice.py index 6eddf8055ef..7af8ef5af2e 100644 --- a/addons/account/tests/test_account_move_out_invoice.py +++ b/addons/account/tests/test_account_move_out_invoice.py @@ -3,7 +3,7 @@ from odoo.addons.account.tests.common import AccountTestInvoicingCommon from odoo.tests.common import Form from odoo.tests import tagged -from odoo import fields +from odoo import fields, Command from odoo.exceptions import UserError from unittest.mock import patch @@ -2066,9 +2066,19 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon): 'currency_id': self.currency_data['currency'].id, 'invoice_payment_term_id': self.pay_terms_a.id, 'invoice_line_ids': [ - (0, None, self.product_line_vals_1), - (0, None, self.product_line_vals_2), - ] + Command.create({ + 'product_id': self.product_line_vals_1['product_id'], + 'product_uom_id': self.product_line_vals_1['product_uom_id'], + 'price_unit': self.product_line_vals_1['price_unit'], + 'tax_ids': [Command.set(self.product_line_vals_1['tax_ids'])], + }), + Command.create({ + 'product_id': self.product_line_vals_2['product_id'], + 'product_uom_id': self.product_line_vals_2['product_uom_id'], + 'price_unit': self.product_line_vals_2['price_unit'], + 'tax_ids': [Command.set(self.product_line_vals_2['tax_ids'])], + }), + ], }) self.assertEqual(partner_a_child.id, move.partner_id.id, 'Keep child partner on the account move record') @@ -2083,13 +2093,23 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon): 'currency_id': self.currency_data['currency'].id, 'invoice_payment_term_id': self.pay_terms_a.id, 'invoice_line_ids': [ - (0, None, self.product_line_vals_1), - ] + Command.create({ + 'product_id': self.product_line_vals_1['product_id'], + 'product_uom_id': self.product_line_vals_1['product_uom_id'], + 'price_unit': self.product_line_vals_1['price_unit'], + 'tax_ids': [Command.set(self.product_line_vals_1['tax_ids'])], + }), + ], }) move.write({ 'invoice_line_ids': [ - (0, None, self.product_line_vals_2), - ] + Command.create({ + 'product_id': self.product_line_vals_2['product_id'], + 'product_uom_id': self.product_line_vals_2['product_uom_id'], + 'price_unit': self.product_line_vals_2['price_unit'], + 'tax_ids': [Command.set(self.product_line_vals_2['tax_ids'])], + }), + ], }) self.assertInvoiceValues(move, [ @@ -2168,9 +2188,19 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon): 'currency_id': self.currency_data['currency'].id, 'invoice_payment_term_id': self.pay_terms_a.id, 'invoice_line_ids': [ - (0, None, self.product_line_vals_1), - (0, None, self.product_line_vals_2), - ] + Command.create({ + 'product_id': self.product_line_vals_1['product_id'], + 'product_uom_id': self.product_line_vals_1['product_uom_id'], + 'price_unit': self.product_line_vals_1['price_unit'], + 'tax_ids': [Command.set(self.product_line_vals_1['tax_ids'])], + }), + Command.create({ + 'product_id': self.product_line_vals_2['product_id'], + 'product_uom_id': self.product_line_vals_2['product_uom_id'], + 'price_unit': self.product_line_vals_2['price_unit'], + 'tax_ids': [Command.set(self.product_line_vals_2['tax_ids'])], + }), + ], }) # Remove the invoice_date to check: @@ -2359,9 +2389,19 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon): 'currency_id': self.currency_data['currency'].id, 'invoice_payment_term_id': self.pay_terms_a.id, 'invoice_line_ids': [ - (0, None, self.product_line_vals_1), - (0, None, self.product_line_vals_2), - ] + Command.create({ + 'product_id': self.product_line_vals_1['product_id'], + 'product_uom_id': self.product_line_vals_1['product_uom_id'], + 'price_unit': self.product_line_vals_1['price_unit'], + 'tax_ids': [Command.set(self.product_line_vals_1['tax_ids'])], + }), + Command.create({ + 'product_id': self.product_line_vals_2['product_id'], + 'product_uom_id': self.product_line_vals_2['product_uom_id'], + 'price_unit': self.product_line_vals_2['price_unit'], + 'tax_ids': [Command.set(self.product_line_vals_2['tax_ids'])], + }), + ], }) move.action_switch_invoice_into_refund_credit_note() @@ -2409,10 +2449,6 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon): def test_out_invoice_switch_out_refund_2(self): # Test creating an account_move with an out_invoice_type and switch it in an out_refund and a negative quantity. - modified_product_line_vals_1 = self.product_line_vals_1.copy() - modified_product_line_vals_1.update({'quantity': -modified_product_line_vals_1['quantity']}) - modified_product_line_vals_2 = self.product_line_vals_2.copy() - modified_product_line_vals_2.update({'quantity': -modified_product_line_vals_2['quantity']}) move = self.env['account.move'].create({ 'move_type': 'out_invoice', 'partner_id': self.partner_a.id, @@ -2420,9 +2456,21 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon): 'currency_id': self.currency_data['currency'].id, 'invoice_payment_term_id': self.pay_terms_a.id, 'invoice_line_ids': [ - (0, None, modified_product_line_vals_1), - (0, None, modified_product_line_vals_2), - ] + Command.create({ + 'product_id': self.product_line_vals_1['product_id'], + 'product_uom_id': self.product_line_vals_1['product_uom_id'], + 'price_unit': self.product_line_vals_1['price_unit'], + 'quantity': -self.product_line_vals_1['quantity'], + 'tax_ids': [Command.set(self.product_line_vals_1['tax_ids'])], + }), + Command.create({ + 'product_id': self.product_line_vals_2['product_id'], + 'product_uom_id': self.product_line_vals_2['product_uom_id'], + 'price_unit': self.product_line_vals_2['price_unit'], + 'quantity': -self.product_line_vals_2['quantity'], + 'tax_ids': [Command.set(self.product_line_vals_2['tax_ids'])], + }), + ], }) self.assertInvoiceValues(move, [ diff --git a/addons/account/tests/test_account_move_out_refund.py b/addons/account/tests/test_account_move_out_refund.py index 7c9aaa3eba5..29a22700428 100644 --- a/addons/account/tests/test_account_move_out_refund.py +++ b/addons/account/tests/test_account_move_out_refund.py @@ -3,7 +3,7 @@ from odoo.addons.account.tests.common import AccountTestInvoicingCommon from odoo.tests.common import Form from odoo.tests import tagged -from odoo import fields +from odoo import fields, Command @tagged('post_install', '-at_install') @@ -827,9 +827,19 @@ class TestAccountMoveOutRefundOnchanges(AccountTestInvoicingCommon): 'currency_id': self.currency_data['currency'].id, 'invoice_payment_term_id': self.pay_terms_a.id, 'invoice_line_ids': [ - (0, None, self.product_line_vals_1), - (0, None, self.product_line_vals_2), - ] + Command.create({ + 'product_id': self.product_line_vals_1['product_id'], + 'product_uom_id': self.product_line_vals_1['product_uom_id'], + 'price_unit': self.product_line_vals_1['price_unit'], + 'tax_ids': [Command.set(self.product_line_vals_1['tax_ids'])], + }), + Command.create({ + 'product_id': self.product_line_vals_2['product_id'], + 'product_uom_id': self.product_line_vals_2['product_uom_id'], + 'price_unit': self.product_line_vals_2['price_unit'], + 'tax_ids': [Command.set(self.product_line_vals_2['tax_ids'])], + }), + ], }) self.assertInvoiceValues(move, [ @@ -877,13 +887,23 @@ class TestAccountMoveOutRefundOnchanges(AccountTestInvoicingCommon): 'currency_id': self.currency_data['currency'].id, 'invoice_payment_term_id': self.pay_terms_a.id, 'invoice_line_ids': [ - (0, None, self.product_line_vals_1), - ] + Command.create({ + 'product_id': self.product_line_vals_1['product_id'], + 'product_uom_id': self.product_line_vals_1['product_uom_id'], + 'price_unit': self.product_line_vals_1['price_unit'], + 'tax_ids': [Command.set(self.product_line_vals_1['tax_ids'])], + }), + ], }) move.write({ 'invoice_line_ids': [ - (0, None, self.product_line_vals_2), - ] + Command.create({ + 'product_id': self.product_line_vals_2['product_id'], + 'product_uom_id': self.product_line_vals_2['product_uom_id'], + 'price_unit': self.product_line_vals_2['price_unit'], + 'tax_ids': [Command.set(self.product_line_vals_2['tax_ids'])], + }), + ], }) self.assertInvoiceValues(move, [ diff --git a/addons/purchase/tests/test_purchase_invoice.py b/addons/purchase/tests/test_purchase_invoice.py index 49fbf70fbb1..e3fbb8ccd39 100644 --- a/addons/purchase/tests/test_purchase_invoice.py +++ b/addons/purchase/tests/test_purchase_invoice.py @@ -299,3 +299,31 @@ class TestPurchaseToInvoice(AccountTestInvoicingCommon): move = move_form.save() self.assertEqual(move.amount_total, 0.01) + + def test_vendor_bill_analytic_account_default_change(self): + """ Tests whether, when an analytic account rule is set, and user changes manually the analytic account on + the po, it is the same that is mentioned in the bill. + """ + analytic_account_default = self.env['account.analytic.account'].create({'name': 'default'}) + analytic_account_manual = self.env['account.analytic.account'].create({'name': 'manual'}) + + self.env['account.analytic.default'].create({ + 'analytic_id': analytic_account_default.id, + 'product_id': self.product_order.id, + }) + + po_form = Form(self.env['purchase.order'].with_context(tracking_disable=True)) + po_form.partner_id = self.partner_a + with po_form.order_line.new() as po_line_form: + po_line_form.name = self.product_order.name + po_line_form.product_id = self.product_order + po_line_form.product_qty = 1.0 + po_line_form.price_unit = 10 + po_line_form.account_analytic_id = analytic_account_manual + + purchase_order = po_form.save() + purchase_order.button_confirm() + purchase_order.action_create_invoice() + + aml = self.env['account.move.line'].search([('purchase_line_id', '=', purchase_order.order_line.id)]) + self.assertRecordValues(aml, [{'analytic_account_id': analytic_account_manual.id}])