Skip to content

feat: re-check the cart against the menu at checkout and cap quantities (#42) - #194

Merged
Yousefa7medmaher merged 1 commit into
devfrom
feat/checkout-revalidation
Oct 13, 2026
Merged

Yousefa7medmaher merged 1 commit into
devfrom
feat/checkout-revalidation

Conversation

@Yousefa7medmaher

Copy link
Copy Markdown
Member

Summary

Checkout re-validation (#42): an order is priced only from a cart re-checked against the menu at the moment of checkout. A customer is never charged a price they didn't see.

Closes #42.

Decision (the issue left it open): refuse and explain, rather than silently charge the current price. The customer always pays the total they were shown.

How it works

POST /cart/validate (cart-service) re-reads every cart item from menu-service.

  • Unchanged: returns the cart.

  • Changed: first brings the cart up to date, then answers 409 CartChanged with details.changes:

    Change Reported as Cart afterwards
    A different price PRICE_CHANGED (previousPrice, currentPrice) Holds the current price
    Sold out UNAVAILABLE Item taken out
    Archived, deleted or now another restaurant's REMOVED Item taken out
    An old line over the cap QUANTITY_LIMITED Lowered to 20
  • A renamed item is refreshed quietly: what the customer pays is the same.

  • A menu-service outage is an error, never a "removed" item.

order-service calls it in createFromCart and passes CartChanged straight to the client. The subtotal is the sum of price × quantity per line, in piasters, never cart.total. It also re-checks each quantity is between 1 and 20. The restaurant-open check is unchanged.

Quantity cap: MAX_CART_ITEM_QUANTITY = 20 per item, enforced by the cart DTOs (@Max), by adding to an existing line, and again at checkout.

shared: AppError gains optional details, which the exception filter sends as details. Adds CartChangedError, CartChange and MAX_CART_ITEM_QUANTITY.

Contract and docs: public OpenAPI adds POST /api/cart/validate and the 409 CartChangedError schema on it and on POST /api/orders. Docs: docs/services/cart-service.md ("Checkout re-validation").

The customer app side (reload the cart and quote on 409, stop + at 20) is Delivery-Plus0/delivery-plus-customer-app#47.

Test plan

  • Unit tests:
    • cart-service (19): quantity cap on add; validate reports every change kind and stores the updated lines; another restaurant's item; a rename only; an outage isn't treated as removal; empty cart.
    • order-service (121): CartChanged passed on with nothing created; subtotal from the items, not the total; quantities 0, 21 and 1.5 refused; closed restaurant.
    • gateway (17).
  • npm run build (all workspaces) and the public OpenAPI generate/validate (73 paths), after rebasing on fix(order-service): today summary misses orders placed 03:00–06:00 Cairo time #192/feat: cancellation window, automatic refunds and post-pickup compensation (#53, #56) #193.
  • npm run e2e on an isolated base + test stack built from this branch, all passing:
    • price 40 → 45 after adding → 409 CartChanged with PRICE_CHANGED 40 → 45;
    • the cart then holds 45, and the retry is priced at 2 × 45 = 90.00;
    • 21 of one item → 400.
  • CI

🤖 Generated with Claude Code

…es (#42)

order-service prices orders from a cart re-checked by cart-service right
before checkout (POST /cart/validate). A changed price, a sold-out,
archived, deleted or foreign item, or a quantity over the cap answers
409 CartChanged with details.changes, after the cart has been brought up
to date, so a customer is never charged a price they did not see. Order
totals come from item price x quantity in piasters, never a cart total.
At most 20 of one item (MAX_CART_ITEM_QUANTITY). AppError gains optional
details, sent in the error response.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Yousefa7medmaher
Yousefa7medmaher requested a review from a team as a code owner October 13, 2026 03:34
@Yousefa7medmaher
Yousefa7medmaher merged commit cdee388 into dev Oct 13, 2026
22 checks passed
@Yousefa7medmaher
Yousefa7medmaher deleted the feat/checkout-revalidation branch October 13, 2026 05:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(cart-service): harden the checkout handoff contract with the order service

1 participant