PayFast provider, Pay online page, amount checks on payments

- PayFast (custom integration): signed form (PHP-style encoding, checked
  against a real sandbox), ITN checks (signature over all posted fields,
  PayFast host, VALID from /eng/query/validate, amount vs checkout).
- ProviderCheckout records every checkout (amount, metadata, request);
  webhooks match payments to it and hold a different amount for review
  (ProviderTransaction.note).
- /pay/<id>: payers choose a provider when several are on, and the
  browser posts PayFast's form from there, so payment links work for
  every provider.
- Site settings → Payments: PayFast card (merchant ID/key, encrypted
  passphrase, sandbox/live) while PayFast is enabled.
- Payer-facing wording no longer names Yoco; legal pages name both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-23 14:25:49 +02:00
co-authored by Claude Opus 5.5
parent 25e3e9d3a6
commit f2b51dbd88
42 changed files with 1220 additions and 109 deletions
+6
View File
@@ -53,6 +53,12 @@ features is in [FEATURES-ROUND-1.md](./FEATURES-ROUND-1.md).
## Tests
- Backend unit tests: `cd backend && npm test` (Jest).
- PayFast e2e (`e2e/payfast.spec.ts`) pays into a real PayFast sandbox account and is skipped
unless `E2E_PAYFAST_MERCHANT_ID`, `E2E_PAYFAST_MERCHANT_KEY` and `E2E_PAYFAST_PASSPHRASE` are
set (from the Sandbox dashboard). PayFast's documented public test merchant (10000100) no
longer accepts payments. ITNs can't reach localhost; they're covered by unit tests
(`backend/tests/payments.test.js`) — to try one for real, use a tunnel, a public
`BACKEND_URL` and `PAYFAST_SKIP_IP_CHECK=true`.
- End-to-end: `npm run test:e2e` from the repo root (first time: `npm install` and
`npx playwright install chromium`). They start their own backend (5100) and
frontend (3100) against `<your DATABASE_URL database>_e2e`, which is dropped and