Security · Purchasing · Multi-vendor

A requisition filed under another company’s supplier

Raise a stock request naming a neighbour’s ingredient and the purchase order landed in their order book. Receiving it would have moved their buying price.


A requisition is how a kitchen asks for stock: two cases of this, from that supplier, please. Under the venue’s spend limit it approves itself, and one tap turns it into a purchase order. We asked what happens if the kitchen names an ingredient and a supplier that belong to a different company in the same hall.

It went all the way through

The purchase order was created with the other company’s product on the line and filed under the other company’s supplier. Two consequences, not one. Receiving a purchase order updates the buying price of whatever the line points at, so a competitor’s cost price would have moved on the strength of your order. And because whose order it is follows the supplier, the order landed in their order book, for a venue that is not theirs, and the person who raised it could not see it afterwards.

The ordinary purchase-order screen has asked both questions since it was written. This was the other road into the same table, and it asked neither.

The refusal that proved nothing

The first attempt was refused, and had we stopped there the road would have been written down as fenced. Raised at nearly nine thousand pounds it came back over the spend limit, and then: you raised this, somebody else has to approve it. Both are real controls doing their job. Neither has anything to do with whose product it was. What gave it away was the control run: the same flow with the kitchen’s own product stopped in the same place for the same reason. Two requests refused identically is the tell that the refusal is not about the thing you are testing. Under the limit a requisition approves on submit and the road runs to the end.

The first fix was worse than the bug

Editing a requisition replaces its lines by deleting the old set and writing the new one. Putting the refusal inside the write meant that an edit naming one foreign product on line two deleted the kitchen’s real order, wrote line one, and then stopped. The record was half gone because the request had been rejected. The check is now a pass of its own that runs before anything is written or deleted, on create and on edit, so a refused request leaves nothing behind.

What is pinned

Reverting the fix fails four tests by name. Moving the check back to after the delete, with everything else intact, fails exactly one, which is the ordering property on its own. And a line with no product and no supplier is still accepted, because a kitchen asking for whatever the fish man has this week is a feature, and a fence that refused it would have broken the thing rather than protected it.


Try it on tonight’s service.

Nothing to install, no card. Not better by the weekend? Close the tab.