odoo18/addons_extensions/menu_control_center/models/masters.py

248 lines
8.7 KiB
Python

from odoo import api, fields, models, _
class MasterControl(models.Model):
_name = 'master.control'
_description = 'Master Control'
_order = 'sequence, name, id'
sequence = fields.Integer()
name = fields.Char(string='Master Name', required=True)
code = fields.Char(string='Code', required=True)
user_ids = fields.Many2many(
'res.users',
'master_control_res_users_rel',
'master_control_id',
'user_id',
string='Users',
)
menu_line_ids = fields.One2many(
'master.control.menu.line',
'master_control_id',
string='Menus',
domain=[('menu_id.parent_id', '=', False)],
)
submenu_line_ids = fields.One2many(
'master.control.menu.line',
'master_control_id',
string='Sub Menus',
domain=[('menu_id.parent_id', '!=', False)],
)
allowed_menu_ids = fields.Many2many(
'ir.ui.menu',
compute='_compute_allowed_menu_ids',
string='Allowed Menus',
)
_sql_constraints = [
('master_control_code_unique', 'unique(code)', 'Master code must be unique.'),
]
@api.depends('name', 'code')
def _compute_display_name(self):
for record in self:
if record.name:
record.display_name = record.name + (f' ({record.code})' if record.code else '')
else:
record.display_name = False
@api.depends('menu_line_ids.show_menu', 'menu_line_ids.menu_id', 'submenu_line_ids.show_menu', 'submenu_line_ids.menu_id')
def _compute_allowed_menu_ids(self):
for record in self:
all_lines = record.menu_line_ids | record.submenu_line_ids
visible_menu_ids = record._expand_menu_ids(all_lines.filtered('show_menu').mapped('menu_id').ids)
hidden_menu_ids = record._expand_menu_ids(all_lines.filtered(lambda line: not line.show_menu).mapped('menu_id').ids)
menus = self.env['ir.ui.menu'].browse(list(visible_menu_ids - hidden_menu_ids))
ancestors = self.env['ir.ui.menu']
for menu in menus:
parent = menu.parent_id
while parent:
ancestors |= parent
parent = parent.parent_id
record.allowed_menu_ids = menus | ancestors
def _expand_menu_ids(self, menu_ids):
if not menu_ids:
return set()
return set(
self.env['ir.ui.menu']
.sudo()
.with_context({'ir.ui.menu.full_list': True})
.search([('id', 'child_of', list(menu_ids))]).ids
)
def _get_all_menus_sql(self):
self.env.cr.execute("""
WITH RECURSIVE menu_tree AS (
SELECT id, parent_id
FROM ir_ui_menu
WHERE parent_id IS NULL
AND active = true
UNION ALL
SELECT menu.id, menu.parent_id
FROM ir_ui_menu menu
JOIN menu_tree tree ON tree.id = menu.parent_id
WHERE menu.active = true
)
SELECT id, parent_id
FROM menu_tree
ORDER BY parent_id NULLS FIRST, id
""")
return self.env.cr.dictfetchall()
def _sync_menu_lines(self, create_missing_only=False):
line_model = self.env['master.control.menu.line']
notification_count = 0
for record in self:
menus = record._get_all_menus_sql()
children_map = {}
for menu in menus:
children_map.setdefault(menu['parent_id'], []).append(menu)
existing_lines = {
line.menu_id.id: line
for line in record.menu_line_ids | record.submenu_line_ids
}
if not create_missing_only:
(record.menu_line_ids | record.submenu_line_ids).unlink()
existing_lines = {}
for main_menu in children_map.get(None, []):
parent_line = existing_lines.get(main_menu['id'])
if not parent_line:
parent_line = line_model.create({
'master_control_id': record.id,
'menu_id': main_menu['id'],
'show_menu': True,
})
existing_lines[main_menu['id']] = parent_line
notification_count += 1
stack = list(children_map.get(main_menu['id'], []))
while stack:
submenu = stack.pop()
if submenu['id'] not in existing_lines:
line_model.create({
'master_control_id': record.id,
'menu_id': submenu['id'],
'show_menu': True,
'parent_line_id': parent_line.id,
})
existing_lines[submenu['id']] = True
notification_count += 1
stack.extend(children_map.get(submenu['id'], []))
return notification_count
def action_generate_menus(self):
self._sync_menu_lines(create_missing_only=False)
return {
'type': 'ir.actions.client',
'tag': 'display_notification',
'params': {
'title': _('Success'),
'message': _('Menus generated successfully.'),
'type': 'success',
'sticky': False,
},
}
def action_update_menus(self):
created_count = self._sync_menu_lines(create_missing_only=True)
return {
'type': 'ir.actions.client',
'tag': 'display_notification',
'params': {
'title': _('Success') if created_count else _('Info'),
'message': _('Added %s new menu(s).') % created_count if created_count else _('No new menus found to add.'),
'type': 'success' if created_count else 'info',
'sticky': False,
},
}
@api.model_create_multi
def create(self, vals_list):
records = super().create(vals_list)
self.env['ir.ui.menu'].sudo().clear_caches()
return records
def write(self, vals):
result = super().write(vals)
self.env['ir.ui.menu'].sudo().clear_caches()
return result
class MasterControlMenuLine(models.Model):
_name = 'master.control.menu.line'
_description = 'Master Control Menu Line'
_rec_name = 'menu_id'
_order = 'menu_id'
master_control_id = fields.Many2one('master.control', required=True, ondelete='cascade')
menu_id = fields.Many2one('ir.ui.menu', string='Menu', required=True)
show_menu = fields.Boolean(string='Show Menu', default=True)
parent_menu_id = fields.Many2one('ir.ui.menu', related='menu_id.parent_id', string='Parent Menu', store=True)
parent_line_id = fields.Many2one('master.control.menu.line', string='Parent Line')
_sql_constraints = [
('master_control_menu_unique', 'unique(master_control_id, menu_id)', 'Menu already exists for this master control.'),
]
def open_submenus_popup_view(self):
self.ensure_one()
return {
'name': _('Sub Menus'),
'type': 'ir.actions.act_window',
'res_model': 'master.control.menu.line',
'view_mode': 'list',
'views': [
(self.env.ref('menu_control_center.view_master_submenu_line_list').id, 'list'),
],
'target': 'new',
'domain': [('parent_line_id', '=', self.id)],
}
@api.model_create_multi
def create(self, vals_list):
records = super().create(vals_list)
self.env['ir.ui.menu'].sudo().clear_caches()
return records
def write(self, vals):
result = super().write(vals)
self.env['ir.ui.menu'].sudo().clear_caches()
return result
def unlink(self):
result = super().unlink()
self.env['ir.ui.menu'].sudo().clear_caches()
return result
class ResUsers(models.Model):
_inherit = 'res.users'
master_control_ids = fields.Many2many(
'master.control',
'master_control_res_users_rel',
'user_id',
'master_control_id',
string='Master Controls',
help='Masters this user is allowed to access. Updating this field also updates the Users field on the master.',
)
@api.model_create_multi
def create(self, vals_list):
records = super().create(vals_list)
if any('master_control_ids' in vals for vals in vals_list):
self.env['ir.ui.menu'].sudo().clear_caches()
return records
def write(self, vals):
result = super().write(vals)
if 'master_control_ids' in vals:
self.env['ir.ui.menu'].sudo().clear_caches()
return result