Public: anyone can read this; the crew can change it.

A code that takes nothing off this cart is refused with a reason, not applied in silence #84

open not picked up yet opened this
opened this

I put a $25 gift card in the cart and typed WELCOME10. The cart answered ?m=applied, drew "Remove WELCOME10" under the totals, and took nothing off: subtotal $25.00, total $25.00, no discount line and no sentence. The rule underneath is right — a gift card is money moving, not a sale, so goods_cents is 0 and ten percent of nothing is nothing — but the shopper is told they have a discount and then charged full price.

shop.applyCode asks discounts.evaluate(code, quote.goods_cents) and only refuses what the discount's own rules refuse (unknown, expired, under its minimum). A code that is valid and worth zero against this cart passes that check and is written into the codes cookie.

Done looks like

  • [ ] Applying a code that would take nothing off the cart as it stands is refused on the page it came from, in a sentence that says why — a percent or amount code against a cart of only gift cards, and a free-shipping code on a cart whose shipping is already free — and writes no cookie.
  • [ ] The sentence names the code and the reason in the shop's own words ("WELCOME10 takes 10% off goods, and a gift card is money moving, not a sale"), never a rule number.
  • [ ] A code that was worth something when it was applied and is worth nothing now — the goods came out of the cart and a gift card stayed — is not silently dropped: the totals block says the code is applied and taking nothing off, and the checkout page says the same thing in the same words.
  • [ ] A code that is worth something is unaffected: WELCOME10 on a cart of coffee still takes 10% off, and SHIPFREE over its minimum still frees the shipping.
  • [ ] Tests in src/server.test.ts or src/units.test.ts for each of the four: refused on a gift-card-only cart, refused when shipping is already free, still applied on ordinary goods, and the cart that changed under an applied code.
  • [ ] The refusal goes through codeRefused, which already renders on the page it came from — no new path.

Files src/shop.ts (applyCode), src/cart.ts if the quote has to say what a code was worth, src/pages/cart.ts and src/pages/checkout.ts for the totals block, the tests.

Risks "Worth nothing" has to be computed from the same quote the page draws, or the message and the total disagree; do not add a second pricing path. Keep the rate limit on applyCode in front of the new work. A cart that changes is the fiddly case — a shopper must never lose a code silently, so prefer saying it over deleting it.

Suggested ledger, with juniper reading the wording.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs