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 ) -> Result<Vec<(billing_customer::Model, billing_subscription::Model)>> {
118 self.transaction(|tx| async move {
119 let mut result = Vec::new();
120 let mut rows = billing_subscription::Entity::find()
121 .inner_join(billing_customer::Entity)
122 .select_also(billing_customer::Entity)
123 .order_by_asc(billing_subscription::Column::Id)
124 .stream(&*tx)
125 .await?;
126
127 while let Some(row) = rows.next().await {
128 if let (subscription, Some(customer)) = row? {
129 result.push((customer, subscription));
130 }
131 }
132
133 Ok(result)
134 })
135 .await
136 }
137
138 /// Returns whether the user has an active billing subscription.
139 pub async fn has_active_billing_subscription(&self, user_id: UserId) -> Result<bool> {
140 Ok(self.count_active_billing_subscriptions(user_id).await? > 0)
141 }
142
143 /// Returns the count of the active billing subscriptions for the user with the specified ID.
144 pub async fn count_active_billing_subscriptions(&self, user_id: UserId) -> Result<usize> {
145 self.transaction(|tx| async move {
146 let count = billing_subscription::Entity::find()
147 .inner_join(billing_customer::Entity)
148 .filter(
149 billing_customer::Column::UserId.eq(user_id).and(
150 billing_subscription::Column::StripeSubscriptionStatus
151 .eq(StripeSubscriptionStatus::Active),
152 ),
153 )
154 .count(&*tx)
155 .await?;
156
157 Ok(count as usize)
158 })
159 .await
160 }
161}