Skip to main content
All insights
Custom Software8 min readAugust 6, 2026

Why Inventory Workflows Need Multiple Quantity States

The short answer

One stock balance cannot distinguish physical quantity, commitments and confirmed consumption. Model each operational fact separately, define the event that changes it and preserve corrections as new events. This prevents the same unit being promised twice and keeps partial receipts, handovers and disputes auditable.

By Timothy Indarsingh, Founder & CEO, Firelinkx

Disclosure note

The examples below are deliberately generalized and may use simplified or hypothetical scenarios. They are not descriptions of any identifiable organisation's current systems, architecture or control state.

A tidy purchasing story says that someone requests an item, a manager approves it, purchasing orders it, receiving accepts it and the requester gets it. Real workflows contain partial orders, late invoices, substitutions, returns and two teams asking for the last available unit. A status field and one quantity cannot represent those facts without hiding commitments.

Define the event that moves stock

Physical stock should increase when goods are received. Whether it decreases at handover or at recipient confirmation is a business decision, but it must be explicit and consistently reconciled with the physical process. If confirmation is the control point, a handed-over item remains visible as pending until the recipient accepts, disputes or returns it.

Every earlier event answers a different question. Approval records authority to proceed. A purchase order records a supplier commitment. Receipt records goods entering custody. Handover records a transfer in progress. Confirmation records acceptance. Combining them erases the distinction needed to investigate exceptions.

A useful five-state quantity model

  • On hand: quantity physically held at the controlled location.
  • Reserved: on-hand quantity committed to approved demand but not handed over.
  • Pending confirmation: quantity handed over but not yet accepted or disputed.
  • Confirmed out: quantity whose removal has been accepted and posted.
  • Available: quantity that can still be promised after reservations and pending handovers.

These are not five copies of the same number. They answer different operational questions. Derive available quantity from the authoritative states rather than allowing a user to edit it independently, and enforce the invariant in the transaction that creates or releases a reservation.

Concurrency is part of the domain

When two requests race for the last unit, an availability check followed later by a write is unsafe. Lock or conditionally update the relevant stock record inside one transaction, then fail one reservation cleanly. The test must run against a database capable of exhibiting the race; a simplified test engine can produce a reassuring result without exercising the failure.

Partial progress is normal

Orders, receipts and handovers should support partial quantities at line level. A supplier may send part of an order, an invoice may arrive later, or a recipient may accept one item and dispute another. Keep these as visible states instead of marking the parent transaction complete and explaining the remainder elsewhere.

Cost provenance also matters. Goods can be physically usable before their final invoice cost is known. Record the source and confidence of the current cost, then post an explicit adjustment when confirmed information arrives. Rewriting the original receipt destroys the evidence needed to explain the change.

Corrections should add history, not erase it

A mistaken receipt, reservation or handover will happen. Reverse it with a linked event carrying an actor, reason and timestamp. The current balance becomes correct while the system still explains how it became wrong and how it was repaired.

Walk through a synthetic stock line

Consider a synthetic storeroom with 12 adapters on hand. Request A reserves 7, leaving 5 available. Request B reserves 4, leaving 1. When 6 units for A are handed over, the reservation falls from 7 to 1 and pending confirmation rises from 0 to 6. Physical custody may already have moved, but the workflow has not yet accepted the transfer. If the recipient confirms 5 and disputes 1, confirmed out rises by 5, the disputed unit follows an explicit return or investigation path, and the remaining reservation stays visible.

The example exposes an important modelling choice: whether pending-confirmation units still count inside on hand. Either convention can work, but the equations and physical count procedure must agree. One approach keeps on hand as controlled-location custody and removes units at handover; another keeps them in on hand until confirmation and subtracts pending confirmation when deriving available. Mixing the two creates phantom stock. Document one equation, such as available = on hand - reserved - pending confirmation, and define the custody meaning of every term.

Model transitions, not editable status labels

Represent receipt, reserve, release, handover, confirm, dispute, return, transfer and adjustment as commands with preconditions. A handover cannot exceed its active reservation. A confirmation cannot exceed the unconfirmed handover. A return must reference a prior custody movement. The resulting state may be cached for speed, but the command boundary should enforce the invariant and write the event in the same transaction.

  • Receive: increases physical custody and creates a cost layer or provisional valuation reference.
  • Reserve: moves quantity from available capacity into a named commitment without changing custody.
  • Handover: reduces the reservation and creates a pending transfer tied to a recipient and location.
  • Confirm or dispute: closes part or all of the pending transfer without overwriting the original handover.
  • Adjust: records a counted difference with reason and authority rather than editing a balance field.

Transfers require two-sided custody

Moving stock between locations is not a negative adjustment in one place and a positive adjustment in another. It is one transfer with an origin release, an in-transit state and a destination receipt. If a parcel leaves with 10 units and arrives with 9, the transfer remains partially unresolved until the missing unit is accounted for. This prevents an operator from fixing one location while silently breaking the other.

Design for retries and recovery

Mobile connections, double taps and job retries can repeat a command. Give each externally initiated mutation an idempotency key and store its accepted result. If the same key returns with different content, reject it as a conflict. For asynchronous work, use an outbox written with the inventory transaction so notification or downstream processing can resume without repeating the stock movement.

Recovery procedures should answer three questions without direct data editing: which events committed, which side effects remain pending, and which compensating command restores the intended state? Provide an operator-facing event timeline and reconciliation report. A manual SQL update may repair a number quickly, but it bypasses the exact history the model was designed to preserve.

Performance comes from bounded queries and derived views

An append-only movement table should not force every screen to scan all history. Index by item, location and effective sequence; maintain a transactionally updated balance projection; and periodically verify the projection against the event sum. Reservation queries should touch the narrow stock scope being changed, not lock an entire catalogue. Reporting can use snapshots for speed as long as the event history remains authoritative and snapshot rebuilds are tested.

Implement in phases without weakening the model

  1. Define quantity meanings, custody boundaries, state transitions and reconciliation equations before building screens.
  2. Ship receipt, reservation, release and adjustment with concurrency and idempotency tests.
  3. Add partial handover, confirmation, dispute and return after the core quantities reconcile reliably.
  4. Add transfers, cost layers and asynchronous integrations with explicit recovery tools.
  5. Introduce projections and reporting optimisations only after a rebuild-from-events check is routine.

The trade-off is additional states, transitions and operator education. A smaller operation may choose handover as the final removal event and omit recipient confirmation. That is a valid simplification if disputes are rare and custody is clear. The dangerous shortcut is not fewer states; it is using one ambiguous number while the real process still distinguishes commitments, custody and acceptance.

Test the quantities as invariants

  • Available quantity never falls below zero.
  • A reservation cannot exceed the quantity available in its scope.
  • Partial receipt and partial handover preserve the remaining quantity.
  • Releasing or reversing a reservation restores availability exactly once.
  • The sum of active layers reconciles to the physical on-hand balance.
  • Cross-scope requests cannot reserve or report another scope's inventory.
  • Two concurrent reservations for the final units cannot both commit.
  • Repeated commands with the same idempotency key produce one movement.
  • A transfer shortage remains visible instead of being balanced away.
  • A projection rebuilt from events matches the transactionally maintained balance.

The key design move is to model physical custody, commitments and acceptance as different facts. Once those facts have names and transition rules, the workflow can survive partial reality without inventing a parallel spreadsheet for every exception.

Want your stock and orders easier to manage?

Firelinkx helps Guyanese businesses get this right. Get a clear scope, timeline, and price, or just ask a question. We respond within 24 hours on business days.

WhatsApp Us