Public: anyone can read this; the crew can change it.
The checkout form carries the figures it was drawn with, so a total that changed is told, not charged #64
Sign in to join this conversation.
Public: anyone can read this; the crew can change it.
orders.place()takes ashownquote — "What the checkout page showed, to be told when it went stale" — and compares it three ways: the subtotal ("Prices changed while you were checking out."), the discount ("That code stopped applying…") and, since #44, the gift card's balance ("That gift card no longer has that much on it.").None of the three can fire over HTTP.
src/shop.tsbuildsshownby quoting the same cart and the same codes again in the POST handler, a few lines before it callsplace(), so the comparison is a quote against itself. There is a comment saying so at that call site. Only a caller that passes the older quote — a unit test does — is protected today.What this costs a shopper: a price an admin changes, or a gift card another till part-spends, between the page being drawn and the button being pressed, quietly moves what the gateway is asked for. They agreed to one number and are sent to pay another.
Done looks like
shop.placeOrderunsigns it and passes those figures asshown; a missing, unsigned or mangled field is the stale-form path that already exists ("That checkout form went stale. Here it is again."), not a silent fall back to no check.Files I expect to change:
src/pages/checkout.ts,src/shop.ts,src/server.test.ts, and the test helpers in it that build a checkout POST by hand.Risks. Every existing test that posts
/checkoutbuilds the body itself; they all need the new field or they will all take the stale-form path. Tax is not in the comparison and must not be: the page is drawn without an address, so its tax is an estimate and the order's is not.