Stripe configuration was a one-way door: keys could be entered but never removed, and entering them moved every student onto card billing at once. This opens both directions from Studio Settings.
Default payment method
A new Billing section chooses between Credit card and E-transfer for every student without a per-student override, stored in us_default_payment_method. Previously BillingMethodResolver::defaultMethod() inferred this from isStripeConfigured() alone.
Card remains the default, so a site that adds keys and changes nothing else behaves exactly as before.
A card default still degrades to e-transfer while Stripe is unconfigured — a card cannot be charged without keys.
comp is not offerable studio-wide: it is a per-student decision, and a studio-wide comp would silently stop billing everybody. An unrecognised stored value reads back as card.
The banner at the top of the page now distinguishes "Stripe configured, defaulting to card" from "Stripe configured but held on e-transfer".
The staged rollout this enables: keep the default on E-transfer with Stripe live, switch individual students to Credit card under Students → student detail → Billing method, let their bookings charge for real, then flip the studio default. Precedence is otherwise unchanged — per-student override, then studio default, then the e-transfer fallback.
Clear Stripe configuration
A button at the foot of the page, shown whenever any Stripe value is stored, that deletes the publishable key, secret key and webhook signing secret and returns the mode to Test — so a later re-configuration cannot go live by inheriting the old setting. Currency, HST, e-transfer and registration settings are untouched, as are payments already recorded. It reuses the page's existing usc_settings_action nonce and manage_billing check, and confirms before submitting.
Disconnecting locally does not remove the webhook endpoint in the Stripe Dashboard; the changelog entry says so.
Notes
Options only — no Schema.php change, so no version bump.
src/Payment/StudioSettings.php was reformatted on disk mid-work by something outside this change (tabs → spaces, single → double quotes, ~80-column rewrapping), which put the file 553 errors away from composer cs. The file here is rebuilt from main with only the semantic changes re-applied, so the diff is 50 insertions and no formatting churn.
Tests
composer test — 915 pass, 2592 assertions (10 new: 5 on the resolver covering both defaults, the Stripe-unconfigured fallback and a per-student card override under an e-transfer default; 5 on the settings covering the default's fallbacks and that clearing touches only the four Stripe options)
Closes #173.
Stripe configuration was a one-way door: keys could be entered but never removed, and entering them moved every student onto card billing at once. This opens both directions from **Studio Settings**.
## Default payment method
A new **Billing** section chooses between Credit card and E-transfer for every student without a per-student override, stored in `us_default_payment_method`. Previously `BillingMethodResolver::defaultMethod()` inferred this from `isStripeConfigured()` alone.
- Card remains the default, so a site that adds keys and changes nothing else behaves exactly as before.
- A card default still degrades to e-transfer while Stripe is unconfigured — a card cannot be charged without keys.
- `comp` is not offerable studio-wide: it is a per-student decision, and a studio-wide comp would silently stop billing everybody. An unrecognised stored value reads back as `card`.
- The banner at the top of the page now distinguishes "Stripe configured, defaulting to card" from "Stripe configured but held on e-transfer".
The staged rollout this enables: keep the default on E-transfer with Stripe live, switch individual students to Credit card under Students → student detail → Billing method, let their bookings charge for real, then flip the studio default. Precedence is otherwise unchanged — per-student override, then studio default, then the e-transfer fallback.
## Clear Stripe configuration
A button at the foot of the page, shown whenever any Stripe value is stored, that deletes the publishable key, secret key and webhook signing secret and returns the mode to Test — so a later re-configuration cannot go live by inheriting the old setting. Currency, HST, e-transfer and registration settings are untouched, as are payments already recorded. It reuses the page's existing `usc_settings_action` nonce and `manage_billing` check, and confirms before submitting.
Disconnecting locally does not remove the webhook endpoint in the Stripe Dashboard; the changelog entry says so.
## Notes
- Options only — no `Schema.php` change, so no version bump.
- `src/Payment/StudioSettings.php` was reformatted on disk mid-work by something outside this change (tabs → spaces, single → double quotes, ~80-column rewrapping), which put the file 553 errors away from `composer cs`. The file here is rebuilt from `main` with only the semantic changes re-applied, so the diff is 50 insertions and no formatting churn.
## Tests
- `composer test` — 915 pass, 2592 assertions (10 new: 5 on the resolver covering both defaults, the Stripe-unconfigured fallback and a per-student card override under an e-transfer default; 5 on the settings covering the default's fallbacks and that clearing touches only the four Stripe options)
- `composer lint` — no PHPStan errors
- `composer cs` — clean
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01WyktWmwNRgMYuwe5eBuPZm
Stripe configuration was a one-way door. Keys could be entered but never
removed, and entering them moved every student onto card billing at once,
so there was no way to have Stripe live and satisfy yourself that card
payments worked before committing the studio to them.
Two settings-page changes open both directions:
Default payment method (`us_default_payment_method`) is now an explicit
choice between card and e-transfer for students with no per-student
override, rather than something inferred from whether keys exist. Card
remains the default, so a site that adds keys and changes nothing else
behaves as before. BillingMethodResolver still degrades a card default to
e-transfer while Stripe is unconfigured — there is nothing to charge a
card with — and `comp` is deliberately not offerable studio-wide, since
it would silently stop billing everybody; an unrecognised stored value
reads back as card. Holding the default on e-transfer with Stripe live is
the staged-rollout path: move individual students to card on their detail
page, watch real charges land, then flip the studio over.
Clear Stripe configuration deletes the publishable key, secret key and
webhook signing secret and returns the mode to test, so a re-configuration
later cannot inherit live. Currency, HST, e-transfer and registration
settings are untouched, as are recorded payments. The button only appears
when some Stripe value is stored, and reuses the page's existing nonce and
`manage_billing` check.
`composer test` (915), `composer lint` and `composer cs` all pass. Options
only — no schema change, so no version bump.
Closes#173
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01WyktWmwNRgMYuwe5eBuPZm
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes #173.
Stripe configuration was a one-way door: keys could be entered but never removed, and entering them moved every student onto card billing at once. This opens both directions from Studio Settings.
Default payment method
A new Billing section chooses between Credit card and E-transfer for every student without a per-student override, stored in
us_default_payment_method. PreviouslyBillingMethodResolver::defaultMethod()inferred this fromisStripeConfigured()alone.compis not offerable studio-wide: it is a per-student decision, and a studio-wide comp would silently stop billing everybody. An unrecognised stored value reads back ascard.The staged rollout this enables: keep the default on E-transfer with Stripe live, switch individual students to Credit card under Students → student detail → Billing method, let their bookings charge for real, then flip the studio default. Precedence is otherwise unchanged — per-student override, then studio default, then the e-transfer fallback.
Clear Stripe configuration
A button at the foot of the page, shown whenever any Stripe value is stored, that deletes the publishable key, secret key and webhook signing secret and returns the mode to Test — so a later re-configuration cannot go live by inheriting the old setting. Currency, HST, e-transfer and registration settings are untouched, as are payments already recorded. It reuses the page's existing
usc_settings_actionnonce andmanage_billingcheck, and confirms before submitting.Disconnecting locally does not remove the webhook endpoint in the Stripe Dashboard; the changelog entry says so.
Notes
Schema.phpchange, so no version bump.src/Payment/StudioSettings.phpwas reformatted on disk mid-work by something outside this change (tabs → spaces, single → double quotes, ~80-column rewrapping), which put the file 553 errors away fromcomposer cs. The file here is rebuilt frommainwith only the semantic changes re-applied, so the diff is 50 insertions and no formatting churn.Tests
composer test— 915 pass, 2592 assertions (10 new: 5 on the resolver covering both defaults, the Stripe-unconfigured fallback and a per-student card override under an e-transfer default; 5 on the settings covering the default's fallbacks and that clearing touches only the four Stripe options)composer lint— no PHPStan errorscomposer cs— clean🤖 Generated with Claude Code
https://claude.ai/code/session_01WyktWmwNRgMYuwe5eBuPZm
fbbd86524etoc077a653fb