billing_subscriptions.rs

  1use crate::db::billing_subscription::{StripeCancellationReason, StripeSubscriptionStatus};
  2
  3use super::*;
  4
  5#[derive(Debug)]
  6pub struct CreateBillingSubscriptionParams {
  7    pub billing_customer_id: BillingCustomerId,
  8    pub stripe_subscription_id: String,
  9    pub stripe_subscription_status: StripeSubscriptionStatus,
 10}
 11
 12#[derive(Debug, Default)]
 13pub struct UpdateBillingSubscriptionParams {
 14    pub billing_customer_id: ActiveValue<BillingCustomerId>,
 15    pub stripe_subscription_id: ActiveValue<String>,
 16    pub stripe_subscription_status: ActiveValue<StripeSubscriptionStatus>,
 17    pub stripe_cancel_at: ActiveValue<Option<DateTime>>,
 18    pub stripe_cancellation_reason: ActiveValue<Option<StripeCancellationReason>>,
 19}
 20
 21impl Database {
 22    /// Creates a new billing subscription.
 23    pub async fn create_billing_subscription(
 24        &self,
 25        params: &CreateBillingSubscriptionParams,
 26    ) -> Result<()> {
 27        self.transaction(|tx| async move {
 28            billing_subscription::Entity::insert(billing_subscription::ActiveModel {
 29                billing_customer_id: ActiveValue::set(params.billing_customer_id),
 30                stripe_subscription_id: ActiveValue::set(params.stripe_subscription_id.clone()),
 31                stripe_subscription_status: ActiveValue::set(params.stripe_subscription_status),
 32                ..Default::default()
 33            })
 34            .exec_without_returning(&*tx)
 35            .await?;
 36
 37            Ok(())
 38        })
 39        .await
 40    }
 41
 42    /// Updates the specified billing subscription.
 43    pub async fn update_billing_subscription(
 44        &self,
 45        id: BillingSubscriptionId,
 46        params: &UpdateBillingSubscriptionParams,
 47    ) -> Result<()> {
 48        self.transaction(|tx| async move {
 49            billing_subscription::Entity::update(billing_subscription::ActiveModel {
 50                id: ActiveValue::set(id),
 51                billing_customer_id: params.billing_customer_id.clone(),
 52                stripe_subscription_id: params.stripe_subscription_id.clone(),
 53                stripe_subscription_status: params.stripe_subscription_status.clone(),
 54                stripe_cancel_at: params.stripe_cancel_at.clone(),
 55                stripe_cancellation_reason: params.stripe_cancellation_reason.clone(),
 56                ..Default::default()
 57            })
 58            .exec(&*tx)
 59            .await?;
 60
 61            Ok(())
 62        })
 63        .await
 64    }
 65
 66    /// Returns the billing subscription with the specified ID.
 67    pub async fn get_billing_subscription_by_id(
 68        &self,
 69        id: BillingSubscriptionId,
 70    ) -> Result<Option<billing_subscription::Model>> {
 71        self.transaction(|tx| async move {
 72            Ok(billing_subscription::Entity::find_by_id(id)
 73                .one(&*tx)
 74                .await?)
 75        })
 76        .await
 77    }
 78
 79    /// Returns the billing subscription with the specified Stripe subscription ID.
 80    pub async fn get_billing_subscription_by_stripe_subscription_id(
 81        &self,
 82        stripe_subscription_id: &str,
 83    ) -> Result<Option<billing_subscription::Model>> {
 84        self.transaction(|tx| async move {
 85            Ok(billing_subscription::Entity::find()
 86                .filter(
 87                    billing_subscription::Column::StripeSubscriptionId.eq(stripe_subscription_id),
 88                )
 89                .one(&*tx)
 90                .await?)
 91        })
 92        .await
 93    }
 94
 95    /// Returns all of the billing subscriptions for the user with the specified ID.
 96    ///
 97    /// Note that this returns the subscriptions regardless of their status.
 98    /// If you're wanting to check if a use has an active billing subscription,
 99    /// use `get_active_billing_subscriptions` instead.
100    pub async fn get_billing_subscriptions(
101        &self,
102        user_id: UserId,
103    ) -> Result<Vec<billing_subscription::Model>> {
104        self.transaction(|tx| async move {
105            let subscriptions = billing_subscription::Entity::find()
106                .inner_join(billing_customer::Entity)
107                .filter(billing_customer::Column::UserId.eq(user_id))
108                .order_by_asc(billing_subscription::Column::Id)
109                .all(&*tx)
110                .await?;
111
112            Ok(subscriptions)
113        })
114        .await
115    }
116
117    pub async fn get_active_billing_subscriptions(
118        &self,
119        user_ids: HashSet<UserId>,
120    ) -> Result<HashMap<UserId, (billing_customer::Model, billing_subscription::Model)>> {
121        self.transaction(|tx| {
122            let user_ids = user_ids.clone();
123            async move {
124                let mut rows = billing_subscription::Entity::find()
125                    .inner_join(billing_customer::Entity)
126                    .select_also(billing_customer::Entity)
127                    .filter(billing_customer::Column::UserId.is_in(user_ids))
128                    .filter(
129                        billing_subscription::Column::StripeSubscriptionStatus
130                            .eq(StripeSubscriptionStatus::Active),
131                    )
132                    .order_by_asc(billing_subscription::Column::Id)
133                    .stream(&*tx)
134                    .await?;
135
136                let mut subscriptions = HashMap::default();
137                while let Some(row) = rows.next().await {
138                    if let (subscription, Some(customer)) = row? {
139                        subscriptions.insert(customer.user_id, (customer, subscription));
140                    }
141                }
142                Ok(subscriptions)
143            }
144        })
145        .await
146    }
147
148    /// Returns whether the user has an active billing subscription.
149    pub async fn has_active_billing_subscription(&self, user_id: UserId) -> Result<bool> {
150        Ok(self.count_active_billing_subscriptions(user_id).await? > 0)
151    }
152
153    /// Returns the count of the active billing subscriptions for the user with the specified ID.
154    pub async fn count_active_billing_subscriptions(&self, user_id: UserId) -> Result<usize> {
155        self.transaction(|tx| async move {
156            let count = billing_subscription::Entity::find()
157                .inner_join(billing_customer::Entity)
158                .filter(
159                    billing_customer::Column::UserId.eq(user_id).and(
160                        billing_subscription::Column::StripeSubscriptionStatus
161                            .eq(StripeSubscriptionStatus::Active),
162                    ),
163                )
164                .count(&*tx)
165                .await?;
166
167            Ok(count as usize)
168        })
169        .await
170    }
171}