billing_subscriptions.rs

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