| Test | Result | Date |
|---|---|---|
| Manual payment recording (Cash £80) | Transaction created, status → COMPLETED, appointment → PAID |
9 Jun 2026 |
| Payment history display on appointment detail | Table shows Date, Amount, Method, Reference, Paid By, Recorded By | 9 Jun 2026 |
| Stripe checkout page renders | Card form with Stripe Elements, amount display, Pay button | 9 Jun 2026 |
| Stripe PaymentIntent creation | POST /appointments/<pk>/create-payment-intent/ returns client_secret |
9 Jun 2026 |
Online payment with test card 4242 4242 4242 4242 |
Payment processed, redirect to detail with ?payment=success |
9 Jun 2026 |
| Webhook endpoint — valid signature | POST /webhooks/stripe/ → 200 OK |
9 Jun 2026 |
| Webhook endpoint — invalid signature | → 400 Bad Request | 9 Jun 2026 |
Webhook payment_intent.succeeded handler |
Transaction → COMPLETED, stripe_reference populated, appointment → PAID |
9 Jun 2026 |
Webhook payment_intent.payment_failed handler |
Transaction → FAILED |
9 Jun 2026 |
| Stripe refund via admin action | Stripe refund created, transaction → REFUNDED, appointment → PENDING |
9 Jun 2026 |
| Invoice creation | INV-2026-NNNNN auto-generated, line items created |
9 Jun 2026 |
| Invoice PDF download | A4 PDF renders with practice name, line items, totals | 9 Jun 2026 |
| Invoice email sending | Email queued in MailHog with PDF attachment | 9 Jun 2026 |
| RBAC — receptionist can record payments | ✅ | 9 Jun 2026 |
RBAC — receptionist cannot access /partner/ |
Returns permission denied | 9 Jun 2026 |
| Migration deployment | All 20 migrations applied to sector_gp (production dsp_clinic database) |
9 Jun 2026 |
Template edge case — missing {% if %} tag |
Fixed and tested | 9 Jun 2026 |
| OIDC role override issue | Fixed — update_user() no longer overwrites existing roles |
9 Jun 2026 |
| # | Item | Priority | Notes |
|---|---|---|---|
| 1 | Deploy with live Stripe keys | 🔴 High | Replace pk_test_... / sk_test_... with live keys in PaymentConfig |
| 2 | Configure Stripe webhook in production | 🔴 High | Add endpoint in Stripe Dashboard → Webhooks. Point to https://gp.veripath.co.uk/webhooks/stripe/ |
| 3 | Set webhook signing secret | 🔴 High | Copy whsec_live_... into PaymentConfig after webhook is created |
| 4 | Verify webhook reaches container | 🟡 Medium | Check nginx/firewall allows Stripe's IPs to reach the webhook endpoint |
| 5 | Stripe Connect onboarding | 🟡 Medium | If using Stripe Connect (each practice has own account), complete the Connect onboarding flow |
| 6 | Deploy with production env | 🔴 High | Rebuild Docker image with env.production (rather than patching env.dev). Currently running with manual patches. See below. |
| # | Item | Priority | Details |
|---|---|---|---|
| 7 | Rebuild Docker image with deps | 🟡 Medium | WeasyPrint system libs (libglib2.0-0, libpango-1.0-0, libpangocairo-1.0-0, libcairo2, libgirepository-1.0-1) were installed manually via apt-get. Must be baked into the Dockerfile's RUN apt-get install |
| 8 | sector_client DB definition | 🟡 Medium | sector_client was missing from DATABASES in settings.py. Added. Ensure env.production has CLIENT_DB_NAME=... |
| 9 | ALLOWED_HOSTS | 🟡 Medium | test-client.gp.veripath.co.uk added via env override. Add to env.production permanently. |
| 10 | Migration graph fix | 🟡 Medium | Several placeholder migrations were created to fix the broken migration graph across partner, clinical_data, and appointments apps. These should be squashed or cleaned up before production. |
| # | Item | Priority | Notes |
|---|---|---|---|
| 11 | Invoice overdue tracking | 🟢 Low | Scheduled task to mark invoices as OVERDUE after due_date passes |
| 12 | Invoice reminders | 🟢 Low | Auto-email reminders for overdue invoices |
| 13 | Refund via UI | 🟢 Low | Currently admin-only. Add staff-facing refund view |
| 14 | Payment dashboard | 🟢 Low | Aggregated view of all payments by practice, date range, method |
| 15 | Partial refunds | 🟢 Low | Allow refunding part of a payment |
| 16 | UI polish | 🟢 Low | Payment history table styling, date format, reference display |
paid_at date correctly when null (cosmetic)