Student detail: history sections and admin actions (cancel, withdraw, edit account) #75

Merged
thatguygriff merged 2 commits from feature/student-detail-history into main 2026-07-18 21:28:53 +00:00
Owner

Closes #69
Closes #70

What & why

The student-administration spec deferred three detail-view sections until Payments landed, and shipped the view read-only. This PR completes both follow-ups on Students → student detail (manage_students).

History sections (#69)

  • Policy acceptances — newest first: policy title, version (v3), context (Account signup / Lesson #n / Enrolment #n), and acceptance date. Falls back gracefully (#id / ) if a version or policy was deleted.
  • Intake answers — question label, answer, and the registration it was given for.
  • Payment history — gated on manage_billing (matching the billing-method section): date, context, method, status, subtotal, HST, total + currency, receipt number.

Admin actions (#70)

  • Edit account — display name + email form in the Account section, with validation (valid email, not owned by another user) and success/error notices.
  • Cancel lesson — per-row button on non-cancelled upcoming lessons, with a JS confirm. Same semantics as student-initiated cancellation: lesson cancelled, slot freed for rebooking, still-pending payment voided; paid lessons keep their payment (refunds stay manual — #72).
  • Withdraw — per-row button on active group-class enrolments: enrolment cancelled (capacity seat freed), pending payment voided.

How

  • New per-student queries: AcceptanceRepository::findByStudent, AnswerRepository::findByStudent, PaymentRepository::findByStudent (all newest-first).
  • New Auth\StudentHistory builds the history display rows and resolves policy/version titles and question labels; new Auth\StudentActions holds the mutation logic (both mockable units in the spirit of StudentSchedule, since controllers aren't unit-tested here). Cancel/withdraw refuse records that don't belong to the student being viewed.
  • The controller routes nonce-protected POSTs (usc_action read for routing only; each branch calls check_admin_referer) — restructured so the existing billing form's nonce no longer wp_dies other forms on the page.
  • The Payment model now maps created_at (appended as a named-arg-only constructor parameter, so no call sites change), giving unpaid e-transfer rows a date in the history.
  • Wired through AdminMenu (now also takes AnswerRepository + AcceptanceRepository) and Plugin.

Tests

  • New tests/Unit/Auth/StudentHistoryTest.php — row building for all three sections plus missing-version/missing-question/undated fallbacks.
  • New tests/Unit/Auth/StudentActionsTest.php — cancel/withdraw side effects (status, slot release, payment voiding) and guards (wrong student, already cancelled, missing), account validation (empty name, invalid/taken email, WP_Error pass-through).
  • findByStudent coverage added to the three repository test suites; created_at mapping asserted in PaymentTest.
  • composer test — 387 tests, 1119 assertions, all passing
  • composer lint — PHPStan clean
  • composer cs — PHPCS clean

As with prior features, no local WP runtime exists in this repo (tests stub WP via Brain\Monkey); worth a manual smoke on staging: open a student who has booked and paid — confirm the three history sections render, cancel an upcoming lesson and check the slot is rebookable and the pending payment left the confirmation queue, withdraw an enrolment, edit the account email, and view the page as a non-billing admin to confirm the payment section is hidden.

Docs updated: docs/features/student-administration.md.

🤖 Generated with Claude Code

Closes #69 Closes #70 ## What & why The student-administration spec deferred three detail-view sections until Payments landed, and shipped the view read-only. This PR completes both follow-ups on **Students → student detail** (`manage_students`). ### History sections (#69) - **Policy acceptances** — newest first: policy title, version (`v3`), context (Account signup / Lesson #n / Enrolment #n), and acceptance date. Falls back gracefully (`#id` / `—`) if a version or policy was deleted. - **Intake answers** — question label, answer, and the registration it was given for. - **Payment history** — gated on `manage_billing` (matching the billing-method section): date, context, method, status, subtotal, HST, total + currency, receipt number. ### Admin actions (#70) - **Edit account** — display name + email form in the Account section, with validation (valid email, not owned by another user) and success/error notices. - **Cancel lesson** — per-row button on non-cancelled upcoming lessons, with a JS confirm. Same semantics as student-initiated cancellation: lesson `cancelled`, slot freed for rebooking, still-pending payment voided; paid lessons keep their payment (refunds stay manual — #72). - **Withdraw** — per-row button on active group-class enrolments: enrolment `cancelled` (capacity seat freed), pending payment voided. ## How - New per-student queries: `AcceptanceRepository::findByStudent`, `AnswerRepository::findByStudent`, `PaymentRepository::findByStudent` (all newest-first). - New `Auth\StudentHistory` builds the history display rows and resolves policy/version titles and question labels; new `Auth\StudentActions` holds the mutation logic (both mockable units in the spirit of `StudentSchedule`, since controllers aren't unit-tested here). Cancel/withdraw refuse records that don't belong to the student being viewed. - The controller routes nonce-protected POSTs (`usc_action` read for routing only; each branch calls `check_admin_referer`) — restructured so the existing billing form's nonce no longer `wp_die`s other forms on the page. - The `Payment` model now maps `created_at` (appended as a named-arg-only constructor parameter, so no call sites change), giving unpaid e-transfer rows a date in the history. - Wired through `AdminMenu` (now also takes `AnswerRepository` + `AcceptanceRepository`) and `Plugin`. ## Tests - New `tests/Unit/Auth/StudentHistoryTest.php` — row building for all three sections plus missing-version/missing-question/undated fallbacks. - New `tests/Unit/Auth/StudentActionsTest.php` — cancel/withdraw side effects (status, slot release, payment voiding) and guards (wrong student, already cancelled, missing), account validation (empty name, invalid/taken email, `WP_Error` pass-through). - `findByStudent` coverage added to the three repository test suites; `created_at` mapping asserted in `PaymentTest`. - `composer test` — 387 tests, 1119 assertions, all passing - `composer lint` — PHPStan clean - `composer cs` — PHPCS clean > As with prior features, no local WP runtime exists in this repo (tests stub WP via Brain\Monkey); worth a manual smoke on staging: open a student who has booked and paid — confirm the three history sections render, cancel an upcoming lesson and check the slot is rebookable and the pending payment left the confirmation queue, withdraw an enrolment, edit the account email, and view the page as a non-billing admin to confirm the payment section is hidden. Docs updated: `docs/features/student-administration.md`. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
thatguygriff added 1 commit 2026-07-18 21:17:47 +00:00
Add policy, intake, and payment history to the admin student detail view
CI / Coding Standards (pull_request) Successful in 2m47s
CI / PHPStan (pull_request) Successful in 2m56s
CI / Tests (PHP 8.3) (pull_request) Successful in 2m39s
CI / Build Plugin Zip (pull_request) Skipped
CI / Tests (PHP 8.2) (pull_request) Successful in 43s
CI / Tests (PHP 8.1) (pull_request) Successful in 44s
CI / No Debug Code (pull_request) Successful in 2s
c49171695a
The student-administration spec deferred three detail-view sections until
Payments landed. Adds them now: policy-acceptance history (title, version,
context, date), intake answers (label, answer, context), and — gated on
manage_billing — payment history with HST breakdown and receipt numbers.

New Auth\StudentHistory builds the display rows from per-student queries
added to AcceptanceRepository, AnswerRepository, and PaymentRepository;
the Payment model now carries created_at so unpaid rows still have a date.

Closes #69

Co-Authored-By: Claude Fable 5 <[email protected]>
thatguygriff added 1 commit 2026-07-18 21:25:16 +00:00
Add admin actions to the student detail view: cancel, withdraw, edit account
CI / Tests (PHP 8.2) (pull_request) Successful in 43s
CI / No Debug Code (pull_request) Successful in 2s
CI / Tests (PHP 8.3) (pull_request) Successful in 2m37s
CI / Tests (PHP 8.1) (pull_request) Successful in 44s
CI / Coding Standards (pull_request) Successful in 2m43s
CI / PHPStan (pull_request) Successful in 2m50s
CI / Build Plugin Zip (pull_request) Skipped
5808523140
Adds the #70 follow-up onto the student detail page: studio admins can now
cancel an upcoming lesson (same path as student cancellation — slot freed,
pending payment voided), withdraw an active group-class enrolment (seat
freed, pending payment voided), and edit the student's display name and
email with validation and uniqueness checks.

Action logic lives in the new Auth\StudentActions (unit-tested with mocked
repositories); the controller routes nonce-protected POSTs to it and shows
success/error notices.

Closes #70

Co-Authored-By: Claude Fable 5 <[email protected]>
thatguygriff changed title from Add policy, intake, and payment history to the admin student detail view to Student detail: history sections and admin actions (cancel, withdraw, edit account) 2026-07-18 21:25:39 +00:00
thatguygriff merged commit caa402778d into main 2026-07-18 21:28:53 +00:00
thatguygriff deleted branch feature/student-detail-history 2026-07-18 21:28:54 +00:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Unsupervised/unsupervised-scheduler#75