[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.
This commit is contained in:
Raphael Collet
2021-05-03 12:33:29 +00:00
parent 34d6f87d54
commit 960cd72774
6 changed files with 39 additions and 32 deletions
+2 -2
View File
@@ -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)
@@ -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:
+2 -2
View File
@@ -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()
@@ -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()
+21 -18
View File
@@ -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:
+1 -1
View File
@@ -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)