From 31e1322b40ab33bf81d4c000f2b2a3f3eb8d0958 Mon Sep 17 00:00:00 2001 From: oco-odoo Date: Tue, 17 Dec 2019 11:55:41 +0000 Subject: [PATCH] [IMP] account: don't always allow modifying the decimal places of a currency If accounting entries have already been generated by this currency, we now forbid setting it a lesser number of decimal places (so, higher rounding factor). We also display a warning when increasing the number of decimal places, to make sure the user is aware of the impact it'll have. closes odoo/odoo#42017 Signed-off-by: Laurent Smet --- addons/account/__manifest__.py | 1 + addons/account/models/__init__.py | 1 + addons/account/models/res_currency.py | 37 +++++++++++++++++++ addons/account/tests/test_tax.py | 40 +++++++++++---------- addons/account/views/res_currency.xml | 21 +++++++++++ addons/account_tax_python/tests/test_tax.py | 2 +- 6 files changed, 82 insertions(+), 20 deletions(-) create mode 100644 addons/account/models/res_currency.py create mode 100644 addons/account/views/res_currency.xml diff --git a/addons/account/__manifest__.py b/addons/account/__manifest__.py index c2585f9ef01..6572c12b3a4 100644 --- a/addons/account/__manifest__.py +++ b/addons/account/__manifest__.py @@ -63,6 +63,7 @@ You could use this simplified accounting in case you work with an (external) acc 'views/account_tax_report_views.xml', 'report/account_hash_integrity_templates.xml', 'wizard/account_transfer_wizard.xml', + 'views/res_currency.xml', ], 'demo': [ 'demo/account_demo.xml', diff --git a/addons/account/models/__init__.py b/addons/account/models/__init__.py index ada7f4d2d52..ff544440e12 100644 --- a/addons/account/models/__init__.py +++ b/addons/account/models/__init__.py @@ -21,3 +21,4 @@ from . import account_incoterms from . import digest from . import res_users from . import ir_actions_report +from . import res_currency diff --git a/addons/account/models/res_currency.py b/addons/account/models/res_currency.py new file mode 100644 index 00000000000..12f401d82a0 --- /dev/null +++ b/addons/account/models/res_currency.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, models, fields, _ + +from odoo.exceptions import UserError + + +class ResCurrency(models.Model): + _inherit = 'res.currency' + + display_rounding_warning = fields.Boolean(string="Display Rounding Warning", compute='_compute_display_rounding_warning', help="Technical field used to tell whether or not to display the warning informing a rounding factor change might be dangerous on res.currency's form view.") + + + @api.depends('rounding') + def _compute_display_rounding_warning(self): + for record in self: + record.display_rounding_warning = record._origin.rounding != record.rounding \ + and record._origin._has_accounting_entries() + + def write(self, vals): + if 'rounding' in vals: + rounding_val = vals['rounding'] + for record in self: + if (rounding_val > record.rounding or rounding_val == 0) and record._has_accounting_entries(): + raise UserError(_("You cannot reduce the number of decimal places of a currency which has already been used to make accounting entries. If you really need to do that, please contact tech support.")) + + return super(ResCurrency, self).write(vals) + + def _has_accounting_entries(self): + """ Returns True iff this currency has been used to generate (hence, round) + some move lines (either as their foreign currency, or as the main currency + of their company). + """ + self.ensure_one() + return bool(self.env['account.move.line'].search_count(['|', ('currency_id', '=', self.id), ('company_currency_id', '=', self.id)])) + diff --git a/addons/account/tests/test_tax.py b/addons/account/tests/test_tax.py index be857511d29..b4ee819e4b1 100644 --- a/addons/account/tests/test_tax.py +++ b/addons/account/tests/test_tax.py @@ -1,46 +1,52 @@ # -*- coding: utf-8 -*- -from odoo.addons.account.tests.common import AccountTestUsersCommon +from odoo.addons.account.tests.common import AccountTestInvoicingCommon from odoo.tests import tagged @tagged('post_install', '-at_install') -class TestTaxCommon(AccountTestUsersCommon): +class TestTaxCommon(AccountTestInvoicingCommon): @classmethod def setUpClass(cls): super(TestTaxCommon, cls).setUpClass() - cls.fixed_tax = cls.tax_model.create({ + # Setup another company having a rounding of 1.0. + cls.currency_data['currency'].rounding = 1.0 + cls.currency_no_decimal = cls.currency_data['currency'] + cls.company_data_2 = cls.setup_company_data('company_2', currency_id=cls.currency_no_decimal.id) + cls.env.user.company_id = cls.company_data['company'] + + cls.fixed_tax = cls.env['account.tax'].create({ 'name': "Fixed tax", 'amount_type': 'fixed', 'amount': 10, 'sequence': 1, }) - cls.fixed_tax_bis = cls.tax_model.create({ + cls.fixed_tax_bis = cls.env['account.tax'].create({ 'name': "Fixed tax bis", 'amount_type': 'fixed', 'amount': 15, 'sequence': 2, }) - cls.percent_tax = cls.tax_model.create({ + cls.percent_tax = cls.env['account.tax'].create({ 'name': "Percent tax", 'amount_type': 'percent', 'amount': 10, 'sequence': 3, }) - cls.percent_tax_bis = cls.tax_model.create({ + cls.percent_tax_bis = cls.env['account.tax'].create({ 'name': "Percent tax bis", 'amount_type': 'percent', 'amount': 10, 'sequence': 4, }) - cls.division_tax = cls.tax_model.create({ + cls.division_tax = cls.env['account.tax'].create({ 'name': "Division tax", 'amount_type': 'division', 'amount': 10, 'sequence': 4, }) - cls.group_tax = cls.tax_model.create({ + cls.group_tax = cls.env['account.tax'].create({ 'name': "Group tax", 'amount_type': 'group', 'amount': 0, @@ -50,7 +56,7 @@ class TestTaxCommon(AccountTestUsersCommon): (4, cls.percent_tax.id, 0) ] }) - cls.group_tax_bis = cls.tax_model.create({ + cls.group_tax_bis = cls.env['account.tax'].create({ 'name': "Group tax bis", 'amount_type': 'group', 'amount': 0, @@ -60,7 +66,7 @@ class TestTaxCommon(AccountTestUsersCommon): (4, cls.percent_tax.id, 0) ] }) - cls.group_of_group_tax = cls.tax_model.create({ + cls.group_of_group_tax = cls.env['account.tax'].create({ 'name': "Group of group tax", 'amount_type': 'group', 'amount': 0, @@ -70,14 +76,14 @@ class TestTaxCommon(AccountTestUsersCommon): (4, cls.group_tax_bis.id, 0) ] }) - cls.tax_with_no_account = cls.tax_model.create({ + cls.tax_with_no_account = cls.env['account.tax'].create({ 'name': "Tax with no account", 'amount_type': 'fixed', 'amount': 0, 'sequence': 8, }) some_account = cls.env['account.account'].search([], limit=1) - cls.tax_with_account = cls.tax_model.create({ + cls.tax_with_account = cls.env['account.tax'].create({ 'name': "Tax with account", 'amount_type': 'fixed', 'amount': 0, @@ -108,15 +114,15 @@ class TestTaxCommon(AccountTestUsersCommon): ], }) - cls.tax_19_percent = cls.tax_model.create({ + cls.tax_19_percent = cls.env['account.tax'].with_company(cls.company_data_2['company']).create({ 'name': "test_rounding_methods_1", 'amount_type': 'percent', 'amount': 19, }) - cls.bank_journal = cls.env['account.journal'].search([('type', '=', 'bank'), ('company_id', '=', cls.account_manager.company_id.id)])[0] + cls.bank_journal = cls.company_data['default_journal_bank'] cls.bank_account = cls.bank_journal.default_debit_account_id - cls.expense_account = cls.env['account.account'].search([('user_type_id.type', '=', 'payable')], limit=1) #Should be done by onchange later + cls.expense_account = cls.company_data['default_account_expense'] def _check_compute_all_results(self, total_included, total_excluded, taxes, res): self.assertAlmostEqual(res['total_included'], total_included) @@ -662,7 +668,6 @@ class TestTax(TestTaxCommon): The decimal precision is set to zero. The computation must be similar to round(22689 * 0.19) + round(9176 * 0.19). ''' - self.tax_19_percent.company_id.currency_id.rounding = 1.0 self.tax_19_percent.company_id.tax_calculation_rounding_method = 'round_per_line' res1 = self.tax_19_percent.compute_all(22689) @@ -696,7 +701,6 @@ class TestTax(TestTaxCommon): The decimal precision is set to zero. The computation must be similar to round((22689 + 9176) * 0.19). ''' - self.tax_19_percent.company_id.currency_id.rounding = 1.0 self.tax_19_percent.company_id.tax_calculation_rounding_method = 'round_globally' res1 = self.tax_19_percent.compute_all(22689) @@ -731,7 +735,6 @@ class TestTax(TestTaxCommon): The computation must be similar to round(27000 / 1.19) + round(10920 / 1.19). ''' self.tax_19_percent.price_include = True - self.tax_19_percent.company_id.currency_id.rounding = 1.0 self.tax_19_percent.company_id.tax_calculation_rounding_method = 'round_per_line' res1 = self.tax_19_percent.compute_all(27000) @@ -766,7 +769,6 @@ class TestTax(TestTaxCommon): The computation must be similar to round((27000 + 10920) / 1.19). ''' self.tax_19_percent.price_include = True - self.tax_19_percent.company_id.currency_id.rounding = 1.0 self.tax_19_percent.company_id.tax_calculation_rounding_method = 'round_globally' res1 = self.tax_19_percent.compute_all(27000) diff --git a/addons/account/views/res_currency.xml b/addons/account/views/res_currency.xml new file mode 100644 index 00000000000..9653580694c --- /dev/null +++ b/addons/account/views/res_currency.xml @@ -0,0 +1,21 @@ + + + + + + res.currency.form.inherit + res.currency + + + + + + + + + + + \ No newline at end of file diff --git a/addons/account_tax_python/tests/test_tax.py b/addons/account_tax_python/tests/test_tax.py index 25c1d1929a0..0ce37033a4a 100644 --- a/addons/account_tax_python/tests/test_tax.py +++ b/addons/account_tax_python/tests/test_tax.py @@ -9,7 +9,7 @@ class TestTaxPython(TestTaxCommon): @classmethod def setUpClass(cls): super(TestTaxPython, cls).setUpClass() - cls.python_tax = cls.tax_model.create({ + cls.python_tax = cls.env['account.tax'].create({ 'name': 'Python TAx', 'amount_type': 'code', 'amount': 0.0,