Merge remote-tracking branch 'origin/feature/stripe_v2' into feature/stripe_v2_fe
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
-13
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user