Inventory permissions
Category: Inventory Management — 10 modules, 52 permissions
1. The full list
Unit of Measure — org_inv_uom (7)
View unit of measures · .menu · .create · .edit · .delete · .deactivate · .createwithai
Raw Materials — org_inventory_rawmaterial (6)
View Raw Materials · .menu · .create · .edit · .delete · .createwithai
Product Category — org_inv_prod_cat (6)
View Product Category · .menu · .create · .edit · .delete · .createwithai
Product Attributes — org_inv_attributes (6)
View Product atributes · .menu · .create · .edit · .delete · .createwithai
Orbit Products — org_inv_products (7)
View Products · .menu · .create · .edit · .delete · .createwithai · .import
Procurement & Inbound — org_inv_procurement (4)
View Inventory Procurements · .menu · .create · .approve
Production & Manufacturing — org_inv_production (6)
View Production and Manufacturing Trends · .menu · .create · .edit · .complete · .cancel
Sales & Outbound — org_inv_sales (3)
View Inventory sales · .menu · .create
Maintenance & Quality Control — org_inv_maintainence (4)
View Maintenance & Quality Control · .menu · .adjust · .waste
Inventory Audit View — org_inv_ledger (3)
View Inventory Ledger · .menu · .export
2. Two traps in the naming
prodcat.attribute.* prefixThe module is org_inv_attributes, but there is no org.inventory.attributes.* permission.
Every one is under org.inventory.prodcat.attribute.*.
The permission to grant is View Product atributes.
org_inv_maintainence — with the typo. Its permissions are spelled correctly
(org.inventory.maintenance.*). Only the module code carries it, and that is what a
package_module_map row or an organization_modules row must match.
3. Four permissions that do nothing
These can be granted. No route and no component reads them.
| Permission | Reality |
|---|---|
| Approve procurement | There is no approval step in Procurement at all |
| Export inventory ledger | The Export button has no handler and there is no endpoint |
| Mark wastage of inventory | Wastage is gated by .adjust — you cannot separate the two |
| Delete Product attributes | DELETE /attributes is gated on .edit, so .delete is unreachable |
A role designed as "can receive stock but not approve it" is indistinguishable from one that can do both, because approval does not exist. Likewise "can count but not write off" is not achievable.
4. Where the UI checks, and where it does not
Three different postures across one category:
| Screens | Idiom | Checks |
|---|---|---|
| Products | usePermission() | 5 |
| UoM, Categories, Attributes, Raw Materials | hasPermission() from the auth store | 16 |
| Procurement, Production, Sales, Maintenance, Ledger | none | 0 |
Add Receipt Batch, New Production Order, Complete, Cancel, New Sale and New Entry all
render for anyone holding the module's .view permission.
The API enforces the real permission, so a user without .create fills in an entire form and meets
a failure on Save. That is the opposite of the product's own standard, which is to surface a missing
prerequisite before the work rather than after it.
Until this is fixed, a .view-only role on those screens is a poor experience, not a safe one.
Two different idioms — usePermission() and hasPermission() — do the same job. Copy whichever the
surrounding file uses.
5. Permissions that gate more than they look like
| Permission | Also required for |
|---|---|
products.edit | Opening a product at all. There is no read-only product page |
products.create | Reaching /products/new |
maintenance.adjust | Wastage as well as adjustments |
| Edit Product Attributes | Deleting an attribute |
uom.create | Both Seed defaults and Discover |
products.import | The Import button — separate from products.create |
6. Building roles
Catalogue author
Everything under products, categories, attributes, units and raw materials, including .createwithai
if AI is entitled. No operations permissions.
Stock clerk
procurement.view + .create, production.view + .create + .complete, sales.view + .create,
maintenance.view + .adjust, ledger.view.
Note this role can also write stock off — .waste is not separable.
Auditor
ledger.view + ledger.menu, plus .view on whatever else you want them to see.
products.view grants the catalogue list only. To let an auditor inspect a product's fields you must
grant products.edit, which also lets them change it. There is no read-only middle ground.
ledger.view exposes customer names and phone numbersThe ledger prints the undecoded [CUST:…] [PH:…] tags from direct sales. Anyone with ledger.view
can read them. Treat it as a permission over personal data, not just over quantities. See
The inventory ledger.
7. Module enablement — before permissions matter
A permission only takes effect if the module is enabled for the organisation. Two independent paths grant that:
| Path | Table |
|---|---|
| Direct org enablement | organization_modules |
| Via a purchased package | package_module_map |
package_module_map row denies everyoneIncluding the org owner. If nobody can reach an Inventory screen despite holding the permission, the module-to-package mapping is the first thing to check, not the role.
8. Troubleshooting
| Symptom | Cause |
|---|---|
| Attribute permissions do nothing | Wrong prefix — use prodcat.attribute.* |
| Nobody can open a module, including the owner | Missing package_module_map row |
| A role can see a button but Save fails | The operations screens do not gate their UI |
.approve / .export / .waste appear to have no effect | They are enforced nowhere |
| An auditor cannot open a product | products.view is list-only |
| A screen is missing from the menu | The .menu permission is separate from .view |