229 lines
7.8 KiB
Python
229 lines
7.8 KiB
Python
# models/models.py
|
|
from odoo import models, fields, api, tools, _
|
|
from collections import defaultdict
|
|
|
|
class MenuControlUnits(models.Model):
|
|
_name = 'menu.control.units'
|
|
_rec_name = 'unit_name'
|
|
|
|
_sql_constraints = [
|
|
('unique_unit_name', 'UNIQUE(unit_name)', "'Unit Name' already defined. Please don't confuse me 😤.")
|
|
]
|
|
|
|
unit_name = fields.Char(string='Unit Name',required=True)
|
|
department_ids = fields.Many2many('hr.department')
|
|
|
|
user_ids = fields.Many2many('res.users')
|
|
|
|
def generate_department_user_ids(self):
|
|
for rec in self:
|
|
user_ids = self.env['hr.employee'].sudo().search([('department_id','in',rec.department_ids.ids)]).user_id.ids
|
|
self.write({
|
|
'user_ids': [(6, 0, user_ids)]
|
|
})
|
|
|
|
class MenuAccessControl(models.Model):
|
|
_name = 'menu.access.control'
|
|
_description = 'Menu Access Control'
|
|
_rec_name = 'control_unit'
|
|
|
|
_sql_constraints = [
|
|
('unique_control_unit', 'UNIQUE(control_unit, master_control)', "Only one service can exist with a specific control_unit & Master. Please don't confuse me 🤪.")
|
|
]
|
|
|
|
control_unit = fields.Many2one('menu.control.units',required=True)
|
|
user_ids = fields.Many2many('res.users', string="Users", related='control_unit.user_ids')
|
|
master_control = fields.Many2one('master.control')
|
|
|
|
|
|
access_menu_line_ids = fields.One2many(
|
|
'menu.access.line', 'access_control_id',
|
|
string="Accessible Menus", domain=[('menu_id.parent_id','=',False)]
|
|
)
|
|
|
|
access_sub_menu_line_ids = fields.One2many('menu.access.line', 'access_control_id',
|
|
string="Accessible Menus", domain=[('menu_id.parent_id','!=',False)]
|
|
)
|
|
|
|
def _get_all_submenus(self, menu):
|
|
"""Returns all submenus recursively for a given menu."""
|
|
submenus = self.env['ir.ui.menu'].search([('parent_id', '=', menu.id), ('active', '=', True)])
|
|
all_subs = submenus
|
|
for sm in submenus:
|
|
all_subs |= self._get_all_submenus(sm)
|
|
return all_subs
|
|
|
|
def _get_all_menus_sql(self):
|
|
"""
|
|
Fetch all active menus with hierarchy using SQL
|
|
Returns list of dicts:
|
|
[
|
|
{id, parent_id}
|
|
]
|
|
"""
|
|
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 m.id, m.parent_id
|
|
FROM ir_ui_menu m
|
|
JOIN menu_tree mt ON mt.id = m.parent_id
|
|
WHERE m.active = true
|
|
)
|
|
SELECT id, parent_id
|
|
FROM menu_tree
|
|
ORDER BY parent_id NULLS FIRST, id
|
|
""")
|
|
return self.env.cr.dictfetchall()
|
|
|
|
def action_generate_menus(self):
|
|
"""
|
|
Generate main menus and all submenus (SQL-based),
|
|
and set access_line_id for every submenu.
|
|
"""
|
|
MenuLine = self.env['menu.access.line']
|
|
|
|
for rec in self:
|
|
# Clear old menus
|
|
rec.access_menu_line_ids.unlink()
|
|
rec.access_sub_menu_line_ids.unlink()
|
|
|
|
menus = rec._get_all_menus_sql()
|
|
|
|
# Map: parent_id -> children
|
|
children_map = {}
|
|
for m in menus:
|
|
children_map.setdefault(m['parent_id'], []).append(m)
|
|
|
|
# ---------- Main menus ----------
|
|
for main in children_map.get(None, []):
|
|
|
|
main_line = MenuLine.create({
|
|
'access_control_id': rec.id,
|
|
'menu_id': main['id'],
|
|
'is_main_menu': True,
|
|
})
|
|
|
|
# ---------- Submenus ----------
|
|
stack = children_map.get(main['id'], [])
|
|
while stack:
|
|
sm = stack.pop()
|
|
MenuLine.create({
|
|
'access_control_id': rec.id,
|
|
'menu_id': sm['id'],
|
|
'is_main_menu': True,
|
|
'access_line_id': main_line.id,
|
|
})
|
|
stack.extend(children_map.get(sm['id'], []))
|
|
|
|
def action_update_menus(self):
|
|
MenuLine = self.env['menu.access.line']
|
|
|
|
for rec in self:
|
|
created_count = 0
|
|
|
|
# Existing menu IDs
|
|
existing_menu_ids = set(
|
|
rec.access_menu_line_ids.mapped('menu_id.id') +
|
|
rec.access_sub_menu_line_ids.mapped('menu_id.id')
|
|
)
|
|
|
|
menus = rec._get_all_menus_sql()
|
|
|
|
# Map parent -> children
|
|
children_map = {}
|
|
for m in menus:
|
|
children_map.setdefault(m['parent_id'], []).append(m)
|
|
|
|
# ---------- Main menus ----------
|
|
for main in children_map.get(None, []):
|
|
|
|
main_line = MenuLine.search([
|
|
('access_control_id', '=', rec.id),
|
|
('menu_id', '=', main['id']),
|
|
('access_line_id', '=', False),
|
|
], limit=1)
|
|
|
|
if not main_line:
|
|
main_line = MenuLine.create({
|
|
'access_control_id': rec.id,
|
|
'menu_id': main['id'],
|
|
'is_main_menu': True,
|
|
})
|
|
created_count += 1
|
|
existing_menu_ids.add(main['id'])
|
|
|
|
# ---------- Submenus ----------
|
|
stack = children_map.get(main['id'], [])
|
|
while stack:
|
|
sm = stack.pop()
|
|
|
|
if sm['id'] not in existing_menu_ids:
|
|
MenuLine.create({
|
|
'access_control_id': rec.id,
|
|
'menu_id': sm['id'],
|
|
'is_main_menu': True,
|
|
'access_line_id': main_line.id,
|
|
})
|
|
created_count += 1
|
|
existing_menu_ids.add(sm['id'])
|
|
|
|
stack.extend(children_map.get(sm['id'], []))
|
|
|
|
# ---------- Notification ----------
|
|
return {
|
|
'type': 'ir.actions.client',
|
|
'tag': 'display_notification',
|
|
'params': {
|
|
'title': _('Success') if created_count else _('Info'),
|
|
'message': (
|
|
_('Added %s new menu(s) (including submenus)') % created_count
|
|
if created_count else
|
|
_('No new menus found to add.')
|
|
),
|
|
'type': 'success' if created_count else 'info',
|
|
'sticky': False,
|
|
}
|
|
}
|
|
|
|
|
|
class MenuAccessLine(models.Model):
|
|
_name = 'menu.access.line'
|
|
_description = 'Menu Access Line'
|
|
_rec_name = 'menu_id'
|
|
|
|
access_control_id = fields.Many2one('menu.access.control', ondelete='cascade')
|
|
menu_id = fields.Many2one('ir.ui.menu', string="Menu")
|
|
is_main_menu = fields.Boolean(string="Is Main Menu", default=True)
|
|
parent_menu = fields.Many2one('ir.ui.menu',related='menu_id.parent_id')
|
|
access_line_id = fields.Many2one('menu.access.line')
|
|
control_unit = fields.Many2one(
|
|
'menu.control.units',
|
|
related='access_control_id.control_unit',
|
|
store=True
|
|
)
|
|
|
|
def open_submenus_popup_view(self):
|
|
self.ensure_one()
|
|
|
|
return {
|
|
"name": _("Sub Menus"),
|
|
"type": "ir.actions.act_window",
|
|
"res_model": "menu.access.line",
|
|
"view_mode": "list,form",
|
|
"views": [
|
|
(self.env.ref("menu_control_center.view_submenu_line_list").id, "list"),
|
|
],
|
|
"target": "new",
|
|
"domain": [("access_line_id", "=", self.id)],
|
|
"context": {"default_access_line_id": self.id},
|
|
}
|
|
|
|
|
|
|