Warehouses & Carriers
Where AIR's stock physically lives, and who moves it to customers. This page covers the Warehouse record — including its stock locations, its linked carriers and the regions it serves — and the standalone Delivery Carrier master list.
Warehouses Built
Warehouses live under Warehouses → Warehouses. A warehouse is where AIR holds stock — the head-office godown, a branch, or a purely notional location used for accounting. Full create/edit/delete is available.
Warehouse list
| Column | Shows |
|---|---|
name | Warehouse name. Searchable, sortable. |
code | Code badge, searchable. |
warehouse_type | Type badge — HO or Branch. |
warehouse_purpose | Purpose badge — Internal, Sale, Display or Not Used. |
is_default | Tick/cross icon — whether this is the system's default warehouse. |
stock_locations_count | Label "Locations" — how many stock locations exist under this warehouse. Sortable. |
created_at | Sortable; hidden by default. |
Filters: Warehouse Type, Warehouse Purpose (both drop-downs), and Default (yes/no/either).
Create / edit a Warehouse
The form has three sections. "Warehouse Details" is expanded by default; "Address" and "Operations" are collapsible and start collapsed.
Warehouse Details
| Field | Type | Required | Notes |
|---|---|---|---|
name | Text | Yes | Max 255. |
code | Text | Yes | Max 20, unique. Locked (disabled) once the warehouse exists. |
warehouse_type | Select | Yes | HO or Branch. |
warehouse_purpose | Select | No | Internal / Sale / Display / Not Used. |
default_carrier_id | Select (searchable) | No | Which carrier is pre-selected for despatches from this warehouse. Nullable. |
region_id | Select (searchable) | No | The Region this warehouse sits in. Nullable. |
pincode_id | Select (searchable) | No | The Pincode this warehouse sits in. Nullable. |
warehouse_description | Textarea | No | Full width. |
Address (collapsible, starts collapsed)
| Field | Type | Required | Notes |
|---|---|---|---|
street, street2, street3, street4 | Text | No | Free-text address lines, all nullable. |
geolocation | Text | No | Nullable — coordinates or map link, free-text. |
Operations (collapsible, starts collapsed)
| Field | Type | Required | Notes |
|---|---|---|---|
is_default | Toggle | No | No preset default — marks this as the system's fallback warehouse. |
is_moving_warehouse | Toggle | No | No preset default — flags a mobile/non-fixed warehouse (e.g. a vehicle). |
is_returned_by_customer | Toggle | No | No preset default — marks this warehouse as where customer returns are booked in. |
allow_autoreservation | Toggle | No | Defaults on. See callout below. |
stock_transfer_permitted | Toggle | No | Defaults on. See callout below. |
stock_max_time_to_deliver | Number | No | Nullable — typical days-to-deliver from this warehouse. |
transit_time_from_ho | Number | No | Nullable — typical transit days from Head Office to this warehouse. |
allow_autoreservation actually doesThis toggle is the gate the console gives you over the daily automatic reservation scheduler. When it is switched on (the default), the scheduler is allowed to consider this warehouse's stock when it automatically reserves stock against ready sale orders. Switch it off and this warehouse's stock is skipped entirely during that automated run — useful for a warehouse that is, say, mid-stocktake or otherwise not ready to promise stock. It has no effect on manual reservation, only the scheduled/automatic pass. See Schedulers for exactly when and how often that job runs, and how it interacts with the matching per-carrier allow_autoreservation flag described below.
stock_transfer_permitted doesGoverns whether this warehouse may take part in stock transfers to or from other warehouses at all. Switching it off is a way to freeze a warehouse's stock in place — for example while it is being physically audited — without touching individual stock levels. (Note: the stock-transfer workflow itself has no dedicated console screen yet — see the callout under Stock Locations below.)
Actions on the list/edit page are the standard Edit and Delete — plain CRUD, no service logic and no delete guard (unlike Regions, deleting a warehouse that still has stock locations or stock is not blocked at this level).
Stock Locations tab
Open a Warehouse and switch to Stock Locations to manage the individual bins/areas inside it that stock actually sits in.
| Column | Shows |
|---|---|
location_name | Name of the stock location. |
stock_location_number | Short reference number/code. |
location_type | Type badge — see the 11 types below. |
whether_in_use | Label "In Use" — tick/cross icon. |
allow_in_wave_scheduler | Label "Wave" — tick/cross icon. See callout below. |
- Open a Warehouse's edit page and select the Stock Locations tab
You'll see every location currently defined under this warehouse.
- Select New stock location (header) to add one
Fill in
location_name(required, max 255),stock_location_number(optional, max 50), and choose alocation_type(required). - Choose the correct Location Type
See the table below — pick a "physical" type for a real shelf/bin that will hold countable stock, or one of the logical types for accounting-only movement points.
- Set In Use, Wave and Auto-gen closing stock record as needed
All three are toggles on the same form.
- Save, or use row Edit/Delete later
This is plain CRUD — no service calls, no guard on delete.
The 11 LocationType options, in the order they appear in the Select:
| Location Type | Physical? | Typical use |
|---|---|---|
| Internal | Physical | A normal internal storage location — the everyday case for a real shelf or bin. |
| Supplier | Logical | Represents stock still with, or coming from, a supplier — not a physical shelf at AIR. |
| Customer | Logical | Represents stock that has left AIR's premises into a customer's hands. |
| Production | Logical | Accounting point for stock being converted/assembled (e.g. into a Set). |
| Transit | Logical | Stock in transit between two other locations, not sitting anywhere yet. |
| View | Logical | A grouping/organisational node with no stock of its own — never holds items directly. |
| MainStock | Physical | The primary saleable-stock area of a warehouse. |
| AttachedStock | Physical | A secondary physical area attached to the main stock area. |
| LooseStock | Physical | Loose/unbundled physical stock, not yet shelved formally. |
| ReturnStock | Physical | Where physical customer returns are received and held pending disposition. |
| Loss | Logical | Accounting point for written-off/lost stock — not a real shelf. |
"Physical" here means the location represents a real, countable shelf/bin that closing-stock counts and stock-on-hand figures meaningfully apply to; the "Logical" types are accounting/organisational points that stock passes through without being physically shelved there.
allow_in_wave_scheduler doesMarks whether this specific stock location is eligible for the automated picking-wave scheduler to pull stock from when it builds waves. Turn it off for a location that should only ever be picked manually — for example a returns bay. See Schedulers for the wave-building job itself, and Picking Waves for how a wave is worked once built.
autogen_closing_stock_record doesWhen on, this location is automatically included whenever new closing-stock statements are generated for its warehouse, rather than needing to be added by hand. See Closing Stock for the counting workflow itself, and Stock on Hand for the live balances a location holds day to day.
Seeded permissions (stock_transfer.request, stock_transfer.view, create, approve, receive) and a full six-state transfer workflow exist behind the scenes, but no Transfer screen exists anywhere in this console yet. The stock_transfer_permitted toggle on the Warehouse form above only controls eligibility for that future workflow — there is nothing to action from the console today.
Delivery Carriers tab
Open a Warehouse and switch to Delivery Carriers to see and manage which carriers this warehouse can despatch through. This is a many-to-many link — there is no create/edit here, only attach/detach.
| Column | Shows |
|---|---|
name | Carrier name. |
code | Code badge. |
carrier_type | Type badge — Courier / Post / Hand Delivery / Transport. |
is_active | Tick/cross icon. |
- Select Add carrier (header)
Opens a dialog titled "Add a delivery carrier" with a pre-loaded searchable Carrier select listing every carrier already defined in the Delivery Carrier master list below.
- Choose the carrier and confirm
The link is created immediately — no separate save step.
- To remove a link, select row Remove
Or select several rows and use the bulk Remove selected action. Removing never deletes the carrier itself, only the link to this warehouse.
Regions tab
Open a Warehouse and switch to Regions to record which Regions this warehouse serves. Also a many-to-many, attach/detach only.
| Column | Shows |
|---|---|
name | Region name. |
region_type | Type badge. |
Same pattern as Delivery Carriers: header Assign region (a "Assign a coverage region" dialog with a pre-loaded searchable Region select over every Region), row Remove, bulk Remove selected. This is a separate link from the single region_id field on the Warehouse's own "Warehouse Details" section — that field says where the warehouse physically is; this tab says which regions it serves, and a warehouse can serve many regions beyond its own.
Hand-delivery beats are now defined separately, on their own Delivery Routes page — each route is owned by one warehouse and lists the ordered pincode stops the beat walks.
Delivery Carriers Partial
Delivery Carriers live under Warehouses → Delivery Carriers — the master list of every courier, postal or transport service AIR despatches through. Unlike the resources on the Geography page, this is a straightforward, flat, full-CRUD master list with no tree and no relation managers of its own (carriers are linked to warehouses and regions from the warehouse side, and to pincode serviceability from the pincode side — see Zones, Regions & Pincodes).
Delivery Carrier list
| Column | Shows |
|---|---|
name | Carrier name. Searchable, sortable. |
code | Code badge, searchable. |
carrier_type | Type badge — Courier / Post / Hand Delivery / Transport. |
is_active | Label "Active" — tick/cross icon. |
created_at | Sortable; hidden by default. |
Filters: Carrier Type (Courier/Post/Hand Delivery/Transport) and Active Status (yes/no/either).
Create / edit a Delivery Carrier
Select New delivery carrier or row Edit. Single section, "Carrier Details":
| Field | Type | Required | Notes |
|---|---|---|---|
name | Text | Yes | Max 255, unique. |
code | Text | Yes | Max 50, unique. Locked (disabled) once the carrier exists. |
carrier_type | Select | Yes | Courier / Post / Hand Delivery / Transport. |
tracking_url_template | Text | No | Max 500, full width — a template URL for building a tracking link from a tracking number. |
is_active | Toggle | No | Defaults on. |
Actions are the standard Edit and Delete — plain CRUD, no service logic, no bulk actions, no guard on delete.
allow_autoreservation flag — not yet editable hereEvery Delivery Carrier record carries its own allow_autoreservation column (defaulting to on), mirroring the Warehouse flag of the same name, and it feeds the same family of background jobs — the auto-wave and auto-reservation schedulers — but from the carrier side: when off, the scheduler skips building reservations or waves destined for that carrier, even if the warehouse holding the stock has its own flag switched on. The Delivery Carrier form in this console does not currently expose a toggle for it — the "Carrier Details" section stops at Name, Code, Carrier Type, Tracking URL Template and Active. Until a form field is added, changing a carrier's autoreservation eligibility requires going outside the console. See Schedulers for how the warehouse-side and carrier-side flags combine.
Delivery-date estimate Built
A read-only API endpoint that answers "if we ship from this warehouse today (or on a given date), when should the customer expect delivery?" — used by the SE field app and the HO console wherever an expected delivery date needs showing without duplicating the day-count logic client-side.
API
| Method & path | Permission | Purpose |
|---|---|---|
GET /api/v1/warehouses/{warehouse}/delivery-estimate |
warehouse.view | Computes an expected delivery date for the given warehouse. Query params: location_id (optional, must be a Stock Location belonging to this warehouse) and ship_date (optional, any parseable date; defaults to today). Returns 404 for an unknown warehouse and 422 if location_id resolves to a location belonging to a different warehouse. |
Response shape:
| Field | Meaning |
|---|---|
warehouse_id | The path warehouse's id. |
location_id | Echoes the resolved location_id, or null when none was supplied. |
ship_date | The ship date used for the calculation, YYYY-MM-DD (today's date, start of day, when omitted from the request). |
transit_days | Days from Head Office to the warehouse — see the coalesce rule below. |
max_delivery_days | Typical days-to-deliver once stock reaches the warehouse — same coalesce rule. |
total_days | transit_days + max_delivery_days. |
expected_delivery_date | ship_date + total_days, YYYY-MM-DD. |
Both transit_days and max_delivery_days are resolved location-first: if a location_id is given and that Stock Location's own transit_time_from_ho / stock_max_time_to_deliver is set, it wins. Otherwise the figure falls back to the same-named column on the Warehouse record above. If neither the location nor the warehouse has a value set, the figure coalesces to 0 — the estimate is never rejected for missing data, it just degrades to same-day.
User↔location assignment & warehouse context Built
Two related pieces of API-only plumbing (no console screen yet) that let a field operator's app learn "which warehouse(s) am I working in, and which specific stock location am I assigned to?" — used by the SE field app and any HO tooling that needs to default a stock location for the acting user.
Assigning a user to a stock location
A user_stock_locations row links one user to one Stock Location, with an is_primary flag.
| Method & path | Permission | Purpose |
|---|---|---|
POST /api/v1/user-stock-locations |
stock_location.edit | Body: user_id, location_id, optional is_primary (default false). Idempotent — re-posting the same user_id/location_id pair updates the existing row (e.g. to flip is_primary) instead of creating a duplicate. |
DELETE /api/v1/user-stock-locations/{userStockLocation} |
stock_location.edit | Removes one assignment by its own id. Returns 204. |
GET /api/v1/users/{user}/stock-locations |
stock_location.view | Every location assigned to the given user, each with the linked location embedded (id, location_name, warehouse_id). |
GET /api/v1/locations/{location}/assigned-users |
stock_location.view | Every user assigned to the given location, each with the linked user embedded. |
Assigning a location with is_primary: true automatically demotes any other location already marked primary for that same user — a user can be assigned to several locations at once, but never has more than one primary location.
Reading your own warehouse context
| Method & path | Permission | Purpose |
|---|---|---|
GET /api/v1/me/warehouse-context |
None — any authenticated, password-changed user | Resolves the calling user's own warehouse context. Like /me, there is no permission gate: a user is always allowed to read their own context. |
Response shape:
| Field | Meaning |
|---|---|
warehouses | Array of {id, name, code} — every Warehouse reachable via the user's effective geography scope (their scoped regions plus descendants, per Regions), derived through the Warehouse↔Region link on the Regions tab. Empty array if the user has no geography scope. |
assigned_locations | Array of {id, location_name, warehouse_id} — every Stock Location directly assigned to the user via user_stock_locations above. Independent of the geography-derived warehouse list. |
primary_location | {id, location_name, warehouse_id}, or null if the user has no location marked primary. |
needs_selection | Boolean. false only when warehouses contains exactly one entry (the app can auto-select it silently); true when it contains zero (the app must block until an admin assigns geography) or more than one (the app must show a warehouse picker). |
warehouses is derived — it is never assigned directly to a user, it falls out of whichever regions the user is geography-scoped to (see Zones, Regions & Pincodes) intersected with each Warehouse's Regions tab links. assigned_locations and primary_location, by contrast, come only from the explicit user_stock_locations rows above — a user can have a location assigned inside a warehouse that geography scoping would not otherwise surface, and the two lists are not cross-validated against each other.
Related pages
- Zones, Regions & Pincodes — the Region/Pincode records a Warehouse links to, and where carrier-pincode serviceability is recorded.
- Schedulers — the daily automated jobs that read
allow_autoreservation(on both warehouses and carriers) andallow_in_wave_scheduler(on stock locations). - Stock on Hand — live quantities per stock location.
- Closing Stock — the physical counting workflow that
autogen_closing_stock_recordfeeds into. - Picking Waves — what happens once the wave scheduler has pulled eligible stock locations into a wave.