stripe-ruby-mock 3.0.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.github/workflows/rspec_tests.yml +38 -0
- data/.rspec +2 -1
- data/CHANGELOG.md +69 -0
- data/Gemfile +1 -0
- data/README.md +13 -5
- data/lib/stripe_mock/api/client.rb +1 -1
- data/lib/stripe_mock/api/errors.rb +3 -0
- data/lib/stripe_mock/api/instance.rb +1 -1
- data/lib/stripe_mock/api/webhooks.rb +66 -25
- data/lib/stripe_mock/client.rb +2 -1
- data/lib/stripe_mock/data/list.rb +42 -9
- data/lib/stripe_mock/data.rb +242 -31
- data/lib/stripe_mock/instance.rb +14 -3
- data/lib/stripe_mock/request_handlers/account_links.rb +15 -0
- data/lib/stripe_mock/request_handlers/accounts.rb +17 -6
- data/lib/stripe_mock/request_handlers/charges.rb +11 -4
- data/lib/stripe_mock/request_handlers/checkout_session.rb +179 -0
- data/lib/stripe_mock/request_handlers/customers.rb +35 -18
- data/lib/stripe_mock/request_handlers/ephemeral_key.rb +1 -1
- data/lib/stripe_mock/request_handlers/events.rb +30 -3
- data/lib/stripe_mock/request_handlers/express_login_links.rb +15 -0
- data/lib/stripe_mock/request_handlers/helpers/coupon_helpers.rb +6 -0
- data/lib/stripe_mock/request_handlers/helpers/subscription_helpers.rb +36 -12
- data/lib/stripe_mock/request_handlers/invoices.rb +10 -4
- data/lib/stripe_mock/request_handlers/payment_intents.rb +19 -1
- data/lib/stripe_mock/request_handlers/payment_methods.rb +10 -24
- data/lib/stripe_mock/request_handlers/plans.rb +1 -1
- data/lib/stripe_mock/request_handlers/prices.rb +62 -0
- data/lib/stripe_mock/request_handlers/promotion_codes.rb +43 -0
- data/lib/stripe_mock/request_handlers/refunds.rb +13 -2
- data/lib/stripe_mock/request_handlers/setup_intents.rb +16 -9
- data/lib/stripe_mock/request_handlers/sources.rb +12 -6
- data/lib/stripe_mock/request_handlers/subscriptions.rb +120 -21
- data/lib/stripe_mock/request_handlers/tokens.rb +6 -4
- data/lib/stripe_mock/request_handlers/transfers.rb +12 -1
- data/lib/stripe_mock/request_handlers/validators/param_validators.rb +33 -4
- data/lib/stripe_mock/server.rb +2 -2
- data/lib/stripe_mock/test_strategies/base.rb +62 -10
- data/lib/stripe_mock/version.rb +1 -1
- data/lib/stripe_mock/webhook_fixtures/account.updated.json +1 -1
- data/lib/stripe_mock/webhook_fixtures/balance.available.json +27 -15
- data/lib/stripe_mock/webhook_fixtures/charge.captured.json +143 -0
- data/lib/stripe_mock/webhook_fixtures/charge.dispute.created.json +63 -16
- data/lib/stripe_mock/webhook_fixtures/charge.failed.json +49 -120
- data/lib/stripe_mock/webhook_fixtures/charge.refund.updated.json +35 -0
- data/lib/stripe_mock/webhook_fixtures/charge.refunded.json +145 -50
- data/lib/stripe_mock/webhook_fixtures/charge.succeeded.json +114 -43
- data/lib/stripe_mock/webhook_fixtures/checkout.session.completed.json +79 -0
- data/lib/stripe_mock/webhook_fixtures/checkout.session.completed.payment_mode.json +53 -0
- data/lib/stripe_mock/webhook_fixtures/checkout.session.completed.setup_mode.json +45 -0
- data/lib/stripe_mock/webhook_fixtures/customer.created.json +37 -46
- data/lib/stripe_mock/webhook_fixtures/customer.deleted.json +36 -32
- data/lib/stripe_mock/webhook_fixtures/customer.source.created.json +31 -22
- data/lib/stripe_mock/webhook_fixtures/customer.source.updated.json +36 -25
- data/lib/stripe_mock/webhook_fixtures/customer.subscription.created.json +135 -47
- data/lib/stripe_mock/webhook_fixtures/customer.subscription.deleted.json +134 -45
- data/lib/stripe_mock/webhook_fixtures/customer.subscription.updated.json +135 -56
- data/lib/stripe_mock/webhook_fixtures/customer.updated.json +38 -47
- data/lib/stripe_mock/webhook_fixtures/invoice.created.json +176 -49
- data/lib/stripe_mock/webhook_fixtures/invoice.finalized.json +171 -0
- data/lib/stripe_mock/webhook_fixtures/invoice.paid.json +171 -0
- data/lib/stripe_mock/webhook_fixtures/invoice.payment_action_required.json +171 -0
- data/lib/stripe_mock/webhook_fixtures/invoice.payment_failed.json +149 -83
- data/lib/stripe_mock/webhook_fixtures/invoice.payment_succeeded.json +149 -90
- data/lib/stripe_mock/webhook_fixtures/invoice.upcoming.json +70 -0
- data/lib/stripe_mock/webhook_fixtures/invoice.updated.json +178 -50
- data/lib/stripe_mock/webhook_fixtures/invoiceitem.created.json +87 -13
- data/lib/stripe_mock/webhook_fixtures/invoiceitem.updated.json +88 -14
- data/lib/stripe_mock/webhook_fixtures/mandate.updated.json +34 -0
- data/lib/stripe_mock/webhook_fixtures/payment_intent.amount_capturable_updated.json +170 -0
- data/lib/stripe_mock/webhook_fixtures/payment_intent.canceled.json +73 -0
- data/lib/stripe_mock/webhook_fixtures/payment_intent.created.json +86 -0
- data/lib/stripe_mock/webhook_fixtures/payment_intent.payment_failed.json +225 -0
- data/lib/stripe_mock/webhook_fixtures/payment_intent.processing.json +162 -0
- data/lib/stripe_mock/webhook_fixtures/payment_intent.requires_action.json +191 -0
- data/lib/stripe_mock/webhook_fixtures/payment_intent.succeeded.json +196 -0
- data/lib/stripe_mock/webhook_fixtures/payment_link.created.json +47 -0
- data/lib/stripe_mock/webhook_fixtures/payment_link.updated.json +50 -0
- data/lib/stripe_mock/webhook_fixtures/payment_method.attached.json +63 -0
- data/lib/stripe_mock/webhook_fixtures/payment_method.detached.json +62 -0
- data/lib/stripe_mock/webhook_fixtures/payout.created.json +40 -0
- data/lib/stripe_mock/webhook_fixtures/payout.paid.json +40 -0
- data/lib/stripe_mock/webhook_fixtures/payout.updated.json +46 -0
- data/lib/stripe_mock/webhook_fixtures/plan.created.json +30 -13
- data/lib/stripe_mock/webhook_fixtures/plan.deleted.json +30 -13
- data/lib/stripe_mock/webhook_fixtures/plan.updated.json +34 -14
- data/lib/stripe_mock/webhook_fixtures/price.created.json +42 -0
- data/lib/stripe_mock/webhook_fixtures/price.deleted.json +42 -0
- data/lib/stripe_mock/webhook_fixtures/price.updated.json +48 -0
- data/lib/stripe_mock/webhook_fixtures/product.created.json +19 -13
- data/lib/stripe_mock/webhook_fixtures/product.deleted.json +20 -14
- data/lib/stripe_mock/webhook_fixtures/product.updated.json +24 -15
- data/lib/stripe_mock/webhook_fixtures/quote.accepted.json +92 -0
- data/lib/stripe_mock/webhook_fixtures/quote.canceled.json +92 -0
- data/lib/stripe_mock/webhook_fixtures/quote.created.json +92 -0
- data/lib/stripe_mock/webhook_fixtures/quote.finalized.json +92 -0
- data/lib/stripe_mock/webhook_fixtures/setup_intent.canceled.json +46 -0
- data/lib/stripe_mock/webhook_fixtures/setup_intent.created.json +51 -0
- data/lib/stripe_mock/webhook_fixtures/setup_intent.setup_failed.json +100 -0
- data/lib/stripe_mock/webhook_fixtures/setup_intent.succeeded.json +46 -0
- data/lib/stripe_mock/webhook_fixtures/subscription_schedule.canceled.json +119 -0
- data/lib/stripe_mock/webhook_fixtures/subscription_schedule.created.json +114 -0
- data/lib/stripe_mock/webhook_fixtures/subscription_schedule.released.json +111 -0
- data/lib/stripe_mock/webhook_fixtures/subscription_schedule.updated.json +125 -0
- data/lib/stripe_mock/webhook_fixtures/tax_rate.created.json +32 -0
- data/lib/stripe_mock/webhook_fixtures/tax_rate.updated.json +37 -0
- data/lib/stripe_mock.rb +7 -0
- data/spec/instance_spec.rb +7 -7
- data/spec/integration_examples/completing_checkout_sessions_example.rb +37 -0
- data/spec/list_spec.rb +38 -0
- data/spec/readme_spec.rb +1 -1
- data/spec/server_spec.rb +4 -2
- data/spec/shared_stripe_examples/account_examples.rb +9 -1
- data/spec/shared_stripe_examples/account_link_examples.rb +16 -0
- data/spec/shared_stripe_examples/balance_examples.rb +6 -0
- data/spec/shared_stripe_examples/card_token_examples.rb +17 -21
- data/spec/shared_stripe_examples/checkout_session_examples.rb +99 -0
- data/spec/shared_stripe_examples/customer_examples.rb +49 -23
- data/spec/shared_stripe_examples/express_login_link_examples.rb +12 -0
- data/spec/shared_stripe_examples/invoice_examples.rb +29 -8
- data/spec/shared_stripe_examples/payment_intent_examples.rb +84 -0
- data/spec/shared_stripe_examples/payment_method_examples.rb +336 -67
- data/spec/shared_stripe_examples/price_examples.rb +223 -0
- data/spec/shared_stripe_examples/product_examples.rb +1 -9
- data/spec/shared_stripe_examples/promotion_code_examples.rb +68 -0
- data/spec/shared_stripe_examples/refund_examples.rb +13 -0
- data/spec/shared_stripe_examples/setup_intent_examples.rb +17 -0
- data/spec/shared_stripe_examples/subscription_examples.rb +361 -9
- data/spec/shared_stripe_examples/transfer_examples.rb +10 -1
- data/spec/shared_stripe_examples/webhook_event_examples.rb +51 -5
- data/spec/spec_helper.rb +4 -0
- data/spec/stripe_mock_spec.rb +2 -2
- data/spec/support/stripe_examples.rb +8 -1
- data/stripe-ruby-mock.gemspec +7 -2
- metadata +73 -12
- data/.travis.yml +0 -28
@@ -0,0 +1,179 @@
|
|
1
|
+
module StripeMock
|
2
|
+
module RequestHandlers
|
3
|
+
module Checkout
|
4
|
+
module Session
|
5
|
+
def Session.included(klass)
|
6
|
+
klass.add_handler 'post /v1/checkout/sessions', :new_session
|
7
|
+
klass.add_handler 'get /v1/checkout/sessions', :list_checkout_sessions
|
8
|
+
klass.add_handler 'get /v1/checkout/sessions/([^/]*)', :get_checkout_session
|
9
|
+
klass.add_handler 'get /v1/checkout/sessions/([^/]*)/line_items', :list_line_items
|
10
|
+
end
|
11
|
+
|
12
|
+
def new_session(route, method_url, params, headers)
|
13
|
+
id = params[:id] || new_id('cs')
|
14
|
+
|
15
|
+
[:cancel_url, :success_url].each do |p|
|
16
|
+
require_param(p) if params[p].nil? || params[p].empty?
|
17
|
+
end
|
18
|
+
|
19
|
+
line_items = nil
|
20
|
+
if params[:line_items]
|
21
|
+
line_items = params[:line_items].each_with_index.map do |line_item, i|
|
22
|
+
throw Stripe::InvalidRequestError("Quantity is required. Add `quantity` to `line_items[#{i}]`") unless line_item[:quantity]
|
23
|
+
unless line_item[:price] || line_item[:price_data] || (line_item[:amount] && line_item[:currency] && line_item[:name])
|
24
|
+
throw Stripe::InvalidRequestError("Price or amount and currency is required. Add `price`, `price_data`, or `amount`, `currency` and `name` to `line_items[#{i}]`")
|
25
|
+
end
|
26
|
+
{
|
27
|
+
id: new_id("li"),
|
28
|
+
price: if line_item[:price]
|
29
|
+
line_item[:price]
|
30
|
+
elsif line_item[:price_data]
|
31
|
+
new_price(nil, nil, line_item[:price_data], nil)[:id]
|
32
|
+
else
|
33
|
+
new_price(nil, nil, {
|
34
|
+
unit_amount: line_item[:amount],
|
35
|
+
currency: line_item[:currency],
|
36
|
+
product_data: {
|
37
|
+
name: line_item[:name]
|
38
|
+
}
|
39
|
+
}, nil)[:id]
|
40
|
+
end,
|
41
|
+
quantity: line_item[:quantity]
|
42
|
+
}
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
amount = nil
|
47
|
+
currency = nil
|
48
|
+
if line_items
|
49
|
+
amount = 0
|
50
|
+
|
51
|
+
line_items.each do |line_item|
|
52
|
+
price = prices[line_item[:price]]
|
53
|
+
|
54
|
+
if price.nil?
|
55
|
+
raise StripeMock::StripeMockError.new("Price not found for ID: #{line_item[:price]}")
|
56
|
+
end
|
57
|
+
|
58
|
+
amount += (price[:unit_amount] * line_item[:quantity])
|
59
|
+
end
|
60
|
+
|
61
|
+
currency = prices[line_items.first[:price]][:currency]
|
62
|
+
end
|
63
|
+
|
64
|
+
payment_status = "unpaid"
|
65
|
+
payment_intent = nil
|
66
|
+
setup_intent = nil
|
67
|
+
case params[:mode]
|
68
|
+
when nil, "payment"
|
69
|
+
params[:customer] ||= new_customer(nil, nil, {email: params[:customer_email]}, nil)[:id]
|
70
|
+
require_param(:line_items) if params[:line_items].nil? || params[:line_items].empty?
|
71
|
+
payment_intent = new_payment_intent(nil, nil, {
|
72
|
+
amount: amount,
|
73
|
+
currency: currency,
|
74
|
+
customer: params[:customer],
|
75
|
+
payment_method_options: params[:payment_method_options],
|
76
|
+
payment_method_types: params[:payment_method_types]
|
77
|
+
}.merge(params[:payment_intent_data] || {}), nil)[:id]
|
78
|
+
checkout_session_line_items[id] = line_items
|
79
|
+
when "setup"
|
80
|
+
if !params[:line_items].nil? && !params[:line_items].empty?
|
81
|
+
throw Stripe::InvalidRequestError.new("You cannot pass `line_items` in `setup` mode", :line_items, http_status: 400)
|
82
|
+
end
|
83
|
+
setup_intent = new_setup_intent(nil, nil, {
|
84
|
+
customer: params[:customer],
|
85
|
+
payment_method_options: params[:payment_method_options],
|
86
|
+
payment_method_types: params[:payment_method_types]
|
87
|
+
}.merge(params[:setup_intent_data] || {}), nil)[:id]
|
88
|
+
payment_status = "no_payment_required"
|
89
|
+
when "subscription"
|
90
|
+
params[:customer] ||= new_customer(nil, nil, {email: params[:customer_email]}, nil)[:id]
|
91
|
+
require_param(:line_items) if params[:line_items].nil? || params[:line_items].empty?
|
92
|
+
checkout_session_line_items[id] = line_items
|
93
|
+
else
|
94
|
+
throw Stripe::InvalidRequestError.new("Invalid mode: must be one of payment, setup, or subscription", :mode, http_status: 400)
|
95
|
+
end
|
96
|
+
|
97
|
+
checkout_sessions[id] = {
|
98
|
+
id: id,
|
99
|
+
object: "checkout.session",
|
100
|
+
allow_promotion_codes: nil,
|
101
|
+
amount_subtotal: amount,
|
102
|
+
amount_total: amount,
|
103
|
+
automatic_tax: {
|
104
|
+
enabled: false,
|
105
|
+
status: nil
|
106
|
+
},
|
107
|
+
billing_address_collection: nil,
|
108
|
+
cancel_url: params[:cancel_url],
|
109
|
+
client_reference_id: nil,
|
110
|
+
currency: currency,
|
111
|
+
customer: params[:customer],
|
112
|
+
customer_details: nil,
|
113
|
+
customer_email: params[:customer_email],
|
114
|
+
livemode: false,
|
115
|
+
locale: nil,
|
116
|
+
metadata: params[:metadata],
|
117
|
+
mode: params[:mode],
|
118
|
+
payment_intent: payment_intent,
|
119
|
+
payment_method_options: params[:payment_method_options],
|
120
|
+
payment_method_types: params[:payment_method_types],
|
121
|
+
payment_status: payment_status,
|
122
|
+
setup_intent: setup_intent,
|
123
|
+
shipping: nil,
|
124
|
+
shipping_address_collection: nil,
|
125
|
+
submit_type: nil,
|
126
|
+
subscription: nil,
|
127
|
+
success_url: params[:success_url],
|
128
|
+
total_details: nil,
|
129
|
+
url: URI.join(StripeMock.checkout_base, id).to_s
|
130
|
+
}
|
131
|
+
end
|
132
|
+
|
133
|
+
def list_checkout_sessions(route, method_url, params, headers)
|
134
|
+
Data.mock_list_object(checkout_sessions.values)
|
135
|
+
end
|
136
|
+
|
137
|
+
def get_checkout_session(route, method_url, params, headers)
|
138
|
+
route =~ method_url
|
139
|
+
checkout_session = assert_existence :checkout_session, $1, checkout_sessions[$1]
|
140
|
+
|
141
|
+
checkout_session = checkout_session.clone
|
142
|
+
if params[:expand]&.include?('setup_intent') && checkout_session[:setup_intent]
|
143
|
+
checkout_session[:setup_intent] = setup_intents[checkout_session[:setup_intent]]
|
144
|
+
end
|
145
|
+
checkout_session
|
146
|
+
end
|
147
|
+
|
148
|
+
def list_line_items(route, method_url, params, headers)
|
149
|
+
route =~ method_url
|
150
|
+
checkout_session = assert_existence :checkout_session, $1, checkout_sessions[$1]
|
151
|
+
|
152
|
+
case checkout_session[:mode]
|
153
|
+
when "payment", "subscription"
|
154
|
+
line_items = assert_existence :checkout_session_line_items, $1, checkout_session_line_items[$1]
|
155
|
+
line_items.map do |line_item|
|
156
|
+
price = prices[line_item[:price]].clone
|
157
|
+
|
158
|
+
if price.nil?
|
159
|
+
raise StripeMock::StripeMockError.new("Price not found for ID: #{line_item[:price]}")
|
160
|
+
end
|
161
|
+
|
162
|
+
{
|
163
|
+
id: line_item[:id],
|
164
|
+
object: "item",
|
165
|
+
amount_subtotal: price[:unit_amount] * line_item[:quantity],
|
166
|
+
amount_total: price[:unit_amount] * line_item[:quantity],
|
167
|
+
currency: price[:currency],
|
168
|
+
price: price.clone,
|
169
|
+
quantity: line_item[:quantity]
|
170
|
+
}
|
171
|
+
end
|
172
|
+
else
|
173
|
+
throw Stripe::InvalidRequestError("Only payment and subscription sessions have line items")
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
@@ -12,6 +12,7 @@ module StripeMock
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def new_customer(route, method_url, params, headers)
|
15
|
+
stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
15
16
|
params[:id] ||= new_id('cus')
|
16
17
|
sources = []
|
17
18
|
|
@@ -29,7 +30,8 @@ module StripeMock
|
|
29
30
|
params[:default_source] = sources.first[:id]
|
30
31
|
end
|
31
32
|
|
32
|
-
customers[
|
33
|
+
customers[stripe_account] ||= {}
|
34
|
+
customers[stripe_account][params[:id]] = Data.mock_customer(sources, params)
|
33
35
|
|
34
36
|
if params[:plan]
|
35
37
|
plan_id = params[:plan].to_s
|
@@ -40,26 +42,30 @@ module StripeMock
|
|
40
42
|
end
|
41
43
|
|
42
44
|
subscription = Data.mock_subscription({ id: new_id('su') })
|
43
|
-
subscription = resolve_subscription_changes(subscription, [plan], customers[
|
44
|
-
add_subscription_to_customer(customers[
|
45
|
+
subscription = resolve_subscription_changes(subscription, [plan], customers[stripe_account][params[:id]], params)
|
46
|
+
add_subscription_to_customer(customers[stripe_account][params[:id]], subscription)
|
45
47
|
subscriptions[subscription[:id]] = subscription
|
46
48
|
elsif params[:trial_end]
|
47
49
|
raise Stripe::InvalidRequestError.new('Received unknown parameter: trial_end', nil, http_status: 400)
|
48
50
|
end
|
49
51
|
|
50
52
|
if params[:coupon]
|
51
|
-
coupon = coupons[
|
53
|
+
coupon = coupons[params[:coupon]]
|
52
54
|
assert_existence :coupon, params[:coupon], coupon
|
53
|
-
|
54
|
-
add_coupon_to_object(customers[params[:id]], coupon)
|
55
|
+
add_coupon_to_object(customers[stripe_account][params[:id]], coupon)
|
55
56
|
end
|
56
57
|
|
57
|
-
customers[
|
58
|
+
customers[stripe_account][params[:id]]
|
58
59
|
end
|
59
60
|
|
60
61
|
def update_customer(route, method_url, params, headers)
|
62
|
+
stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
61
63
|
route =~ method_url
|
62
|
-
cus = assert_existence :customer, $1, customers[$1]
|
64
|
+
cus = assert_existence :customer, $1, customers[stripe_account][$1]
|
65
|
+
|
66
|
+
# get existing and pending metadata
|
67
|
+
metadata = cus.delete(:metadata) || {}
|
68
|
+
metadata_updates = params.delete(:metadata) || {}
|
63
69
|
|
64
70
|
# Delete those params if their value is nil. Workaround of the problematic way Stripe serialize objects
|
65
71
|
params.delete(:sources) if params[:sources] && params[:sources][:data].nil?
|
@@ -72,10 +78,13 @@ module StripeMock
|
|
72
78
|
params.delete(:subscriptions) unless params[:subscriptions][:data].any?{ |v| !!v[:type]}
|
73
79
|
end
|
74
80
|
cus.merge!(params)
|
81
|
+
cus[:metadata] = {**metadata, **metadata_updates}
|
75
82
|
|
76
83
|
if params[:source]
|
77
84
|
if params[:source].is_a?(String)
|
78
85
|
new_card = get_card_or_bank_by_token(params.delete(:source))
|
86
|
+
elsif params[:source].is_a?(Stripe::Token)
|
87
|
+
new_card = get_card_or_bank_by_token(params[:source][:id])
|
79
88
|
elsif params[:source].is_a?(Hash)
|
80
89
|
unless params[:source][:object] && params[:source][:number] && params[:source][:exp_month] && params[:source][:exp_year]
|
81
90
|
raise Stripe::InvalidRequestError.new('You must supply a valid card', nil, http_status: 400)
|
@@ -87,31 +96,37 @@ module StripeMock
|
|
87
96
|
end
|
88
97
|
|
89
98
|
if params[:coupon]
|
90
|
-
|
91
|
-
|
99
|
+
if params[:coupon] == ''
|
100
|
+
delete_coupon_from_object(cus)
|
101
|
+
else
|
102
|
+
coupon = coupons[params[:coupon]]
|
103
|
+
assert_existence :coupon, params[:coupon], coupon
|
92
104
|
|
93
|
-
|
105
|
+
add_coupon_to_object(cus, coupon)
|
106
|
+
end
|
94
107
|
end
|
95
108
|
|
96
109
|
cus
|
97
110
|
end
|
98
111
|
|
99
112
|
def delete_customer(route, method_url, params, headers)
|
113
|
+
stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
100
114
|
route =~ method_url
|
101
|
-
assert_existence :customer, $1, customers[$1]
|
115
|
+
assert_existence :customer, $1, customers[stripe_account][$1]
|
102
116
|
|
103
|
-
customers[$1] = {
|
104
|
-
id: customers[$1][:id],
|
117
|
+
customers[stripe_account][$1] = {
|
118
|
+
id: customers[stripe_account][$1][:id],
|
105
119
|
deleted: true
|
106
120
|
}
|
107
121
|
end
|
108
122
|
|
109
123
|
def get_customer(route, method_url, params, headers)
|
124
|
+
stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
110
125
|
route =~ method_url
|
111
|
-
customer = assert_existence :customer, $1, customers[$1]
|
126
|
+
customer = assert_existence :customer, $1, customers[stripe_account][$1]
|
112
127
|
|
113
128
|
customer = customer.clone
|
114
|
-
if params[:expand] == ['default_source']
|
129
|
+
if params[:expand] == ['default_source'] && customer[:sources][:data]
|
115
130
|
customer[:default_source] = customer[:sources][:data].detect do |source|
|
116
131
|
source[:id] == customer[:default_source]
|
117
132
|
end
|
@@ -121,12 +136,14 @@ module StripeMock
|
|
121
136
|
end
|
122
137
|
|
123
138
|
def list_customers(route, method_url, params, headers)
|
124
|
-
|
139
|
+
stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
140
|
+
Data.mock_list_object(customers[stripe_account]&.values, params)
|
125
141
|
end
|
126
142
|
|
127
143
|
def delete_customer_discount(route, method_url, params, headers)
|
144
|
+
stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
128
145
|
route =~ method_url
|
129
|
-
cus = assert_existence :customer, $1, customers[$1]
|
146
|
+
cus = assert_existence :customer, $1, customers[stripe_account][$1]
|
130
147
|
|
131
148
|
cus[:discount] = nil
|
132
149
|
|
@@ -4,7 +4,7 @@ module StripeMock
|
|
4
4
|
|
5
5
|
def Events.included(klass)
|
6
6
|
klass.add_handler 'get /v1/events/(.*)', :retrieve_event
|
7
|
-
klass.add_handler 'get /v1/events', :list_events
|
7
|
+
klass.add_handler 'get /v1/events', :list_events
|
8
8
|
end
|
9
9
|
|
10
10
|
def retrieve_event(route, method_url, params, headers)
|
@@ -13,9 +13,36 @@ module StripeMock
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def list_events(route, method_url, params, headers)
|
16
|
-
|
16
|
+
values = filter_by_created(events.values, params: params)
|
17
|
+
Data.mock_list_object(values, params)
|
17
18
|
end
|
18
|
-
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def filter_by_created(event_list, params:)
|
23
|
+
if params[:created].nil?
|
24
|
+
return event_list
|
25
|
+
end
|
26
|
+
|
27
|
+
if params[:created].is_a?(Hash)
|
28
|
+
if params[:created][:gt]
|
29
|
+
event_list = event_list.select { |event| event[:created] > params[:created][:gt].to_i }
|
30
|
+
end
|
31
|
+
if params[:created][:gte]
|
32
|
+
event_list = event_list.select { |event| event[:created] >= params[:created][:gte].to_i }
|
33
|
+
end
|
34
|
+
if params[:created][:lt]
|
35
|
+
event_list = event_list.select { |event| event[:created] < params[:created][:lt].to_i }
|
36
|
+
end
|
37
|
+
if params[:created][:lte]
|
38
|
+
event_list = event_list.select { |event| event[:created] <= params[:created][:lte].to_i }
|
39
|
+
end
|
40
|
+
else
|
41
|
+
event_list = event_list.select { |event| event[:created] == params[:created].to_i }
|
42
|
+
end
|
43
|
+
event_list
|
44
|
+
end
|
45
|
+
|
19
46
|
end
|
20
47
|
end
|
21
48
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module StripeMock
|
2
|
+
module RequestHandlers
|
3
|
+
module ExpressLoginLinks
|
4
|
+
|
5
|
+
def ExpressLoginLinks.included(klass)
|
6
|
+
klass.add_handler 'post /v1/accounts/(.*)/login_links', :new_account_login_link
|
7
|
+
end
|
8
|
+
|
9
|
+
def new_account_login_link(route, method_url, params, headers)
|
10
|
+
route =~ method_url
|
11
|
+
Data.mock_express_login_link(params)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -7,11 +7,17 @@ module StripeMock
|
|
7
7
|
attrs[:coupon] = coupon
|
8
8
|
attrs[:start] = Time.now.to_i
|
9
9
|
attrs[:end] = (DateTime.now >> coupon[:duration_in_months].to_i).to_time.to_i if coupon[:duration] == 'repeating'
|
10
|
+
attrs[:id] = new_id("di")
|
10
11
|
end
|
11
12
|
|
12
13
|
object[:discount] = Stripe::Discount.construct_from(discount_attrs)
|
13
14
|
object
|
14
15
|
end
|
16
|
+
|
17
|
+
def delete_coupon_from_object(object)
|
18
|
+
object[:discount] = nil
|
19
|
+
object
|
20
|
+
end
|
15
21
|
end
|
16
22
|
end
|
17
23
|
end
|
@@ -11,12 +11,17 @@ module StripeMock
|
|
11
11
|
items = options[:items]
|
12
12
|
items = items.values if items.respond_to?(:values)
|
13
13
|
subscription[:items][:data] = plans.map do |plan|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
14
|
+
matching_item = items && items.detect { |item| [item[:price], item[:plan]].include? plan[:id] }
|
15
|
+
if matching_item
|
16
|
+
matching_item[:quantity] ||= 1
|
17
|
+
matching_item[:id] ||= new_id('si')
|
18
|
+
params = matching_item.merge(plan: plan)
|
19
|
+
params[:price] = plan if plan[:object] == "price"
|
20
|
+
Data.mock_subscription_item(params)
|
18
21
|
else
|
19
|
-
|
22
|
+
params = { plan: plan, id: new_id('si') }
|
23
|
+
params[:price] = plan if plan[:object] == "price"
|
24
|
+
Data.mock_subscription_item(params)
|
20
25
|
end
|
21
26
|
end
|
22
27
|
subscription
|
@@ -32,7 +37,7 @@ module StripeMock
|
|
32
37
|
start_time = options[:current_period_start] || now
|
33
38
|
params = { customer: cus[:id], current_period_start: start_time, created: created_time }
|
34
39
|
params.merge!({ :plan => (plans.size == 1 ? plans.first : nil) })
|
35
|
-
keys_to_merge = /application_fee_percent|quantity|metadata|tax_percent|billing|days_until_due|default_tax_rates/
|
40
|
+
keys_to_merge = /application_fee_percent|quantity|metadata|tax_percent|billing|days_until_due|default_tax_rates|pending_invoice_item_interval|default_payment_method|collection_method/
|
36
41
|
params.merge! options.select {|k,v| k =~ keys_to_merge}
|
37
42
|
|
38
43
|
if options[:cancel_at_period_end] == true
|
@@ -45,10 +50,10 @@ module StripeMock
|
|
45
50
|
|
46
51
|
if (((plan && plan[:trial_period_days]) || 0) == 0 && options[:trial_end].nil?) || options[:trial_end] == "now"
|
47
52
|
end_time = options[:billing_cycle_anchor] || get_ending_time(start_time, plan)
|
48
|
-
params.merge!({status: 'active', current_period_end: end_time, trial_start: nil, trial_end: nil, billing_cycle_anchor: options[:billing_cycle_anchor]})
|
53
|
+
params.merge!({status: 'active', current_period_end: end_time, trial_start: nil, trial_end: nil, billing_cycle_anchor: options[:billing_cycle_anchor] || created_time})
|
49
54
|
else
|
50
55
|
end_time = options[:trial_end] || (Time.now.utc.to_i + plan[:trial_period_days]*86400)
|
51
|
-
params.merge!({status: 'trialing', current_period_end: end_time, trial_start: start_time, trial_end: end_time, billing_cycle_anchor:
|
56
|
+
params.merge!({status: 'trialing', current_period_end: end_time, trial_start: start_time, trial_end: end_time, billing_cycle_anchor: options[:billing_cycle_anchor] || created_time})
|
52
57
|
end
|
53
58
|
|
54
59
|
params
|
@@ -85,11 +90,13 @@ module StripeMock
|
|
85
90
|
def get_ending_time(start_time, plan, intervals = 1)
|
86
91
|
return start_time unless plan
|
87
92
|
|
88
|
-
|
93
|
+
interval = plan[:interval] || plan.dig(:recurring, :interval)
|
94
|
+
interval_count = plan[:interval_count] || plan.dig(:recurring, :interval_count) || 1
|
95
|
+
case interval
|
89
96
|
when "week"
|
90
|
-
start_time + (604800 * (
|
97
|
+
start_time + (604800 * (interval_count) * intervals)
|
91
98
|
when "month"
|
92
|
-
(Time.at(start_time).to_datetime >> ((
|
99
|
+
(Time.at(start_time).to_datetime >> ((interval_count) * intervals)).to_time.to_i
|
93
100
|
when "year"
|
94
101
|
(Time.at(start_time).to_datetime >> (12 * intervals)).to_time.to_i # max period is 1 year
|
95
102
|
else
|
@@ -111,9 +118,26 @@ module StripeMock
|
|
111
118
|
|
112
119
|
def total_items_amount(items)
|
113
120
|
total = 0
|
114
|
-
items.each
|
121
|
+
items.each do |item|
|
122
|
+
quantity = item[:quantity] || 1
|
123
|
+
amount = item[:plan][:unit_amount] || item[:plan][:amount]
|
124
|
+
total += quantity * amount
|
125
|
+
end
|
115
126
|
total
|
116
127
|
end
|
128
|
+
|
129
|
+
def filter_by_timestamp(subscriptions, field:, value:)
|
130
|
+
if value.is_a?(Hash)
|
131
|
+
operator_mapping = { gt: :>, gte: :>=, lt: :<, lte: :<= }
|
132
|
+
subscriptions.filter do |sub|
|
133
|
+
sub[field].public_send(operator_mapping[value.keys[0]], value.values[0])
|
134
|
+
end
|
135
|
+
else
|
136
|
+
subscriptions.filter do |sub|
|
137
|
+
sub[field] == value
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
117
141
|
end
|
118
142
|
end
|
119
143
|
end
|
@@ -53,16 +53,22 @@ module StripeMock
|
|
53
53
|
route =~ method_url
|
54
54
|
assert_existence :invoice, $1, invoices[$1]
|
55
55
|
charge = invoice_charge(invoices[$1])
|
56
|
-
invoices[$1].merge!(
|
56
|
+
invoices[$1].merge!(
|
57
|
+
:paid => true,
|
58
|
+
:status => "paid",
|
59
|
+
:attempted => true,
|
60
|
+
:charge => charge[:id],
|
61
|
+
)
|
57
62
|
end
|
58
63
|
|
59
|
-
def upcoming_invoice(route, method_url, params, headers)
|
64
|
+
def upcoming_invoice(route, method_url, params, headers = {})
|
65
|
+
stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
60
66
|
route =~ method_url
|
61
|
-
raise Stripe::InvalidRequestError.new('Missing required param: customer', nil, http_status: 400) if params[:customer].nil?
|
67
|
+
raise Stripe::InvalidRequestError.new('Missing required param: customer if subscription is not provided', nil, http_status: 400) if params[:customer].nil? && params[:subscription].nil?
|
62
68
|
raise Stripe::InvalidRequestError.new('When previewing changes to a subscription, you must specify either `subscription` or `subscription_items`', nil, http_status: 400) if !params[:subscription_proration_date].nil? && params[:subscription].nil? && params[:subscription_plan].nil?
|
63
69
|
raise Stripe::InvalidRequestError.new('Cannot specify proration date without specifying a subscription', nil, http_status: 400) if !params[:subscription_proration_date].nil? && params[:subscription].nil?
|
64
70
|
|
65
|
-
customer = customers[params[:customer]]
|
71
|
+
customer = customers[stripe_account][params[:customer]]
|
66
72
|
assert_existence :customer, params[:customer], customer
|
67
73
|
|
68
74
|
raise Stripe::InvalidRequestError.new("No upcoming invoices for customer: #{customer[:id]}", nil, http_status: 404) if customer[:subscriptions][:data].length == 0
|
@@ -20,6 +20,7 @@ module StripeMock
|
|
20
20
|
status = case params[:amount]
|
21
21
|
when 3184 then 'requires_action'
|
22
22
|
when 3178 then 'requires_payment_method'
|
23
|
+
when 3055 then 'requires_capture'
|
23
24
|
else
|
24
25
|
'succeeded'
|
25
26
|
end
|
@@ -80,6 +81,10 @@ module StripeMock
|
|
80
81
|
route =~ method_url
|
81
82
|
payment_intent = assert_existence :payment_intent, $1, payment_intents[$1]
|
82
83
|
|
84
|
+
if params[:payment_method]
|
85
|
+
payment_intent[:payment_method] = params[:payment_method]
|
86
|
+
end
|
87
|
+
|
83
88
|
succeeded_payment_intent(payment_intent)
|
84
89
|
end
|
85
90
|
|
@@ -167,7 +172,20 @@ module StripeMock
|
|
167
172
|
def succeeded_payment_intent(payment_intent)
|
168
173
|
payment_intent[:status] = 'succeeded'
|
169
174
|
btxn = new_balance_transaction('txn', { source: payment_intent[:id] })
|
170
|
-
|
175
|
+
|
176
|
+
charge_id = new_id('ch')
|
177
|
+
|
178
|
+
charges[charge_id] = Data.mock_charge(
|
179
|
+
id: charge_id,
|
180
|
+
balance_transaction: btxn,
|
181
|
+
payment_intent: payment_intent[:id],
|
182
|
+
amount: payment_intent[:amount],
|
183
|
+
currency: payment_intent[:currency],
|
184
|
+
payment_method: payment_intent[:payment_method]
|
185
|
+
)
|
186
|
+
|
187
|
+
payment_intent[:charges][:data] << charges[charge_id].clone
|
188
|
+
|
171
189
|
payment_intent
|
172
190
|
end
|
173
191
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
module StripeMock
|
2
2
|
module RequestHandlers
|
3
3
|
module PaymentMethods
|
4
|
-
|
5
4
|
ALLOWED_PARAMS = [:customer, :type]
|
6
5
|
|
7
6
|
def PaymentMethods.included(klass)
|
@@ -53,33 +52,14 @@ module StripeMock
|
|
53
52
|
Data.mock_list_object(clone.values, params)
|
54
53
|
end
|
55
54
|
|
56
|
-
#
|
57
|
-
# params: {:customer=>"test_cus_3"}
|
58
|
-
#
|
59
|
-
def attach_payment_method(route, method_url, params, headers)
|
60
|
-
route =~ method_url
|
61
|
-
id = $1
|
62
|
-
payment_methods[id].merge!(params)
|
63
|
-
payment_methods[id].clone
|
64
|
-
end
|
65
|
-
|
66
|
-
def detach_payment_method(route, method_url, params, headers)
|
67
|
-
|
68
|
-
end
|
69
|
-
|
70
|
-
def get_payment_method(route, method_url, params, headers)
|
71
|
-
route =~ method_url
|
72
|
-
id = $1
|
73
|
-
assert_existence(:payment_method, $1, payment_methods[id])
|
74
|
-
end
|
75
|
-
|
76
55
|
# post /v1/payment_methods/:id/attach
|
77
56
|
def attach_payment_method(route, method_url, params, headers)
|
57
|
+
stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
78
58
|
allowed_params = [:customer]
|
79
59
|
|
80
60
|
id = method_url.match(route)[1]
|
81
61
|
|
82
|
-
assert_existence :customer, params[:customer], customers[params[:customer]]
|
62
|
+
assert_existence :customer, params[:customer], customers[stripe_account][params[:customer]]
|
83
63
|
|
84
64
|
payment_method = assert_existence :payment_method, id, payment_methods[id]
|
85
65
|
payment_methods[id] = Util.rmerge(payment_method, params.select { |k, _v| allowed_params.include?(k) })
|
@@ -99,6 +79,10 @@ module StripeMock
|
|
99
79
|
# post /v1/payment_methods/:id
|
100
80
|
def update_payment_method(route, method_url, params, headers)
|
101
81
|
allowed_params = [:billing_details, :card, :metadata]
|
82
|
+
disallowed_params = params.keys - allowed_params
|
83
|
+
unless disallowed_params.empty?
|
84
|
+
raise Stripe::InvalidRequestError.new("Received unknown parameter: #{disallowed_params.first}", disallowed_params.first)
|
85
|
+
end
|
102
86
|
|
103
87
|
id = method_url.match(route)[1]
|
104
88
|
|
@@ -107,6 +91,7 @@ module StripeMock
|
|
107
91
|
if payment_method[:customer].nil?
|
108
92
|
raise Stripe::InvalidRequestError.new(
|
109
93
|
'You must save this PaymentMethod to a customer before you can update it.',
|
94
|
+
nil,
|
110
95
|
http_status: 400
|
111
96
|
)
|
112
97
|
end
|
@@ -124,14 +109,15 @@ module StripeMock
|
|
124
109
|
|
125
110
|
if invalid_type?(params[:type])
|
126
111
|
raise Stripe::InvalidRequestError.new(
|
127
|
-
'Invalid type: must be one of card or
|
112
|
+
'Invalid type: must be one of card, ideal or sepa_debit',
|
113
|
+
nil,
|
128
114
|
http_status: 400
|
129
115
|
)
|
130
116
|
end
|
131
117
|
end
|
132
118
|
|
133
119
|
def invalid_type?(type)
|
134
|
-
|
120
|
+
!%w(card ideal sepa_debit).include?(type)
|
135
121
|
end
|
136
122
|
end
|
137
123
|
end
|
@@ -34,7 +34,7 @@ module StripeMock
|
|
34
34
|
|
35
35
|
def list_plans(route, method_url, params, headers)
|
36
36
|
limit = params[:limit] ? params[:limit] : 10
|
37
|
-
Data.mock_list_object(plans.values.first(limit), limit: limit)
|
37
|
+
Data.mock_list_object(plans.values.first(limit), params.merge!(limit: limit))
|
38
38
|
end
|
39
39
|
|
40
40
|
end
|