From fade49a11ae44f9608d9c6cc4fa32fa934c52169 Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Thu, 17 Apr 2025 13:44:14 -0400 Subject: [PATCH] collab: Don't use a separate product for Zed Pro trials (#28986) This PR removes the separate product used for the Zed Pro trials, in favor of using Stripe's trial functionality. Release Notes: - N/A --- crates/collab/src/api/billing.rs | 19 +++++++++++-------- crates/collab/src/lib.rs | 7 ------- crates/collab/src/stripe_billing.rs | 26 ++++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/crates/collab/src/api/billing.rs b/crates/collab/src/api/billing.rs index ad8e1f662d..fd346c90e2 100644 --- a/crates/collab/src/api/billing.rs +++ b/crates/collab/src/api/billing.rs @@ -321,8 +321,8 @@ async fn create_billing_subscription( } Some(ProductCode::ZedProTrial) => { stripe_billing - .checkout_with_price( - app.config.zed_pro_trial_price_id()?, + .checkout_with_zed_pro_trial( + app.config.zed_pro_price_id()?, customer_id, &user.github_login, &success_url, @@ -444,7 +444,6 @@ async fn manage_billing_subscription( ManageSubscriptionIntent::ManageSubscription => None, ManageSubscriptionIntent::UpgradeToPro => { let zed_pro_price_id = app.config.zed_pro_price_id()?; - let zed_pro_trial_price_id = app.config.zed_pro_trial_price_id()?; let zed_free_price_id = app.config.zed_free_price_id()?; let stripe_subscription = @@ -457,7 +456,10 @@ async fn manage_billing_subscription( .find_map(|item| { let price = item.price.as_ref()?; - if price.id == zed_free_price_id || price.id == zed_pro_trial_price_id { + if price.id == zed_free_price_id + || (price.id == zed_pro_price_id + && stripe_subscription.status == SubscriptionStatus::Trialing) + { Some(item.id.clone()) } else { None @@ -771,16 +773,17 @@ async fn handle_customer_subscription_event( let subscription_kind = maybe!({ let zed_pro_price_id = app.config.zed_pro_price_id().ok()?; - let zed_pro_trial_price_id = app.config.zed_pro_trial_price_id().ok()?; let zed_free_price_id = app.config.zed_free_price_id().ok()?; subscription.items.data.iter().find_map(|item| { let price = item.price.as_ref()?; if price.id == zed_pro_price_id { - Some(SubscriptionKind::ZedPro) - } else if price.id == zed_pro_trial_price_id { - Some(SubscriptionKind::ZedProTrial) + Some(if subscription.status == SubscriptionStatus::Trialing { + SubscriptionKind::ZedProTrial + } else { + SubscriptionKind::ZedPro + }) } else if price.id == zed_free_price_id { Some(SubscriptionKind::ZedFree) } else { diff --git a/crates/collab/src/lib.rs b/crates/collab/src/lib.rs index f697e01e43..9e2e967eb8 100644 --- a/crates/collab/src/lib.rs +++ b/crates/collab/src/lib.rs @@ -207,13 +207,6 @@ impl Config { Self::parse_stripe_price_id("Zed Pro", self.stripe_zed_pro_price_id.as_deref()) } - pub fn zed_pro_trial_price_id(&self) -> anyhow::Result { - Self::parse_stripe_price_id( - "Zed Pro Trial", - self.stripe_zed_pro_trial_price_id.as_deref(), - ) - } - pub fn zed_free_price_id(&self) -> anyhow::Result { Self::parse_stripe_price_id("Zed Free", self.stripe_zed_pro_price_id.as_deref()) } diff --git a/crates/collab/src/stripe_billing.rs b/crates/collab/src/stripe_billing.rs index 44d27714ad..cedd8b7e19 100644 --- a/crates/collab/src/stripe_billing.rs +++ b/crates/collab/src/stripe_billing.rs @@ -405,6 +405,32 @@ impl StripeBilling { let session = stripe::CheckoutSession::create(&self.client, params).await?; Ok(session.url.context("no checkout session URL")?) } + + pub async fn checkout_with_zed_pro_trial( + &self, + zed_pro_price_id: PriceId, + customer_id: stripe::CustomerId, + github_login: &str, + success_url: &str, + ) -> Result { + let mut params = stripe::CreateCheckoutSession::new(); + params.subscription_data = Some(stripe::CreateCheckoutSessionSubscriptionData { + trial_period_days: Some(14), + ..Default::default() + }); + params.mode = Some(stripe::CheckoutSessionMode::Subscription); + params.customer = Some(customer_id); + params.client_reference_id = Some(github_login); + params.line_items = Some(vec![stripe::CreateCheckoutSessionLineItems { + price: Some(zed_pro_price_id.to_string()), + quantity: Some(1), + ..Default::default() + }]); + params.success_url = Some(success_url); + + let session = stripe::CheckoutSession::create(&self.client, params).await?; + Ok(session.url.context("no checkout session URL")?) + } } #[derive(Serialize)]