first commit

This commit is contained in:
Suherdy Yacob 2026-01-05 12:03:16 +07:00
commit 6601b57833
11 changed files with 188 additions and 0 deletions

38
README.md Normal file
View File

@ -0,0 +1,38 @@
# Access Restriction By User
This module allows administrators to restrict user access to specific records in Inventory, Manufacturing, and Approvals without using complex Record Rules.
## Features
Restrict visibility of the following records based on User configuration:
* **Warehouses** (`stock.warehouse`)
* **Picking Types** (`stock.picking.type`)
* **Locations** (`stock.location`)
* **Work Centers** (`mrp.workcenter`)
* **Approval Categories** (`approval.category`)
## Configuration
1. Navigate to **Settings > Users & Companies > Users**.
2. Select the user you want to restrict.
3. Go to the **Access Restrictions** tab.
4. Add records to the following fields:
* **Allowed Warehouses**
* **Allowed Picking Types**
* **Allowed Locations**
* **Allowed Work Centers**
* **Allowed Approvals**
## Important Usage Notes
* **Empty List = Unrestricted**: If an "Allowed" field is left empty for a user, they will have access to **ALL** records of that type.
* **Populated List = Restricted**: If one or more records are added, the user will **ONLY** see those specific records.
* **Superuser**: The Superuser (OdooBot) and administrators bypassing access rights are not affected by these restrictions.
## Technical Details
This module overrides the `_search` method on the target models to apply a domain filter based on the current user's allowed list. This ensures consistency across views (list, kanban, many2one dropdowns) and avoids common issues associated with Record Rules.
## Author
Suherdy Yacob

1
__init__.py Normal file
View File

@ -0,0 +1 @@
from . import models

26
__manifest__.py Normal file
View File

@ -0,0 +1,26 @@
{
'name': 'Access Restriction By User',
'version': '18.0.1.0.0',
'summary': 'Restrict access to Warehouses, Picking Types, Locations, Work Centers, and Approvals by User',
'description': """
Restricts visibility of:
- Warehouses
- Picking Types
- Locations
- Work Centers
- Approval Categories
Files are filtered based on "Allowed" lists in the User Settings.
If the allowed list is empty, the user sees all records (default behavior).
Does NOT use Record Rules.
""",
'category': 'Extra Tools',
'author': 'Suherdy Yacob',
'depends': ['base', 'stock', 'mrp', 'approvals'],
'data': [
'views/res_users_views.xml',
],
'installable': True,
'application': False,
'license': 'LGPL-3',
}

Binary file not shown.

2
models/__init__.py Normal file
View File

@ -0,0 +1,2 @@
from . import res_users
from . import restricted_models

Binary file not shown.

Binary file not shown.

Binary file not shown.

49
models/res_users.py Normal file
View File

@ -0,0 +1,49 @@
from odoo import models, fields
class ResUsers(models.Model):
_inherit = 'res.users'
allowed_warehouse_ids = fields.Many2many(
'stock.warehouse',
'res_users_stock_warehouse_rel',
'user_id',
'warehouse_id',
string="Allowed Warehouses",
help="Warehouses this user is allowed to access. Leave empty to allow all."
)
allowed_picking_type_ids = fields.Many2many(
'stock.picking.type',
'res_users_stock_picking_type_rel',
'user_id',
'picking_type_id',
string="Allowed Picking Types",
help="Picking Types this user is allowed to access. Leave empty to allow all."
)
allowed_location_ids = fields.Many2many(
'stock.location',
'res_users_stock_location_rel',
'user_id',
'location_id',
string="Allowed Locations",
help="Locations this user is allowed to access. Leave empty to allow all."
)
allowed_workcenter_ids = fields.Many2many(
'mrp.workcenter',
'res_users_mrp_workcenter_rel',
'user_id',
'workcenter_id',
string="Allowed Work Centers",
help="Work Centers this user is allowed to access. Leave empty to allow all."
)
allowed_approval_category_ids = fields.Many2many(
'approval.category',
'res_users_approval_category_rel',
'user_id',
'category_id',
string="Allowed Approvals",
help="Approval Categories this user is allowed to access. Leave empty to allow all."
)

View File

@ -0,0 +1,47 @@
from odoo import models, api
from odoo.osv import expression
class StockWarehouse(models.Model):
_inherit = 'stock.warehouse'
@api.model
def _search(self, domain, offset=0, limit=None, order=None):
if not self.env.su and self.env.user.allowed_warehouse_ids:
domain = expression.AND([domain or [], [('id', 'in', self.env.user.allowed_warehouse_ids.ids)]])
return super()._search(domain, offset=offset, limit=limit, order=order)
class StockPickingType(models.Model):
_inherit = 'stock.picking.type'
@api.model
def _search(self, domain, offset=0, limit=None, order=None):
if not self.env.su and self.env.user.allowed_picking_type_ids:
domain = expression.AND([domain or [], [('id', 'in', self.env.user.allowed_picking_type_ids.ids)]])
return super()._search(domain, offset=offset, limit=limit, order=order)
class StockLocation(models.Model):
_inherit = 'stock.location'
@api.model
def _search(self, domain, offset=0, limit=None, order=None):
if not self.env.su and self.env.user.allowed_location_ids:
domain = expression.AND([domain or [], [('id', 'in', self.env.user.allowed_location_ids.ids)]])
return super()._search(domain, offset=offset, limit=limit, order=order)
class MrpWorkcenter(models.Model):
_inherit = 'mrp.workcenter'
@api.model
def _search(self, domain, offset=0, limit=None, order=None):
if not self.env.su and self.env.user.allowed_workcenter_ids:
domain = expression.AND([domain or [], [('id', 'in', self.env.user.allowed_workcenter_ids.ids)]])
return super()._search(domain, offset=offset, limit=limit, order=order)
class ApprovalCategory(models.Model):
_inherit = 'approval.category'
@api.model
def _search(self, domain, offset=0, limit=None, order=None):
if not self.env.su and self.env.user.allowed_approval_category_ids:
domain = expression.AND([domain or [], [('id', 'in', self.env.user.allowed_approval_category_ids.ids)]])
return super()._search(domain, offset=offset, limit=limit, order=order)

25
views/res_users_views.xml Normal file
View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="view_users_form_inherit_access_restriction" model="ir.ui.view">
<field name="name">res.users.form.inherit.access.restriction</field>
<field name="model">res.users</field>
<field name="inherit_id" ref="base.view_users_form"/>
<field name="arch" type="xml">
<notebook position="inside">
<page string="Access Restrictions" name="access_restrictions">
<group>
<group string="Inventory">
<field name="allowed_warehouse_ids" widget="many2many_tags"/>
<field name="allowed_picking_type_ids" widget="many2many_tags"/>
<field name="allowed_location_ids" widget="many2many_tags"/>
</group>
<group string="Manufacturing &amp; others">
<field name="allowed_workcenter_ids" widget="many2many_tags"/>
<field name="allowed_approval_category_ids" widget="many2many_tags"/>
</group>
</group>
</page>
</notebook>
</field>
</record>
</odoo>