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 7b3a5c300..8987a15e8 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 @@ -1,104 +1,101 @@ require 'rails_helper' describe Enterprise::Billing::CreateStripeCustomerService do - subject(:create_stripe_customer_service) { described_class } + subject(:service) { described_class.new(account: account) } let(:account) { create(:account) } - let!(:admin1) { create(:user, account: account, role: :administrator) } + let!(:admin) { create(:user, account: account, role: :administrator) } + let(:stripe_customer_double) { instance_double(Stripe::Customer, id: 'cus_new') } + let(:subscriptions_list) { Stripe::ListObject.construct_from({ data: [] }) } + let(:hacker_plan_id) { 'price_hacker_random' } + + before do + create( + :installation_config, + name: 'CHATWOOT_CLOUD_PLANS', + value: [ + { + 'name' => 'Hacker', + 'limits' => { + 'captain_responses_monthly' => 5, + 'captain_responses_topup' => 0 + } + } + ] + ) + + create(:installation_config, name: 'STRIPE_HACKER_PLAN_ID', value: hacker_plan_id) + end describe '#perform' do - context 'when V2 configs are missing' do - it 'raises a configuration error' do - expect do - create_stripe_customer_service.new(account: account).perform - end.to raise_error(StandardError, /V2 billing configuration is required/) + context 'when account already has an active subscription' do + before do + account.update!(custom_attributes: { stripe_customer_id: 'cus_existing' }) + allow(Stripe::Subscription).to receive(:list) + .and_return(Stripe::ListObject.construct_from({ data: ['subscription'] })) + end + + it 'returns without modifying the account or contacting Stripe' do + expect(Stripe::Customer).not_to receive(:create) + + expect { service.perform }.not_to(change { account.reload.custom_attributes }) end end - context 'with V2 billing' 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 - + context 'when v2 billing configuration is missing' do before do - # Setup configs - cloud_plans_config - hacker_plan_config + InstallationConfig.find_by(name: 'STRIPE_HACKER_PLAN_ID').destroy! 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_billing_version' => 2, - 'stripe_pricing_plan_id' => 'bpp_hacker_123', - 'plan_name' => 'Hacker', - 'subscribed_quantity' => 2 - ) - expect(service).to have_received(:enable_plan_specific_features).with('Hacker') - 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_billing_version' => 2, - 'stripe_pricing_plan_id' => 'bpp_hacker_123', - 'plan_name' => 'Hacker', - 'subscribed_quantity' => 2 + it 'raises an informative error' do + expect { service.perform }.to raise_error( + StandardError, + 'V2 billing configuration is required. Please configure STRIPE_HACKER_PLAN_ID.' ) end + end - it 'skips setup when active subscription exists' do - account.update!(custom_attributes: { stripe_customer_id: 'cus_existing_v2' }) + context 'when account needs to be upgraded to v2 billing' do + context 'when stripe customer already exists' do + before do + account.update!(custom_attributes: { stripe_customer_id: 'cus_existing' }) + allow(Stripe::Subscription).to receive(:list).and_return(subscriptions_list) + allow(Stripe::Customer).to receive(:create) + end - 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) + it 'does not create a new customer but updates custom attributes for v2 billing' do + service.perform - create_stripe_customer_service.new(account: account).perform + expect(Stripe::Customer).not_to have_received(:create) - expect(Stripe::Customer).not_to have_received(:create) - expect(account.reload.custom_attributes['stripe_customer_id']).to eq('cus_existing_v2') + expect(account.reload.custom_attributes).to include( + 'stripe_customer_id' => 'cus_existing', + 'stripe_pricing_plan_id' => hacker_plan_id, + 'plan_name' => 'Hacker', + 'subscribed_quantity' => described_class::DEFAULT_QUANTITY, + 'stripe_billing_version' => 2 + ) + end + end + + context 'when stripe customer does not exist' do + before do + allow(Stripe::Customer).to receive(:create).and_return(stripe_customer_double) + end + + it 'creates a stripe customer and updates the account with v2 billing attributes' do + service.perform + + expect(Stripe::Customer).to have_received(:create).with({ name: account.name, email: admin.email }) + + expect(account.reload.custom_attributes).to include( + 'stripe_customer_id' => 'cus_new', + 'stripe_pricing_plan_id' => hacker_plan_id, + 'plan_name' => 'Hacker', + 'subscribed_quantity' => described_class::DEFAULT_QUANTITY, + 'stripe_billing_version' => 2 + ) + end end end end