from unittest.mock import patch from odoo import Command from odoo.addons.account.models.chart_template import AccountChartTemplate from odoo.addons.account.tests.common import instantiate_accountman from odoo.tests import tagged from odoo.tests.common import TransactionCase def _get_chart_template_mapping(self, get_all=False): return { 'local': { 'name': 'local', 'country_id': self.env.ref("base.be").id, 'country_code': 'be', 'modules': ['account'], 'parent': None, 'installed': True, }, 'foreign': { 'name': 'foreign', 'country_id': self.env.ref("base.fr").id, 'country_code': 'fr', 'modules': ['account'], 'parent': None, 'installed': True, }, } def data_method_provider(chart_template_name, country_code): country = f"base.{country_code}" # this is used to simulated differences between xml_ids external_id_prefix = '' if chart_template_name == 'local' else f"{chart_template_name}_" def test_data_getter(self, template_code): return { 'template_data': { 'code_digits': 6, 'currency_id': 'base.EUR', 'property_account_income_categ_id': f'{external_id_prefix}test_account_income_template', 'property_account_expense_categ_id': f'{external_id_prefix}test_account_expense_template', }, 'res.company': { self.env.company.id: { 'bank_account_code_prefix': '1000', 'cash_account_code_prefix': '2000', 'transfer_account_code_prefix': '3000', }, }, 'account.account': { f'{external_id_prefix}test_account_tax_recoverable_template': { 'name': f'{external_id_prefix}tax recoverable', 'code': '411000', 'account_type': 'asset_current', }, f'{external_id_prefix}test_account_tax_receivable_template': { 'name': f'{external_id_prefix}tax recoverable', 'code': '411200', 'account_type': 'asset_current', }, f'{external_id_prefix}test_account_advance_payment_tax_template': { 'name': f'{external_id_prefix}advance tax payment', 'code': '411900', 'account_type': 'asset_current', }, f'{external_id_prefix}test_account_tax_payable_template': { 'name': f'{external_id_prefix}tax recoverable', 'code': '451200', 'account_type': 'liability_current', }, f'{external_id_prefix}test_account_cash_basis_transition_account_id': { 'name': f'{external_id_prefix}cash basis transition account', 'code': '451500', 'account_type': 'liability_current', }, f'{external_id_prefix}test_account_income_template': { 'name': f'{external_id_prefix}income', 'code': '600000', 'account_type': 'income', }, f'{external_id_prefix}test_account_expense_template': { 'name': f'{external_id_prefix}expense', 'code': '700000', 'account_type': 'expense', }, }, 'account.journal': self._get_account_journal(template_code), 'account.tax.group': { 'tax_group_taxes': { 'name': f"{external_id_prefix}Taxes", 'sequence': 0, 'country_id': country, 'tax_payable_account_id': f'{external_id_prefix}test_account_tax_payable_template', 'tax_receivable_account_id': f'{external_id_prefix}test_account_tax_receivable_template', 'advance_tax_payment_account_id': f'{external_id_prefix}test_account_advance_payment_tax_template', }, }, 'account.tax': { **{ xmlid: _tax_vals(name, amount, external_id_prefix) for name, xmlid, amount in ( ('Tax 1', 'test_tax_1_template', 15), ('Tax 2', 'test_tax_2_template', 0), ) }, 'test_composite_tax_template': { 'name': 'Tax Grouped', 'amount_type': 'group', 'type_tax_use': 'purchase', 'tax_group_id': 'tax_group_taxes', 'children_tax_ids': 'test_tax_1_template,test_tax_2_template', } }, } return test_data_getter def _tax_vals(name, amount, external_id_prefix): return { 'name': name, 'amount': amount, 'type_tax_use': 'purchase', 'tax_group_id': 'tax_group_taxes', 'cash_basis_transition_account_id': f'{external_id_prefix}test_account_cash_basis_transition_account_id', 'repartition_line_ids': [ Command.create({'document_type': 'invoice', 'factor_percent': 100, 'repartition_type': 'base'}), Command.create({'document_type': 'invoice', 'factor_percent': 100, 'repartition_type': 'tax', 'account_id': f'{external_id_prefix}test_account_tax_recoverable_template'}), Command.create({'document_type': 'refund', 'factor_percent': 100, 'repartition_type': 'base'}), Command.create({'document_type': 'refund', 'factor_percent': 100, 'repartition_type': 'tax', 'account_id': f'{external_id_prefix}test_account_tax_recoverable_template'}), ] } @tagged('post_install', '-at_install') @patch.object(AccountChartTemplate, '_get_chart_template_mapping', _get_chart_template_mapping) class TestMultiVAT(TransactionCase): @classmethod @patch.object(AccountChartTemplate, '_get_chart_template_mapping', _get_chart_template_mapping) def setUpClass(cls): """ Setups a company with a custom chart template, containing a tax and a fiscal position. We need to add xml_ids to the templates because they are loaded from their xml_ids """ super().setUpClass() instantiate_accountman(cls) cls.company_1 = cls.env['res.company'].create({ 'name': 'TestCompany1', 'country_id': cls.env.ref('base.be').id, }) cls.user.write({ 'company_ids': [Command.set(cls.company_1.ids)], 'company_id': cls.company_1.id, }) test_get_data = data_method_provider("local", "be") with patch.object(AccountChartTemplate, '_get_chart_template_data', side_effect=test_get_data, autospec=True): cls.env['account.chart.template'].try_loading('local', company=cls.company_1, install_demo=False) foreign_country = cls.env.ref("base.fr") cls.foreign_vat_fpos = cls.env["account.fiscal.position"].create({ "name": "FR foreign VAT", "auto_apply": True, "country_id": foreign_country.id, "foreign_vat": "FR23334175221", }) test_get_data = data_method_provider("foreign", "fr") with patch.object(AccountChartTemplate, '_get_chart_template_data', side_effect=test_get_data, autospec=True): cls.foreign_vat_fpos.action_create_foreign_taxes() def test_tax_and_tax_group_should_be_reachable_using_standard_api(self): # Ensure local and foreign tax is reachable using the custom ref api for xml_id in ( # tax group 'tax_group_taxes', 'foreign_tax_group_taxes', # tax 'test_tax_1_template', 'test_tax_2_template', 'test_composite_tax_template', 'foreign_test_tax_1_template', 'foreign_test_tax_2_template', 'foreign_test_composite_tax_template' ): with self.subTest(xml_id=xml_id): record = self.env["account.chart.template"].ref(xml_id, raise_if_not_found=False) self.assertTrue(record, "We should be able to retrieve the record") def test_tax_group_data(self): # Ensure the correct country is set on tax group for xml_id, country_code in (('tax_group_taxes', 'BE'), ('foreign_tax_group_taxes', 'FR')): tax_group = self.env["account.chart.template"].ref(xml_id) with self.subTest(xml_id=xml_id, country_code=country_code): self.assertEqual(tax_group.country_id.code, country_code) local_tax_group = self.env["account.chart.template"].ref('tax_group_taxes') foreign_tax_group = self.env["account.chart.template"].ref('foreign_tax_group_taxes') for field in ('tax_payable_account_id', 'tax_receivable_account_id', 'advance_tax_payment_account_id'): with self.subTest(field=field): self.assertTrue(foreign_tax_group[field], "This account should have been set") self.assertNotEqual(foreign_tax_group[field], local_tax_group[field], "A copy of the local tax group account should have been created and set") def test_tax_data_should_be_consistent(self): # Ensure the correct country is set for xml_id, country_code in ( # tax ('test_tax_1_template', 'BE'), ('test_tax_2_template', 'BE'), ('foreign_test_tax_1_template', 'FR'), ('foreign_test_tax_2_template', 'FR'), ): model = self.env["account.chart.template"].ref(xml_id) with self.subTest(xml_id=xml_id, country_code=country_code): self.assertEqual(model.country_id.code, country_code) tax = self.env["account.chart.template"].ref('foreign_test_tax_1_template') self.assertEqual(tax.country_id.code, 'FR') self.assertEqual(tax.cash_basis_transition_account_id.code, '451501') _base_line, tax_line = tax.invoice_repartition_line_ids self.assertEqual(tax_line.account_id.code, '411001', "The foreign tax account should be a new account with a code close to the local tax account code") tax = self.env["account.chart.template"].ref('foreign_test_tax_2_template') self.assertEqual(tax.country_id.code, 'FR') self.assertEqual(tax.cash_basis_transition_account_id.code, '451501') _base_line, tax_line = tax.invoice_repartition_line_ids self.assertEqual(tax_line.account_id.code, '411001', "The previously created tax account should be reused for similar tax") def test_children_taxes(self): # Ensure that group-type taxes are correctly linked to their children composite_taxes = ['test_composite_tax_template', 'foreign_test_composite_tax_template'] children_taxes = { 'test_composite_tax_template': ['test_tax_1_template', 'test_tax_2_template'], 'foreign_test_composite_tax_template': ['foreign_test_tax_1_template', 'foreign_test_tax_2_template'], } for xml_id in composite_taxes: with self.subTest(xml_id=xml_id): record = self.env["account.chart.template"].ref(xml_id, raise_if_not_found=False) for i, child in enumerate(record.children_tax_ids): child_tax = self.env["account.chart.template"].ref(children_taxes[xml_id][i], raise_if_not_found=False) self.assertEqual(child.id, child_tax.id)