How adjustments move stock & cost
A manual adjustment is the direct way to change what SKU.io thinks you have on a shelf. You reach for one when reality and the system disagree — you found extra units, you dropped and broke some, you're keying an opening balance, or you're writing off expired stock. Unlike a stock take, an adjustment is immediate: you pick a product, a warehouse, a direction, and a quantity, and the change lands the moment you save. This page explains what actually happens underneath — to on-hand, to the movement ledger, to FIFO cost layers, and to your books.
To make one, see Adjust stock (increase, decrease, set). To review or correct existing ones, see Review, correct & delete adjustments.
FIFO layer, COGS, allocation, backorder, and on-hand vs. available are each explained on the concept pages linked here.
The increase / decrease / set model
Every adjustment is one of three types, which you choose in the Adjust Stock dialog:
| Type | You enter | What it means |
|---|---|---|
| Increase | A positive quantity | Add that many units on top of what's there. |
| Decrease | A positive quantity | Remove that many units from what's there. |
| Set | A target on-hand number | Make the warehouse balance equal to this figure. |
The type is a request-time selector, not a stored column. What the database actually keeps is a single signed quantity on the adjustment: an increase saves +abs(quantity), a decrease saves -abs(quantity). A set is resolved before anything is written — SKU.io reads the product's current on-hand in that warehouse, computes the difference between your target and that count, and then routes the adjustment through the increase path (if the difference is positive) or the decrease path (if it's negative). Because of this, a set is really just a convenience wrapper that spares you the mental arithmetic.
If the target you enter already equals the on-hand quantity, the difference is zero and no adjustment is created — nothing is written, no movement, no ledger entry. This is intended: setting stock to what it already is should change nothing.
Because the stored value is a signed quantity, the direction you see later on the adjustment list and detail views is derived from the sign, not read from a saved "type" field. A row with a negative quantity reads as a decrease; a positive one reads as an increase. There is no separate "set" row — a set always appears as the increase or decrease it resolved to.
When you update an existing adjustment, the type field accepts only increase or decrease — never set. A set only makes sense against a live on-hand figure at creation time; re-running that math against an already-applied adjustment would be ambiguous, so the edit path forbids it. See Review, correct & delete adjustments.
What one adjustment does
Saving an adjustment triggers a tight, synchronous sequence. Understanding these five effects is understanding the whole feature.
- A movement is written. Every adjustment writes at least one inventory movement of type Adjustment, marked active, at the resolved warehouse location (bin). This is the audit trail — the movement carries the signed quantity, the product, the warehouse, the date, and a link back to the adjustment.
- FIFO layers move. An increase creates a new FIFO layer valued at
quantity × unit cost. A decrease consumes existing layers oldest-first and books their cost as it goes (covered under FIFO and cost flow below). - The location is resolved. The
inventory_adjustmentstable has no bin column — the location lives on the movement. SKU.io resolves it in priority order: the bin you explicitly chose > the product's preferred bin in that warehouse > the warehouse's default location. - The inventory cache is recomputed. Immediately after the stock engine runs, SKU.io recomputes the product's cached on-hand, available, and weighted-average cost for that warehouse — synchronously, in the same database transaction. There's no wait for a background job to see the new numbers. On write, cached available is floored at zero (it never shows a negative), even when the true on-hand position is negative — see negative inventory below.
- An event fires. An
InventoryAdjustedevent is dispatched. It's queued (ShouldQueue), so downstream listeners — demand-planning refreshes, integration pushes — run in the background without slowing your save.
The whole stock-moving sequence runs inside a database transaction that auto-retries up to three times on a deadlock, because a manual adjustment and a concurrent fulfillment can contend for locks on the same FIFO layers. That retry is invisible to you; it just prevents an occasional 500 under contention.
FIFO layers and cost flow
Adjustments touch cost differently depending on direction. This is where an adjustment stops being "change a number" and starts affecting your valuation and COGS.
Increasing: A new layer at a chosen (or inferred) cost
An increase creates a new FIFO layer for the quantity you added. Its unit cost is whichever of these is available first:
- The unit cost you typed in the dialog (required if the product has no cost history to fall back on).
- The product's current FIFO layer average for that warehouse.
- The product's default unit cost.
Because the new layer carries its own cost, adding units at a different cost than what's already on hand shifts the product's weighted-average cost for that warehouse. Add cheap units and the average drops; add expensive ones and it rises.
If the product has no average cost yet (a brand-new item, or one that's never been received), the dialog requires a unit cost before you can increase or set stock. This is exactly the "opening balance / found stock with no source document" case — SKU.io needs a number to value the new layer.
Decreasing: Consuming layers oldest-first
A decrease consumes existing FIFO layers, drawing down the oldest layers first (or soonest-to-expire first for lot-tracked products) and booking each layer's own cost as the cost of the removed units. Because different layers can carry different costs, removing units realizes a FIFO-weighted cost, not a flat average.
The Adjust Stock dialog previews this before you commit. For a decrease on a non-lot product, it shows:
- Each layer that will be consumed, with its date, available quantity, units to use, and per-unit cost.
- The total cost of the removal across all consumed layers.
- The weighted-average cost per unit — the total cost divided by the units actually covered by layers.
The preview reads the current layers at the moment you open the dialog. If stock moves between opening the dialog and saving — a fulfillment ships, another adjustment lands — the actual layers consumed (and therefore the actual cost) may differ. The final figures on the saved adjustment reflect what was really consumed. The per-unit COGS on any adjustment is its total realized cost divided by its quantity (and is zero when the quantity is zero).
Decreasing past available: Negative FIFO and re-backordering
SKU.io lets you decrease beyond what the FIFO layers can cover. This is deliberate — sometimes the physical count really is lower than any layer explains, and forcing you to reconcile first would block an honest correction. When the decrease exceeds available layer quantity, the dialog warns you:
When units exceed the available FIFO layers — the system will create negative FIFO entries.
Here's what happens when you proceed:
- Negative FIFO is created. The uncovered portion is written as a negative layer entry, so the product's on-hand can legitimately go below zero.
- Unbacked allocations are released. SKU.io scans the product/warehouse for allocations whose FIFO backing you just consumed, and releases those that are now dangling.
- Affected sales-order lines flip back to backorder. SKU.io recomputes the product's true on-hand for the warehouse — unfloored, as
(total − in transit) − allocated − on hold— and if that figure is negative, it flips the affected open sales-order lines back to has backorder. Stock you no longer have can't stay committed to an order. - Open fulfillment orders are reconciled. For each line that was re-backordered, SKU.io shrinks the open, unsubmitted fulfillment-order lines down to the new, smaller allocated quantity — so the pick footprint matches reality.
Step 4 is best-effort: a hiccup while reconciling a fulfillment order is logged and swallowed rather than rolling back your adjustment. The drift is corrected automatically on the next reserve, release, or background sweep — the stock change itself always sticks.
This is why an adjustment is never "just a number": pulling stock below your commitments ripples straight into the backorder queue and the orders waiting on it.
Lot tracking and FEFO
For lot-tracked products, an adjustment values and consumes stock by lot:
- Increasing captures each lot row (batch number, manufacture/expiry date) as its own FIFO layer, so every batch is valued and later consumed independently. Manual adjustments intentionally allow undated or blank-batch lots — the opening-balance and found-stock cases where you genuinely don't have batch paperwork.
- Decreasing consumes soonest-to-expire first (FEFO) by default, so short-dated stock leaves before long-dated stock. You can override the suggested allocation in the dialog and name exactly which lots to draw from — the read-only FIFO preview is replaced by a lot-consumption picker for these items.
The adjustment record exposes the product's lot settings (is_lot_tracked, lot_tracking_method, shelf_life_days, near_expiry_threshold_days) and the per-layer lot details, so downstream views can show which batches an adjustment touched. See FIFO layers & how COGS is realized for how lot layers carry cost.
Accounting: How an adjustment posts to the GL
Each adjustment is a financial document that builds one Accounting Transaction of type Inventory Adjustment. Its reference reads Stock Adjustment {SKU} (ID: {id}), and it posts a balanced, double-entry pair against the product's nominal codes:
| Direction | Debit | Credit |
|---|---|---|
| Increase (stock added) | Inventory account | COGS / expense account |
| Decrease (stock removed) | COGS / expense account | Inventory account |
The transaction amount is the adjustment's per-unit COGS applied across the quantity. Two special cases change the counter-account:
- Expired / spoiled write-offs — an adjustment with the Expired reason books the loss to a dedicated stock write-off (shrinkage) nominal code when one is configured, falling back to COGS.
- Purchase-order-linked adjustments — when the adjustment traces back to a purchase-order receipt, the counter-account is the accrued purchases account, and the reference is enriched with the supplier name and PO number.
The transaction appears on the adjustment's detail page under its Accounting Transactions tab, with its sync status to your connected accounting integration. If an adjustment is later rebuilt, its existing accounting-integration link is preserved so you don't double-post. Adjustments can also be batched into a combined accounting transaction for cleaner books.
Adjustment vs. stock take
An adjustment and a stock take both end in a stock change, but they're different tools:
| Manual adjustment | Stock take | |
|---|---|---|
| Definition | A direct, immediate change you enter by hand | A physical count reconciled against system quantities |
| When it applies | The moment you save | At finalization, when counts are committed |
| What it produces | One signed movement (+ FIFO + GL) | Adjustments generated from count variances, linked to the count |
| Traceability | Free-text reason and notes | Each generated adjustment carries a Stock Take link |
Stock-take-generated adjustments show a Stock Take reference on the adjustment list, so you can tell a reconciled count apart from a hand-keyed correction at a glance.
If a stock take is open for a product while you're adjusting it, the adjustments list shows an info banner: "Open stock takes in progress — adjustments will be reconciled at count finalization." A manual change you make now competes with the physical count that's about to be committed. Finish or cancel the count, or hold off on manual changes, to avoid a surprise variance when the take finalizes. See Finalize & reconcile a stock take.
Next steps
- Adjust stock (increase, decrease, set) — make an adjustment step by step.
- Review, correct & delete adjustments — edit, correct, or remove an existing one.
- Adjustment fields, reasons & columns — every field, reason, and list column.
- FIFO layers & how COGS is realized — the cost model adjustments feed.
- Stock states: on-hand, available, allocated, on-hold, non-sellable — what the numbers an adjustment changes actually mean.
- The inventory movement ledger — where every adjustment movement is recorded.
- Allocations & backorders — what a negative adjustment does to committed stock.
- How stock takes work — the reconciled-count alternative to a manual adjustment.