Skip to content
All guides

Inventory · Updated September 3, 2026

Stock on Hand

What the Stock on hand screen shows, where every number on it comes from, and what to do when a figure looks wrong.


What you're looking at

Stock on hand shows what the ledger says is at each location in the outlet you've picked, right now. Every figure is a sum over the stock ledger, which only ever grows. There is no edit button anywhere on this screen, and that's deliberate: stock moves by document (a goods receipt, an issue, a transfer, a waste note, an approved count), never by someone typing a better number over a worse one. If the screen says the cold room holds 14 crates and the cold room holds 9, the fix is a stocktake or a reversal, not an edit.

The page needs view_inventory. Asking for an outlet you're not assigned to gets a refusal from the server, not an empty table.

A few things about how it reads:

  • Rows are grouped by location (Cold room, Dry store, Main bar), with items alphabetical inside each group, roughly the order you'd walk a shelf. Each location pages on its own.
  • Quantities are in each item's own stock unit. Bottles for the Gilbeys, kilos for the rice. That's why the column carries no shared unit label.
  • Items at exactly zero are hidden, so the list shows what's present rather than every SKU that ever passed through.
  • A discontinuing item that still holds stock stays visible. New retirement is allowed only after that balance reaches zero; older imported/deactivated records with stock also remain visible rather than being hidden.
  • Each shelf carries what it's worth. The location header shows the value of the items listed under it, and every row shows its own Value (KES). Stock that has never been priced shows a dash rather than a zero, and stays out of the totals. Values need the Reporting module; without it the screen is quantities only, exactly as before.

Filters and the below-minimum chip

Along the top you get an Outlet picker, a Search box (item name or code), a Category dropdown, and a Below minimum only checkbox. Filters live in the URL, so "the dry store's spirits, below minimum" is a link you can send to someone.

Below minimum is judged at outlet level: the item's total across all this outlet's locations, against the minimum set on the item. A row that trips it gets a small "below min" chip. Tick Below minimum only and, if you hold manage_purchase_order, a Draft order from these button appears. It opens a new purchase order pre-filled with those items; the quantities are left to you, because how much to buy is a buyer's call, not a formula.

The Export button downloads what's on screen as one flat file (location, code, item, on hand, below minimum), ready to sort or pivot.

Behind every figure: the Movements screen

Each row's "Last movement" date is a link. Click it and you land on the Movements screen filtered to that outlet, location and item, which is the answer to the question a balance always provokes: why is it that number?

Movements is the ledger read back, newest first. By default it shows the last 7 days, and it says so on screen; set a From and To date to look further back (both dates are included). You can also filter by location and item. A window caps at 200 rows, and when it fills, a banner tells you to narrow the dates rather than assume you've seen everything. A busy bar posts hundreds of rows a night.

Every row carries a type, and each type has a fixed direction:

TypeDirection
Receipt, Transfer inAdds stock (always positive)
Issue, Waste, Transfer outRemoves stock (always negative)
Historical adjustment, Count variance, Transit discrepancy, ReversalEither way

The server enforces the signs. Try to post a positive waste and it answers: "A waste removes stock, so its quantity must be negative. A positive one would create stock out of nothing."

Correcting a mistake

Rows are never edited or deleted. A wrong movement is corrected by reversing it: a new opposing row is appended, pointing back at the original, and both stay in the ledger forever. On Movements, anyone holding reverse_stock_movement sees a Reverse button on each eligible row.

The dialog shows you exactly what will happen (the opposite quantity, at the same location, dated now) and requires a reason. Write the reason for whoever reads the ledger in six months, because it's the only record of why the figures moved. Something like "Counted the delivery twice, duplicates GRN-0184" is worth far more than "fix".

Only three kinds of row can be reversed here: a manual adjustment, a supplier free issue and an opening balance, because nothing else owns them. Every other row never offers the button, and the screen says why in place of it:

  • a row that is itself a reversal ("A reversal cannot itself be reversed");
  • a row already reversed. A movement is reversed at most once; the reversed original stays visible, tinted, with a link to its correction;
  • a row a document posted, marked "Via its goods receipt", "Via its waste note" and so on. Correct it through that document instead: reverse the goods receipt, reject the cash purchase or the waste note, take a new count, transfer the other way, or void the sales import. That keeps the document and the ledger agreeing. The server refuses a direct reversal of these rows and names the document to use. See Waste for how rejecting a note reverses its movements.

Quick captures from the phone

The mobile app's Record Stock screen (behind post_stock_movement) can post two things straight to the ledger: an issue, and a receipt that is strictly a supplier free issue, the crate of tonic a distributor throws in with a delivery. On web, use Movements → Record free issue. A free issue must be positive, carries no cost, and needs a note saying who gave it and with which delivery. Everything else enters through its own document.

Free-form manual adjustments are retired. Correct a balance through a stock count, record destroyed stock through a waste note, reverse the document or movement that was wrong, or use the appropriate transfer/purchase flow. Historical adjustment rows remain visible and reversible because the ledger is append-only.

Captures queue in the phone's offline outbox and sync when there's signal. Each carries its own operation id, so a capture that syncs twice posts once. The On hand screen on the phone shows the same quantities to the same view_inventory holders; the shilling values are on the web screen only.

FAQ

Can I just edit a balance that's obviously wrong? No, and there's no screen that will let you. Find the movement that made it wrong and reverse it, or run a stocktake and let the approved count post the correction. Both leave a record of what changed and why; an edit would leave nothing.

Why is an item we stopped selling still on the list? Because it is discontinuing and still holds stock. It cannot be added to new purchasing or recipes, but the four bottles in the store are real and hiding them would make the shelf disagree with the screen. Count, transfer, issue or write them off; once the balance and live references reach zero, finish its replacement or retire it. See Replacing & Retiring Items.

Where do the shilling values come from? The server, always. Each item is valued at the outlet's weighted-average cost (what you actually paid, across every delivery of it into that outlet) and multiplied by what's on the shelf. That multiplication only ever happens on the server; the screen adds up the shelf totals in front of you but never works out a value of its own, which is why these figures and the ones on the Reports page and its export can't disagree. Two rooms show the same unit value for the same item on purpose: moving a crate between rooms doesn't make it worth more.

Why does an item show a dash instead of a value? Because nothing has priced it yet. An item is valued by the delivery that brings it in, so stock counted at opening, before its first goods receipt, is genuinely of unknown value rather than free. A dash says so; a zero would lie. The shelf total then reads "at least", with the count of rows sitting outside it, and the values fill in as deliveries arrive.

The shelf total changed when I filtered. Is it wrong? No. It's the value of the items you're looking at, matching the item count beside it, and it says "across matching items" when a filter is on. Clear the filters and the shelf totals add up to the outlet's stock value on the Reports page exactly.

The Movements list looks short. Has something been deleted? Nothing is ever deleted from the ledger. You're almost certainly looking at the default 7-day window; the note under the filters says exactly what range is showing. Widen the dates. If the window is full at 200 rows, narrow the filters instead, because there are older rows the page didn't reach.

Who can reverse a movement? Anyone holding reverse_stock_movement, typically an outlet manager. Viewing the ledger only needs view_inventory, the same grant as this page, since a balance is just the sum of those rows. See Roles & Permissions.