diff --git a/openerp/addons/base/ir/ir.xml b/openerp/addons/base/ir/ir.xml index 877de335dcc..7e8a6c481b0 100644 --- a/openerp/addons/base/ir/ir.xml +++ b/openerp/addons/base/ir/ir.xml @@ -219,7 +219,7 @@ {'active_test': False} - + @@ -1574,7 +1574,7 @@ - + @@ -1950,7 +1950,7 @@ form The configuration wizards are used to help you configure a new instance of OpenERP. They are launched during the installation of new modules, but you can choose to restart some wizards manually from this menu. - - + diff --git a/openerp/addons/base/ir/ir_values.py b/openerp/addons/base/ir/ir_values.py index 2a33e0c73c4..7af11789225 100644 --- a/openerp/addons/base/ir/ir_values.py +++ b/openerp/addons/base/ir/ir_values.py @@ -251,6 +251,21 @@ class ir_values(osv.osv): 'company_id': company_id, }) + def get_default(self, cr, uid, model, field_name, for_all_users=True, company_id=False, condition=False): + """ Return the default value defined for model, field_name, users, company and condition. + Return ``None`` if no such default exists. + """ + search_criteria = [ + ('key', '=', 'default'), + ('key2', '=', condition and condition[:200]), + ('model', '=', model), + ('name', '=', field_name), + ('user_id', '=', False if for_all_users else uid), + ('company_id','=', company_id) + ] + defaults = self.browse(cr, uid, self.search(cr, uid, search_criteria)) + return pickle.loads(defaults[0].value.encode('utf-8')) if defaults else None + def get_defaults(self, cr, uid, model, condition=False): """Returns any default values that are defined for the current model and user, (and match ``condition``, if specified), previously registered via diff --git a/openerp/addons/base/module/module.py b/openerp/addons/base/module/module.py index acf22923d14..c6342307867 100644 --- a/openerp/addons/base/module/module.py +++ b/openerp/addons/base/module/module.py @@ -69,6 +69,7 @@ class module_category(osv.osv): 'description' : fields.text("Description", translate=True), 'sequence' : fields.integer('Sequence'), 'visible' : fields.boolean('Visible'), + 'xml_id': fields.function(osv.osv.get_external_id, type='char', size=128, string="External ID"), } _order = 'name' diff --git a/openerp/addons/base/res/ir_property_view.xml b/openerp/addons/base/res/ir_property_view.xml index b793c090491..d0292576199 100644 --- a/openerp/addons/base/res/ir_property_view.xml +++ b/openerp/addons/base/res/ir_property_view.xml @@ -75,7 +75,7 @@ form - + diff --git a/openerp/addons/base/res/res_config.py b/openerp/addons/base/res/res_config.py index 2054badb41c..0b348da3d74 100644 --- a/openerp/addons/base/res/res_config.py +++ b/openerp/addons/base/res/res_config.py @@ -396,4 +396,162 @@ class ir_actions_configuration_wizard(osv.osv_memory): ir_actions_configuration_wizard() + + +class res_config_settings(osv.osv_memory): + """ Base configuration wizard for application settings. It provides support for setting + default values, assigning groups to employee users, and installing modules. + To make such a 'settings' wizard, define a model like:: + + class my_config_wizard(osv.osv_memory): + _name = 'my.settings' + _inherit = 'res.config.settings' + _columns = { + 'default_foo': fields.type(..., default_model='my.model'), + 'group_bar': fields.boolean(..., group='base.group_user', implied_group='my.group'), + 'module_baz': fields.boolean(...), + 'other_field': fields.type(...), + } + + The method ``execute`` provides some support based on a naming convention: + + * For a field like 'default_XXX', ``execute`` sets the (global) default value of + the field 'XXX' in the model named by ``default_model`` to the field's value. + + * For a boolean field like 'group_XXX', ``execute`` adds/removes 'implied_group' + to/from the implied groups of 'group', depending on the field's value. + By default 'group' is the group Employee. Groups are given by their xml id. + + * For a boolean field like 'module_XXX', ``execute`` triggers the immediate + installation of the module named 'XXX' if the field has value ``True``. + + * For the other fields, the method ``execute`` invokes all methods with a name + that starts with 'set_'; such methods can be defined to implement the effect + of those fields. + + The method ``default_get`` retrieves values that reflect the current status of the + fields like 'default_XXX', 'group_XXX' and 'module_XXX'. It also invokes all methods + with a name that starts with 'get_default_'; such methods can be defined to provide + current values for other fields. + """ + _name = 'res.config.settings' + + def copy(self, cr, uid, id, values, context=None): + raise osv.except_osv(_("Cannot duplicate configuration!"), "") + + def _get_classified_fields(self, cr, uid, context=None): + """ return a dictionary with the fields classified by category:: + + { 'default': [('default_foo', 'model', 'foo'), ...], + 'group': [('group_bar', browse_group, browse_implied_group), ...], + 'module': [('module_baz', browse_module), ...], + 'other': ['other_field', ...], + } + """ + ir_model_data = self.pool.get('ir.model.data') + ir_module = self.pool.get('ir.module.module') + def ref(xml_id): + mod, xml = xml_id.split('.', 1) + return ir_model_data.get_object(cr, uid, mod, xml, context) + + defaults, groups, modules, others = [], [], [], [] + for name, field in self._columns.items(): + if name.startswith('default_') and hasattr(field, 'default_model'): + defaults.append((name, field.default_model, name[8:])) + elif name.startswith('group_') and isinstance(field, fields.boolean) and hasattr(field, 'implied_group'): + field_group = getattr(field, 'group', 'base.group_user') + groups.append((name, ref(field_group), ref(field.implied_group))) + elif name.startswith('module_') and isinstance(field, fields.boolean): + mod_ids = ir_module.search(cr, uid, [('name', '=', name[7:])]) + modules.append((name, ir_module.browse(cr, uid, mod_ids[0], context))) + else: + others.append(name) + + return {'default': defaults, 'group': groups, 'module': modules, 'other': others} + + def default_get(self, cr, uid, fields, context=None): + ir_values = self.pool.get('ir.values') + classified = self._get_classified_fields(cr, uid, context) + + res = super(res_config_settings, self).default_get(cr, uid, fields, context) + + # defaults: take the corresponding default value they set + for name, model, field in classified['default']: + value = ir_values.get_default(cr, uid, model, field) + if value is not None: + res[name] = value + + # groups: which groups are implied by the group Employee + for name, group, implied_group in classified['group']: + res[name] = implied_group in group.implied_ids + + # modules: which modules are installed/to install + for name, module in classified['module']: + res[name] = module.state in ('installed', 'to install', 'to upgrade') + + # other fields: call all methods that start with 'get_default_' + for method in dir(self): + if method.startswith('get_default_'): + res.update(getattr(self, method)(cr, uid, fields, context)) + + return res + + def fields_get(self, cr, uid, allfields=None, context=None, write_access=True): + # overridden to make fields of installed modules readonly + res = super(res_config_settings, self).fields_get(cr, uid, allfields, context, write_access) + classified = self._get_classified_fields(cr, uid, context) + for name, module in classified['module']: + if name in res and module.state in ('installed', 'to install', 'to upgrade'): + res[name]['readonly'] = True + return res + + def execute(self, cr, uid, ids, context=None): + ir_values = self.pool.get('ir.values') + ir_model_data = self.pool.get('ir.model.data') + ir_module = self.pool.get('ir.module.module') + res_groups = self.pool.get('res.groups') + classified = self._get_classified_fields(cr, uid, context) + + config = self.browse(cr, uid, ids[0], context) + + # default values fields + for name, model, field in classified['default']: + ir_values.set_default(cr, uid, model, field, config[name]) + + # group fields: modify group / implied groups + for name, group, implied_group in classified['group']: + if config[name]: + group.write({'implied_ids': [(4, implied_group.id)]}) + else: + group.write({'implied_ids': [(3, implied_group.id)]}) + implied_group.write({'users': [(3, u.id) for u in group.users]}) + + # other fields: execute all methods that start with 'set_' + for method in dir(self): + if method.startswith('set_'): + getattr(self, method)(cr, uid, ids, context) + + # module fields: install immediately the selected modules + to_install_ids = [] + for name, module in classified['module']: + if config[name] and module.state == 'uninstalled': + to_install_ids.append(module.id) + if to_install_ids: + ir_module.button_immediate_install(cr, uid, to_install_ids, context) + + # open the menu for this wizard (or Settings), and force client-side refresh + act_ids = self.pool.get('ir.actions.act_window').search(cr, uid, [('res_model', '=', self._name)]) + act_refs = ['ir.actions.act_window,%s' % id for id in act_ids] + val_ids = ir_values.search(cr, uid, [('model', '=', 'ir.ui.menu'), ('key', '=', 'action'), + ('key2', '=', 'tree_but_open'), ('value', 'in', act_refs)]) + if val_ids: + menu_id = ir_values.browse(cr, uid, val_ids[0]).res_id + else: + menu_id = ir_model_data.get_object(cr, uid, 'base', 'menu_administration', context).id + return { + 'type': 'ir.ui.menu', + 'menu_id': menu_id, + 'reload': True, + } + # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/addons/base/res/res_security.xml b/openerp/addons/base/res/res_security.xml index 6a2bf52d21b..f02abd90985 100644 --- a/openerp/addons/base/res/res_security.xml +++ b/openerp/addons/base/res/res_security.xml @@ -2,7 +2,7 @@ - + Partner Manager diff --git a/openerp/addons/base/res/res_users.py b/openerp/addons/base/res/res_users.py index 63892ebd869..4b8fb330a78 100644 --- a/openerp/addons/base/res/res_users.py +++ b/openerp/addons/base/res/res_users.py @@ -97,22 +97,6 @@ class groups(osv.osv): self.pool.get('ir.model.access').call_cache_clearing_methods(cr) return res - def create(self, cr, uid, vals, context=None): - if 'name' in vals: - if vals['name'].startswith('-'): - raise osv.except_osv(_('Error'), - _('The name of the group can not start with "-"')) - gid = super(groups, self).create(cr, uid, vals, context=context) - if context and context.get('noadmin', False): - pass - else: - # assign this new group to user_root - user_obj = self.pool.get('res.users') - aid = user_obj.browse(cr, 1, user_obj._get_admin_id(cr)) - if aid: - aid.write({'groups_id': [(4, gid)]}) - return gid - def get_extended_interface_group(self, cr, uid, context=None): data_obj = self.pool.get('ir.model.data') extended_group_data_id = data_obj._get_id(cr, uid, 'base', 'group_extended') @@ -771,22 +755,23 @@ class groups_view(osv.osv): # and introduces the reified group fields view = self.get_user_groups_view(cr, uid, context) if view: - xml1, xml2 = [], [] xml1.append(E.separator(string=_('Application'), colspan="4")) for app, kind, gs in self.get_groups_by_application(cr, uid, context): + # hide groups in category 'Hidden' (except to group_no_one) + attrs = {'groups': 'base.group_no_one'} if app and app.xml_id == 'base.module_category_hidden' else {} if kind == 'selection': # application name with a selection field field_name = name_selection_groups(map(int, gs)) - xml1.append(E.field(name=field_name)) + xml1.append(E.field(name=field_name, **attrs)) xml1.append(E.newline()) else: # application separator with boolean fields app_name = app and app.name or _('Other') - xml2.append(E.separator(string=app_name, colspan="4")) + xml2.append(E.separator(string=app_name, colspan="4", **attrs)) for g in gs: field_name = name_boolean_group(g.id) - xml2.append(E.field(name=field_name)) + xml2.append(E.field(name=field_name, **attrs)) xml = E.field(*(xml1 + xml2), name="groups_id", position="replace") xml.addprevious(etree.Comment("GENERATED AUTOMATICALLY BY GROUPS")) diff --git a/openerp/addons/base/security/base_security.xml b/openerp/addons/base/security/base_security.xml index b41f87c72da..3b0194922ca 100644 --- a/openerp/addons/base/security/base_security.xml +++ b/openerp/addons/base/security/base_security.xml @@ -12,28 +12,30 @@ Configuration + Employee + - + Multi Companies - + Extended View - + Technical Features - + User - + Manager