Search code examples
odooodoo-17

How do I restrict menu (website.menu) access for different types of portal users (e.g., Employees and Parents)?


im trying to restrict the menus (website.menu) based on the for different types of portal users signed in,

I tried inheriting the compute visibility function from base as follows:

class WebsiteMenu(models.Model):
_inherit = 'website.menu'

restricted = fields.Boolean(string='Restricted', default=False)
parent_menu = fields.Boolean(string='Parent Menu', default=False)
employee_menu = fields.Boolean(string='Employee Menu', default=False)
manager_menu = fields.Boolean(string='Manager Menu', default=False)
need_request_menu = fields.Boolean(string='Need Request Menu', default=False)

def _compute_visible(self):
    """Compute menu visibility"""
    super()._compute_visible()
    for menu in self:
        if not menu.is_visible:
            continue
        employee_id = self.env.user.employee_id or self.env.user.existing_employee_id
        is_user_or_portal = self.env.user.has_group('base.group_user') or self.env.user.has_group(
            'base.group_portal')
        if menu.employee_menu or menu.manager_menu:
            if not employee_id or not is_user_or_portal:
                menu.is_visible = False
                continue
        if menu.manager_menu and employee_id:
            employees = self.env['hr.employee'].sudo().search([('parent_id', '=', employee_id.id)])
            if not employees:
                menu.is_visible = False
                continue
        if menu.need_request_menu and employee_id:
            if not employee_id.need_request:
                menu.is_visible = False
                continue
        is_parent = self.env.user.parent_id
        if menu.parent_menu and not (is_user_or_portal and is_parent):
            menu.is_visible = False
            continue

Views.xml

<record id="parent_payment_menu" model="website.menu">
    <field name="name">Payments</field>
    <field name="url">my/payments</field>
    <field name="parent_id" ref="website.main_menu"/>
    <field name="sequence" type="int">60</field>
    <field name="parent_menu" eval="True"/>
</record>
<record id="leave_main_menu" model="website.menu">
        <field name="name">My Leave Management</field>
        <field name="parent_id" ref="website.main_menu"/>
        <field name="sequence" type="int">50</field>
        <field name="employee_menu" eval="True"/>
    </record>
    <record id="manager_attendances_menu" model="website.menu">
        <field name="name">Employee's Attendances</field>
        <field name="url">manager/employee_attendances</field>
        <field name="parent_id" ref="website.main_menu"/>
        <field name="sequence" type="int">51</field>
        <field name="manager_menu" eval="True"/>
    </record>
        <record id="need_request_main_menu" model="website.menu">
        <field name="name">Need Requests</field>
        <field name="parent_id" ref="website.main_menu"/>
        <field name="sequence" type="int">50</field>
        <field name="need_request_menu" eval="True"/>
    </record>

Still im not able to restrict the views based on the user, i have the logic to check which kind of user is logged in. Please educate me if i'm missing anything?

Or there is any other method to handle those views? Basically both are portal users.


Solution

  • I may not have the full answer, because I only have experience with Odoo16 on this topic. In addition to overwriting the method like you did, it is necessary in v16 to disable the caching of the menus by inheriting website.layout and removing the t-cache attribute. (see code block below)

    It seems that in Odoo17 this issue is kind of addressed already, but not exactly the way you want: https://github.com/odoo/odoo/blob/17.0/addons/website/views/website_templates.xml#L160

    There is a function on the website model, which checks if menu caching is possible or not: https://github.com/odoo/odoo/blob/17.0/addons/website/models/website.py#L193C9-L193C31

    As you can see from the comment, this check is related to the URLs of websites and if any is linked to a record (in which case the caching is disabled).

    You can probably inherit website model, overwrite this method and always return True. Alternatively you inherit website.layout and remove the t-cache attribute (like I did in v16).

    <template id="website_layout_menu_no_cache" inherit_id="website.layout" name="No cache on website layout header">
        <xpath expr="//header/t[@t-cache]" position="attributes">
            <attribute name="t-cache"/>
        </xpath>
    </template>