Skip to content

feat: add Stripe Terminal SDK integration and on-site POS#54

Merged
JacobCoffee merged 2 commits intomainfrom
phase-18/stripe-terminal-pos
Mar 19, 2026
Merged

feat: add Stripe Terminal SDK integration and on-site POS#54
JacobCoffee merged 2 commits intomainfrom
phase-18/stripe-terminal-pos

Conversation

@JacobCoffee
Copy link
Copy Markdown
Owner

Summary

  • Add TerminalPayment model extending Payment with terminal-specific fields (reader_id, capture_status, card_brand/last4, receipt_url)
  • Add Stripe Terminal SDK methods to StripeClient: connection tokens, reader listing, pre-auth payment intents, reader dispatch, capture/cancel
  • Add 8 JSON API endpoints for the POS flow: connection-token, create-payment-intent, capture, cancel, attendee lookup, inventory, cart operations, reader list
  • Add POS UI template in manage app: three-panel layout with reader connection, attendee lookup, product catalog, cart builder, and full payment flow with Stripe Terminal JS SDK
  • Add TERMINAL payment method to Payment.Method choices
  • 22 tests covering models, API views (with mocked Stripe), and manage views

Design notes

  • Pre-authorization flow: create intent with capture_method=manual → dispatch to reader → cardholder taps → capture after confirmation
  • Supports both order-linked payments and walk-up (amount-based) sales
  • POS UI uses Stripe Terminal JS SDK v1 for reader connection and card collection
  • Permission model matches check-in system (requires change_conference perm)

Test plan

  • 22 new tests pass (tests/test_registration/test_terminal.py)
  • All 1903 tests pass (1 pre-existing flaky test)
  • Lint, format, and type-check pass (make ci)
  • Manual verification with Stripe Terminal simulated reader
  • Verify POS UI renders and connects to reader

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings March 19, 2026 03:32
@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

Comment thread src/django_program/registration/views_terminal.py Fixed
Comment thread src/django_program/registration/views_terminal.py
Comment thread src/django_program/registration/views_terminal.py
Comment thread src/django_program/registration/views_terminal.py
Comment thread src/django_program/registration/views_terminal.py
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a staff-facing Stripe Terminal Point-of-Sale flow to the registration system, including a new terminal payment model, JSON API endpoints for the POS workflow, and a manage UI page for on-site payments.

Changes:

  • Introduces TerminalPayment model and adds TERMINAL to Payment.Method.
  • Adds Stripe Terminal support in StripeClient and new staff-only JSON endpoints (views_terminal.py) + URL wiring.
  • Adds manage UI page (terminal_pos.html) and navigation entry, plus tests covering the new model/endpoints/manage view.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 12 comments.

Show a summary per file
File Description
tests/test_registration/test_terminal.py New tests for terminal model, API endpoints (mocked Stripe), and manage POS view permissions/context.
src/django_program/registration/views_terminal.py Implements staff-only JSON endpoints for connection tokens, intents, capture/cancel, attendee lookup, inventory, cart ops, and reader listing.
src/django_program/registration/views_checkin.py Small refactor/formatting change in JSON parsing helper and a long line wrap.
src/django_program/registration/urls.py Wires up new terminal JSON endpoints under the registration app.
src/django_program/registration/terminal.py Adds TerminalPayment model to store terminal-specific metadata/lifecycle.
src/django_program/registration/stripe_client.py Adds Stripe Terminal wrapper methods (connection token, list readers, create/process intents, cancel action).
src/django_program/registration/models.py Adds TERMINAL payment method choice and exports TerminalPayment.
src/django_program/registration/migrations/0018_alter_payment_method_terminalpayment.py Migration to add Terminal payment method choice and create TerminalPayment table.
src/django_program/registration/admin.py Adds read-only admin for TerminalPayment.
src/django_program/manage/views_terminal.py Adds manage TerminalPOSView rendering the POS template.
src/django_program/manage/urls.py Adds manage route for the terminal POS page.
src/django_program/manage/templates/django_program/manage/terminal_pos.html Adds POS UI (layout + Stripe Terminal JS integration + client-side flow).
src/django_program/manage/templates/django_program/manage/base.html Adds sidebar nav entry for “Terminal POS”.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/django_program/manage/templates/django_program/manage/terminal_pos.html Outdated
Comment thread src/django_program/manage/templates/django_program/manage/terminal_pos.html Outdated
Comment thread src/django_program/registration/views_terminal.py
Comment thread src/django_program/manage/templates/django_program/manage/terminal_pos.html Outdated
Comment thread src/django_program/registration/views_checkin.py
Comment thread src/django_program/registration/views_terminal.py
Comment thread src/django_program/registration/views_terminal.py
Comment thread src/django_program/registration/views_terminal.py Outdated
Comment thread src/django_program/registration/views_terminal.py Outdated
JacobCoffee and others added 2 commits March 19, 2026 08:57
Implements Phase 18: Stripe Terminal for in-person card payments at
the registration desk with pre-authorization capture flow, attendee
lookup, inventory fetching, cart operations, and a full POS UI.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…d validation

- Sanitize Stripe error responses to generic message (no info leak)
- Fix except syntax to tuple form throughout views_terminal.py
- Remove double amount conversion in create_terminal_payment_intent
- Add client_secret to create-intent response
- Add ValueError handler to CancelPaymentView
- Validate quantity as integer in cart operations
- Fix terminal POS UI: attendee/inventory response shapes, price format,
  cart payload keys, chargeCard reader_id, CSRF token seeding
- Extract _add_cart_item helper to reduce complexity

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@JacobCoffee JacobCoffee force-pushed the phase-18/stripe-terminal-pos branch from 0f63d3c to f214bdb Compare March 19, 2026 14:03
try:
client = StripeClient(self.conference)
except ValueError as exc:
return JsonResponse({"error": str(exc)}, status=400)

Check warning

Code scanning / CodeQL

Information exposure through an exception Medium

Stack trace information
flows to this location and may be exposed to an external user.

Copilot Autofix

AI 29 days ago

In general, to fix information exposure through exceptions, you should avoid returning raw exception messages or stack traces to the client. Instead, log the exception (including stack trace) on the server for debugging, and send the client a generic, non-sensitive error message (optionally with a stable error code) so that behavior is preserved without leaking internal details.

Here, the problematic code is in src/django_program/registration/views_terminal.py inside the post method shown, specifically the except ValueError as exc: block at lines 348–351. The fix is to change this block so that it logs the exception (using the already-configured logger in this module) and returns a generic error string. To avoid changing existing functionality more than necessary, we keep the HTTP status code 400 (client error) and still indicate a configuration failure in a generic way, e.g. "Stripe configuration error" or "Unable to initialize Stripe client", while not including str(exc) in the response. We can also include the exception and, optionally, stack information in the log via logger.exception, which uses the existing logger import and definition at the top of the file, so no new imports are needed.

Concretely:

  • Edit the except ValueError as exc: block so that:
    • It calls logger.exception("Failed to initialize Stripe client") (or similar), passing exc for context.
    • It returns JsonResponse({"error": "Unable to initialize Stripe client"}, status=400) (or a similarly generic message).
  • No changes are needed elsewhere in this file for this fix.
Suggested changeset 1
src/django_program/registration/views_terminal.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/django_program/registration/views_terminal.py b/src/django_program/registration/views_terminal.py
--- a/src/django_program/registration/views_terminal.py
+++ b/src/django_program/registration/views_terminal.py
@@ -348,7 +348,8 @@
         try:
             client = StripeClient(self.conference)
         except ValueError as exc:
-            return JsonResponse({"error": str(exc)}, status=400)
+            logger.exception("Failed to initialize Stripe client", exc_info=exc)
+            return JsonResponse({"error": "Unable to initialize Stripe client"}, status=400)
 
         try:
             if reader_id:
EOF
@@ -348,7 +348,8 @@
try:
client = StripeClient(self.conference)
except ValueError as exc:
return JsonResponse({"error": str(exc)}, status=400)
logger.exception("Failed to initialize Stripe client", exc_info=exc)
return JsonResponse({"error": "Unable to initialize Stripe client"}, status=400)

try:
if reader_id:
Copilot is powered by AI and may make mistakes. Always verify output.
@JacobCoffee JacobCoffee merged commit e70573e into main Mar 19, 2026
11 of 13 checks passed
@JacobCoffee JacobCoffee deleted the phase-18/stripe-terminal-pos branch March 19, 2026 15:52
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.

3 participants