add default payment method for topup and change of subscription
This commit is contained in:
@@ -9,6 +9,7 @@ class Enterprise::Billing::V2::InvoicePaymentService < Enterprise::Billing::V2::
|
||||
# @return [Hash] { success:, invoice_id:, invoice_url:, amount:, status: }
|
||||
|
||||
# Validate that customer has a default payment method
|
||||
# If no default is set but payment methods exist, automatically set the first one as default
|
||||
# @return [Hash, nil] Returns error hash if validation fails, nil if success
|
||||
def validate_payment_method
|
||||
return { success: false, message: 'No Stripe customer ID found' } if stripe_customer_id.blank?
|
||||
@@ -16,10 +17,9 @@ class Enterprise::Billing::V2::InvoicePaymentService < Enterprise::Billing::V2::
|
||||
customer = Stripe::Customer.retrieve(stripe_customer_id)
|
||||
|
||||
if customer.invoice_settings.default_payment_method.nil? && customer.default_source.nil?
|
||||
return {
|
||||
success: false,
|
||||
message: 'No default payment method found. Please add a default payment method before making a purchase.'
|
||||
}
|
||||
# No default payment method found - try to set one automatically
|
||||
ensure_default_payment_method_result = ensure_default_payment_method(customer)
|
||||
return ensure_default_payment_method_result unless ensure_default_payment_method_result.nil?
|
||||
end
|
||||
|
||||
nil
|
||||
@@ -28,6 +28,40 @@ class Enterprise::Billing::V2::InvoicePaymentService < Enterprise::Billing::V2::
|
||||
{ success: false, message: "Error validating payment method: #{e.message}" }
|
||||
end
|
||||
|
||||
# Ensure a default payment method is set for the customer
|
||||
# If payment methods exist but none is default, set the first one as default
|
||||
# @param customer [Stripe::Customer] The Stripe customer object
|
||||
# @return [Hash, nil] Returns error hash if no payment methods exist, nil if default is set successfully
|
||||
def ensure_default_payment_method(customer)
|
||||
payment_methods = fetch_customer_payment_methods(customer.id)
|
||||
return no_payment_methods_error if payment_methods.data.empty?
|
||||
|
||||
set_first_payment_method_as_default(customer.id, payment_methods.data.first)
|
||||
nil
|
||||
rescue Stripe::StripeError => e
|
||||
Rails.logger.error("Failed to set default payment method: #{e.message}")
|
||||
{ success: false, message: "Error setting default payment method: #{e.message}" }
|
||||
end
|
||||
|
||||
def fetch_customer_payment_methods(customer_id)
|
||||
Stripe::PaymentMethod.list(customer: customer_id, limit: 100)
|
||||
end
|
||||
|
||||
def no_payment_methods_error
|
||||
{
|
||||
success: false,
|
||||
message: 'No payment methods found. Please add a payment method before making a purchase.'
|
||||
}
|
||||
end
|
||||
|
||||
def set_first_payment_method_as_default(customer_id, payment_method)
|
||||
Stripe::Customer.update(
|
||||
customer_id,
|
||||
invoice_settings: { default_payment_method: payment_method.id }
|
||||
)
|
||||
Rails.logger.info("Automatically set payment method #{payment_method.id} as default for customer #{customer_id}")
|
||||
end
|
||||
|
||||
# Create invoice with line items and charge immediately
|
||||
#
|
||||
# @param line_items [Array<Hash>] Line items: [{ amount: (cents), description:, metadata: }]
|
||||
|
||||
@@ -25,11 +25,114 @@ describe Enterprise::Billing::V2::TopupService do
|
||||
end
|
||||
|
||||
describe '#create_topup' do
|
||||
it 'creates topup' do
|
||||
result = service.create_topup(credits: 500)
|
||||
context 'when customer has a default payment method' do
|
||||
it 'creates topup successfully' do
|
||||
result = service.create_topup(credits: 500)
|
||||
|
||||
expect(result[:success]).to be true
|
||||
expect(result[:credits]).to eq(500)
|
||||
expect(result[:success]).to be true
|
||||
expect(result[:credits]).to eq(500)
|
||||
expect(result[:amount]).to eq(50.0)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when customer has no default payment method but has payment methods available' do
|
||||
let(:payment_methods_list) { OpenStruct.new(data: [OpenStruct.new(id: 'pm_first')]) }
|
||||
|
||||
before do
|
||||
allow(Stripe::Customer).to receive(:retrieve).and_return(
|
||||
OpenStruct.new(
|
||||
id: 'cus_123',
|
||||
invoice_settings: OpenStruct.new(default_payment_method: nil),
|
||||
default_source: nil
|
||||
)
|
||||
)
|
||||
allow(Stripe::PaymentMethod).to receive(:list).and_return(payment_methods_list)
|
||||
allow(Stripe::Customer).to receive(:update)
|
||||
end
|
||||
|
||||
it 'automatically sets default payment method and creates topup' do
|
||||
result = service.create_topup(credits: 500)
|
||||
|
||||
expect(Stripe::Customer).to have_received(:update).with(
|
||||
'cus_123',
|
||||
invoice_settings: { default_payment_method: 'pm_first' }
|
||||
)
|
||||
expect(result[:success]).to be true
|
||||
expect(result[:credits]).to eq(500)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when customer has no payment methods at all' do
|
||||
let(:empty_payment_methods) { OpenStruct.new(data: []) }
|
||||
|
||||
before do
|
||||
allow(Stripe::Customer).to receive(:retrieve).and_return(
|
||||
OpenStruct.new(
|
||||
id: 'cus_123',
|
||||
invoice_settings: OpenStruct.new(default_payment_method: nil),
|
||||
default_source: nil
|
||||
)
|
||||
)
|
||||
allow(Stripe::PaymentMethod).to receive(:list).and_return(empty_payment_methods)
|
||||
end
|
||||
|
||||
it 'returns an error' do
|
||||
result = service.create_topup(credits: 500)
|
||||
|
||||
expect(result[:success]).to be false
|
||||
expect(result[:message]).to include('No payment methods found')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when on Hacker plan' do
|
||||
let(:account) { create(:account, custom_attributes: { 'stripe_customer_id' => 'cus_123', 'plan_name' => 'Hacker' }) }
|
||||
|
||||
it 'returns an error' do
|
||||
result = service.create_topup(credits: 500)
|
||||
|
||||
expect(result[:success]).to be false
|
||||
expect(result[:message]).to include('only available for Startup, Business, and Enterprise plans')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when no plan is set' do
|
||||
let(:account) { create(:account, custom_attributes: { 'stripe_customer_id' => 'cus_123' }) }
|
||||
|
||||
it 'returns an error' do
|
||||
result = service.create_topup(credits: 500)
|
||||
|
||||
expect(result[:success]).to be false
|
||||
expect(result[:message]).to include('only available for Startup, Business, and Enterprise plans')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with invalid topup amount' do
|
||||
it 'returns an error for zero credits' do
|
||||
result = service.create_topup(credits: 0)
|
||||
|
||||
expect(result[:success]).to be false
|
||||
expect(result[:message]).to eq('Invalid topup amount')
|
||||
end
|
||||
|
||||
it 'returns an error for negative credits' do
|
||||
result = service.create_topup(credits: -100)
|
||||
|
||||
expect(result[:success]).to be false
|
||||
expect(result[:message]).to eq('Invalid topup amount')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when topup amount is not supported' do
|
||||
before do
|
||||
allow(Enterprise::Billing::V2::TopupCatalog).to receive(:find_option).with(999).and_return(nil)
|
||||
end
|
||||
|
||||
it 'returns an error' do
|
||||
result = service.create_topup(credits: 999)
|
||||
|
||||
expect(result[:success]).to be false
|
||||
expect(result[:message]).to eq('Unsupported topup amount')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user