diff --git a/app/policies/account_policy.rb b/app/policies/account_policy.rb index bd8fc7b98..7a51fe1af 100644 --- a/app/policies/account_policy.rb +++ b/app/policies/account_policy.rb @@ -58,4 +58,21 @@ class AccountPolicy < ApplicationPolicy def change_pricing_plan? @account_user.administrator? end + + # V2 Billing API actions + def pricing_plans? + @account_user.administrator? + end + + def topup_options? + @account_user.administrator? + end + + def topup? + @account_user.administrator? + end + + def subscribe? + @account_user.administrator? + end end diff --git a/app/views/api/v1/models/_account.json.jbuilder b/app/views/api/v1/models/_account.json.jbuilder index 463db1cd3..8104865c6 100644 --- a/app/views/api/v1/models/_account.json.jbuilder +++ b/app/views/api/v1/models/_account.json.jbuilder @@ -5,8 +5,10 @@ if resource.custom_attributes.present? json.plan_name resource.custom_attributes['plan_name'] json.subscribed_quantity resource.custom_attributes['subscribed_quantity'] json.subscription_status resource.custom_attributes['subscription_status'] - json.subscription_ends_on resource.custom_attributes['subscription_ends_on'] + json.subscription_ends_at resource.custom_attributes['subscription_ends_at'] + json.subscription_cancelled_at resource.custom_attributes['subscription_cancelled_at'] if resource.custom_attributes['subscription_cancelled_at'].present? json.stripe_subscription_id resource.custom_attributes['stripe_subscription_id'] if resource.custom_attributes['stripe_subscription_id'].present? + json.stripe_plan_id resource.custom_attributes['stripe_plan_id'] if resource.custom_attributes['stripe_plan_id'].present? json.stripe_billing_version resource.custom_attributes['stripe_billing_version'] if resource.custom_attributes['stripe_billing_version'].present? json.stripe_customer_id resource.custom_attributes['stripe_customer_id'] if resource.custom_attributes['stripe_customer_id'].present? if resource.custom_attributes['pending_stripe_pricing_plan_id'].present? diff --git a/config/routes.rb b/config/routes.rb index 7c6bdcf27..a84db1282 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -444,7 +444,7 @@ Rails.application.routes.draw do namespace :v2 do resources :accounts, only: [] do - resource :billing, only: [] do + resource :billing, only: [], controller: 'billing' do get :credit_grants get :pricing_plans get :topup_options diff --git a/enterprise/app/controllers/enterprise/api/v2/billing_controller.rb b/enterprise/app/controllers/enterprise/api/v2/billing_controller.rb index 460c67bc4..bad22e3b1 100644 --- a/enterprise/app/controllers/enterprise/api/v2/billing_controller.rb +++ b/enterprise/app/controllers/enterprise/api/v2/billing_controller.rb @@ -1,6 +1,6 @@ class Enterprise::Api::V2::BillingController < Api::BaseController before_action :fetch_account - before_action :check_authorization + before_action :check_billing_authorization before_action :validate_topup_amount, only: [:topup] rescue_from StandardError, with: :render_error @@ -46,7 +46,10 @@ class Enterprise::Api::V2::BillingController < Api::BaseController def cancel_subscription service = Enterprise::Billing::V2::CancelSubscriptionService.new(account: @account) - result = service.cancel_subscription + result = service.cancel_subscription( + reason: params[:reason], + feedback: params[:feedback] + ) if result[:success] # Include account ID and updated attributes for frontend store update @@ -111,4 +114,8 @@ class Enterprise::Api::V2::BillingController < Api::BaseController def render_not_implemented(exception) render json: { error: exception.message }, status: :not_implemented end + + def check_billing_authorization + authorize(@account, "#{action_name}?".to_sym) + end end diff --git a/enterprise/app/services/enterprise/billing/v2/cancel_subscription_service.rb b/enterprise/app/services/enterprise/billing/v2/cancel_subscription_service.rb index 82f5d1b0b..b9aac176c 100644 --- a/enterprise/app/services/enterprise/billing/v2/cancel_subscription_service.rb +++ b/enterprise/app/services/enterprise/billing/v2/cancel_subscription_service.rb @@ -8,14 +8,16 @@ class Enterprise::Billing::V2::CancelSubscriptionService < Enterprise::Billing:: # Creates a deactivate billing intent for the pricing plan subscription # Subscription remains active until the end of the current billing period # + # @param reason [String] Optional cancellation reason + # @param feedback [String] Optional additional feedback # @return [Hash] { success:, cancel_at_period_end:, period_end:, message: } # - def cancel_subscription + def cancel_subscription(reason: nil, feedback: nil) with_locked_account do metadata = fetch_subscription_metadata intent_params = build_deactivate_params(metadata[:subscription_id], metadata[:cadence_id]) execute_billing_intent(intent_params) - update_account_status(metadata[:next_billing_date]) + update_account_status(metadata[:next_billing_date], reason: reason, feedback: feedback) build_success_response end rescue Stripe::StripeError => e @@ -40,14 +42,18 @@ class Enterprise::Billing::V2::CancelSubscriptionService < Enterprise::Billing:: } end - def update_account_status(next_billing_date) + def update_account_status(next_billing_date, reason: nil, feedback: nil) # Mark subscription as cancelling (will be cancelled at period end) # Store next_billing_date so the UI can show when the subscription ends - update_custom_attributes({ - 'subscription_status' => 'cancel_at_period_end', - 'subscription_cancelled_at' => Time.current.iso8601, - 'subscription_ends_at' => next_billing_date - }) + attributes = { + 'subscription_status' => 'cancel_at_period_end', + 'subscription_cancelled_at' => Time.current.iso8601, + 'subscription_ends_at' => next_billing_date + } + attributes['cancellation_reason'] = reason if reason.present? + attributes['cancellation_feedback'] = feedback if feedback.present? + + update_custom_attributes(attributes) end def build_success_response diff --git a/enterprise/app/services/enterprise/billing/v2/topup_catalog.rb b/enterprise/app/services/enterprise/billing/v2/topup_catalog.rb index 1106a15ed..284ea33c5 100644 --- a/enterprise/app/services/enterprise/billing/v2/topup_catalog.rb +++ b/enterprise/app/services/enterprise/billing/v2/topup_catalog.rb @@ -1,9 +1,9 @@ module Enterprise::Billing::V2::TopupCatalog DEFAULT_TOPUPS = [ { credits: 1000, amount: 20.0 }, - { credits: 2000, amount: 40.0 }, - { credits: 3000, amount: 60.0 }, - { credits: 4000, amount: 80.0 } + { credits: 2500, amount: 50.0 }, + { credits: 5000, amount: 100.0 }, + { credits: 10_000, amount: 200.0 } ].freeze module_function