Add group-class enrolment deadline with instructor late-enrolment override
CI / Tests (PHP 8.1) (pull_request) Successful in 48s
CI / Tests (PHP 8.2) (pull_request) Successful in 47s
CI / No Debug Code (pull_request) Successful in 3s
CI / PHPStan (pull_request) Successful in 2m51s
CI / Coding Standards (pull_request) Successful in 3m2s
CI / Tests (PHP 8.3) (pull_request) Successful in 2m37s
CI / Build Plugin Zip (pull_request) Skipped
CI / Tests (PHP 8.1) (pull_request) Successful in 48s
CI / Tests (PHP 8.2) (pull_request) Successful in 47s
CI / No Debug Code (pull_request) Successful in 3s
CI / PHPStan (pull_request) Successful in 2m51s
CI / Coding Standards (pull_request) Successful in 3m2s
CI / Tests (PHP 8.3) (pull_request) Successful in 2m37s
CI / Build Plugin Zip (pull_request) Skipped
Group classes gain an instructor-set enrolment deadline (new us_offerings.enrollment_deadline column) that defaults to the first day of the class (term_start). Past the deadline students can no longer self-enrol: the enrolment endpoint rejects it (403 enrollment_closed) and the front-end class list shows "Enrolment has closed." in place of the Enrol button. Instructors keep a manual path: the "Add students directly" control on each class's details page now renders for public classes too (not just invite-only) and deliberately bypasses the deadline and capacity, so a student can be added as a late enrolment after the class has closed. Past the deadline the details page labels these as late enrolments. Bumps USC_VERSION to 1.1.3 for the schema change. Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
@@ -48,6 +48,19 @@ cancelled enrolment does not block re-enrolling).
|
||||
Capacity is enforced at enrolment time by counting `active` rows for the offering;
|
||||
a class at capacity rejects further enrolments.
|
||||
|
||||
Enrolment also closes after the class's **enrolment deadline** (the instructor's
|
||||
`enrollment_deadline`, defaulting to `term_start` — the first class day; see
|
||||
`offerings.md`). Past the deadline `POST /enrollments` rejects the enrolment with
|
||||
`403 enrollment_closed`, and the class list shows "Enrolment has closed." in place
|
||||
of the Enrol button.
|
||||
|
||||
The deadline only bounds student **self**-enrolment. An instructor (or studio admin)
|
||||
can still enrol someone by hand from the class **details page** — the **Add students
|
||||
directly** control, available for every group class, deliberately bypasses the
|
||||
deadline (and capacity) so a **late enrolment** can be added after the class has
|
||||
closed. Past the deadline the details page labels these as late enrolments. See
|
||||
**Admin Interface** below.
|
||||
|
||||
## REST API
|
||||
| Method | Endpoint | Permission |
|
||||
|----------|----------------------------------------------|----------------------------------|
|
||||
@@ -74,13 +87,15 @@ flips their grant from `invited` to `enrolled`.
|
||||
|
||||
Access to an invite-only class is recorded in `{prefix}us_group_access` — a grant per
|
||||
person, separate from the enrolment itself. The instructor manages access from
|
||||
**My Lessons → My Group Classes**, which renders three controls under each invite-only
|
||||
class:
|
||||
**My Lessons → My Group Classes**. **Add students directly** is available on every
|
||||
class's details page (see **Admin Interface**); invite-only classes add two more
|
||||
controls beneath it:
|
||||
|
||||
1. **Add students directly** — the selected registered students are enrolled immediately
|
||||
(`status = active`) with a **pending payment** at the class price (comp students are
|
||||
settled at once by `PaymentService`). No access grant is needed — this writes straight
|
||||
to `us_group_enrollments` + `us_payments`.
|
||||
to `us_group_enrollments` + `us_payments`. It bypasses the enrolment deadline and
|
||||
capacity, so it doubles as the **late-enrolment** path after a class has closed.
|
||||
2. **Make available** — the selected registered students get an `invited` grant so the
|
||||
class appears in their own group-class list; they then self-enrol through the normal
|
||||
paid flow. Each is emailed a "you've been added" notice.
|
||||
@@ -121,12 +136,14 @@ class becomes enrollable for them — they choose whether to enrol.
|
||||
against capacity, plus a **View details** link (**View & invite** for invite-only
|
||||
classes). Selecting a class (`?class_id=<id>`, scoped to the owning instructor) opens its
|
||||
**details page**: a class-details panel (when, instructor, enrolled/capacity, duration,
|
||||
price, schedule note, description, status), the roster of enrolled students with enrolment
|
||||
and payment status, and — for invite-only classes — an **Invite & enrol students** section
|
||||
listing who has been invited but not yet enrolled alongside the add/make-available/
|
||||
invite-by-email controls (nonce-checked `usc_action` POSTs, scoped to the owning
|
||||
instructor). Managing who is in an invite-only class is therefore done entirely from this
|
||||
page. The summary (`templates/admin/my-group-classes.php`) and the details page
|
||||
price, schedule note, enrolment deadline, status), the roster of enrolled students with
|
||||
enrolment and payment status, and an **Add students** section. Every class — public or
|
||||
invite-only — carries the **Add students directly** control there, which enrols the
|
||||
selected students immediately (a late enrolment past the deadline; the section says so
|
||||
when the deadline has passed). Invite-only classes additionally get the
|
||||
**make-available** and **invite-by-email** controls plus the list of who has been invited
|
||||
but not yet enrolled. These are nonce-checked `usc_action` POSTs, scoped to the owning
|
||||
instructor. The summary (`templates/admin/my-group-classes.php`) and the details page
|
||||
(`templates/admin/my-group-class-detail.php`) are separate templates.
|
||||
|
||||
## Implementation
|
||||
|
||||
Reference in New Issue
Block a user