billing.rs

 1use std::sync::Arc;
 2use stripe::SubscriptionStatus;
 3
 4use crate::AppState;
 5use crate::db::billing_subscription::StripeSubscriptionStatus;
 6use crate::db::{CreateBillingCustomerParams, billing_customer};
 7use crate::stripe_client::{StripeClient, StripeCustomerId};
 8
 9impl From<SubscriptionStatus> for StripeSubscriptionStatus {
10    fn from(value: SubscriptionStatus) -> Self {
11        match value {
12            SubscriptionStatus::Incomplete => Self::Incomplete,
13            SubscriptionStatus::IncompleteExpired => Self::IncompleteExpired,
14            SubscriptionStatus::Trialing => Self::Trialing,
15            SubscriptionStatus::Active => Self::Active,
16            SubscriptionStatus::PastDue => Self::PastDue,
17            SubscriptionStatus::Canceled => Self::Canceled,
18            SubscriptionStatus::Unpaid => Self::Unpaid,
19            SubscriptionStatus::Paused => Self::Paused,
20        }
21    }
22}
23
24/// Finds or creates a billing customer using the provided customer.
25pub async fn find_or_create_billing_customer(
26    app: &Arc<AppState>,
27    stripe_client: &dyn StripeClient,
28    customer_id: &StripeCustomerId,
29) -> anyhow::Result<Option<billing_customer::Model>> {
30    // If we already have a billing customer record associated with the Stripe customer,
31    // there's nothing more we need to do.
32    if let Some(billing_customer) = app
33        .db
34        .get_billing_customer_by_stripe_customer_id(customer_id.0.as_ref())
35        .await?
36    {
37        return Ok(Some(billing_customer));
38    }
39
40    let customer = stripe_client.get_customer(customer_id).await?;
41
42    let Some(email) = customer.email else {
43        return Ok(None);
44    };
45
46    let Some(user) = app.db.get_user_by_email(&email).await? else {
47        return Ok(None);
48    };
49
50    let billing_customer = app
51        .db
52        .create_billing_customer(&CreateBillingCustomerParams {
53            user_id: user.id,
54            stripe_customer_id: customer.id.to_string(),
55        })
56        .await?;
57
58    Ok(Some(billing_customer))
59}