[FIX] account: prevent changing date and journal of move with name

We need to ensure the name stays consitent with the journal_id and the
date when we try to change one of those fields.

X-original-commit: 634aaeeac36d2371743338536466a0bcc9ad6c69
This commit is contained in:
william-andre
2020-11-06 11:24:26 +00:00
committed by wan
parent 7da9cc2f27
commit d4b4069dec
5 changed files with 76 additions and 22 deletions
+15 -1
View File
@@ -7,7 +7,7 @@ msgstr ""
"Project-Id-Version: Odoo Server 14.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-10-29 15:48+0000\n"
"PO-Revision-Date: 2020-10-29 15:48+0000\n"
"PO-Revision-Date: 2020-11-05 16:17+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
@@ -11680,6 +11680,12 @@ msgid ""
" There is nothing left to process."
msgstr ""
#: code:addons/account/models/sequence_mixin.py:0
#, python-format
msgid ""
"The date (%(date)s) doesn't match the sequence number (%(sequence)s).\n"
"You might want to remove the sequence before proceeding with the change of the date."
#. module: account
#: code:addons/account/models/account_payment_term.py:0
#, python-format
@@ -13556,6 +13562,14 @@ msgid ""
" the journal: %s."
msgstr ""
#. module: account
#: code:addons/account/models/account_move.py:0
#, python-format
msgid ""
"You cannot edit the journal of an account move if it has already a sequence "
"number assigned."
msgstr ""
#. module: account
#: code:addons/account/models/account_move.py:0
#, python-format
@@ -317,7 +317,7 @@ class AccountBankStatement(models.Model):
st_line_vals['payment_ref'] = _("Cash difference observed during the counting (Profit)")
st_line_vals['counterpart_account_id'] = stmt.journal_id.profit_account_id.id
self.env['account.bank.statement.line'].create(st_line_vals)
else:
balance_end_real = formatLang(self.env, stmt.balance_end_real, currency_obj=stmt.currency_id)
+10 -2
View File
@@ -1063,8 +1063,14 @@ class AccountMove(models.Model):
# it. We only check the first move as an approximation (enough for new in form view)
pass
elif (move.name and move.name != '/') or move.state != 'posted':
# Has already a name or is not posted, we don't add to a batch
continue
try:
if not move.posted_before:
move._constrains_date_sequence()
# Has already a name or is not posted, we don't add to a batch
continue
except ValidationError:
# Has never been posted and the name doesn't match the date: recompute it
pass
group = grouped[journal_key(move)][date_key(move)]
if not group['records']:
# Compute all the values needed to sequence this whole group
@@ -1792,6 +1798,8 @@ class AccountMove(models.Model):
raise UserError(_('You cannot overwrite the values ensuring the inalterability of the accounting.'))
if (move.posted_before and 'journal_id' in vals and move.journal_id.id != vals['journal_id']):
raise UserError(_('You cannot edit the journal of an account move if it has been posted once.'))
if (move.name and move.name != '/' and 'journal_id' in vals and move.journal_id.id != vals['journal_id']):
raise UserError(_('You cannot edit the journal of an account move if it has already a sequence number assigned.'))
# You can't change the date of a move being inside a locked period.
if 'date' in vals and move.date != vals['date']:
+41 -10
View File
@@ -44,6 +44,28 @@ class SequenceMixin(models.AbstractModel):
field=sql.Identifier(self._sequence_field),
))
def __init__(self, pool, cr):
api.constrains(self._sequence_field, self._sequence_date_field)(type(self)._constrains_date_sequence)
return super().__init__(pool, cr)
def _constrains_date_sequence(self):
for record in self:
date = fields.Date.to_date(record[record._sequence_date_field])
sequence = record[record._sequence_field]
if sequence and date:
format_values = record._get_sequence_format_param(sequence)[1]
if (
format_values['year'] and format_values['year'] != date.year % 10**len(str(format_values['year']))
or format_values['month'] and format_values['month'] != date.month
):
raise ValidationError(_(
"The date (%(date)s) doesn't match the sequence number (%(sequence)s).\n"
"You might want to remove the sequence before proceeding with the change of the date."
) % {
'date': date,
'sequence': sequence,
})
@api.depends(lambda self: [self._sequence_field])
def _compute_split_sequence(self):
for record in self:
@@ -61,25 +83,34 @@ class SequenceMixin(models.AbstractModel):
periodicity. Typically, it is the last before the one you want to give a
sequence.
"""
def _check_grouping(grouping, optional=None, required=None):
sequence_dict = sequence.groupdict()
check = all(key in sequence_dict for key in (optional or [])) and all(sequence_dict.get(key) for key in (required or []))
check &= 'year' not in (required or []) or 2000 <= int(sequence_dict.get('year', -1)) <= 2100 or len(sequence_dict.get('year', '')) == 2
check &= 'month' not in (required or []) or 1 <= int(sequence_dict.get('month', -1)) <= 12
return check
def _check_grouping(grouping, required):
sequence_dict = grouping.groupdict()
if 'seq' not in sequence_dict or any(not sequence_dict.get(key) for key in required):
return False
if 'year' in required and not (
2000 <= int(sequence_dict.get('year') or -1) <= 2100
or len(sequence_dict.get('year') or '') == 2
):
return False
if 'month' in required and not 1 <= int(sequence_dict.get('month') or -1) <= 12:
return False
return True
if not name:
return False
sequence = re.match(self._sequence_monthly_regex, name)
if sequence and _check_grouping(sequence, ['seq'], ['year', 'month']):
if sequence and _check_grouping(sequence, ['year', 'month']):
return 'month'
sequence = re.match(self._sequence_yearly_regex, name)
if sequence and _check_grouping(sequence, ['seq'], ['year']):
if sequence and _check_grouping(sequence, ['year']):
return 'year'
sequence = re.match(self._sequence_fixed_regex, name)
if sequence and _check_grouping(sequence, ['seq']):
if sequence and _check_grouping(sequence, []):
return 'never'
raise ValidationError(_('The sequence regex should at least contain the seq grouping keys. For instance:\n^(?P<prefix1>.*?)(?P<seq>\d*)(?P<suffix>\D*?)$'))
raise ValidationError(_(
'The sequence regex should at least contain the seq grouping keys. For instance:\n'
'^(?P<prefix1>.*?)(?P<seq>\d*)(?P<suffix>\D*?)$'
))
def _get_last_sequence_domain(self, relaxed=False):
"""Get the sql domain to retreive the previous sequence number.
@@ -379,17 +379,17 @@ class TestAccountMove(AccountTestInvoicingCommon):
copy2.journal_id = new_journal
self.assertEqual(copy2.name, 'MISC2/2016/01/0001')
with Form(copy2) as move_form: # It is editable in the form
move_form.name = 'MyMISC/2099/0001'
move_form.name = 'MyMISC/2016/0001'
copy2.action_post()
self.assertEqual(copy2.name, 'MyMISC/2099/0001')
self.assertEqual(copy2.name, 'MyMISC/2016/0001')
copy3 = copy2.copy({'date': copy2.date})
self.assertEqual(copy3.name, '/')
with self.assertRaises(AssertionError):
with Form(copy2) as move_form: # It is not editable in the form
move_form.name = 'MyMISC/2099/0002'
move_form.name = 'MyMISC/2016/0002'
copy3.action_post()
self.assertEqual(copy3.name, 'MyMISC/2099/0002')
self.assertEqual(copy3.name, 'MyMISC/2016/0002')
copy3.name = 'MISC2/2016/00002'
copy4 = copy2.copy({'date': copy2.date})
@@ -412,10 +412,10 @@ class TestAccountMove(AccountTestInvoicingCommon):
('JRNL/2016/00001', 'JRNL/2016/00002', 'JRNL/2016/00003', 'JRNL/2017/00001'),
('1234567', '1234568', '1234569', '1234570'),
('20190910', '20190911', '20190912', '20190913'),
('2019-0910', '2019-0911', '2019-0912', '2017-0001'),
('201909-10', '201909-11', '201604-01', '201703-01'),
('20-10-10', '20-10-11', '16-04-01', '17-03-01'),
('2010-10', '2010-11', '2010-12', '2017-01'),
('2016-0910', '2016-0911', '2016-0912', '2017-0001'),
('201603-10', '201603-11', '201604-01', '201703-01'),
('16-03-10', '16-03-11', '16-04-01', '17-03-01'),
('2016-10', '2016-11', '2016-12', '2017-01'),
('JRNL/2016/00001suffix', 'JRNL/2016/00002suffix', 'JRNL/2016/00003suffix', 'JRNL/2017/00001suffix'),
]
other_moves = self.env['account.move'].search([('journal_id', '=', self.test_move.journal_id.id)]) - self.test_move
@@ -472,6 +472,7 @@ class TestAccountMove(AccountTestInvoicingCommon):
def test_journal_override_sequence_regex(self):
other_moves = self.env['account.move'].search([('journal_id', '=', self.test_move.journal_id.id)]) - self.test_move
other_moves.unlink() # Do not interfere when trying to get the highest name for new periods
self.test_move.date = '2020-01-01'
self.test_move.name = '00000876-G 0002/2020'
next = self.test_move.copy({'date': self.test_move.date})
next.action_post()