Skip to Content
Inventory

Inventory

Inventory is what you have on hand right now — every barrel of grain in the warehouse, every bottle in the case room, every drop in a tank. vestl tracks inventory by lot so you always know which specific receipt or production run a unit came from.


Core concepts

Lot. A specific receipt or production run of a product. Lots have a lot number, received date, quantity, location, and remaining quantity. Two batches of the same SKU received on different days are two separate lots.

Location. Where the inventory physically lives. Locations are typed: a tank, a warehouse, or generic storage. Tanks have capacity; warehouses don’t.

On-hand. The sum of remaining_quantity across all available lots of a product. Different from “received” because production batches consume from lots and decrement remaining.

Status. Each lot is available, on_hold, quarantine, consumed, or expired. Only available lots are pickable for production. on_hold and quarantine are visible but blocked from being consumed.


Where inventory comes from

A lot is created in three ways, and the lot type field records which:

  • Purchased — created by a purchase receipt (/purchasing/receipts). The receipt line that created the lot is linked back via purchase_receipt_line_id so you can audit “where did this lot come from” with one click.
  • Produced — created when a production batch packages out. The batch’s MO/recipe/bottle BOM/case BOM are pinned to the lot, so traceability flows forward to the finished case.
  • Adjusted — created by a manual /inventory/adjustments entry (cycle-count discoveries, found inventory, write-ons). Adjusted lots require a reason note.

Most lots are purchased or produced. Adjusted lots are an exception path and should be rare.


Inventory pages

/inventory — On-hand by product

The main inventory landing page. Shows one row per product with the on-hand quantity rolled up across all available lots. Click into a row to see the lots that make up that on-hand number.

Filters: location, product type (finished goods only / raw materials only), low-stock (below reorder point — see /inventory/reorder).

/inventory/lots — Every lot, individually

The lot-level view. Use this when you need to find a specific lot (debugging traceability, looking up a lot that was flagged in QC, hunting for an expired lot to write off). Sortable by received date, expiry date, status.

/inventory/receive — Receive raw materials

Used for raw material receipts (finished goods are received by closing a production batch, not through this page). Two flows:

  1. PO-anchored receive — you have an open purchase order; pick the PO line and confirm quantity/lot/location. Most receipts go this way.
  2. Unplanned receive — material arrived without a PO (samples, returns, vendor errors). Requires a reason note in the lot’s notes field — operators want to know why later.

/inventory/adjustments

Manual quantity changes outside the receive/produce/consume flow. Cycle-count discrepancies, write-offs, found inventory. Every adjustment requires a reason and is audit-logged.

/inventory/transfers

Move inventory between locations. Common case: a tank has been emptied and the remainder was siphoned into a different tank — record the transfer so the lot’s location stays accurate.

/inventory/cycle-counts

Periodic physical counts. The page generates a count sheet for a location, you fill it in, and the system records adjustments for any variance.

/inventory/reorder

The reorder dashboard. Surfaces products that are below their reorder point (set per-product on the product detail page). MRP also feeds this view — anything MRP says you’ll need that you don’t have shows up here.

/inventory/reports/expiry-report

Lots that are within N days of their expiry date. Filter by lookahead window (7 / 30 / 90 days). Used for FEFO (first-expiry-first-out) picking and to prevent compliance issues with aged stock.


Field reference (lot detail)

Lot number

The identifier for this specific lot. For purchased lots, you can match it to your vendor’s lot/batch number; for produced lots, it’s auto-generated from the batch ID.

Supplier lot number

The vendor’s own lot/batch identifier from their packaging or COA. Optional, but strongly recommended for raw materials — TTB traceability requires being able to walk from a finished bottle back to the supplier lot of every ingredient.

Received date

The date the lot was actually received (not the PO date, not the day someone got around to entering it). Drives FEFO and aging reports.

Expiry date

When the lot becomes unusable. Optional for non-perishable materials. The expiry report at /inventory/reports/expiry-report flags lots within a configurable lookahead window.

Removal date

When the lot was fully consumed or written off. Set automatically when remaining_quantity hits zero.

Quantity / Remaining quantity

Quantity is what you received; remaining_quantity is what’s left after consumption. Production batches and adjustments decrement remaining; you cannot edit it directly.

Unit cost

The cost per UoM unit at the time of receipt. Used by inventory valuation reports and batch costing. Pulled from the PO line for purchased lots; computed from input costs for produced lots.

Location

Where the lot physically lives. Move it via /inventory/transfers.

Lot status

  • Available — pickable for production. Default.
  • On hold — visible but blocked from consumption. Use this when QC has flagged the lot pending an investigation.
  • Quarantine — segregated for a compliance reason (failed QC, recall, regulatory hold). Requires a quarantine_reason note. Cannot be consumed without manual unblock.
  • Consumed — fully drawn down to zero remaining.
  • Expired — past expiry date, blocked from consumption.

Quarantine reason

Required when status is quarantine. Free-text, but should be specific enough to audit later (“Failed micro test 2026-04-12, retain for retest”). Visible in the audit trail.

Notes

Free-text. Especially useful for unplanned receives (“Vendor sent extra by mistake — kept per email with rep on 2026-04-15”).


Locations

Locations are configured at /settings/locations. Three types:

  • Tank — has capacity. Used for liquid in process (mash tuns, fermenters, blending tanks). When capacity is set, the system warns if a transfer would exceed it.
  • Warehouse — bulk dry-goods storage. No capacity tracking.
  • Storage — generic location that doesn’t fit the other two (cold room, lab fridge, packaging staging).

A location can allows_negative if you want to permit negative on-hand for that location (rare; usually only for transit or virtual locations).


Inventory + production

A production batch reads inventory the same way you would: it picks available lots of each ingredient and decrements remaining_quantity as it consumes them. Lot selection follows FEFO by default — earliest-expiring lot first — but operators can override during batch creation if they need to clear a specific lot.

When a batch packages out, vestl creates a new produced lot for each finished SKU at the configured packaging location. The new lot’s traceability chain links forward through MO → batch → recipe/bottle BOM/case BOM, and backward through every consumed input lot.


Inventory + compliance

For TTB-regulated products, lot traceability is legally required. vestl never deletes a lot — consumed and expired lots stay on the books indefinitely so the trail from finished bottle to source ingredient can be reconstructed years later.

Quarantine status and quarantine reasons are also part of the audit trail. If a lot was held for a compliance reason and then released, the audit log shows the hold, the reason, the release, and who released it.

Last updated on