diff --git a/config/locales/en.yml b/config/locales/en.yml index ce52530c6..59ba6c960 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -172,6 +172,7 @@ en: unsupported_currency: This currency is not supported same_currency: This account is already billed in the selected currency stripe_customer_not_configured: Stripe customer not configured + past_due_subscription: Please settle the outstanding payment before switching currency unknown_plan: Could not determine the current plan currency_not_available_for_plan: The selected currency is not available for your current plan no_payment_method: No payment methods found. Please add a payment method before switching currency. diff --git a/enterprise/app/services/enterprise/billing/switch_currency_service.rb b/enterprise/app/services/enterprise/billing/switch_currency_service.rb index 7760534b4..67c52ce75 100644 --- a/enterprise/app/services/enterprise/billing/switch_currency_service.rb +++ b/enterprise/app/services/enterprise/billing/switch_currency_service.rb @@ -10,6 +10,7 @@ class Enterprise::Billing::SwitchCurrencyService def perform validate! + reject_past_due_paid_subscription! subscriptions = live_subscriptions paid_subscription = subscriptions.find { |subscription| !default_price?(subscription) } @@ -130,10 +131,19 @@ class Enterprise::Billing::SwitchCurrencyService ) end - # Includes trialing (a prior switch leaves the new sub trialing); excludes past_due so a delinquent account can't switch to restore access unpaid. + # Block the switch while a paid sub is past_due, else the account currency/location changes but the unpaid sub stays in the old currency. + def reject_past_due_paid_subscription! + past_due = all_subscriptions.any? { |subscription| subscription.status == 'past_due' && !default_price?(subscription) } + raise Error, I18n.t('errors.billing.past_due_subscription') if past_due + end + + def all_subscriptions + @all_subscriptions ||= Stripe::Subscription.list(customer: stripe_customer_id, status: 'all', limit: 100).data + end + + # Includes trialing (a prior switch leaves the new sub trialing); excludes past_due, which is handled by reject_past_due_paid_subscription!. def live_subscriptions - Stripe::Subscription.list(customer: stripe_customer_id, status: 'all', limit: 100).data - .select { |subscription| %w[active trialing].include?(subscription.status) } + all_subscriptions.select { |subscription| %w[active trialing].include?(subscription.status) } end def validate_payment_method!