Flow
Order of decisions for one item
1Reserve room store by store
Stores go in a fixed order. Reviewed fills keep what they asked for.
2Clip machine demand
It gets the room still free at its turn, rounded down.
3Plan whole cases
If they do not fit, aim one case lower and try again.
4Defer the leftover
Keep it on the books for the next run.
5Check the books
Allocated plus deferred equals demand, and a rerun matches.
A hard stock ceiling and a supplier who only sells whole cases collided in the reorder planner, and nothing said which one wins. When I made it stop, my first try went too far and threw away orders it could have placed.
Two rules that fight
The ordering system sets a ceiling for each item: how much stock I'm willing to hold, based on recent sales. A second part, the case planner, splits whole supplier cases across the stores. When the room under the ceiling isn't a whole number of cases, there's a leftover. If no store can take it, the plan gets flagged for review.
Nothing said which rule wins.
Machine demand loses to the ceiling
For demand a person signed off on, review is fine. For demand the machine works out from sales, rounding up is the lazy answer. Say there's room for a bit over two cases. Rounding up orders three. I won't do that. So the ceiling wins, and the leftover is deferred. It stays on the books, and the next run probably looks at it again.
Keep the gate narrow. Only machine demand can be deferred, and only when the planner's sole complaint is that the leftover has nowhere to go. Any other problem should still stop the plan. Reviewed and machine demand share the same room. The planner walks stores in a fixed order and reserves room as it goes: reviewed demand keeps what it asked for, and machine demand gets whatever is still free at its turn, rounded down.
Zero cases instead of two
My first version skipped the whole order when it hit this case. Room for a bit over two cases meant zero cases, not two. That's just a different bug. Now it aims one case lower and takes units away from the lowest-priority store one at a time.
So instead of giving up, it keeps lowering the order and re-planning until the check passes or nothing is left to order.
Going one unit at a time is slow but safe, because store minimums make the math lumpy. Each pass lowers demand, so it always ends.
Items with stock and no sales
The second bug was worse. The case planner read a missing limit as no limit. Items with stock and no sales never got a limit written. So an overflow store could take any amount. Now those items get an explicit zero. If your code treats a missing key as "anything goes", check every place that fills that map.
Nothing goes missing
Every unit of demand ends up either allocated or deferred, never lost. The same input run twice gives the same plan. And an idle overflow store gets nothing.
Before I trust it
I haven't counted deferrals at a real store, so I can't say how many units this pushes back. Trimming by priority can miss a better split.