diff --git a/addons/account/views/account_payment_view.xml b/addons/account/views/account_payment_view.xml index 94b07812105..242fce7bb74 100644 --- a/addons/account/views/account_payment_view.xml +++ b/addons/account/views/account_payment_view.xml @@ -328,19 +328,11 @@ ir.actions.server code + records.post() - - - Confirm Payments - client_action_multi - - action - account.payment - - diff --git a/addons/account/wizard/account_move_reversal_view.xml b/addons/account/wizard/account_move_reversal_view.xml index b7ec625065d..dbe59d4ae3a 100644 --- a/addons/account/wizard/account_move_reversal_view.xml +++ b/addons/account/wizard/account_move_reversal_view.xml @@ -26,15 +26,7 @@ tree,form new - - - - - Reverse Moves - client_action_multi - - action - account.move + diff --git a/addons/account/wizard/account_reconcile_view.xml b/addons/account/wizard/account_reconcile_view.xml index e8087327fa2..4225438b351 100644 --- a/addons/account/wizard/account_reconcile_view.xml +++ b/addons/account/wizard/account_reconcile_view.xml @@ -33,15 +33,7 @@ form new - - - - - Reconcile Entries - client_action_multi - - action - account.move.line + diff --git a/addons/account/wizard/account_report_general_ledger_view.xml b/addons/account/wizard/account_report_general_ledger_view.xml index e6e1dbfdb1f..680cd08849b 100644 --- a/addons/account/wizard/account_report_general_ledger_view.xml +++ b/addons/account/wizard/account_report_general_ledger_view.xml @@ -25,15 +25,8 @@ form new - - - - - General Ledger - client_print_multi - - action - account.account + + report form new - - - - - Partner Ledger - client_print_multi - - action - account.account + + report form new + + report - - - Trial Balance - client_print_multi - - action - account.account - - diff --git a/addons/account/wizard/account_unreconcile_view.xml b/addons/account/wizard/account_unreconcile_view.xml index ec435cdb189..1c7927b2f8b 100644 --- a/addons/account/wizard/account_unreconcile_view.xml +++ b/addons/account/wizard/account_unreconcile_view.xml @@ -22,17 +22,9 @@ account.unreconcile form form - - new - - - - - Unreconcile Entries - client_action_multi - - action - account.move.line + + new + diff --git a/addons/account/wizard/account_validate_move_view.xml b/addons/account/wizard/account_validate_move_view.xml index 021b952bf99..2d94db9afbe 100644 --- a/addons/account/wizard/account_validate_move_view.xml +++ b/addons/account/wizard/account_validate_move_view.xml @@ -27,15 +27,7 @@ {} new This wizard will validate all journal entries selected. Once journal entries are validated, you can not update them anymore. - - - - - Post Journal Entries - client_action_multi - - action - account.move + diff --git a/addons/account_check_printing/data/account_check_printing_data.xml b/addons/account_check_printing/data/account_check_printing_data.xml index 4089bef5cb9..53ce8625e86 100644 --- a/addons/account_check_printing/data/account_check_printing_data.xml +++ b/addons/account_check_printing/data/account_check_printing_data.xml @@ -14,20 +14,12 @@ Print Checks + if records: action = records.print_checks() - - - Print Checks - client_action_multi - - action - account.payment - - diff --git a/addons/base_automation/views/base_automation_view.xml b/addons/base_automation/views/base_automation_view.xml index a81dd04d75b..174ac11a135 100644 --- a/addons/base_automation/views/base_automation_view.xml +++ b/addons/base_automation/views/base_automation_view.xml @@ -12,7 +12,7 @@ diff --git a/addons/crm/views/crm_lead_views.xml b/addons/crm/views/crm_lead_views.xml index d3cd818330e..4f9d8a1d58e 100644 --- a/addons/crm/views/crm_lead_views.xml +++ b/addons/crm/views/crm_lead_views.xml @@ -715,8 +715,9 @@ 'Mark as Lost' in action dropdown --> - Crm: Mark Leads as lost + Mark as lost + code if record: @@ -726,13 +727,6 @@ if record: - - - - Mark as lost - - - diff --git a/addons/hr/views/hr_views.xml b/addons/hr/views/hr_views.xml index 275048127bf..06f881b2813 100644 --- a/addons/hr/views/hr_views.xml +++ b/addons/hr/views/hr_views.xml @@ -292,15 +292,7 @@ [('id','in',active_ids)] tree - - - - Subordinate Hierarchy - - - action - client_action_multi - hr.employee + diff --git a/addons/hr_expense/views/hr_expense_views.xml b/addons/hr_expense/views/hr_expense_views.xml index b27bd9eafb8..362c37f1fc1 100644 --- a/addons/hr_expense/views/hr_expense_views.xml +++ b/addons/hr_expense/views/hr_expense_views.xml @@ -736,6 +736,7 @@ Expense: Submit To Manager ir.actions.server + code if records: @@ -743,14 +744,6 @@ if records: - - Submit To Manager - - hr.expense - client_action_multi - - - diff --git a/addons/hr_holidays/wizard/hr_holidays_summary_employees_views.xml b/addons/hr_holidays/wizard/hr_holidays_summary_employees_views.xml index 8cb47fc3ed8..7ea33bf3e01 100644 --- a/addons/hr_holidays/wizard/hr_holidays_summary_employees_views.xml +++ b/addons/hr_holidays/wizard/hr_holidays_summary_employees_views.xml @@ -28,15 +28,8 @@ form form new - - - - - Leaves Summary - client_print_multi - - action - hr.employee + + report diff --git a/addons/hr_payroll/wizard/hr_payroll_contribution_register_report_views.xml b/addons/hr_payroll/wizard/hr_payroll_contribution_register_report_views.xml index 5bd067d0574..e1f7db1735f 100644 --- a/addons/hr_payroll/wizard/hr_payroll_contribution_register_report_views.xml +++ b/addons/hr_payroll/wizard/hr_payroll_contribution_register_report_views.xml @@ -26,15 +26,8 @@ form form new - - - - - PaySlip Lines - client_print_multi - - action - hr.contribution.register + + report diff --git a/addons/lunch/data/lunch_data.xml b/addons/lunch/data/lunch_data.xml index d8531ddb752..f66fbb4788a 100644 --- a/addons/lunch/data/lunch_data.xml +++ b/addons/lunch/data/lunch_data.xml @@ -3,6 +3,7 @@ Lunch: Order meals + code if records: @@ -10,45 +11,20 @@ if records: - - - Order meals - client_action_multi - - action - lunch.order.line - - Lunch: Receive meals + code records.confirm() - - - Receive meals - client_action_multi - - action - lunch.order.line - - Lunch: Cancel meals + code records.cancel() - - - Cancel meals - client_action_multi - - action - lunch.order.line - - diff --git a/addons/lunch/views/lunch_views.xml b/addons/lunch/views/lunch_views.xml index c192795958c..f0e8ac5a65e 100644 --- a/addons/lunch/views/lunch_views.xml +++ b/addons/lunch/views/lunch_views.xml @@ -548,20 +548,11 @@ Lunch: Archive/Restore products ir.actions.server + code records.toggle_active() - - action_lunch_archive_product - - - action - - lunch.product - client_action_multi - - lunch.product.search diff --git a/addons/mail/models/mail_template.py b/addons/mail/models/mail_template.py index 1bd92aff430..e0e16eeef7c 100644 --- a/addons/mail/models/mail_template.py +++ b/addons/mail/models/mail_template.py @@ -171,8 +171,6 @@ class MailTemplate(models.Model): ref_ir_act_window = fields.Many2one('ir.actions.act_window', 'Sidebar action', readonly=True, copy=False, help="Sidebar action to make this template available on records " "of the related document model") - ref_ir_value = fields.Many2one('ir.values', 'Sidebar Button', readonly=True, copy=False, - help="Sidebar button to open the sidebar action") attachment_ids = fields.Many2many('ir.attachment', 'email_template_attachment_rel', 'email_template_id', 'attachment_id', 'Attachments', help="You may attach files to this template, to be added to all " @@ -255,40 +253,28 @@ class MailTemplate(models.Model): for template in self: if template.ref_ir_act_window: template.ref_ir_act_window.sudo().unlink() - if template.ref_ir_value: - template.ref_ir_value.sudo().unlink() return True @api.multi def create_action(self): ActWindowSudo = self.env['ir.actions.act_window'].sudo() - IrValuesSudo = self.env['ir.values'].sudo() view = self.env.ref('mail.email_compose_message_wizard_form') for template in self: - src_obj = template.model_id.model - button_name = _('Send Mail (%s)') % template.name action = ActWindowSudo.create({ 'name': button_name, 'type': 'ir.actions.act_window', 'res_model': 'mail.compose.message', - 'src_model': src_obj, + 'src_model': template.model_id.model, 'view_type': 'form', 'context': "{'default_composition_mode': 'mass_mail', 'default_template_id' : %d, 'default_use_template': True}" % (template.id), 'view_mode': 'form,tree', 'view_id': view.id, 'target': 'new', + 'binding_model_id': template.model_id.id, }) - ir_value = IrValuesSudo.create({ - 'name': button_name, - 'model': src_obj, - 'key2': 'client_action_multi', - 'value': "ir.actions.act_window,%s" % action.id}) - template.write({ - 'ref_ir_act_window': action.id, - 'ref_ir_value': ir_value.id, - }) + template.write({'ref_ir_act_window': action.id}) return True diff --git a/addons/mail/tests/test_mail_template.py b/addons/mail/tests/test_mail_template.py index e5da1c628ae..d5a68a73fe5 100644 --- a/addons/mail/tests/test_mail_template.py +++ b/addons/mail/tests/test_mail_template.py @@ -129,15 +129,13 @@ class TestMailTemplate(TestMail): def test_add_context_action(self): self.email_template.create_action() - # check template act_window and ir_values has been updated + # check template act_window has been updated self.assertTrue(bool(self.email_template.ref_ir_act_window)) - self.assertTrue(bool(self.email_template.ref_ir_value)) # check those records action = self.email_template.ref_ir_act_window self.assertEqual(action.name, 'Send Mail (%s)' % self.email_template.name) - value = self.email_template.ref_ir_value - self.assertEqual(value.name, 'Send Mail (%s)' % self.email_template.name) + self.assertEqual(action.binding_model_id.model, 'mail.test') def test_set_scheduled_date_on_a_template(self): self.email_template_in_2_days = self.email_template.copy() diff --git a/addons/mrp/views/mrp_bom_views.xml b/addons/mrp/views/mrp_bom_views.xml index b17d0a14898..cf442e62ff6 100644 --- a/addons/mrp/views/mrp_bom_views.xml +++ b/addons/mrp/views/mrp_bom_views.xml @@ -239,12 +239,7 @@ tree tree - - - - - Bill of Materials Structure - + diff --git a/addons/mrp/views/mrp_production_views.xml b/addons/mrp/views/mrp_production_views.xml index 92c3a24708c..cc4774192d4 100644 --- a/addons/mrp/views/mrp_production_views.xml +++ b/addons/mrp/views/mrp_production_views.xml @@ -24,19 +24,11 @@ Mrp: Plan Production Orders + code records.button_plan() - - - Plan Orders - client_action_multi - action - mrp.production - - - mrp.production.form mrp.production diff --git a/addons/procurement/views/procurement_views.xml b/addons/procurement/views/procurement_views.xml index 5b088ef8b89..7d546c05dd2 100644 --- a/addons/procurement/views/procurement_views.xml +++ b/addons/procurement/views/procurement_views.xml @@ -337,8 +337,9 @@ - Procurement: Run Procurements + Run Procurements + code if records: @@ -346,14 +347,5 @@ if records: - - - Run Procurements - client_action_multi - action - procurement.order - - - diff --git a/addons/project/views/project_views.xml b/addons/project/views/project_views.xml index 700caa7007d..085914b124d 100644 --- a/addons/project/views/project_views.xml +++ b/addons/project/views/project_views.xml @@ -696,13 +696,6 @@ action = model.activate_sample_project() {'project_id':active_id} - - - - View project's tasks - - - project.task.type.search diff --git a/addons/sale/wizard/sale_make_invoice_advance_views.xml b/addons/sale/wizard/sale_make_invoice_advance_views.xml index 9b6e653857c..10c9a27cd42 100644 --- a/addons/sale/wizard/sale_make_invoice_advance_views.xml +++ b/addons/sale/wizard/sale_make_invoice_advance_views.xml @@ -48,16 +48,8 @@ form new - - - - - - Invoice Orders - client_action_multi - - action - sale.order + + diff --git a/addons/survey/views/survey_views.xml b/addons/survey/views/survey_views.xml index de59354fb1f..ccd62832d02 100644 --- a/addons/survey/views/survey_views.xml +++ b/addons/survey/views/survey_views.xml @@ -682,6 +682,7 @@ Survey: Clean test answers ir.actions.server + code if records: @@ -689,16 +690,6 @@ if records: - - Survey clean test answers - - - action - - survey.survey - client_action_multi - - diff --git a/addons/website_crm_partner_assign/views/crm_lead_views.xml b/addons/website_crm_partner_assign/views/crm_lead_views.xml index 277ab9ac3f0..5bd875d9193 100644 --- a/addons/website_crm_partner_assign/views/crm_lead_views.xml +++ b/addons/website_crm_partner_assign/views/crm_lead_views.xml @@ -122,8 +122,9 @@ - Crm Assignation: Assign salesman of assigned partner + Assign salesman of assigned partner + code if env.context.get('active_domain'): @@ -132,13 +133,4 @@ records.assign_salesman_of_assigned_partner() - - - Assign salesman of assigned partner - client_action_multi - - action - crm.lead - - diff --git a/odoo/addons/base/ir/ir_actions.py b/odoo/addons/base/ir/ir_actions.py index bef65ab67d4..a3cbe9d5d79 100644 --- a/odoo/addons/base/ir/ir_actions.py +++ b/odoo/addons/base/ir/ir_actions.py @@ -8,6 +8,7 @@ from odoo.tools.safe_eval import safe_eval, test_python_expr from odoo.tools import pycompat from odoo.http import request +from collections import defaultdict import datetime import dateutil import logging @@ -29,6 +30,11 @@ class IrActions(models.Model): help = fields.Html(string='Action Description', help='Optional help text for the users with a description of the target view, such as its usage and purpose.', translate=True) + binding_model_id = fields.Many2one('ir.model', ondelete='cascade', + help="Setting a value makes this action available in the sidebar for the given model.") + binding_type = fields.Selection([('action', 'Action'), + ('report', 'Report')], + required=True, default='action') def _compute_xml_id(self): res = self.get_external_id() @@ -38,6 +44,8 @@ class IrActions(models.Model): @api.model def create(self, vals): res = super(IrActions, self).create(vals) + # self.get_bindings() depends on action records + self.clear_caches() # ir_values.get_actions() depends on action records self.env['ir.values'].clear_caches() return res @@ -45,6 +53,8 @@ class IrActions(models.Model): @api.multi def write(self, vals): res = super(IrActions, self).write(vals) + # self.get_bindings() depends on action records + self.clear_caches() # ir_values.get_actions() depends on action records self.env['ir.values'].clear_caches() return res @@ -56,6 +66,8 @@ class IrActions(models.Model): todos = self.env['ir.actions.todo'].search([('action_id', 'in', self.ids)]) todos.unlink() res = super(IrActions, self).unlink() + # self.get_bindings() depends on action records + self.clear_caches() # ir_values.get_actions() depends on action records self.env['ir.values'].clear_caches() return res @@ -72,6 +84,38 @@ class IrActions(models.Model): 'timezone': timezone, } + @api.model + @tools.ormcache('frozenset(self.env.user.groups_id.ids)', 'model_name') + def get_bindings(self, model_name): + """ Retrieve the list of actions bound to the given model. + + :return: a dict mapping binding types to a list of dict describing + actions, where the latter is given by calling the method + ``read`` on the action record. + """ + cr = self.env.cr + query = """ SELECT a.id, a.type, a.binding_type + FROM ir_actions a, ir_model m + WHERE a.binding_model_id=m.id AND m.model=%s + ORDER BY a.id """ + cr.execute(query, [model_name]) + + # discard unauthorized actions, and read action definitions + result = defaultdict(list) + user_groups = self.env.user.groups_id + for action_id, action_model, binding_type in cr.fetchall(): + try: + action = self.env[action_model].browse(action_id) + action_groups = getattr(action, 'groups_id', ()) + if action_groups and not action_groups & user_groups: + # the user may not perform this action + continue + result[binding_type].append(action.read()[0]) + except (AccessError, MissingError): + continue + + return result + class IrActionsActWindow(models.Model): _name = 'ir.actions.act_window' @@ -320,9 +364,6 @@ class IrActionsServer(models.Model): model_id = fields.Many2one('ir.model', string='Model', required=True, ondelete='cascade', help="Model on which the server action runs.") model_name = fields.Char(related='model_id.model', readonly=True, store=True) - menu_ir_values_id = fields.Many2one('ir.values', string='Action on Object', - copy=False, readonly=True, - help='IrValues entry of the related more menu entry action') # Python code code = fields.Text(string='Python Code', groups='base.group_system', default=DEFAULT_PYTHON_CODE, @@ -365,25 +406,15 @@ class IrActionsServer(models.Model): def create_action(self): """ Create a contextual action for each server action. """ for action in self: - ir_values = self.env['ir.values'].sudo().create({ - 'name': _('Run %s') % action.name, - 'model': action.model_id.model, - 'key2': 'client_action_multi', - 'value': "ir.actions.server,%s" % action.id, - }) - action.write({'menu_ir_values_id': ir_values.id}) + action.write({'binding_model_id': action.model_id.id, + 'binding_type': 'action'}) return True @api.multi def unlink_action(self): """ Remove the contextual actions created for the server actions. """ self.check_access_rights('write', raise_exception=True) - for action in self: - if action.menu_ir_values_id: - try: - action.menu_ir_values_id.sudo().unlink() - except Exception: - raise UserError(_('Deletion of the action record failed.')) + self.filtered('binding_model_id').write({'binding_model_id': False}) return True @api.model diff --git a/odoo/addons/base/ir/ir_actions.xml b/odoo/addons/base/ir/ir_actions.xml index 1fe709dc00d..128face6f04 100644 --- a/odoo/addons/base/ir/ir_actions.xml +++ b/odoo/addons/base/ir/ir_actions.xml @@ -52,14 +52,14 @@ ir.actions.report - + - + diff --git a/odoo/addons/base/ir/ir_actions_report.py b/odoo/addons/base/ir/ir_actions_report.py index fa7365f1b50..27215611d0b 100644 --- a/odoo/addons/base/ir/ir_actions_report.py +++ b/odoo/addons/base/ir/ir_actions_report.py @@ -79,6 +79,7 @@ class IrActionsReport(models.Model): name = fields.Char(translate=True) type = fields.Char(default='ir.actions.report') + binding_type = fields.Selection(default='report') model = fields.Char(required=True) report_type = fields.Selection([('qweb-html', 'HTML'), ('qweb-pdf', 'PDF')], required=True, default='qweb-pdf', @@ -90,8 +91,6 @@ class IrActionsReport(models.Model): report_file = fields.Char(string='Report File', required=False, readonly=False, store=True, help="The path to the main report file (depending on Report Type) or empty if the content is in another field") groups_id = fields.Many2many('res.groups', 'res_groups_report_rel', 'uid', 'gid', string='Groups') - ir_values_id = fields.Many2one('ir.values', string='More Menu entry', readonly=True, - help='More menu entry.', copy=False) multi = fields.Boolean(string='On Multiple Doc.', help="If set to true, the action will not be displayed on the right toolbar of a form view.") paperformat_id = fields.Many2one('report.paperformat', 'Paper format') @@ -119,25 +118,15 @@ class IrActionsReport(models.Model): def create_action(self): """ Create a contextual action for each report. """ for report in self: - ir_values = self.env['ir.values'].sudo().create({ - 'name': report.name, - 'model': report.model, - 'key2': 'client_print_multi', - 'value': "ir.actions.report,%s" % report.id, - }) - report.write({'ir_values_id': ir_values.id}) + model = self.env['ir.model']._get(report.model) + report.write({'binding_model_id': model.id, 'binding_type': 'report'}) return True @api.multi def unlink_action(self): """ Remove the contextual actions created for the reports. """ self.check_access_rights('write', raise_exception=True) - for report in self: - if report.ir_values_id: - try: - report.ir_values_id.sudo().unlink() - except Exception: - raise UserError(_('Deletion of the action record failed.')) + self.filtered('binding_model_id').write({'binding_model_id': False}) return True #-------------------------------------------------------------------------- diff --git a/odoo/addons/base/module/module_view.xml b/odoo/addons/base/module/module_view.xml index d0e842b5e3e..77c6f0b13a6 100644 --- a/odoo/addons/base/module/module_view.xml +++ b/odoo/addons/base/module/module_view.xml @@ -50,20 +50,6 @@ - - Apps - ir.module.module - form - tree,form,kanban - [('category_id','=',active_id)] - - - - - Categorized Apps - - - diff --git a/odoo/addons/base/module/wizard/base_module_immediate_install.xml b/odoo/addons/base/module/wizard/base_module_immediate_install.xml index dc5668b247b..09f7ed53668 100644 --- a/odoo/addons/base/module/wizard/base_module_immediate_install.xml +++ b/odoo/addons/base/module/wizard/base_module_immediate_install.xml @@ -5,18 +5,9 @@ Base: Module Immediate Install ir.actions.server + code records.button_immediate_install() - - - action_module_immediate_install - - - action - - ir.module.module - client_action_multi - diff --git a/odoo/addons/base/res/res_company_view.xml b/odoo/addons/base/res/res_company_view.xml index 0e481931a2e..5ef55a63632 100644 --- a/odoo/addons/base/res/res_company_view.xml +++ b/odoo/addons/base/res/res_company_view.xml @@ -113,13 +113,6 @@ - - - - Companies - - - res.company.report.form res.company diff --git a/odoo/addons/base/res/res_users.py b/odoo/addons/base/res/res_users.py index ff200716a59..729e8c612f9 100644 --- a/odoo/addons/base/res/res_users.py +++ b/odoo/addons/base/res/res_users.py @@ -681,6 +681,8 @@ class GroupsView(models.Model): def create(self, values): user = super(GroupsView, self).create(values) self._update_user_groups_view() + # actions.get_bindings() depends on action records + self.env['ir.actions.actions'].clear_caches() # ir_values.get_actions() depends on action records self.env['ir.values'].clear_caches() return user @@ -689,6 +691,8 @@ class GroupsView(models.Model): def write(self, values): res = super(GroupsView, self).write(values) self._update_user_groups_view() + # actions.get_bindings() depends on action records + self.env['ir.actions.actions'].clear_caches() # ir_values.get_actions() depends on action records self.env['ir.values'].clear_caches() return res @@ -697,6 +701,8 @@ class GroupsView(models.Model): def unlink(self): res = super(GroupsView, self).unlink() self._update_user_groups_view() + # actions.get_bindings() depends on action records + self.env['ir.actions.actions'].clear_caches() # ir_values.get_actions() depends on action records self.env['ir.values'].clear_caches() return res diff --git a/odoo/addons/base/tests/test_ir_actions.py b/odoo/addons/base/tests/test_ir_actions.py index a2663964f59..110bd2fe83c 100644 --- a/odoo/addons/base/tests/test_ir_actions.py +++ b/odoo/addons/base/tests/test_ir_actions.py @@ -60,19 +60,11 @@ class TestServerActions(TestServerActionsBase): # Do: create contextual action self.action.create_action() - - # Test: ir_values created - ir_values = self.env['ir.values'].search([('name', '=', 'Run TestAction')]) - self.assertEqual(len(ir_values), 1, 'ir_actions_server: create_action should have created an entry in ir_values') - self.assertEqual(ir_values.value, b'ir.actions.server,%d' % self.action.id, 'ir_actions_server: created ir_values should reference the server action') - self.assertEqual(ir_values.model, 'res.partner', 'ir_actions_server: created ir_values should be linked to the action base model') + self.assertEqual(self.action.binding_model_id.model, 'res.partner') # Do: remove contextual action self.action.unlink_action() - - # Test: ir_values removed - ir_values = self.env['ir.values'].search([('name', '=', 'Run TestAction')]) - self.assertEqual(len(ir_values), 0, 'ir_actions_server: unlink_action should remove the ir_values record') + self.assertFalse(self.action.binding_model_id) def test_10_code(self): self.action.write({ @@ -186,6 +178,55 @@ class TestServerActions(TestServerActionsBase): }) +class TestActionBindings(common.TransactionCase): + + def test_bindings(self): + """ check the action bindings on models """ + Actions = self.env['ir.actions.actions'] + + # first make sure there is no bound action + bindings = Actions.get_bindings('res.partner') + self.assertFalse(bindings['action']) + self.assertFalse(bindings['report']) + + # create action bindings, and check the returned bindings + action1 = self.env.ref('base.action_attachment') + action2 = self.env.ref('base.ir_default_menu_action') + action3 = self.env['ir.actions.report'].search([('groups_id', '=', False)], limit=1) + action1.binding_model_id = action2.binding_model_id \ + = action3.binding_model_id \ + = self.env['ir.model']._get('res.partner') + + bindings = Actions.get_bindings('res.partner') + self.assertItemsEqual( + bindings['action'], + (action1 + action2).read(), + "Wrong action bindings", + ) + self.assertItemsEqual( + bindings['report'], + action3.read(), + "Wrong action bindings", + ) + + # add a group on an action, and check that it is not returned + group = self.env.ref('base.group_user') + action2.groups_id += group + self.env.user.groups_id -= group + + bindings = Actions.get_bindings('res.partner') + self.assertItemsEqual( + bindings['action'], + action1.read(), + "Wrong action bindings", + ) + self.assertItemsEqual( + bindings['report'], + action3.read(), + "Wrong action bindings", + ) + + class TestCustomFields(common.TransactionCase): MODEL = 'res.partner' diff --git a/odoo/models.py b/odoo/models.py index ee5329cf9d7..6604e0ea222 100644 --- a/odoo/models.py +++ b/odoo/models.py @@ -1302,28 +1302,20 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})): # Add related action information if aksed if toolbar: - IrValues = self.env['ir.values'] - resprint = IrValues.get_actions('client_print_multi', self._name) - resaction = IrValues.get_actions('client_action_multi', self._name) - resrelate = IrValues.get_actions('client_action_relate', self._name) - resprint = [print_[2] - for print_ in resprint - if view_type == 'tree' or not print_[2].get('multi')] - resaction = [action[2] - for action in resaction - if view_type == 'tree' or not action[2].get('multi')] - #When multi="True" set it will display only in More of the list view - resrelate = [action[2] - for action in resrelate - if (action[2].get('multi') and view_type == 'tree') or (not action[2].get('multi') and view_type == 'form')] + bindings = self.env['ir.actions.actions'].get_bindings(self._name) + resreport = [action + for action in bindings['report'] + if view_type == 'tree' or not action.get('multi')] + resaction = [action + for action in bindings['action'] + if view_type == 'tree' or not action.get('multi')] - for x in itertools.chain(resprint, resaction, resrelate): - x['string'] = x['name'] + for res in itertools.chain(resreport, resaction): + res['string'] = res['name'] result['toolbar'] = { - 'print': resprint, + 'print': resreport, 'action': resaction, - 'relate': resrelate, } return result diff --git a/odoo/tools/convert.py b/odoo/tools/convert.py index 57b692f7ae4..d2c2ae6d0a7 100644 --- a/odoo/tools/convert.py +++ b/odoo/tools/convert.py @@ -276,13 +276,6 @@ form: module.record_id""" % (xml_id,) if records: records.unlink() - def _remove_ir_values(self, name, value, model): - domain = [('name', '=', name), ('value', '=', value), ('model', '=', model)] - ir_values = self.env['ir.values'].search(domain) - if ir_values: - ir_values.unlink() - return True - def _tag_report(self, rec, data_node=None, mode=None): res = {} for dest,f in (('name','string'),('model','model'),('report_name','name')): @@ -328,15 +321,12 @@ form: module.record_id""" % (xml_id,) self.idref[xml_id] = int(id) if not rec.get('menu') or safe_eval(rec.get('menu','False')): - keyword = str(rec.get('keyword', 'client_print_multi')) - value = 'ir.actions.report,'+str(id) - action = self.env['ir.values'].set_action(res['name'], keyword, res['model'], value) - self.env['ir.actions.report'].browse(id).write({'ir_values_id': action.id}) + report = self.env['ir.actions.report'].browse(id) + report.create_action() elif self.mode=='update' and safe_eval(rec.get('menu','False'))==False: # Special check for report having attribute menu=False on update - value = 'ir.actions.report,'+str(id) - self._remove_ir_values(res['name'], value, res['model']) - self.env['ir.actions.report'].browse(id).write({'ir_values_id': False}) + report = self.env['ir.actions.report'].browse(id) + report.unlink_action() return id def _tag_function(self, rec, data_node=None, mode=None): @@ -437,46 +427,14 @@ form: module.record_id""" % (xml_id,) if rec.get('target'): res['target'] = rec.get('target','') + if src_model: + res['binding_model_id'] = self.env['ir.model']._get(src_model).id + res['binding_type'] = 'report' if rec.get('key2') == 'client_print_multi' else 'action' if rec.get('multi'): res['multi'] = safe_eval(rec.get('multi', 'False')) id = self.env['ir.model.data']._update('ir.actions.act_window', self.module, res, xml_id, noupdate=self.isnoupdate(data_node), mode=self.mode) self.idref[xml_id] = int(id) - if src_model: - #keyword = 'client_action_relate' - res_id = False - model = src_model - if isinstance(model, (list, tuple)): - model, res_id = model - keyword = rec.get('key2') or 'client_action_relate' - value = 'ir.actions.act_window,%s' % id - replace = rec.get('replace') or True - self.env['ir.values'].set_action(xml_id, action_slot=keyword, model=model, action=value, res_id=res_id) - # TODO add remove ir.model.data - - def _tag_ir_set(self, rec, data_node=None, mode=None): - """ - .. deprecated:: 9.0 - - Use the notation with ``ir.values`` as model instead. - """ - if self.mode != 'init': - return - res = {} - for field in rec.findall('./field'): - f_name = field.get("name") - f_val = _eval_xml(self, field, self.env) - res[f_name] = f_val - ir_values = self.env['ir.values'] - for model in res['models']: - res_id = False - if isinstance(model, (list, tuple)): - model, res_id = model - if res['key'] == 'default': - ir_values.set_default(model, field_name=res['name'], value=res['value'], condition=res['key2']) - elif res['key'] == 'action': - ir_values.set_action(res['name'], action_slot=res['key2'], model=model, action=res['value'], res_id=res_id) - def _tag_menuitem(self, rec, data_node=None, mode=None): rec_id = rec.get("id") self._test_xml_id(rec_id) @@ -812,7 +770,6 @@ form: module.record_id""" % (xml_id,) 'menuitem': self._tag_menuitem, 'template': self._tag_template, 'report': self._tag_report, - 'ir_set': self._tag_ir_set, # deprecated:: 9.0 'act_window': self._tag_act_window, 'assert': self._tag_assert, } diff --git a/odoo/tools/yaml_import.py b/odoo/tools/yaml_import.py index 79f997045a2..674047cd22a 100644 --- a/odoo/tools/yaml_import.py +++ b/odoo/tools/yaml_import.py @@ -79,9 +79,6 @@ def is_ref(node): return isinstance(node, yaml_tag.Ref) \ or _is_yaml_mapping(node, yaml_tag.Ref) -def is_ir_set(node): - return _is_yaml_mapping(node, yaml_tag.IrSet) - def is_string(node): return isinstance(node, pycompat.string_types) @@ -728,17 +725,12 @@ class YamlInterpreter(object): if node.target: values['target'] = node.target + + if node.src_model and isinstance(node.src_model, basestring): + values['binding_model_id'] = self.env['ir.model']._get(node.src_model).id + id = self.sudo_env['ir.model.data']._update('ir.actions.act_window', self.module, values, node.id, mode=self.mode) self.id_map[node.id] = int(id) - - if node.src_model: - keyword = 'client_action_relate' - value = 'ir.actions.act_window,%s' % id - res_id = False - model = node.src_model - if isinstance(model, (list, tuple)): - model, res_id = model - self.env['ir.values'].sudo().set_action(node.id, action_slot=keyword, model=model, action=value, res_id=res_id) # TODO add remove ir.model.data def process_delete(self, node): @@ -755,37 +747,13 @@ class YamlInterpreter(object): def process_url(self, node): self.validate_xml_id(node.id) - res = {'name': node.name, 'url': node.url, 'target': node.target} - id = self.sudo_env['ir.model.data']._update("ir.actions.act_url", self.module, res, node.id, mode=self.mode) self.id_map[node.id] = int(id) # ir_set if (not node.menu or safe_eval(node.menu)) and id: - keyword = node.keyword or 'client_action_multi' - value = 'ir.actions.act_url,%s' % id - self.env['ir.values'].sudo().set_action(node.url, action_slot=keyword, model="ir.actions.act_url", action=value, res_id=False) - - def process_ir_set(self, node): - if not self.mode == 'init': - return False - _, fields = list(node.items())[0] - res = {} - for fieldname, expression in fields.items(): - if is_eval(expression): - value = safe_eval(expression.expression, self.eval_context) - else: - value = expression - res[fieldname] = value - ir_values = self.env['ir.values'] - for model in res['models']: - res_id = False - if isinstance(model, (list, tuple)): - model, res_id = model - if res['key'] == 'default': - ir_values.sudo().set_default(model, field_name=res['name'], value=res['value'], condition=res['key2']) - elif res['key'] == 'action': - ir_values.sudo().set_action(res['name'], action_slot=res['key2'], model=model, action=res['value'], res_id=res_id) + action = self.env['ir.actions.actions'].browse(int(id)) + action.binding_model_id = self.env['ir.model']._get('ir.actions.act_url') def process_report(self, node): values = {} @@ -806,14 +774,8 @@ class YamlInterpreter(object): self.id_map[xml_id] = int(id) if not node.menu or safe_eval(node.menu): - keyword = node.keyword or 'client_print_multi' - value = 'ir.actions.report,%s' % id - ir_values = self.env['ir.values'] - res_id = False - model = values['model'] - if isinstance(model, (list, tuple)): - model, res_id = model - ir_values.sudo().set_action(values['name'], action_slot=keyword, model=model, action=value, res_id=res_id) + report = self.env['ir.actions.report'].browse(id) + report.create_action() def process_none(self): """ @@ -854,8 +816,6 @@ class YamlInterpreter(object): self.process_url(node) elif is_context(node): self.process_context(node) - elif is_ir_set(node): - self.process_ir_set(node) elif is_act_window(node): self.process_act_window(node) elif is_report(node): diff --git a/odoo/tools/yaml_tag.py b/odoo/tools/yaml_tag.py index 9f57111bf37..eb9c6357ae8 100644 --- a/odoo/tools/yaml_tag.py +++ b/odoo/tools/yaml_tag.py @@ -91,10 +91,6 @@ class Ref(YamlTag): def __str__(self): return 'ref(%s)' % repr(self.expr) -class IrSet(YamlTag): - def __init__(self): - super(IrSet, self).__init__() - def assert_constructor(loader, node): kwargs = loader.construct_mapping(node) return Assert(**kwargs) @@ -149,10 +145,6 @@ def ref_constructor(loader, tag_suffix, node): kwargs = loader.construct_mapping(node) return Ref(**kwargs) -def ir_set_constructor(loader, node): - kwargs = loader.construct_mapping(node) - return IrSet(**kwargs) - # Registers constructors for custom tags. # Constructors are actually defined globally: do not redefined them in another # class/file/package. This means that module recorder need import this file. @@ -169,5 +161,4 @@ def add_constructors(): yaml.add_constructor(u"!url", url_constructor) yaml.add_constructor(u"!eval", eval_constructor) yaml.add_multi_constructor(u"!ref", ref_constructor) - yaml.add_constructor(u"!ir_set", ir_set_constructor) add_constructors()