collab: Add separate billing_customers
table (#15457)
This PR adds a new `billing_customers` table to hold the billing customers. Previously we were storing both the `stripe_customer_id` and `stripe_subscription_id` in the `billable_subscriptions` table. However, this creates problems when we need to correlate subscription events back to the subscription record, as we don't know the user that the Stripe event corresponds to. By moving the `stripe_customer_id` to a separate table we can create the Stripe customer earlier in the flow—before we create the Stripe Checkout session—and associate that customer with a user. This way when we receive events down the line we can use the Stripe customer ID to correlate it back to the user. We're doing some destructive actions to the `billing_subscriptions` table, but this is fine, as we haven't started using them yet. Release Notes: - N/A
This commit is contained in:
parent
66121fa0e8
commit
28c14cdee4
13 changed files with 183 additions and 52 deletions
42
crates/collab/src/db/queries/billing_customers.rs
Normal file
42
crates/collab/src/db/queries/billing_customers.rs
Normal file
|
@ -0,0 +1,42 @@
|
|||
use super::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CreateBillingCustomerParams {
|
||||
pub user_id: UserId,
|
||||
pub stripe_customer_id: String,
|
||||
}
|
||||
|
||||
impl Database {
|
||||
/// Creates a new billing customer.
|
||||
pub async fn create_billing_customer(
|
||||
&self,
|
||||
params: &CreateBillingCustomerParams,
|
||||
) -> Result<billing_customer::Model> {
|
||||
self.transaction(|tx| async move {
|
||||
let customer = billing_customer::Entity::insert(billing_customer::ActiveModel {
|
||||
user_id: ActiveValue::set(params.user_id),
|
||||
stripe_customer_id: ActiveValue::set(params.stripe_customer_id.clone()),
|
||||
..Default::default()
|
||||
})
|
||||
.exec_with_returning(&*tx)
|
||||
.await?;
|
||||
|
||||
Ok(customer)
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
/// Returns the billing customer for the user with the specified ID.
|
||||
pub async fn get_billing_customer_by_user_id(
|
||||
&self,
|
||||
user_id: UserId,
|
||||
) -> Result<Option<billing_customer::Model>> {
|
||||
self.transaction(|tx| async move {
|
||||
Ok(billing_customer::Entity::find()
|
||||
.filter(billing_customer::Column::UserId.eq(user_id))
|
||||
.one(&*tx)
|
||||
.await?)
|
||||
})
|
||||
.await
|
||||
}
|
||||
}
|
|
@ -4,8 +4,7 @@ use super::*;
|
|||
|
||||
#[derive(Debug)]
|
||||
pub struct CreateBillingSubscriptionParams {
|
||||
pub user_id: UserId,
|
||||
pub stripe_customer_id: String,
|
||||
pub billing_customer_id: BillingCustomerId,
|
||||
pub stripe_subscription_id: String,
|
||||
pub stripe_subscription_status: StripeSubscriptionStatus,
|
||||
}
|
||||
|
@ -18,8 +17,7 @@ impl Database {
|
|||
) -> Result<()> {
|
||||
self.transaction(|tx| async move {
|
||||
billing_subscription::Entity::insert(billing_subscription::ActiveModel {
|
||||
user_id: ActiveValue::set(params.user_id),
|
||||
stripe_customer_id: ActiveValue::set(params.stripe_customer_id.clone()),
|
||||
billing_customer_id: ActiveValue::set(params.billing_customer_id),
|
||||
stripe_subscription_id: ActiveValue::set(params.stripe_subscription_id.clone()),
|
||||
stripe_subscription_status: ActiveValue::set(params.stripe_subscription_status),
|
||||
..Default::default()
|
||||
|
@ -56,7 +54,8 @@ impl Database {
|
|||
) -> Result<Vec<billing_subscription::Model>> {
|
||||
self.transaction(|tx| async move {
|
||||
let subscriptions = billing_subscription::Entity::find()
|
||||
.filter(billing_subscription::Column::UserId.eq(user_id))
|
||||
.inner_join(billing_customer::Entity)
|
||||
.filter(billing_customer::Column::UserId.eq(user_id))
|
||||
.order_by_asc(billing_subscription::Column::Id)
|
||||
.all(&*tx)
|
||||
.await?;
|
||||
|
@ -73,8 +72,9 @@ impl Database {
|
|||
) -> Result<Vec<billing_subscription::Model>> {
|
||||
self.transaction(|tx| async move {
|
||||
let subscriptions = billing_subscription::Entity::find()
|
||||
.inner_join(billing_customer::Entity)
|
||||
.filter(
|
||||
billing_subscription::Column::UserId.eq(user_id).and(
|
||||
billing_customer::Column::UserId.eq(user_id).and(
|
||||
billing_subscription::Column::StripeSubscriptionStatus
|
||||
.eq(StripeSubscriptionStatus::Active),
|
||||
),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue