diff options
| author | Raphael Collet <rco@odoo.com> | 2019-04-11 08:21:54 +0000 |
|---|---|---|
| committer | Raphael Collet <rco@odoo.com> | 2019-05-23 05:47:11 +0000 |
| commit | d0bb596f1d51b72a6aa20d56eef3e65aefbd09b2 (patch) | |
| tree | 8d56a32b6f0eea496d0e9af26a4349e8979dfc37 /odoo/addons | |
| parent | 60be9f2c098cfead8a5e3fd23453b7e93243e0c5 (diff) | |
[IMP] fields: x2many fields of new records are new records
The value of an x2many field on a new record are new records, possibly
related to a real record, called its "origin".
Diffstat (limited to 'odoo/addons')
| -rw-r--r-- | odoo/addons/base/models/ir_model.py | 2 | ||||
| -rw-r--r-- | odoo/addons/base/models/res_partner.py | 8 | ||||
| -rw-r--r-- | odoo/addons/base/models/res_users.py | 14 | ||||
| -rw-r--r-- | odoo/addons/test_new_api/models.py | 1 | ||||
| -rw-r--r-- | odoo/addons/test_new_api/tests/test_new_fields.py | 158 | ||||
| -rw-r--r-- | odoo/addons/test_performance/tests/test_performance.py | 12 |
6 files changed, 180 insertions, 15 deletions
diff --git a/odoo/addons/base/models/ir_model.py b/odoo/addons/base/models/ir_model.py index 45af7c4fe4e..117d3be6d63 100644 --- a/odoo/addons/base/models/ir_model.py +++ b/odoo/addons/base/models/ir_model.py @@ -535,7 +535,7 @@ class IrModelFields(models.Model): # check whether other fields use the same table others = self.search([('ttype', '=', 'many2many'), ('relation_table', '=', self.relation_table), - ('id', 'not in', self._origin.ids)]) + ('id', 'not in', self.ids)]) if others: for other in others: if (other.model, other.relation) == (self.relation, self.model): diff --git a/odoo/addons/base/models/res_partner.py b/odoo/addons/base/models/res_partner.py index 0cf10f1ad55..fb5f0906a32 100644 --- a/odoo/addons/base/models/res_partner.py +++ b/odoo/addons/base/models/res_partner.py @@ -266,10 +266,8 @@ class Partner(models.Model): @api.depends('vat') def _compute_same_vat_partner_id(self): for partner in self: - partner_id = partner.id - if isinstance(partner_id, models.NewId): - # deal with onchange(), which is always called on a single record - partner_id = self._origin.id + # use _origin to deal with onchange() + partner_id = partner._origin.id domain = [('vat', '=', partner.vat)] if partner_id: domain += [('id', '!=', partner_id), '!', ('id', 'child_of', partner_id)] @@ -379,7 +377,7 @@ class Partner(models.Model): if not self.parent_id: return result = {} - partner = getattr(self, '_origin', self) + partner = self._origin if partner.parent_id and partner.parent_id != self.parent_id: result['warning'] = { 'title': _('Warning'), diff --git a/odoo/addons/base/models/res_users.py b/odoo/addons/base/models/res_users.py index 256e89cbb7d..f55b99bfdeb 100644 --- a/odoo/addons/base/models/res_users.py +++ b/odoo/addons/base/models/res_users.py @@ -962,15 +962,15 @@ class UsersImplied(models.Model): if 'groups_id' in values: # complete 'groups_id' with implied groups user = self.new(values) + gs = user.groups_id._origin group_public = self.env.ref('base.group_public', raise_if_not_found=False) group_portal = self.env.ref('base.group_portal', raise_if_not_found=False) - if group_public and group_public in user.groups_id: - gs = self.env.ref('base.group_public') | self.env.ref('base.group_public').trans_implied_ids - elif group_portal and group_portal in user.groups_id: - gs = self.env.ref('base.group_portal') | self.env.ref('base.group_portal').trans_implied_ids - else: - gs = user.groups_id | user.groups_id.trans_implied_ids - values['groups_id'] = type(self).groups_id.convert_to_write(gs, user.groups_id) + if group_public and group_public in gs: + gs = group_public + elif group_portal and group_portal in gs: + gs = group_portal + gs = gs | gs.trans_implied_ids + values['groups_id'] = type(self).groups_id.convert_to_write(gs, user) return super(UsersImplied, self).create(vals_list) @api.multi diff --git a/odoo/addons/test_new_api/models.py b/odoo/addons/test_new_api/models.py index e6ad747097d..31e8e9eeeb1 100644 --- a/odoo/addons/test_new_api/models.py +++ b/odoo/addons/test_new_api/models.py @@ -214,6 +214,7 @@ class Multi(models.Model): name = fields.Char(related='partner.name', readonly=True) partner = fields.Many2one('res.partner') lines = fields.One2many('test_new_api.multi.line', 'multi') + partners = fields.One2many(related='partner.child_ids') @api.onchange('name') def _onchange_name(self): 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 de9bc11dcaf..c83704dbbe3 100644 --- a/odoo/addons/test_new_api/tests/test_new_fields.py +++ b/odoo/addons/test_new_api/tests/test_new_fields.py @@ -956,10 +956,154 @@ class TestFields(common.TransactionCase): 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) + self.assertEqual(new_disc.categories._origin, cat1) # value is combined with default value new_disc = discussion.new({'name': "Foo", 'categories': [(4, cat2.id)]}) - self.assertEqual(new_disc.categories, cat1 + cat2) + self.assertEqual(new_disc.categories._origin, cat1 + cat2) + + def test_40_new_fields(self): + """ Test new records with relational fields. """ + # create a new discussion with all kinds of relational fields + msg0 = self.env['test_new_api.message'].create({'body': "XXX"}) + msg1 = self.env['test_new_api.message'].create({'body': "WWW"}) + cat0 = self.env['test_new_api.category'].create({'name': 'AAA'}) + cat1 = self.env['test_new_api.category'].create({'name': 'DDD'}) + new_disc = self.env['test_new_api.discussion'].new({ + 'name': "Stuff", + 'moderator': self.env.uid, + 'messages': [ + (4, msg0.id), + (4, msg1.id), (1, msg1.id, {'body': "YYY"}), + (0, 0, {'body': "ZZZ"}) + ], + 'categories': [ + (4, cat0.id), + (4, cat1.id), (1, cat1.id, {'name': "BBB"}), + (0, 0, {'name': "CCC"}) + ], + }) + self.assertFalse(new_disc.id) + + # many2one field values are actual records + self.assertEqual(new_disc.moderator.id, self.env.uid) + + # x2many fields values are new records + new_msg0, new_msg1, new_msg2 = new_disc.messages + self.assertFalse(new_msg0.id) + self.assertFalse(new_msg1.id) + self.assertFalse(new_msg2.id) + + new_cat0, new_cat1, new_cat2 = new_disc.categories + self.assertFalse(new_cat0.id) + self.assertFalse(new_cat1.id) + self.assertFalse(new_cat2.id) + + # the x2many has its inverse field set + self.assertEqual(new_msg0.discussion, new_disc) + self.assertEqual(new_msg1.discussion, new_disc) + self.assertEqual(new_msg2.discussion, new_disc) + + self.assertFalse(msg0.discussion) + self.assertFalse(msg1.discussion) + + self.assertEqual(new_cat0.discussions, new_disc) # add other discussions + self.assertEqual(new_cat1.discussions, new_disc) + self.assertEqual(new_cat2.discussions, new_disc) + + self.assertNotIn(new_disc, cat0.discussions) + self.assertNotIn(new_disc, cat1.discussions) + + # new lines are connected to their origin + self.assertEqual(new_msg0._origin, msg0) + self.assertEqual(new_msg1._origin, msg1) + self.assertFalse(new_msg2._origin) + + self.assertEqual(new_cat0._origin, cat0) + self.assertEqual(new_cat1._origin, cat1) + self.assertFalse(new_cat2._origin) + + # the field values are either specific, or the same as the origin + self.assertEqual(new_msg0.body, "XXX") + self.assertEqual(new_msg1.body, "YYY") + self.assertEqual(new_msg2.body, "ZZZ") + + self.assertEqual(msg0.body, "XXX") + self.assertEqual(msg1.body, "WWW") + + self.assertEqual(new_cat0.name, "AAA") + self.assertEqual(new_cat1.name, "BBB") + self.assertEqual(new_cat2.name, "CCC") + + self.assertEqual(cat0.name, "AAA") + self.assertEqual(cat1.name, "DDD") + + # special case for many2one fields that define _inherits + new_email = self.env['test_new_api.emailmessage'].new({'body': "XXX"}) + self.assertFalse(new_email.id) + self.assertTrue(new_email.message) + self.assertFalse(new_email.message.id) + self.assertEqual(new_email.body, "XXX") + + new_email = self.env['test_new_api.emailmessage'].new({'message': msg0.id}) + self.assertFalse(new_email.id) + self.assertFalse(new_email._origin) + self.assertFalse(new_email.message.id) + self.assertEqual(new_email.message._origin, msg0) + self.assertEqual(new_email.body, "XXX") + + def test_40_new_ref_origin(self): + """ Test the behavior of new records with ref/origin. """ + Discussion = self.env['test_new_api.discussion'] + new = Discussion.new + + # new records with identical/different refs + xs = new() + new(ref='a') + new(ref='b') + new(ref='b') + self.assertEqual([x == y for x in xs for y in xs], [ + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 1, + 0, 0, 1, 1, + ]) + for x in xs: + self.assertFalse(x._origin) + + # new records with identical/different origins + a, b = Discussion.create([{'name': "A"}, {'name': "B"}]) + xs = new() + new(origin=a) + new(origin=b) + new(origin=b) + self.assertEqual([x == y for x in xs for y in xs], [ + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 1, + 0, 0, 1, 1, + ]) + self.assertFalse(xs[0]._origin) + self.assertEqual(xs[1]._origin, a) + self.assertEqual(xs[2]._origin, b) + self.assertEqual(xs[3]._origin, b) + self.assertEqual(xs._origin, a + b + b) + self.assertEqual(xs._origin._origin, a + b + b) + + # new records with refs and origins + x1 = new(ref='a') + x2 = new(origin=b) + self.assertNotEqual(x1, x2) + + # new discussion based on existing discussion + disc = self.env.ref('test_new_api.discussion_0') + new_disc = disc.new(origin=disc) + self.assertFalse(new_disc.id) + self.assertEqual(new_disc._origin, disc) + self.assertEqual(new_disc.name, disc.name) + # many2one field + self.assertEqual(new_disc.moderator, disc.moderator) + # one2many field + self.assertTrue(new_disc.messages) + self.assertNotEqual(new_disc.messages, disc.messages) + self.assertEqual(new_disc.messages._origin, disc.messages) + # many2many field + self.assertTrue(new_disc.participants) + self.assertNotEqual(new_disc.participants, disc.participants) + self.assertEqual(new_disc.participants._origin, disc.participants) @mute_logger('odoo.addons.base.models.ir_model') def test_41_new_related(self): @@ -1005,6 +1149,16 @@ class TestFields(common.TransactionCase): self.assertNotEqual(message.sudo().env, message.env) self.assertEqual(message.discussion_name, discussion.name) + def test_43_new_related(self): + """ test the behavior of one2many related fields """ + partner = self.env['res.partner'].create({ + 'name': 'Foo', + 'child_ids': [(0, 0, {'name': 'Bar'})], + }) + multi = self.env['test_new_api.multi'].new() + multi.partner = partner + self.assertEqual(multi.partners.mapped('name'), ['Bar']) + def test_50_defaults(self): """ test default values. """ fields = ['discussion', 'body', 'author', 'size'] diff --git a/odoo/addons/test_performance/tests/test_performance.py b/odoo/addons/test_performance/tests/test_performance.py index 7ea5fbcdadc..c05a62cc4d9 100644 --- a/odoo/addons/test_performance/tests/test_performance.py +++ b/odoo/addons/test_performance/tests/test_performance.py @@ -355,14 +355,26 @@ class TestPerformance(TransactionCase): ) records = self.env['test_performance.base'].search([]) self.assertEqual(len(records), 1280) + # should only cause 2 queries thanks to prefetching with self.assertQueryCount(__system__=2, demo=2): records.mapped('value') + records.invalidate_cache(['value']) + with self.assertQueryCount(__system__=2, demo=2): + records.mapped('value') + records.invalidate_cache(['value']) + with self.assertQueryCount(__system__=2, demo=2): + new_recs = records.browse(records.new(origin=record).id for record in records) + new_recs.mapped('value') + + records.invalidate_cache(['value']) with self.assertQueryCount(__system__=2, demo=2): with self.env.do_in_onchange(): records.mapped('value') + + # clean up after each pass self.env.cr.execute( 'delete from test_performance_base where id not in %s', (tuple(initial_records.ids),) |
