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}