Repository navigation
Record invoice-paid storage grants from the admin panel #6159
Description
❌ This issue is not open for contribution. Visit Contributing guidelines to learn about the contributing process and how to find suitable issues.
Overview
Some customers pay for storage by invoice rather than through Stripe Checkout, often because the person paying is not the account owner. Stripe records that as an invoice with no subscription behind it, so no UserSubscription row is created and the storage cannot be granted as purchased space.
Complexity: Medium
Target branch: hotfixes
Context
UserSubscriptionrows are created only byCheckoutCompletedSerializer, keyed on theclient_reference_idthat Studio's own Checkout Session sets. Thecustomer.subscription.updatedand.deletedwebhooks then look the row up bystripe_subscription_id.get_effective_disk_space()adds the subscription space only whenUserSubscription.is_active, which testsstripe_subscription_statusagainstactiveandtrialing.- Show purchased subscription storage in the admin panel #6158 adds the admin display of purchased disk space, subscription status and period end; this issue adds the means to create such a row by hand.
The Change
- An admin should be able to record an invoice grant against a user, so the space reads as purchased rather than as an admin grant.
- The grant should carry an end date the admin sets, since nothing in Stripe will report one.
How to Get There
- The user detail panel is at
/administration/#/users/<userId>, behindIsAdminUser. - The user's own view of their storage is Settings > Storage, rendered by
SubscriptionCard.vuefromSubscriptionStatusView. - An invoice grant has no counterpart in Stripe, so no webhook will ever fire against it.
Out of Scope
- Revoking the space automatically when the end date passes.
- Reading invoices from the Stripe API — the admin types the reference in, and Studio neither fetches nor reconciles anything from Stripe.
- Unblocking self-service Checkout while an invoice grant is active; the existing 400 stands.
- The admin display of purchased disk space.
- The Checkout and webhook flows for Stripe subscriptions.
Acceptance Criteria
General
- An admin can record an invoice grant against a user from
/administration/#/users/<userId>, entering a storage amount in GB, an end date and an invoice reference, with no upper bound on the amount. - An invoice grant sets
stripe_subscription_statustoactiveand stores the end date incurrent_period_end, soget_effective_disk_space()counts the space. - The invoice reference is stored and shown on the user detail panel.
- The panel refuses to record an invoice grant for a user who already has a
UserSubscriptionrow, and says why. - An admin can edit and remove an invoice grant.
- An invoice grant sets
cancel_at_period_end, so the detail panel labels its end date "Expires on". - Settings > Storage hides the Manage button when the subscription has no
stripe_customer_id.
Testing
- Python tests cover recording an invoice grant, refusing one where a
UserSubscriptionrow exists, editing, removing, andget_effective_disk_space()counting the granted space. - Jest tests cover the detail panel form and the hidden Manage button.
AI usage
I raised this after a customer paid for storage by invoice, and used Claude Code to trace how subscription rows get created and to draft the issue section by section. I chose the admin panel as the entry point, decided the grant reuses the existing subscription fields, and settled what stays out of scope.

Activity