204 lines
7.1 KiB
Python
204 lines
7.1 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)', "Only one service can exist with a specific control_unit. 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')
|
||
|
||
|
||
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 action_generate_menus(self):
|
||
"""
|
||
Generate main menus and all submenus (recursive),
|
||
and set access_line_id for every submenu.
|
||
"""
|
||
for rec in self:
|
||
|
||
# clear old menus
|
||
rec.access_menu_line_ids.unlink()
|
||
rec.access_sub_menu_line_ids.unlink()
|
||
|
||
active_menus = self.env['ir.ui.menu'].search([
|
||
('parent_id', '=', False),
|
||
('active', '=', True)
|
||
])
|
||
|
||
for menu in active_menus:
|
||
|
||
# 1️⃣ Create main menu line
|
||
main_line = self.env['menu.access.line'].create({
|
||
'access_control_id': rec.id,
|
||
'menu_id': menu.id,
|
||
'is_main_menu': True,
|
||
})
|
||
|
||
# 2️⃣ Fetch all recursive submenus
|
||
submenus = self._get_all_submenus(menu)
|
||
|
||
# 3️⃣ Create submenu lines with correct parent
|
||
for sm in submenus:
|
||
self.env['menu.access.line'].create({
|
||
'access_control_id': rec.id,
|
||
'menu_id': sm.id,
|
||
'is_main_menu': True,
|
||
'access_line_id': main_line.id, # important
|
||
})
|
||
|
||
def action_update_menus(self):
|
||
line = self.env['menu.access.line']
|
||
menu = self.env['ir.ui.menu']
|
||
|
||
for rec in self:
|
||
created_count = 0
|
||
|
||
# All existing menu IDs across BOTH One2manys
|
||
existing_menu_ids = set(
|
||
rec.access_menu_line_ids.mapped('menu_id.id') +
|
||
rec.access_sub_menu_line_ids.mapped('menu_id.id')
|
||
)
|
||
|
||
# ---------- Step 1: Ensure all top-level menus exist ----------
|
||
top_menus = menu.search([
|
||
('parent_id', '=', False),
|
||
('active', '=', True),
|
||
])
|
||
|
||
for menu in top_menus:
|
||
|
||
# Create missing MAIN MENU
|
||
main_line = line.search([
|
||
('access_control_id', '=', rec.id),
|
||
('menu_id', '=', menu.id),
|
||
('access_line_id', '=', False)
|
||
], limit=1)
|
||
|
||
if not main_line:
|
||
main_line = line.create({
|
||
'access_control_id': rec.id,
|
||
'menu_id': menu.id,
|
||
'is_main_menu': True,
|
||
})
|
||
created_count += 1
|
||
existing_menu_ids.add(menu.id)
|
||
|
||
# ---------- Step 2: Ensure all SUBMENUS exist ----------
|
||
submenus = rec._get_all_submenus(menu)
|
||
|
||
for sm in submenus:
|
||
|
||
# If submenu is missing → create it
|
||
if sm.id not in existing_menu_ids:
|
||
line.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)
|
||
|
||
# ---------- Notification ----------
|
||
if created_count:
|
||
return {
|
||
'type': 'ir.actions.client',
|
||
'tag': 'display_notification',
|
||
'params': {
|
||
'title': _('Success'),
|
||
'message': _('Added %s new menu(s) (including submenus)') % created_count,
|
||
'type': 'success',
|
||
'sticky': False,
|
||
}
|
||
}
|
||
else:
|
||
return {
|
||
'type': 'ir.actions.client',
|
||
'tag': 'display_notification',
|
||
'params': {
|
||
'title': _('Info'),
|
||
'message': _('No new menus found to add.'),
|
||
'type': '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},
|
||
}
|
||
|
||
|
||
|