From 84a28e045beff088d439477e45ea0eb26c5d22c1 Mon Sep 17 00:00:00 2001 From: Emma Alexia Date: Sat, 19 Apr 2025 00:39:18 -0400 Subject: [PATCH] Allow servers to be unprovisioned without issuing a refund (#3534) * Allow servers to be unprovisioned without issuing a refund for very specific weird circumstances where a server gets stuck/etc; useful for support * still create a charge * Fix compile --- .../frontend/src/pages/admin/billing/[id].vue | 2 +- apps/labrinth/src/routes/internal/billing.rs | 86 ++++++++++--------- 2 files changed, 48 insertions(+), 40 deletions(-) diff --git a/apps/frontend/src/pages/admin/billing/[id].vue b/apps/frontend/src/pages/admin/billing/[id].vue index 235c9a53f..79bbdf2ab 100644 --- a/apps/frontend/src/pages/admin/billing/[id].vue +++ b/apps/frontend/src/pages/admin/billing/[id].vue @@ -277,7 +277,7 @@ const refunding = ref(false); const refundModal = ref(); const selectedCharge = ref(null); const refundType = ref("full"); -const refundTypes = ref(["full", "partial"]); +const refundTypes = ref(["full", "partial", "none"]); const refundAmount = ref(0); const unprovision = ref(false); diff --git a/apps/labrinth/src/routes/internal/billing.rs b/apps/labrinth/src/routes/internal/billing.rs index a92a51661..7ef810286 100644 --- a/apps/labrinth/src/routes/internal/billing.rs +++ b/apps/labrinth/src/routes/internal/billing.rs @@ -135,6 +135,7 @@ pub async fn subscriptions( pub enum ChargeRefundAmount { Full, Partial { amount: u64 }, + None, } #[derive(Deserialize)] @@ -189,6 +190,7 @@ pub async fn refund_charge( let refund_amount = match body.0.amount { ChargeRefundAmount::Full => refundable, ChargeRefundAmount::Partial { amount } => amount as i64, + ChargeRefundAmount::None => 0, }; if charge.status != ChargeStatus::Succeeded { @@ -197,55 +199,61 @@ pub async fn refund_charge( )); } - if (refundable - refund_amount) < 0 || refund_amount == 0 { + if (refundable - refund_amount) < 0 { return Err(ApiError::InvalidInput( "You cannot refund more than the amount of the charge!" .to_string(), )); } - let (id, net) = match charge.payment_platform { - PaymentPlatform::Stripe => { - if let Some(payment_platform_id) = charge - .payment_platform_id - .and_then(|x| stripe::PaymentIntentId::from_str(&x).ok()) - { - let mut metadata = HashMap::new(); + let (id, net) = if refund_amount != 0 { + (None, None) + } else { + match charge.payment_platform { + PaymentPlatform::Stripe => { + if let Some(payment_platform_id) = + charge.payment_platform_id.and_then(|x| { + stripe::PaymentIntentId::from_str(&x).ok() + }) + { + let mut metadata = HashMap::new(); - metadata.insert( - "modrinth_user_id".to_string(), - to_base62(user.id.0), - ); - metadata.insert( - "modrinth_charge_id".to_string(), - to_base62(charge.id.0 as u64), - ); + metadata.insert( + "modrinth_user_id".to_string(), + to_base62(user.id.0), + ); + metadata.insert( + "modrinth_charge_id".to_string(), + to_base62(charge.id.0 as u64), + ); - let refund = stripe::Refund::create( - &stripe_client, - CreateRefund { - amount: Some(refund_amount), - metadata: Some(metadata), - payment_intent: Some(payment_platform_id), + let refund = stripe::Refund::create( + &stripe_client, + CreateRefund { + amount: Some(refund_amount), + metadata: Some(metadata), + payment_intent: Some(payment_platform_id), - expand: &["balance_transaction"], + expand: &["balance_transaction"], - ..Default::default() - }, - ) - .await?; + ..Default::default() + }, + ) + .await?; - ( - refund.id.to_string(), - refund - .balance_transaction - .and_then(|x| x.into_object()) - .map(|x| x.net), - ) - } else { - return Err(ApiError::InvalidInput( - "Charge does not have attached payment id!".to_string(), - )); + ( + Some(refund.id.to_string()), + refund + .balance_transaction + .and_then(|x| x.into_object()) + .map(|x| x.net), + ) + } else { + return Err(ApiError::InvalidInput( + "Charge does not have attached payment id!" + .to_string(), + )); + } } } }; @@ -266,7 +274,7 @@ pub async fn refund_charge( subscription_id: charge.subscription_id, subscription_interval: charge.subscription_interval, payment_platform: charge.payment_platform, - payment_platform_id: Some(id), + payment_platform_id: id, parent_charge_id: Some(charge.id), net, }