Skip to main content

Delayed transactions

For some types of transactions, the sequence of the transactions is important to get the calculations done correctly. However, since some transactions might be delayed for a reason, the system needs to handle this when processing the transactions.

The case that matters is a stock count, because a count does not describe a change — it asserts an absolute truth about a point in time. A movement that happened before the count but arrives after it — a sale from a till that was offline, a delivery registered late — is already reflected in the counted quantity. It must not be applied on top of it, or the same goods are removed (or added) twice.

Example:

  • 10:00, the system quantity is 12
  • 11:00, business unit performs a stock count, counted quantity is 10
    • System calculates a loss/gain based on whether the counted quantity deviates from the system quantity, in this case, it's a loss of 2 items
    • System calculates new stock quantity = 12 - 2 (loss) = 10
  • 11:05, receives a sale performed at 11:05, sales quantity is 1
    • System calculates new stock quantity = 10 - 1 (sale) = 9
  • 11:10, receives a sale performed at 10:30, sales quantity is 2
    • The sales transaction is actually done prior to the stock count, so the transaction should not affect the current stock quantity.
    • On the other hand, the stock count performed at 11:00 reported a loss of 2 items, so the system creates a gain of +2 items to adjust the previously reported loss. In addition, the sales transaction is stored, i.e. reducing the stock by -2 items, so the result for both transactions is no change in stock quantity:
    • System calculates new stock quantity = 9 + 2 (adjust/nullify loss reported for stock count) - 2 (sale) = 9

A sale that happened before a stock count but arrives after it. At 10:30 an offline till sells 2. At 11:00 the count finds 10 where 12 were expected and books a loss of 2. At 11:05 a sale of 1 brings stock to 9. At 11:10 the offline till syncs and the 10:30 sale arrives. It is stored with minus 2, and a compensating plus 2 dated 11:00 cancels it, so stock stays at 9. Applied on its own it would give 7, removing the 2 bags twice, because the count already saw them gone.

Note: The transactions are immutable, so any adjustment of previously created transactions needs to be handled by creating a delta transaction.

What this looks like to a consumer​

The correction is published like any other transaction, so a subscriber sees three transactions from the example above: the original count from earlier, then the late sale and the compensating gain.

TransactionoperationTypequantitytransactionDate
the original countSTOCK_COUNT−211:00
the late saleSALES−210:30
the compensating gainSTOCK_COUNT+211:00

The late movement and its compensation always cancel out: their quantities sum to zero, and so do their costs. These fields identify what is happening:

FieldUse
transactionDatewhen the movement actually happened — 10:30 for the late sale. The compensating transaction carries the count's date, 11:00
linkIdDelayedset on both the late movement and its compensating transaction, to the transactionId of the stock count transaction they relate to. Empty on every other transaction
linkIdRelatedthe same value on the late movement and its compensation, so the pair can be grouped as one operation
documentType / documentIdon the compensating transaction, StockCount and the id of the count it corrects

transactionDate can therefore be older than that of a transaction you already received. A consumer that assumes the stream is ordered by business date will misread this. Order by timestamp — when STP processed the movement — and treat transactionDate as data. See External Events.

Scope​

Compensation applies to every movement of sellable stock (SalesStock) that is dated before the item's most recent stock count — sales, deliveries, stock corrections and transfers alike. It is always made against that most recent count, because that count is the latest statement of what was there.

It does not apply to the operations that themselves assert an absolute quantity — a stock count or a synchronize stock. Those are never compensated.

A movement with no stock count after its date needs none of this. Ordinary movements are deltas, so a late arrival simply applies its delta, and the total comes out right whatever order the movements were processed in.


Return