The partner-facing Stripe configuration UI has been fully implemented. All items in the original plan are now live.
/partner/stripe-config/)A full form at /partner/stripe-config/ allowing partner admins to manage Stripe keys:
| Field | Type | Notes |
|---|---|---|
| Is active | Checkbox | Enable/disable Stripe payments |
| Default currency | Select (GBP, EUR, USD) | Defaults to GBP |
| Stripe publishable key | Text input | Shown in plaintext |
| Stripe secret key | Password input | Encrypted at rest, never echoed back |
| Stripe webhook secret | Password input | Encrypted, same security as secret key |
| Stripe Connect account ID | Text input (optional) | For future Connect integration |
Security:
EncryptedTextFieldAccessible to roles: ORG_ADMIN, PARTNER_REGISTERED_MANAGER, PARTNER_ADMIN, ADMIN
POSTs the secret key to /partner/stripe-config/test-connection/, calls stripe.Balance.retrieve(). On success: account name, email, country, balance.
Creates a Stripe webhook endpoint at https://{subdomain}.gp.veripath.co.uk/webhooks/stripe/ for events payment_intent.succeeded and payment_intent.payment_failed.
View at /partner/stripe-transactions/ — paginated table of PaymentTransaction records (date, patient, invoice, amount, status, Stripe ID) with filters.
Patients can pay invoices at patient.veripath.co.uk. API endpoints:
| Endpoint | Purpose |
|---|---|
GET /api/patient/invoices/ |
List SENT + PAID invoices |
GET /api/patient/invoices/{id}/ |
Invoice with line items |
POST /api/patient/invoices/{id}/pay/ |
Creates PaymentIntent, returns client_secret |
GET /api/patient/dashboard/ |
Includes unpaid_invoices array |
receipt_email field| File | Status |
|---|---|
partner/forms.py — PartnerStripeConfigForm |
✅ Done |
partner/views.py — 4 views (Config, Test, Webhook, Transactions) |
✅ Done |
partner/urls.py — 4 routes |
✅ Done |
partner/templates/partner/stripe_config_form.html |
✅ Done |
partner/templates/partner/stripe_transactions.html |
✅ Done |
partner/templates/partner/dashboard.html — nav links |
✅ Done |
patient_portal/serializers.py — PatientInvoiceSerializer |
✅ Done |
patient_portal/views.py — PatientInvoiceViewSet + pay action |
✅ Done |
patient_portal/urls.py — invoice routes |
✅ Done |
PWA frontend: InvoicesView.vue, InvoiceDetailView.vue, router, nav |
✅ Done |
insurance_billing/webhooks.py — shortfall webhook URL |
✅ Done |
dsp_clinic/urls.py — shortfall webhook route |
✅ Done |
The Practice model uses org_id (CharField) to link to PartnerOrg (partner_org.slug). The Stripe config view finds practices by matching Practice.org_id to PartnerOrg.slug.
org_id=None), primary VPS staff must set org_id