[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:
@@ -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)
|
||||
|
||||
@@ -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']:
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user