Flow
One rule, one planner, three checks
1Piece size
Case size and unit cost in, the smallest legal store piece out. The planner and the checker both ask this one function.
2Planner
Adds up demand per product, rounds to whole cases once, gives the overflow store the first extra piece, then hands out the rest to whichever store ends up closest to its request. Typed-in overrides come in here as demand.
3Checkout
The checker runs before any order rows are saved and stops a bad order, naming the item and store.
4Buyer approval
The version a buyer is about to approve gets checked, never changed.
5Supplier document
Checked one last time before the supplier sees it.
Store quantities that nobody was allowed to order were going into the cart from the ordering system, which then fixed the total in a second pass.
Two rules, one product
The supplier sells whole cases, so each product has to add up to whole cases across all my stores. Inside my stores, a case can sometimes be split. A store can take half a case only if the item costs more than a set price line and half the case is a whole number of units. Otherwise it takes a full case. An item right on the line gets full cases. So does an odd pack. If you build this, compare prices in whole cents, not dollars with decimals, so the line is exact.
What the old planner did
The old planner rounded each product's total up to whole cases and put the extra at the store I use for overflow. Every other store kept its raw request. If a store wanted four of something that comes in twelves, the cart said four. A later step added a row to cover any missing half case. The cart was only legal after that step ran.
Manual overrides were worse. They wrote the typed number straight into the cart and skipped the case math. If you have an override path, check where it writes.
The checker went in first
That evening I wrote a checker before I touched the planner. It reads order lines and changes nothing. It checks a few things:
- each product adds up to whole cases
- each store holds a multiple of that product's piece size
- one product has one case size and one price
- a store's split lines get added up before the check
It runs at checkout, at buyer approval, and when the supplier document is built. If it fails, the order stops and the message names the item and store. It never rounds anything, because the buyer should get exactly what they approved.
Then the planner
A bit over an hour later I rewrote the planner so it only makes legal quantities. It adds up demand once and rounds to cases once. If there's extra, the overflow store gets the first piece, even if it didn't ask for any. The remaining pieces go out greedily.
Each piece goes to whichever store it brings closest to what it asked for.
Ties break in a fixed order, so the same input gives the same cart. Overrides now count as demand and go through the same steps. The planner and the checker both ask one shared function for the piece size, so they agree on what's legal.
Each cart row also records the numbers behind its share, so a later check can redo the math instead of trusting a label. Two small follow-ups came within about twenty minutes, so the suggestion report and the bucket path handle the overflow store the same way.
The store that gets nothing
This design has a cost you should decide on up front. With a six-unit piece, stores asking for six and five, and the extra seeded at the overflow store, the result is six, zero and six. The store that asked for five gets nothing. My tests show the same thing in another case. It's legal, but someone at that store will ask where their order went.