How it fits together

Stock lifecycle

One unit of stock, from the order you placed with a supplier to the moment it leaves the building. Every screen it passes through, every record it creates, and what it does to your quantity, your cost and your books.

User guide › Stock lifecycle

Before you start

Stock, receiving and purchasing are surfaces of the Point of Sale app, not separate apps you install. One catalog, one set of warehouses, one stock ledger — shared by the register, the online store and Manufacturing. Accounting is a separate app; if you haven't installed it, everything below still happens to your stock, it just doesn't reach a ledger.

The three records that matter

Almost everything in this page is one of three things, and it helps to keep them straight from the beginning:

RecordWhat it is
Stock A running balance — one row per product per warehouse, holding the quantity on hand. This is what the register checks before it lets you sell.
Stock movement The audit trail. Every single change writes one, signed positive or negative, tagged with a reason: receipt, sale, return, transfer, adjustment, void, consume, produce.
Documents Purchase orders, goods receipts and supplier returns. Header-plus-lines paperwork that sits on top of the movements and links them to a supplier.

The balance is a cache of the movements, and BackOffice keeps them in step by updating both inside one locked transaction. If a stock change fails halfway, the whole thing rolls back — you never get a movement without a balance change, or the other way round.

Two settings decide the rest of this page

Before you trace anything, know where these two live, because they change what every step below does. Both are at Settings → Accounting (/__accounting), on the Settings tab.

SettingDefaultWhat it changes
Inventory method None / periodic On the default, stock operations post nothing to the ledger — receiving, adjusting and transferring are pure stock events, and purchases reach the books through the supplier bill. Switch to Perpetual and inventory becomes a balance-sheet asset that moves with every operation.
Costing method Weighted average How a unit leaving stock is valued. Average blends every receipt into one running cost per product. FIFO keeps a layer per receipt and relieves the oldest first — or the soonest-expiring first, for lot-tracked products.
Don't flip perpetual on casually

Perpetual only balances if the purchase side capitalises stock as it arrives. Turning it on halfway through a trading year, on top of purchases that were already expensed, will make the inventory account disagree with reality. Decide it at setup, with your bookkeeper, and leave it alone. See Accounting.

The journey

  1. Raise a purchase order — /pos-purchase-orders

    Pick a supplier, a destination warehouse and the lines you want. Saving creates a Purchase Order document numbered PO-YYYYMMDD-NNNN, with one line per product carrying ordered quantity and unit cost, at status draft.

    Stock: unchanged. Ledger: nothing. A purchase order is an intention, not an event. Nothing has arrived and nothing is owed.

    Send to supplier emails the order to the supplier's address with you on copy and advances a draft PO to sent. Mark sent does the status flip without the email, for orders you phoned in. Needs the purchasing capability.

  2. Receive the delivery — /pos-receive

    The moment the goods land, this is the screen. Choose the warehouse, the supplier, and optionally the purchase order it fulfils; enter a line per product with quantity and unit cost. Freight, duty and other landed costs go in the header.

    In one transaction, receiving:

    • Raises stock on hand at that warehouse, per line, under a row lock.
    • Writes a receipt stock movement per line.
    • Creates a Goods Receipt document, GR-YYYYMMDD-NNNN, header plus lines — the record a supplier return is later raised against.
    • Recalculates the product's cost (see below).
    • If you linked a purchase order, bumps the received quantity on the matching PO lines and recomputes the PO's status to partially received or received.
    • Registers lot numbers and expiry dates, or serial numbers, for products set to track them.

    Ledger: nothing on periodic. Under perpetual, with the "Post goods receipt to ledger" auto-action enabled, it posts Dr Inventory (1340) / Cr GRNI (3240) at the receipt's total cost. No VAT is recognised here — that arrives with the supplier's tax invoice.

    Needs the receive capability.

  3. Stock is on hand — /pos-stock-overview

    The overview is a read-only pivot: products down, warehouses across, quantity in the cells, with anything at or below its reorder point highlighted. It also carries a value column — quantity × unit cost — and a grand total, which is the number you reconcile against the inventory account.

    Under FIFO the same page grows a Batch cost layers panel: every open layer with its received date, lot, expiry, quantity left and unit cost.

    Any user with access to the POS app can read this. The raw records are also browsable at Stock and Stock movements in the sidebar.

  4. Something happens to it

    From here the unit takes one of five exits. Each is covered in its own section below: it sells, it moves to another location, it gets adjusted, it gets counted, or it goes back to the supplier.

Exit 1 — it sells

A sale at the register (/pos) or through the online store runs the same checkout. Inside one transaction it locks each product's stock row, decrements it, writes a sale movement, and creates the Sale plus Sale Lines with a server-computed total and a monotonic receipt number.

Checkout also snapshots the cost it relieved onto the sale — per line and as a header total. That snapshot is what a later refund or void reverses, so goods are always valued at what they cost when they sold, not at today's catalog cost.

SituationStockCost relieved
Product with no stock row (untracked — services, prep, made-to-order) Sells freely, nothing to decrement Zero. There's no cost basis to relieve.
Tracked, enough on hand Decrements normally The full quantity, at weighted-average cost — or oldest-layer cost under FIFO.
Tracked, short on hand Refused, unless the register has Allow overselling switched on — then it goes negative Only the units that were actually on hand. The oversold portion relieves nothing.

That last rule is deliberate and it's what keeps the books honest: cost is only ever relieved for units that were genuinely capitalised, so the inventory asset can't be driven below zero by an oversell.

Ledger: a completed sale posts Dr Cash / Cr Sales revenue / Cr VAT payable — and, under perpetual, an additional Dr COGS (7100) / Cr Inventory (1340) leg for the cost it relieved. Full detail in Order to cash.

Exit 2 — it moves to another location

/pos-transfer moves quantity between warehouses. Pick source and destination, add lines, submit. Each line produces two movements: an OUT with negative quantity on the source and an IN with positive quantity on the destination, so both ends carry an audit trail.

A pre-flight check refuses the whole transfer if any line is short — there are no partial transfers. Fix the line and resubmit.

Transfers never touch the ledger

And they shouldn't. Nothing has been bought, sold or lost — the same value is simply sitting in a different building. Under FIFO the cost layers move with the goods, so the destination inherits what the source actually paid and total inventory value is conserved to the penny.

Needs the transfer capability.

Exit 3 — you adjust it

/pos-adjust sets the absolute quantity on hand for a product at a warehouse. You type what's actually there; the server works out the difference and writes that difference as an adjustment movement, so the audit trail stays a continuous chain rather than a series of overwrites. Lines where the new quantity already matches are skipped.

Three reasons are available, and they behave differently in the books:

ReasonUse it forLedger under perpetual
Adjustment Damage, breakage, a correction you spotted Net decrease → Dr Inventory write-off (7110) / Cr Inventory (1340). Net increase reverses it.
Count The result of physically counting a shelf Same as adjustment. Also stamps a last-counted date on the stock row.
Opening Go-live: the stock you already owned on day one Net increase → Dr Inventory (1340) / Cr Opening balance equity (5500). You can supply a unit cost, which also sets the product's cost.

The value posted is the quantity difference at the product's current cost — or, under FIFO, at the actual cost of the layers relieved. On periodic (the default) none of this posts; the stock still moves, quietly.

/pos-import is the same machinery behind a CSV paste (sku, qty, notes) with reason opening, for loading a starting position at go-live. It resolves SKUs before submitting and shows you the invalid rows so you can fix them rather than importing junk. One file, one warehouse.

All three screens need the count capability.

Exit 4 — you count it properly

/pos-stocktake is the guided version: pick a warehouse, work through the products, enter counted quantities, and review the variance before you commit. Submitting posts the whole thing through the same adjustment path with reason count — so a stocktake is a batch of delta movements, valued and posted exactly like a manual adjustment, but with the counting workflow around it.

This is the reconciliation point of the whole lifecycle. If the count and the system disagree, the count wins and the difference lands as a write-off or a recovery.

Exit 5 — it goes back to the supplier

Supplier returns are raised against a goods receipt, not out of thin air. Open /pos-goods-receipts, select the receipt, and enter per-line return quantities with a reason.

Each line is validated twice before anything happens — against what's still returnable on that receipt (received minus already returned) and against what's actually on hand. Any bad line aborts the entire return. Then, in one transaction:

  • A return movement (negative) is written and stock is decremented.
  • The receipt line's returned quantity goes up.
  • The receipt's status recomputes: receivedpartially returnedreturned.
  • A Supplier Return document is stored, SR-YYYYMMDD-NNNN.

Ledger under perpetual: the return reverses the receipt's capitalisation. You choose how it settles — against GRNI (the usual case, when the supplier hasn't billed you yet) giving Dr GRNI (3240) / Cr Inventory (1340), or against A/P when the bill has already landed and the return becomes a supplier credit. Periodic posts nothing.

/pos-supplier-returns is the read-only history. Both screens need the purchasing capability; goods receipts need receive.

Every step, side by side

The ledger column assumes perpetual inventory with the relevant posting enabled, and uses the Georgia chart's account codes. On the default periodic setting the whole column reads "nothing".

StepScreenRecordStockLedger
Order /pos-purchase-orders Purchase Order + lines
Receive /pos-receive Goods Receipt + lines, receipt movements Up Dr 1340 / Cr 3240
Supplier bill Your bill entity Bill Dr 3240 + Dr VAT input / Cr A/P
Sell /pos or the store Sale + lines, sale movement Down Dr Cash / Cr 6100 / Cr 3330, plus Dr 7100 / Cr 1340
Transfer /pos-transfer Two transfer movements per line Moves
Adjust / count /pos-adjust, /pos-stocktake Delta adjustment movement Set to counted Dr 7110 / Cr 1340 (or reverse)
Opening balance /pos-import, /pos-adjust Delta adjustment movement Up Dr 1340 / Cr 5500
Return to supplier /pos-goods-receipts Supplier Return + lines, return movement Down Dr 3240 (or A/P) / Cr 1340

Account codes come from the country pack your workspace uses and are editable per workspace — the inventory, GRNI and cash accounts are all settings, not hard-coded. The codes above are the Georgia pack's defaults.

How cost is worked out

Cost matters because it decides what a sale relieves and what your stock is worth. There is one rule that surprises people and it's worth stating on its own:

Only receipts change a product's cost

Selling, transferring and returning to a supplier never move the average. That's correct — a moving average only changes when new stock arrives at a new price. Opening balances set it, and a manufacturing completion updates it for the finished good. Nothing else does.

Weighted average (the default) blends each receipt in:

  • New cost = (prior quantity × prior cost + received value) ÷ (prior quantity + received quantity), computed across all warehouses.
  • If the product had no prior cost, it adopts the receipt cost outright rather than blending down from zero.
  • Lines received without a unit cost leave the average alone entirely.
  • Freight, duty and other landed costs are spread across the lines by value and folded into each unit's cost before any of this runs — so inventory is valued at what it truly cost to get on the shelf.

FIFO keeps a cost layer per receipt instead. A sale walks the layers oldest-received first and relieves each at its own actual cost. For products flagged as lot-tracked it orders by soonest expiry instead — the right rule for pharmacy and perishables, where a batch received later but expiring sooner should go out first, at that batch's cost.

Switching to FIFO seeds an opening layer from your current on-hand at the current average cost, so nothing is left uncosted. It's a workspace-wide choice, not per product.

When stock is wrong

"I received a delivery and stock didn't change"

Check whether the receipt was deduplicated. If you fill in the reference field, receiving is idempotent on it — a second submission with the same reference is treated as a retry of the first and does nothing. That's what stops a double-click or a flaky connection creating phantom stock. Use a fresh reference for a genuinely separate delivery.

"On-hand went negative"

Only one thing does that: a register with Allow overselling switched on. Everything else — transfers, supplier returns, manufacturing issues — refuses outright when there isn't enough. Turn overselling off on the register unless you genuinely run backorders, and never run it alongside perpetual inventory: the oversold units sell with no cost basis, so your margin reads high until you receive them.

"The cost on a product looks wrong"

Work backwards through the receipts. The usual causes: a delivery entered with no unit cost (which leaves the average untouched, so an expensive batch never registered), a landed cost you forgot to enter, or a first receipt at an unrepresentative price that the average has been carrying ever since. A count or an adjustment can't fix a cost — it only moves quantity. To correct a cost, receive at the right price, or set it on the product.

"A transfer never showed up in accounting"

It isn't meant to. Moving stock between your own warehouses doesn't change what the business owns. Look at the two movements on the stock-movements list instead — one negative on the source, one positive on the destination.

"Stock is right but the ledger doesn't move at all"

Two independent gates, and both must be open. First, inventory method must be perpetual — on the default periodic setting stock operations post nothing by design, and purchases reach your P&L through the supplier bill. Second, the relevant posting has to be switched on under Settings → Reconciliation → Auto-actions: goods receipts, supplier returns and POS sales each have their own toggle and all start off.

"The inventory account doesn't match the stock overview total"

Compare the overview's value total against the inventory account balance and look for these, in order of likelihood:

  • Perpetual was switched on partway through. Receipts before the switch never capitalised, so the account starts from an arbitrary point. The account and the shelf can only agree from a clean start.
  • A posting toggle is on for one operation and off for another — receipts capitalising but sales not relieving will run the account up forever.
  • Oversold units. They sold with no cost basis, so the account holds value the shelf doesn't.
  • Price variance. When a supplier bill's net differs from the cost you received at, the difference is left sitting in GRNI or inventory rather than posted to a variance account. Small by design; check it if it's growing.
  • A locked period. Ledger posting is deliberately best-effort — if the period was locked, or accounting wasn't configured yet, the stock change still committed and the journal didn't. Stock is never rolled back because the books had a problem.

"GRNI has a balance that won't clear"

GRNI is the clearing account between "goods arrived" and "supplier invoiced us". A receipt credits it; the matching supplier bill debits it. A persistent balance means deliveries you haven't been billed for yet — which is often correct and worth reviewing — or bills entered against something other than the bill entity that clears it.

"A colleague can't open Receive or Transfer"

Each screen has its own capability: receive, count, transfer, purchasing. Granting someone access to the POS app lets them use the register and read the overview; the operational screens are granted individually. Admins always pass. See Permissions & access.

"A product sells but never appears in stock"

It has no stock row, which makes it untracked — deliberate, for services and made-to-order items. Untracked products sell freely and relieve no cost. To start tracking one, receive some or set an opening quantity; the decrement path switches on by itself from then on.

Where to go next