From c45a164b136f3f12eb3b203646463dfa0bddd50b Mon Sep 17 00:00:00 2001 From: Brice bib Bartoletti Date: Tue, 29 Nov 2022 07:02:57 +0000 Subject: [PATCH] [IMP] account: tax tag on any journal item The aim of this commit is to allow any tax tag to be set on a journal item and to allow the user to put tax tag from foreign countries in which they have a VAT number on any tax. The end goal is to allow the user to impact tax reports from several country with the same journal item, avoiding the creation of a whole journal entry and setting the path for some more automation. Context: Our user has a company based in Belgium but has a warehouse in Netherland. Thus, when the company sells anything from that warehouse, it needs to fill the Dutch tax report directly. Moreover, the company needs to fill a grid on the Belgian VAT tax report. That means that the user would need to gather some journal items on both the Belgian tax report and the Dutch tax report. Before this commit: The user can't set tax tag from another country on its tax nor in the same move. After this commit: The user can set tax tags from any country for which its company has a foreign vat number on any tax and in a move Task-id: 3196547 opw-2810712 closes odoo/odoo#113027 Related: odoo/enterprise#37247 Signed-off-by: Olivier Colson (oco) --- addons/account/models/account_account_tag.py | 14 +++++++++++- addons/account/models/account_move.py | 2 +- addons/account/models/account_tax.py | 14 +++++++----- addons/account/models/company.py | 22 +++++++++++++++++++ addons/account/tests/common.py | 13 +++++++++++ .../views/account_account_tag_views.xml | 1 + addons/account/views/account_tax_views.xml | 6 ++++- 7 files changed, 63 insertions(+), 9 deletions(-) diff --git a/addons/account/models/account_account_tag.py b/addons/account/models/account_account_tag.py index 5b55efb4bb2..394ab1f255f 100644 --- a/addons/account/models/account_account_tag.py +++ b/addons/account/models/account_account_tag.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- from odoo import api, fields, models, _ -from odoo.exceptions import ValidationError from odoo import osv @@ -15,6 +14,19 @@ class AccountAccountTag(models.Model): tax_negate = fields.Boolean(string="Negate Tax Balance", help="Check this box to negate the absolute value of the balance of the lines associated with this tag in tax report computation.") country_id = fields.Many2one(string="Country", comodel_name='res.country', help="Country for which this tag is available, when applied on taxes.") + def name_get(self): + if not self.env.company.multi_vat_foreign_country_ids: + return super().name_get() + + res = [] + for tag in self: + name = tag.name + if tag.applicability == "taxes" and tag.country_id and tag.country_id != self.env.company.account_fiscal_country_id: + name = _("%s (%s)", tag.name, tag.country_id.code) + res.append((tag.id, name,)) + + return res + @api.model def _get_tax_tags(self, tag_name, country_id): """ Returns all the tax tags corresponding to the tag name given in parameter diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index fc15e28483a..4a68b395d32 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -1820,7 +1820,7 @@ class AccountMove(models.Model): self._compute_tax_country_id() # We need to ensure this field has been computed, as we use it in our check for record in self: amls = record.line_ids - impacted_countries = amls.tax_ids.country_id | amls.tax_line_id.country_id | amls.tax_tag_ids.country_id + impacted_countries = amls.tax_ids.country_id | amls.tax_line_id.country_id if impacted_countries and impacted_countries != record.tax_country_id: if record.fiscal_position_id and impacted_countries != record.fiscal_position_id.country_id: raise ValidationError(_("This entry contains taxes that are not compatible with your fiscal position. Check the country set in fiscal position and in your tax configuration.")) diff --git a/addons/account/models/account_tax.py b/addons/account/models/account_tax.py index 4d69723a56c..08b5dec0d36 100644 --- a/addons/account/models/account_tax.py +++ b/addons/account/models/account_tax.py @@ -1305,6 +1305,14 @@ class AccountTaxRepartitionLine(models.Model): help="The order in which distribution lines are displayed and matched. For refunds to work properly, invoice distribution lines should be arranged in the same order as the credit note distribution lines they correspond to.") use_in_tax_closing = fields.Boolean(string="Tax Closing Entry", default=True) + tag_ids_domain = fields.Binary(string="tag domain", help="Dynamic domain used for the tag that can be set on tax", compute="_compute_tag_ids_domain") + + @api.depends('company_id.multi_vat_foreign_country_ids', 'company_id.account_fiscal_country_id') + def _compute_tag_ids_domain(self): + for rep_line in self: + allowed_country_ids = (False, rep_line.company_id.account_fiscal_country_id.id, *rep_line.company_id.multi_vat_foreign_country_ids.ids,) + rep_line.tag_ids_domain = [('applicability', '=', 'taxes'), ('country_id', 'in', allowed_country_ids)] + @api.onchange('account_id', 'repartition_type') def _on_change_account_id(self): if not self.account_id or self.repartition_type == 'base': @@ -1312,12 +1320,6 @@ class AccountTaxRepartitionLine(models.Model): else: self.use_in_tax_closing = self.account_id.internal_group not in ('income', 'expense') - @api.constrains('tax_id', 'tag_ids') - def validate_tags_country(self): - for record in self: - if record.tag_ids.country_id and record.tax_id.country_id != record.tag_ids.country_id: - raise ValidationError(_("A tax should only use tags from its country. You should use another tax and a fiscal position if you wish to uses the tags from foreign tax reports.")) - @api.depends('factor_percent') def _compute_factor(self): for record in self: diff --git a/addons/account/models/company.py b/addons/account/models/company.py index bc307542fa2..7514d9826c5 100644 --- a/addons/account/models/company.py +++ b/addons/account/models/company.py @@ -172,6 +172,15 @@ class ResCompany(models.Model): # Storno Accounting account_storno = fields.Boolean(string="Storno accounting", readonly=False) + # Multivat + fiscal_position_ids = fields.One2many(comodel_name="account.fiscal.position", inverse_name="company_id") + multi_vat_foreign_country_ids = fields.Many2many( + string="Foreign VAT countries", + help="Countries for which the company has a VAT number", + comodel_name='res.country', + compute='_compute_multi_vat_foreign_country', + ) + # Fiduciary mode quick_edit_mode = fields.Selection( selection=[ @@ -197,6 +206,19 @@ class ResCompany(models.Model): if rec.fiscalyear_last_day > max_day: raise ValidationError(_("Invalid fiscal year last day")) + @api.depends('fiscal_position_ids.foreign_vat') + def _compute_multi_vat_foreign_country(self): + company_to_foreign_vat_country = { + val['company_id'][0]: val['country_ids'] + for val in self.env['account.fiscal.position'].read_group( + domain=[('company_id', 'in', self.ids), ('foreign_vat', '!=', False)], + fields=['country_ids:array_agg(country_id)'], + groupby='company_id', + ) + } + for company in self: + company.multi_vat_foreign_country_ids = self.env['res.country'].browse(company_to_foreign_vat_country.get(company.id)) + @api.depends('country_id') def compute_account_tax_fiscal_country(self): for record in self: diff --git a/addons/account/tests/common.py b/addons/account/tests/common.py index 5d7d68de955..5cd34288323 100644 --- a/addons/account/tests/common.py +++ b/addons/account/tests/common.py @@ -283,6 +283,19 @@ class AccountTestInvoicingCommon(TransactionCase): 'rates': rate1 + rate2, } + @classmethod + def _instantiate_basic_test_tax_group(cls, company=None, country=None): + company = company or cls.env.company + vals = { + 'name': 'Test tax group', + 'company_id': company.id, + 'tax_receivable_account_id': cls.company_data['default_account_receivable'].sudo().copy({'company_id': company.id}).id, + 'tax_payable_account_id': cls.company_data['default_account_payable'].sudo().copy({'company_id': company.id}).id, + } + if country: + vals['country_id'] = country.id + return cls.env['account.tax.group'].sudo().create(vals) + @classmethod def setup_armageddon_tax(cls, tax_name, company_data): return cls.env['account.tax'].create({ diff --git a/addons/account/views/account_account_tag_views.xml b/addons/account/views/account_account_tag_views.xml index 2b1fbc4d8f8..9d43680c58a 100644 --- a/addons/account/views/account_account_tag_views.xml +++ b/addons/account/views/account_account_tag_views.xml @@ -28,6 +28,7 @@ + diff --git a/addons/account/views/account_tax_views.xml b/addons/account/views/account_tax_views.xml index 6ffa2a605b0..867c509835b 100644 --- a/addons/account/views/account_tax_views.xml +++ b/addons/account/views/account_tax_views.xml @@ -41,11 +41,15 @@ - + +