[FIX] account: protect currency recompute without blocking completely

The previous fix[^1] was preventing the recomputation of the currency as
soon as there was one set.
For instance, the currency wouldn't change if we changed the journal
for one with another currency.

[^1]: 7f7743470ac1309d5e047563d06362e54edb552a

closes odoo/odoo#125671

X-original-commit: 9f8bd34818414698f9b3fd9fe926659781c13c67
Signed-off-by: John Laterre (jol) <jol@odoo.com>
Signed-off-by: William André (wan) <wan@odoo.com>
This commit is contained in:
william-andre
2023-06-20 01:34:42 +02:00
parent fa0f687337
commit 355dea8b83
2 changed files with 77 additions and 22 deletions
+39 -20
View File
@@ -142,7 +142,7 @@ class AccountMove(models.Model):
journal_id = fields.Many2one(
'account.journal',
string='Journal',
compute='_compute_journal_id', store=True, readonly=False, precompute=True,
compute='_compute_journal_id', inverse='_inverse_journal_id', store=True, readonly=False, precompute=True,
required=True,
states={'draft': [('readonly', False)]},
check_company=True,
@@ -660,10 +660,6 @@ class AccountMove(models.Model):
def _compute_journal_id(self):
for record in self.filtered(lambda r: r.journal_id.type not in r._get_valid_journal_types()):
record.journal_id = record._search_default_journal()
if not record.company_id or record.company_id != record.journal_id.company_id:
self.env.add_to_compute(self._fields['company_id'], record)
if not record.currency_id or record.journal_id.currency_id and record.currency_id != record.journal_id.currency_id:
self.env.add_to_compute(self._fields['currency_id'], record)
def _get_valid_journal_types(self):
if self.is_sale_document(include_receipts=True):
@@ -687,10 +683,13 @@ class AccountMove(models.Model):
domain = [('company_id', '=', company_id), ('type', 'in', journal_types)]
journal = None
currency_id = self.currency_id.id or self._context.get('default_currency_id')
if currency_id and currency_id != self.company_id.currency_id.id:
currency_domain = domain + [('currency_id', '=', currency_id)]
journal = self.env['account.journal'].search(currency_domain, limit=1)
# the currency is not a hard dependence, it triggers via manual add_to_compute
# avoid computing the currency before all it's dependences are set (like the journal...)
if self.env.cache.contains(self, self._fields['currency_id']):
currency_id = self.currency_id.id or self._context.get('default_currency_id')
if currency_id and currency_id != self.company_id.currency_id.id:
currency_domain = domain + [('currency_id', '=', currency_id)]
journal = self.env['account.journal'].search(currency_domain, limit=1)
if not journal:
journal = self.env['account.journal'].search(domain, limit=1)
@@ -847,8 +846,7 @@ class AccountMove(models.Model):
def _compute_currency_id(self):
for invoice in self:
currency = (
invoice.currency_id
or invoice.statement_line_id.foreign_currency_id
invoice.statement_line_id.foreign_currency_id
or invoice.journal_id.currency_id
or invoice.journal_id.company_id.currency_id
)
@@ -1589,15 +1587,27 @@ class AccountMove(models.Model):
@api.onchange('company_id')
def _inverse_company_id(self):
for move in self:
if move.journal_id.company_id != move.company_id:
self.env.add_to_compute(self._fields['journal_id'], move)
self._conditional_add_to_compute('journal_id', lambda m: (
m.journal_id.company_id != m.company_id
))
@api.onchange('currency_id')
def _inverse_currency_id(self):
for invoice in self:
if invoice.journal_id.currency_id and invoice.journal_id.currency_id != invoice.currency_id:
self.env.add_to_compute(self._fields['journal_id'], invoice)
self._conditional_add_to_compute('journal_id', lambda m: (
m.journal_id.currency_id
and m.journal_id.currency_id != m.currency_id
))
@api.onchange('journal_id')
def _inverse_journal_id(self):
self._conditional_add_to_compute('company_id', lambda m: (
not m.company_id
or m.company_id != m.journal_id.company_id
))
self._conditional_add_to_compute('currency_id', lambda m: (
not m.currency_id
or m.journal_id.currency_id and m.currency_id != m.journal_id.currency_id
))
def _inverse_payment_reference(self):
self.line_ids._conditional_add_to_compute('name', lambda line: (
@@ -2313,8 +2323,13 @@ class AccountMove(models.Model):
raise UserError(_('The Journal Entry sequence is not conform to the current format. Only the Accountant can change it.'))
move.journal_id.sequence_override_regex = False
to_protect = []
for fname in vals:
field = self._fields[fname]
if field.compute and not field.readonly:
to_protect.append(field)
container = {'records': self}
with self._check_balanced(container):
with self.env.protecting(to_protect, self), self._check_balanced(container):
with self._sync_dynamic_lines(container):
res = super(AccountMove, self.with_context(
skip_account_move_synchronization=True,
@@ -2377,7 +2392,10 @@ class AccountMove(models.Model):
# del values[to_del]
# KeyError: 'line_ids'
values.pop(to_del, None)
return super().onchange(values, field_name, field_onchange)
if field_name and not isinstance(field_name, list):
field_name = [field_name]
with self.env.protecting([self._fields[fname] for fname in field_name or []], self):
return super().onchange(values, field_name, field_onchange)
# -------------------------------------------------------------------------
# RECONCILIATION METHODS
@@ -4352,7 +4370,8 @@ class AccountMove(models.Model):
field = self._fields[fname]
to_reset = self.filtered(lambda move:
condition(move)
and not self.env.is_protected(field, move)
and not self.env.is_protected(field, move._origin)
and (move._origin or not move[fname])
)
to_reset.invalidate_recordset([fname])
self.env.add_to_compute(field, to_reset)
@@ -3438,15 +3438,51 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon):
self.assertEqual(move.currency_id, self.currency_data['currency'])
self.assertRecordValues(move.line_ids, [
{
'display_type': 'product',
'currency_id': self.currency_data['currency'].id,
'debit': 0.0,
'credit': self.currency_data['currency']._convert(750.0, self.company_data['currency'], self.env.company, fields.Date.today()),
'credit': 375.0,
},
{
'debit': self.currency_data['currency']._convert(750.0, self.company_data['currency'], self.env.company, fields.Date.today()),
'display_type': 'payment_term',
'currency_id': self.currency_data['currency'].id,
'debit': 375.0,
'credit': 0.0,
},
])
move.currency_id = self.company_data['currency']
with Form(move) as move_form:
move_form.currency_id = self.currency_data['currency']
self.assertEqual(move.currency_id, self.currency_data['currency'])
with Form(self.env['account.move'].with_context(default_move_type='out_invoice')) as move_form:
move_form.currency_id = self.currency_data['currency']
self.assertEqual(move_form.currency_id, self.currency_data['currency'])
def test_change_journal_currency(self):
second_journal = self.company_data['default_journal_sale'].copy({
'currency_id': self.currency_data['currency'].id,
})
move = self.env['account.move'].create({
'move_type': 'out_invoice',
'partner_id': self.partner_a.id,
'journal_id': self.company_data['default_journal_sale'].id,
'invoice_line_ids': [
Command.create({
'name': 'My super product.',
'quantity': 1.0,
'price_unit': 750.0,
'account_id': self.product_a.property_account_income_id.id,
'tax_ids': False,
})
],
})
self.assertEqual(move.currency_id, self.company_data['currency'])
move.journal_id = second_journal
self.assertEqual(move.currency_id, self.currency_data['currency'])
@freeze_time('2019-01-01')
def test_date_reversal_exchange_move(self):
"""