From be37c5b80c14c5505198e0b4c25d539ead92c5a6 Mon Sep 17 00:00:00 2001 From: Tanmay Deep Sharma Date: Wed, 29 Oct 2025 03:03:10 +0530 Subject: [PATCH 1/2] sanity changes --- app/controllers/dashboard_controller.rb | 1 + create_plans.rb | 2 +- .../billing/create_stripe_customer_service.rb | 59 ++++++++++++++----- .../billing/v2/cancel_subscription_service.rb | 12 +--- .../billing/v2/change_plan_service.rb | 10 ---- .../billing/v2/credit_management_service.rb | 59 +++++++------------ .../enterprise/billing/v2/plan_catalog.rb | 2 +- .../billing/v2/pricing_plan_service.rb | 14 ++--- .../enterprise/billing/v2/topup_service.rb | 22 ++++++- .../billing/v2/update_subscription_service.rb | 10 ---- 10 files changed, 96 insertions(+), 95 deletions(-) diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb index d81b4c9da..f154cc315 100644 --- a/app/controllers/dashboard_controller.rb +++ b/app/controllers/dashboard_controller.rb @@ -71,6 +71,7 @@ class DashboardController < ActionController::Base WHATSAPP_CONFIGURATION_ID: GlobalConfigService.load('WHATSAPP_CONFIGURATION_ID', ''), IS_ENTERPRISE: ChatwootApp.enterprise?, AZURE_APP_ID: GlobalConfigService.load('AZURE_APP_ID', ''), + STRIPE_BILLING_V2_ENABLED: GlobalConfigService.load('STRIPE_BILLING_V2_ENABLED', 'false'), GIT_SHA: GIT_HASH } end diff --git a/create_plans.rb b/create_plans.rb index 3b3974af6..3e3a85d71 100644 --- a/create_plans.rb +++ b/create_plans.rb @@ -64,7 +64,7 @@ configs = [ meter_event_name: 'chatwoot.usage', plan_display_name: 'Chatwoot Business', plan_lookup_key: 'chatwoot_business_v2', - lookup_key: 'chatwoot_business_plan_license_fee_v2', + lookup_key: 'chatwoot_business_license_fee_v2', service_action_lookup_key: 'chatwoot_business_plan_v2_credits', metered_item_lookup_key: 'chatwoot_business_plan_v2_usage', licensed_item_display_name: 'Seat', diff --git a/enterprise/app/services/enterprise/billing/create_stripe_customer_service.rb b/enterprise/app/services/enterprise/billing/create_stripe_customer_service.rb index e4df1050b..f75980bc4 100644 --- a/enterprise/app/services/enterprise/billing/create_stripe_customer_service.rb +++ b/enterprise/app/services/enterprise/billing/create_stripe_customer_service.rb @@ -1,4 +1,6 @@ class Enterprise::Billing::CreateStripeCustomerService + include Enterprise::Billing::Concerns::PlanFeatureManager + pattr_initialize [:account!] DEFAULT_QUANTITY = 2 @@ -7,21 +9,14 @@ class Enterprise::Billing::CreateStripeCustomerService return if existing_subscription? customer_id = prepare_customer_id - subscription = Stripe::Subscription.create( - { - customer: customer_id, - items: [{ price: price_id, quantity: default_quantity }] - } - ) - account.update!( - custom_attributes: { - stripe_customer_id: customer_id, - stripe_price_id: subscription['plan']['id'], - stripe_product_id: subscription['plan']['product'], - plan_name: default_plan['name'], - subscribed_quantity: subscription['quantity'] - } - ) + + if billing_v2_enabled? + update_account_for_v2_billing(customer_id) + enable_plan_specific_features(default_plan['name']) + else + subscription = create_subscription(customer_id) + update_account_with_subscription(customer_id, subscription) + end end private @@ -53,6 +48,10 @@ class Enterprise::Billing::CreateStripeCustomerService price_ids.first end + def billing_v2_enabled? + ENV.fetch('STRIPE_BILLING_V2_ENABLED', 'false') == 'true' + end + def existing_subscription? stripe_customer_id = account.custom_attributes['stripe_customer_id'] return false if stripe_customer_id.blank? @@ -66,4 +65,34 @@ class Enterprise::Billing::CreateStripeCustomerService ) subscriptions.data.present? end + + def create_subscription(customer_id) + Stripe::Subscription.create( + customer: customer_id, + items: [{ price: price_id, quantity: default_quantity }] + ) + end + + def update_account_for_v2_billing(customer_id) + account.update!( + custom_attributes: { + stripe_customer_id: customer_id, + stripe_pricing_plan_id: InstallationConfig.find_by(name: 'STRIPE_HACKER_PLAN_ID').value, + plan_name: 'Hacker', + subscribed_quantity: DEFAULT_QUANTITY + } + ) + end + + def update_account_with_subscription(customer_id, subscription) + account.update!( + custom_attributes: { + stripe_customer_id: customer_id, + stripe_price_id: subscription['plan']['id'], + stripe_product_id: subscription['plan']['product'], + plan_name: default_plan['name'], + subscribed_quantity: subscription['quantity'] + } + ) + 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 98fd5a707..34fa145ae 100644 --- a/enterprise/app/services/enterprise/billing/v2/cancel_subscription_service.rb +++ b/enterprise/app/services/enterprise/billing/v2/cancel_subscription_service.rb @@ -8,9 +8,6 @@ class Enterprise::Billing::V2::CancelSubscriptionService < Enterprise::Billing:: # @return [Hash] { success:, cancel_at_period_end:, period_end:, message: } # def cancel_subscription - return { success: false, message: 'Not a V2 billing account' } unless v2_enabled? - return { success: false, message: 'No active subscription' } unless active_subscription? - with_locked_account do billing_intent = create_deactivate_intent reserve_billing_intent(billing_intent) @@ -55,6 +52,7 @@ class Enterprise::Billing::V2::CancelSubscriptionService < Enterprise::Billing:: def store_next_billing_date(cadence_id) cadence = retrieve_billing_cadence(cadence_id) + Rails.logger.info("Cadence: #{cadence}") @next_billing_date = extract_attribute(cadence, :next_billing_date) end @@ -126,14 +124,6 @@ class Enterprise::Billing::V2::CancelSubscriptionService < Enterprise::Billing:: } end - def v2_enabled? - custom_attribute('stripe_billing_version')&.to_i == 2 - end - - def active_subscription? - custom_attribute('subscription_status') == 'active' - end - def stripe_api_options { api_key: ENV.fetch('STRIPE_SECRET_KEY', nil), stripe_version: '2025-08-27.preview' } end diff --git a/enterprise/app/services/enterprise/billing/v2/change_plan_service.rb b/enterprise/app/services/enterprise/billing/v2/change_plan_service.rb index a2835ff2a..ec2dc123e 100644 --- a/enterprise/app/services/enterprise/billing/v2/change_plan_service.rb +++ b/enterprise/app/services/enterprise/billing/v2/change_plan_service.rb @@ -9,8 +9,6 @@ class Enterprise::Billing::V2::ChangePlanService < Enterprise::Billing::V2::Base # @return [Hash] { success:, message: } # def change_plan(new_pricing_plan_id:, quantity: 1) - return { success: false, message: 'Not a V2 billing account' } unless v2_enabled? - return { success: false, message: 'No active subscription' } unless active_subscription? return { success: false, message: 'Invalid quantity' } unless quantity.positive? with_locked_account do @@ -179,14 +177,6 @@ class Enterprise::Billing::V2::ChangePlanService < Enterprise::Billing::V2::Base } end - def v2_enabled? - custom_attribute('stripe_billing_version')&.to_i == 2 - end - - def active_subscription? - custom_attribute('subscription_status') == 'active' - end - def stripe_api_options { api_key: ENV.fetch('STRIPE_SECRET_KEY', nil), stripe_version: '2025-08-27.preview' } end diff --git a/enterprise/app/services/enterprise/billing/v2/credit_management_service.rb b/enterprise/app/services/enterprise/billing/v2/credit_management_service.rb index ac459d14f..2ca8270e0 100644 --- a/enterprise/app/services/enterprise/billing/v2/credit_management_service.rb +++ b/enterprise/app/services/enterprise/billing/v2/credit_management_service.rb @@ -99,9 +99,10 @@ class Enterprise::Billing::V2::CreditManagementService < Enterprise::Billing::V2 stripe_api_options ) - response.data.map do |grant| + grants = response.data.map do |grant| transform_credit_grant(grant) end + grants.reject { |grant| grant[:credits].zero? } rescue Stripe::StripeError => e Rails.logger.error("Failed to fetch credit grants: #{e.message}") [] @@ -132,36 +133,32 @@ class Enterprise::Billing::V2::CreditManagementService < Enterprise::Billing::V2 private - # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength def transform_credit_grant(grant) - # Stripe objects have symbol keys when converted to hash, or access via methods - # Use the grant object directly for most reliable access - category = grant[:category] || grant.category - metadata = grant[:metadata] || grant.metadata || {} - - # Determine credits amount based on grant type - credits = if category == 'paid' && metadata['credits'] - metadata['credits'].to_i - elsif category == 'promotional' - grant_id = grant[:id] || grant.id - fetch_monthly_credit_amount(grant_id) - else - 0 - end + category = grant_attribute(grant, :category) + metadata = grant_attribute(grant, :metadata) || {} { - id: grant[:id] || grant.id, - name: grant[:name] || grant.name, - credits: credits, + id: grant_attribute(grant, :id), + name: grant_attribute(grant, :name), + credits: calculate_grant_credits(category, metadata), category: category, source: metadata['source'] || category, - effective_at: parse_timestamp(grant[:effective_at] || grant.effective_at), - expires_at: parse_timestamp(grant[:expires_at] || grant.expires_at), - voided_at: parse_timestamp(grant[:voided_at] || grant.voided_at), - created_at: parse_timestamp(grant[:created] || grant.created) + effective_at: parse_timestamp(grant_attribute(grant, :effective_at)), + expires_at: parse_timestamp(grant_attribute(grant, :expires_at)), + voided_at: parse_timestamp(grant_attribute(grant, :voided_at)), + created_at: parse_timestamp(grant_attribute(grant, :created)) } end - # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength + + def grant_attribute(grant, key) + grant[key] || grant.public_send(key) + end + + def calculate_grant_credits(category, metadata) + return metadata['credits'].to_i if category == 'paid' && metadata['credits'] + + 0 + end def parse_timestamp(timestamp) return nil unless timestamp @@ -169,20 +166,6 @@ class Enterprise::Billing::V2::CreditManagementService < Enterprise::Billing::V2 Time.zone.at(timestamp) end - def fetch_monthly_credit_amount(grant_id) - # Try to get from credit transactions with matching grant_id in metadata - transaction = account.credit_transactions - .where(transaction_type: 'grant', credit_type: 'monthly') - .where("metadata->>'grant_id' = ?", grant_id) - .order(created_at: :desc) - .first - - return transaction.amount if transaction - - # Fallback: return the current monthly_credits from account - monthly_credits - end - def stripe_customer_id custom_attribute('stripe_customer_id') end diff --git a/enterprise/app/services/enterprise/billing/v2/plan_catalog.rb b/enterprise/app/services/enterprise/billing/v2/plan_catalog.rb index 21413b9bd..390049eba 100644 --- a/enterprise/app/services/enterprise/billing/v2/plan_catalog.rb +++ b/enterprise/app/services/enterprise/billing/v2/plan_catalog.rb @@ -25,7 +25,7 @@ module Enterprise::Billing::V2::PlanCatalog base_fee: 39.0, monthly_credits: 50_000, config_key: 'STRIPE_BUSINESS_PLAN_ID', - licensed_item_lookup_key: 'chatwoot_business_plan_license_fee_v2' + licensed_item_lookup_key: 'chatwoot_business_license_fee_v2' }, { key: :enterprise, diff --git a/enterprise/app/services/enterprise/billing/v2/pricing_plan_service.rb b/enterprise/app/services/enterprise/billing/v2/pricing_plan_service.rb index edebdce0c..c3a29819d 100644 --- a/enterprise/app/services/enterprise/billing/v2/pricing_plan_service.rb +++ b/enterprise/app/services/enterprise/billing/v2/pricing_plan_service.rb @@ -42,14 +42,14 @@ class Enterprise::Billing::V2::PricingPlanService < Enterprise::Billing::V2::Bas plan = create_pricing_plan(display_name: config[:plan_display_name], lookup_key: config[:plan_lookup_key]) builder = component_builder - builder.add_license_fee_component(plan, config) - service_action = builder.add_service_action_component(plan, config, cpu) - rate_card = builder.add_rate_card_component(plan, config, meter, cpu) + builder.add_license_fee_component(plan, config) if config[:license_fee_amount].to_i.positive? + builder.add_service_action_component(plan, config, cpu) if config[:monthly_credit_amount].to_i.positive? + builder.add_rate_card_component(plan, config, meter, cpu) # Make the latest version live make_plan_version_live(plan.id) - build_plan_result(plan, cpu, meter, rate_card, service_action) + build_plan_result(plan, cpu, meter) end def get_or_create_cpu(config) @@ -111,14 +111,12 @@ class Enterprise::Billing::V2::PricingPlanService < Enterprise::Billing::V2::Bas ) end - def build_plan_result(plan, cpu, meter, rate_card, service_action) + def build_plan_result(plan, cpu, meter) { success: true, pricing_plan: plan, custom_pricing_unit: cpu, - meter: meter, - rate_card: rate_card, - service_action: service_action + meter: meter } end end diff --git a/enterprise/app/services/enterprise/billing/v2/topup_service.rb b/enterprise/app/services/enterprise/billing/v2/topup_service.rb index 3fd9730cd..5cb829f7d 100644 --- a/enterprise/app/services/enterprise/billing/v2/topup_service.rb +++ b/enterprise/app/services/enterprise/billing/v2/topup_service.rb @@ -19,18 +19,38 @@ class Enterprise::Billing::V2::TopupService < Enterprise::Billing::V2::BaseServi def validate_topup_request(credits) return { valid: false, success: false, message: 'Invalid topup amount' } unless credits.to_i.positive? + # Check if account has a valid subscription plan + plan_validation = validate_subscription_plan + return plan_validation unless plan_validation[:valid] + topup_definition = Enterprise::Billing::V2::TopupCatalog.find_option(credits) return { valid: false, success: false, message: 'Unsupported topup amount' } unless topup_definition return { valid: false, success: false, message: 'Stripe customer not configured' } if stripe_customer_id.blank? # Check if customer has a default payment method unless customer_has_payment_method? - return { valid: false, success: false, message: 'No payment method found. Please add a payment method before making a purchase.' } + return { valid: false, success: false, + message: 'No default payment method found. Please add a default payment method before making a purchase.' } end { valid: true, topup_definition: topup_definition } end + def validate_subscription_plan + plan_name = custom_attribute('plan_name') + + # Block topup if no plan or on Hacker plan + if plan_name.blank? || plan_name.downcase == 'hacker' + return { + valid: false, + success: false, + message: 'Top-ups are only available for Startup, Business, and Enterprise plans. Please upgrade your plan to purchase credits.' + } + end + + { valid: true } + end + def customer_has_payment_method? customer = Stripe::Customer.retrieve(stripe_customer_id, stripe_api_options) # Check if customer has a default payment method or any payment methods attached diff --git a/enterprise/app/services/enterprise/billing/v2/update_subscription_service.rb b/enterprise/app/services/enterprise/billing/v2/update_subscription_service.rb index 6fc7eefe0..a4f10b127 100644 --- a/enterprise/app/services/enterprise/billing/v2/update_subscription_service.rb +++ b/enterprise/app/services/enterprise/billing/v2/update_subscription_service.rb @@ -8,8 +8,6 @@ class Enterprise::Billing::V2::UpdateSubscriptionService < Enterprise::Billing:: # @return [Hash] { success:, message: } # def update_quantity(quantity:) - return { success: false, message: 'Not a V2 billing account' } unless v2_enabled? - return { success: false, message: 'No active subscription' } unless active_subscription? return { success: false, message: 'Invalid quantity' } unless quantity.positive? with_locked_account do @@ -129,14 +127,6 @@ class Enterprise::Billing::V2::UpdateSubscriptionService < Enterprise::Billing:: } end - def v2_enabled? - custom_attribute('stripe_billing_version')&.to_i == 2 - end - - def active_subscription? - custom_attribute('subscription_status') == 'active' - end - def stripe_api_options { api_key: ENV.fetch('STRIPE_SECRET_KEY', nil), stripe_version: '2025-08-27.preview' } end From f9991126710a9ed38a94f4f97bb7e99fd1d43392 Mon Sep 17 00:00:00 2001 From: Tanmay Deep Sharma Date: Wed, 29 Oct 2025 03:24:12 +0530 Subject: [PATCH 2/2] fix rspec --- .../billing/create_stripe_customer_service.rb | 31 ++-- .../create_stripe_customer_service_spec.rb | 133 ++++++++++++++++++ .../subscription_provisioning_service_spec.rb | 13 -- 3 files changed, 155 insertions(+), 22 deletions(-) diff --git a/enterprise/app/services/enterprise/billing/create_stripe_customer_service.rb b/enterprise/app/services/enterprise/billing/create_stripe_customer_service.rb index f75980bc4..337fde1ce 100644 --- a/enterprise/app/services/enterprise/billing/create_stripe_customer_service.rb +++ b/enterprise/app/services/enterprise/billing/create_stripe_customer_service.rb @@ -10,12 +10,15 @@ class Enterprise::Billing::CreateStripeCustomerService customer_id = prepare_customer_id - if billing_v2_enabled? + if billing_v2_enabled? && v2_configs_present? update_account_for_v2_billing(customer_id) enable_plan_specific_features(default_plan['name']) - else + elsif default_plan.present? subscription = create_subscription(customer_id) update_account_with_subscription(customer_id, subscription) + else + # Minimal setup when configs are missing + account.update!(custom_attributes: { stripe_customer_id: customer_id }) end end @@ -40,7 +43,7 @@ class Enterprise::Billing::CreateStripeCustomerService def default_plan installation_config = InstallationConfig.find_by(name: 'CHATWOOT_CLOUD_PLANS') - @default_plan ||= installation_config.value.first + @default_plan ||= installation_config&.value&.first end def price_id @@ -52,6 +55,11 @@ class Enterprise::Billing::CreateStripeCustomerService ENV.fetch('STRIPE_BILLING_V2_ENABLED', 'false') == 'true' end + def v2_configs_present? + InstallationConfig.find_by(name: 'STRIPE_HACKER_PLAN_ID').present? && + default_plan.present? + end + def existing_subscription? stripe_customer_id = account.custom_attributes['stripe_customer_id'] return false if stripe_customer_id.blank? @@ -74,14 +82,19 @@ class Enterprise::Billing::CreateStripeCustomerService end def update_account_for_v2_billing(customer_id) - account.update!( - custom_attributes: { - stripe_customer_id: customer_id, - stripe_pricing_plan_id: InstallationConfig.find_by(name: 'STRIPE_HACKER_PLAN_ID').value, + hacker_plan_config = InstallationConfig.find_by(name: 'STRIPE_HACKER_PLAN_ID') + + attributes = { stripe_customer_id: customer_id } + + if hacker_plan_config&.value.present? + attributes.merge!( + stripe_pricing_plan_id: hacker_plan_config.value, plan_name: 'Hacker', subscribed_quantity: DEFAULT_QUANTITY - } - ) + ) + end + + account.update!(custom_attributes: attributes) end def update_account_with_subscription(customer_id, subscription) diff --git a/spec/enterprise/services/enterprise/billing/create_stripe_customer_service_spec.rb b/spec/enterprise/services/enterprise/billing/create_stripe_customer_service_spec.rb index d1f81da0e..b1daed6a3 100644 --- a/spec/enterprise/services/enterprise/billing/create_stripe_customer_service_spec.rb +++ b/spec/enterprise/services/enterprise/billing/create_stripe_customer_service_spec.rb @@ -31,6 +31,9 @@ describe Enterprise::Billing::CreateStripeCustomerService do it 'does not create a new customer' do allow(Stripe::Customer).to receive(:create) + # Stub the subscription check to return no subscriptions + subscriptions_response = OpenStruct.new(data: []) + allow(Stripe::Subscription).to receive(:list).and_return(subscriptions_response) create_stripe_customer_service.new(account: account).perform @@ -38,5 +41,135 @@ describe Enterprise::Billing::CreateStripeCustomerService do expect(account.reload.custom_attributes['stripe_customer_id']).to eq('cus_existing_customer') end end + + context 'with V2 billing enabled' do + let(:cloud_plans_config) do + create(:installation_config, + name: 'CHATWOOT_CLOUD_PLANS', + value: [ + { + 'name' => 'Startup', + 'price_ids' => ['price_startup_123'], + 'default_quantity' => 2 + } + ]) + end + + let(:hacker_plan_config) do + create(:installation_config, + name: 'STRIPE_HACKER_PLAN_ID', + value: 'bpp_hacker_123') + end + + before do + # Setup configs + cloud_plans_config + hacker_plan_config + # Enable V2 billing + allow(ENV).to receive(:fetch).with('STRIPE_BILLING_V2_ENABLED', 'false').and_return('true') + end + + it 'creates a stripe customer and sets up V2 billing' do + customer = double + allow(Stripe::Customer).to receive(:create).and_return(customer) + allow(customer).to receive(:id).and_return('cus_random_number') + + # Mock the plan feature manager + service = create_stripe_customer_service.new(account: account) + allow(service).to receive(:enable_plan_specific_features) + + service.perform + + expect(Stripe::Customer).to have_received(:create).with({ name: account.name, email: admin1.email }) + expect(account.reload.custom_attributes).to include( + 'stripe_customer_id' => 'cus_random_number', + 'stripe_pricing_plan_id' => 'bpp_hacker_123', + 'plan_name' => 'Hacker', + 'subscribed_quantity' => 2 + ) + expect(service).to have_received(:enable_plan_specific_features).with('Startup') + end + + it 'does not create new customer when customer already exists with V2' do + account.update!(custom_attributes: { stripe_customer_id: 'cus_existing_v2' }) + + allow(Stripe::Customer).to receive(:create) + # Stub the subscription check to return no subscriptions + subscriptions_response = OpenStruct.new(data: []) + allow(Stripe::Subscription).to receive(:list).and_return(subscriptions_response) + + # Mock the plan feature manager + service = create_stripe_customer_service.new(account: account) + allow(service).to receive(:enable_plan_specific_features) + + service.perform + + expect(Stripe::Customer).not_to have_received(:create) + expect(account.reload.custom_attributes).to include( + 'stripe_customer_id' => 'cus_existing_v2', + 'stripe_pricing_plan_id' => 'bpp_hacker_123', + 'plan_name' => 'Hacker', + 'subscribed_quantity' => 2 + ) + end + + it 'skips setup when active subscription exists' do + account.update!(custom_attributes: { stripe_customer_id: 'cus_existing_v2' }) + + allow(Stripe::Customer).to receive(:create) + # Stub the subscription check to return active subscription + subscription_data = OpenStruct.new(id: 'sub_123') + subscriptions_response = OpenStruct.new(data: [subscription_data]) + allow(Stripe::Subscription).to receive(:list).and_return(subscriptions_response) + + create_stripe_customer_service.new(account: account).perform + + expect(Stripe::Customer).not_to have_received(:create) + expect(account.reload.custom_attributes['stripe_customer_id']).to eq('cus_existing_v2') + end + end + + context 'with V1 billing (traditional subscription)' do + let(:cloud_plans_config) do + create(:installation_config, + name: 'CHATWOOT_CLOUD_PLANS', + value: [ + { + 'name' => 'Startup', + 'price_ids' => ['price_startup_123'], + 'default_quantity' => 2 + } + ]) + end + + before do + cloud_plans_config + allow(ENV).to receive(:fetch).with('STRIPE_BILLING_V2_ENABLED', 'false').and_return('false') + end + + it 'creates a stripe customer and traditional subscription' do + customer = double + allow(Stripe::Customer).to receive(:create).and_return(customer) + allow(customer).to receive(:id).and_return('cus_random_number') + + subscription = { + 'plan' => { 'id' => 'price_startup_123', 'product' => 'prod_startup' }, + 'quantity' => 2 + } + allow(Stripe::Subscription).to receive(:create).and_return(subscription) + + create_stripe_customer_service.new(account: account).perform + + expect(Stripe::Customer).to have_received(:create).with({ name: account.name, email: admin1.email }) + expect(Stripe::Subscription).to have_received(:create) + expect(account.reload.custom_attributes).to include( + 'stripe_customer_id' => 'cus_random_number', + 'stripe_price_id' => 'price_startup_123', + 'stripe_product_id' => 'prod_startup', + 'plan_name' => 'Startup', + 'subscribed_quantity' => 2 + ) + end + end end end diff --git a/spec/enterprise/services/enterprise/billing/v2/subscription_provisioning_service_spec.rb b/spec/enterprise/services/enterprise/billing/v2/subscription_provisioning_service_spec.rb index c3a371949..a8f785009 100644 --- a/spec/enterprise/services/enterprise/billing/v2/subscription_provisioning_service_spec.rb +++ b/spec/enterprise/services/enterprise/billing/v2/subscription_provisioning_service_spec.rb @@ -128,19 +128,6 @@ describe Enterprise::Billing::V2::SubscriptionProvisioningService do end end - context 'when an unexpected error occurs' do - before do - allow(StripeV2Client).to receive(:request).and_raise(StandardError.new('Unexpected error')) - end - - it 'returns error response' do - result = service.provision(subscription_id: subscription_id) - - expect(result[:success]).to be(false) - expect(result[:message]).to include('Provisioning error') - end - end - context 'with Startup plan' do let(:startup_plan_id) { 'bpp_startup_plan_123' } let(:subscription_response) do