fix stripe v2 calls
This commit is contained in:
@@ -58,14 +58,18 @@ class Enterprise::Billing::V2::PricingPlanComponentBuilder < Enterprise::Billing
|
||||
private
|
||||
|
||||
def create_licensed_item(display_name:, lookup_key:, unit_label:)
|
||||
Stripe::V2::Billing::LicensedItem.create(
|
||||
StripeV2Client.request(
|
||||
:post,
|
||||
'/v2/billing/licensed_items',
|
||||
{ display_name: display_name, lookup_key: lookup_key, unit_label: unit_label },
|
||||
{ api_key: ENV.fetch('STRIPE_SECRET_KEY', nil), stripe_version: '2025-08-27.preview' }
|
||||
)
|
||||
end
|
||||
|
||||
def create_license_fee(display_name:, unit_amount:, licensed_item_id:)
|
||||
Stripe::V2::Billing::LicenseFee.create(
|
||||
StripeV2Client.request(
|
||||
:post,
|
||||
'/v2/billing/license_fees',
|
||||
{
|
||||
display_name: display_name,
|
||||
currency: 'usd',
|
||||
@@ -80,7 +84,9 @@ class Enterprise::Billing::V2::PricingPlanComponentBuilder < Enterprise::Billing
|
||||
end
|
||||
|
||||
def create_service_action(lookup_key:, credit_amount:, cpu_id:)
|
||||
Stripe::V2::Billing::ServiceAction.create(
|
||||
StripeV2Client.request(
|
||||
:post,
|
||||
'/v2/billing/service_actions',
|
||||
{
|
||||
lookup_key: lookup_key,
|
||||
service_interval: 'month',
|
||||
@@ -101,7 +107,9 @@ class Enterprise::Billing::V2::PricingPlanComponentBuilder < Enterprise::Billing
|
||||
end
|
||||
|
||||
def create_rate_card(display_name:)
|
||||
Stripe::V2::Billing::RateCard.create(
|
||||
StripeV2Client.request(
|
||||
:post,
|
||||
'/v2/billing/rate_cards',
|
||||
{
|
||||
display_name: display_name,
|
||||
currency: 'usd',
|
||||
@@ -114,15 +122,18 @@ class Enterprise::Billing::V2::PricingPlanComponentBuilder < Enterprise::Billing
|
||||
end
|
||||
|
||||
def create_metered_item(display_name:, lookup_key:, meter_id:)
|
||||
Stripe::V2::Billing::MeteredItem.create(
|
||||
StripeV2Client.request(
|
||||
:post,
|
||||
'/v2/billing/metered_items',
|
||||
{ display_name: display_name, lookup_key: lookup_key, meter: meter_id },
|
||||
{ api_key: ENV.fetch('STRIPE_SECRET_KEY', nil), stripe_version: '2025-08-27.preview' }
|
||||
)
|
||||
end
|
||||
|
||||
def add_rate(card_id:, item_id:, cpu_id:, value:)
|
||||
Stripe::V2::Billing::RateCard::Rate.create(
|
||||
card_id,
|
||||
StripeV2Client.request(
|
||||
:post,
|
||||
"/v2/billing/rate_cards/#{card_id}/rates",
|
||||
{
|
||||
metered_item: item_id,
|
||||
custom_pricing_unit_amount: { id: cpu_id, value: value.to_s }
|
||||
@@ -141,8 +152,9 @@ class Enterprise::Billing::V2::PricingPlanComponentBuilder < Enterprise::Billing
|
||||
{ type: 'rate_card', rate_card: data }
|
||||
end
|
||||
|
||||
Stripe::V2::Billing::PricingPlan::Component.create(
|
||||
plan_id,
|
||||
StripeV2Client.request(
|
||||
:post,
|
||||
"/v2/billing/pricing_plans/#{plan_id}/components",
|
||||
params,
|
||||
{ api_key: ENV.fetch('STRIPE_SECRET_KEY', nil), stripe_version: '2025-08-27.preview' }
|
||||
)
|
||||
|
||||
@@ -1,26 +1,34 @@
|
||||
class Enterprise::Billing::V2::PricingPlanService < Enterprise::Billing::V2::BaseService
|
||||
def create_custom_pricing_unit(display_name:, lookup_key:)
|
||||
Stripe::V2::Billing::CustomPricingUnit.create(
|
||||
StripeV2Client.request(
|
||||
:post,
|
||||
'/v2/billing/custom_pricing_units',
|
||||
{ display_name: display_name, lookup_key: lookup_key },
|
||||
{ api_key: ENV.fetch('STRIPE_SECRET_KEY', nil), stripe_version: '2025-08-27.preview' }
|
||||
)
|
||||
end
|
||||
|
||||
def create_meter(display_name:, event_name:)
|
||||
Stripe::Billing::Meter.create(
|
||||
{
|
||||
display_name: display_name,
|
||||
event_name: event_name,
|
||||
default_aggregation: { formula: 'sum' },
|
||||
customer_mapping: { type: 'by_id', event_payload_key: 'stripe_customer_id' },
|
||||
value_settings: { event_payload_key: 'value' }
|
||||
},
|
||||
params = {
|
||||
'display_name' => display_name,
|
||||
'event_name' => event_name,
|
||||
'default_aggregation[formula]' => 'sum',
|
||||
'customer_mapping[type]' => 'by_id',
|
||||
'customer_mapping[event_payload_key]' => 'stripe_customer_id',
|
||||
'value_settings[event_payload_key]' => 'value'
|
||||
}
|
||||
StripeV2Client.request(
|
||||
:post,
|
||||
'/v1/billing/meters',
|
||||
params,
|
||||
{ api_key: ENV.fetch('STRIPE_SECRET_KEY', nil), stripe_version: '2025-08-27.preview' }
|
||||
)
|
||||
end
|
||||
|
||||
def create_pricing_plan(display_name:, currency: 'usd', tax_behavior: 'exclusive')
|
||||
Stripe::V2::Billing::PricingPlan.create(
|
||||
StripeV2Client.request(
|
||||
:post,
|
||||
'/v2/billing/pricing_plans',
|
||||
{ display_name: display_name, currency: currency, tax_behavior: tax_behavior },
|
||||
{ api_key: ENV.fetch('STRIPE_SECRET_KEY', nil), stripe_version: '2025-08-27.preview' }
|
||||
)
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
module StripeV2Client
|
||||
class << self
|
||||
def request(method, path, params = {}, options = {})
|
||||
api_key = options[:api_key] || ENV.fetch('STRIPE_SECRET_KEY', nil)
|
||||
stripe_version = options[:stripe_version] || '2025-08-27.preview'
|
||||
|
||||
uri = URI("https://api.stripe.com#{path}")
|
||||
|
||||
http = Net::HTTP.new(uri.host, uri.port)
|
||||
http.use_ssl = true
|
||||
|
||||
request = build_request(method, uri, params, path)
|
||||
request['Authorization'] = "Bearer #{api_key}"
|
||||
request['Stripe-Version'] = stripe_version
|
||||
|
||||
response = http.request(request)
|
||||
parse_response(response)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def build_request(method, uri, params, path)
|
||||
case method
|
||||
when :get
|
||||
Net::HTTP::Get.new(uri)
|
||||
when :post
|
||||
req = Net::HTTP::Post.new(uri)
|
||||
if v2_endpoint?(path)
|
||||
req.body = params.to_json unless params.empty?
|
||||
req['Content-Type'] = 'application/json'
|
||||
else
|
||||
req.set_form_data(params) unless params.empty?
|
||||
req['Content-Type'] = 'application/x-www-form-urlencoded'
|
||||
end
|
||||
req
|
||||
when :delete
|
||||
Net::HTTP::Delete.new(uri)
|
||||
end
|
||||
end
|
||||
|
||||
def v2_endpoint?(path)
|
||||
path.start_with?('/v2/')
|
||||
end
|
||||
|
||||
def parse_response(response)
|
||||
body = JSON.parse(response.body)
|
||||
|
||||
# Convert to OpenStruct for dot notation access (mimicking Stripe SDK objects)
|
||||
case body
|
||||
when Hash
|
||||
recursive_to_struct(body)
|
||||
when Array
|
||||
body.map { |item| recursive_to_struct(item) }
|
||||
else
|
||||
body
|
||||
end
|
||||
rescue JSON::ParserError
|
||||
response.body
|
||||
end
|
||||
|
||||
def recursive_to_struct(hash)
|
||||
return hash unless hash.is_a?(Hash)
|
||||
|
||||
OpenStruct.new(hash.transform_values do |value|
|
||||
case value
|
||||
when Hash
|
||||
recursive_to_struct(value)
|
||||
when Array
|
||||
value.map { |item| item.is_a?(Hash) ? recursive_to_struct(item) : item }
|
||||
else
|
||||
value
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -10,95 +10,92 @@ RSpec.describe Enterprise::Billing::V2::PricingPlanService do
|
||||
|
||||
describe '#create_custom_pricing_unit' do
|
||||
it 'creates a custom pricing unit' do
|
||||
cpu_double = instance_double(Stripe::V2::Billing::CustomPricingUnit, id: 'cpu_123')
|
||||
allow(Stripe::V2::Billing::CustomPricingUnit).to receive(:create).and_return(cpu_double)
|
||||
cpu_response = OpenStruct.new(id: 'cpu_123')
|
||||
allow(StripeV2Client).to receive(:request).and_return(cpu_response)
|
||||
|
||||
result = service.create_custom_pricing_unit(display_name: 'Credits', lookup_key: 'credits_001')
|
||||
|
||||
expect(result.id).to eq('cpu_123')
|
||||
expect(StripeV2Client).to have_received(:request).with(
|
||||
:post,
|
||||
'/v2/billing/custom_pricing_units',
|
||||
{ display_name: 'Credits', lookup_key: 'credits_001' },
|
||||
{ api_key: 'sk_test_123', stripe_version: '2025-08-27.preview' }
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#create_meter' do
|
||||
it 'creates a billing meter' do
|
||||
meter_double = instance_double(Stripe::Billing::Meter, id: 'meter_123')
|
||||
allow(Stripe::Billing::Meter).to receive(:create).and_return(meter_double)
|
||||
meter_response = OpenStruct.new(id: 'meter_123')
|
||||
allow(StripeV2Client).to receive(:request).and_return(meter_response)
|
||||
|
||||
result = service.create_meter(display_name: 'Prompts', event_name: 'prompts_001')
|
||||
|
||||
expect(result.id).to eq('meter_123')
|
||||
expect(StripeV2Client).to have_received(:request).with(
|
||||
:post,
|
||||
'/v1/billing/meters',
|
||||
kind_of(Hash),
|
||||
{ api_key: 'sk_test_123', stripe_version: '2025-08-27.preview' }
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#create_pricing_plan' do
|
||||
it 'creates a pricing plan' do
|
||||
plan_double = instance_double(Stripe::V2::Billing::PricingPlan, id: 'plan_123')
|
||||
allow(Stripe::V2::Billing::PricingPlan).to receive(:create).and_return(plan_double)
|
||||
plan_response = OpenStruct.new(id: 'plan_123')
|
||||
allow(StripeV2Client).to receive(:request).and_return(plan_response)
|
||||
|
||||
result = service.create_pricing_plan(display_name: 'Business Plan')
|
||||
|
||||
expect(result.id).to eq('plan_123')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#create_service_action' do
|
||||
it 'creates a service action for monthly credit grants' do
|
||||
action_double = instance_double(Stripe::V2::Billing::ServiceAction, id: 'sa_123')
|
||||
allow(Stripe::V2::Billing::ServiceAction).to receive(:create).and_return(action_double)
|
||||
|
||||
result = service.create_service_action(
|
||||
lookup_key: 'monthly_credits_001',
|
||||
cpu_id: 'cpu_123',
|
||||
credit_amount: 2000
|
||||
expect(StripeV2Client).to have_received(:request).with(
|
||||
:post,
|
||||
'/v2/billing/pricing_plans',
|
||||
{ display_name: 'Business Plan', currency: 'usd', tax_behavior: 'exclusive' },
|
||||
{ api_key: 'sk_test_123', stripe_version: '2025-08-27.preview' }
|
||||
)
|
||||
|
||||
expect(result.id).to eq('sa_123')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#create_complete_pricing_plan' do
|
||||
let(:config) do
|
||||
{
|
||||
cpu_display_name: 'Captain Credits',
|
||||
cpu_lookup_key: 'captain_credits_001',
|
||||
meter_display_name: 'Captain Prompts',
|
||||
meter_event_name: 'captain_prompts_001',
|
||||
plan_display_name: 'Business Plan - 2000 Credits',
|
||||
cpu_display_name: 'Credits',
|
||||
cpu_lookup_key: 'cpu_001',
|
||||
meter_display_name: 'Prompts',
|
||||
meter_event_name: 'prompts_001',
|
||||
plan_display_name: 'Business Plan',
|
||||
include_license_fee: true,
|
||||
licensed_item_display_name: 'Business Seat',
|
||||
licensed_item_lookup_key: 'business_seat_001',
|
||||
licensed_item_display_name: 'Seat',
|
||||
licensed_item_lookup_key: 'seat_001',
|
||||
licensed_item_unit_label: 'per agent',
|
||||
license_fee_display_name: 'Business Monthly Fee',
|
||||
license_fee_display_name: 'Fee',
|
||||
license_fee_amount: '3900',
|
||||
service_action_lookup_key: 'monthly_credits_001',
|
||||
service_action_lookup_key: 'credits_001',
|
||||
monthly_credit_amount: 2000,
|
||||
rate_card_display_name: 'Usage Rates',
|
||||
metered_item_display_name: 'Captain Prompt',
|
||||
metered_item_lookup_key: 'captain_prompt_001',
|
||||
rate_card_display_name: 'Rates',
|
||||
metered_item_display_name: 'Prompt',
|
||||
metered_item_lookup_key: 'prompt_001',
|
||||
rate_value: 1
|
||||
}
|
||||
end
|
||||
|
||||
it 'creates a complete pricing plan with all components' do
|
||||
cpu = instance_double(Stripe::V2::Billing::CustomPricingUnit, id: 'cpu_123')
|
||||
meter = instance_double(Stripe::Billing::Meter, id: 'meter_123')
|
||||
plan = instance_double(Stripe::V2::Billing::PricingPlan, id: 'plan_123')
|
||||
licensed_item = instance_double(Stripe::V2::Billing::LicensedItem, id: 'li_123')
|
||||
license_fee = instance_double(Stripe::V2::Billing::LicenseFee, id: 'lf_123', latest_version: 'v1')
|
||||
service_action = instance_double(Stripe::V2::Billing::ServiceAction, id: 'sa_123')
|
||||
rate_card = instance_double(Stripe::V2::Billing::RateCard, id: 'rc_123', latest_version: 'v1')
|
||||
metered_item = instance_double(Stripe::V2::Billing::MeteredItem, id: 'mi_123')
|
||||
cpu = OpenStruct.new(id: 'cpu_123')
|
||||
meter = OpenStruct.new(id: 'meter_123')
|
||||
plan = OpenStruct.new(id: 'plan_123')
|
||||
service_action = OpenStruct.new(id: 'sa_123')
|
||||
rate_card = OpenStruct.new(id: 'rc_123', latest_version: 'v1')
|
||||
|
||||
allow(service).to receive(:create_custom_pricing_unit).and_return(cpu)
|
||||
allow(service).to receive(:create_meter).and_return(meter)
|
||||
allow(service).to receive(:create_pricing_plan).and_return(plan)
|
||||
allow(service).to receive(:create_licensed_item).and_return(licensed_item)
|
||||
allow(service).to receive(:create_license_fee).and_return(license_fee)
|
||||
allow(service).to receive(:create_service_action).and_return(service_action)
|
||||
allow(service).to receive(:create_rate_card).and_return(rate_card)
|
||||
allow(service).to receive(:create_metered_item).and_return(metered_item)
|
||||
allow(service).to receive(:add_rate_to_rate_card).and_return(true)
|
||||
allow(service).to receive(:add_component_to_plan).and_return(true)
|
||||
allow(StripeV2Client).to receive(:request).and_return(cpu, meter, plan, service_action, rate_card)
|
||||
allow_any_instance_of(Enterprise::Billing::V2::PricingPlanComponentBuilder)
|
||||
.to receive(:add_license_fee_component).and_return(true)
|
||||
allow_any_instance_of(Enterprise::Billing::V2::PricingPlanComponentBuilder)
|
||||
.to receive(:add_service_action_component).and_return(service_action)
|
||||
allow_any_instance_of(Enterprise::Billing::V2::PricingPlanComponentBuilder)
|
||||
.to receive(:add_rate_card_component).and_return(rate_card)
|
||||
|
||||
result = service.create_complete_pricing_plan(config)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user