Warehouses
Warehouse locations, the default warehouse, virtual warehouses, and the warehouse-scoping access model.
Overview
A warehouse is a physical or virtual location that owns stock, documents, numbering sequences, and communication templates. Almost every financial and inventory entity carries a warehouse_id, so warehouses are the anchor for warehouse scoping — the mechanism that limits what a user (or API token) can see and act on.
Warehouses are managed under Admin → Settings → Warehouses (/admin/settings/warehouses). Creating, updating, and deleting a warehouse requires the settings.manage permission; viewing requires settings.view.
The default warehouse
The first warehouse created is automatically flagged as the default (is_default = true) so warehouse scoping always resolves to something. Exactly one warehouse is the default at a time; promote another warehouse by setting its is_default flag. The default warehouse cannot be deleted — the delete action rejects it with a validation error.
When a warehouse is created, Signals seeds its per-warehouse document templates and communication templates automatically.
Virtual warehouses
A warehouse flagged is_virtual = true represents a virtual location — a vehicle, a job site, or a sub-hire holding location. A separate flag, include_in_default_queries, controls whether a warehouse participates in warehouse-spanning availability grids:
include_in_default_queries = true(default) — the warehouse appears in default availability and warehouse-aggregation queries.include_in_default_queries = false— the warehouse is excluded from those warehouse-spanning grids but remains addressable directly by id, so you can still query or transfer against it explicitly.
Warehouse scoping
Warehouse scoping decides which warehouse-owned rows a user can see. It is resolved from the user's accessible warehouse ids:
- Owners (the
is_ownerflag) and users holding any role with theall_warehousesflag are unrestricted — they can access every warehouse. - Everyone else is limited to the warehouses assigned to their account, taken from
account_warehouses(preferred) or, as a fallback, theirmemberships. A membership with anullwarehouse_idgrants access to all warehouses; a user with no assignments has access to none.
Two layers enforce this:
WarehouseScope— a global Eloquent scope applied to warehouse-owned models. For a restricted user it constrains queries to their accessiblewarehouse_idvalues (directly, or through a relation path for indirectly-owned rows). Unrestricted users and unauthenticated contexts are not filtered.WarehouseScope::withoutScoping()temporarily lifts it when a row must be read regardless of scope.ChecksWarehouseAccess— a policy trait whosecanAccessStore()gate confirms a specific model's warehouse is one the user can access. Global entities (no resolvablewarehouse_id) are always allowed.
The warehouses catalogue itself is not warehouse-scoped: the Warehouses API and admin screen list all warehouses, gated by the settings.view / settings.manage permissions. Warehouse scoping applies to the entities that reference a warehouse (rentals, invoices, assets, documents, and so on).
Warehouse settings
Beyond address and contact details, each warehouse carries operational configuration:
- Shortage policy — the confirmation-gate policy and dispatch-gate policy, plus optional synchronous auto-resolution with an ordered list of preferred resolvers. See Shortages.
- Branding — a logo, primary/secondary colours, and font family used when rendering the warehouse's documents.
- Operating hours — per-day-of-week hours used by availability and scheduling.
API
See the Warehouses API for the REST surface, Ransack filtering, and response shapes. Warehouse lifecycle events (warehouse.created, warehouse.updated, warehouse.deleted) are available on the webhook surface.