169 lines · 6.2 KB · Rust
RawDownload
use crate::db::billing_subscription::StripeSubscriptionStatus; use super::*; #[derive(Debug)]pub struct CreateBillingSubscriptionParams {    pub billing_customer_id: BillingCustomerId,    pub stripe_subscription_id: String,    pub stripe_subscription_status: StripeSubscriptionStatus,} #[derive(Debug, Default)]pub struct UpdateBillingSubscriptionParams {    pub billing_customer_id: ActiveValue<BillingCustomerId>,    pub stripe_subscription_id: ActiveValue<String>,    pub stripe_subscription_status: ActiveValue<StripeSubscriptionStatus>,    pub stripe_cancel_at: ActiveValue<Option<DateTime>>,} impl Database {    /// Creates a new billing subscription.    pub async fn create_billing_subscription(        &self,        params: &CreateBillingSubscriptionParams,    ) -> Result<()> {        self.transaction(|tx| async move {            billing_subscription::Entity::insert(billing_subscription::ActiveModel {                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()            })            .exec_without_returning(&*tx)            .await?;             Ok(())        })        .await    }     /// Updates the specified billing subscription.    pub async fn update_billing_subscription(        &self,        id: BillingSubscriptionId,        params: &UpdateBillingSubscriptionParams,    ) -> Result<()> {        self.transaction(|tx| async move {            billing_subscription::Entity::update(billing_subscription::ActiveModel {                id: ActiveValue::set(id),                billing_customer_id: params.billing_customer_id.clone(),                stripe_subscription_id: params.stripe_subscription_id.clone(),                stripe_subscription_status: params.stripe_subscription_status.clone(),                stripe_cancel_at: params.stripe_cancel_at.clone(),                ..Default::default()            })            .exec(&*tx)            .await?;             Ok(())        })        .await    }     /// Returns the billing subscription with the specified ID.    pub async fn get_billing_subscription_by_id(        &self,        id: BillingSubscriptionId,    ) -> Result<Option<billing_subscription::Model>> {        self.transaction(|tx| async move {            Ok(billing_subscription::Entity::find_by_id(id)                .one(&*tx)                .await?)        })        .await    }     /// Returns the billing subscription with the specified Stripe subscription ID.    pub async fn get_billing_subscription_by_stripe_subscription_id(        &self,        stripe_subscription_id: &str,    ) -> Result<Option<billing_subscription::Model>> {        self.transaction(|tx| async move {            Ok(billing_subscription::Entity::find()                .filter(                    billing_subscription::Column::StripeSubscriptionId.eq(stripe_subscription_id),                )                .one(&*tx)                .await?)        })        .await    }     /// Returns all of the billing subscriptions for the user with the specified ID.    ///    /// Note that this returns the subscriptions regardless of their status.    /// If you're wanting to check if a use has an active billing subscription,    /// use `get_active_billing_subscriptions` instead.    pub async fn get_billing_subscriptions(        &self,        user_id: UserId,    ) -> Result<Vec<billing_subscription::Model>> {        self.transaction(|tx| async move {            let subscriptions = billing_subscription::Entity::find()                .inner_join(billing_customer::Entity)                .filter(billing_customer::Column::UserId.eq(user_id))                .order_by_asc(billing_subscription::Column::Id)                .all(&*tx)                .await?;             Ok(subscriptions)        })        .await    }     pub async fn get_active_billing_subscriptions(        &self,        user_ids: HashSet<UserId>,    ) -> Result<HashMap<UserId, (billing_customer::Model, billing_subscription::Model)>> {        self.transaction(|tx| {            let user_ids = user_ids.clone();            async move {                let mut rows = billing_subscription::Entity::find()                    .inner_join(billing_customer::Entity)                    .select_also(billing_customer::Entity)                    .filter(billing_customer::Column::UserId.is_in(user_ids))                    .filter(                        billing_subscription::Column::StripeSubscriptionStatus                            .eq(StripeSubscriptionStatus::Active),                    )                    .order_by_asc(billing_subscription::Column::Id)                    .stream(&*tx)                    .await?;                 let mut subscriptions = HashMap::default();                while let Some(row) = rows.next().await {                    if let (subscription, Some(customer)) = row? {                        subscriptions.insert(customer.user_id, (customer, subscription));                    }                }                Ok(subscriptions)            }        })        .await    }     /// Returns whether the user has an active billing subscription.    pub async fn has_active_billing_subscription(&self, user_id: UserId) -> Result<bool> {        Ok(self.count_active_billing_subscriptions(user_id).await? > 0)    }     /// Returns the count of the active billing subscriptions for the user with the specified ID.    pub async fn count_active_billing_subscriptions(&self, user_id: UserId) -> Result<usize> {        self.transaction(|tx| async move {            let count = billing_subscription::Entity::find()                .inner_join(billing_customer::Entity)                .filter(                    billing_customer::Column::UserId.eq(user_id).and(                        billing_subscription::Column::StripeSubscriptionStatus                            .eq(StripeSubscriptionStatus::Active),                    ),                )                .count(&*tx)                .await?;             Ok(count as usize)        })        .await    }}