Files
unsupervised-scheduler/docs/features/payments.md
T
thatguygriff d3a2767976
CI / Coding Standards (push) Successful in 2m23s
CI / PHPStan (push) Successful in 59s
CI / Tests (PHP 8.1) (push) Successful in 50s
CI / Tests (PHP 8.2) (push) Successful in 51s
CI / Tests (PHP 8.3) (push) Successful in 48s
CI / No Debug Code (push) Successful in 3s
Add feature specs for booking platform requirements
Update availability, lesson-booking, and user-roles docs and add specs
for offerings, group classes, registration questions, versioned policies,
Stripe payments (with e-transfer/comp overrides and receipts), and
monthly per-instructor payment reporting. Tracked in issues #1-#9.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 09:58:50 -03:00

5.1 KiB

Feature: Payments

Overview

Payment is taken at registration. The default rail is a credit card charged through Stripe, but the studio admin can set any student to pay by e-transfer (recorded, marked paid manually) or to be comped (no charge). Single bookings are charged once; weekly reservations and group classes are charged the full term upfront. A numbered receipt is emailed automatically when a payment is marked paid.

Stripe Configuration

Stripe credentials live in WordPress options, managed on the Studio Settings page (manage_billing, studio admin only):

Option Notes
us_stripe_publishable_key Stripe publishable key
us_stripe_secret_key Stripe secret key
us_stripe_mode test or live
us_currency Default ISO 4217 currency, e.g. CAD

Per-Student Billing Method

Each student's billing method is stored in user meta us_payment_method, set by the studio admin (default card):

Method Behaviour
card Charged immediately via Stripe; payment paid on success
etransfer Payment row created pending; admin marks it paid when funds arrive
comp No charge; registration is confirmed immediately, no payment row required

Data Model — {prefix}us_payments

Column Type Notes
id BIGINT UNSIGNED Primary key
student_id BIGINT UNSIGNED WordPress user ID
instructor_id BIGINT UNSIGNED WordPress user ID (denormalised for reporting)
registration_type VARCHAR(20) lesson or enrollment
registration_id BIGINT UNSIGNED FK → us_lessons.id or us_group_enrollments.id
amount_cents INT UNSIGNED Charged amount in the smallest currency unit
currency VARCHAR(3) ISO 4217, e.g. CAD
method VARCHAR(20) card / etransfer / comp
status VARCHAR(20) pending / paid / failed / refunded
stripe_payment_intent_id VARCHAR(255) Stripe PaymentIntent id; NULL for e-transfer / comp
receipt_number VARCHAR(50) Sequential receipt id; set when paid
receipt_sent_at DATETIME When the receipt email was sent; NULL until sent
created_at DATETIME Insertion time
paid_at DATETIME When marked paid; NULL otherwise

Payment Flow

  1. During registration the front-end calls POST /payments/intent, which creates a Stripe PaymentIntent for a card student and returns the client secret. (etransfer returns a pending payment; comp returns none.)
  2. The browser confirms the card payment with Stripe.
  3. Stripe calls POST /payments/webhook; on payment_intent.succeeded the payment is marked paid, paid_at is stamped, and the linked lesson/enrolment is confirmed.
  4. On transition to paid, ReceiptMailer assigns a receipt_number, emails the student a receipt, and stamps receipt_sent_at.
  5. For an e-transfer, the studio admin later calls PATCH /payments/{id} to mark it paid, which triggers the same confirmation + receipt.

REST API

Method Endpoint Permission
POST /wp-json/us-scheduler/v1/payments/intent book_lesson
POST /wp-json/us-scheduler/v1/payments/webhook Public (Stripe signature verified)
PATCH /wp-json/us-scheduler/v1/payments/{id} manage_billing

See payment-reporting.md for the monthly report and CSV export endpoints.

Implementation

  • Repository: Unsupervised\Schedular\Payment\PaymentRepository
  • Model: Unsupervised\Schedular\Payment\Payment
  • Stripe gateway: Unsupervised\Schedular\Payment\StripeGateway
  • Receipts: Unsupervised\Schedular\Payment\ReceiptMailer
  • Settings page: Unsupervised\Schedular\Payment\StudioSettings
  • REST endpoint: Unsupervised\Schedular\Payment\PaymentEndpoint

Tests

  • tests/Unit/Payment/PaymentRepositoryTest.php
  • tests/Unit/Payment/PaymentTest.php
  • tests/Unit/Payment/StripeGatewayTest.php
  • tests/Unit/Payment/ReceiptMailerTest.php