# -*- coding: utf-8 -*- from odoo import Command from odoo.addons.account.tests.common import AccountTestInvoicingCommon from odoo.tests import tagged from odoo.exceptions import UserError @tagged('post_install', '-at_install') class TestAccountTax(AccountTestInvoicingCommon): @classmethod def setUpClass(cls): super().setUpClass() cls.company_data_2 = cls.setup_other_company() @classmethod def default_env_context(cls): # OVERRIDE return {} def set_up_and_use_tax(self): self.env['account.move'].create({ 'move_type': 'out_invoice', 'date': '2023-01-01', 'invoice_line_ids': [ Command.create({ 'name': 'invoice_line', 'quantity': 1.0, 'price_unit': 100.0, 'tax_ids': [Command.set(self.company_data['default_tax_sale'].ids)], }), ], }) # Create two lines after creating the move so that those lines are not used in the move self.company_data['default_tax_sale'].write({ 'invoice_repartition_line_ids': [ Command.create({'repartition_type': 'tax', 'factor_percent': 0.0}), ], 'refund_repartition_line_ids': [ Command.create({'repartition_type': 'tax', 'factor_percent': 0.0}), ], }) self.flush_tracking() self.assertTrue(self.company_data['default_tax_sale'].is_used) def flush_tracking(self): """ Force the creation of tracking values. """ self.env.flush_all() self.cr.flush() def test_changing_tax_company(self): ''' Ensure you can't change the company of an account.tax if there are some journal entries ''' # Avoid duplicate key value violates unique constraint "account_tax_name_company_uniq". self.company_data['default_tax_sale'].name = 'test_changing_account_company' self.env['account.move'].create({ 'move_type': 'out_invoice', 'date': '2019-01-01', 'invoice_line_ids': [ (0, 0, { 'name': 'invoice_line', 'quantity': 1.0, 'price_unit': 100.0, 'tax_ids': [(6, 0, self.company_data['default_tax_sale'].ids)], }), ], }) with self.assertRaises(UserError), self.cr.savepoint(): self.company_data['default_tax_sale'].company_id = self.company_data_2['company'] def test_logging_of_tax_update_when_tax_is_used(self): """ Modifications of a used tax should be logged. """ self.set_up_and_use_tax() self.company_data['default_tax_sale'].write({ 'name': self.company_data['default_tax_sale'].name + ' MODIFIED', 'amount': 21, 'amount_type': 'fixed', 'type_tax_use': 'purchase', 'price_include_override': 'tax_included', 'include_base_amount': True, 'is_base_affected': False, }) self.flush_tracking() self.assertEqual(len(self.company_data['default_tax_sale'].message_ids), 1, "Only 1 message should have been created when updating all the values.") # There are 7 tracked values in account.tax and we update each of them, each on should be included in the message self.assertEqual(len(self.company_data['default_tax_sale'].message_ids.tracking_value_ids), 7, "The number of updated value should be 7.") def test_logging_of_repartition_lines_addition_when_tax_is_used(self): """ Adding repartition lines in a used tax should be logged. """ self.set_up_and_use_tax() self.company_data['default_tax_sale'].write({ 'invoice_repartition_line_ids': [ Command.create({'repartition_type': 'tax', 'factor_percent': -100.0}), ], 'refund_repartition_line_ids': [ Command.create({'repartition_type': 'tax', 'factor_percent': -100.0}), ], }) self.flush_tracking() previews = self.company_data['default_tax_sale'].message_ids.mapped('preview') self.assertIn( "New Invoice repartition line 4: -100.0 (Factor Percent) None (Account) None (Tax Grids) False (Use in tax closing)", previews ) self.assertIn( "New Refund repartition line 4: -100.0 (Factor Percent) None (Account) None (Tax Grids) False (Use in tax closing)", previews ) def test_logging_of_repartition_lines_update_when_tax_is_used(self): """ Updating repartition lines in a used tax should be logged. """ self.set_up_and_use_tax() last_invoice_rep_line = self.company_data['default_tax_sale'].invoice_repartition_line_ids\ .filtered(lambda tax_rep: not tax_rep.factor_percent) last_refund_rep_line = self.company_data['default_tax_sale'].refund_repartition_line_ids\ .filtered(lambda tax_rep: not tax_rep.factor_percent) self.company_data['default_tax_sale'].write({ "invoice_repartition_line_ids": [ Command.update(last_invoice_rep_line.id, { 'factor_percent': -100, 'tag_ids': [Command.create({'name': 'TaxTag12345'})] }), ], "refund_repartition_line_ids": [ Command.update(last_refund_rep_line.id, { 'factor_percent': -100, 'account_id': self.company_data['default_account_tax_purchase'].id, }), ], }) self.flush_tracking() previews = self.company_data['default_tax_sale'].message_ids.mapped('preview') self.assertIn("Invoice repartition line 3: 0.0 -100.0 (Factor Percent) None ['TaxTag12345'] (Tax Grids)", previews) self.assertIn("Refund repartition line 3: 0.0 -100.0 (Factor Percent) None 131000 Tax Paid (Account) False True (Use in tax closing)", previews) def test_logging_of_repartition_lines_reordering_when_tax_is_used(self): """ Reordering repartition lines in a used tax should be logged. """ self.set_up_and_use_tax() last_invoice_rep_line = self.company_data['default_tax_sale'].invoice_repartition_line_ids\ .filtered(lambda tax_rep: not tax_rep.factor_percent) last_refund_rep_line = self.company_data['default_tax_sale'].refund_repartition_line_ids\ .filtered(lambda tax_rep: not tax_rep.factor_percent) self.company_data['default_tax_sale'].write({ "invoice_repartition_line_ids": [ Command.update(last_invoice_rep_line.id, {'sequence': 0}), ], "refund_repartition_line_ids": [ Command.update(last_refund_rep_line.id, {'sequence': 0}), ], }) self.flush_tracking() previews = self.company_data['default_tax_sale'].message_ids.mapped('preview') self.assertIn("Invoice repartition line 1: 100.0 0.0 (Factor Percent)", previews) self.assertIn("Invoice repartition line 3: 0.0 100.0 (Factor Percent) None 251000 Tax Received (Account) False True (Use in tax closing)", previews) def test_logging_of_repartition_lines_removal_when_tax_is_used(self): """ Deleting repartition lines in a used tax should be logged. """ self.set_up_and_use_tax() last_invoice_rep_line = self.company_data['default_tax_sale'].invoice_repartition_line_ids.sorted(key=lambda r: r.sequence)[-1] last_refund_rep_line = self.company_data['default_tax_sale'].refund_repartition_line_ids.sorted(key=lambda r: r.sequence)[-1] self.company_data['default_tax_sale'].write({ "invoice_repartition_line_ids": [ Command.delete(last_invoice_rep_line.id), ], "refund_repartition_line_ids": [ Command.delete(last_refund_rep_line.id), ], }) self.flush_tracking() previews = self.company_data['default_tax_sale'].message_ids.mapped('preview') self.assertIn( "Removed Invoice repartition line 3: 0.0 (Factor Percent) None (Account) None (Tax Grids) False (Use in tax closing)", previews ) self.assertIn( "Removed Refund repartition line 3: 0.0 (Factor Percent) None (Account) None (Tax Grids) False (Use in tax closing)", previews ) def test_tax_is_used_when_in_transactions(self): ''' Ensures that a tax is set to used when it is part of some transactions ''' # Account.move is one type of transaction tax_invoice = self.env['account.tax'].create({ 'name': 'test_is_used_invoice', 'amount': '100', }) self.env['account.move'].create({ 'move_type': 'out_invoice', 'date': '2023-01-01', 'invoice_line_ids': [ Command.create({ 'name': 'invoice_line', 'quantity': 1.0, 'price_unit': 100.0, 'tax_ids': [Command.set(tax_invoice.ids)], }), ], }) tax_invoice.invalidate_model(fnames=['is_used']) self.assertTrue(tax_invoice.is_used) # Account.reconcile is another of transaction tax_reconciliation = self.env['account.tax'].create({ 'name': 'test_is_used_reconcilition', 'amount': '100', }) self.env['account.reconcile.model'].create({ 'name': "test_tax_is_used", 'rule_type': 'writeoff_suggestion', 'auto_reconcile': False, 'line_ids': [Command.create({ 'account_id': self.company_data['default_account_revenue'].id, 'tax_ids': [Command.set(tax_reconciliation.ids)], })], }) tax_reconciliation.invalidate_model(fnames=['is_used']) self.assertTrue(tax_reconciliation.is_used)