stripe-ruby-mock 3.0.1 → 3.1.0.rc2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.travis.yml +2 -5
- data/CHANGELOG.md +28 -15
- data/Gemfile +1 -0
- data/lib/stripe_mock.rb +4 -0
- data/lib/stripe_mock/api/client.rb +1 -1
- data/lib/stripe_mock/api/instance.rb +1 -1
- data/lib/stripe_mock/api/webhooks.rb +2 -0
- data/lib/stripe_mock/client.rb +2 -1
- data/lib/stripe_mock/data.rb +127 -25
- data/lib/stripe_mock/data/list.rb +31 -6
- data/lib/stripe_mock/instance.rb +7 -2
- data/lib/stripe_mock/request_handlers/account_links.rb +15 -0
- data/lib/stripe_mock/request_handlers/charges.rb +6 -4
- data/lib/stripe_mock/request_handlers/checkout_session.rb +16 -0
- data/lib/stripe_mock/request_handlers/customers.rb +22 -13
- data/lib/stripe_mock/request_handlers/ephemeral_key.rb +1 -1
- data/lib/stripe_mock/request_handlers/express_login_links.rb +15 -0
- data/lib/stripe_mock/request_handlers/helpers/subscription_helpers.rb +12 -7
- data/lib/stripe_mock/request_handlers/invoices.rb +4 -3
- data/lib/stripe_mock/request_handlers/payment_methods.rb +8 -5
- data/lib/stripe_mock/request_handlers/prices.rb +44 -0
- data/lib/stripe_mock/request_handlers/sources.rb +12 -6
- data/lib/stripe_mock/request_handlers/subscriptions.rb +29 -19
- data/lib/stripe_mock/request_handlers/tokens.rb +6 -4
- data/lib/stripe_mock/request_handlers/validators/param_validators.rb +32 -0
- data/lib/stripe_mock/test_strategies/base.rb +26 -0
- data/lib/stripe_mock/version.rb +1 -1
- data/lib/stripe_mock/webhook_fixtures/balance.available.json +6 -0
- data/lib/stripe_mock/webhook_fixtures/payment_intent.payment_failed.json +186 -0
- data/lib/stripe_mock/webhook_fixtures/payment_intent.succeeded.json +164 -0
- data/spec/instance_spec.rb +4 -6
- data/spec/list_spec.rb +23 -0
- data/spec/server_spec.rb +4 -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/card_token_examples.rb +17 -21
- data/spec/shared_stripe_examples/checkout_examples.rb +20 -1
- data/spec/shared_stripe_examples/customer_examples.rb +11 -13
- data/spec/shared_stripe_examples/express_login_link_examples.rb +12 -0
- data/spec/shared_stripe_examples/invoice_examples.rb +8 -8
- data/spec/shared_stripe_examples/payment_method_examples.rb +332 -68
- data/spec/shared_stripe_examples/price_examples.rb +183 -0
- data/spec/shared_stripe_examples/subscription_examples.rb +115 -8
- data/spec/spec_helper.rb +4 -0
- data/spec/stripe_mock_spec.rb +2 -2
- data/spec/support/stripe_examples.rb +5 -1
- data/stripe-ruby-mock.gemspec +6 -1
- metadata +25 -11
@@ -17,26 +17,29 @@ module StripeMock
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def retrieve_customer_subscription(route, method_url, params, headers)
|
20
|
+
stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
20
21
|
route =~ method_url
|
21
22
|
|
22
|
-
customer = assert_existence :customer, $1, customers[$1]
|
23
|
+
customer = assert_existence :customer, $1, customers[stripe_account][$1]
|
23
24
|
subscription = get_customer_subscription(customer, $2)
|
24
25
|
|
25
26
|
assert_existence :subscription, $2, subscription
|
26
27
|
end
|
27
28
|
|
28
29
|
def retrieve_customer_subscriptions(route, method_url, params, headers)
|
30
|
+
stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
29
31
|
route =~ method_url
|
30
32
|
|
31
|
-
customer = assert_existence :customer, $1, customers[$1]
|
33
|
+
customer = assert_existence :customer, $1, customers[stripe_account][$1]
|
32
34
|
customer[:subscriptions]
|
33
35
|
end
|
34
36
|
|
35
37
|
def create_customer_subscription(route, method_url, params, headers)
|
38
|
+
stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
36
39
|
route =~ method_url
|
37
40
|
|
38
41
|
subscription_plans = get_subscription_plans_from_params(params)
|
39
|
-
customer = assert_existence :customer, $1, customers[$1]
|
42
|
+
customer = assert_existence :customer, $1, customers[stripe_account][$1]
|
40
43
|
|
41
44
|
if params[:source]
|
42
45
|
new_card = get_card_by_token(params.delete(:source))
|
@@ -73,10 +76,10 @@ module StripeMock
|
|
73
76
|
end
|
74
77
|
|
75
78
|
def create_subscription(route, method_url, params, headers)
|
79
|
+
stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
76
80
|
if headers && headers[:idempotency_key]
|
77
81
|
if subscriptions.any?
|
78
82
|
original_subscription = subscriptions.values.find { |c| c[:idempotency_key] == headers[:idempotency_key]}
|
79
|
-
puts original_subscription
|
80
83
|
return subscriptions[original_subscription[:id]] if original_subscription
|
81
84
|
end
|
82
85
|
end
|
@@ -86,15 +89,7 @@ module StripeMock
|
|
86
89
|
|
87
90
|
customer = params[:customer]
|
88
91
|
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
|
92
|
+
customer = assert_existence :customer, customer_id, customers[stripe_account][customer_id]
|
98
93
|
|
99
94
|
if params[:source]
|
100
95
|
new_card = get_card_by_token(params.delete(:source))
|
@@ -102,7 +97,7 @@ module StripeMock
|
|
102
97
|
customer[:default_source] = new_card[:id]
|
103
98
|
end
|
104
99
|
|
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 enable_incomplete_payments cancel_at_period_end default_tax_rates payment_behavior pending_invoice_item_interval)
|
100
|
+
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 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 expand)
|
106
101
|
unknown_params = params.keys - allowed_params.map(&:to_sym)
|
107
102
|
if unknown_params.length > 0
|
108
103
|
raise Stripe::InvalidRequestError.new("Received unknown parameter: #{unknown_params.join}", unknown_params.first.to_s, http_status: 400)
|
@@ -133,6 +128,10 @@ module StripeMock
|
|
133
128
|
end
|
134
129
|
end
|
135
130
|
|
131
|
+
if params[:trial_period_days]
|
132
|
+
subscription[:status] = 'trialing'
|
133
|
+
end
|
134
|
+
|
136
135
|
if params[:cancel_at_period_end]
|
137
136
|
subscription[:cancel_at_period_end] = true
|
138
137
|
subscription[:canceled_at] = Time.now.utc.to_i
|
@@ -151,14 +150,16 @@ module StripeMock
|
|
151
150
|
end
|
152
151
|
|
153
152
|
def retrieve_subscriptions(route, method_url, params, headers)
|
153
|
+
# stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
154
154
|
route =~ method_url
|
155
155
|
|
156
156
|
Data.mock_list_object(subscriptions.values, params)
|
157
|
-
#customer = assert_existence :customer, $1, customers[$1]
|
157
|
+
#customer = assert_existence :customer, $1, customers[stripe_account][$1]
|
158
158
|
#customer[:subscriptions]
|
159
159
|
end
|
160
160
|
|
161
161
|
def update_subscription(route, method_url, params, headers)
|
162
|
+
stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
162
163
|
route =~ method_url
|
163
164
|
|
164
165
|
subscription_id = $2 ? $2 : $1
|
@@ -166,7 +167,7 @@ module StripeMock
|
|
166
167
|
verify_active_status(subscription)
|
167
168
|
|
168
169
|
customer_id = subscription[:customer]
|
169
|
-
customer = assert_existence :customer, customer_id, customers[customer_id]
|
170
|
+
customer = assert_existence :customer, customer_id, customers[stripe_account][customer_id]
|
170
171
|
|
171
172
|
if params[:source]
|
172
173
|
new_card = get_card_by_token(params.delete(:source))
|
@@ -197,6 +198,10 @@ module StripeMock
|
|
197
198
|
end
|
198
199
|
end
|
199
200
|
|
201
|
+
if params[:trial_period_days]
|
202
|
+
subscription[:status] = 'trialing'
|
203
|
+
end
|
204
|
+
|
200
205
|
if params[:cancel_at_period_end]
|
201
206
|
subscription[:cancel_at_period_end] = true
|
202
207
|
subscription[:canceled_at] = Time.now.utc.to_i
|
@@ -222,13 +227,14 @@ module StripeMock
|
|
222
227
|
end
|
223
228
|
|
224
229
|
def cancel_subscription(route, method_url, params, headers)
|
230
|
+
stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
225
231
|
route =~ method_url
|
226
232
|
|
227
233
|
subscription_id = $2 ? $2 : $1
|
228
234
|
subscription = assert_existence :subscription, subscription_id, subscriptions[subscription_id]
|
229
235
|
|
230
236
|
customer_id = subscription[:customer]
|
231
|
-
customer = assert_existence :customer, customer_id, customers[customer_id]
|
237
|
+
customer = assert_existence :customer, customer_id, customers[stripe_account][customer_id]
|
232
238
|
|
233
239
|
cancel_params = { canceled_at: Time.now.utc.to_i }
|
234
240
|
cancelled_at_period_end = (params[:at_period_end] == true)
|
@@ -257,14 +263,17 @@ module StripeMock
|
|
257
263
|
elsif params[:items]
|
258
264
|
items = params[:items]
|
259
265
|
items = items.values if items.respond_to?(:values)
|
260
|
-
items.map { |item| item[:plan]
|
266
|
+
items.map { |item| item[:plan] ? item[:plan] : item[:price] }
|
261
267
|
else
|
262
268
|
[]
|
263
269
|
end
|
270
|
+
plan_ids.compact!
|
264
271
|
plan_ids.each do |plan_id|
|
265
272
|
assert_existence :plan, plan_id, plans[plan_id]
|
273
|
+
rescue Stripe::InvalidRequestError
|
274
|
+
assert_existence :price, plan_id, prices[plan_id]
|
266
275
|
end
|
267
|
-
plan_ids.map { |plan_id| plans[plan_id] }
|
276
|
+
plan_ids.map { |plan_id| plans[plan_id] || prices[plan_id]}
|
268
277
|
end
|
269
278
|
|
270
279
|
# Ensure customer has card to charge unless one of the following criterias is met:
|
@@ -276,6 +285,7 @@ module StripeMock
|
|
276
285
|
return if customer[:invoice_settings][:default_payment_method]
|
277
286
|
return if customer[:trial_end]
|
278
287
|
return if params[:trial_end]
|
288
|
+
return if subscription[:default_payment_method]
|
279
289
|
|
280
290
|
plan_trial_period_days = plan[:trial_period_days] || 0
|
281
291
|
plan_has_trial = plan_trial_period_days != 0 || plan[:amount] == 0 || plan[:trial_end]
|
@@ -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
|
|
@@ -110,9 +110,41 @@ module StripeMock
|
|
110
110
|
|
111
111
|
end
|
112
112
|
|
113
|
+
def validate_create_price_params(params)
|
114
|
+
price_id = params[:id].to_s
|
115
|
+
product_id = params[:product]
|
116
|
+
|
117
|
+
@base_strategy.create_price_params.keys.each do |attr_name|
|
118
|
+
message = "Missing required param: #{attr_name}."
|
119
|
+
raise Stripe::InvalidRequestError.new(message, attr_name) if params[attr_name].nil?
|
120
|
+
end
|
121
|
+
|
122
|
+
if prices[price_id]
|
123
|
+
message = already_exists_message(Stripe::Price)
|
124
|
+
raise Stripe::InvalidRequestError.new(message, :id)
|
125
|
+
end
|
126
|
+
|
127
|
+
unless products[product_id]
|
128
|
+
message = not_found_message(Stripe::Product, product_id)
|
129
|
+
raise Stripe::InvalidRequestError.new(message, :product)
|
130
|
+
end
|
131
|
+
|
132
|
+
unless SUPPORTED_CURRENCIES.include?(params[:currency])
|
133
|
+
message = invalid_currency_message(params[:currency])
|
134
|
+
raise Stripe::InvalidRequestError.new(message, :currency)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def validate_list_prices_params(params)
|
139
|
+
if params[:lookup_keys] && !params[:lookup_keys].is_a?(Array)
|
140
|
+
raise Stripe::InvalidRequestError.new('Invalid array', :lookup_keys)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
113
144
|
def require_param(param_name)
|
114
145
|
raise Stripe::InvalidRequestError.new("Missing required param: #{param_name}.", param_name.to_s, http_status: 400)
|
115
146
|
end
|
147
|
+
|
116
148
|
end
|
117
149
|
end
|
118
150
|
end
|
@@ -41,6 +41,15 @@ module StripeMock
|
|
41
41
|
}.merge(params)
|
42
42
|
end
|
43
43
|
|
44
|
+
def create_price(params={})
|
45
|
+
Stripe::Price.create create_price_params(params)
|
46
|
+
end
|
47
|
+
|
48
|
+
def create_price_params(params={})
|
49
|
+
{
|
50
|
+
:currency => StripeMock.default_currency,
|
51
|
+
}.merge(params)
|
52
|
+
end
|
44
53
|
|
45
54
|
def list_subscriptions(limit)
|
46
55
|
Stripe::Subscription.list(limit: limit)
|
@@ -97,10 +106,27 @@ module StripeMock
|
|
97
106
|
}.merge(params)
|
98
107
|
end
|
99
108
|
|
109
|
+
def create_checkout_session_params(params = {})
|
110
|
+
{
|
111
|
+
payment_method_types: ['card'],
|
112
|
+
line_items: [{
|
113
|
+
name: 'T-shirt',
|
114
|
+
quantity: 1,
|
115
|
+
amount: 500,
|
116
|
+
currency: 'usd',
|
117
|
+
}],
|
118
|
+
}.merge(params)
|
119
|
+
end
|
120
|
+
|
121
|
+
|
100
122
|
def create_coupon(params = {})
|
101
123
|
Stripe::Coupon.create create_coupon_params(params)
|
102
124
|
end
|
103
125
|
|
126
|
+
def create_checkout_session(params = {})
|
127
|
+
Stripe::Checkout::Session.create create_checkout_session_params(params)
|
128
|
+
end
|
129
|
+
|
104
130
|
def delete_all_coupons
|
105
131
|
coupons = Stripe::Coupon.list
|
106
132
|
coupons.data.map(&:delete) if coupons.data.count > 0
|
data/lib/stripe_mock/version.rb
CHANGED
@@ -0,0 +1,186 @@
|
|
1
|
+
{
|
2
|
+
"id": "evt_00000000000000",
|
3
|
+
"object": "event",
|
4
|
+
"api_version": "2018-02-28",
|
5
|
+
"created": 1578401135,
|
6
|
+
"data": {
|
7
|
+
"object": {
|
8
|
+
"id": "pi_00000000000000",
|
9
|
+
"object": "payment_intent",
|
10
|
+
"allowed_source_types": ["card", "sepa_debit"],
|
11
|
+
"amount": 200,
|
12
|
+
"amount_capturable": 0,
|
13
|
+
"amount_received": 0,
|
14
|
+
"application": null,
|
15
|
+
"application_fee_amount": null,
|
16
|
+
"canceled_at": null,
|
17
|
+
"cancellation_reason": null,
|
18
|
+
"capture_method": "automatic",
|
19
|
+
"charges": {
|
20
|
+
"object": "list",
|
21
|
+
"data": [
|
22
|
+
{
|
23
|
+
"id": "py_00000000000000",
|
24
|
+
"object": "charge",
|
25
|
+
"amount": 200,
|
26
|
+
"amount_refunded": 0,
|
27
|
+
"application": null,
|
28
|
+
"application_fee": null,
|
29
|
+
"application_fee_amount": null,
|
30
|
+
"balance_transaction": null,
|
31
|
+
"billing_details": {
|
32
|
+
"address": {
|
33
|
+
"city": null,
|
34
|
+
"country": null,
|
35
|
+
"line1": null,
|
36
|
+
"line2": null,
|
37
|
+
"postal_code": null,
|
38
|
+
"state": null
|
39
|
+
},
|
40
|
+
"email": "john.doe@example.com",
|
41
|
+
"name": "John Doe",
|
42
|
+
"phone": null
|
43
|
+
},
|
44
|
+
"captured": true,
|
45
|
+
"created": 1578401129,
|
46
|
+
"currency": "eur",
|
47
|
+
"customer": "cus_00000000000000",
|
48
|
+
"description": null,
|
49
|
+
"destination": "acct_00000000000000",
|
50
|
+
"dispute": null,
|
51
|
+
"disputed": false,
|
52
|
+
"failure_code": null,
|
53
|
+
"failure_message": null,
|
54
|
+
"fraud_details": {},
|
55
|
+
"invoice": null,
|
56
|
+
"livemode": false,
|
57
|
+
"metadata": {},
|
58
|
+
"on_behalf_of": null,
|
59
|
+
"order": null,
|
60
|
+
"outcome": {
|
61
|
+
"network_status": "approved_by_network",
|
62
|
+
"reason": null,
|
63
|
+
"risk_level": "not_assessed",
|
64
|
+
"seller_message": "Payment complete.",
|
65
|
+
"type": "authorized"
|
66
|
+
},
|
67
|
+
"paid": false,
|
68
|
+
"payment_intent": "pi_00000000000000",
|
69
|
+
"payment_method": "pm_00000000000000",
|
70
|
+
"payment_method_details": {
|
71
|
+
"sepa_debit": {
|
72
|
+
"bank_code": "37040044",
|
73
|
+
"branch_code": null,
|
74
|
+
"country": "DE",
|
75
|
+
"fingerprint": "00000000000000",
|
76
|
+
"last4": "3001",
|
77
|
+
"mandate": "mandate_00000000000000"
|
78
|
+
},
|
79
|
+
"type": "sepa_debit"
|
80
|
+
},
|
81
|
+
"receipt_email": null,
|
82
|
+
"receipt_number": null,
|
83
|
+
"receipt_url": "https://pay.stripe.com/receipts/acct_00000000000000/py_00000000000000/rcpt_00000000000000",
|
84
|
+
"refunded": false,
|
85
|
+
"refunds": {
|
86
|
+
"object": "list",
|
87
|
+
"data": [],
|
88
|
+
"has_more": false,
|
89
|
+
"total_count": 0,
|
90
|
+
"url": "/v1/charges/py_00000000000000/refunds"
|
91
|
+
},
|
92
|
+
"review": null,
|
93
|
+
"shipping": null,
|
94
|
+
"source": null,
|
95
|
+
"source_transfer": null,
|
96
|
+
"statement_descriptor": "ACME Corp",
|
97
|
+
"statement_descriptor_suffix": null,
|
98
|
+
"status": "failed",
|
99
|
+
"transfer_data": {
|
100
|
+
"amount": null,
|
101
|
+
"destination": "acct_00000000000000"
|
102
|
+
},
|
103
|
+
"transfer_group": "group_pi_00000000000000"
|
104
|
+
}
|
105
|
+
],
|
106
|
+
"has_more": false,
|
107
|
+
"total_count": 1,
|
108
|
+
"url": "/v1/charges?payment_intent=pi_00000000000000"
|
109
|
+
},
|
110
|
+
"client_secret": "pi_00000000000000",
|
111
|
+
"confirmation_method": "automatic",
|
112
|
+
"created": 1578401129,
|
113
|
+
"currency": "eur",
|
114
|
+
"customer": "cus_00000000000000",
|
115
|
+
"description": null,
|
116
|
+
"invoice": null,
|
117
|
+
"last_payment_error": {
|
118
|
+
"code": "payment_intent_payment_attempt_failed",
|
119
|
+
"doc_url": "https://stripe.com/docs/error-codes/payment-intent-payment-attempt-failed",
|
120
|
+
"message": "The payment failed.",
|
121
|
+
"payment_method": {
|
122
|
+
"id": "pm_00000000000000",
|
123
|
+
"object": "payment_method",
|
124
|
+
"billing_details": {
|
125
|
+
"address": {
|
126
|
+
"city": null,
|
127
|
+
"country": null,
|
128
|
+
"line1": null,
|
129
|
+
"line2": null,
|
130
|
+
"postal_code": null,
|
131
|
+
"state": null
|
132
|
+
},
|
133
|
+
"email": "john.doe@example.com",
|
134
|
+
"name": "John Doe",
|
135
|
+
"phone": null
|
136
|
+
},
|
137
|
+
"created": 1578400666,
|
138
|
+
"customer": "cus_00000000000000",
|
139
|
+
"livemode": false,
|
140
|
+
"metadata": {},
|
141
|
+
"sepa_debit": {
|
142
|
+
"bank_code": "37040044",
|
143
|
+
"branch_code": "",
|
144
|
+
"country": "DE",
|
145
|
+
"fingerprint": "00000000000000",
|
146
|
+
"last4": "3001"
|
147
|
+
},
|
148
|
+
"type": "sepa_debit"
|
149
|
+
},
|
150
|
+
"type": "invalid_request_error"
|
151
|
+
},
|
152
|
+
"livemode": false,
|
153
|
+
"metadata": {},
|
154
|
+
"next_action": null,
|
155
|
+
"next_source_action": null,
|
156
|
+
"on_behalf_of": null,
|
157
|
+
"payment_method": null,
|
158
|
+
"payment_method_options": {
|
159
|
+
"card": {
|
160
|
+
"installments": null,
|
161
|
+
"request_three_d_secure": "automatic"
|
162
|
+
}
|
163
|
+
},
|
164
|
+
"payment_method_types": ["card", "sepa_debit"],
|
165
|
+
"receipt_email": null,
|
166
|
+
"review": null,
|
167
|
+
"setup_future_usage": null,
|
168
|
+
"shipping": null,
|
169
|
+
"source": null,
|
170
|
+
"statement_descriptor": "ACME Corp",
|
171
|
+
"statement_descriptor_suffix": null,
|
172
|
+
"status": "requires_source",
|
173
|
+
"transfer_data": {
|
174
|
+
"destination": "acct_00000000000000"
|
175
|
+
},
|
176
|
+
"transfer_group": null
|
177
|
+
}
|
178
|
+
},
|
179
|
+
"livemode": false,
|
180
|
+
"pending_webhooks": 3,
|
181
|
+
"request": {
|
182
|
+
"id": null,
|
183
|
+
"idempotency_key": null
|
184
|
+
},
|
185
|
+
"type": "payment_intent.payment_failed"
|
186
|
+
}
|