summaryrefslogtreecommitdiff
path: root/odoo
diff options
context:
space:
mode:
authorPierre Masereel <pim@odoo.com>2019-11-15 15:38:48 +0000
committerRaphael Collet <rco@odoo.com>2019-11-22 12:34:43 +0000
commite85faf398659a5beb0b1570a06af64dcf78dc1c8 (patch)
tree2726de4e47cb5f61bfd748416f85f3fadfb6bf7d /odoo
parent8821f0e9176e3b976828f088ce5b7f5c6517b0c7 (diff)
[IMP] base: add unique constraint on ir.property
There is no unique constraint on the properties to avoid having two properties for the same field, company and res_id. Having two properties for the same field, company and res_id, leads to inconsistencies through the code, as reading a company-dependent field nondeterministically returns one of the available property value. So now, before creating a property, we have to check that there is not already a value for the field, company and res_id and write or create depending on if it is already exists. The properties of specific records already satisfy the constraint thanks to the implementation of company-dependent fields that use the method `set_multi`. We added a method `set_default` to set generic properties, and its implementation does the right thing. It also simplifies the code to set such properties, by the way. closes odoo/odoo#40473 Signed-off-by: Xavier Morel (xmo) <xmo@odoo.com> Co-authored-by: Raphael Collet <rco@odoo.com>
Diffstat (limited to 'odoo')
-rw-r--r--odoo/addons/base/models/ir_property.py38
-rw-r--r--odoo/addons/test_main_flows/tests/test_flow.py33
-rw-r--r--odoo/addons/test_new_api/tests/test_new_fields.py11
3 files changed, 48 insertions, 34 deletions
diff --git a/odoo/addons/base/models/ir_property.py b/odoo/addons/base/models/ir_property.py
index a8bab99215e..a303e6ab4f6 100644
--- a/odoo/addons/base/models/ir_property.py
+++ b/odoo/addons/base/models/ir_property.py
@@ -38,7 +38,7 @@ class Property(models.Model):
name = fields.Char(index=True)
res_id = fields.Char(string='Resource', index=True, help="If not set, acts as a default value for new resources",)
company_id = fields.Many2one('res.company', string='Company', index=True)
- fields_id = fields.Many2one('ir.model.fields', string='Field', ondelete='cascade', required=True, index=True)
+ fields_id = fields.Many2one('ir.model.fields', string='Field', ondelete='cascade', required=True)
value_float = fields.Float()
value_integer = fields.Integer()
value_text = fields.Text() # will contain (char, text)
@@ -60,6 +60,14 @@ class Property(models.Model):
default='many2one',
index=True)
+ def init(self):
+ # Ensure there is at most one active variant for each combination.
+ query = """
+ CREATE UNIQUE INDEX IF NOT EXISTS ir_property_unique_index
+ ON %s (fields_id, COALESCE(company_id, 0), COALESCE(res_id, ''))
+ """
+ self.env.cr.execute(query % self._table)
+
def _update_values(self, values):
if 'value' not in values:
return values
@@ -168,6 +176,34 @@ class Property(models.Model):
return False
@api.model
+ def set_default(self, name, model, value, company=False):
+ """ Set the given field's generic value for the given company.
+
+ :param name: the field's name
+ :param model: the field's model name
+ :param value: the field's value
+ :param company: the company (record or id)
+ """
+ field_id = self.env['ir.model.fields']._get(model, name).id
+ company_id = int(company) if company else False
+ prop = self.search([
+ ('fields_id', '=', field_id),
+ ('company_id', '=', company_id),
+ ('res_id', '=', False),
+ ])
+ if prop:
+ prop.write({'value': value})
+ else:
+ self.create({
+ 'fields_id': field_id,
+ 'company_id': company_id,
+ 'res_id': False,
+ 'name': name,
+ 'value': value,
+ 'type': self.env[model]._fields[name].type,
+ })
+
+ @api.model
def get(self, name, model, res_id=False):
if not res_id:
t, v = self._get_default_property(name, model)
diff --git a/odoo/addons/test_main_flows/tests/test_flow.py b/odoo/addons/test_main_flows/tests/test_flow.py
index fe86f8187c6..2f359d4cccc 100644
--- a/odoo/addons/test_main_flows/tests/test_flow.py
+++ b/odoo/addons/test_main_flows/tests/test_flow.py
@@ -36,32 +36,13 @@ class TestUi(odoo.tests.HttpCase):
'user_type_id': self.env.ref('account.data_account_type_liquidity').id,
})
- self.env['ir.property'].create([{
- 'name': 'property_account_receivable_id',
- 'fields_id': self.env['ir.model.fields'].search([('model', '=', 'res.partner'), ('name', '=', 'property_account_receivable_id')], limit=1).id,
- 'value': 'account.account,%s' % (a_recv.id),
- 'company_id': self.env.company.id,
- }, {
- 'name': 'property_account_payable_id',
- 'fields_id': self.env['ir.model.fields'].search([('model', '=', 'res.partner'), ('name', '=', 'property_account_payable_id')], limit=1).id,
- 'value': 'account.account,%s' % (a_pay.id),
- 'company_id': self.env.company.id,
- }, {
- 'name': 'property_account_position_id',
- 'fields_id': self.env['ir.model.fields'].search([('model', '=', 'res.partner'), ('name', '=', 'property_account_position_id')], limit=1).id,
- 'value': False,
- 'company_id': self.env.company.id,
- }, {
- 'name': 'property_account_expense_categ_id',
- 'fields_id': self.env['ir.model.fields'].search([('model', '=', 'product.category'), ('name', '=', 'property_account_expense_categ_id')], limit=1).id,
- 'value': 'account.account,%s' % (a_expense.id),
- 'company_id': self.env.company.id,
- }, {
- 'name': 'property_account_income_categ_id',
- 'fields_id': self.env['ir.model.fields'].search([('model', '=', 'product.category'), ('name', '=', 'property_account_income_categ_id')], limit=1).id,
- 'value': 'account.account,%s' % (a_sale.id),
- 'company_id': self.env.company.id,
- }])
+ Property = self.env['ir.property']
+ Property.set_default('property_account_receivable_id', 'res.partner', a_recv, self.env.company)
+ Property.set_default('property_account_payable_id', 'res.partner', a_pay, self.env.company)
+ Property.set_default('property_account_position_id', 'res.partner', False, self.env.company)
+ Property.set_default('property_account_expense_categ_id', 'product.category', a_expense, self.env.company)
+ Property.set_default('property_account_income_categ_id', 'product.category', a_sale, self.env.company)
+
self.expenses_journal = self.env['account.journal'].create({
'name': 'Vendor Bills - Test',
'code': 'TEXJ',
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 b68ae8220fb..5600affc125 100644
--- a/odoo/addons/test_new_api/tests/test_new_fields.py
+++ b/odoo/addons/test_new_api/tests/test_new_fields.py
@@ -951,12 +951,9 @@ class TestFields(TransactionCaseWithUserDemo):
tag2 = self.env['test_new_api.multi.tag'].create({'name': 'Quuz'})
# create default values for the company-dependent fields
- field_foo = self.env['ir.model.fields']._get('test_new_api.company', 'foo')
- self.env['ir.property'].create({'name': 'foo', 'fields_id': field_foo.id,
- 'value': 'default', 'type': 'char'})
- field_tag_id = self.env['ir.model.fields']._get('test_new_api.company', 'tag_id')
- self.env['ir.property'].create({'name': 'foo', 'fields_id': field_tag_id.id,
- 'value': tag0, 'type': 'many2one'})
+ self.env['ir.property'].set_default('foo', 'test_new_api.company', 'default')
+ self.env['ir.property'].set_default('foo', 'test_new_api.company', 'default1', company1)
+ self.env['ir.property'].set_default('tag_id', 'test_new_api.company', tag0)
# assumption: users don't have access to 'ir.property'
accesses = self.env['ir.model.access'].search([('model_id.model', '=', 'ir.property')])
@@ -970,7 +967,7 @@ class TestFields(TransactionCaseWithUserDemo):
'tag_id': tag1.id,
})
self.assertEqual(record.with_user(user0).foo, 'main')
- self.assertEqual(record.with_user(user1).foo, 'default')
+ self.assertEqual(record.with_user(user1).foo, 'default1')
self.assertEqual(record.with_user(user2).foo, 'default')
self.assertEqual(str(record.with_user(user0).date), '1932-11-09')
self.assertEqual(record.with_user(user1).date, False)