fix: restart-loop-A findings — pending sweep refunds, tip carve on discounts, TOCTOU redemption, single-use 2FA code + mint endpoint, refresh-token family revocation, admin 2FA code UX
Restart of Loop A (fresh review -> fix -> verify) findings from commit 5e967fa: - B1: sweep auto-refund treats Square PENDING refunds as NON-terminal (row stays pending, no gift-card clawback, refunds row inserted for payments AND till_sales, re-polls the deterministic sweepdup- key); Square-less pre-pass exempts square_refund_id IS NOT NULL rows - M4: terminal tip carve accounts for pending campaign discounts (headroom = total - pending - paid) so explicit tips aren't absorbed as service revenue; no-tip case stays a single record - max_redemptions TOCTOU closed with atomic conditional UPDATE ... RETURNING; exhausted-at-apply surfaces campaign_fully_redeemed - 2FA: verification code is single-use on the saved-card gate (VerifyForUser consume=true, interactive flows unaffected); new POST /api/user/2fa/code mints a fresh code for enabled users (RequireAuth + RequireNonGuest + mint cooldown + per-user limiter) - Refresh tokens: family_id + used_at columns; reuse of an already-rotated token revokes the ENTIRE family and inserts a refresh_token_reuse admin alert; rotation mints descendants in the same family - Frontend: 2FA code input + Request-a-new-code on all saved-card surfaces; admin modal keys code input to customer 2FA + 403 self-heal; tip-display note for pending discounts; 76 frontend tests - Verified: all 26 backend packages pass, frontend build+tests green, env-docs 41/41
This commit is contained in:
@@ -68,13 +68,12 @@ func TestTerminalCash_ClampsToRemainingObligation(t *testing.T) {
|
||||
assert.InDelta(t, 20.00, clamped, 0.001, "the cash payment must be clamped to the £20 remaining obligation")
|
||||
}
|
||||
|
||||
// TestTerminalCash_FullyPaid_RecordsVerbatim locks the fully-paid edge of
|
||||
// B3(a): when the booking has no remaining obligation, a cash payment is
|
||||
// recorded VERBATIM (a deliberate admin overpayment is real money received and
|
||||
// must stay on the ledger — the app's "overpayment handled at the counter"
|
||||
// semantics). The clamp only protects the common B3 case where prior payments
|
||||
// left a positive remaining obligation.
|
||||
func TestTerminalCash_FullyPaid_RecordsVerbatim(t *testing.T) {
|
||||
// TestTerminalCash_FullyPaid_RejectsOvercharge locks the fully-paid edge of
|
||||
// B3(a): when the booking has no remaining obligation, a no-tip charge is
|
||||
// rejected with 400 — recording the requested amount verbatim would overcharge
|
||||
// a customer who already paid in full (overpayment is handled manually at the
|
||||
// counter, not minted into the ledger).
|
||||
func TestTerminalCash_FullyPaid_RejectsOvercharge(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx, tx := testutils.SetupTestTx(t)
|
||||
|
||||
@@ -89,13 +88,11 @@ func TestTerminalCash_FullyPaid_RecordsVerbatim(t *testing.T) {
|
||||
PaymentMethod: strPtr("cash"),
|
||||
}
|
||||
w := makePaymentRequest(handler, "POST", "/api/admin/bookings/"+bookingID+"/payment", req, adminToken, ctx)
|
||||
require.Equal(t, http.StatusOK, w.Code, "a fully-paid booking must still record the admin's deliberate overpayment, body: %s", w.Body.String())
|
||||
require.Equal(t, http.StatusBadRequest, w.Code, "a charge on a fully-paid booking must be rejected, body: %s", w.Body.String())
|
||||
|
||||
var resp CheckoutResponse
|
||||
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp), "cash response must carry the payment id")
|
||||
var lastCash float64
|
||||
require.NoError(t, tx.QueryRow(ctx, `SELECT amount FROM payments WHERE id = $1`, resp.CheckoutID).Scan(&lastCash))
|
||||
assert.InDelta(t, 45.00, lastCash, 0.001, "the fully-paid cash receipt must be recorded verbatim")
|
||||
var payCount int
|
||||
require.NoError(t, tx.QueryRow(ctx, `SELECT COUNT(*) FROM payments WHERE booking_id = $1 AND payment_method = 'cash'`, bookingID).Scan(&payCount))
|
||||
assert.Equal(t, 1, payCount, "only the £50 prior payment may exist — the overcharge must not be recorded")
|
||||
}
|
||||
|
||||
// TestTerminalSavedCard_ClampsToRemainingObligation locks B3(a) for the
|
||||
|
||||
Reference in New Issue
Block a user