mirror of
https://github.com/maybe-finance/maybe.git
synced 2025-08-04 21:15:19 +02:00
Subscription tests and domain (#2209)
* Save work * Subscriptions and trials domain * Store family ID on customer * Remove indirection of stripe calls * Test simplifications * Update brakeman * Fix stripe tests in CI * Update billing page to show subscription details * Remove legacy columns * Complete billing settings page * Fix hardcoded plan name * Handle subscriptions for self hosting mode * Lint fixes
This commit is contained in:
parent
8c10e87387
commit
5da4bb6dc3
40 changed files with 1041 additions and 233 deletions
|
@ -3,6 +3,7 @@ require "test_helper"
|
|||
class OnboardableTest < ActionDispatch::IntegrationTest
|
||||
setup do
|
||||
sign_in @user = users(:empty)
|
||||
@user.family.subscription.destroy
|
||||
end
|
||||
|
||||
test "must complete onboarding before any other action" do
|
||||
|
@ -10,32 +11,18 @@ class OnboardableTest < ActionDispatch::IntegrationTest
|
|||
|
||||
get root_path
|
||||
assert_redirected_to onboarding_path
|
||||
|
||||
@user.family.update!(trial_started_at: 1.day.ago, stripe_subscription_status: "active")
|
||||
|
||||
get root_path
|
||||
assert_redirected_to onboarding_path
|
||||
end
|
||||
|
||||
test "must subscribe if onboarding complete and no trial or subscription is active" do
|
||||
test "must have subscription to visit dashboard" do
|
||||
@user.update!(onboarded_at: 1.day.ago)
|
||||
@user.family.update!(trial_started_at: nil, stripe_subscription_status: "incomplete")
|
||||
|
||||
get root_path
|
||||
assert_redirected_to upgrade_subscription_path
|
||||
end
|
||||
|
||||
test "onboarded trial user can visit dashboard" do
|
||||
@user.update!(onboarded_at: 1.day.ago)
|
||||
@user.family.update!(trial_started_at: 1.day.ago, stripe_subscription_status: "incomplete")
|
||||
|
||||
get root_path
|
||||
assert_response :success
|
||||
assert_redirected_to trial_onboarding_path
|
||||
end
|
||||
|
||||
test "onboarded subscribed user can visit dashboard" do
|
||||
@user.update!(onboarded_at: 1.day.ago)
|
||||
@user.family.update!(stripe_subscription_status: "active")
|
||||
@user.family.start_trial_subscription!
|
||||
|
||||
get root_path
|
||||
assert_response :success
|
||||
|
|
|
@ -1,41 +1,78 @@
|
|||
require "test_helper"
|
||||
require "ostruct"
|
||||
|
||||
class SubscriptionsControllerTest < ActionDispatch::IntegrationTest
|
||||
setup do
|
||||
sign_in @user = users(:family_admin)
|
||||
sign_in @user = users(:empty)
|
||||
@family = @user.family
|
||||
|
||||
@mock_stripe = mock
|
||||
Provider::Registry.stubs(:get_provider).with(:stripe).returns(@mock_stripe)
|
||||
end
|
||||
|
||||
test "can start trial" do
|
||||
@user.update!(onboarded_at: nil)
|
||||
@user.family.update!(trial_started_at: nil, stripe_subscription_status: "incomplete")
|
||||
|
||||
assert_nil @user.onboarded_at
|
||||
assert_nil @user.family.trial_started_at
|
||||
|
||||
post start_trial_subscription_path
|
||||
assert_redirected_to root_path
|
||||
assert_equal "Welcome to Maybe!", flash[:notice]
|
||||
|
||||
assert @user.reload.onboarded?
|
||||
assert @user.family.reload.trial_started_at.present?
|
||||
end
|
||||
|
||||
test "if user re-enters onboarding, don't restart trial" do
|
||||
onboard_time = 1.day.ago
|
||||
trial_start_time = 1.day.ago
|
||||
|
||||
@user.update!(onboarded_at: onboard_time)
|
||||
@user.family.update!(trial_started_at: trial_start_time, stripe_subscription_status: "incomplete")
|
||||
|
||||
post start_trial_subscription_path
|
||||
assert_redirected_to root_path
|
||||
|
||||
assert @user.reload.family.trial_started_at < Date.current
|
||||
end
|
||||
|
||||
test "redirects to settings if self hosting" do
|
||||
test "disabled for self hosted users" do
|
||||
Rails.application.config.app_mode.stubs(:self_hosted?).returns(true)
|
||||
get subscription_path
|
||||
post subscription_path
|
||||
assert_response :forbidden
|
||||
end
|
||||
|
||||
# Trial subscriptions are managed internally and do NOT go through Stripe
|
||||
test "can create trial subscription" do
|
||||
@family.subscription.destroy
|
||||
@family.reload
|
||||
|
||||
assert_difference "Subscription.count", 1 do
|
||||
post subscription_path
|
||||
end
|
||||
|
||||
assert_redirected_to root_path
|
||||
assert_equal "Welcome to Maybe!", flash[:notice]
|
||||
assert_equal "trialing", @family.subscription.status
|
||||
assert_in_delta Subscription::TRIAL_DAYS.days.from_now, @family.subscription.trial_ends_at, 1.minute
|
||||
end
|
||||
|
||||
test "users who have already trialed cannot create a new subscription" do
|
||||
@family.start_trial_subscription!
|
||||
|
||||
assert_no_difference "Subscription.count" do
|
||||
post subscription_path
|
||||
end
|
||||
|
||||
assert_redirected_to root_path
|
||||
assert_equal "You have already started or completed a trial. Please upgrade to continue.", flash[:alert]
|
||||
end
|
||||
|
||||
test "creates new checkout session" do
|
||||
@mock_stripe.expects(:create_checkout_session).with(
|
||||
plan: "monthly",
|
||||
family_id: @family.id,
|
||||
family_email: @family.billing_email,
|
||||
success_url: success_subscription_url + "?session_id={CHECKOUT_SESSION_ID}",
|
||||
cancel_url: upgrade_subscription_url
|
||||
).returns(
|
||||
OpenStruct.new(
|
||||
url: "https://checkout.stripe.com/c/pay/test-session-id",
|
||||
customer_id: "test-customer-id"
|
||||
)
|
||||
)
|
||||
|
||||
get new_subscription_path(plan: "monthly")
|
||||
|
||||
assert_redirected_to "https://checkout.stripe.com/c/pay/test-session-id"
|
||||
assert_equal "test-customer-id", @family.reload.stripe_customer_id
|
||||
end
|
||||
|
||||
test "creates active subscription on checkout success" do
|
||||
@mock_stripe.expects(:get_checkout_result).with("test-session-id").returns(
|
||||
OpenStruct.new(
|
||||
success?: true,
|
||||
subscription_id: "test-subscription-id"
|
||||
)
|
||||
)
|
||||
|
||||
get success_subscription_url(session_id: "test-session-id")
|
||||
|
||||
assert @family.subscription.active?
|
||||
assert_equal "Welcome to Maybe! Your subscription has been created.", flash[:notice]
|
||||
end
|
||||
end
|
||||
|
|
2
test/fixtures/families.yml
vendored
2
test/fixtures/families.yml
vendored
|
@ -1,10 +1,8 @@
|
|||
empty:
|
||||
name: Family
|
||||
stripe_subscription_status: active
|
||||
last_synced_at: <%= Time.now %>
|
||||
|
||||
dylan_family:
|
||||
name: The Dylan Family
|
||||
stripe_subscription_status: active
|
||||
last_synced_at: <%= Time.now %>
|
||||
|
||||
|
|
9
test/fixtures/subscriptions.yml
vendored
Normal file
9
test/fixtures/subscriptions.yml
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
active:
|
||||
family: dylan_family
|
||||
status: active
|
||||
stripe_id: "test_1234567890"
|
||||
|
||||
trialing:
|
||||
family: empty
|
||||
status: trialing
|
||||
trial_ends_at: <%= 12.days.from_now %>
|
1
test/fixtures/users.yml
vendored
1
test/fixtures/users.yml
vendored
|
@ -5,6 +5,7 @@ empty:
|
|||
email: user1@email.com
|
||||
password_digest: $2a$12$XoNBo/cMCyzpYtvhrPAhsubG21mELX48RAcjSVCRctW8dG8wrDIla
|
||||
onboarded_at: <%= 3.days.ago %>
|
||||
role: admin
|
||||
ai_enabled: true
|
||||
|
||||
maybe_support_staff:
|
||||
|
|
13
test/models/family/subscribeable_test.rb
Normal file
13
test/models/family/subscribeable_test.rb
Normal file
|
@ -0,0 +1,13 @@
|
|||
require "test_helper"
|
||||
|
||||
class Family::SubscribeableTest < ActiveSupport::TestCase
|
||||
setup do
|
||||
@family = families(:dylan_family)
|
||||
end
|
||||
|
||||
# We keep the status eventually consistent, but don't rely on it for guarding the app
|
||||
test "trial respects end date even if status is not yet updated" do
|
||||
@family.subscription.update!(trial_ends_at: 1.day.ago, status: "trialing")
|
||||
assert_not @family.trialing?
|
||||
end
|
||||
end
|
|
@ -1,7 +0,0 @@
|
|||
require "test_helper"
|
||||
|
||||
class Provider::Stripe::CustomerEventProcessorTest < ActiveSupport::TestCase
|
||||
# test "process" do
|
||||
|
||||
# end
|
||||
end
|
|
@ -1,6 +1,57 @@
|
|||
require "test_helper"
|
||||
require "ostruct"
|
||||
|
||||
class Provider::Stripe::SubscriptionEventProcessorTest < ActiveSupport::TestCase
|
||||
# test "process" do
|
||||
# end
|
||||
test "handles subscription event" do
|
||||
test_customer_id = "test-customer-id"
|
||||
test_subscription_id = "test-subscription-id"
|
||||
|
||||
mock_event = JSON.parse({
|
||||
type: "customer.subscription.created",
|
||||
data: {
|
||||
object: {
|
||||
id: test_subscription_id,
|
||||
status: "active",
|
||||
customer: test_customer_id,
|
||||
items: {
|
||||
data: [
|
||||
{
|
||||
current_period_end: 1.month.from_now.to_i,
|
||||
plan: {
|
||||
interval: "month",
|
||||
amount: 900,
|
||||
currency: "usd"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}.to_json, object_class: OpenStruct)
|
||||
|
||||
family = Family.create!(
|
||||
name: "Test Subscribed Family",
|
||||
stripe_customer_id: test_customer_id
|
||||
)
|
||||
|
||||
family.start_subscription!(test_subscription_id)
|
||||
|
||||
processor = Provider::Stripe::SubscriptionEventProcessor.new(mock_event)
|
||||
|
||||
assert_equal "active", family.subscription.status
|
||||
assert_equal test_subscription_id, family.subscription.stripe_id
|
||||
assert_nil family.subscription.amount
|
||||
assert_nil family.subscription.currency
|
||||
assert_nil family.subscription.current_period_ends_at
|
||||
|
||||
processor.process
|
||||
|
||||
family.reload
|
||||
|
||||
assert_equal "active", family.subscription.status
|
||||
assert_equal test_subscription_id, family.subscription.stripe_id
|
||||
assert_equal 9, family.subscription.amount
|
||||
assert_equal "USD", family.subscription.currency
|
||||
assert family.subscription.current_period_ends_at > 20.days.from_now
|
||||
end
|
||||
end
|
||||
|
|
45
test/models/provider/stripe_test.rb
Normal file
45
test/models/provider/stripe_test.rb
Normal file
|
@ -0,0 +1,45 @@
|
|||
require "test_helper"
|
||||
|
||||
class Provider::StripeTest < ActiveSupport::TestCase
|
||||
setup do
|
||||
@stripe = Provider::Stripe.new(
|
||||
secret_key: ENV["STRIPE_SECRET_KEY"] || "foo",
|
||||
webhook_secret: ENV["STRIPE_WEBHOOK_SECRET"] || "bar"
|
||||
)
|
||||
end
|
||||
|
||||
test "creates checkout session" do
|
||||
test_email = "test@example.com"
|
||||
|
||||
test_success_url = "http://localhost:3000/subscription/success?session_id={CHECKOUT_SESSION_ID}"
|
||||
test_cancel_url = "http://localhost:3000/subscription/upgrade"
|
||||
|
||||
VCR.use_cassette("stripe/create_checkout_session") do
|
||||
session = @stripe.create_checkout_session(
|
||||
plan: "monthly",
|
||||
family_id: 1,
|
||||
family_email: test_email,
|
||||
success_url: test_success_url,
|
||||
cancel_url: test_cancel_url
|
||||
)
|
||||
|
||||
assert_match /https:\/\/checkout.stripe.com\/c\/pay\/cs_test_.*/, session.url
|
||||
assert_match /cus_.*/, session.customer_id
|
||||
end
|
||||
end
|
||||
|
||||
# To re-run VCR for this test:
|
||||
# 1. Complete a checkout session locally in the UI
|
||||
# 2. Find the session ID, replace below
|
||||
# 3. Re-run VCR, make sure ENV vars are in test environment
|
||||
test "validates checkout session and returns subscription ID" do
|
||||
test_session_id = "cs_test_b1RD8r6DAkSA8vrQ3grBC2QVgR5zUJ7QQFuVHZkcKoSYaEOQgCMPMOCOM5" # must exist in test Dashboard
|
||||
|
||||
VCR.use_cassette("stripe/checkout_session") do
|
||||
result = @stripe.get_checkout_result(test_session_id)
|
||||
|
||||
assert result.success?
|
||||
assert_match /sub_.*/, result.subscription_id
|
||||
end
|
||||
end
|
||||
end
|
33
test/models/subscription_test.rb
Normal file
33
test/models/subscription_test.rb
Normal file
|
@ -0,0 +1,33 @@
|
|||
require "test_helper"
|
||||
|
||||
class SubscriptionTest < ActiveSupport::TestCase
|
||||
setup do
|
||||
@family = families(:empty)
|
||||
end
|
||||
|
||||
test "can create subscription without stripe details if trial" do
|
||||
subscription = Subscription.new(
|
||||
family: @family,
|
||||
status: :trialing,
|
||||
)
|
||||
|
||||
assert_not subscription.valid?
|
||||
|
||||
subscription.trial_ends_at = 14.days.from_now
|
||||
|
||||
assert subscription.valid?
|
||||
end
|
||||
|
||||
test "stripe details required for all statuses except trial" do
|
||||
subscription = Subscription.new(
|
||||
family: @family,
|
||||
status: :active,
|
||||
)
|
||||
|
||||
assert_not subscription.valid?
|
||||
|
||||
subscription.stripe_id = "test-stripe-id"
|
||||
|
||||
assert subscription.valid?
|
||||
end
|
||||
end
|
|
@ -26,6 +26,8 @@ VCR.configure do |config|
|
|||
config.filter_sensitive_data("<SYNTH_API_KEY>") { ENV["SYNTH_API_KEY"] }
|
||||
config.filter_sensitive_data("<OPENAI_ACCESS_TOKEN>") { ENV["OPENAI_ACCESS_TOKEN"] }
|
||||
config.filter_sensitive_data("<OPENAI_ORGANIZATION_ID>") { ENV["OPENAI_ORGANIZATION_ID"] }
|
||||
config.filter_sensitive_data("<STRIPE_SECRET_KEY>") { ENV["STRIPE_SECRET_KEY"] }
|
||||
config.filter_sensitive_data("<STRIPE_WEBHOOK_SECRET>") { ENV["STRIPE_WEBHOOK_SECRET"] }
|
||||
end
|
||||
|
||||
module ActiveSupport
|
||||
|
|
181
test/vcr_cassettes/stripe/checkout_session.yml
Normal file
181
test/vcr_cassettes/stripe/checkout_session.yml
Normal file
|
@ -0,0 +1,181 @@
|
|||
---
|
||||
http_interactions:
|
||||
- request:
|
||||
method: get
|
||||
uri: https://api.stripe.com/v1/checkout/sessions/cs_test_b1RD8r6DAkSA8vrQ3grBC2QVgR5zUJ7QQFuVHZkcKoSYaEOQgCMPMOCOM5
|
||||
body:
|
||||
encoding: US-ASCII
|
||||
string: ''
|
||||
headers:
|
||||
User-Agent:
|
||||
- Stripe/v1 RubyBindings/15.1.0
|
||||
Authorization:
|
||||
- Bearer <STRIPE_SECRET_KEY>
|
||||
Stripe-Version:
|
||||
- 2025-04-30.basil
|
||||
X-Stripe-Client-User-Agent:
|
||||
- '{"bindings_version":"15.1.0","lang":"ruby","lang_version":"3.4.1 p0 (2024-12-25)","platform":"arm64-darwin24","engine":"ruby","publisher":"stripe","uname":"Darwin
|
||||
Zachs-MacBook-Pro.local 24.3.0 Darwin Kernel Version 24.3.0: Thu Jan 2 20:24:16
|
||||
PST 2025; root:xnu-11215.81.4~3/RELEASE_ARM64_T6000 arm64","hostname":"Zachs-MacBook-Pro.local"}'
|
||||
Accept-Encoding:
|
||||
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
||||
Accept:
|
||||
- "*/*"
|
||||
response:
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
headers:
|
||||
Server:
|
||||
- nginx
|
||||
Date:
|
||||
- Mon, 05 May 2025 16:09:23 GMT
|
||||
Content-Type:
|
||||
- application/json
|
||||
Content-Length:
|
||||
- '2667'
|
||||
Connection:
|
||||
- keep-alive
|
||||
Access-Control-Allow-Credentials:
|
||||
- 'true'
|
||||
Access-Control-Allow-Methods:
|
||||
- GET, HEAD, PUT, PATCH, POST, DELETE
|
||||
Access-Control-Allow-Origin:
|
||||
- "*"
|
||||
Access-Control-Expose-Headers:
|
||||
- Request-Id, Stripe-Manage-Version, Stripe-Should-Retry, X-Stripe-External-Auth-Required,
|
||||
X-Stripe-Privileged-Session-Required
|
||||
Access-Control-Max-Age:
|
||||
- '300'
|
||||
Cache-Control:
|
||||
- no-cache, no-store
|
||||
Content-Security-Policy:
|
||||
- base-uri 'none'; default-src 'none'; form-action 'none'; frame-ancestors 'none';
|
||||
img-src 'self'; script-src 'self' 'report-sample'; style-src 'self'; worker-src
|
||||
'none'; upgrade-insecure-requests; report-uri https://q.stripe.com/csp-violation?q=7L6NHIm4wk05H5wi0PfH951BH62utb5j2ZImtzEXvcfJgdc1v5juGoNb0oSAXIHhGQtWiGOiCmz3UG1W
|
||||
Request-Id:
|
||||
- req_c2n4M98HkgTk63
|
||||
Stripe-Version:
|
||||
- 2025-04-30.basil
|
||||
Vary:
|
||||
- Origin
|
||||
X-Stripe-Priority-Routing-Enabled:
|
||||
- 'true'
|
||||
X-Stripe-Routing-Context-Priority-Tier:
|
||||
- api-testmode
|
||||
X-Wc:
|
||||
- ABGHI
|
||||
Strict-Transport-Security:
|
||||
- max-age=63072000; includeSubDomains; preload
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: |-
|
||||
{
|
||||
"id": "cs_test_b1RD8r6DAkSA8vrQ3grBC2QVgR5zUJ7QQFuVHZkcKoSYaEOQgCMPMOCOM5",
|
||||
"object": "checkout.session",
|
||||
"adaptive_pricing": null,
|
||||
"after_expiration": null,
|
||||
"allow_promotion_codes": true,
|
||||
"amount_subtotal": 900,
|
||||
"amount_total": 900,
|
||||
"automatic_tax": {
|
||||
"enabled": false,
|
||||
"liability": null,
|
||||
"provider": null,
|
||||
"status": null
|
||||
},
|
||||
"billing_address_collection": null,
|
||||
"cancel_url": "http://localhost:3000/subscription/upgrade?plan=monthly",
|
||||
"client_reference_id": null,
|
||||
"client_secret": null,
|
||||
"collected_information": {
|
||||
"shipping_details": null
|
||||
},
|
||||
"consent": null,
|
||||
"consent_collection": null,
|
||||
"created": 1746281950,
|
||||
"currency": "usd",
|
||||
"currency_conversion": null,
|
||||
"custom_fields": [],
|
||||
"custom_text": {
|
||||
"after_submit": null,
|
||||
"shipping_address": null,
|
||||
"submit": null,
|
||||
"terms_of_service_acceptance": null
|
||||
},
|
||||
"customer": "cus_SFBH32Bf5lsggB",
|
||||
"customer_creation": "always",
|
||||
"customer_details": {
|
||||
"address": {
|
||||
"city": null,
|
||||
"country": "US",
|
||||
"line1": null,
|
||||
"line2": null,
|
||||
"postal_code": "12345",
|
||||
"state": null
|
||||
},
|
||||
"email": "user@maybe.local",
|
||||
"name": "Test Checkout User",
|
||||
"phone": null,
|
||||
"tax_exempt": "none",
|
||||
"tax_ids": []
|
||||
},
|
||||
"customer_email": "user@maybe.local",
|
||||
"discounts": [],
|
||||
"expires_at": 1746368350,
|
||||
"invoice": "in_1RKguoQT2jbOS8G0PuBVklxw",
|
||||
"invoice_creation": null,
|
||||
"livemode": false,
|
||||
"locale": null,
|
||||
"metadata": {},
|
||||
"mode": "subscription",
|
||||
"payment_intent": null,
|
||||
"payment_link": null,
|
||||
"payment_method_collection": "always",
|
||||
"payment_method_configuration_details": {
|
||||
"id": "pmc_1RJyv5QT2jbOS8G0PDwTVBar",
|
||||
"parent": null
|
||||
},
|
||||
"payment_method_options": {
|
||||
"card": {
|
||||
"request_three_d_secure": "automatic"
|
||||
}
|
||||
},
|
||||
"payment_method_types": [
|
||||
"card",
|
||||
"link",
|
||||
"cashapp",
|
||||
"amazon_pay"
|
||||
],
|
||||
"payment_status": "paid",
|
||||
"permissions": null,
|
||||
"phone_number_collection": {
|
||||
"enabled": false
|
||||
},
|
||||
"recovered_from": null,
|
||||
"saved_payment_method_options": {
|
||||
"allow_redisplay_filters": [
|
||||
"always"
|
||||
],
|
||||
"payment_method_remove": null,
|
||||
"payment_method_save": null
|
||||
},
|
||||
"setup_intent": null,
|
||||
"shipping_address_collection": null,
|
||||
"shipping_cost": null,
|
||||
"shipping_options": [],
|
||||
"status": "complete",
|
||||
"submit_type": null,
|
||||
"subscription": "sub_1RKguoQT2jbOS8G0Zih79ix9",
|
||||
"success_url": "http://localhost:3000/subscription/success?session_id={CHECKOUT_SESSION_ID}",
|
||||
"total_details": {
|
||||
"amount_discount": 0,
|
||||
"amount_shipping": 0,
|
||||
"amount_tax": 0
|
||||
},
|
||||
"ui_mode": "hosted",
|
||||
"url": null,
|
||||
"wallet_options": null
|
||||
}
|
||||
recorded_at: Mon, 05 May 2025 16:09:23 GMT
|
||||
recorded_with: VCR 6.3.1
|
298
test/vcr_cassettes/stripe/create_checkout_session.yml
Normal file
298
test/vcr_cassettes/stripe/create_checkout_session.yml
Normal file
|
@ -0,0 +1,298 @@
|
|||
---
|
||||
http_interactions:
|
||||
- request:
|
||||
method: post
|
||||
uri: https://api.stripe.com/v1/customers
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: email=test%40example.com&metadata[family_id]=1
|
||||
headers:
|
||||
User-Agent:
|
||||
- Stripe/v1 RubyBindings/15.1.0
|
||||
Authorization:
|
||||
- Bearer <STRIPE_SECRET_KEY>
|
||||
Idempotency-Key:
|
||||
- 7e129de1-324e-456a-8bd7-44382f6b4fa7
|
||||
Stripe-Version:
|
||||
- 2025-04-30.basil
|
||||
X-Stripe-Client-User-Agent:
|
||||
- '{"bindings_version":"15.1.0","lang":"ruby","lang_version":"3.4.1 p0 (2024-12-25)","platform":"arm64-darwin24","engine":"ruby","publisher":"stripe","uname":"Darwin
|
||||
Zachs-MacBook-Pro.local 24.3.0 Darwin Kernel Version 24.3.0: Thu Jan 2 20:24:16
|
||||
PST 2025; root:xnu-11215.81.4~3/RELEASE_ARM64_T6000 arm64","hostname":"Zachs-MacBook-Pro.local"}'
|
||||
Content-Type:
|
||||
- application/x-www-form-urlencoded
|
||||
Accept-Encoding:
|
||||
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
||||
Accept:
|
||||
- "*/*"
|
||||
response:
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
headers:
|
||||
Server:
|
||||
- nginx
|
||||
Date:
|
||||
- Mon, 05 May 2025 16:09:23 GMT
|
||||
Content-Type:
|
||||
- application/json
|
||||
Content-Length:
|
||||
- '652'
|
||||
Connection:
|
||||
- keep-alive
|
||||
Access-Control-Allow-Credentials:
|
||||
- 'true'
|
||||
Access-Control-Allow-Methods:
|
||||
- GET, HEAD, PUT, PATCH, POST, DELETE
|
||||
Access-Control-Allow-Origin:
|
||||
- "*"
|
||||
Access-Control-Expose-Headers:
|
||||
- Request-Id, Stripe-Manage-Version, Stripe-Should-Retry, X-Stripe-External-Auth-Required,
|
||||
X-Stripe-Privileged-Session-Required
|
||||
Access-Control-Max-Age:
|
||||
- '300'
|
||||
Cache-Control:
|
||||
- no-cache, no-store
|
||||
Content-Security-Policy:
|
||||
- base-uri 'none'; default-src 'none'; form-action 'none'; frame-ancestors 'none';
|
||||
img-src 'self'; script-src 'self' 'report-sample'; style-src 'self'; worker-src
|
||||
'none'; upgrade-insecure-requests; report-uri https://q.stripe.com/csp-violation?q=o27rhODPrC4hNe4D-N6JT0tcY2dQoSKNy5hNsSJNdH_SL3lHJ8eS2959Oc-3UnIGMeyex9H3Qo_613Zp
|
||||
Idempotency-Key:
|
||||
- 7e129de1-324e-456a-8bd7-44382f6b4fa7
|
||||
Original-Request:
|
||||
- req_LIU5SlUlOEkoOg
|
||||
Request-Id:
|
||||
- req_LIU5SlUlOEkoOg
|
||||
Stripe-Should-Retry:
|
||||
- 'false'
|
||||
Stripe-Version:
|
||||
- 2025-04-30.basil
|
||||
Vary:
|
||||
- Origin
|
||||
X-Stripe-Priority-Routing-Enabled:
|
||||
- 'true'
|
||||
X-Stripe-Routing-Context-Priority-Tier:
|
||||
- api-testmode
|
||||
X-Wc:
|
||||
- ABGHI
|
||||
Strict-Transport-Security:
|
||||
- max-age=63072000; includeSubDomains; preload
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: |-
|
||||
{
|
||||
"id": "cus_SFxVsSZ9enVBNC",
|
||||
"object": "customer",
|
||||
"address": null,
|
||||
"balance": 0,
|
||||
"created": 1746461363,
|
||||
"currency": null,
|
||||
"default_source": null,
|
||||
"delinquent": false,
|
||||
"description": null,
|
||||
"discount": null,
|
||||
"email": "test@example.com",
|
||||
"invoice_prefix": "JPHCOASK",
|
||||
"invoice_settings": {
|
||||
"custom_fields": null,
|
||||
"default_payment_method": null,
|
||||
"footer": null,
|
||||
"rendering_options": null
|
||||
},
|
||||
"livemode": false,
|
||||
"metadata": {
|
||||
"family_id": "1"
|
||||
},
|
||||
"name": null,
|
||||
"next_invoice_sequence": 1,
|
||||
"phone": null,
|
||||
"preferred_locales": [],
|
||||
"shipping": null,
|
||||
"tax_exempt": "none",
|
||||
"test_clock": null
|
||||
}
|
||||
recorded_at: Mon, 05 May 2025 16:09:23 GMT
|
||||
- request:
|
||||
method: post
|
||||
uri: https://api.stripe.com/v1/checkout/sessions
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: customer=cus_SFxVsSZ9enVBNC&line_items[0][price]=price_1RJz6KQT2jbOS8G0Otv3qD01&line_items[0][quantity]=1&mode=subscription&allow_promotion_codes=true&success_url=http%3A%2F%2Flocalhost%3A3000%2Fsubscription%2Fsuccess%3Fsession_id%3D%7BCHECKOUT_SESSION_ID%7D&cancel_url=http%3A%2F%2Flocalhost%3A3000%2Fsubscription%2Fupgrade
|
||||
headers:
|
||||
User-Agent:
|
||||
- Stripe/v1 RubyBindings/15.1.0
|
||||
Authorization:
|
||||
- Bearer <STRIPE_SECRET_KEY>
|
||||
X-Stripe-Client-Telemetry:
|
||||
- '{"last_request_metrics":{"request_id":"req_LIU5SlUlOEkoOg","request_duration_ms":307}}'
|
||||
Idempotency-Key:
|
||||
- d62353a3-199a-468d-9f78-a4fb10fa28bd
|
||||
Stripe-Version:
|
||||
- 2025-04-30.basil
|
||||
X-Stripe-Client-User-Agent:
|
||||
- '{"bindings_version":"15.1.0","lang":"ruby","lang_version":"3.4.1 p0 (2024-12-25)","platform":"arm64-darwin24","engine":"ruby","publisher":"stripe","uname":"Darwin
|
||||
Zachs-MacBook-Pro.local 24.3.0 Darwin Kernel Version 24.3.0: Thu Jan 2 20:24:16
|
||||
PST 2025; root:xnu-11215.81.4~3/RELEASE_ARM64_T6000 arm64","hostname":"Zachs-MacBook-Pro.local"}'
|
||||
Content-Type:
|
||||
- application/x-www-form-urlencoded
|
||||
Accept-Encoding:
|
||||
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
||||
Accept:
|
||||
- "*/*"
|
||||
response:
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
headers:
|
||||
Server:
|
||||
- nginx
|
||||
Date:
|
||||
- Mon, 05 May 2025 16:09:24 GMT
|
||||
Content-Type:
|
||||
- application/json
|
||||
Content-Length:
|
||||
- '2850'
|
||||
Connection:
|
||||
- keep-alive
|
||||
Access-Control-Allow-Credentials:
|
||||
- 'true'
|
||||
Access-Control-Allow-Methods:
|
||||
- GET, HEAD, PUT, PATCH, POST, DELETE
|
||||
Access-Control-Allow-Origin:
|
||||
- "*"
|
||||
Access-Control-Expose-Headers:
|
||||
- Request-Id, Stripe-Manage-Version, Stripe-Should-Retry, X-Stripe-External-Auth-Required,
|
||||
X-Stripe-Privileged-Session-Required
|
||||
Access-Control-Max-Age:
|
||||
- '300'
|
||||
Cache-Control:
|
||||
- no-cache, no-store
|
||||
Content-Security-Policy:
|
||||
- base-uri 'none'; default-src 'none'; form-action 'none'; frame-ancestors 'none';
|
||||
img-src 'self'; script-src 'self' 'report-sample'; style-src 'self'; worker-src
|
||||
'none'; upgrade-insecure-requests; report-uri https://q.stripe.com/csp-violation?q=7L6NHIm4wk05H5wi0PfH951BH62utb5j2ZImtzEXvcfJgdc1v5juGoNb0oSAXIHhGQtWiGOiCmz3UG1W
|
||||
Idempotency-Key:
|
||||
- d62353a3-199a-468d-9f78-a4fb10fa28bd
|
||||
Original-Request:
|
||||
- req_8AIKuqTzBWcO76
|
||||
Request-Id:
|
||||
- req_8AIKuqTzBWcO76
|
||||
Stripe-Should-Retry:
|
||||
- 'false'
|
||||
Stripe-Version:
|
||||
- 2025-04-30.basil
|
||||
Vary:
|
||||
- Origin
|
||||
X-Stripe-Priority-Routing-Enabled:
|
||||
- 'true'
|
||||
X-Stripe-Routing-Context-Priority-Tier:
|
||||
- api-testmode
|
||||
X-Wc:
|
||||
- ABGHI
|
||||
Strict-Transport-Security:
|
||||
- max-age=63072000; includeSubDomains; preload
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: |-
|
||||
{
|
||||
"id": "cs_test_b1lPPmtTEFw5w9GpyzQYlxz2TAN4JeUTosGjyXzfjkx9ocP59UhcF0WgWf",
|
||||
"object": "checkout.session",
|
||||
"adaptive_pricing": null,
|
||||
"after_expiration": null,
|
||||
"allow_promotion_codes": true,
|
||||
"amount_subtotal": 900,
|
||||
"amount_total": 900,
|
||||
"automatic_tax": {
|
||||
"enabled": false,
|
||||
"liability": null,
|
||||
"provider": null,
|
||||
"status": null
|
||||
},
|
||||
"billing_address_collection": null,
|
||||
"cancel_url": "http://localhost:3000/subscription/upgrade",
|
||||
"client_reference_id": null,
|
||||
"client_secret": null,
|
||||
"collected_information": {
|
||||
"shipping_details": null
|
||||
},
|
||||
"consent": null,
|
||||
"consent_collection": null,
|
||||
"created": 1746461364,
|
||||
"currency": "usd",
|
||||
"currency_conversion": null,
|
||||
"custom_fields": [],
|
||||
"custom_text": {
|
||||
"after_submit": null,
|
||||
"shipping_address": null,
|
||||
"submit": null,
|
||||
"terms_of_service_acceptance": null
|
||||
},
|
||||
"customer": "cus_SFxVsSZ9enVBNC",
|
||||
"customer_creation": null,
|
||||
"customer_details": {
|
||||
"address": null,
|
||||
"email": "test@example.com",
|
||||
"name": null,
|
||||
"phone": null,
|
||||
"tax_exempt": "none",
|
||||
"tax_ids": null
|
||||
},
|
||||
"customer_email": null,
|
||||
"discounts": [],
|
||||
"expires_at": 1746547763,
|
||||
"invoice": null,
|
||||
"invoice_creation": null,
|
||||
"livemode": false,
|
||||
"locale": null,
|
||||
"metadata": {},
|
||||
"mode": "subscription",
|
||||
"payment_intent": null,
|
||||
"payment_link": null,
|
||||
"payment_method_collection": "always",
|
||||
"payment_method_configuration_details": {
|
||||
"id": "pmc_1RJyv5QT2jbOS8G0PDwTVBar",
|
||||
"parent": null
|
||||
},
|
||||
"payment_method_options": {
|
||||
"card": {
|
||||
"request_three_d_secure": "automatic"
|
||||
}
|
||||
},
|
||||
"payment_method_types": [
|
||||
"card",
|
||||
"link",
|
||||
"cashapp",
|
||||
"amazon_pay"
|
||||
],
|
||||
"payment_status": "unpaid",
|
||||
"permissions": null,
|
||||
"phone_number_collection": {
|
||||
"enabled": false
|
||||
},
|
||||
"recovered_from": null,
|
||||
"saved_payment_method_options": {
|
||||
"allow_redisplay_filters": [
|
||||
"always"
|
||||
],
|
||||
"payment_method_remove": null,
|
||||
"payment_method_save": null
|
||||
},
|
||||
"setup_intent": null,
|
||||
"shipping_address_collection": null,
|
||||
"shipping_cost": null,
|
||||
"shipping_options": [],
|
||||
"status": "open",
|
||||
"submit_type": null,
|
||||
"subscription": null,
|
||||
"success_url": "http://localhost:3000/subscription/success?session_id={CHECKOUT_SESSION_ID}",
|
||||
"total_details": {
|
||||
"amount_discount": 0,
|
||||
"amount_shipping": 0,
|
||||
"amount_tax": 0
|
||||
},
|
||||
"ui_mode": "hosted",
|
||||
"url": "https://checkout.stripe.com/c/pay/cs_test_b1lPPmtTEFw5w9GpyzQYlxz2TAN4JeUTosGjyXzfjkx9ocP59UhcF0WgWf#fid2cGd2ZndsdXFsamtQa2x0cGBrYHZ2QGtkZ2lgYSc%2FY2RpdmApJ2R1bE5gfCc%2FJ3VuWnFgdnFaMDRXT3xwYVRRN29nSlY9QjUzNUttakJibmcxXH11Z2M8R3UzYUh3dGtNNlA8M3ExMTRKd0Z3M2p%2FdXdkcTNHcmg8NWA1YUx%2FbTRdTEM1cXI8TXNIT0FTRkY1NU5RME9EcjBpJyknY3dqaFZgd3Ngdyc%2FcXdwYCknaWR8anBxUXx1YCc%2FJ2hwaXFsWmxxYGgnKSdga2RnaWBVaWRmYG1qaWFgd3YnP3F3cGB4JSUl",
|
||||
"wallet_options": null
|
||||
}
|
||||
recorded_at: Mon, 05 May 2025 16:09:24 GMT
|
||||
recorded_with: VCR 6.3.1
|
Loading…
Add table
Add a link
Reference in a new issue