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