Skip to content

Slice 4: Payment & turn - #9

Merged
DanMat merged 1 commit into
nimbus-rebuildfrom
slice/payment
Sep 5, 2026
Merged

DanMat merged 1 commit into
nimbus-rebuildfrom
slice/payment

Conversation

@DanMat

@DanMat DanMat commented Sep 5, 2026

Copy link
Copy Markdown
Owner

Closes the service loop — settle a bill, close the order, turn the table for the next party. The money slice, with the payment-integrity controls the security review pinned.

What's here

  • Schema — payment columns on rest_order (amount_paid, payment_method, paid_at), folded into its migration (unreleased; no deployed install to ALTER).
  • Orders::pay(orderId, method, now) — the amount is the server-computed order total, never a caller value; only the method (allow-list cash/card/other) is chosen. Marks the order paid + closed and sets its table dirty, atomically. Rejects a bad method, a missing order, and a double payment. Reads now surface amount_paid / payment_method / paid_at.
  • Admin — a payment section on the order screen: total due + a method select, no amount input; a receipt once settled. "served" no longer shows a Close button — payment closes the order; the floor's existing dirty→open quick action finishes the turn.
  • MCP — order_pay (id + method only — no amount can be supplied).
  • Guide — payment note.

Security posture

The amount is never client-set — pay() takes no amount parameter, so it's structurally impossible to charge anything but the computed total (tested over both the service and MCP). The payment record carries no guest PII.

Tests

OrdersTest (charges the computed total, closes, turns the table, method allow-list, missing/double-pay rejected), OrdersAdminTest (pay form shows the total and has no amount input; receipt after), RestaurantToolsetTest (order_pay listed; pays the computed total over MCP; bad method comes back as data).

cs-fixer + PHPStan L6 green locally; phpunit in CI (8.2 + 8.3).

🤖 Generated with Claude Code

Closes the service loop — settle a bill, close the order, turn the table.

- Schema: payment columns on rest_order (amount_paid, payment_method, paid_at)
  folded into its migration (unreleased; no deployed install to ALTER).
- Orders::pay(orderId, method, now): the AMOUNT is the server-computed order
  total — never a caller value; only the method (allow-list cash/card/other) is
  chosen. Marks paid + closed and sets the table `dirty`, atomically. Rejects a
  bad method, a missing order, and a double payment. get()/all() now surface
  amount_paid / payment_method / paid_at.
- Admin: a payment section on the order screen (shows total due + method select,
  no amount input; a receipt once settled). "served" no longer offers a Close
  button — payment closes the order. The floor's existing dirty→open quick action
  finishes the turn.
- MCP: order_pay (id + method only).
- Guide: payment note.
- Tests: OrdersTest (computed-total charge, close, table turn, method allow-list,
  missing/double-pay rejected), OrdersAdminTest (pay form has total + no amount
  input; receipt after), RestaurantToolsetTest (order_pay listed; pays the
  computed total over MCP; bad method as data).

Security: amount is never client-set (structurally — pay() takes no amount); the
payment record carries no PII.

cs-fixer + PHPStan green locally; phpunit runs in CI.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@DanMat
DanMat merged commit c078452 into nimbus-rebuild Sep 5, 2026
4 checks passed
@DanMat
DanMat deleted the slice/payment branch September 5, 2026 23:34
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.

1 participant