collab: Remove unused StripeBilling
methods (#35740)
This PR removes some unused methods from the `StripeBilling` object. Release Notes: - N/A
This commit is contained in:
parent
740597492b
commit
b08e26df60
2 changed files with 4 additions and 341 deletions
|
@ -1,21 +1,15 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use anyhow::anyhow;
|
||||
use chrono::Utc;
|
||||
use collections::HashMap;
|
||||
use stripe::SubscriptionStatus;
|
||||
use tokio::sync::RwLock;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::Result;
|
||||
use crate::db::billing_subscription::SubscriptionKind;
|
||||
use crate::stripe_client::{
|
||||
RealStripeClient, StripeAutomaticTax, StripeClient, StripeCreateMeterEventParams,
|
||||
StripeCreateMeterEventPayload, StripeCreateSubscriptionItems, StripeCreateSubscriptionParams,
|
||||
StripeCustomerId, StripePrice, StripePriceId, StripeSubscription, StripeSubscriptionId,
|
||||
StripeSubscriptionTrialSettings, StripeSubscriptionTrialSettingsEndBehavior,
|
||||
StripeSubscriptionTrialSettingsEndBehaviorMissingPaymentMethod, UpdateSubscriptionItems,
|
||||
UpdateSubscriptionParams,
|
||||
RealStripeClient, StripeAutomaticTax, StripeClient, StripeCreateSubscriptionItems,
|
||||
StripeCreateSubscriptionParams, StripeCustomerId, StripePrice, StripePriceId,
|
||||
StripeSubscription,
|
||||
};
|
||||
|
||||
pub struct StripeBilling {
|
||||
|
@ -94,30 +88,6 @@ impl StripeBilling {
|
|||
.ok_or_else(|| crate::Error::Internal(anyhow!("no price found for {lookup_key:?}")))
|
||||
}
|
||||
|
||||
pub async fn determine_subscription_kind(
|
||||
&self,
|
||||
subscription: &StripeSubscription,
|
||||
) -> Option<SubscriptionKind> {
|
||||
let zed_pro_price_id = self.zed_pro_price_id().await.ok()?;
|
||||
let zed_free_price_id = self.zed_free_price_id().await.ok()?;
|
||||
|
||||
subscription.items.iter().find_map(|item| {
|
||||
let price = item.price.as_ref()?;
|
||||
|
||||
if price.id == zed_pro_price_id {
|
||||
Some(if subscription.status == SubscriptionStatus::Trialing {
|
||||
SubscriptionKind::ZedProTrial
|
||||
} else {
|
||||
SubscriptionKind::ZedPro
|
||||
})
|
||||
} else if price.id == zed_free_price_id {
|
||||
Some(SubscriptionKind::ZedFree)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the Stripe customer associated with the provided email address, or creates a new customer, if one does
|
||||
/// not already exist.
|
||||
///
|
||||
|
@ -150,65 +120,6 @@ impl StripeBilling {
|
|||
Ok(customer_id)
|
||||
}
|
||||
|
||||
pub async fn subscribe_to_price(
|
||||
&self,
|
||||
subscription_id: &StripeSubscriptionId,
|
||||
price: &StripePrice,
|
||||
) -> Result<()> {
|
||||
let subscription = self.client.get_subscription(subscription_id).await?;
|
||||
|
||||
if subscription_contains_price(&subscription, &price.id) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
const BILLING_THRESHOLD_IN_CENTS: i64 = 20 * 100;
|
||||
|
||||
let price_per_unit = price.unit_amount.unwrap_or_default();
|
||||
let _units_for_billing_threshold = BILLING_THRESHOLD_IN_CENTS / price_per_unit;
|
||||
|
||||
self.client
|
||||
.update_subscription(
|
||||
subscription_id,
|
||||
UpdateSubscriptionParams {
|
||||
items: Some(vec![UpdateSubscriptionItems {
|
||||
price: Some(price.id.clone()),
|
||||
}]),
|
||||
trial_settings: Some(StripeSubscriptionTrialSettings {
|
||||
end_behavior: StripeSubscriptionTrialSettingsEndBehavior {
|
||||
missing_payment_method: StripeSubscriptionTrialSettingsEndBehaviorMissingPaymentMethod::Cancel
|
||||
},
|
||||
}),
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn bill_model_request_usage(
|
||||
&self,
|
||||
customer_id: &StripeCustomerId,
|
||||
event_name: &str,
|
||||
requests: i32,
|
||||
) -> Result<()> {
|
||||
let timestamp = Utc::now().timestamp();
|
||||
let idempotency_key = Uuid::new_v4();
|
||||
|
||||
self.client
|
||||
.create_meter_event(StripeCreateMeterEventParams {
|
||||
identifier: &format!("model_requests/{}", idempotency_key),
|
||||
event_name,
|
||||
payload: StripeCreateMeterEventPayload {
|
||||
value: requests as u64,
|
||||
stripe_customer_id: customer_id,
|
||||
},
|
||||
timestamp: Some(timestamp),
|
||||
})
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn subscribe_to_zed_free(
|
||||
&self,
|
||||
customer_id: StripeCustomerId,
|
||||
|
@ -243,14 +154,3 @@ impl StripeBilling {
|
|||
Ok(subscription)
|
||||
}
|
||||
}
|
||||
|
||||
fn subscription_contains_price(
|
||||
subscription: &StripeSubscription,
|
||||
price_id: &StripePriceId,
|
||||
) -> bool {
|
||||
subscription.items.iter().any(|item| {
|
||||
item.price
|
||||
.as_ref()
|
||||
.map_or(false, |price| price.id == *price_id)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,14 +1,9 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use chrono::{Duration, Utc};
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use crate::stripe_billing::StripeBilling;
|
||||
use crate::stripe_client::{
|
||||
FakeStripeClient, StripeCustomerId, StripeMeter, StripeMeterId, StripePrice, StripePriceId,
|
||||
StripePriceRecurring, StripeSubscription, StripeSubscriptionId, StripeSubscriptionItem,
|
||||
StripeSubscriptionItemId, UpdateSubscriptionItems,
|
||||
};
|
||||
use crate::stripe_client::{FakeStripeClient, StripePrice, StripePriceId, StripePriceRecurring};
|
||||
|
||||
fn make_stripe_billing() -> (StripeBilling, Arc<FakeStripeClient>) {
|
||||
let stripe_client = Arc::new(FakeStripeClient::new());
|
||||
|
@ -21,24 +16,6 @@ fn make_stripe_billing() -> (StripeBilling, Arc<FakeStripeClient>) {
|
|||
async fn test_initialize() {
|
||||
let (stripe_billing, stripe_client) = make_stripe_billing();
|
||||
|
||||
// Add test meters
|
||||
let meter1 = StripeMeter {
|
||||
id: StripeMeterId("meter_1".into()),
|
||||
event_name: "event_1".to_string(),
|
||||
};
|
||||
let meter2 = StripeMeter {
|
||||
id: StripeMeterId("meter_2".into()),
|
||||
event_name: "event_2".to_string(),
|
||||
};
|
||||
stripe_client
|
||||
.meters
|
||||
.lock()
|
||||
.insert(meter1.id.clone(), meter1);
|
||||
stripe_client
|
||||
.meters
|
||||
.lock()
|
||||
.insert(meter2.id.clone(), meter2);
|
||||
|
||||
// Add test prices
|
||||
let price1 = StripePrice {
|
||||
id: StripePriceId("price_1".into()),
|
||||
|
@ -144,217 +121,3 @@ async fn test_find_or_create_customer_by_email() {
|
|||
assert_eq!(customer.email.as_deref(), Some(email));
|
||||
}
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_subscribe_to_price() {
|
||||
let (stripe_billing, stripe_client) = make_stripe_billing();
|
||||
|
||||
let price = StripePrice {
|
||||
id: StripePriceId("price_test".into()),
|
||||
unit_amount: Some(2000),
|
||||
lookup_key: Some("test-price".to_string()),
|
||||
recurring: None,
|
||||
};
|
||||
stripe_client
|
||||
.prices
|
||||
.lock()
|
||||
.insert(price.id.clone(), price.clone());
|
||||
|
||||
let now = Utc::now();
|
||||
let subscription = StripeSubscription {
|
||||
id: StripeSubscriptionId("sub_test".into()),
|
||||
customer: StripeCustomerId("cus_test".into()),
|
||||
status: stripe::SubscriptionStatus::Active,
|
||||
current_period_start: now.timestamp(),
|
||||
current_period_end: (now + Duration::days(30)).timestamp(),
|
||||
items: vec![],
|
||||
cancel_at: None,
|
||||
cancellation_details: None,
|
||||
};
|
||||
stripe_client
|
||||
.subscriptions
|
||||
.lock()
|
||||
.insert(subscription.id.clone(), subscription.clone());
|
||||
|
||||
stripe_billing
|
||||
.subscribe_to_price(&subscription.id, &price)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let update_subscription_calls = stripe_client
|
||||
.update_subscription_calls
|
||||
.lock()
|
||||
.iter()
|
||||
.map(|(id, params)| (id.clone(), params.clone()))
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(update_subscription_calls.len(), 1);
|
||||
assert_eq!(update_subscription_calls[0].0, subscription.id);
|
||||
assert_eq!(
|
||||
update_subscription_calls[0].1.items,
|
||||
Some(vec![UpdateSubscriptionItems {
|
||||
price: Some(price.id.clone())
|
||||
}])
|
||||
);
|
||||
|
||||
// Subscribing to a price that is already on the subscription is a no-op.
|
||||
{
|
||||
let now = Utc::now();
|
||||
let subscription = StripeSubscription {
|
||||
id: StripeSubscriptionId("sub_test".into()),
|
||||
customer: StripeCustomerId("cus_test".into()),
|
||||
status: stripe::SubscriptionStatus::Active,
|
||||
current_period_start: now.timestamp(),
|
||||
current_period_end: (now + Duration::days(30)).timestamp(),
|
||||
items: vec![StripeSubscriptionItem {
|
||||
id: StripeSubscriptionItemId("si_test".into()),
|
||||
price: Some(price.clone()),
|
||||
}],
|
||||
cancel_at: None,
|
||||
cancellation_details: None,
|
||||
};
|
||||
stripe_client
|
||||
.subscriptions
|
||||
.lock()
|
||||
.insert(subscription.id.clone(), subscription.clone());
|
||||
|
||||
stripe_billing
|
||||
.subscribe_to_price(&subscription.id, &price)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(stripe_client.update_subscription_calls.lock().len(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_subscribe_to_zed_free() {
|
||||
let (stripe_billing, stripe_client) = make_stripe_billing();
|
||||
|
||||
let zed_pro_price = StripePrice {
|
||||
id: StripePriceId("price_1".into()),
|
||||
unit_amount: Some(0),
|
||||
lookup_key: Some("zed-pro".to_string()),
|
||||
recurring: None,
|
||||
};
|
||||
stripe_client
|
||||
.prices
|
||||
.lock()
|
||||
.insert(zed_pro_price.id.clone(), zed_pro_price.clone());
|
||||
let zed_free_price = StripePrice {
|
||||
id: StripePriceId("price_2".into()),
|
||||
unit_amount: Some(0),
|
||||
lookup_key: Some("zed-free".to_string()),
|
||||
recurring: None,
|
||||
};
|
||||
stripe_client
|
||||
.prices
|
||||
.lock()
|
||||
.insert(zed_free_price.id.clone(), zed_free_price.clone());
|
||||
|
||||
stripe_billing.initialize().await.unwrap();
|
||||
|
||||
// Customer is subscribed to Zed Free when not already subscribed to a plan.
|
||||
{
|
||||
let customer_id = StripeCustomerId("cus_no_plan".into());
|
||||
|
||||
let subscription = stripe_billing
|
||||
.subscribe_to_zed_free(customer_id)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(subscription.items[0].price.as_ref(), Some(&zed_free_price));
|
||||
}
|
||||
|
||||
// Customer is not subscribed to Zed Free when they already have an active subscription.
|
||||
{
|
||||
let customer_id = StripeCustomerId("cus_active_subscription".into());
|
||||
|
||||
let now = Utc::now();
|
||||
let existing_subscription = StripeSubscription {
|
||||
id: StripeSubscriptionId("sub_existing_active".into()),
|
||||
customer: customer_id.clone(),
|
||||
status: stripe::SubscriptionStatus::Active,
|
||||
current_period_start: now.timestamp(),
|
||||
current_period_end: (now + Duration::days(30)).timestamp(),
|
||||
items: vec![StripeSubscriptionItem {
|
||||
id: StripeSubscriptionItemId("si_test".into()),
|
||||
price: Some(zed_pro_price.clone()),
|
||||
}],
|
||||
cancel_at: None,
|
||||
cancellation_details: None,
|
||||
};
|
||||
stripe_client.subscriptions.lock().insert(
|
||||
existing_subscription.id.clone(),
|
||||
existing_subscription.clone(),
|
||||
);
|
||||
|
||||
let subscription = stripe_billing
|
||||
.subscribe_to_zed_free(customer_id)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(subscription, existing_subscription);
|
||||
}
|
||||
|
||||
// Customer is not subscribed to Zed Free when they already have a trial subscription.
|
||||
{
|
||||
let customer_id = StripeCustomerId("cus_trial_subscription".into());
|
||||
|
||||
let now = Utc::now();
|
||||
let existing_subscription = StripeSubscription {
|
||||
id: StripeSubscriptionId("sub_existing_trial".into()),
|
||||
customer: customer_id.clone(),
|
||||
status: stripe::SubscriptionStatus::Trialing,
|
||||
current_period_start: now.timestamp(),
|
||||
current_period_end: (now + Duration::days(14)).timestamp(),
|
||||
items: vec![StripeSubscriptionItem {
|
||||
id: StripeSubscriptionItemId("si_test".into()),
|
||||
price: Some(zed_pro_price.clone()),
|
||||
}],
|
||||
cancel_at: None,
|
||||
cancellation_details: None,
|
||||
};
|
||||
stripe_client.subscriptions.lock().insert(
|
||||
existing_subscription.id.clone(),
|
||||
existing_subscription.clone(),
|
||||
);
|
||||
|
||||
let subscription = stripe_billing
|
||||
.subscribe_to_zed_free(customer_id)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(subscription, existing_subscription);
|
||||
}
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_bill_model_request_usage() {
|
||||
let (stripe_billing, stripe_client) = make_stripe_billing();
|
||||
|
||||
let customer_id = StripeCustomerId("cus_test".into());
|
||||
|
||||
stripe_billing
|
||||
.bill_model_request_usage(&customer_id, "some_model/requests", 73)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let create_meter_event_calls = stripe_client
|
||||
.create_meter_event_calls
|
||||
.lock()
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(create_meter_event_calls.len(), 1);
|
||||
assert!(
|
||||
create_meter_event_calls[0]
|
||||
.identifier
|
||||
.starts_with("model_requests/")
|
||||
);
|
||||
assert_eq!(create_meter_event_calls[0].stripe_customer_id, customer_id);
|
||||
assert_eq!(
|
||||
create_meter_event_calls[0].event_name.as_ref(),
|
||||
"some_model/requests"
|
||||
);
|
||||
assert_eq!(create_meter_event_calls[0].value, 73);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue