Skip to main content
Version: v1.0.0

Finished Goods Inventory

Finished-goods inventory is the running record of product stock, kept as a ledger in exactly the same way as materials inventory: movements are appended as entries and the position is summed per product and location. What's different is that finished goods track a demand side (what customers want and what's been set aside), not just what's physically on hand.

How the ledger works

Each entry records one movement: a product, a location, an event type, a quantity, an optional unit cost, and a ref linking it back to whatever caused it. Entries are never edited or deleted in normal operation; a movement that needs undoing is offset by a reversing entry. Two timestamps matter: event date is the business moment the movement happened, date and time, so same-day movements keep their real order (you can set it), while created-at is when the row was written. Positions and ordering use the event date.

Product can arrive three ways: bought on a purchase order, made by a work or production order, or moved in by a transfer. All three arrive as a RECEIVE; the entry's source says which.

Event types

Each entry's event type is drawn from the shared inventory vocabulary, identical on both ledgers. The single canonical list, with every forward event, its REVERSE_ counterpart, and the SETTLE_ close forms, lives in the modules overview.

A SETTLE_ entry trues an order up when it is closed. The first receipt moves an order to Partial and Received is set by hand, so the booked commitment rarely matches exactly what arrived. On reaching Received the system writes a settle entry for the gap between ordered and received: SETTLE_ORDER on the on-order side, SETTLE_ALLOCATE on a job's allocated stock. The gap is signed, so the one entry trues the figure to zero whether the order came up short (it clears the leftover) or over (it cancels the excess). It is written automatically, never by hand, and is undone by deletion: revert an order back out of Received and its settle entries are removed, restoring the open commitment.

Deriving the position

Finished goods derive four figures, each a signed sum over the entries with every REVERSE_ form backing out its event:

  • On hand = RECEIVE + ADJUST - CONSUME - DISPOSE. A transfer out is a CONSUME, so it is already counted.
  • Demand = DEMAND - ALLOCATE.
  • Allocated = ALLOCATE - CONSUME - SETTLE_ALLOCATE.
  • Available = on hand - allocated.

The supply side also carries on order = ORDER - RECEIVE - SETTLE_ORDER. A finished-goods output is delivered either by a purchase-order delivery or by a work or production order's produced goods coming back, both a RECEIVE, so both draw on-order down as they arrive; SETTLE_ORDER clears whatever is left when the order is closed short. A transfer's arrival never touches on-order, because a transfer never booked an ORDER.

A SETTLE_ term is added only to the figures that do not already reach their closed value on their own. Closing an order that received 3 of 10:

FigureAt closeLands atSettle
On order10 - 37SETTLE_ORDER
Allocated10 - 37SETTLE_ALLOCATE
Demand10 - 100none

Receiving over flips the sign: 12 of 10 leaves on order at -2, and the settle carries that signed gap to bring it back to 0. A settle always holds the signed difference between ordered and received, so it trues the figure to zero either way.

ALLOCATE does double duty: it relieves demand (so demand reaches 0 by itself) and it creates the reservation (which CONSUME only partly relieves, so allocated still needs a settle). That is why there is a SETTLE_ORDER and a SETTLE_ALLOCATE but no SETTLE_DEMAND. Positions are grouped by product and location.

The API serves one complete position per product and location: on hand, on order, allocated, available, in stock (on hand net of allocation, never below zero), demand, wasted (the DISPOSE total), in-transit, and net position (in stock plus on order plus in-transit minus demand). The same shape is served for materials, so the two ledgers cannot drift.

A manual ADJUST corrects a count in either direction: a positive quantity raises on-hand, a negative one lowers it (for example, fixing a count that was entered too high). A DISPOSE is the write-off path for damage, loss, or expiry; it carries waste semantics and stays a positive reduction.

Lots and expirations

An arrival carries the lot and expiration entered on its receipt line; every later movement of that stock derives them from there. When one movement spans several lots (a shipment drawn from two batches, say) the ledger view splits it into one line per lot, each with its own expiration and unit cost, even though only one movement is stored. How that works, and why, is covered in Lots & Expirations.

Where the entries come from

SourceEvents
Purchase orders (finished goods)ORDER, RECEIVE, SETTLE_ORDER
Work orders (outputs)ORDER, RECEIVE, SETTLE_ORDER
Work orders (sub-assembly inputs)DEMAND, ALLOCATE, CONSUME, SETTLE_ALLOCATE
Production orders (outputs)ORDER, RECEIVE, SETTLE_ORDER
Sales ordersDEMAND, ALLOCATE, CONSUME
TransfersCONSUME, RECEIVE
Manual operationsADJUST, DISPOSE

The interplay between the supply side (purchase, work, and production orders) and the demand side (sales orders) is what the Pipelines section traces end to end.

See also

Read summaries and post manual events through the REST API or the MCP server.