stripe-ruby-mock 2.5.8 → 4.0.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/.gitignore +1 -1
- data/.rspec +2 -1
- data/CHANGELOG.md +77 -0
- data/Gemfile +1 -5
- data/README.md +19 -11
- data/lib/stripe_mock/api/client.rb +2 -2
- data/lib/stripe_mock/api/errors.rb +34 -28
- data/lib/stripe_mock/api/instance.rb +1 -1
- data/lib/stripe_mock/api/webhooks.rb +68 -24
- data/lib/stripe_mock/client.rb +2 -1
- data/lib/stripe_mock/data/list.rb +42 -9
- data/lib/stripe_mock/data.rb +359 -21
- data/lib/stripe_mock/instance.rb +23 -5
- 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/balance_transactions.rb +2 -2
- data/lib/stripe_mock/request_handlers/charges.rb +31 -5
- data/lib/stripe_mock/request_handlers/checkout_session.rb +179 -0
- data/lib/stripe_mock/request_handlers/customers.rb +47 -19
- 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/search_helpers.rb +67 -0
- data/lib/stripe_mock/request_handlers/helpers/subscription_helpers.rb +36 -12
- data/lib/stripe_mock/request_handlers/helpers/token_helpers.rb +1 -1
- data/lib/stripe_mock/request_handlers/invoices.rb +26 -6
- data/lib/stripe_mock/request_handlers/payment_intents.rb +202 -0
- data/lib/stripe_mock/request_handlers/payment_methods.rb +124 -0
- data/lib/stripe_mock/request_handlers/plans.rb +1 -1
- data/lib/stripe_mock/request_handlers/prices.rb +71 -0
- data/lib/stripe_mock/request_handlers/products.rb +15 -5
- 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 +100 -0
- data/lib/stripe_mock/request_handlers/sources.rb +12 -6
- data/lib/stripe_mock/request_handlers/subscriptions.rb +146 -25
- 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 +124 -9
- data/lib/stripe_mock/server.rb +2 -2
- data/lib/stripe_mock/test_strategies/base.rb +98 -12
- data/lib/stripe_mock/test_strategies/live.rb +23 -12
- data/lib/stripe_mock/test_strategies/mock.rb +6 -2
- 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 +101 -44
- 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 -45
- 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 -46
- 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 +40 -0
- data/lib/stripe_mock/webhook_fixtures/product.deleted.json +40 -0
- data/lib/stripe_mock/webhook_fixtures/product.updated.json +47 -0
- 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 +11 -0
- data/spec/instance_spec.rb +13 -13
- 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 +6 -3
- data/spec/shared_stripe_examples/account_examples.rb +10 -2
- 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/balance_transaction_examples.rb +3 -3
- data/spec/shared_stripe_examples/bank_examples.rb +3 -3
- data/spec/shared_stripe_examples/bank_token_examples.rb +5 -7
- data/spec/shared_stripe_examples/card_examples.rb +4 -4
- data/spec/shared_stripe_examples/card_token_examples.rb +17 -21
- data/spec/shared_stripe_examples/charge_examples.rb +106 -22
- data/spec/shared_stripe_examples/checkout_session_examples.rb +99 -0
- data/spec/shared_stripe_examples/coupon_examples.rb +1 -1
- data/spec/shared_stripe_examples/customer_examples.rb +149 -53
- data/spec/shared_stripe_examples/dispute_examples.rb +2 -2
- data/spec/shared_stripe_examples/error_mock_examples.rb +8 -7
- data/spec/shared_stripe_examples/express_login_link_examples.rb +12 -0
- data/spec/shared_stripe_examples/external_account_examples.rb +3 -3
- data/spec/shared_stripe_examples/invoice_examples.rb +148 -40
- data/spec/shared_stripe_examples/invoice_item_examples.rb +1 -1
- data/spec/shared_stripe_examples/payment_intent_examples.rb +283 -0
- data/spec/shared_stripe_examples/payment_method_examples.rb +454 -0
- data/spec/shared_stripe_examples/payout_examples.rb +2 -2
- data/spec/shared_stripe_examples/plan_examples.rb +135 -92
- data/spec/shared_stripe_examples/price_examples.rb +292 -0
- data/spec/shared_stripe_examples/product_examples.rb +215 -0
- data/spec/shared_stripe_examples/promotion_code_examples.rb +68 -0
- data/spec/shared_stripe_examples/refund_examples.rb +38 -21
- data/spec/shared_stripe_examples/setup_intent_examples.rb +85 -0
- data/spec/shared_stripe_examples/subscription_examples.rb +706 -324
- data/spec/shared_stripe_examples/subscription_items_examples.rb +3 -2
- data/spec/shared_stripe_examples/transfer_examples.rb +16 -7
- data/spec/shared_stripe_examples/webhook_event_examples.rb +62 -16
- data/spec/spec_helper.rb +8 -5
- data/spec/stripe_mock_spec.rb +4 -4
- data/spec/support/shared_contexts/stripe_validator_spec.rb +8 -0
- data/spec/support/stripe_examples.rb +11 -1
- data/stripe-ruby-mock.gemspec +9 -5
- metadata +115 -47
- data/.travis.yml +0 -28
- data/spec/shared_stripe_examples/product_example.rb +0 -65
@@ -12,30 +12,35 @@ module StripeMock
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def create_source(route, method_url, params, headers)
|
15
|
+
stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
15
16
|
route =~ method_url
|
16
|
-
add_source_to(:customer, $1, params, customers)
|
17
|
+
add_source_to(:customer, $1, params, customers[stripe_account])
|
17
18
|
end
|
18
19
|
|
19
20
|
def retrieve_sources(route, method_url, params, headers)
|
21
|
+
stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
20
22
|
route =~ method_url
|
21
|
-
retrieve_object_cards(:customer, $1, customers)
|
23
|
+
retrieve_object_cards(:customer, $1, customers[stripe_account])
|
22
24
|
end
|
23
25
|
|
24
26
|
def retrieve_source(route, method_url, params, headers)
|
27
|
+
stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
25
28
|
route =~ method_url
|
26
|
-
customer = assert_existence :customer, $1, customers[$1]
|
29
|
+
customer = assert_existence :customer, $1, customers[stripe_account][$1]
|
27
30
|
|
28
31
|
assert_existence :card, $2, get_card(customer, $2)
|
29
32
|
end
|
30
33
|
|
31
34
|
def delete_source(route, method_url, params, headers)
|
35
|
+
stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
32
36
|
route =~ method_url
|
33
|
-
delete_card_from(:customer, $1, $2, customers)
|
37
|
+
delete_card_from(:customer, $1, $2, customers[stripe_account])
|
34
38
|
end
|
35
39
|
|
36
40
|
def update_source(route, method_url, params, headers)
|
41
|
+
stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
37
42
|
route =~ method_url
|
38
|
-
customer = assert_existence :customer, $1, customers[$1]
|
43
|
+
customer = assert_existence :customer, $1, customers[stripe_account][$1]
|
39
44
|
|
40
45
|
card = assert_existence :card, $2, get_card(customer, $2)
|
41
46
|
card.merge!(params)
|
@@ -43,8 +48,9 @@ module StripeMock
|
|
43
48
|
end
|
44
49
|
|
45
50
|
def verify_source(route, method_url, params, headers)
|
51
|
+
stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
46
52
|
route =~ method_url
|
47
|
-
customer = assert_existence :customer, $1, customers[$1]
|
53
|
+
customer = assert_existence :customer, $1, customers[stripe_account][$1]
|
48
54
|
|
49
55
|
bank_account = assert_existence :bank_account, $2, verify_bank_account(customer, $2)
|
50
56
|
bank_account
|
@@ -5,8 +5,9 @@ module StripeMock
|
|
5
5
|
def Subscriptions.included(klass)
|
6
6
|
klass.add_handler 'get /v1/subscriptions', :retrieve_subscriptions
|
7
7
|
klass.add_handler 'post /v1/subscriptions', :create_subscription
|
8
|
-
klass.add_handler 'get /v1/subscriptions/(.*)', :retrieve_subscription
|
8
|
+
klass.add_handler 'get /v1/subscriptions/((?!search).*)', :retrieve_subscription
|
9
9
|
klass.add_handler 'post /v1/subscriptions/(.*)', :update_subscription
|
10
|
+
klass.add_handler 'get /v1/subscriptions/search', :search_subscriptions
|
10
11
|
klass.add_handler 'delete /v1/subscriptions/(.*)', :cancel_subscription
|
11
12
|
|
12
13
|
klass.add_handler 'post /v1/customers/(.*)/subscription(?:s)?', :create_customer_subscription
|
@@ -17,26 +18,29 @@ module StripeMock
|
|
17
18
|
end
|
18
19
|
|
19
20
|
def retrieve_customer_subscription(route, method_url, params, headers)
|
21
|
+
stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
20
22
|
route =~ method_url
|
21
23
|
|
22
|
-
customer = assert_existence :customer, $1, customers[$1]
|
24
|
+
customer = assert_existence :customer, $1, customers[stripe_account][$1]
|
23
25
|
subscription = get_customer_subscription(customer, $2)
|
24
26
|
|
25
27
|
assert_existence :subscription, $2, subscription
|
26
28
|
end
|
27
29
|
|
28
30
|
def retrieve_customer_subscriptions(route, method_url, params, headers)
|
31
|
+
stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
29
32
|
route =~ method_url
|
30
33
|
|
31
|
-
customer = assert_existence :customer, $1, customers[$1]
|
34
|
+
customer = assert_existence :customer, $1, customers[stripe_account][$1]
|
32
35
|
customer[:subscriptions]
|
33
36
|
end
|
34
37
|
|
35
38
|
def create_customer_subscription(route, method_url, params, headers)
|
39
|
+
stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
36
40
|
route =~ method_url
|
37
41
|
|
38
42
|
subscription_plans = get_subscription_plans_from_params(params)
|
39
|
-
customer = assert_existence :customer, $1, customers[$1]
|
43
|
+
customer = assert_existence :customer, $1, customers[stripe_account][$1]
|
40
44
|
|
41
45
|
if params[:source]
|
42
46
|
new_card = get_card_by_token(params.delete(:source))
|
@@ -66,6 +70,16 @@ module StripeMock
|
|
66
70
|
end
|
67
71
|
end
|
68
72
|
|
73
|
+
if params[:promotion_code]
|
74
|
+
promotion_code_id = params[:promotion_code]
|
75
|
+
|
76
|
+
promotion_code = promotion_codes[promotion_code_id]
|
77
|
+
|
78
|
+
unless promotion_code
|
79
|
+
raise Stripe::InvalidRequestError.new("No such promotion code: #{promotion_code_id}", 'promotion_code', http_status: 400)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
69
83
|
subscriptions[subscription[:id]] = subscription
|
70
84
|
add_subscription_to_customer(customer, subscription)
|
71
85
|
|
@@ -73,10 +87,10 @@ module StripeMock
|
|
73
87
|
end
|
74
88
|
|
75
89
|
def create_subscription(route, method_url, params, headers)
|
90
|
+
stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
76
91
|
if headers && headers[:idempotency_key]
|
77
92
|
if subscriptions.any?
|
78
93
|
original_subscription = subscriptions.values.find { |c| c[:idempotency_key] == headers[:idempotency_key]}
|
79
|
-
puts original_subscription
|
80
94
|
return subscriptions[original_subscription[:id]] if original_subscription
|
81
95
|
end
|
82
96
|
end
|
@@ -86,15 +100,7 @@ module StripeMock
|
|
86
100
|
|
87
101
|
customer = params[:customer]
|
88
102
|
customer_id = customer.is_a?(Stripe::Customer) ? customer[:id] : customer.to_s
|
89
|
-
customer = assert_existence :customer, customer_id, customers[customer_id]
|
90
|
-
|
91
|
-
if subscription_plans && customer
|
92
|
-
subscription_plans.each do |plan|
|
93
|
-
unless customer[:currency].to_s == plan[:currency].to_s
|
94
|
-
raise Stripe::InvalidRequestError.new("Customer's currency of #{customer[:currency]} does not match plan's currency of #{plan[:currency]}", 'currency', http_status: 400)
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
103
|
+
customer = assert_existence :customer, customer_id, customers[stripe_account][customer_id]
|
98
104
|
|
99
105
|
if params[:source]
|
100
106
|
new_card = get_card_by_token(params.delete(:source))
|
@@ -102,7 +108,7 @@ module StripeMock
|
|
102
108
|
customer[:default_source] = new_card[:id]
|
103
109
|
end
|
104
110
|
|
105
|
-
allowed_params = %w(customer application_fee_percent coupon items metadata plan quantity source tax_percent trial_end trial_period_days current_period_start created prorate billing_cycle_anchor billing days_until_due idempotency_key)
|
111
|
+
allowed_params = %w(id customer application_fee_percent coupon items metadata plan quantity source tax_percent trial_end trial_period_days current_period_start created prorate billing_cycle_anchor billing days_until_due idempotency_key enable_incomplete_payments cancel_at_period_end default_tax_rates payment_behavior pending_invoice_item_interval default_payment_method collection_method off_session trial_from_plan proration_behavior backdate_start_date transfer_data expand automatic_tax payment_settings trial_settings promotion_code)
|
106
112
|
unknown_params = params.keys - allowed_params.map(&:to_sym)
|
107
113
|
if unknown_params.length > 0
|
108
114
|
raise Stripe::InvalidRequestError.new("Received unknown parameter: #{unknown_params.join}", unknown_params.first.to_s, http_status: 400)
|
@@ -118,6 +124,10 @@ module StripeMock
|
|
118
124
|
# Note: needs updating for subscriptions with multiple plans
|
119
125
|
verify_card_present(customer, subscription_plans.first, subscription, params)
|
120
126
|
|
127
|
+
if params[:coupon] && params[:promotion_code]
|
128
|
+
raise Stripe::InvalidRequestError.new("You may only specify one of these parameters: coupon, promotion_code", "coupon", http_status: 400)
|
129
|
+
end
|
130
|
+
|
121
131
|
if params[:coupon]
|
122
132
|
coupon_id = params[:coupon]
|
123
133
|
|
@@ -133,6 +143,50 @@ module StripeMock
|
|
133
143
|
end
|
134
144
|
end
|
135
145
|
|
146
|
+
if params[:promotion_code]
|
147
|
+
promotion_code_id = params[:promotion_code]
|
148
|
+
|
149
|
+
promotion_code = promotion_codes[promotion_code_id]
|
150
|
+
|
151
|
+
unless promotion_code
|
152
|
+
raise Stripe::InvalidRequestError.new("No such promotion code: #{promotion_code_id}", 'promotion_code', http_status: 400)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
if params[:trial_period_days]
|
157
|
+
subscription[:status] = 'trialing'
|
158
|
+
end
|
159
|
+
|
160
|
+
if params[:payment_behavior] == 'default_incomplete'
|
161
|
+
subscription[:status] = 'incomplete'
|
162
|
+
end
|
163
|
+
|
164
|
+
if params[:cancel_at_period_end]
|
165
|
+
subscription[:cancel_at_period_end] = true
|
166
|
+
subscription[:canceled_at] = Time.now.utc.to_i
|
167
|
+
end
|
168
|
+
|
169
|
+
if params[:transfer_data] && !params[:transfer_data].empty?
|
170
|
+
throw Stripe::InvalidRequestError.new(missing_param_message("transfer_data[destination]")) unless params[:transfer_data][:destination]
|
171
|
+
subscription[:transfer_data] = params[:transfer_data].dup
|
172
|
+
subscription[:transfer_data][:amount_percent] ||= 100
|
173
|
+
end
|
174
|
+
|
175
|
+
if (s = params[:expand]&.find { |s| s.start_with? 'latest_invoice' })
|
176
|
+
payment_intent = nil
|
177
|
+
unless subscription[:status] == 'trialing'
|
178
|
+
intent_status = subscription[:status] == 'incomplete' ? 'requires_payment_method' : 'succeeded'
|
179
|
+
intent = Data.mock_payment_intent({
|
180
|
+
status: intent_status,
|
181
|
+
amount: subscription[:plan][:amount],
|
182
|
+
currency: subscription[:plan][:currency]
|
183
|
+
})
|
184
|
+
payment_intent = s.include?('latest_invoice.payment_intent') ? intent : intent.id
|
185
|
+
end
|
186
|
+
invoice = Data.mock_invoice([], { payment_intent: payment_intent })
|
187
|
+
subscription[:latest_invoice] = invoice
|
188
|
+
end
|
189
|
+
|
136
190
|
subscriptions[subscription[:id]] = subscription
|
137
191
|
add_subscription_to_customer(customer, subscription)
|
138
192
|
|
@@ -146,22 +200,43 @@ module StripeMock
|
|
146
200
|
end
|
147
201
|
|
148
202
|
def retrieve_subscriptions(route, method_url, params, headers)
|
203
|
+
# stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
149
204
|
route =~ method_url
|
150
205
|
|
151
|
-
|
152
|
-
|
153
|
-
|
206
|
+
subs = subscriptions.values
|
207
|
+
|
208
|
+
case params[:status]
|
209
|
+
when nil
|
210
|
+
subs = subs.filter {|subscription| subscription[:status] != "canceled"}
|
211
|
+
when "all"
|
212
|
+
# Include all subscriptions
|
213
|
+
else
|
214
|
+
subs = subs.filter {|subscription| subscription[:status] == params[:status]}
|
215
|
+
end
|
216
|
+
if params[:current_period_end]
|
217
|
+
subs = filter_by_timestamp(subs, field: :current_period_end, value: params[:current_period_end])
|
218
|
+
end
|
219
|
+
if params[:current_period_start]
|
220
|
+
subs = filter_by_timestamp(subs, field: :current_period_start, value: params[:current_period_start])
|
221
|
+
end
|
222
|
+
|
223
|
+
Data.mock_list_object(subs, params)
|
154
224
|
end
|
155
225
|
|
156
226
|
def update_subscription(route, method_url, params, headers)
|
227
|
+
stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
157
228
|
route =~ method_url
|
158
229
|
|
230
|
+
if params[:billing_cycle_anchor] == 'now'
|
231
|
+
params[:billing_cycle_anchor] = Time.now.utc.to_i
|
232
|
+
end
|
233
|
+
|
159
234
|
subscription_id = $2 ? $2 : $1
|
160
235
|
subscription = assert_existence :subscription, subscription_id, subscriptions[subscription_id]
|
161
236
|
verify_active_status(subscription)
|
162
237
|
|
163
238
|
customer_id = subscription[:customer]
|
164
|
-
customer = assert_existence :customer, customer_id, customers[customer_id]
|
239
|
+
customer = assert_existence :customer, customer_id, customers[stripe_account][customer_id]
|
165
240
|
|
166
241
|
if params[:source]
|
167
242
|
new_card = get_card_by_token(params.delete(:source))
|
@@ -191,17 +266,48 @@ module StripeMock
|
|
191
266
|
raise Stripe::InvalidRequestError.new("No such coupon: #{coupon_id}", 'coupon', http_status: 400)
|
192
267
|
end
|
193
268
|
end
|
194
|
-
verify_card_present(customer, subscription_plans.first, subscription)
|
195
269
|
|
196
|
-
if
|
270
|
+
if params[:promotion_code]
|
271
|
+
promotion_code_id = params[:promotion_code]
|
272
|
+
|
273
|
+
promotion_code = promotion_codes[promotion_code_id]
|
274
|
+
|
275
|
+
if promotion_code
|
276
|
+
# You can't apply a promotion code with amount restrictions on the Customer object or on a subscription
|
277
|
+
# update API call
|
278
|
+
if promotion_code[:restrictions][:minimum_amount]
|
279
|
+
raise Stripe::InvalidRequestError.new(
|
280
|
+
"This promotion code cannot be redeemed on a subcription update because it uses the `minimum_amount` restriction.",
|
281
|
+
"promotion_code",
|
282
|
+
http_status: 400
|
283
|
+
)
|
284
|
+
end
|
285
|
+
else
|
286
|
+
raise Stripe::InvalidRequestError.new("No such promotion code: #{promotion_code_id}", 'promotion_code', http_status: 400)
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
if params[:trial_period_days]
|
291
|
+
subscription[:status] = 'trialing'
|
292
|
+
end
|
293
|
+
|
294
|
+
if params[:cancel_at_period_end]
|
295
|
+
subscription[:cancel_at_period_end] = true
|
296
|
+
subscription[:canceled_at] = Time.now.utc.to_i
|
297
|
+
elsif params.has_key?(:cancel_at_period_end)
|
197
298
|
subscription[:cancel_at_period_end] = false
|
198
299
|
subscription[:canceled_at] = nil
|
199
300
|
end
|
200
301
|
|
201
302
|
params[:current_period_start] = subscription[:current_period_start]
|
202
303
|
params[:trial_end] = params[:trial_end] || subscription[:trial_end]
|
304
|
+
|
305
|
+
plan_amount_was = subscription.dig(:plan, :amount)
|
306
|
+
|
203
307
|
subscription = resolve_subscription_changes(subscription, subscription_plans, customer, params)
|
204
308
|
|
309
|
+
verify_card_present(customer, subscription_plans.first, subscription, params) if plan_amount_was == 0 && subscription.dig(:plan, :amount) && subscription.dig(:plan, :amount) > 0
|
310
|
+
|
205
311
|
# delete the old subscription, replace with the new subscription
|
206
312
|
customer[:subscriptions][:data].reject! { |sub| sub[:id] == subscription[:id] }
|
207
313
|
customer[:subscriptions][:data] << subscription
|
@@ -210,13 +316,14 @@ module StripeMock
|
|
210
316
|
end
|
211
317
|
|
212
318
|
def cancel_subscription(route, method_url, params, headers)
|
319
|
+
stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
213
320
|
route =~ method_url
|
214
321
|
|
215
322
|
subscription_id = $2 ? $2 : $1
|
216
323
|
subscription = assert_existence :subscription, subscription_id, subscriptions[subscription_id]
|
217
324
|
|
218
325
|
customer_id = subscription[:customer]
|
219
|
-
customer = assert_existence :customer, customer_id, customers[customer_id]
|
326
|
+
customer = assert_existence :customer, customer_id, customers[stripe_account][customer_id]
|
220
327
|
|
221
328
|
cancel_params = { canceled_at: Time.now.utc.to_i }
|
222
329
|
cancelled_at_period_end = (params[:at_period_end] == true)
|
@@ -237,6 +344,14 @@ module StripeMock
|
|
237
344
|
subscription
|
238
345
|
end
|
239
346
|
|
347
|
+
SEARCH_FIELDS = ["status"].freeze
|
348
|
+
def search_subscriptions(route, method_url, params, headers)
|
349
|
+
require_param(:query) unless params[:query]
|
350
|
+
|
351
|
+
results = search_results(subscriptions.values, params[:query], fields: SEARCH_FIELDS, resource_name: "subscriptions")
|
352
|
+
Data.mock_list_object(results, params)
|
353
|
+
end
|
354
|
+
|
240
355
|
private
|
241
356
|
|
242
357
|
def get_subscription_plans_from_params(params)
|
@@ -245,14 +360,17 @@ module StripeMock
|
|
245
360
|
elsif params[:items]
|
246
361
|
items = params[:items]
|
247
362
|
items = items.values if items.respond_to?(:values)
|
248
|
-
items.map { |item| item[:plan]
|
363
|
+
items.map { |item| item[:plan] ? item[:plan] : item[:price] }
|
249
364
|
else
|
250
365
|
[]
|
251
366
|
end
|
367
|
+
plan_ids.compact!
|
252
368
|
plan_ids.each do |plan_id|
|
253
369
|
assert_existence :plan, plan_id, plans[plan_id]
|
370
|
+
rescue Stripe::InvalidRequestError
|
371
|
+
assert_existence :price, plan_id, prices[plan_id]
|
254
372
|
end
|
255
|
-
plan_ids.map { |plan_id| plans[plan_id] }
|
373
|
+
plan_ids.map { |plan_id| plans[plan_id] || prices[plan_id]}
|
256
374
|
end
|
257
375
|
|
258
376
|
# Ensure customer has card to charge unless one of the following criterias is met:
|
@@ -261,8 +379,11 @@ module StripeMock
|
|
261
379
|
# 3) has billing set to send invoice
|
262
380
|
def verify_card_present(customer, plan, subscription, params={})
|
263
381
|
return if customer[:default_source]
|
382
|
+
return if customer[:invoice_settings][:default_payment_method]
|
264
383
|
return if customer[:trial_end]
|
265
384
|
return if params[:trial_end]
|
385
|
+
return if params[:payment_behavior] == 'default_incomplete'
|
386
|
+
return if subscription[:default_payment_method]
|
266
387
|
|
267
388
|
plan_trial_period_days = plan[:trial_period_days] || 0
|
268
389
|
plan_has_trial = plan_trial_period_days != 0 || plan[:amount] == 0 || plan[:trial_end]
|
@@ -281,7 +402,7 @@ module StripeMock
|
|
281
402
|
|
282
403
|
return if params[:billing] == 'send_invoice'
|
283
404
|
|
284
|
-
raise Stripe::InvalidRequestError.new('
|
405
|
+
raise Stripe::InvalidRequestError.new('This customer has no attached payment source', nil, http_status: 400)
|
285
406
|
end
|
286
407
|
|
287
408
|
def verify_active_status(subscription)
|
@@ -8,6 +8,8 @@ module StripeMock
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def create_token(route, method_url, params, headers)
|
11
|
+
stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
12
|
+
|
11
13
|
if params[:customer].nil? && params[:card].nil? && params[:bank_account].nil?
|
12
14
|
raise Stripe::InvalidRequestError.new('You must supply either a card, customer, or bank account to create a token.', nil, http_status: 400)
|
13
15
|
end
|
@@ -15,13 +17,13 @@ module StripeMock
|
|
15
17
|
cus_id = params[:customer]
|
16
18
|
|
17
19
|
if cus_id && params[:source]
|
18
|
-
customer = assert_existence :customer, cus_id, customers[cus_id]
|
20
|
+
customer = assert_existence :customer, cus_id, customers[stripe_account][cus_id]
|
19
21
|
|
20
22
|
# params[:card] is an id; grab it from the db
|
21
23
|
customer_card = get_card(customer, params[:source])
|
22
24
|
assert_existence :card, params[:source], customer_card
|
23
25
|
elsif params[:card].is_a?(String)
|
24
|
-
customer = assert_existence :customer, cus_id, customers[cus_id]
|
26
|
+
customer = assert_existence :customer, cus_id, customers[stripe_account][cus_id]
|
25
27
|
|
26
28
|
# params[:card] is an id; grab it from the db
|
27
29
|
customer_card = get_card(customer, params[:card])
|
@@ -32,7 +34,7 @@ module StripeMock
|
|
32
34
|
params[:card][:last4] = params[:card][:number][-4,4]
|
33
35
|
customer_card = params[:card]
|
34
36
|
elsif params[:bank_account].is_a?(String)
|
35
|
-
customer = assert_existence :customer, cus_id, customers[cus_id]
|
37
|
+
customer = assert_existence :customer, cus_id, customers[stripe_account][cus_id]
|
36
38
|
|
37
39
|
# params[:bank_account] is an id; grab it from the db
|
38
40
|
bank_account = verify_bank_account(customer, params[:bank_account])
|
@@ -41,7 +43,7 @@ module StripeMock
|
|
41
43
|
# params[:card] is a hash of cc info; "Sanitize" the card number
|
42
44
|
bank_account = params[:bank_account]
|
43
45
|
else
|
44
|
-
customer = assert_existence :customer, cus_id, customers[cus_id]
|
46
|
+
customer = assert_existence :customer, cus_id, customers[stripe_account][cus_id] || customers[Stripe.api_key][cus_id]
|
45
47
|
customer_card = get_card(customer, customer[:default_source])
|
46
48
|
end
|
47
49
|
|
@@ -45,7 +45,18 @@ module StripeMock
|
|
45
45
|
raise Stripe::InvalidRequestError.new("Invalid integer: #{params[:amount]}", 'amount', http_status: 400)
|
46
46
|
end
|
47
47
|
|
48
|
-
|
48
|
+
bal_trans_params = { amount: params[:amount].to_i, source: id }
|
49
|
+
|
50
|
+
balance_transaction_id = new_balance_transaction('txn', bal_trans_params)
|
51
|
+
|
52
|
+
transfers[id] = Data.mock_transfer(params.merge(id: id, balance_transaction: balance_transaction_id))
|
53
|
+
|
54
|
+
transfer = transfers[id].clone
|
55
|
+
if params[:expand] == ['balance_transaction']
|
56
|
+
transfer[:balance_transaction] = balance_transactions[balance_transaction_id]
|
57
|
+
end
|
58
|
+
|
59
|
+
transfer
|
49
60
|
end
|
50
61
|
|
51
62
|
def get_transfer(route, method_url, params, headers)
|
@@ -2,31 +2,146 @@ module StripeMock
|
|
2
2
|
module RequestHandlers
|
3
3
|
module ParamValidators
|
4
4
|
|
5
|
-
def
|
5
|
+
def already_exists_message(obj_class)
|
6
|
+
"#{obj_class.to_s.split("::").last} already exists."
|
7
|
+
end
|
8
|
+
|
9
|
+
def not_found_message(obj_class, obj_id)
|
10
|
+
"No such #{obj_class.to_s.split("::").last.downcase}: #{obj_id}"
|
11
|
+
end
|
12
|
+
|
13
|
+
def missing_param_message(attr_name)
|
14
|
+
"Missing required param: #{attr_name}."
|
15
|
+
end
|
16
|
+
|
17
|
+
def invalid_integer_message(my_val)
|
18
|
+
"Invalid integer: #{my_val}"
|
19
|
+
end
|
20
|
+
|
21
|
+
#
|
22
|
+
# ProductValidator
|
23
|
+
#
|
24
|
+
|
25
|
+
|
26
|
+
def validate_create_product_params(params)
|
6
27
|
params[:id] = params[:id].to_s
|
28
|
+
@base_strategy.create_product_params.keys.reject{ |k,_| k == :id }.each do |k|
|
29
|
+
raise Stripe::InvalidRequestError.new(missing_param_message(k), k) if params[k].nil?
|
30
|
+
end
|
31
|
+
|
32
|
+
if products[ params[:id] ]
|
33
|
+
raise Stripe::InvalidRequestError.new(already_exists_message(Stripe::Product), :id)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
#
|
38
|
+
# PlanValidator
|
39
|
+
#
|
40
|
+
|
41
|
+
def missing_plan_amount_message
|
42
|
+
"Plans require an `amount` parameter to be set."
|
43
|
+
end
|
44
|
+
|
45
|
+
SUPPORTED_PLAN_INTERVALS = ["month", "year", "week", "day"]
|
46
|
+
|
47
|
+
def invalid_plan_interval_message
|
48
|
+
"Invalid interval: must be one of day, month, week, or year"
|
49
|
+
end
|
50
|
+
|
51
|
+
SUPPORTED_CURRENCIES = [
|
52
|
+
"usd", "aed", "afn", "all", "amd", "ang", "aoa", "ars", "aud", "awg", "azn", "bam", "bbd", "bdt", "bgn",
|
53
|
+
"bif", "bmd", "bnd", "bob", "brl", "bsd", "bwp", "bzd", "cad", "cdf", "chf", "clp", "cny", "cop", "crc",
|
54
|
+
"cve", "czk", "djf", "dkk", "dop", "dzd", "egp", "etb", "eur", "fjd", "fkp", "gbp", "gel", "gip", "gmd",
|
55
|
+
"gnf", "gtq", "gyd", "hkd", "hnl", "hrk", "htg", "huf", "idr", "ils", "inr", "isk", "jmd", "jpy", "kes",
|
56
|
+
"kgs", "khr", "kmf", "krw", "kyd", "kzt", "lak", "lbp", "lkr", "lrd", "lsl", "mad", "mdl", "mga", "mkd",
|
57
|
+
"mmk", "mnt", "mop", "mro", "mur", "mvr", "mwk", "mxn", "myr", "mzn", "nad", "ngn", "nio", "nok", "npr",
|
58
|
+
"nzd", "pab", "pen", "pgk", "php", "pkr", "pln", "pyg", "qar", "ron", "rsd", "rub", "rwf", "sar", "sbd",
|
59
|
+
"scr", "sek", "sgd", "shp", "sll", "sos", "srd", "std", "szl", "thb", "tjs", "top", "try", "ttd", "twd",
|
60
|
+
"tzs", "uah", "ugx", "uyu", "uzs", "vnd", "vuv", "wst", "xaf", "xcd", "xof", "xpf", "yer", "zar", "zmw",
|
61
|
+
"eek", "lvl", "svc", "vef", "ltl"
|
62
|
+
]
|
63
|
+
|
64
|
+
def invalid_currency_message(my_val)
|
65
|
+
"Invalid currency: #{my_val.downcase}. Stripe currently supports these currencies: #{SUPPORTED_CURRENCIES.join(", ")}"
|
66
|
+
end
|
7
67
|
|
8
|
-
|
68
|
+
def validate_create_plan_params(params)
|
69
|
+
plan_id = params[:id].to_s
|
70
|
+
product_id = params[:product]
|
71
|
+
|
72
|
+
@base_strategy.create_plan_params.keys.each do |attr_name|
|
9
73
|
message =
|
10
|
-
if
|
11
|
-
"Plans require an `#{
|
74
|
+
if attr_name == :amount
|
75
|
+
"Plans require an `#{attr_name}` parameter to be set."
|
12
76
|
else
|
13
|
-
"Missing required param: #{
|
77
|
+
"Missing required param: #{attr_name}."
|
14
78
|
end
|
15
|
-
raise Stripe::InvalidRequestError.new(message,
|
79
|
+
raise Stripe::InvalidRequestError.new(message, attr_name) if params[attr_name].nil?
|
80
|
+
end
|
81
|
+
|
82
|
+
if plans[plan_id]
|
83
|
+
message = already_exists_message(Stripe::Plan)
|
84
|
+
raise Stripe::InvalidRequestError.new(message, :id)
|
85
|
+
end
|
86
|
+
|
87
|
+
unless products[product_id]
|
88
|
+
message = not_found_message(Stripe::Product, product_id)
|
89
|
+
raise Stripe::InvalidRequestError.new(message, :product)
|
16
90
|
end
|
17
91
|
|
18
|
-
|
19
|
-
|
92
|
+
unless SUPPORTED_PLAN_INTERVALS.include?(params[:interval])
|
93
|
+
message = invalid_plan_interval_message
|
94
|
+
raise Stripe::InvalidRequestError.new(message, :interval)
|
95
|
+
end
|
96
|
+
|
97
|
+
unless SUPPORTED_CURRENCIES.include?(params[:currency])
|
98
|
+
message = invalid_currency_message(params[:currency])
|
99
|
+
raise Stripe::InvalidRequestError.new(message, :currency)
|
20
100
|
end
|
21
101
|
|
22
102
|
unless params[:amount].integer?
|
23
|
-
|
103
|
+
message = invalid_integer_message(params[:amount])
|
104
|
+
raise Stripe::InvalidRequestError.new(message, :amount)
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
def validate_create_price_params(params)
|
110
|
+
price_id = params[:id].to_s
|
111
|
+
|
112
|
+
require_param(:currency) unless params[:currency]
|
113
|
+
unless params[:product] || params[:product_data]
|
114
|
+
raise Stripe::InvalidRequestError("Requires product or product_data")
|
115
|
+
end
|
116
|
+
|
117
|
+
product_id = params[:product] || create_product(nil, nil, params[:product_data], nil).id
|
118
|
+
|
119
|
+
if prices[price_id]
|
120
|
+
message = already_exists_message(Stripe::Price)
|
121
|
+
raise Stripe::InvalidRequestError.new(message, :id)
|
122
|
+
end
|
123
|
+
|
124
|
+
unless products[product_id]
|
125
|
+
message = not_found_message(Stripe::Product, product_id)
|
126
|
+
raise Stripe::InvalidRequestError.new(message, :product)
|
127
|
+
end
|
128
|
+
|
129
|
+
unless SUPPORTED_CURRENCIES.include?(params[:currency])
|
130
|
+
message = invalid_currency_message(params[:currency])
|
131
|
+
raise Stripe::InvalidRequestError.new(message, :currency)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def validate_list_prices_params(params)
|
136
|
+
if params[:lookup_keys] && !params[:lookup_keys].is_a?(Array)
|
137
|
+
raise Stripe::InvalidRequestError.new('Invalid array', :lookup_keys)
|
24
138
|
end
|
25
139
|
end
|
26
140
|
|
27
141
|
def require_param(param_name)
|
28
142
|
raise Stripe::InvalidRequestError.new("Missing required param: #{param_name}.", param_name.to_s, http_status: 400)
|
29
143
|
end
|
144
|
+
|
30
145
|
end
|
31
146
|
end
|
32
147
|
end
|
data/lib/stripe_mock/server.rb
CHANGED
@@ -16,9 +16,9 @@ module StripeMock
|
|
16
16
|
self.clear_data
|
17
17
|
end
|
18
18
|
|
19
|
-
def mock_request(*args)
|
19
|
+
def mock_request(*args, **kwargs)
|
20
20
|
begin
|
21
|
-
@instance.mock_request(*args)
|
21
|
+
@instance.mock_request(*args, **kwargs)
|
22
22
|
rescue Stripe::InvalidRequestError => e
|
23
23
|
{
|
24
24
|
:error_raised => 'invalid_request',
|