[IMP] account: add tax lock date

Purpose:
Journal entry can be changed the way we want while the lock date is before then entry date..
Entry : Draft -> Validated (or posted)

Specs:

    add a date field in the accounting settings: tax lock date
    implement a constraint ensuring that no one can modify the information related to tax on account.move.line prior to this lock date. That means the debit, credit, tax_ids, tax_line_id fields. Other fields can be modified. This also means we cannot create/delete an account.move.line with tax information prior to this lock date.

Task 1914762

closes odoo/odoo#29272

Signed-off-by: Quentin De Paoli (qdp) <qdp@openerp.com>
This commit is contained in:
wan
2019-03-06 13:09:10 +00:00
parent 2e19c5e923
commit 14961e934c
4 changed files with 136 additions and 4 deletions
+19 -4
View File
@@ -62,13 +62,13 @@ class AccountMove(models.Model):
move.matched_percentage = 1.0
else:
move.matched_percentage = total_reconciled / total_amount
@api.multi
@api.depends('line_ids.reconcile_model_id')
def _compute_reconcile_model(self):
for move in self:
move.reconcile_model_id = move.line_ids.mapped('reconcile_model_id')
@api.model
@api.depends('reconcile_model_id')
def _search_reconcile_model(self, operator, operand):
@@ -688,6 +688,22 @@ class AccountMoveLine(models.Model):
rec.update({'credit': balance})
return rec
@api.multi
@api.constrains('tax_ids', 'tax_line_id')
def _check_tax_lock_date1(self):
for line in self:
if line.date <= (line.company_id.tax_lock_date or date.min):
raise ValidationError(_("The operation is refused as it would impact an already issued tax statement. " +
"Please change the journal entry date or the tax lock date set in the settings ({}) to proceed").format(line.company_id.tax_lock_date or date.min))
@api.multi
@api.constrains('credit', 'debit', 'date')
def _check_tax_lock_date2(self):
for line in self:
if (line.tax_ids or line.tax_line_id) and line.date <= (line.company_id.tax_lock_date or date.min):
raise ValidationError(_("The operation is refused as it would impact an already issued tax statement. " +
"Please change the journal entry date or the tax lock date set in the settings ({}) to proceed").format(line.company_id.tax_lock_date or date.min))
@api.multi
@api.constrains('currency_id', 'account_id')
def _check_currency(self):
@@ -1174,6 +1190,7 @@ class AccountMoveLine(models.Model):
@api.multi
def unlink(self):
self._update_check()
self._check_tax_lock_date2()
move_ids = set()
for line in self:
if line.move_id.id not in move_ids:
@@ -1222,8 +1239,6 @@ class AccountMoveLine(models.Model):
move_ids = set()
for line in self:
err_msg = _('Move name (id): %s (%s)') % (line.move_id.name, str(line.move_id.id))
if line.move_id.state != 'draft':
raise UserError(_('You cannot do this modification on a posted journal entry, you can just change some non legal fields. You must revert the journal entry to cancel it.\n%s.') % err_msg)
if line.reconciled and not (line.debit == 0 and line.credit == 0):
raise UserError(_('You cannot do this modification on a reconciled entry. You can just change some non legal fields or you must unreconcile first.\n%s.') % err_msg)
if line.move_id.id not in move_ids:
+1
View File
@@ -39,6 +39,7 @@ class ResCompany(models.Model):
fiscalyear_last_month = fields.Selection(MONTH_SELECTION, default='12', required=True)
period_lock_date = fields.Date(string="Lock Date for Non-Advisers", help="Only users with the 'Adviser' role can edit accounts prior to and inclusive of this date. Use it for period locking inside an open fiscal year, for example.")
fiscalyear_lock_date = fields.Date(string="Lock Date", help="No users, including Advisers, can edit accounts prior to and inclusive of this date. Use it for fiscal year locking for example.")
tax_lock_date = fields.Date("Tax Lock Date", help="No users can edit journal entries related to a tax prior and inclusive of this date.")
transfer_account_id = fields.Many2one('account.account',
domain=lambda self: [('reconcile', '=', True), ('user_type_id.id', '=', self.env.ref('account.data_account_type_current_assets').id), ('deprecated', '=', False)], string="Inter-Banks Transfer Account", help="Intermediary account used when moving money from a liquidity account to another")
expects_chart_of_accounts = fields.Boolean(string='Expects a Chart of Accounts', default=True)
+1
View File
@@ -3,6 +3,7 @@
from . import test_account_customer_invoice
from . import test_account_move_closed_period
from . import test_account_move_tax_lock_date
from . import test_account_supplier_invoice
from . import test_account_validate_account_move
from . import test_account_invoice_rounding
@@ -0,0 +1,115 @@
from odoo.addons.account.tests.account_test_classes import AccountingTestCase
from odoo.exceptions import ValidationError, UserError
from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta
from calendar import monthrange
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT
from odoo.tests import tagged
@tagged('post_install', '-at_install')
class TestTaxBlockDate(AccountingTestCase):
"""
Forbid creation, edition and deletion of Journal Items related to taxes with
a date prior to the Tax Block Date.
"""
def setUp(self):
super(TestTaxBlockDate, self).setUp()
self.user_id = self.env.user
last_day_month = datetime.now()
last_day_month = last_day_month.replace(day=monthrange(last_day_month.year, last_day_month.month)[1])
self.last_day_month_str = last_day_month.strftime(DEFAULT_SERVER_DATE_FORMAT)
first_day_month = datetime.now()
first_day_month = first_day_month.replace(day=1)
self.first_day_month_str = first_day_month.strftime(DEFAULT_SERVER_DATE_FORMAT)
middle_day_month = datetime.now()
middle_day_month = middle_day_month.replace(day=15)
self.middle_day_month_str = middle_day_month.strftime(DEFAULT_SERVER_DATE_FORMAT)
self.sale_journal_id = self.env['account.journal'].search([('type', '=', 'sale')], limit=1)[0]
self.account_id = self.env['account.account'].search([('internal_type', '=', 'receivable')], limit=1)[0]
self.other_account_id = self.env['account.account'].search([('internal_type', '!=', 'receivable')], limit=1)[0]
self.tax_id = self.env['account.tax'].search([], limit=1)[0]
self.move = {
'name': '/',
'journal_id': self.sale_journal_id.id,
'date': self.middle_day_month_str,
'line_ids': [(0, 0, {
'name': 'foo',
'debit': 10,
'account_id': self.account_id.id,
'tax_ids': [(6, False, [self.tax_id.id])]
}), (0, 0, {
'name': 'bar',
'credit': 10,
'account_id': self.account_id.id,
})]
}
def test_create_before_block_date(self):
"""
Checks that you cannot create an account.move with a date before the tax
lock date
"""
self.user_id.company_id.tax_lock_date = self.last_day_month_str
with self.assertRaises(ValidationError):
move = self.env['account.move'].create(self.move)
move.post()
def test_change_after_block_date(self):
"""
Checks that you can change an account.move with a date after the tax
lock date
"""
self.user_id.company_id.tax_lock_date = self.first_day_month_str
move = self.env['account.move'].create(self.move)
move.line_ids[0].write({'account_id': self.other_account_id.id})
move.line_ids[1].write({'account_id': self.other_account_id.id})
move.line_ids[1].write({'debit': 11})
move.line_ids[0].write({'credit': 11})
move.post()
move.line_ids[1].write({'tax_ids': [(5, False, False)]})
def test_change_before_block_date(self):
"""
Checks that you cannot change an account.move with a date before the tax
lock date
"""
self.user_id.company_id.tax_lock_date = self.first_day_month_str
move = self.env['account.move'].create(self.move)
self.user_id.company_id.tax_lock_date = self.last_day_month_str
move.line_ids[0].write({'account_id': self.other_account_id.id})
move.line_ids[1].write({'account_id': self.other_account_id.id})
with self.assertRaises(ValidationError):
with self.cr.savepoint():
move.line_ids[1].write({'debit': 11})
with self.assertRaises(ValidationError):
with self.cr.savepoint():
move.line_ids[1].write({'date': self.last_day_month_str, 'tax_ids': [(5, False, False)]})
move.line_ids[0].write({'credit': 10})
move.post()
def test_unlink_before_block_date(self):
"""
Checks that you cannot unlink an account.move with a date before the tax
lock date
"""
self.user_id.company_id.tax_lock_date = self.first_day_month_str
move = self.env['account.move'].create(self.move)
move.post()
self.user_id.company_id.tax_lock_date = self.last_day_month_str
with self.assertRaises(ValidationError):
move.unlink()
def test_unlink_after_block_date(self):
"""
Checks that you can unlink an account.move with a date after the lock
date
"""
self.user_id.company_id.tax_lock_date = self.first_day_month_str
move = self.env['account.move'].create(self.move)
move.post()
move.unlink()