forked from coracle/caravel
Remove relay subscription item column
This commit is contained in:
@@ -27,16 +27,15 @@ Members:
|
||||
|
||||
Reconciles a tenant's single Stripe subscription with the set of relays that should be billed. Only paid (non-free) relays interact with Stripe. Free-only tenants have no subscription. Must be idempotent.
|
||||
|
||||
Stripe forbids two subscription items on the same subscription from sharing a price, so billing is modeled as **one subscription item per plan (price), with `quantity` equal to the number of the tenant's `active` relays on that plan**. Every such relay's `stripe_subscription_item_id` points at the shared item for its plan; relays that aren't billed (free, inactive, delinquent) have it cleared.
|
||||
Stripe forbids two subscription items on the same subscription from sharing a price, so billing is modeled as **one subscription item per plan (price), with `quantity` equal to the number of the tenant's `active` relays on that plan**. The relay → item mapping is fully derivable from `relay.plan → plan.stripe_price_id` and the live subscription's items, so we don't persist it on the relay.
|
||||
|
||||
Stripe uses **pay-in-advance** by default: when a subscription is first created, Stripe immediately generates an open invoice for the current period. The `invoice.created` webhook fires shortly after and `handle_invoice_created` attempts payment.
|
||||
|
||||
- Fetch the tenant and its relays. Build the desired state: for each `active` relay on a paid plan with a non-empty `stripe_price_id`, count relays per price.
|
||||
- **Resolve the live subscription**: if the tenant has a `stripe_subscription_id`, fetch it. If Stripe no longer knows about it, or its status is `canceled`/`incomplete_expired`, call `command.clear_tenant_subscription` and treat the tenant as having no subscription.
|
||||
- **No relays to bill** (desired state empty): if the tenant still has a `stripe_subscription_id`, cancel the Stripe subscription and call `command.clear_tenant_subscription`. Clear `stripe_subscription_item_id` on every relay that has one. Return.
|
||||
- **No relays to bill** (desired state empty): if the tenant still has a `stripe_subscription_id`, cancel the Stripe subscription and call `command.clear_tenant_subscription`. Return.
|
||||
- **No subscription yet**: create a Stripe subscription for the customer with `collection_method: "charge_automatically"` and one item per `(price, quantity)`. Save the subscription ID via `command.set_tenant_subscription`.
|
||||
- **Existing subscription**: fetch its current items. For each desired `(price, quantity)`: update the matching item's quantity if it differs, otherwise create the item. Delete any item whose price no longer appears in the desired state.
|
||||
- **Point relays at items**: for each relay, set `stripe_subscription_item_id` (via `command.set_relay_subscription_item`) to the shared item for its plan, or clear it (via `command.delete_relay_subscription_item`) if the relay is not billed.
|
||||
- **Downgrade validation**: if any quantity decreased or any item was removed, preview the upcoming Stripe invoice and log proration line/amount details to validate expected credit/proration behavior.
|
||||
|
||||
## `pub fn handle_webhook(&self, payload: &str, signature: &str) -> Result<()>`
|
||||
|
||||
@@ -68,16 +68,6 @@ Notes:
|
||||
- Sets `synced = 1`, clears `sync_error`
|
||||
- Logs activity as `(complete_relay_sync, relay_id)`
|
||||
|
||||
## `pub fn delete_relay_subscription_item(&self, relay_id: &str) -> Result<()>`
|
||||
|
||||
- Sets `stripe_subscription_item_id = null`
|
||||
- Does not log activity
|
||||
|
||||
## `pub fn set_relay_subscription_item(&self, relay_id: &str, stripe_subscription_item_id: &str) -> Result<()>`
|
||||
|
||||
- Sets `stripe_subscription_item_id`
|
||||
- Does not log activity
|
||||
|
||||
## `pub fn set_tenant_subscription(&self, pubkey: &str, stripe_subscription_id: &str) -> Result<()>`
|
||||
|
||||
- Sets `stripe_subscription_id` on the tenant
|
||||
|
||||
@@ -68,7 +68,6 @@ A relay is a nostr relay owned by a `tenant` and hosted by the attached zooid in
|
||||
- `schema` - the relay's db schema (read only, same as `id`)
|
||||
- `subdomain` - the relay's subdomain
|
||||
- `plan` - the relay's plan
|
||||
- `stripe_subscription_item_id` (nullable) - the Stripe subscription item id. Only set for relays on paid plans.
|
||||
- `status` - one of `active|inactive|delinquent`. Only `active` relays count toward billing. `delinquent` is set by the billing system when a relay's subscription becomes past due; `inactive` is set when a user or admin manually deactivates a relay.
|
||||
- `synced` - whether the relay has been successfully synced to zooid at least once.
|
||||
- `sync_error` - a string indicating any errors encountered when synchronizing.
|
||||
|
||||
@@ -37,11 +37,10 @@ Constructs the client with a fresh `reqwest::Client` from explicit keys (does no
|
||||
- Idempotent on the customer and the `(price, quantity)` set
|
||||
- Returns the subscription id and a map from price id to the created subscription item id
|
||||
|
||||
## `pub async fn create_subscription_item(&self, subscription_id: &str, price_id: &str, quantity: i64) -> Result<String>`
|
||||
## `pub async fn create_subscription_item(&self, subscription_id: &str, price_id: &str, quantity: i64) -> Result<()>`
|
||||
|
||||
- `POST /v1/subscription_items`
|
||||
- Idempotent on `(subscription_id, price_id)`
|
||||
- Returns the new subscription item id
|
||||
|
||||
## `pub async fn set_subscription_item_quantity(&self, item_id: &str, quantity: i64) -> Result<()>`
|
||||
|
||||
|
||||
Reference in New Issue
Block a user