Why your stock count can be wrong by a whole order
Stock was taken off at order and again at dispatch, so every shipped order was miscounted. Partial dispatch then let two drops ship the last unit.
Your stock count says you have forty units. The shelf says twenty. Nobody stole anything and nobody mistyped anything. Every step in the workflow looks correct when you check it on its own, and the total is still wrong.
That was the old system this one replaced. Stock was taken off when an order was confirmed, and then taken off again when the order was dispatched. The count was wrong by the whole quantity of every dispatched order, and it was wrong quietly. Nothing errored, nothing flagged it, and decisions about what to reorder were made on a number that was lower than the truth.
What was actually going on
There were two separate problems in the same area, and the second one only appeared because of how the first was handled.
The first was the double count. Confirming an order reserves stock. Dispatching ships it. If both steps subtract, the same physical goods leave the count twice. The same trap sits in demonstration stock: issuing a demo unit takes it out of the branch, and converting that demo into a sale is a change of category, not a second movement of goods.
The second was a race. The first version of the dispatch module allowed exactly one dispatch per order. That was written down as a scope decision: partial shipment was a later feature, and refusing a second dispatch kept version one small. When partial dispatch was built, the rule came off, and the check became “what is being shipped now, plus everything already shipped, must not exceed what was ordered”.
That check is a read, then a decision, then a write. Two drops raised against the same order at the same moment both read the same already-shipped total, both see one unit left, and both ship it. The one-dispatch-per-order rule had been preventing that all along, and nobody had listed it among the things the rule was for.
What we changed
For the double count, each physical movement now has exactly one step that is allowed to make it. Dispatch never touches stock, because stock left at order confirmation. Converting a demonstration into a sale nets off the quantity outstanding and records no movement. Marking a demo lost writes it off, and the stock stays out, because it is out.
Each of those rules has an automated check that asserts the quantity does not change across the step. That sounds odd until you have chased the alternative: a check that stock is unchanged after a dispatch is the only thing standing between you and a tidy-minded change later that decides dispatch is where stock should leave.
For the race, stock reductions were already safe elsewhere in the system, because the condition is part of the change itself: take five off only if at least five are there, decided by the database in one step. That works when the quantity sits in one place. The dispatched total is a sum across several rows, so it cannot be protected that way. The dispatch step now locks the order line first, so a second drop waits, sees the first drop’s quantity, and is refused if nothing is left.
What it did not fix
The lock makes a dispatch slower than a stock reduction, and that cannot be avoided when the rule covers a set of records rather than a single one. It also does not repair the old system’s miscounts; those figures were already wrong before this work began.
The other limit is a habit rather than a bug. The one-per-order rule was documented as “partial dispatch is out of scope”. That was true and incomplete. It was also the only thing making the shipped quantity a simple fact instead of a sum.
The pattern, for anyone running stock through a system
Ask two questions of your own process. Which single step moves a given quantity, and can you name it? If two steps both subtract, you have a double count that no individual screen will show.
And when someone removes a restriction, ask what the restriction was quietly guaranteeing, not only why it was put there. The reason it was introduced survives in the notes. What it kept true usually does not.
Where this ends up
Partial dispatch in Sazinga Field is built on these rules: dispatch never touches stock, and two drops against the same order are decided by the database, so only one can take the last unit.