From 960cd72774110b48ad3fed4b41d68c3537e5902a Mon Sep 17 00:00:00 2001 From: Raphael Collet Date: Fri, 19 Mar 2021 11:57:59 +0000 Subject: [PATCH] [REF] core: add method get_currency_field() on Monetary to retrieve it This replaces the setup of the attribute 'currency_field', which depends on the presence of other fields on the model, and may therefore vary from one registry to another. This is necessary to make monetary fields shareable across registries. --- addons/account/models/account_move.py | 4 +- .../website/models/website_snippet_filter.py | 2 +- odoo/addons/base/models/ir_qweb_fields.py | 4 +- .../test_new_api/tests/test_new_fields.py | 20 ++++++---- odoo/fields.py | 39 ++++++++++--------- odoo/tests/common.py | 2 +- 6 files changed, 39 insertions(+), 32 deletions(-) diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index 3f2c99ef5f4..f2204edb6c4 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -355,8 +355,8 @@ class AccountMove(models.Model): return current_ids != after_write_ids if field.type == 'one2many': return True - if field.type == 'monetary' and record[field.currency_field]: - return not record[field.currency_field].is_zero(record[field_name] - vals[field_name]) + if field.type == 'monetary' and record[field.get_currency_field(record)]: + return not record[field.get_currency_field(record)].is_zero(record[field_name] - vals[field_name]) if field.type == 'float': record_value = field.convert_to_cache(record[field_name], record) to_write_value = field.convert_to_cache(vals[field_name], record) diff --git a/addons/website/models/website_snippet_filter.py b/addons/website/models/website_snippet_filter.py index 5896eabb001..6f0d0e8b83e 100644 --- a/addons/website/models/website_snippet_filter.py +++ b/addons/website/models/website_snippet_filter.py @@ -241,7 +241,7 @@ class WebsiteSnippetFilter(models.Model): elif field_widget == 'monetary': model_currency = None if field and field.type == 'monetary': - model_currency = record[record[field_name].currency_field] + model_currency = record[field.get_currency_field(record)] elif 'currency_id' in model._fields: model_currency = record['currency_id'] if model_currency: diff --git a/odoo/addons/base/models/ir_qweb_fields.py b/odoo/addons/base/models/ir_qweb_fields.py index 42fdbf9dd3c..51ae5a88f62 100644 --- a/odoo/addons/base/models/ir_qweb_fields.py +++ b/odoo/addons/base/models/ir_qweb_fields.py @@ -460,8 +460,8 @@ class MonetaryConverter(models.AbstractModel): #currency should be specified by monetary field field = record._fields[field_name] - if not options.get('display_currency') and field.type == 'monetary' and field.currency_field: - options['display_currency'] = record[field.currency_field] + if not options.get('display_currency') and field.type == 'monetary' and field.get_currency_field(record): + options['display_currency'] = record[field.get_currency_field(record)] if not options.get('display_currency'): # search on the model if they are a res.currency field to set as default fields = record._fields.items() diff --git a/odoo/addons/test_new_api/tests/test_new_fields.py b/odoo/addons/test_new_api/tests/test_new_fields.py index 841db4520e1..b461d4ac201 100644 --- a/odoo/addons/test_new_api/tests/test_new_fields.py +++ b/odoo/addons/test_new_api/tests/test_new_fields.py @@ -2042,22 +2042,26 @@ class TestFields(TransactionCaseWithUserDemo): def test_93_monetary_related(self): """ Check the currency field on related monetary fields. """ # check base field - field = self.env['test_new_api.monetary_base']._fields['amount'] - self.assertEqual(field.currency_field, 'base_currency_id') + model = self.env['test_new_api.monetary_base'] + field = model._fields['amount'] + self.assertEqual(field.get_currency_field(model), 'base_currency_id') # related fields must use the field 'currency_id' or 'x_currency_id' - field = self.env['test_new_api.monetary_related']._fields['amount'] + model = self.env['test_new_api.monetary_related'] + field = model._fields['amount'] self.assertEqual(field.related, ('monetary_id', 'amount')) - self.assertEqual(field.currency_field, 'currency_id') + self.assertEqual(field.get_currency_field(model), 'currency_id') - field = self.env['test_new_api.monetary_custom']._fields['x_amount'] + model = self.env['test_new_api.monetary_custom'] + field = model._fields['x_amount'] self.assertEqual(field.related, ('monetary_id', 'amount')) - self.assertEqual(field.currency_field, 'x_currency_id') + self.assertEqual(field.get_currency_field(model), 'x_currency_id') # inherited field must use the same field as its parent field - field = self.env['test_new_api.monetary_inherits']._fields['amount'] + model = self.env['test_new_api.monetary_inherits'] + field = model._fields['amount'] self.assertEqual(field.related, ('monetary_id', 'amount')) - self.assertEqual(field.currency_field, 'base_currency_id') + self.assertEqual(field.get_currency_field(model), 'base_currency_id') def test_94_image(self): f = io.BytesIO() diff --git a/odoo/fields.py b/odoo/fields.py index 093038bab38..06a1d4af3bf 100644 --- a/odoo/fields.py +++ b/odoo/fields.py @@ -1422,40 +1422,42 @@ class Monetary(Field): def __init__(self, string=Default, currency_field=Default, **kwargs): super(Monetary, self).__init__(string=string, currency_field=currency_field, **kwargs) - _description_currency_field = property(attrgetter('currency_field')) + def _description_currency_field(self, env): + return self.get_currency_field(env[self.model_name]) - def _setup_currency_field(self, model): - if not self.currency_field: - # pick a default, trying in order: 'currency_id', 'x_currency_id' - if 'currency_id' in model._fields: - self.currency_field = 'currency_id' - elif 'x_currency_id' in model._fields: - self.currency_field = 'x_currency_id' - assert self.currency_field in model._fields, \ - "Field %s with unknown currency_field %r" % (self, self.currency_field) + def get_currency_field(self, model): + """ Return the name of the currency field. """ + return self.currency_field or ( + 'currency_id' if 'currency_id' in model._fields else + 'x_currency_id' if 'x_currency_id' in model._fields else + None + ) def setup_nonrelated(self, model): super().setup_nonrelated(model) - self._setup_currency_field(model) + assert self.get_currency_field(model) in model._fields, \ + "Field %s with unknown currency_field %r" % (self, self.get_currency_field(model)) def setup_related(self, model): super().setup_related(model) if self.inherited: - self.currency_field = self.related_field.currency_field - self._setup_currency_field(model) + self.currency_field = self.related_field.get_currency_field(model.env[self.related_field.model_name]) + assert self.get_currency_field(model) in model._fields, \ + "Field %s with unknown currency_field %r" % (self, self.get_currency_field(model)) def convert_to_column(self, value, record, values=None, validate=True): # retrieve currency from values or record - if values and self.currency_field in values: - field = record._fields[self.currency_field] - currency = field.convert_to_cache(values[self.currency_field], record, validate) + currency_field = self.get_currency_field(record) + if values and currency_field in values: + field = record._fields[currency_field] + currency = field.convert_to_cache(values[currency_field], record, validate) currency = field.convert_to_record(currency, record) else: # Note: this is wrong if 'record' is several records with different # currencies, which is functional nonsense and should not happen # BEWARE: do not prefetch other fields, because 'value' may be in # cache, and would be overridden by the value read from database! - currency = record[:1].with_context(prefetch_fields=False)[self.currency_field] + currency = record[:1].with_context(prefetch_fields=False)[currency_field] value = float(value or 0.0) if currency: @@ -1470,7 +1472,8 @@ class Monetary(Field): # a function or related field! # BEWARE: do not prefetch other fields, because 'value' may be in # cache, and would be overridden by the value read from database! - currency = record.sudo().with_context(prefetch_fields=False)[self.currency_field] + currency_field = self.get_currency_field(record) + currency = record.sudo().with_context(prefetch_fields=False)[currency_field] if len(currency) > 1: raise ValueError("Got multiple currencies while assigning values of monetary field %s" % str(self)) elif currency: diff --git a/odoo/tests/common.py b/odoo/tests/common.py index e00f84411db..7e7e80fedda 100644 --- a/odoo/tests/common.py +++ b/odoo/tests/common.py @@ -540,7 +540,7 @@ class BaseCase(unittest.TestCase, metaclass=MetaCase): field_type = field.type if field_type == 'monetary': # Compare monetary field. - currency_field_name = record._fields[field_name].currency_field + currency_field_name = record._fields[field_name].get_currency_field(record) record_currency = record[currency_field_name] if field_name not in candidate: diff[field_name] = (record_value, None)