collab: Check if the user has a payment method before upgrading to Zed Pro (#30310)

This PR adds a check for if the user has a payment method before
attempting to upgrade them to Zed Pro.

Release Notes:

- N/A
This commit is contained in:
Marshall Bowers 2025-05-08 16:58:36 -04:00 committed by GitHub
parent 8b764a5477
commit 822580cb12
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -18,7 +18,8 @@ use stripe::{
CreateBillingPortalSessionFlowDataSubscriptionUpdateConfirm,
CreateBillingPortalSessionFlowDataSubscriptionUpdateConfirmItems,
CreateBillingPortalSessionFlowDataType, CreateCustomer, Customer, CustomerId, EventObject,
EventType, Expandable, ListEvents, Subscription, SubscriptionId, SubscriptionStatus,
EventType, Expandable, ListEvents, PaymentMethod, Subscription, SubscriptionId,
SubscriptionStatus,
};
use util::{ResultExt, maybe};
@ -445,6 +446,7 @@ struct ManageBillingSubscriptionBody {
intent: ManageSubscriptionIntent,
/// The ID of the subscription to manage.
subscription_id: BillingSubscriptionId,
redirect_to: Option<String>,
}
#[derive(Debug, Serialize)]
@ -542,6 +544,23 @@ async fn manage_billing_subscription(
.map_or(false, |price| price.id == zed_pro_price_id)
});
if is_on_zed_pro_trial {
let payment_methods = PaymentMethod::list(
&stripe_client,
&stripe::ListPaymentMethods {
customer: Some(stripe_subscription.customer.id()),
..Default::default()
},
)
.await?;
let has_payment_method = !payment_methods.data.is_empty();
if !has_payment_method {
return Err(Error::http(
StatusCode::BAD_REQUEST,
"missing payment method".into(),
));
}
// If the user is already on a Zed Pro trial and wants to upgrade to Pro, we just need to end their trial early.
Subscription::update(
&stripe_client,
@ -596,7 +615,11 @@ async fn manage_billing_subscription(
after_completion: Some(CreateBillingPortalSessionFlowDataAfterCompletion {
type_: stripe::CreateBillingPortalSessionFlowDataAfterCompletionType::Redirect,
redirect: Some(CreateBillingPortalSessionFlowDataAfterCompletionRedirect {
return_url: format!("{}/account", app.config.zed_dot_dev_url()),
return_url: format!(
"{}{path}",
app.config.zed_dot_dev_url(),
path = body.redirect_to.unwrap_or_else(|| "/account".to_string())
),
}),
..Default::default()
}),