From 65aab85da00a3f5c40cf7e73f06b1ce31b516810 Mon Sep 17 00:00:00 2001 From: oco-odoo Date: Tue, 18 Jan 2022 10:08:01 +0000 Subject: [PATCH] [FIX] account: apply correct tags to move lines when using cash rounding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To reproduce: 1- Configure a 0.05 cash rounding modifying the tax amount 2- Create an invoice using this rounding, for 3€, with a 21% tax (configured with some tags related on tax repartition; a Belgian one for example). => This will create a 0.02 tax rounding move line, for a total tax amount of 0.63 + 0.02 = 0.65 3- Check the tax report => Only 0.63 appears This is wrong and leads to inconsistencies with the tax closing (which will consider 0.65 because of the tax account used), or the generic tax report (which only considers tax_line_id field, not tag_ids). The tags should be copied from the line we intend to modify the tax amounts of. OPW 2714411 closes odoo/odoo#83091 X-original-commit: e8e4b0fe3913aadb0c8e1f958b65a24543e6fd9d Signed-off-by: Laurent Smet Signed-off-by: Olivier Colson --- addons/account/models/account_move.py | 1 + .../tests/test_account_move_in_invoice.py | 68 ++++++++++++++++--- .../tests/test_account_move_in_refund.py | 68 ++++++++++++++++--- .../tests/test_account_move_out_invoice.py | 68 ++++++++++++++++--- .../tests/test_account_move_out_refund.py | 68 ++++++++++++++++--- 5 files changed, 241 insertions(+), 32 deletions(-) diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index b59e58a8d81..6035aa5d466 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -918,6 +918,7 @@ class AccountMove(models.Model): 'name': _('%s (rounding)', biggest_tax_line.name), 'account_id': biggest_tax_line.account_id.id, 'tax_repartition_line_id': biggest_tax_line.tax_repartition_line_id.id, + 'tax_tag_ids': [(6, 0, biggest_tax_line.tax_tag_ids.ids)], 'exclude_from_invoice_tab': True, }) diff --git a/addons/account/tests/test_account_move_in_invoice.py b/addons/account/tests/test_account_move_in_invoice.py index 1fc1195144e..dc4fa24c146 100644 --- a/addons/account/tests/test_account_move_in_invoice.py +++ b/addons/account/tests/test_account_move_in_invoice.py @@ -848,6 +848,7 @@ class TestAccountMoveInInvoiceOnchanges(AccountTestInvoicingCommon): }) def test_in_invoice_line_onchange_cash_rounding_1(self): + # Test 'add_invoice_line' rounding move_form = Form(self.invoice) # Add a cash rounding having 'add_invoice_line'. move_form.invoice_cash_rounding_id = self.cash_rounding_a @@ -901,12 +902,45 @@ class TestAccountMoveInInvoiceOnchanges(AccountTestInvoicingCommon): self.term_line_vals_1, ], self.move_vals) - move_form = Form(self.invoice) - # Change the cash rounding to one having 'biggest_tax'. - move_form.invoice_cash_rounding_id = self.cash_rounding_b - move_form.save() + # Test 'biggest_tax' rounding - self.assertInvoiceValues(self.invoice, [ + self.company_data['company'].country_id = self.env.ref('base.us') + + # Add a tag to product_a's default tax + tax_line_tag = self.env['account.account.tag'].create({ + 'name': "Tax tag", + 'applicability': 'taxes', + 'country_id': self.company_data['company'].country_id.id, + }) + + repartition_line = self.tax_purchase_a.invoice_repartition_line_ids.filtered(lambda x: x.repartition_type == 'tax') + repartition_line.write({'tag_ids': [(4, tax_line_tag.id, 0)]}) + + # Create the invoice + biggest_tax_invoice = self.env['account.move'].create({ + 'move_type': 'in_invoice', + 'invoice_date': '2019-01-01', + 'partner_id': self.partner_a.id, + 'invoice_cash_rounding_id': self.cash_rounding_b.id, + 'invoice_payment_term_id': self.pay_terms_a.id, + 'invoice_line_ids': [ + (0, 0, { + 'product_id': self.product_a.id, + 'price_unit': 799.99, + 'tax_ids': [(6, 0, self.product_a.supplier_taxes_id.ids)], + 'product_uom_id': self.product_a.uom_id.id, + }), + + (0, 0, { + 'product_id': self.product_b.id, + 'price_unit': self.product_b.standard_price, + 'tax_ids': [(6, 0, self.product_b.supplier_taxes_id.ids)], + 'product_uom_id': self.product_b.uom_id.id, + }), + ], + }) + + self.assertInvoiceValues(biggest_tax_invoice, [ { **self.product_line_vals_1, 'price_unit': 799.99, @@ -914,10 +948,24 @@ class TestAccountMoveInInvoiceOnchanges(AccountTestInvoicingCommon): 'price_total': 919.99, 'amount_currency': 799.99, 'debit': 799.99, + 'tax_repartition_line_id': None, + 'tax_tag_ids': [], + }, + { + **self.product_line_vals_2, + 'tax_repartition_line_id': None, + 'tax_tag_ids': [], + }, + { + **self.tax_line_vals_1, + 'tax_repartition_line_id': repartition_line.id, + 'tax_tag_ids': tax_line_tag.ids, + }, + { + **self.tax_line_vals_2, + 'tax_repartition_line_id': self.tax_purchase_b.invoice_repartition_line_ids.filtered(lambda x: x.repartition_type == 'tax').id, + 'tax_tag_ids': [], }, - self.product_line_vals_2, - self.tax_line_vals_1, - self.tax_line_vals_2, { 'name': '%s (rounding)' % self.tax_purchase_a.name, 'product_id': False, @@ -931,6 +979,8 @@ class TestAccountMoveInInvoiceOnchanges(AccountTestInvoicingCommon): 'price_total': -0.04, 'tax_ids': [], 'tax_line_id': self.tax_purchase_a.id, + 'tax_repartition_line_id': repartition_line.id, + 'tax_tag_ids': tax_line_tag.ids, 'currency_id': self.company_data['currency'].id, 'amount_currency': -0.04, 'debit': 0.0, @@ -944,6 +994,8 @@ class TestAccountMoveInInvoiceOnchanges(AccountTestInvoicingCommon): 'price_total': -1127.95, 'amount_currency': -1127.95, 'credit': 1127.95, + 'tax_repartition_line_id': None, + 'tax_tag_ids': [], }, ], { **self.move_vals, diff --git a/addons/account/tests/test_account_move_in_refund.py b/addons/account/tests/test_account_move_in_refund.py index 54a498bc412..454ee1d6052 100644 --- a/addons/account/tests/test_account_move_in_refund.py +++ b/addons/account/tests/test_account_move_in_refund.py @@ -531,6 +531,7 @@ class TestAccountMoveInRefundOnchanges(AccountTestInvoicingCommon): }) def test_in_refund_line_onchange_cash_rounding_1(self): + # Test 'add_invoice_line' rounding move_form = Form(self.invoice) # Add a cash rounding having 'add_invoice_line'. move_form.invoice_cash_rounding_id = self.cash_rounding_a @@ -584,12 +585,45 @@ class TestAccountMoveInRefundOnchanges(AccountTestInvoicingCommon): self.term_line_vals_1, ], self.move_vals) - move_form = Form(self.invoice) - # Change the cash rounding to one having 'biggest_tax'. - move_form.invoice_cash_rounding_id = self.cash_rounding_b - move_form.save() + # Test 'biggest_tax' rounding - self.assertInvoiceValues(self.invoice, [ + self.company_data['company'].country_id = self.env.ref('base.us') + + # Add a tag to product_a's default tax + tax_line_tag = self.env['account.account.tag'].create({ + 'name': "Tax tag", + 'applicability': 'taxes', + 'country_id': self.company_data['company'].country_id.id, + }) + + repartition_line = self.tax_purchase_a.refund_repartition_line_ids.filtered(lambda x: x.repartition_type == 'tax') + repartition_line.write({'tag_ids': [(4, tax_line_tag.id, 0)]}) + + # Create the invoice + biggest_tax_invoice = self.env['account.move'].create({ + 'move_type': 'in_refund', + 'invoice_date': '2019-01-01', + 'partner_id': self.partner_a.id, + 'invoice_cash_rounding_id': self.cash_rounding_b.id, + 'invoice_payment_term_id': self.pay_terms_a.id, + 'invoice_line_ids': [ + (0, 0, { + 'product_id': self.product_a.id, + 'price_unit': 799.99, + 'tax_ids': [(6, 0, self.product_a.supplier_taxes_id.ids)], + 'product_uom_id': self.product_a.uom_id.id, + }), + + (0, 0, { + 'product_id': self.product_b.id, + 'price_unit': self.product_b.standard_price, + 'tax_ids': [(6, 0, self.product_b.supplier_taxes_id.ids)], + 'product_uom_id': self.product_b.uom_id.id, + }), + ], + }) + + self.assertInvoiceValues(biggest_tax_invoice, [ { **self.product_line_vals_1, 'price_unit': 799.99, @@ -597,10 +631,24 @@ class TestAccountMoveInRefundOnchanges(AccountTestInvoicingCommon): 'price_total': 919.99, 'amount_currency': -799.99, 'credit': 799.99, + 'tax_repartition_line_id': None, + 'tax_tag_ids': [], + }, + { + **self.product_line_vals_2, + 'tax_repartition_line_id': None, + 'tax_tag_ids': [], + }, + { + **self.tax_line_vals_1, + 'tax_repartition_line_id': repartition_line.id, + 'tax_tag_ids': tax_line_tag.ids, + }, + { + **self.tax_line_vals_2, + 'tax_repartition_line_id': self.tax_purchase_b.refund_repartition_line_ids.filtered(lambda x: x.repartition_type == 'tax').id, + 'tax_tag_ids': [], }, - self.product_line_vals_2, - self.tax_line_vals_1, - self.tax_line_vals_2, { 'name': '%s (rounding)' % self.tax_purchase_a.name, 'product_id': False, @@ -614,6 +662,8 @@ class TestAccountMoveInRefundOnchanges(AccountTestInvoicingCommon): 'price_total': -0.04, 'tax_ids': [], 'tax_line_id': self.tax_purchase_a.id, + 'tax_repartition_line_id': repartition_line.id, + 'tax_tag_ids': tax_line_tag.ids, 'currency_id': self.company_data['currency'].id, 'amount_currency': 0.04, 'debit': 0.04, @@ -627,6 +677,8 @@ class TestAccountMoveInRefundOnchanges(AccountTestInvoicingCommon): 'price_total': -1127.95, 'amount_currency': 1127.95, 'debit': 1127.95, + 'tax_repartition_line_id': None, + 'tax_tag_ids': [], }, ], { **self.move_vals, diff --git a/addons/account/tests/test_account_move_out_invoice.py b/addons/account/tests/test_account_move_out_invoice.py index fe2e7b63f05..bf3e320ca17 100644 --- a/addons/account/tests/test_account_move_out_invoice.py +++ b/addons/account/tests/test_account_move_out_invoice.py @@ -1450,6 +1450,7 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon): ]) def test_out_invoice_line_onchange_cash_rounding_1(self): + # Test 'add_invoice_line' rounding move_form = Form(self.invoice) # Add a cash rounding having 'add_invoice_line'. move_form.invoice_cash_rounding_id = self.cash_rounding_a @@ -1503,12 +1504,45 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon): self.term_line_vals_1, ], self.move_vals) - move_form = Form(self.invoice) - # Change the cash rounding to one having 'biggest_tax'. - move_form.invoice_cash_rounding_id = self.cash_rounding_b - move_form.save() + # Test 'biggest_tax' rounding - self.assertInvoiceValues(self.invoice, [ + self.company_data['company'].country_id = self.env.ref('base.us') + + # Add a tag to product_a's default tax + tax_line_tag = self.env['account.account.tag'].create({ + 'name': "Tax tag", + 'applicability': 'taxes', + 'country_id': self.company_data['company'].country_id.id, + }) + + repartition_line = self.tax_sale_a.invoice_repartition_line_ids.filtered(lambda x: x.repartition_type == 'tax') + repartition_line.write({'tag_ids': [(4, tax_line_tag.id, 0)]}) + + # Create the invoice + biggest_tax_invoice = self.env['account.move'].create({ + 'move_type': 'out_invoice', + 'invoice_date': '2019-01-01', + 'partner_id': self.partner_a.id, + 'invoice_cash_rounding_id': self.cash_rounding_b.id, + 'invoice_payment_term_id': self.pay_terms_a.id, + 'invoice_line_ids': [ + (0, 0, { + 'product_id': self.product_a.id, + 'price_unit': 999.99, + 'tax_ids': [(6, 0, self.product_a.taxes_id.ids)], + 'product_uom_id': self.product_a.uom_id.id, + }), + + (0, 0, { + 'product_id': self.product_b.id, + 'price_unit': self.product_b.lst_price, + 'tax_ids': [(6, 0, self.product_b.taxes_id.ids)], + 'product_uom_id': self.product_b.uom_id.id, + }), + ], + }) + + self.assertInvoiceValues(biggest_tax_invoice, [ { **self.product_line_vals_1, 'price_unit': 999.99, @@ -1516,10 +1550,24 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon): 'price_total': 1149.99, 'amount_currency': -999.99, 'credit': 999.99, + 'tax_repartition_line_id': None, + 'tax_tag_ids': [], + }, + { + **self.product_line_vals_2, + 'tax_repartition_line_id': None, + 'tax_tag_ids': [], + }, + { + **self.tax_line_vals_1, + 'tax_repartition_line_id': repartition_line.id, + 'tax_tag_ids': tax_line_tag.ids, + }, + { + **self.tax_line_vals_2, + 'tax_repartition_line_id': self.tax_sale_b.invoice_repartition_line_ids.filtered(lambda x: x.repartition_type == 'tax').id, + 'tax_tag_ids': [], }, - self.product_line_vals_2, - self.tax_line_vals_1, - self.tax_line_vals_2, { 'name': '%s (rounding)' % self.tax_sale_a.name, 'product_id': False, @@ -1533,6 +1581,8 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon): 'price_total': -0.04, 'tax_ids': [], 'tax_line_id': self.tax_sale_a.id, + 'tax_repartition_line_id': repartition_line.id, + 'tax_tag_ids': tax_line_tag.ids, 'currency_id': self.company_data['currency'].id, 'amount_currency': 0.04, 'debit': 0.04, @@ -1546,6 +1596,8 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon): 'price_total': -1409.95, 'amount_currency': 1409.95, 'debit': 1409.95, + 'tax_repartition_line_id': None, + 'tax_tag_ids': [], }, ], { **self.move_vals, diff --git a/addons/account/tests/test_account_move_out_refund.py b/addons/account/tests/test_account_move_out_refund.py index 29a22700428..fc5321a63ee 100644 --- a/addons/account/tests/test_account_move_out_refund.py +++ b/addons/account/tests/test_account_move_out_refund.py @@ -531,6 +531,7 @@ class TestAccountMoveOutRefundOnchanges(AccountTestInvoicingCommon): }) def test_out_refund_line_onchange_cash_rounding_1(self): + # Test 'add_invoice_line' rounding move_form = Form(self.invoice) # Add a cash rounding having 'add_invoice_line'. move_form.invoice_cash_rounding_id = self.cash_rounding_a @@ -584,12 +585,45 @@ class TestAccountMoveOutRefundOnchanges(AccountTestInvoicingCommon): self.term_line_vals_1, ], self.move_vals) - move_form = Form(self.invoice) - # Change the cash rounding to one having 'biggest_tax'. - move_form.invoice_cash_rounding_id = self.cash_rounding_b - move_form.save() + # Test 'biggest_tax' rounding - self.assertInvoiceValues(self.invoice, [ + self.company_data['company'].country_id = self.env.ref('base.us') + + # Add a tag to product_a's default tax + tax_line_tag = self.env['account.account.tag'].create({ + 'name': "Tax tag", + 'applicability': 'taxes', + 'country_id': self.company_data['company'].country_id.id, + }) + + repartition_line = self.tax_sale_a.refund_repartition_line_ids.filtered(lambda x: x.repartition_type == 'tax') + repartition_line.write({'tag_ids': [(4, tax_line_tag.id, 0)]}) + + # Create the invoice + biggest_tax_invoice = self.env['account.move'].create({ + 'move_type': 'out_refund', + 'invoice_date': '2019-01-01', + 'partner_id': self.partner_a.id, + 'invoice_cash_rounding_id': self.cash_rounding_b.id, + 'invoice_payment_term_id': self.pay_terms_a.id, + 'invoice_line_ids': [ + (0, 0, { + 'product_id': self.product_a.id, + 'price_unit': 999.99, + 'tax_ids': [(6, 0, self.product_a.taxes_id.ids)], + 'product_uom_id': self.product_a.uom_id.id, + }), + + (0, 0, { + 'product_id': self.product_b.id, + 'price_unit': self.product_b.lst_price, + 'tax_ids': [(6, 0, self.product_b.taxes_id.ids)], + 'product_uom_id': self.product_b.uom_id.id, + }), + ], + }) + + self.assertInvoiceValues(biggest_tax_invoice, [ { **self.product_line_vals_1, 'price_unit': 999.99, @@ -597,10 +631,24 @@ class TestAccountMoveOutRefundOnchanges(AccountTestInvoicingCommon): 'price_total': 1149.99, 'amount_currency': 999.99, 'debit': 999.99, + 'tax_repartition_line_id': None, + 'tax_tag_ids': [], + }, + { + **self.product_line_vals_2, + 'tax_repartition_line_id': None, + 'tax_tag_ids': [], + }, + { + **self.tax_line_vals_1, + 'tax_repartition_line_id': repartition_line.id, + 'tax_tag_ids': tax_line_tag.ids, + }, + { + **self.tax_line_vals_2, + 'tax_repartition_line_id': self.tax_sale_b.refund_repartition_line_ids.filtered(lambda x: x.repartition_type == 'tax').id, + 'tax_tag_ids': [], }, - self.product_line_vals_2, - self.tax_line_vals_1, - self.tax_line_vals_2, { 'name': '%s (rounding)' % self.tax_sale_a.name, 'product_id': False, @@ -614,6 +662,8 @@ class TestAccountMoveOutRefundOnchanges(AccountTestInvoicingCommon): 'price_total': -0.04, 'tax_ids': [], 'tax_line_id': self.tax_sale_a.id, + 'tax_repartition_line_id': repartition_line.id, + 'tax_tag_ids': tax_line_tag.ids, 'currency_id': self.company_data['currency'].id, 'amount_currency': -0.04, 'debit': 0.0, @@ -627,6 +677,8 @@ class TestAccountMoveOutRefundOnchanges(AccountTestInvoicingCommon): 'price_total': -1409.95, 'amount_currency': -1409.95, 'credit': 1409.95, + 'tax_repartition_line_id': None, + 'tax_tag_ids': [], }, ], { **self.move_vals,