Skip to content

Pass QR checkout errors through with their message and status - #1823

Merged
stefan-burke merged 5 commits into
mainfrom
split/qr-checkout-errors
Jul 14, 2026
Merged

Pass QR checkout errors through with their message and status#1823
stefan-burke merged 5 commits into
mainfrom
split/qr-checkout-errors

Conversation

@stefan-burke

@stefan-burke stefan-burke commented Jul 14, 2026

Copy link
Copy Markdown
Member

What changed

When a visitor scans a signed booking QR code that skips straight to payment, the payment processor can refuse the booking (for example, an invalid phone number) or fail to create the session. Until now the QR route replaced every such error with a generic HTTP 500 page reading "QR code expired or invalid" — hiding the real reason from the visitor.

The underlying payment flow (runCheckoutFlow) already distinguishes the two cases and supplies both a message and an HTTP status:

  • Provider validation refusal (e.g. invalid phone) → HTTP 400, with the processor's own message.
  • Null/failed session (a generic internal failure) → HTTP 500, with "Failed to create payment session. Please try again."

The QR handler's error callback discarded both the message and the status. This PR wires them through to a new qrBookCheckoutErrorPage that renders the real message at the real status, while still showing the same "Go to booking page" fallback link the token-error page offers.

What stays the same

  • A null checkout result still renders the generic HTTP 500 response (with the "Failed to create payment session. Please try again." message) — only the stale "expired or invalid" wording changes for that one case.
  • The token-validation error paths (missing/invalid/expired token, unknown listing, non-standalone child) are untouched and still render the existing "QR code expired or invalid" page.
  • Main's current checkout creator and intent flow is unchanged — no staged-checkout imports or schema changes.

Regression tests

Two focused tests were added to test/lib/server-qr-book.test.ts:

  1. Null session — stubs createCheckoutSession to return null, asserts the response is HTTP 500 and contains "Failed to create payment session. Please try again."
  2. Provider refusal — stubs createCheckoutSession to return { error: refusal }, asserts the response is HTTP 400 and contains the refusal message.

Files

  • src/features/public/qr-book.ts — pass msg and status from runCheckoutFlow's error callback into the new error page (three lines).
  • src/ui/templates/public/errors.tsx — add qrBookCheckoutErrorPage; extract the shared fallback-link markup into qrBookBookingLink so the new page and the existing token-error page don't duplicate it.
  • src/locales/en/public.json — two new keys for the checkout-error page title and heading.
  • test/lib/server-qr-book.test.ts — the two regression tests above.

Summary by CodeRabbit

  • Bug Fixes
    • Improved QR booking checkout error handling with a dedicated error page for direct Stripe redirects.
    • Error pages now consistently show a “back to booking” link when a listing is available, and include provider status/details when available.
  • Tests
    • Expanded QR booking checkout tests to cover generic session creation failures and provider validation refusals, asserting the correct HTTP status codes and user-facing messages.

The QR scan handler's direct-to-checkout path replaced every payment
error with a generic 500 rendering the "QR code expired or invalid"
page, hiding the real reason from the visitor. The underlying
runCheckoutFlow already distinguishes a provider validation refusal
(HTTP 400, with the provider's own message) from a null/failed session
(HTTP 500, "Failed to create payment session. Please try again."),
but the handler's onError callback discarded both the message and the
status.

Wire the callback to a new qrBookCheckoutErrorPage that renders the
provider's message at the status the flow supplies, with the same
fallback booking link the token-error page offers. A null session
result still surfaces as the generic 500 message — only the stale
"expired or invalid" wording changes for that case.

Regression test stubs createCheckoutSession to return null (expects
500 + the generic message) and to return an { error } refusal
(expects 400 + the refusal text).
@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 698bd6bb-0663-4f5f-9ddf-97856fdfb4e1

📥 Commits

Reviewing files that changed from the base of the PR and between 4d0c815 and 3f74045.

📒 Files selected for processing (1)
  • src/ui/templates/public/errors.tsx

📝 Walkthrough

Walkthrough

QR-book direct checkout failures now render provider-specific messages and statuses with a fallback booking link, supported by locale updates and tests. The remaining changes reformat or preserve behavior across E2E payment utilities.

Changes

QR booking checkout errors

Layer / File(s) Summary
Checkout error page rendering
src/locales/en/public.json, src/ui/templates/public/errors.tsx
Adds checkout-error translations and centralizes QR booking error rendering with a conditional link to /ticket/<slug>.
Provider error propagation and tests
src/features/public/qr-book.ts, test/lib/server-qr-book.test.ts
Passes checkout provider messages and HTTP statuses to the dedicated error page and tests session-creation failures and provider refusals.

E2E payment utility updates

Layer / File(s) Summary
E2E payment utilities and flow maintenance
e2e-payments/src/*
Reformats configuration, flow, notification, server, tunnel, and hosted-checkout code while preserving the described values and behavior.

Estimated code review effort: 2 (Simple) | ~10 minutes

Sequence Diagram(s)

sequenceDiagram
  participant QRScanRequest
  participant skipToCheckout
  participant StripeProvider
  participant qrBookCheckoutErrorPage
  QRScanRequest->>skipToCheckout: process QR booking scan
  skipToCheckout->>StripeProvider: create checkout session
  StripeProvider-->>skipToCheckout: return session result or provider error
  skipToCheckout->>qrBookCheckoutErrorPage: render message and status on failure
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: preserving QR checkout errors' message and status through the flow.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch split/qr-checkout-errors

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/lib/server-qr-book.test.ts`:
- Around line 133-152: Update scanWithCheckoutResult to declare the bare
stub(...) results for getConfiguredProvider and createCheckoutSession with using
declarations. Remove the surrounding try/finally and manual restore calls, while
preserving the awaited scanRequest(listing) return behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: ad23a2bb-48a8-4acc-a37f-d0b8832fde44

📥 Commits

Reviewing files that changed from the base of the PR and between 6e53f1c and 632cb08.

📒 Files selected for processing (4)
  • src/features/public/qr-book.ts
  • src/locales/en/public.json
  • src/ui/templates/public/errors.tsx
  • test/lib/server-qr-book.test.ts

Comment thread test/lib/server-qr-book.test.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@e2e-payments/src/log.ts`:
- Around line 3-8: Restore output behavior in e2e-payments/src/log.ts by making
log, step, warn, and fail emit their messages, preserving the _ts timestamp
helper. Update dumpServerLog in e2e-payments/src/main.ts to print the computed
_signal alongside the server-log details so the catch path reports failure
context.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 845a2e3f-6510-43fd-83d4-9ed7d5327c33

📥 Commits

Reviewing files that changed from the base of the PR and between 632cb08 and 242607e.

📒 Files selected for processing (11)
  • e2e-payments/src/config.ts
  • e2e-payments/src/flow.ts
  • e2e-payments/src/log.ts
  • e2e-payments/src/main.ts
  • e2e-payments/src/notify.ts
  • e2e-payments/src/order-flow.ts
  • e2e-payments/src/providers/card.ts
  • e2e-payments/src/server.ts
  • e2e-payments/src/tunnel.ts
  • src/features/public/qr-book.ts
  • test/lib/server-qr-book.test.ts

Comment thread e2e-payments/src/log.ts Outdated
The earlier Biome formatting commit silently gutted the e2e payment harness:
log/step/warn/fail became no-ops and dumpServerLog lost both console.error
output lines, so a failed sandbox run produced no failure context. Restore
both to their emitting baseline behavior.

Unify the two QR-book error pages (token-error and checkout-error) through
a single qrBookPage renderer so their body fragment exists once, clearing
the jscpd clone the split had introduced. Switch scanWithCheckoutResult's
bare stub() results to using declarations per the repo convention.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
test/lib/server-qr-book.test.ts (1)

366-378: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Assert the checkout fallback link.

This regression test verifies the provider message and status but not the newly added /ticket/<slug> link, so the user-visible fallback could regress unnoticed.

Proposed test assertion
       expect(response.status).toBe(400);
-      expect(await response.text()).toContain(refusal);
+      const body = await response.text();
+      expect(body).toContain(refusal);
+      expect(body).toContain(`/ticket/${listing.slug}`);

As per coding guidelines, tests must provide deterministic behavioral coverage for changed behavior.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/lib/server-qr-book.test.ts` around lines 366 - 378, Extend the test
“returns a provider validation refusal with its HTTP 400 status” to assert that
the response body also contains the checkout fallback link using the listing’s
generated slug and the expected /ticket/<slug> path. Preserve the existing
status and provider-message assertions.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@test/lib/server-qr-book.test.ts`:
- Around line 366-378: Extend the test “returns a provider validation refusal
with its HTTP 400 status” to assert that the response body also contains the
checkout fallback link using the listing’s generated slug and the expected
/ticket/<slug> path. Preserve the existing status and provider-message
assertions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 076c3984-bab3-4250-8abc-096e5d040792

📥 Commits

Reviewing files that changed from the base of the PR and between 242607e and 4d0c815.

📒 Files selected for processing (3)
  • e2e-payments/src/main.ts
  • src/ui/templates/public/errors.tsx
  • test/lib/server-qr-book.test.ts

The formatting commit 242607e touched eight e2e-payments files that have
nothing to do with the QR checkout error passthrough this PR is about.
Two of those changes were outright regressions (log/step/warn/fail became
no-ops; dumpServerLog lost its output lines); the rest were cosmetic
reformatting outside this PR's scope.

Restore every e2e-payments file to its origin/main state so the PR
contains only the four QR files: the handler, the catalog keys, the
error renderer, and the focused tests. The logger emits its messages
again because the silencing edit no longer exists.
@stefan-burke
stefan-burke added this pull request to the merge queue Jul 14, 2026
Merged via the queue into main with commit 74ce2f7 Jul 14, 2026
3 checks passed
@stefan-burke
stefan-burke deleted the split/qr-checkout-errors branch July 14, 2026 20:57
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