diff --git a/trytond/trytond/backend/postgresql/init.sql b/trytond/trytond/backend/postgresql/init.sql index c53645d147..6a190733eb 100644 --- a/trytond/trytond/backend/postgresql/init.sql +++ b/trytond/trytond/backend/postgresql/init.sql @@ -7,7 +7,7 @@ CREATE TABLE ir_configuration ( ); CREATE TABLE ir_model ( - id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL + id INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 3) NOT NULL CONSTRAINT ir_model_id_positive CHECK(id >= 0), name VARCHAR NOT NULL, string VARCHAR, @@ -18,6 +18,9 @@ CREATE TABLE ir_model ( ALTER TABLE ir_model ADD CONSTRAINT ir_model_name_unique UNIQUE (name); +INSERT INTO ir_model (id, name, module) VALUES (1, 'res.user', 'res'); +INSERT INTO ir_model (id, name, module) VALUES (2, 'res.group', 'res'); + CREATE TABLE ir_model_field ( id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL CONSTRAINT ir_model_field_id_positive CHECK(id >= 0), @@ -35,6 +38,23 @@ CREATE TABLE ir_model_field ( ALTER TABLE ir_model_field ADD CONSTRAINT ir_model_field_name_model_uniq UNIQUE (name, model); +CREATE TABLE ir_model_data ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 3) NOT NULL + CONSTRAINT ir_model_id_positive CHECK(id >= 0), + db_id INTEGER, + fs_id VARCHAR, + model VARCHAR NOT NULL, + module VARCHAR NOT NULL, + noupdate BOOL, + fs_values TEXT, + "values" TEXT, + PRIMARY KEY(id), + FOREIGN KEY (model) REFERENCES ir_model(name) ON DELETE CASCADE +); + +INSERT INTO ir_model_data (id, db_id, fs_id, model, module, noupdate, fs_values, "values") VALUES (1, 1, 'user_admin', 'res.user', 'res', False, '[["login","admin"],["name","Administrator"]]', '[["login","admin"],["name","Administrator"]]'); +INSERT INTO ir_model_data (id, db_id, fs_id, model, module, noupdate, fs_values, "values") VALUES (2, 1, 'group_admin', 'res.group', 'res', False, '[["name","Administrator"]]', '[["name","Administrator"]]'); + CREATE TABLE ir_ui_view ( id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL CONSTRAINT ir_ui_view_id_positive CHECK(id >= 0), @@ -83,7 +103,7 @@ CREATE TABLE ir_lang ( ); CREATE TABLE res_user ( - id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL + id INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 2) NOT NULL CONSTRAINT res_user_id_positive CHECK(id >= 0), name VARCHAR, active BOOLEAN NOT NULL, @@ -95,14 +115,17 @@ CREATE TABLE res_user ( ALTER TABLE res_user ADD CONSTRAINT res_user_login_key UNIQUE (login); INSERT INTO res_user (id, login, password, name, active) VALUES (0, 'root', NULL, 'Root', False); +INSERT INTO res_user (id, login, password, name, active) VALUES (1, 'admin', NULL, 'Administrator', True); CREATE TABLE res_group ( - id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL + id INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 2) NOT NULL CONSTRAINT res_group_id_positive CHECK(id >= 0), name VARCHAR NOT NULL, PRIMARY KEY(id) ); +INSERT INTO res_group (id, name) VALUES (1, 'Administration'); + CREATE TABLE "res_user-res_group" ( id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL CONSTRAINT "res_user-res_group_id_positive" CHECK(id >= 0), diff --git a/trytond/trytond/backend/sqlite/init.sql b/trytond/trytond/backend/sqlite/init.sql index a7a2451f45..b6f2695cf0 100644 --- a/trytond/trytond/backend/sqlite/init.sql +++ b/trytond/trytond/backend/sqlite/init.sql @@ -14,6 +14,9 @@ CREATE TABLE ir_model ( CREATE UNIQUE INDEX ir_model_name_unique ON ir_model (name); +INSERT INTO ir_model (id, name, module) VALUES (1, 'res.user', 'res'); +INSERT INTO ir_model (id, name, module) VALUES (2, 'res.group', 'res'); + CREATE TABLE ir_model_field ( id INTEGER PRIMARY KEY AUTOINCREMENT, model VARCHAR NOT NULL, @@ -26,6 +29,19 @@ CREATE TABLE ir_model_field ( "access" BOOLEAN ); +CREATE TABLE ir_model_data ( + id INTEGER PRIMARY KEy AUTOINCREMENT, + db_id INTEGER, + fs_id VARCHAR, + model VARCHAR NOT NULL, + module VARCHAR NOT NULL, + noupdate BOOL, + fs_values TEXT, + "values" TEXT +); + +INSERT INTO ir_model_data (id, db_id, fs_id, model, module, noupdate, fs_values, "values") VALUES (1, 1, 'user_admin', 'res.user', 'res', False, '[["login","admin"],["name","Administrator"]]', '[["login","admin"],["name","Administrator"]]'); +INSERT INTO ir_model_data (id, db_id, fs_id, model, module, noupdate, fs_values, "values") VALUES (2, 1, 'group_admin', 'res.group', 'res', False, '[["name","Administrator"]]', '[["name","Administrator"]]'); CREATE TABLE ir_ui_view ( id INTEGER PRIMARY KEY AUTOINCREMENT, @@ -79,12 +95,15 @@ CREATE TABLE res_user ( CREATE UNIQUE INDEX res_user_login_key ON res_user (login); INSERT INTO res_user (id, login, password, name, active) VALUES (0, 'root', NULL, 'Root', 0); +INSERT INTO res_user (id, login, password, name, active) VALUES (1, 'admin', NULL, 'Administrator', 1); CREATE TABLE res_group ( id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR ); +INSERT INTO res_group (id, name) VALUES (1, 'Administration'); + CREATE TABLE "res_user-res_group" ( id INTEGER PRIMARY KEY AUTOINCREMENT, "user" INTEGER NOT NULL, diff --git a/trytond/trytond/ir/__init__.py b/trytond/trytond/ir/__init__.py index b8ddd055b1..cf104fb2b5 100644 --- a/trytond/trytond/ir/__init__.py +++ b/trytond/trytond/ir/__init__.py @@ -23,9 +23,11 @@ def register(): translation.TranslationExportStart, translation.TranslationExportResult, sequence.SequenceType, + sequence.SequenceTypeGroup, sequence.Sequence, sequence.SequenceStrict, ui.menu.UIMenu, + ui.menu.UIMenuGroup, ui.menu.UIMenuFavorite, ui.view.View, ui.view.ShowViewStart, @@ -35,6 +37,7 @@ def register(): ui.view.ViewSearch, ui.icon.Icon, action.Action, + action.ActionGroup, action.ActionKeyword, action.ActionReport, action.ActionActWindow, @@ -46,6 +49,7 @@ def register(): model.ModelAccess, model.ModelFieldAccess, model.ModelButton, + model.ModelButtonGroup, model.ModelButtonRule, model.ModelButtonClick, model.ModelButtonReset, @@ -63,7 +67,10 @@ def register(): lang.LangConfigStart, export.Export, export.ExportLine, + export.ExportGroup, + export.ExportWriteGroup, rule.RuleGroup, + rule.RuleGroup_Group, rule.Rule, module.Module, module.ModuleDependency, diff --git a/trytond/trytond/ir/action.py b/trytond/trytond/ir/action.py index 1401b31e9c..5c55312d23 100644 --- a/trytond/trytond/ir/action.py +++ b/trytond/trytond/ir/action.py @@ -66,6 +66,9 @@ class Action(DeactivableMixin, ModelSQL, ModelView): keywords = fields.One2Many('ir.action.keyword', 'action', 'Keywords') icon = fields.Many2One('ir.ui.icon', 'Icon') + groups = fields.Many2Many( + 'ir.action-res.group', 'action', 'group', "Groups") + _groups_cache = Cache('ir.action.get_groups', context=False) @classmethod def __setup__(cls): @@ -148,6 +151,47 @@ class Action(DeactivableMixin, ModelSQL, ModelView): return self.get_action_values(self.type, [action_id])[0] +class ActionGroup(ModelSQL): + "Action - Group" + __name__ = 'ir.action-res.group' + action = fields.Many2One( + 'ir.action', "Action", ondelete='CASCADE', required=True) + group = fields.Many2One( + 'res.group', "Group", ondelete='CASCADE', required=True) + + @classmethod + def create(cls, vlist): + pool = Pool() + Action = pool.get('ir.action') + vlist = [x.copy() for x in vlist] + for vals in vlist: + if vals.get('action'): + vals['action'] = Action.get_action_id(vals['action']) + Action._groups_cache.clear() + return super().create(vlist) + + @classmethod + def write(cls, records, values, *args): + pool = Pool() + Action = pool.get('ir.action') + actions = iter((records, values) + args) + args = [] + for records, values in zip(actions, actions): + if values.get('action'): + values = values.copy() + values['action'] = Action.get_action_id(values['action']) + args.extend((records, values)) + Action._groups_cache.clear() + super().write(*args) + + @classmethod + def delete(cls, records): + pool = Pool() + Action = pool.get('ir.action') + Action._groups_cache.clear() + super().delete(records) + + class ActionKeyword(ModelSQL, ModelView): __name__ = 'ir.action.keyword' keyword = fields.Selection([ @@ -160,6 +204,10 @@ class ActionKeyword(ModelSQL, ModelView): model = fields.Reference('Model', selection='models_get') action = fields.Many2One('ir.action', 'Action', ondelete='CASCADE') + groups = fields.Function( + fields.One2Many('res.group', None, "Groups"), + 'get_groups', searcher='search_groups') + _get_keyword_cache = Cache( 'ir_action_keyword.get_keyword', context=False) @@ -219,6 +267,13 @@ class ActionKeyword(ModelSQL, ModelView): Model = pool.get('ir.model') return [(None, '')] + Model.get_name_items(ModelView) + def get_groups(self, name): + return [g.id for g in self.action.groups] + + @classmethod + def search_groups(cls, name, clause): + return [('action.' + clause[0],) + tuple(clause[1:])] + @classmethod def delete(cls, keywords): ModelView._view_toolbar_get_cache.clear() @@ -380,6 +435,27 @@ class ActionMixin(ModelSQL): def search_action(cls, name, clause): return [('action.' + clause[0],) + tuple(clause[1:])] + @classmethod + @without_check_access + def get_groups(cls, name, action_id=None): + pool = Pool() + Action = pool.get('ir.action') + + key = (name, action_id) + groups = Action._groups_cache.get(key) + if groups is not None: + return set(groups) + + domain = [ + (cls._action_name, '=', name), + ] + if action_id: + domain.append(('id', '=', action_id)) + actions = cls.search(domain) + groups = {g.id for a in actions for g in a.groups} + Action._groups_cache.set(key, list(groups)) + return groups + @classmethod def create(cls, vlist): pool = Pool() diff --git a/trytond/trytond/ir/action.xml b/trytond/trytond/ir/action.xml index 81bec8d062..1207b5777f 100644 --- a/trytond/trytond/ir/action.xml +++ b/trytond/trytond/ir/action.xml @@ -41,6 +41,36 @@ this repository contains the full copyright notices and license terms. --> sequence="10" id="menu_act_action"/> + + ir.action + + + + + + + ir.action + + + + + + + + + User in groups + ir.action + + + + + + + + + + + ir.action.keyword tree diff --git a/trytond/trytond/ir/cron.xml b/trytond/trytond/ir/cron.xml index b85d9dbe5e..764a84a215 100644 --- a/trytond/trytond/ir/cron.xml +++ b/trytond/trytond/ir/cron.xml @@ -47,6 +47,26 @@ this repository contains the full copyright notices and license terms. --> run_once Run Once + + + + + + + ir.cron + + + + + + + ir.cron + + + + + + ir.cron.log diff --git a/trytond/trytond/ir/email.xml b/trytond/trytond/ir/email.xml index f2ea815b25..46c3963c38 100644 --- a/trytond/trytond/ir/email.xml +++ b/trytond/trytond/ir/email.xml @@ -95,5 +95,21 @@ this repository contains the full copyright notices and license terms. --> action="act_email_template_form" sequence="50" id="menu_email_template_form"/> + + + ir.email.template + + + + + + + ir.email.template + + + + + + diff --git a/trytond/trytond/ir/error.xml b/trytond/trytond/ir/error.xml index 57835fdf21..ba291a3347 100644 --- a/trytond/trytond/ir/error.xml +++ b/trytond/trytond/ir/error.xml @@ -73,6 +73,22 @@ this repository contains the full copyright notices and license terms. --> solve Solve + + + ir.error + + + + + + + ir.error + + + + + + diff --git a/trytond/trytond/ir/export.py b/trytond/trytond/ir/export.py index 6a14b4de50..d39c331d76 100644 --- a/trytond/trytond/ir/export.py +++ b/trytond/trytond/ir/export.py @@ -3,6 +3,7 @@ "Exports" from trytond.model import ModelSQL, ModelView, fields from trytond.pool import Pool +from trytond.pyson import Eval from trytond.rpc import RPC from trytond.transaction import Transaction @@ -30,6 +31,19 @@ class Export(_ClearCache, ModelSQL, ModelView): resource = fields.Char('Resource') user = fields.Many2One( 'res.user', "User", required=True, ondelete='CASCADE') + groups = fields.Many2Many( + 'ir.export-res.group', 'export', 'group', "Groups", + help="The user groups that can use the export.") + write_groups = fields.Many2Many( + 'ir.export-write-res.group', 'export', 'group', + "Modification Groups", + domain=[ + ('id', 'in', Eval('groups', [])), + ], + states={ + 'invisible': ~Eval('groups'), + }, + help="The user groups that can modify the export.") header = fields.Boolean( "Header", help="Check to include field names on the export.") @@ -139,3 +153,20 @@ class ExportLine(_ClearCache, ModelSQL, ModelView): def __setup__(cls): super().__setup__() cls.__access__.add('export') + + +class ExportGroup(ModelSQL): + "Export Group" + __name__ = 'ir.export-res.group' + + export = fields.Many2One( + 'ir.export', "Export", required=True, ondelete='CASCADE') + group = fields.Many2One( + 'res.group', "Group", required=True, ondelete='CASCADE') + + +class ExportWriteGroup(ExportGroup): + "Export Modification Group" + __name__ = 'ir.export-write-res.group' + __string__ = None + _table = None # Needed to reset Export_Group._table diff --git a/trytond/trytond/ir/export.xml b/trytond/trytond/ir/export.xml index 1cb5fdeb6b..26c7880c1a 100644 --- a/trytond/trytond/ir/export.xml +++ b/trytond/trytond/ir/export.xml @@ -36,6 +36,22 @@ this repository contains the full copyright notices and license terms. --> sequence="50" id="menu_export_form"/> + + ir.export + + + + + + + ir.export + + + + + + + ir.export.line form diff --git a/trytond/trytond/ir/lang.xml b/trytond/trytond/ir/lang.xml index e8fcc01631..dd55f8608c 100644 --- a/trytond/trytond/ir/lang.xml +++ b/trytond/trytond/ir/lang.xml @@ -606,6 +606,22 @@ this repository contains the full copyright notices and license terms. --> Are you sure you want to remove languages' translations? + + ir.lang + + + + + + + ir.lang + + + + + + + ir.lang.config.start form @@ -617,6 +633,10 @@ this repository contains the full copyright notices and license terms. --> ir.lang.config + + + + diff --git a/trytond/trytond/ir/message.xml b/trytond/trytond/ir/message.xml index 180db966be..4353dd0bdc 100644 --- a/trytond/trytond/ir/message.xml +++ b/trytond/trytond/ir/message.xml @@ -32,6 +32,22 @@ this repository contains the full copyright notices and license terms. --> action="act_message_form" sequence="20" id="menu_message_form"/> + + + ir.message + + + + + + + ir.message + + + + + + diff --git a/trytond/trytond/ir/model.py b/trytond/trytond/ir/model.py index 520ec6b292..512c752123 100644 --- a/trytond/trytond/ir/model.py +++ b/trytond/trytond/ir/model.py @@ -982,6 +982,9 @@ class ModelButton( ('id', '!=', Eval('id', -1)), ]) _reset_cache = Cache('ir.model.button.reset') + groups = fields.Many2Many( + 'ir.model.button-res.group', 'button', 'group', "Groups") + _groups_cache = Cache('ir.model.button.groups') _view_attributes_cache = Cache( 'ir.model.button.view_attributes', context=False) @@ -1029,6 +1032,7 @@ class ModelButton( result = super(ModelButton, cls).create(vlist) cls._rules_cache.clear() cls._reset_cache.clear() + cls._groups_cache.clear() cls._view_attributes_cache.clear() return result @@ -1037,6 +1041,7 @@ class ModelButton( super(ModelButton, cls).write(buttons, values, *args) cls._rules_cache.clear() cls._reset_cache.clear() + cls._groups_cache.clear() cls._view_attributes_cache.clear() @classmethod @@ -1044,6 +1049,7 @@ class ModelButton( super(ModelButton, cls).delete(buttons) cls._rules_cache.clear() cls._reset_cache.clear() + cls._groups_cache.clear() cls._view_attributes_cache.clear() @classmethod @@ -1097,6 +1103,27 @@ class ModelButton( cls._reset_cache.set(key, reset) return reset + @classmethod + def get_groups(cls, model, name): + ''' + Return a set of group ids for the named button on the model. + ''' + key = (model, name) + groups = cls._groups_cache.get(key) + if groups is not None: + return groups + buttons = cls.search([ + ('model.name', '=', model), + ('name', '=', name), + ]) + if not buttons: + groups = set() + else: + button, = buttons + groups = set(g.id for g in button.groups) + cls._groups_cache.set(key, groups) + return groups + @classmethod def get_view_attributes(cls, model, name): "Return the view attributes of the named button of the model" @@ -1121,6 +1148,37 @@ class ModelButton( return attributes +class ModelButtonGroup(DeactivableMixin, ModelSQL): + "Model Button - Group" + __name__ = 'ir.model.button-res.group' + button = fields.Many2One( + 'ir.model.button', "Button", ondelete='CASCADE', required=True) + group = fields.Many2One( + 'res.group', "Group", ondelete='CASCADE', required=True) + + @classmethod + def create(cls, vlist): + pool = Pool() + result = super().create(vlist) + # Restart the cache for get_groups + pool.get('ir.model.button')._groups_cache.clear() + return result + + @classmethod + def write(cls, records, values, *args): + pool = Pool() + super().write(records, values, *args) + # Restart the cache for get_groups + pool.get('ir.model.button')._groups_cache.clear() + + @classmethod + def delete(cls, records): + pool = Pool() + super().delete(records) + # Restart the cache for get_groups + pool.get('ir.model.button')._groups_cache.clear() + + class ModelButtonRule(ModelSQL, ModelView): __name__ = 'ir.model.button.rule' button = fields.Many2One( @@ -1131,6 +1189,7 @@ class ModelButtonRule(ModelSQL, ModelView): "Condition", help='A PYSON statement evaluated with the record represented by ' '"self"\nIt activate the rule if true.') + group = fields.Many2One('res.group', "Group", ondelete='CASCADE') @classmethod def __setup__(cls): @@ -1205,6 +1264,7 @@ class ModelButtonClick(DeactivableMixin, ModelSQL, ModelView): button = fields.Many2One( 'ir.model.button', "Button", required=True, ondelete='CASCADE') record_id = fields.Integer("Record ID", required=True) + user = fields.Many2One('res.user', "User", ondelete='CASCADE') @classmethod def __setup__(cls): diff --git a/trytond/trytond/ir/model.xml b/trytond/trytond/ir/model.xml index f604dba4e4..ebb496e59d 100644 --- a/trytond/trytond/ir/model.xml +++ b/trytond/trytond/ir/model.xml @@ -39,6 +39,23 @@ this repository contains the full copyright notices and license terms. --> action="act_model_form" sequence="10" id="menu_model_form"/> + + + ir.model + + + + + + + ir.model + + + + + + + ir.model.field form @@ -304,5 +321,13 @@ this repository contains the full copyright notices and license terms. --> action="act_model_log_form" sequence="50" id="menu_model_log_form"/> + + + ir.model.log + + + + + diff --git a/trytond/trytond/ir/module.xml b/trytond/trytond/ir/module.xml index 1a2be9e195..d4bb1a84e4 100644 --- a/trytond/trytond/ir/module.xml +++ b/trytond/trytond/ir/module.xml @@ -47,31 +47,76 @@ this repository contains the full copyright notices and license terms. --> activate Mark for Activation + + + + + ir.module activate_cancel Cancel Activation + + + + + ir.module deactivate Mark for Deactivation (beta) + + + + + ir.module deactivate_cancel Cancel Deactivation + + + + + ir.module upgrade Mark for Upgrade + + + + + ir.module upgrade_cancel Cancel Upgrade + + + + + + + ir.module + + + + + + + ir.module + + + + + + ir.module.dependency @@ -140,6 +185,11 @@ this repository contains the full copyright notices and license terms. --> Perform Pending Activation/Upgrade ir.module.activate_upgrade + + + + + form_action diff --git a/trytond/trytond/ir/rule.py b/trytond/trytond/ir/rule.py index 57a517cbc9..a47d6c81be 100644 --- a/trytond/trytond/ir/rule.py +++ b/trytond/trytond/ir/rule.py @@ -66,6 +66,8 @@ class RuleGroup( ()), ], help="Add this rule to all users by default.") + groups = fields.Many2Many( + 'ir.rule.group-res.group', 'rule_group', 'group', "Groups") rules = fields.One2Many('ir.rule', 'rule_group', 'Tests', help="The rule is satisfied if at least one test is True.\n" "If there is no test defined, " @@ -161,6 +163,15 @@ class RuleGroup( Pool().get('ir.rule')._domain_get_cache.clear() +class RuleGroup_Group(ModelSQL): + "Rule Group - Group" + __name__ = 'ir.rule.group-res.group' + rule_group = fields.Many2One( + 'ir.rule.group', "Rule Group", ondelete='CASCADE', required=True) + group = fields.Many2One( + 'res.group', "Group", ondelete='CASCADE', required=True) + + class Rule(ModelSQL, ModelView): __name__ = 'ir.rule' rule_group = fields.Many2One('ir.rule.group', 'Group', diff --git a/trytond/trytond/ir/rule.xml b/trytond/trytond/ir/rule.xml index 415d253f31..f2828981b2 100644 --- a/trytond/trytond/ir/rule.xml +++ b/trytond/trytond/ir/rule.xml @@ -34,6 +34,23 @@ this repository contains the full copyright notices and license terms. --> action="act_rule_group_form" sequence="30" id="menu_rule_group_form"/> + + + ir.rule.group + + + + + + + ir.rule.group + + + + + + + ir.rule form diff --git a/trytond/trytond/ir/sequence.py b/trytond/trytond/ir/sequence.py index 8fe43cf999..b91a13e08f 100644 --- a/trytond/trytond/ir/sequence.py +++ b/trytond/trytond/ir/sequence.py @@ -35,6 +35,9 @@ class SequenceType(ModelSQL, ModelView): __name__ = 'ir.sequence.type' name = fields.Char('Sequence Name', required=True, translate=True) + groups = fields.Many2Many( + 'ir.sequence.type-res.group', 'sequence_type', 'group', "Groups", + help="Groups allowed to edit the sequences of this type.") @classmethod def __register__(cls, module): @@ -46,6 +49,15 @@ class SequenceType(ModelSQL, ModelView): table_h.not_null_action('code', action='remove') +class SequenceTypeGroup(ModelSQL): + 'Sequence Type - Group' + __name__ = 'ir.sequence.type-res.group' + sequence_type = fields.Many2One( + 'ir.sequence.type', "Sequence Type", ondelete='CASCADE', required=True) + group = fields.Many2One( + 'res.group', "Group", ondelete='CASCADE', required=True) + + class Sequence(DeactivableMixin, ModelSQL, ModelView): __name__ = 'ir.sequence' diff --git a/trytond/trytond/ir/sequence.xml b/trytond/trytond/ir/sequence.xml index e75f747fc8..3d02e48faf 100644 --- a/trytond/trytond/ir/sequence.xml +++ b/trytond/trytond/ir/sequence.xml @@ -43,6 +43,17 @@ this repository contains the full copyright notices and license terms. --> sequence="10" id="menu_sequence_form"/> + + User in groups + ir.sequence + + + + + + + + ir.sequence.strict @@ -78,6 +89,17 @@ this repository contains the full copyright notices and license terms. --> id="menu_sequence_strict_form" icon="tryton-list"/> + + User in groups + ir.sequence.strict + + + + + + + + ir.sequence.type form @@ -111,5 +133,21 @@ this repository contains the full copyright notices and license terms. --> action="act_sequence_type_form" sequence="20" id="menu_ir_sequence_type"/> + + + ir.sequence.type + + + + + + + ir.sequence.type + + + + + + diff --git a/trytond/trytond/ir/translation.xml b/trytond/trytond/ir/translation.xml index 756df84992..5a405b94ba 100644 --- a/trytond/trytond/ir/translation.xml +++ b/trytond/trytond/ir/translation.xml @@ -50,6 +50,22 @@ this repository contains the full copyright notices and license terms. --> sequence="20" id="menu_translation_form"/> + + ir.translation + + + + + + + ir.translation + + + + + + + Translations ir.translation.report @@ -131,6 +147,10 @@ this repository contains the full copyright notices and license terms. --> Synchronize Translations ir.translation.update + + + + form_action @@ -165,6 +185,10 @@ this repository contains the full copyright notices and license terms. --> Export Translations ir.translation.export + + + + sequence="50" id="menu_trigger_form"/> + + ir.trigger + + + + + + + ir.trigger + + + + + + + + + + ir.trigger|trigger_time + + minutes + diff --git a/trytond/trytond/ir/ui/icon.xml b/trytond/trytond/ir/ui/icon.xml index 4bae5a7b7f..4f1c21acfd 100644 --- a/trytond/trytond/ir/ui/icon.xml +++ b/trytond/trytond/ir/ui/icon.xml @@ -34,5 +34,21 @@ action="act_icon_form" sequence="20" id="menu_icon_form"/> + + + ir.ui.icon + + + + + + + ir.ui.icon + + + + + + diff --git a/trytond/trytond/ir/ui/menu.py b/trytond/trytond/ir/ui/menu.py index 9466c95273..cdcaf68a83 100644 --- a/trytond/trytond/ir/ui/menu.py +++ b/trytond/trytond/ir/ui/menu.py @@ -106,6 +106,8 @@ class UIMenu( filter=[ ('keyword', '=', 'tree_open'), ]) + groups = fields.Many2Many( + 'ir.ui.menu-res.group', 'menu', 'group', "Groups") favorite = fields.Function(fields.Boolean('Favorite'), 'get_favorite') favorites = fields.Many2Many( 'ir.ui.menu.favorite', 'menu', 'user', "Favorites") @@ -262,6 +264,15 @@ class UIMenu( return menu2favorite +class UIMenuGroup(ModelSQL): + "UI Menu - Group" + __name__ = 'ir.ui.menu-res.group' + menu = fields.Many2One( + 'ir.ui.menu', "Menu", ondelete='CASCADE', required=True) + group = fields.Many2One( + 'res.group', "Group", ondelete='CASCADE', required=True) + + class UIMenuFavorite(ModelSQL): "Menu Favorite" __name__ = 'ir.ui.menu.favorite' diff --git a/trytond/trytond/ir/ui/menu.xml b/trytond/trytond/ir/ui/menu.xml index db9b37d024..ecc0dccf19 100644 --- a/trytond/trytond/ir/ui/menu.xml +++ b/trytond/trytond/ir/ui/menu.xml @@ -59,5 +59,35 @@ this repository contains the full copyright notices and license terms. --> action="act_menu_list" sequence="10" id="menu_menu_list"/> + + + ir.ui.menu + + + + + + + ir.ui.menu + + + + + + + + + User in groups + ir.ui.menu + + + + + + + + + + diff --git a/trytond/trytond/ir/ui/ui.xml b/trytond/trytond/ir/ui/ui.xml index 4c578ec517..0dec71fca8 100644 --- a/trytond/trytond/ir/ui/ui.xml +++ b/trytond/trytond/ir/ui/ui.xml @@ -45,6 +45,10 @@ this repository contains the full copyright notices and license terms. --> sequence="9999" id="menu_administration" icon="tryton-settings"/> + + + + show Show + + + + + + + ir.ui.view + + + + + + + ir.ui.view + + + + + + ir.ui.view_tree_width @@ -158,6 +178,22 @@ this repository contains the full copyright notices and license terms. --> + + ir.ui.view_tree_state + + + + + + + ir.ui.view_tree_state + + + + + + + ir.ui.view_search form @@ -191,5 +227,21 @@ this repository contains the full copyright notices and license terms. --> ir.model,-1 + + + ir.ui.view_search + + + + + + + ir.ui.view_search + + + + + + diff --git a/trytond/trytond/ir/view/export_form.xml b/trytond/trytond/ir/view/export_form.xml index e7fd6cbcdd..8f78405da2 100644 --- a/trytond/trytond/ir/view/export_form.xml +++ b/trytond/trytond/ir/view/export_form.xml @@ -15,5 +15,9 @@ this repository contains the full copyright notices and license terms. -->