Skip to main content

Reading a movement

How to take one ledger row and work out what actually happened.


1. What every row carries​

FieldAlways presentNotes
transaction_type✅One of the six
quantity✅Signed
Item key✅Either variation_id or raw_material_id, never both
created_at✅
created_by✅ storedNever displayed — Audit Info reads N/A
reference_noreceipts, sales, maintenanceProduction writes none
batch_idreceipts, sales, maintenanceProduction writes none
reference_idproduction onlyThe production order's id
unit_costreceipts, salesCost on a receipt, selling price on a sale
batch_number, expiry_datereceipts onlyVendor lot data
remarksusuallyEncoded, and shown undecoded here
One row is either a product movement or a material movement

A database check constraint enforces it: exactly one of variation_id and raw_material_id is set. There is no row that moves both.


2. Identifying the item​

Row keys onItem Details shows
A variationProduct name, SKU, variation — correctly
A raw materialNothing
Raw-material rows are anonymous in the UI

The API returns raw_material_name on every row. The ledger page renders only product_name, so the name is dropped for materials.

To identify a raw-material movement you have to work sideways:

  1. Read the unit in the Movement column — KG, LT, PCS narrows it
  2. Read the Remarks — a receipt's remarks name the vendor and the delivery
  3. Match the reference number back to the receipt or maintenance entry, which do show names
  4. Or query it through the external API, which returns the name

3. Tracing each type back to its source​

TypeTrace by
PURCHASEreference_no → the goods receipt batch
SALEreference_no → the invoice
ADJUSTMENT / WASTAGEreference_no → the maintenance batch
PRODUCTION_INThe remark Production Order #xxxxxxxx completion
CONSUMPTION_OUTThe remark Consumption for Production Order #xxxxxxxx

Recognising a production run​

A completed run always looks the same:

PRODUCTION_IN +18 <product> "Production Order #36385abd completion"
CONSUMPTION_OUT −7.6 (blank) "Consumption for Production Order #36385abd"
CONSUMPTION_OUT −0.1 (blank) "Consumption for Production Order #36385abd"
…one per ingredient

One positive row naming the product, followed by N anonymous negative rows sharing the same 8-character id. That id is the first 8 characters of the production order's UUID, which is also what the order list displays.


4. Decoding the remarks yourself​

The ledger prints the tags raw. They mean:

TagFromMeaning
[CUST:…]SalesCustomer name
[PH:…]SalesCustomer phone
[PAY:…]Salescash · card · upi · bank · credit
[DISC:…]SalesDiscount percent applied to the cart
[TAX:…]SalesTax percent, typed by the operator
[REASON:…]MaintenanceFree-text reason
[REASON_ID:…]MaintenanceA master reason id — never written, because the master list cannot be populated
[BATCH:…] / [REF:…]LegacyAn older receipt encoding, superseded by the real batch_id and reference_no columns
Anything after the tags is the operator's own text

[REASON:Expired stock] Past shelf life at morning check — the reason is Expired stock, the note is the rest.


5. Working out a balance​

There is no balance column. The balance for a variation is SUM(quantity) over its rows — which is what the webhook payload's new_level uses.

That sum is not the number any screen shows

The catalogue Stock column and the raw material Stock Status read current_stock, which no ledger operation writes.

The ledger sum and the displayed stock are independent and routinely disagree. Read How stock is counted.

The sum can be negative — nothing blocks a production run or a sale that exceeds what has been received.


6. Worked example​

A row reading:

Jul 29, 2026 20:00 | (blank) | WASTAGE | ↙ 3.5 KG | N/A Ref: Manual
[REASON:Spoilage — cold chain break] Chiller failure overnight; batch discarded

Tells you:

  • A raw material was written off — blank Item Details means material, not product
  • 3.5 KG — so a material measured in kilograms
  • It was wastage, not a counting correction: the stock existed and was destroyed
  • The reason was a cold-chain failure, with the operator's own note
  • Who did it is unrecoverable from this screen — Audit Info is always N/A

To find out which material, open the maintenance batch with the same reference number, where the names are shown.


7. Troubleshooting​

SymptomCause
Cannot tell what item a row refers toRaw-material rows do not render their name
No reference number on a rowIt is a production movement; trace via the remark
Two rows look identicalThey are separate lines of the same batch on different items
Who posted this?Not answerable from the UI — created_by is stored but never resolved
The sum does not match the stock columnTwo independent systems