[FIX] account: compute name of multiple moves at the same time
Computing the name of multiple moves at the same time could lead to some errors because we don't know when the field will be flushed: 1: We can't rely on the context to compute moves, for instance when mixing payments and other moves in a bank journal. The context key has been removed as it could be useful only when the `payment_id` was not set yet, which should only happen in the Form view. But the name of payments was not editable before posting a first time(like it is for invoices) Was failing following test with only `account_reports` installed `TestReconciliationReport.test_reconciliation_report_multi_currencies` 2: There was an optimization tho avoid doing `O(n)` queries to find if the current move is the first one of the sequence (and needs to be precomputed in draft because of that). The algorithm is doing the same `SELECT` after anyways[1] or even a second one to relax the domain, followed by an `UPDATE` right after. This can't be batched and delayed because we rely on the SQL unique constraint to assign the numbers. Was failing folloing test with only `account_reports` installed `TestAgedReceivableReport.test_aged_receivable_sort_lines_by_date` The reason why it started causing issues on some test databases (only `account_reports` installed, not on a full runbot build) is still unknown. [1]: In order to reduce the number of duplicated queries, we could do it only once per tuple (journal, date range, is_refund, is_payment), but getting this tuple is not so easy and reliable without a complex implementation. It is also not really possible to cache and reuse (i.e in `highest_number`) because the value changes when other moves are posted. Part-of: odoo/odoo#110016
This commit is contained in:
@@ -667,13 +667,12 @@ class AccountMove(models.Model):
|
||||
domain = [('company_id', '=', company_id), ('type', '=', journal_type)]
|
||||
m.suitable_journal_ids = self.env['account.journal'].search(domain)
|
||||
|
||||
@api.depends('posted_before', 'state', 'journal_id', 'date', 'move_type')
|
||||
@api.depends('posted_before', 'state', 'journal_id', 'date', 'move_type', 'payment_id')
|
||||
def _compute_name(self):
|
||||
self = self.sorted(lambda m: (m.date, m.ref or '', m.id))
|
||||
highest_name = self[0]._get_last_sequence(lock=False) if self else False
|
||||
|
||||
for move in self:
|
||||
if not highest_name and move == self[0] and not move.posted_before and move.date and (not move.name or move.name == '/'):
|
||||
if not move.highest_name and not move.posted_before and move.date and (not move.name or move.name == '/'):
|
||||
# In the form view, we need to compute a default sequence so that the user can edit
|
||||
# it. We only check the first move as an approximation (enough for new in form view)
|
||||
move._set_next_sequence()
|
||||
@@ -2382,7 +2381,6 @@ class AccountMove(models.Model):
|
||||
return "WHERE FALSE", {}
|
||||
where_string = "WHERE journal_id = %(journal_id)s AND name != '/'"
|
||||
param = {'journal_id': self.journal_id.id}
|
||||
is_payment = self.payment_id or self._context.get('is_payment')
|
||||
|
||||
if not relaxed:
|
||||
domain = [('journal_id', '=', self.journal_id.id), ('id', '!=', self.id or self._origin.id), ('name', 'not in', ('/', '', False))]
|
||||
@@ -2390,7 +2388,7 @@ class AccountMove(models.Model):
|
||||
refund_types = ('out_refund', 'in_refund')
|
||||
domain += [('move_type', 'in' if self.move_type in refund_types else 'not in', refund_types)]
|
||||
if self.journal_id.payment_sequence:
|
||||
domain += [('payment_id', '!=' if is_payment else '=', False)]
|
||||
domain += [('payment_id', '!=' if self.payment_id else '=', False)]
|
||||
reference_move_name = self.search(domain + [('date', '<=', self.date)], order='date desc', limit=1).name
|
||||
if not reference_move_name:
|
||||
reference_move_name = self.search(domain, order='date asc', limit=1).name
|
||||
@@ -2414,7 +2412,7 @@ class AccountMove(models.Model):
|
||||
else:
|
||||
where_string += " AND move_type NOT IN ('out_refund', 'in_refund') "
|
||||
elif self.journal_id.payment_sequence:
|
||||
if is_payment:
|
||||
if self.payment_id:
|
||||
where_string += " AND payment_id IS NOT NULL "
|
||||
else:
|
||||
where_string += " AND payment_id IS NULL "
|
||||
@@ -2424,14 +2422,13 @@ class AccountMove(models.Model):
|
||||
def _get_starting_sequence(self):
|
||||
# EXTENDS account sequence.mixin
|
||||
self.ensure_one()
|
||||
is_payment = self.payment_id or self._context.get('is_payment')
|
||||
if self.journal_id.type in ['sale', 'bank', 'cash']:
|
||||
starting_sequence = "%s/%04d/00000" % (self.journal_id.code, self.date.year)
|
||||
else:
|
||||
starting_sequence = "%s/%04d/%02d/0000" % (self.journal_id.code, self.date.year, self.date.month)
|
||||
if self.journal_id.refund_sequence and self.move_type in ('out_refund', 'in_refund'):
|
||||
starting_sequence = "R" + starting_sequence
|
||||
if self.journal_id.payment_sequence and is_payment:
|
||||
if self.journal_id.payment_sequence and self.payment_id:
|
||||
starting_sequence = "P" + starting_sequence
|
||||
return starting_sequence
|
||||
|
||||
|
||||
@@ -670,8 +670,9 @@ class AccountPayment(models.Model):
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
def new(self, values=None, origin=None, ref=None):
|
||||
payment = super(AccountPayment, self.with_context(is_payment=True)).new(values, origin, ref)
|
||||
payment = super().new(values, origin, ref)
|
||||
if not payment.journal_id: # might not be computed because declared by inheritance
|
||||
payment.move_id.payment_id = payment
|
||||
payment.move_id._compute_journal_id()
|
||||
return payment
|
||||
|
||||
@@ -688,9 +689,11 @@ class AccountPayment(models.Model):
|
||||
# Force the move_type to avoid inconsistency with residual 'default_move_type' inside the context.
|
||||
vals['move_type'] = 'entry'
|
||||
|
||||
payments = super(AccountPayment, self.with_context(is_payment=True))\
|
||||
.create(vals_list)\
|
||||
.with_context(is_payment=False)
|
||||
payments = super().create([{
|
||||
'name': False,
|
||||
'journal_id': self.move_id.with_context(is_payment=True)._search_default_journal().id,
|
||||
**vals,
|
||||
} for vals in vals_list])
|
||||
|
||||
for i, pay in enumerate(payments):
|
||||
write_off_line_vals = write_off_line_vals_list[i]
|
||||
|
||||
Reference in New Issue
Block a user