a2cece750b3a40341ddfabdcfdbd918e2a0bd69a
13
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
122f7a0f53
|
Show "Booked by" in the Account section of a student's detail page
CI / No Debug Code (pull_request) Successful in 2s
CI / PHPStan (pull_request) Successful in 2m48s
CI / Tests (PHP 8.3) (pull_request) Successful in 2m42s
CI / Tests (PHP 8.2) (pull_request) Successful in 57s
CI / Tests (PHP 8.1) (pull_request) Successful in 59s
CI / Coding Standards (pull_request) Successful in 3m1s
CI / Build Plugin Zip (pull_request) Skipped
The parent/guardian was only named further down under Profile, where it reads as background rather than as an account fact, and only when there was one — so a page with no such line was ambiguous between "books for themselves" and "the lookup found nothing". It now sits in the Account table beside display name and email, as the guardian's name linked to their own detail page, and always renders: a student who books for themselves says so outright. No email address — theirs is one click away on their own page, and repeating it here only makes the row harder to scan. The Profile section keeps only the note explaining the placeholder email, which is a different point. Tests: composer test (863), composer lint, composer cs all pass. Co-Authored-By: Claude Opus 5 <[email protected]> |
||
|
|
c9a1205fc0
|
Never drop an enrolled class from upcoming lessons; delete a guardian's children with them; pin the panel's line spacing
CI / Tests (PHP 8.2) (pull_request) Successful in 58s
CI / PHPStan (pull_request) Successful in 2m53s
CI / Coding Standards (pull_request) Successful in 2m58s
CI / Tests (PHP 8.3) (pull_request) Successful in 2m47s
CI / Build Plugin Zip (pull_request) Skipped
CI / Tests (PHP 8.1) (pull_request) Successful in 1m1s
CI / No Debug Code (pull_request) Successful in 3s
Three fixes from testing the branch. A group class was only listed when its schedule resolved to exact datetimes, which needs a class time *and* a duration — both optional on the offering form, and the schedule note exists precisely so a studio can write "Tuesdays 4:00pm" instead. A class configured that way vanished from the list, which is the one thing this feature must never do. So Offering::sessionStarts() splits "when does it meet" from "how long does it run" (sessionWindows() is that plus the duration, unchanged), and SessionSchedule degrades instead of disappearing: dated rows with an open end when there is no duration, and a single row carrying Offering::scheduleLabel() when there is no time to derive dates from. Only a class whose last day has passed drops out. Deleting a guardian now deletes the children linked to them, releasing each one's lessons and enrolments first. A child account is login-less and exists only so the guardian has somebody to book for; without the guardian nobody can reach it, book for it, or be billed for it, so it was left stranded on the roster still holding slots. A `handled` set makes the re-entrant delete_user each child deletion fires a no-op, and stops a circular link recursing. The upcoming panel never stated its own line-height, so a theme setting line-height: 0 above it — the usual icon-font reset — was inherited straight through. Below 1 that produces both reported symptoms at once: stacked lines overlap, and the status pill's background is shorter than the text in it. Pinned at the same id-level specificity as the rest. Tests: composer test (863), composer lint, composer cs all pass. Co-Authored-By: Claude Opus 5 <[email protected]> |
||
|
|
cb347ffca0
|
Demo follow-ups: editable policy name, one-page signup, group classes in upcoming lessons, deletion cleanup
CI / Tests (PHP 8.1) (pull_request) Successful in 1m0s
CI / Tests (PHP 8.2) (pull_request) Successful in 1m0s
CI / No Debug Code (pull_request) Successful in 3s
CI / Coding Standards (pull_request) Successful in 3m8s
CI / Build Plugin Zip (pull_request) Skipped
CI / PHPStan (pull_request) Successful in 2m49s
CI / Tests (PHP 8.3) (pull_request) Successful in 2m44s
Five items from the latest demo pass: - A policy's title can be edited from the Policies screen. Only the title moves; the slug is what the gates resolve policies by, so a rename can never detach a policy from acceptances already recorded against it. - Signup is one page again. The studio's registration questions move from a second step behind "Next" onto the main form, in an "About you" panel above the students being added, and that panel also asks an adult student for their birth year (the same us_birth_year meta a child's uses). register.js disables and hides the whole panel for a pure guardian, since the questions describe a student. - The password is re-scored on submit, not only as it is typed. zxcvbn's dictionary arrives after page load, so a password typed straight away was never scored at all and the first the student heard of it was the server rejecting the whole form. - Group-class sessions appear alongside lessons wherever upcoming lessons are listed: the [us_scheduler] panel (students and instructors) and the admin student detail page. GroupClass\SessionSchedule derives them from Offering::sessionWindows(), the same derivation the billing scan uses. They carry kind = 'group_class' and no Cancel action - a session is one date in a term, not a booked slot. - Deleting a user releases what the account was holding: each upcoming lesson is cancelled, its slot freed for rebooking, its pending payment voided, and active class enrolments cancelled. Past lessons and paid history are left alone. Tests: composer test (851), composer lint, composer cs all pass. Co-Authored-By: Claude Opus 5 <[email protected]> |
||
|
|
7e2bba79fe
|
Collect a birth year instead of a full date of birth
CI / Tests (PHP 8.1) (pull_request) Successful in 43s
CI / No Debug Code (pull_request) Successful in 2s
CI / Tests (PHP 8.2) (pull_request) Successful in 50s
CI / PHPStan (pull_request) Successful in 2m55s
CI / Coding Standards (pull_request) Successful in 3m0s
CI / Tests (PHP 8.3) (pull_request) Successful in 2m40s
CI / Build Plugin Zip (pull_request) Skipped
Signup and the profile page now ask for a four-digit year between 1900 and the current year. Anything else — a short year, a full date, a year in the future — is discarded rather than stored, so a typo cannot leave a nonsense age on the record. The year lives in a new us_birth_year user meta rather than reusing us_date_of_birth, which would have left one key holding two formats. The old key is not migrated in bulk. Instead GuardianService handles it in two halves: birthYear() falls back to the year of the old date when the new key is absent, so a student added before this change still shows one, and setBirthYear() deletes the old date on every save. That deletion is what makes the fallback safe rather than merely tidy. Without it, clearing the birth year on a student who predates the change would leave the old date behind for the fallback to read straight back, and the year could never be cleared at all. Stored in user meta, so no Schema.php change and no USC_VERSION bump. Closes #147 Co-Authored-By: Claude Opus 5 <[email protected]> |
||
|
|
76caf178f0
|
Say "student" and "profile" in the UI, not "child" and "family"
CI / Tests (PHP 8.1) (pull_request) Successful in 41s
CI / Tests (PHP 8.2) (pull_request) Successful in 40s
CI / No Debug Code (pull_request) Successful in 2s
CI / Coding Standards (pull_request) Successful in 2m55s
CI / PHPStan (pull_request) Successful in 3m1s
CI / Tests (PHP 8.3) (pull_request) Successful in 2m43s
CI / Build Plugin Zip (pull_request) Skipped
Sweep the translatable strings across the frontend templates, the admin screens, the editor previews and the block inserter entry. Nothing else moves: the database columns, request parameters, form field names, CSS classes, the us_family shortcode and the us-scheduler/family block name are contracts with existing installs and with post content people have already saved, so renaming them would break sites for no user-visible gain. Two strings are reworded rather than swapped, because the direct substitution reads wrong: - The students list said "Child of Jane" and now says "Managed by Jane". "Student of Jane" would read as a teacher's pupil, which is exactly the wrong idea in a music studio. - A managed account is now "a managed student account" rather than "a student account", which would not distinguish it from the account holder. The guardian feature doc gains a short section on the split, so the next person to work on it does not read the mismatch as drift and "fix" it. Closes #144 Co-Authored-By: Claude Opus 5 <[email protected]> |
||
|
|
b772e1811e
|
Let parents register once and book for their children
A parent registers once and manages lessons for one or more children, who need no login of their own. A child is a real wp_users row with the student role but no usable login — so student_id keeps meaning "a WordPress user" on every table, and booking, credits, policies and enrolments work unchanged. A us_guardians link table maps guardian to child. The signup form gains a parent/guardian tick that reveals a block per child, with the account-signup questions asked per child rather than per guardian — they describe the student, not the account holder. Signup policies are recorded once per child with the guardian as the acceptor, which is the record that actually means something. A family that half-creates is rolled back entirely rather than leaving a guardian who cannot re-register. The booking and enrolment forms gain a "Who is this for?" picker listing children first, so the default selection is never the parent — booking for the wrong child is correctable, quietly billing a parent for their kid's lesson is not. POST /bookings and POST /enrollments take an optional student_id honoured only for that child's guardian; anything else is a 403. That check is the authorisation boundary of the feature. Payments and credits gain a payer: the charge names the child it was for and the guardian who owes it, so per-child reporting is unchanged while notices, receipts and the payment step reach the parent. Credit is held by the payer, so one child's cancellation can settle a sibling's charge, and the daily billing scan sends a guardian one notice covering every child. Closes #132 Co-Authored-By: Claude Opus 5 <[email protected]> |
||
|
|
e8e66eef3c
|
Credit students for cancelled paid lessons
CI / Tests (PHP 8.1) (pull_request) Successful in 47s
CI / Tests (PHP 8.2) (pull_request) Successful in 47s
CI / PHPStan (pull_request) Successful in 3m12s
CI / Tests (PHP 8.3) (pull_request) Successful in 2m42s
CI / Build Plugin Zip (pull_request) Skipped
CI / No Debug Code (pull_request) Successful in 3s
CI / Coding Standards (pull_request) Successful in 2m52s
Cancelling a lesson that was already paid for now credits the student that money instead of leaving it as a manual refund, and the daily scheduled-billing scan applies any available credit against their due charges before emailing the notice. - New us_credits ledger + us_payments.credit_applied column (Payment::netDue). - PaymentService::creditForCancelledLesson issues a per-lesson share of the covering payment's total; wired into all three cancel paths (student self-cancel, instructor status update, admin student-detail cancel). - PaymentService::applyCredits draws credit down FIFO across a run's charges, marking a fully-covered charge paid-by-credit; the notice shows the credit applied and reduced total, and the admin queue shows net due. - Student detail page shows a student's credit balance and history. Ships as part of the unreleased 1.2.0 (same release as scheduled billing). Tests: composer test (585), composer lint, composer cs all pass. Co-Authored-By: Claude Opus 4.8 <[email protected]> |
||
|
|
49c59a950c
|
Add studio-defined account-registration questions
CI / Tests (PHP 8.2) (pull_request) Successful in 44s
CI / Tests (PHP 8.1) (pull_request) Successful in 45s
CI / No Debug Code (pull_request) Successful in 2s
CI / Coding Standards (pull_request) Successful in 2m46s
CI / PHPStan (pull_request) Successful in 2m58s
CI / Tests (PHP 8.3) (pull_request) Successful in 2m41s
CI / Build Plugin Zip (pull_request) Skipped
Studio admins can now define registration questions that every new student answers as a required second step during signup, with each student's answers shown under a "Registration Information" section in the admin. Extends the existing Registration domain: us_questions gains a scope column (offering | account) and a nullable offering_id, and account answers reuse us_question_answers with registration_type = 'account'. Authoring reuses the Offerings -> Questions page via an "Account signup" scope (studio-admin only). The registration form becomes two steps (progressive enhancement via assets/js/register.js; works without JS); required answers are validated before the account is created and apply to all signup paths (invite, group link, self-approval). StudentHistory::registrationInfo() powers the admin section. Bumps the plugin version to 1.1.0 so dbDelta runs the schema migration. Closes #90 Co-Authored-By: Claude Opus 4.8 <[email protected]> |
||
|
|
5808523140
|
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
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]> |
||
|
|
c49171695a
|
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
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]> |
||
|
|
b7d5e3039e
|
Split availability windows into bookable lesson-length slots with weekly calendar views
CI / Build Plugin Zip (pull_request) Has been skipped
CI / Tests (PHP 8.2) (pull_request) Successful in 45s
CI / PHPStan (pull_request) Successful in 2m48s
CI / Tests (PHP 8.1) (pull_request) Successful in 41s
CI / No Debug Code (pull_request) Failing after 2s
CI / Coding Standards (pull_request) Successful in 52s
CI / Tests (PHP 8.3) (pull_request) Successful in 2m36s
Availability windows were stored and served as a single bookable row, so a 9:00 AM-4:00 PM window showed to students as one giant slot and booking it consumed the whole day; past and multi-day windows also leaked into the booking page as nonsense entries. - Split windows into consecutive lesson-length slots on save (REST and admin form); each chunk is independently bookable and weekly recurrence creates a series per chunk so "reserve this time weekly" holds the same hour each week - Reject windows spanning multiple days or shorter than the lesson length (400 invalid_window) - Never return slots whose start has passed from GET /availability - Migrate pre-split rows: Plugin::boot re-runs the Installer on version change and AvailabilityRepository::splitOversizedWindows() rewrites unbooked same-day oversized windows in place - Display all times in 12-hour AM/PM form (booking page, wp-admin lists, editor previews) - Add a List | Week view toggle to the student booking page and the instructor availability page, with previous/next-week navigation honouring the site's start_of_week option (new WeekCalendar helper) Co-Authored-By: Claude Fable 5 <[email protected]> |
||
|
|
6c4097b385
|
Add payments foundation (e-transfer/comp, Stripe config, receipts)
CI / Tests (PHP 8.1) (pull_request) Successful in 45s
CI / Tests (PHP 8.3) (pull_request) Successful in 50s
CI / No Debug Code (pull_request) Successful in 3s
CI / Coding Standards (pull_request) Successful in 1m2s
CI / Tests (PHP 8.2) (pull_request) Successful in 1m0s
CI / PHPStan (pull_request) Successful in 1m4s
CI / Build Plugin Zip (pull_request) Has been skipped
Implements the payments foundation for #7. Without Stripe credentials everything works on e-transfer (pending payment confirmed by a studio admin); when Stripe keys are configured the default flips to credit card. Per-student override (card/etransfer/comp) is set on the student detail. - Schema: us_payments (amount DECIMAL dollars, method, status, receipt, stripe intent id). - src/Payment/: Payment VO, PaymentRepository, StudioSettings (Stripe options + isStripeConfigured + settings page), BillingMethodResolver (per-student override; default card if configured else etransfer), ReceiptMailer, PaymentService (create at registration, link payment_id, comp->paid+confirm, markPaid->confirm+receipt), PaymentController (e-transfer confirmation queue), PaymentEndpoint (PATCH /payments/{id}). - Booking + enrolment create the payment from the offering price; comp auto-confirms the lesson; setPaymentId on both repositories. - Admin: Studio Settings + Payments menus (manage_billing); per-student billing method on the student detail page. - Docs: payments.md + README updated. Deferred to a follow-up: the live Stripe card charge (PaymentIntent + Stripe.js Elements + webhook + stripe/stripe-php). Until then a card payment is created pending and confirmed like an e-transfer. Tests: tests/Unit/Payment/ (VO, repository, resolver, service, mailer). composer test (147), cs, and PHPStan level 6 all pass. Refs #7 Co-Authored-By: Claude Opus 4.8 <[email protected]> |
||
|
|
8fb5ff8270
|
Add student administration view (studio-admin)
CI / Tests (PHP 8.1) (pull_request) Successful in 43s
CI / Coding Standards (pull_request) Successful in 56s
CI / PHPStan (pull_request) Successful in 57s
CI / No Debug Code (pull_request) Successful in 2s
CI / Tests (PHP 8.2) (pull_request) Successful in 44s
CI / Tests (PHP 8.3) (pull_request) Successful in 48s
CI / Build Plugin Zip (pull_request) Has been skipped
Implements #22: a read-only Students area for studio admins. - StudentController (manage_students): a list of us_student users with upcoming-lesson and active-enrolment counts, each linking to a detail page showing account info, upcoming/past lessons (offering, instructor, status), and group-class enrolments. - StudentSchedule::partition() — pure, unit-tested upcoming/past split. - Repo counts: BookingRepository::countUpcomingForStudent and EnrollmentRepository::countActiveForStudent (single-query, tested). - Templates: templates/admin/students.php, student-detail.php. - Students admin menu wired in AdminMenu (no Plugin change — the repos were already available there). - Docs: README status flipped to implemented; feature spec updated. Payment history slots into the detail when Payments (#7) lands. Tests: StudentScheduleTest + the two repo count tests. composer test (127), cs, and PHPStan level 6 all pass. Refs #22 Co-Authored-By: Claude Opus 4.8 <[email protected]> |