[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 <smetl@users.noreply.github.com>
This commit is contained in:
@@ -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',
|
||||
|
||||
@@ -21,3 +21,4 @@ from . import account_incoterms
|
||||
from . import digest
|
||||
from . import res_users
|
||||
from . import ir_actions_report
|
||||
from . import res_currency
|
||||
|
||||
@@ -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)]))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
|
||||
<record id="res_currency_form_inherit" model="ir.ui.view">
|
||||
<field name="name">res.currency.form.inherit</field>
|
||||
<field name="model">res.currency</field>
|
||||
<field name="inherit_id" ref="base.view_currency_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//sheet" position="before">
|
||||
<field name="display_rounding_warning" invisible="1"/>
|
||||
<div class="alert alert-warning" role="alert" attrs="{'invisible': [('display_rounding_warning', '=', False)]}">
|
||||
<strong>This currency has already been used to generate accounting entries.</strong> <br/>
|
||||
Changing its rounding factor now will not change the rounding made on previous entries; possibly causing an inconsistency with the new ones.
|
||||
</div>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user