Skip to content

Odoo 19 Multi-Company & Multi-Warehouse Access Management Using Studio

Odoo 19 Multi-Company & Multi-Warehouse Access Management Using Studio

Managing inventory across multiple companies and warehouses becomes challenging the moment different users need different levels of access.

Consider a typical requirement:

  • A warehouse user should access only WH/India.
  • Another user should access WH/UAE.
  • A regional manager should access both.
  • A corporate inventory manager should access all warehouses within their allowed companies.
  • Manufacturing users should be able to create and process Manufacturing Orders without Odoo’s internal stock moves being blocked by security rules.

Odoo provides Access Rights and Record Rules to achieve this. With Odoo Studio, we can extend this into a practical Allowed Warehouse access-management framework without immediately developing a custom module.

1. The Business Requirement

The objective is to create a simple rule:

If no warehouse restriction is applied, the user can access all warehouses belonging to their allowed companies. If warehouse restriction is enabled, the user can access only the warehouses assigned to them.

For example:

UserAllowed CompaniesAllowed WarehousesResult
Warehouse ManagerIndiaEmptyAll India warehouses
Regional ManagerIndia + UAEEmptyAll India + UAE warehouses
India UserIndia + UAEWH/IndiaWH/India only
Regional UserIndia + UAEWH/India + WH/UAEBoth warehouses

The important principle is:

Company access remains the first security boundary.

A warehouse should never give a user access to a company that is not already included in the user’s Odoo Allowed Companies.

2. Access Rights vs Record Rules

Before configuring anything, it is important to understand the difference.

Access Rights

Access Rights answer: “Can this user access this model?”

For example, on stock.picking:

ModelReadWriteCreateDelete
stock.picking

Record Rules

Record Rules answer: “Which records of this model can this user access?”

For example: a user can access stock.picking, but only pickings belonging to WH/India.

Therefore, our solution uses:

Access Rights + Record Rules + Allowed Companies + Allowed Warehouses

3. Configure Allowed Companies

First configure Odoo’s standard company access.

Go to Settings → Users & Companies → Users and open the required user.

Under Allowed Companies, select the companies the user is permitted to work with.

For example:

  • ☑ edu-manufacturing1
  • ☑ edu-trading1
  • ☐ edu-services1

Set the appropriate Default Company.

This is important because our warehouse security should work inside the company boundary, not replace it.

4. Add Allowed Warehouses Using Studio

Open a user record and activate Studio, then add a new field.

Field configuration

PropertyValue
Field TypeMany2many
Related ModelWarehouse (stock.warehouse)
LabelAllowed Warehouses
Suggested technical namex_studio_allowed_warehouse_ids

The user record can then contain:

Allowed Warehouses: [ WH/India ] [ WH/UAE ]

For security reasons, this field should normally be editable only by administrators or authorized managers. A user should not be able to change their own warehouse permissions.

5. Add a Warehouse Restriction Switch

For a clean implementation, add another Studio field to the User model.

PropertyValue
LabelRestrict Warehouse Access
TypeBoolean
Suggested technical namex_studio_restrict_warehouse_access

This gives us two clearly defined scenarios.

Scenario A — No restriction

Restrict Warehouse Access = False, Allowed Warehouses = Empty.

Result: the user can access all warehouses belonging to their allowed companies.

Scenario B — Restricted

Restrict Warehouse Access = True, Allowed Warehouses = WH/India.

Result: the user can access only WH/India.

This explicit Boolean is safer than trying to infer the user’s security mode purely from whether a Many2many field happens to be empty.

6. Create a Security Group

Create a dedicated group under Settings → Users & Companies → Groups.

For example: Inventory / Warehouse Restricted User

Assign this group to users who should follow the warehouse restriction rules. This gives us a clean way to distinguish:

  • Normal Inventory users
  • Warehouse-restricted users
  • Inventory Managers / Administrators

7. Warehouse Record Rule

Now create the first Record Rule. Go to Settings → Technical → Security → Record Rules and create:

PropertyValue
NameWarehouse Access by Company/Warehouse
ModelWarehouse (stock.warehouse)
GroupInventory / Warehouse Restricted User
PermissionsRead ✅ · Write ❌ · Create ❌ · Delete ❌

The warehouse is configuration data, so ordinary warehouse users should generally not be allowed to modify or delete warehouses.

Domain

The intended logic is:

[
    ('company_id', 'in', company_ids)
] + (
    [('id', 'in', user.x_studio_allowed_warehouse_ids.ids)]
    if user.x_studio_restrict_warehouse_access
    else []
)

This means: Company is allowed AND (Warehouse restriction is OFF OR Warehouse is in Allowed Warehouses).

8. Operation Type Record Rule

The next important model is stock.picking.type. This represents operation types such as:

  • Receipts
  • Delivery Orders
  • Internal Transfers
  • Manufacturing
  • Returns

Create:

PropertyValue
NameOperation Type Access by Warehouse
ModelOperation Type (stock.picking.type)
GroupInventory / Warehouse Restricted User
PermissionsRead ✅ · Write ❌ · Create ❌ · Delete ❌

Domain

[
    ('company_id', 'in', company_ids)
] + (
    [('warehouse_id', 'in', user.x_studio_allowed_warehouse_ids.ids)]
    if user.x_studio_restrict_warehouse_access
    else []
)

Now a user restricted to WH/India will see WH/India Receipts, Delivery Orders, Internal Transfers and Manufacturing — but not WH/UAE Receipts, Delivery Orders or Manufacturing.

9. Stock Transfer Record Rule

Now we apply the restriction to actual inventory operations on the stock.picking model.

PropertyValue
NameTransfer Access by Warehouse
ModelTransfer (stock.picking)
PermissionsRead ✅ · Write ✅ · Create ✅ · Delete ❌

Domain

[
    ('company_id', 'in', company_ids)
] + (
    [('picking_type_id.warehouse_id', 'in',
      user.x_studio_allowed_warehouse_ids.ids)]
    if user.x_studio_restrict_warehouse_access
    else []
)

This allows users to view, create and modify transfers — but only within their permitted warehouse scope.

10. Manufacturing Order Record Rule

This is particularly important for companies using Odoo Manufacturing. The model is mrp.production.

PropertyValue
NameManufacturing Order Access by Warehouse
ModelManufacturing Order (mrp.production)
PermissionsRead ✅ · Write ✅ · Create ✅ · Delete ❌

Domain

[
    ('company_id', 'in', company_ids)
] + (
    [('picking_type_id.warehouse_id', 'in',
      user.x_studio_allowed_warehouse_ids.ids)]
    if user.x_studio_restrict_warehouse_access
    else []
)

This ensures that a user restricted to a particular warehouse can create and process Manufacturing Orders for that warehouse.

11. Critical Lesson: Do NOT Restrict stock.move Directly

This is one of the most important lessons from implementing this solution.

It may initially seem logical to create a Stock Move Access by Warehouse rule using warehouse_id in user.x_studio_allowed_warehouse_ids.

However, this can break Odoo’s internal inventory and manufacturing workflows.

For example, when a Manufacturing Order is confirmed, Odoo automatically creates and updates a chain of records:

Manufacturing Order → Stock Move → Stock Move Line → Stock Quant

If a warehouse record rule blocks the underlying stock.move, Odoo can generate errors such as “User doesn’t have ‘create’ access to Stock Move” or “User doesn’t have ‘write’ access to Stock Move” — even though the user legitimately has permission to operate the Manufacturing Order.

Therefore

Do not apply the warehouse restriction directly to stock.move initially.

Keep the standard Odoo security for stock.move, stock.move.line and stock.quant, and control access through the business documents instead.

12. Recommended Access Configuration

The resulting architecture should look like this:

ModelReadWriteCreateDeleteWarehouse Rule
stock.warehouse
stock.picking.type
stock.picking
mrp.production
stock.moveStandardStandardStandardStandardNo
stock.move.lineStandardStandardStandardStandardNo
stock.quantStandardStandardStandardStandardNo
stock.locationStandardStandardStandardStandardCareful

The exact standard ACLs should remain appropriate to the user’s Inventory/MRP role.

13. What About Locations?

Locations require special attention. A warehouse may contain a full hierarchy:

WH/India
 ├── Input
 ├── Stock
 │    ├── Shelf A
 │    ├── Shelf B
 │    └── Shelf C
 └── Output
WH/UAE
 ├── Input
 ├── Stock
 └── Output

A user restricted to WH/India should not be able to manipulate WH/UAE locations.

However, do not simply apply a generic company-based location rule. Odoo locations can also include:

  • Customer locations
  • Vendor locations
  • Transit locations
  • Production locations
  • Virtual locations
  • Inventory adjustment locations
  • Shared/company-neutral locations

Therefore, location security should be designed after reviewing the actual location hierarchy.

14. Why We Should Not Apply the Same Domain Everywhere

This is another important principle.

It is tempting to use warehouse_id in user.allowed_warehouses on every Inventory model. That is dangerous, because different Odoo models have different relationships.

For example, stock.picking reaches the warehouse through picking_type_id → warehouse_id, while other models may use warehouse_id directly, or derive their company/warehouse context through locations or other records.

Therefore: Each model should have a domain based on its actual Odoo relationship.

15. Testing the Security

Create at least four test users.

Test UserCompaniesRestrict WarehouseAllowed WarehousesExpected Result
Test User 1edu-manufacturing1OFFEmptyAll warehouses belonging to edu-manufacturing1
Test User 2edu-manufacturing1ONWH/ProductionWH/Production only
Test User 3edu-manufacturing1, edu-trading1ONWH/Production, WH/TradingOnly those two warehouses
Test User 4edu-manufacturing1, edu-trading1OFFEmptyAll warehouses belonging to both allowed companies

16. Test Manufacturing Carefully

For a Manufacturing user, test the complete flow:

Manufacturing → Manufacturing Order → Select Operation Type → Confirm → Check Availability → Produce → Validate

Then verify that Odoo can internally create and update stock.move, stock.move.line and stock.quant without your custom warehouse rules blocking them.

This is exactly where overly aggressive record rules tend to cause problems.

17. Test Cross-Warehouse Transfers

This scenario deserves special attention.

Suppose a user has only WH/India as an allowed warehouse, and attempts a transfer from WH/India/Stock → WH/UAE/Stock.

You need to decide whether this should be allowed. For strict warehouse security, we recommend:

A user should not be able to initiate or manipulate a transfer involving a warehouse outside their permitted scope.

If cross-warehouse transfers are a legitimate business process, create a separate role for users authorized to perform them.

18. Test Direct Record Access

Do not test only menus. A user may potentially access a record through:

  • Search
  • Smart Buttons
  • Related records
  • Favorites
  • URLs
  • Reports
  • Many2one fields

Therefore, while logged in as a WH/India-only user, test access to a WH/UAE Transfer, WH/UAE Operation Type, WH/UAE Manufacturing Order and WH/UAE Warehouse.

The security rule should deny access even if the user attempts to reach the record indirectly.

19. The Final Architecture

The complete design becomes:

USER
 ├── Allowed Companies
 └── Warehouse Restriction
      └── Allowed Warehouses
              │
              ▼
      BUSINESS DOCUMENTS
       ├── Warehouse
       ├── Operation Type
       ├── Transfer
       └── Manufacturing Order
              │
              ▼
      INTERNAL ODOO RECORDS
       ├── Stock Move
       ├── Move Line
       └── Quant

The philosophy is simple:

Restrict what the user operates on, not every internal record Odoo creates behind the scenes.

20. Final Recommendation

For an Odoo 19 multi-company environment, we recommend this security strategy:

LevelApproachApplies To
Company levelUse Odoo’s standard Allowed CompaniesAll users
Warehouse levelUse Studio: Allowed Warehouses + Restrict Warehouse AccessRestricted users
Business-document levelUse Record Rulesstock.warehouse, stock.picking.type, stock.picking, mrp.production
Internal transaction levelInitially leave under standard Odoo securitystock.move, stock.move.line, stock.quant

This approach gives you warehouse-level security while avoiding the type of MRP errors that occur when a Record Rule blocks Odoo’s internal stock transactions.

One final implementation caution: test the exact domains in a staging database first. Odoo security rules can interact with existing global and group rules, and an overly restrictive rule can unintentionally remove access or break automated workflows.

Need Help Implementing Multi-Company Access Control in Odoo 19?

Designing warehouse-level security correctly takes experience — the difference between a rule that protects your data and one that breaks your manufacturing workflow is often a single domain expression. Get in touch today for a free Odoo consultation and security architecture review.
Mustafa Rahi

Mustufa Rahi is an Odoo Certified Functional Consultant and ERP expert at Techvaria with 15+ years of experience in implementation, automation, and business process optimization, helping organizations scale efficiently.