From 022ecb50fedf4f444f1d37c182ef438de27e460b Mon Sep 17 00:00:00 2001 From: Laurent Smet Date: Fri, 7 Jan 2022 09:51:32 +0000 Subject: [PATCH] [FIX] account: 0% tax not in tax report due Steps to reproduce: Have a 0% Tax Make an invoice with it Open tax report The 0% tax is not present in the report because there is no tax lines generated for them because the resulting balance is zero. Since the tax details is making a mapping between tax lines and base lines and the tax report is using them to compute the report, the tax report is not able to compute the tax base amount for such taxes. Explanation: Until now, the tax line with a zero amount wasn't generated because considered as noisy journal items. Now we must be able to groupby on the base tax account on the tax report, we are forced to use the tax details. Injecting dynamically the 0% tax on the tax details sub-queries is really complicated and leads to a huge performance drop. For that reason, we start to generate the tax lines for 0% tax even the balance is zero. However, since there is nothing creating the missing lines in the past, it should be fixed case by case if needed. opw-2711432 closes odoo/odoo#82971 X-original-commit: 65b5ec4ad65f798b1d647978b5b42a49e760139a Signed-off-by: Olivier Colson Signed-off-by: Laurent Smet --- addons/account/models/account_move.py | 6 -- .../test_account_move_line_tax_details.py | 85 +++++++++++++++++++ .../tests/test_account_move_out_invoice.py | 2 +- ...o_saxon_valuation_reconciliation_common.py | 2 +- 4 files changed, 87 insertions(+), 8 deletions(-) diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index b72d2b69aa8..eecc683341c 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -787,12 +787,6 @@ class AccountMove(models.Model): currency = self.env['res.currency'].browse(taxes_map_entry['grouping_dict']['currency_id']) - # Don't create tax lines with zero balance. - if currency.is_zero(taxes_map_entry['amount']): - if taxes_map_entry['tax_line'] and not recompute_tax_base_amount: - self.line_ids -= taxes_map_entry['tax_line'] - continue - # tax_base_amount field is expressed using the company currency. tax_base_amount = currency._convert(taxes_map_entry['tax_base_amount'], self.company_currency_id, self.company_id, self.date or fields.Date.context_today(self)) diff --git a/addons/account/tests/test_account_move_line_tax_details.py b/addons/account/tests/test_account_move_line_tax_details.py index 2f942dd6c26..4e8d5669e11 100644 --- a/addons/account/tests/test_account_move_line_tax_details.py +++ b/addons/account/tests/test_account_move_line_tax_details.py @@ -1167,3 +1167,88 @@ class TestAccountTaxDetailsReport(AccountTestInvoicingCommon): ], ) self.assertTotalAmounts(invoice, tax_details) + + def test_zero_amount_tax(self): + """ Ensure the tax details is generated for 0% tax. """ + zero_tax = self.env['account.tax'].create({ + 'name': "zero_tax", + 'amount_type': 'percent', + 'amount': 0.0, + }) + + invoice = self.env['account.move'].create({ + 'move_type': 'out_invoice', + 'partner_id': self.partner_a.id, + 'invoice_date': '2019-01-01', + 'invoice_line_ids': [ + Command.create({ + 'name': 'line1', + 'account_id': self.company_data['default_account_revenue'].id, + 'price_unit': 1000.0, + 'tax_ids': [Command.set(zero_tax.ids)], + }), + Command.create({ + 'name': 'line2', + 'account_id': self.company_data['default_account_revenue'].id, + 'price_unit': 1000.0, + 'tax_ids': [Command.set(zero_tax.ids)], + }), + ] + }) + base_lines, tax_lines = self._dispatch_move_lines(invoice) + + tax_details = self._get_tax_details() + self.assertTaxDetailsValues( + tax_details, + [ + { + 'base_line_id': base_lines[0].id, + 'tax_line_id': tax_lines[0].id, + 'base_amount': -1000.0, + 'tax_amount': 0.0, + }, + { + 'base_line_id': base_lines[1].id, + 'tax_line_id': tax_lines[0].id, + 'base_amount': -1000.0, + 'tax_amount': 0.0, + }, + ], + ) + self.assertTotalAmounts(invoice, tax_details) + + # Same with a group of taxes + + tax_group = self.env['account.tax'].create({ + 'name': "tax_group", + 'amount_type': 'group', + 'children_tax_ids': [Command.set(zero_tax.ids)], + }) + + invoice.write({ + 'invoice_line_ids': [ + Command.update(base_lines[0].id, {'tax_ids': [Command.set(tax_group.ids)]}), + Command.update(base_lines[1].id, {'tax_ids': [Command.set(tax_group.ids)]}), + ], + }) + base_lines, tax_lines = self._dispatch_move_lines(invoice) + + tax_details = self._get_tax_details() + self.assertTaxDetailsValues( + tax_details, + [ + { + 'base_line_id': base_lines[0].id, + 'tax_line_id': tax_lines[0].id, + 'base_amount': -1000.0, + 'tax_amount': 0.0, + }, + { + 'base_line_id': base_lines[1].id, + 'tax_line_id': tax_lines[0].id, + 'base_amount': -1000.0, + 'tax_amount': 0.0, + }, + ], + ) + self.assertTotalAmounts(invoice, tax_details) diff --git a/addons/account/tests/test_account_move_out_invoice.py b/addons/account/tests/test_account_move_out_invoice.py index 7af8ef5af2e..fe2e7b63f05 100644 --- a/addons/account/tests/test_account_move_out_invoice.py +++ b/addons/account/tests/test_account_move_out_invoice.py @@ -2802,7 +2802,7 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon): }) self.assertEqual(len(invoice.invoice_line_ids), 1) - self.assertEqual(len(invoice.line_ids), 2) + self.assertEqual(len(invoice.line_ids), 3) def test_out_invoice_recomputation_receivable_lines(self): ''' Test a tricky specific case caused by some framework limitations. Indeed, when diff --git a/addons/stock_account/tests/test_anglo_saxon_valuation_reconciliation_common.py b/addons/stock_account/tests/test_anglo_saxon_valuation_reconciliation_common.py index d611af5c0bc..1da8b017ada 100644 --- a/addons/stock_account/tests/test_anglo_saxon_valuation_reconciliation_common.py +++ b/addons/stock_account/tests/test_anglo_saxon_valuation_reconciliation_common.py @@ -80,7 +80,7 @@ class ValuationReconciliationTestCommon(AccountTestInvoicingCommon): def check_reconciliation(self, invoice, picking, full_reconcile=True, operation='purchase'): interim_account_id = self.company_data['default_account_stock_in'].id if operation == 'purchase' else self.company_data['default_account_stock_out'].id - invoice_line = invoice.line_ids.filtered(lambda line: line.account_id.id == interim_account_id) + invoice_line = invoice.line_ids.filtered(lambda line: line.account_id.id == interim_account_id and not line.tax_line_id) stock_moves = picking.move_ids