feat(cloud-billing): cancel subscriptions at period end on deletion mark (#13580)
## How to reproduce In Chatwoot Cloud, mark an account for deletion from account settings while the account has an active Stripe subscription. Before this change, deletion marking did not explicitly mark subscriptions to stop renewing at period end. ## What changed This PR adds `Enterprise::Billing::CancelCloudSubscriptionsService` and calls it from the delete action path in `Enterprise::Api::V1::AccountsController`. The service lists only active Stripe subscriptions for the customer and sets `cancel_at_period_end: true` when needed. The account deletion schedule remains unchanged (existing static 7-day behavior), and Stripe deleted-event fallback behavior remains unchanged. ## How this was tested Added and updated specs: - `spec/enterprise/services/enterprise/billing/cancel_cloud_subscriptions_service_spec.rb` - `spec/enterprise/controllers/enterprise/api/v1/accounts_controller_spec.rb` Executed: - `bundle exec rspec spec/enterprise/services/enterprise/billing/cancel_cloud_subscriptions_service_spec.rb` - `bundle exec rspec spec/enterprise/controllers/enterprise/api/v1/accounts_controller_spec.rb:363`
This commit is contained in:
@@ -102,6 +102,8 @@ class Enterprise::Api::V1::AccountsController < Api::BaseController
|
||||
reason = 'manual_deletion'
|
||||
|
||||
if @account.mark_for_deletion(reason)
|
||||
cancel_cloud_subscriptions_for_deletion
|
||||
|
||||
render json: { message: 'Account marked for deletion' }, status: :ok
|
||||
else
|
||||
render json: { message: @account.errors.full_messages.join(', ') }, status: :unprocessable_entity
|
||||
@@ -125,6 +127,12 @@ class Enterprise::Api::V1::AccountsController < Api::BaseController
|
||||
render_redirect_url(session.url)
|
||||
end
|
||||
|
||||
def cancel_cloud_subscriptions_for_deletion
|
||||
Enterprise::Billing::CancelCloudSubscriptionsService.new(account: @account).perform
|
||||
rescue Stripe::StripeError => e
|
||||
Rails.logger.warn("Failed to cancel cloud subscriptions for account #{@account.id}: #{e.class} - #{e.message}")
|
||||
end
|
||||
|
||||
def render_redirect_url(redirect_url)
|
||||
render json: { redirect_url: redirect_url }
|
||||
end
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
class Enterprise::Billing::CancelCloudSubscriptionsService
|
||||
pattr_initialize [:account!]
|
||||
|
||||
def perform
|
||||
return if stripe_customer_id.blank?
|
||||
return unless ChatwootApp.chatwoot_cloud?
|
||||
|
||||
subscriptions.each do |subscription|
|
||||
next if subscription.cancel_at_period_end
|
||||
|
||||
Stripe::Subscription.update(subscription.id, cancel_at_period_end: true)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def subscriptions
|
||||
Stripe::Subscription.list(customer: stripe_customer_id, status: 'active', limit: 100).data
|
||||
end
|
||||
|
||||
def stripe_customer_id
|
||||
account.custom_attributes['stripe_customer_id']
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user