diff --git a/odoo/addons/base/ir/ir_values.py b/odoo/addons/base/ir/ir_values.py index c1f1d4c03d7..8df8cde1d8a 100644 --- a/odoo/addons/base/ir/ir_values.py +++ b/odoo/addons/base/ir/ir_values.py @@ -4,7 +4,7 @@ from ast import literal_eval from odoo import api, fields, models, tools, _ -from odoo.exceptions import AccessError, MissingError +from odoo.exceptions import AccessError, MissingError, ValidationError from odoo.tools import pickle EXCLUDED_FIELDS = set(('code', @@ -219,6 +219,15 @@ class IrValues(models.Model): # should be company-specific, need to get company id company_id = self.env.user.company_id.id + # check consistency of model, field_name and value + try: + field = self.env[model]._fields[field_name] + field.convert_to_cache(value, self.browse()) + except KeyError: + raise ValidationError(_("Invalid field %s.%s") % (model, field_name)) + except Exception: + raise ValidationError(_("Invalid value for %s.%s: %s") % (model, field_name, value)) + # remove existing defaults for the same scope search_criteria = [ ('key', '=', 'default'), diff --git a/odoo/addons/base/tests/test_ir_values.py b/odoo/addons/base/tests/test_ir_values.py index 50fba76615b..b8aa0cdb331 100644 --- a/odoo/addons/base/tests/test_ir_values.py +++ b/odoo/addons/base/tests/test_ir_values.py @@ -1,90 +1,95 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +from odoo.exceptions import ValidationError from odoo.tests.common import TransactionCase class TestIrValues(TransactionCase): - def test_00(self): - # Create some default value for some (non-existing) model, for all users. - + def test_defaults(self): + # Create some default value for some model, for all users. ir_values = self.env['ir.values'] - # use the old API - ir_values.set_default('unexisting_model', 'my_test_field', 'global value', condition=False) - # use the new API - ir_values.set_default('other_unexisting_model', 'my_other_test_field', - 'conditional value', condition='foo=bar') + ir_values.set_default('res.partner', 'ref', 'X11') + ir_values.set_default('res.partner.title', 'shortcut', 'Mr', condition='name=Mister') - # Retrieve them. + # Retrieve them: ds is a list of triplets (id, name, value) + ds = ir_values.get_defaults('res.partner') + d = next((d for d in ds if d[1] == 'ref'), None) + self.assertTrue(d, "At least one value should be retrieved for this model.") + self.assertEqual(d[2], 'X11', "Can't retrieve the created default value.") - # d is a list of triplets (id, name, value) - # Old API - d = ir_values.get_defaults('unexisting_model', condition=False) - self.assertEqual(len(d), 1, "Only one single value should be retrieved for this model") - self.assertEqual(d[0][1], 'my_test_field', "Can't retrieve the created default value. (1)") - self.assertEqual(d[0][2], 'global value', "Can't retrieve the created default value. (2)") + ds = ir_values.get_defaults('res.partner.title') + d = next((d for d in ds if d[1] == 'shortcut'), None) + self.assertFalse(d, "No value should be retrieved, the condition is not met.") - # New API, Conditional version - d = ir_values.get_defaults('other_unexisting_model') - self.assertEqual(len(d), 0, "No value should be retrieved, the condition is not met") - d = ir_values.get_defaults('other_unexisting_model', condition="foo=eggs") - self.assertEqual(len(d), 0, 'Condition is not met either, no defaults should be returned') - d = ir_values.get_defaults('other_unexisting_model', condition="foo=bar") - self.assertEqual(len(d), 1, "Only one single value should be retrieved") - self.assertEqual(d[0][1], 'my_other_test_field', "Can't retrieve the created default value. (5)") - self.assertEqual(d[0][2], 'conditional value', "Can't retrieve the created default value. (6)") + ds = ir_values.get_defaults('res.partner.title', condition="name=Miss") + d = next((d for d in ds if d[1] == 'shortcut'), None) + self.assertFalse(d, "No value should be retrieved, the condition is not met.") + + ds = ir_values.get_defaults('res.partner.title', condition="name=Mister") + d = next((d for d in ds if d[1] == 'shortcut'), None) + self.assertTrue(d, "At least one value should be retrieved.") + self.assertEqual(d[2], 'Mr', "Can't retrieve the created default value.") # Do it again but for a specific user. - ir_values.set_default('unexisting_model', 'my_test_field', 'specific value', for_all_users=False, condition=False) + ir_values.set_default('res.partner', 'ref', '007', for_all_users=False) # Retrieve it and check it is the one for the current user. + ds = ir_values.get_defaults('res.partner') + d = next((d for d in ds if d[1] == 'ref'), None) + self.assertTrue(d, "At least one value should be retrieved for this model.") + self.assertEqual(d[2], '007', "Can't retrieve the created default value.") - d = ir_values.get_defaults('unexisting_model', condition=False) - self.assertEqual(len(d), 1, "Only one default must be returned per field") - self.assertEqual(d[0][1], 'my_test_field', "Can't retrieve the created default value.") - self.assertEqual(d[0][2], 'specific value', "Can't retrieve the created default value.") - - # Create some action bindings for a non-existing model. + # create invalid defaults + with self.assertRaises(ValidationError): + ir_values.set_default('unknown_model', 'unknown_field', 42) + with self.assertRaises(ValidationError): + ir_values.set_default('res.partner', 'unknown_field', 42) + with self.assertRaises(ValidationError): + ir_values.set_default('res.partner', 'lang', 'some_LANG') + with self.assertRaises(ValidationError): + ir_values.set_default('res.partner', 'credit_limit', 'foo') + def test_actions(self): + # Create some action bindings for a model. act_id_1 = self.ref('base.act_values_form_action') act_id_2 = self.ref('base.act_values_form_defaults') act_id_3 = self.ref('base.action_res_company_form') - ir_values.set_action('OnDblClick Action', action_slot='tree_but_open', model='unexisting_model', action='ir.actions.act_window,%d' % act_id_1, res_id=False) - ir_values.set_action('OnDblClick Action 2', action_slot='tree_but_open', model='unexisting_model', action='ir.actions.act_window,%d' % act_id_2, res_id=False) - ir_values.set_action('Side Wizard', action_slot='client_action_multi', model='unexisting_model', action='ir.actions.act_window,%d' % act_id_3, res_id=False) + ir_values = self.env['ir.values'] + ir_values.set_action('OnDblClick Action', action_slot='tree_but_open', model='res.partner', action='ir.actions.act_window,%d' % act_id_1, res_id=False) + ir_values.set_action('OnDblClick Action 2', action_slot='tree_but_open', model='res.partner', action='ir.actions.act_window,%d' % act_id_2, res_id=False) + ir_values.set_action('Side Wizard', action_slot='client_action_multi', model='res.partner', action='ir.actions.act_window,%d' % act_id_3, res_id=False) reports = self.env['ir.actions.report.xml'].search([]) report_id = next(report.id for report in reports if not report.groups_id) - ir_values.set_action('Nice Report', action_slot='client_print_multi', model='unexisting_model', action='ir.actions.report.xml,%d' % report_id, res_id=False) + ir_values.set_action('Nice Report', action_slot='client_print_multi', model='res.partner', action='ir.actions.report.xml,%d' % report_id, res_id=False) # Replace one action binding to set a new name. - - ir_values.set_action('OnDblClick Action New', action_slot='tree_but_open', model='unexisting_model', action='ir.actions.act_window,%d' % act_id_1, res_id=False) + ir_values.set_action('OnDblClick Action New', action_slot='tree_but_open', model='res.partner', action='ir.actions.act_window,%d' % act_id_1, res_id=False) # Retrieve the action bindings and check they're correct - - actions = ir_values.get_actions(action_slot='tree_but_open', model='unexisting_model', res_id=False) + actions = ir_values.get_actions(action_slot='tree_but_open', model='res.partner', res_id=False) self.assertEqual(len(actions), 2, "Mismatching number of bound actions") - #first action + # first action self.assertEqual(len(actions[0]), 3, "Malformed action definition") self.assertEqual(actions[0][1], 'OnDblClick Action 2', 'Bound action does not match definition') self.assertTrue(isinstance(actions[0][2], dict) and actions[0][2]['id'] == act_id_2, 'Bound action does not match definition') - #second action - this ones comes last because it was re-created with a different name + # second action - this ones comes last because it was re-created with a different name self.assertEqual(len(actions[1]), 3, "Malformed action definition") self.assertEqual(actions[1][1], 'OnDblClick Action New', 'Re-Registering an action should replace it') self.assertTrue(isinstance(actions[1][2], dict) and actions[1][2]['id'] == act_id_1, 'Bound action does not match definition') - actions = ir_values.get_actions(action_slot='client_action_multi', model='unexisting_model', res_id=False) + actions = ir_values.get_actions(action_slot='client_action_multi', model='res.partner', res_id=False) self.assertEqual(len(actions), 1, "Mismatching number of bound actions") self.assertEqual(len(actions[0]), 3, "Malformed action definition") self.assertEqual(actions[0][1], 'Side Wizard', 'Bound action does not match definition') self.assertTrue(isinstance(actions[0][2], dict) and actions[0][2]['id'] == act_id_3, 'Bound action does not match definition') - actions = ir_values.get_actions(action_slot='client_print_multi', model='unexisting_model', res_id=False) + actions = ir_values.get_actions(action_slot='client_print_multi', model='res.partner', res_id=False) self.assertEqual(len(actions), 1, "Mismatching number of bound actions") self.assertEqual(len(actions[0]), 3, "Malformed action definition") self.assertEqual(actions[0][1], 'Nice Report', 'Bound action does not match definition')