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 578ad04d6f1..de9bc11dcaf 100644 --- a/odoo/addons/test_new_api/tests/test_new_fields.py +++ b/odoo/addons/test_new_api/tests/test_new_fields.py @@ -928,25 +928,38 @@ class TestFields(common.TransactionCase): with self.assertRaises(AccessError): cat1.name - def test_40_new(self): - """ test new records. """ + def test_40_new_defaults(self): + """ Test new records with defaults. """ + user = self.env.user discussion = self.env.ref('test_new_api.discussion_0') - # create a new message - message = self.env['test_new_api.message'].new() - self.assertFalse(message.id) + # create a new message; fields have their default value if not given + new_msg = self.env['test_new_api.message'].new({'body': "XXX"}) + self.assertFalse(new_msg.id) + self.assertEqual(new_msg.body, "XXX") + self.assertEqual(new_msg.author, user) # assign some fields; should have no side effect - message.discussion = discussion - message.body = BODY = "May the Force be with you." - self.assertEqual(message.discussion, discussion) - self.assertEqual(message.body, BODY) - self.assertFalse(message.author) - self.assertNotIn(message, discussion.messages) + new_msg.discussion = discussion + new_msg.body = "YYY" + self.assertEqual(new_msg.discussion, discussion) + self.assertEqual(new_msg.body, "YYY") + self.assertNotIn(new_msg, discussion.messages) # check computed values of fields - self.assertEqual(message.name, "[%s] %s" % (discussion.name, '')) - self.assertEqual(message.size, len(BODY)) + self.assertEqual(new_msg.name, "[%s] %s" % (discussion.name, user.name)) + self.assertEqual(new_msg.size, 3) + + # extra tests for x2many fields with default + cat1 = self.env['test_new_api.category'].create({'name': "Cat1"}) + cat2 = self.env['test_new_api.category'].create({'name': "Cat2"}) + discussion = discussion.with_context(default_categories=[(4, cat1.id)]) + # no value gives the default value + new_disc = discussion.new({'name': "Foo"}) + self.assertEqual(new_disc.categories, cat1) + # value is combined with default value + new_disc = discussion.new({'name': "Foo", 'categories': [(4, cat2.id)]}) + self.assertEqual(new_disc.categories, cat1 + cat2) @mute_logger('odoo.addons.base.models.ir_model') def test_41_new_related(self): diff --git a/odoo/fields.py b/odoo/fields.py index db533ecbb51..25cdcfe1adb 100644 --- a/odoo/fields.py +++ b/odoo/fields.py @@ -1116,12 +1116,20 @@ class Field(MetaField('DummyField', (object,), {})): def determine_draft_value(self, record): """ Determine the value of ``self`` for the given draft ``record``. """ if self.compute: - fields = record._field_computed[self] - with record.env.protecting(fields, record): - self._compute_value(record) - else: - null = self.convert_to_cache(False, record, validate=False) - record.env.cache.set_special(record, self, lambda: null) + return self.compute_value(record) + + null = self.convert_to_cache(False, record, validate=False) + record.env.cache.set_special(record, self, lambda: null) + + defaults = record.default_get([self.name]) + if self.name in defaults: + # The null value above is necessary to convert x2many field values. + # For instance, converting [(4, id)] accesses the field's current + # value, then adds the given id. Without an initial value, the + # conversion ends up here to determine the field's value, and this + # generates an infinite recursion. + value = self.convert_to_cache(defaults[self.name], record) + return record.env.cache.set(record, self, value) def determine_inverse(self, records): """ Given the value of ``self`` on ``records``, inverse the computation. """