epopia-stripe-ruby-mock 2.5.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.env +2 -0
- data/.gitignore +8 -0
- data/.rspec +1 -0
- data/.travis.yml +28 -0
- data/Gemfile +12 -0
- data/LICENSE.txt +22 -0
- data/README.md +413 -0
- data/Rakefile +14 -0
- data/bin/stripe-mock-server +19 -0
- data/lib/stripe_mock.rb +95 -0
- data/lib/stripe_mock/api/account_balance.rb +14 -0
- data/lib/stripe_mock/api/bank_tokens.rb +13 -0
- data/lib/stripe_mock/api/card_tokens.rb +13 -0
- data/lib/stripe_mock/api/client.rb +41 -0
- data/lib/stripe_mock/api/conversion_rate.rb +14 -0
- data/lib/stripe_mock/api/debug.rb +11 -0
- data/lib/stripe_mock/api/errors.rb +65 -0
- data/lib/stripe_mock/api/global_id_prefix.rb +22 -0
- data/lib/stripe_mock/api/instance.rb +38 -0
- data/lib/stripe_mock/api/live.rb +15 -0
- data/lib/stripe_mock/api/server.rb +39 -0
- data/lib/stripe_mock/api/test_helpers.rb +24 -0
- data/lib/stripe_mock/api/webhooks.rb +88 -0
- data/lib/stripe_mock/client.rb +127 -0
- data/lib/stripe_mock/data.rb +1193 -0
- data/lib/stripe_mock/data/list.rb +73 -0
- data/lib/stripe_mock/error_queue.rb +27 -0
- data/lib/stripe_mock/errors/closed_client_connection_error.rb +9 -0
- data/lib/stripe_mock/errors/server_timeout_error.rb +12 -0
- data/lib/stripe_mock/errors/stripe_mock_error.rb +15 -0
- data/lib/stripe_mock/errors/uninitialized_instance_error.rb +9 -0
- data/lib/stripe_mock/errors/unstarted_state_error.rb +9 -0
- data/lib/stripe_mock/errors/unsupported_request_error.rb +4 -0
- data/lib/stripe_mock/instance.rb +237 -0
- data/lib/stripe_mock/request_handlers/accounts.rb +86 -0
- data/lib/stripe_mock/request_handlers/balance.rb +17 -0
- data/lib/stripe_mock/request_handlers/balance_transactions.rb +37 -0
- data/lib/stripe_mock/request_handlers/cards.rb +35 -0
- data/lib/stripe_mock/request_handlers/charges.rb +177 -0
- data/lib/stripe_mock/request_handlers/country_spec.rb +22 -0
- data/lib/stripe_mock/request_handlers/coupons.rb +35 -0
- data/lib/stripe_mock/request_handlers/customers.rb +137 -0
- data/lib/stripe_mock/request_handlers/disputes.rb +35 -0
- data/lib/stripe_mock/request_handlers/ephemeral_key.rb +13 -0
- data/lib/stripe_mock/request_handlers/events.rb +21 -0
- data/lib/stripe_mock/request_handlers/external_accounts.rb +55 -0
- data/lib/stripe_mock/request_handlers/helpers/bank_account_helpers.rb +14 -0
- data/lib/stripe_mock/request_handlers/helpers/card_helpers.rb +127 -0
- data/lib/stripe_mock/request_handlers/helpers/charge_helpers.rb +16 -0
- data/lib/stripe_mock/request_handlers/helpers/coupon_helpers.rb +17 -0
- data/lib/stripe_mock/request_handlers/helpers/external_account_helpers.rb +49 -0
- data/lib/stripe_mock/request_handlers/helpers/subscription_helpers.rb +119 -0
- data/lib/stripe_mock/request_handlers/helpers/token_helpers.rb +44 -0
- data/lib/stripe_mock/request_handlers/invoice_items.rb +45 -0
- data/lib/stripe_mock/request_handlers/invoices.rb +177 -0
- data/lib/stripe_mock/request_handlers/orders.rb +80 -0
- data/lib/stripe_mock/request_handlers/payment_intents.rb +203 -0
- data/lib/stripe_mock/request_handlers/payment_methods.rb +112 -0
- data/lib/stripe_mock/request_handlers/payouts.rb +32 -0
- data/lib/stripe_mock/request_handlers/plans.rb +42 -0
- data/lib/stripe_mock/request_handlers/products.rb +43 -0
- data/lib/stripe_mock/request_handlers/recipients.rb +60 -0
- data/lib/stripe_mock/request_handlers/refunds.rb +91 -0
- data/lib/stripe_mock/request_handlers/sources.rb +55 -0
- data/lib/stripe_mock/request_handlers/subscription_items.rb +36 -0
- data/lib/stripe_mock/request_handlers/subscriptions.rb +296 -0
- data/lib/stripe_mock/request_handlers/tax_rates.rb +36 -0
- data/lib/stripe_mock/request_handlers/tokens.rb +75 -0
- data/lib/stripe_mock/request_handlers/transfers.rb +65 -0
- data/lib/stripe_mock/request_handlers/validators/param_validators.rb +32 -0
- data/lib/stripe_mock/server.rb +93 -0
- data/lib/stripe_mock/test_strategies/base.rb +81 -0
- data/lib/stripe_mock/test_strategies/live.rb +40 -0
- data/lib/stripe_mock/test_strategies/mock.rb +27 -0
- data/lib/stripe_mock/util.rb +44 -0
- data/lib/stripe_mock/version.rb +4 -0
- data/lib/stripe_mock/webhook_fixtures/account.application.deauthorized.json +12 -0
- data/lib/stripe_mock/webhook_fixtures/account.external_account.created.json +27 -0
- data/lib/stripe_mock/webhook_fixtures/account.external_account.deleted.json +27 -0
- data/lib/stripe_mock/webhook_fixtures/account.external_account.updated.json +27 -0
- data/lib/stripe_mock/webhook_fixtures/account.updated.json +26 -0
- data/lib/stripe_mock/webhook_fixtures/balance.available.json +25 -0
- data/lib/stripe_mock/webhook_fixtures/charge.dispute.closed.json +22 -0
- data/lib/stripe_mock/webhook_fixtures/charge.dispute.created.json +22 -0
- data/lib/stripe_mock/webhook_fixtures/charge.dispute.funds_reinstated.json +88 -0
- data/lib/stripe_mock/webhook_fixtures/charge.dispute.funds_withdrawn.json +88 -0
- data/lib/stripe_mock/webhook_fixtures/charge.dispute.updated.json +25 -0
- data/lib/stripe_mock/webhook_fixtures/charge.failed.json +56 -0
- data/lib/stripe_mock/webhook_fixtures/charge.refunded.json +69 -0
- data/lib/stripe_mock/webhook_fixtures/charge.succeeded.json +55 -0
- data/lib/stripe_mock/webhook_fixtures/charge.updated.json +58 -0
- data/lib/stripe_mock/webhook_fixtures/coupon.created.json +23 -0
- data/lib/stripe_mock/webhook_fixtures/coupon.deleted.json +23 -0
- data/lib/stripe_mock/webhook_fixtures/customer.created.json +54 -0
- data/lib/stripe_mock/webhook_fixtures/customer.deleted.json +42 -0
- data/lib/stripe_mock/webhook_fixtures/customer.discount.created.json +28 -0
- data/lib/stripe_mock/webhook_fixtures/customer.discount.deleted.json +28 -0
- data/lib/stripe_mock/webhook_fixtures/customer.discount.updated.json +43 -0
- data/lib/stripe_mock/webhook_fixtures/customer.source.created.json +32 -0
- data/lib/stripe_mock/webhook_fixtures/customer.source.deleted.json +32 -0
- data/lib/stripe_mock/webhook_fixtures/customer.source.updated.json +36 -0
- data/lib/stripe_mock/webhook_fixtures/customer.subscription.created.json +66 -0
- data/lib/stripe_mock/webhook_fixtures/customer.subscription.deleted.json +65 -0
- data/lib/stripe_mock/webhook_fixtures/customer.subscription.trial_will_end.json +65 -0
- data/lib/stripe_mock/webhook_fixtures/customer.subscription.updated.json +78 -0
- data/lib/stripe_mock/webhook_fixtures/customer.updated.json +57 -0
- data/lib/stripe_mock/webhook_fixtures/invoice.created.json +71 -0
- data/lib/stripe_mock/webhook_fixtures/invoice.payment_failed.json +105 -0
- data/lib/stripe_mock/webhook_fixtures/invoice.payment_succeeded.json +112 -0
- data/lib/stripe_mock/webhook_fixtures/invoice.updated.json +74 -0
- data/lib/stripe_mock/webhook_fixtures/invoiceitem.created.json +21 -0
- data/lib/stripe_mock/webhook_fixtures/invoiceitem.deleted.json +21 -0
- data/lib/stripe_mock/webhook_fixtures/invoiceitem.updated.json +24 -0
- data/lib/stripe_mock/webhook_fixtures/plan.created.json +20 -0
- data/lib/stripe_mock/webhook_fixtures/plan.deleted.json +20 -0
- data/lib/stripe_mock/webhook_fixtures/plan.updated.json +23 -0
- data/lib/stripe_mock/webhook_fixtures/transfer.created.json +89 -0
- data/lib/stripe_mock/webhook_fixtures/transfer.failed.json +89 -0
- data/lib/stripe_mock/webhook_fixtures/transfer.paid.json +89 -0
- data/lib/stripe_mock/webhook_fixtures/transfer.updated.json +92 -0
- data/lib/trollop.rb +782 -0
- data/spec/_dummy/webhooks/dummy.event.json +6 -0
- data/spec/api/instance_spec.rb +30 -0
- data/spec/fixtures/create_refund.yml +126 -0
- data/spec/fixtures/stripe_webhooks/account.updated.json +7 -0
- data/spec/fixtures/stripe_webhooks/custom.account.updated.json +5 -0
- data/spec/instance_spec.rb +100 -0
- data/spec/integration_examples/charge_token_examples.rb +51 -0
- data/spec/integration_examples/customer_card_examples.rb +42 -0
- data/spec/integration_examples/prepare_error_examples.rb +38 -0
- data/spec/list_spec.rb +140 -0
- data/spec/readme_spec.rb +75 -0
- data/spec/server_spec.rb +139 -0
- data/spec/shared_stripe_examples/account_examples.rb +96 -0
- data/spec/shared_stripe_examples/balance_examples.rb +11 -0
- data/spec/shared_stripe_examples/balance_transaction_examples.rb +63 -0
- data/spec/shared_stripe_examples/bank_examples.rb +229 -0
- data/spec/shared_stripe_examples/bank_token_examples.rb +59 -0
- data/spec/shared_stripe_examples/card_examples.rb +307 -0
- data/spec/shared_stripe_examples/card_token_examples.rb +185 -0
- data/spec/shared_stripe_examples/charge_examples.rb +510 -0
- data/spec/shared_stripe_examples/country_specs_examples.rb +18 -0
- data/spec/shared_stripe_examples/coupon_examples.rb +85 -0
- data/spec/shared_stripe_examples/customer_examples.rb +453 -0
- data/spec/shared_stripe_examples/dispute_examples.rb +98 -0
- data/spec/shared_stripe_examples/ephemeral_key_examples.rb +17 -0
- data/spec/shared_stripe_examples/error_mock_examples.rb +162 -0
- data/spec/shared_stripe_examples/external_account_examples.rb +170 -0
- data/spec/shared_stripe_examples/extra_features_examples.rb +36 -0
- data/spec/shared_stripe_examples/invoice_examples.rb +524 -0
- data/spec/shared_stripe_examples/invoice_item_examples.rb +69 -0
- data/spec/shared_stripe_examples/payment_intent_examples.rb +131 -0
- data/spec/shared_stripe_examples/payment_method_examples.rb +175 -0
- data/spec/shared_stripe_examples/payout_examples.rb +68 -0
- data/spec/shared_stripe_examples/plan_examples.rb +194 -0
- data/spec/shared_stripe_examples/product_example.rb +65 -0
- data/spec/shared_stripe_examples/recipient_examples.rb +118 -0
- data/spec/shared_stripe_examples/refund_examples.rb +472 -0
- data/spec/shared_stripe_examples/subscription_examples.rb +1148 -0
- data/spec/shared_stripe_examples/subscription_items_examples.rb +75 -0
- data/spec/shared_stripe_examples/tax_rate_examples.rb +42 -0
- data/spec/shared_stripe_examples/transfer_examples.rb +130 -0
- data/spec/shared_stripe_examples/validation_examples.rb +19 -0
- data/spec/shared_stripe_examples/webhook_event_examples.rb +261 -0
- data/spec/spec_helper.rb +58 -0
- data/spec/stripe_mock_spec.rb +123 -0
- data/spec/support/stripe_examples.rb +42 -0
- data/spec/util_spec.rb +121 -0
- data/stripe-ruby-mock.gemspec +27 -0
- metadata +344 -0
@@ -0,0 +1,44 @@
|
|
1
|
+
module StripeMock
|
2
|
+
module RequestHandlers
|
3
|
+
module Helpers
|
4
|
+
|
5
|
+
def generate_bank_token(bank_params = {})
|
6
|
+
token = new_id 'btok'
|
7
|
+
bank_params[:id] = new_id 'bank_account'
|
8
|
+
@bank_tokens[token] = Data.mock_bank_account bank_params
|
9
|
+
token
|
10
|
+
end
|
11
|
+
|
12
|
+
def generate_card_token(card_params = {})
|
13
|
+
token = new_id 'tok'
|
14
|
+
card_params[:id] = new_id 'cc'
|
15
|
+
@card_tokens[token] = Data.mock_card symbolize_names(card_params)
|
16
|
+
token
|
17
|
+
end
|
18
|
+
|
19
|
+
def get_bank_by_token(token)
|
20
|
+
if token.nil? || @bank_tokens[token].nil?
|
21
|
+
Data.mock_bank_account
|
22
|
+
else
|
23
|
+
@bank_tokens.delete(token)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def get_card_by_token(token)
|
28
|
+
if token.nil? || @card_tokens[token].nil?
|
29
|
+
# TODO: Make this strict
|
30
|
+
msg = "Invalid token id: #{token}"
|
31
|
+
raise Stripe::InvalidRequestError.new(msg, 'tok', http_status: 404)
|
32
|
+
else
|
33
|
+
@card_tokens.delete(token)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def get_card_or_bank_by_token(token)
|
38
|
+
token_id = token['id'] || token
|
39
|
+
@card_tokens[token_id] || @bank_tokens[token_id] || raise(Stripe::InvalidRequestError.new("Invalid token id: #{token_id}", 'tok', http_status: 404))
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module StripeMock
|
2
|
+
module RequestHandlers
|
3
|
+
module InvoiceItems
|
4
|
+
|
5
|
+
def InvoiceItems.included(klass)
|
6
|
+
klass.add_handler 'post /v1/invoiceitems', :new_invoice_item
|
7
|
+
klass.add_handler 'post /v1/invoiceitems/(.*)', :update_invoice_item
|
8
|
+
klass.add_handler 'get /v1/invoiceitems/(.*)', :get_invoice_item
|
9
|
+
klass.add_handler 'get /v1/invoiceitems', :list_invoice_items
|
10
|
+
klass.add_handler 'delete /v1/invoiceitems/(.*)', :delete_invoice_item
|
11
|
+
end
|
12
|
+
|
13
|
+
def new_invoice_item(route, method_url, params, headers)
|
14
|
+
params[:id] ||= new_id('ii')
|
15
|
+
invoice_items[params[:id]] = Data.mock_invoice_item(params)
|
16
|
+
end
|
17
|
+
|
18
|
+
def update_invoice_item(route, method_url, params, headers)
|
19
|
+
route =~ method_url
|
20
|
+
list_item = assert_existence :list_item, $1, invoice_items[$1]
|
21
|
+
list_item.merge!(params)
|
22
|
+
end
|
23
|
+
|
24
|
+
def delete_invoice_item(route, method_url, params, headers)
|
25
|
+
route =~ method_url
|
26
|
+
assert_existence :list_item, $1, invoice_items[$1]
|
27
|
+
|
28
|
+
invoice_items[$1] = {
|
29
|
+
id: invoice_items[$1][:id],
|
30
|
+
deleted: true
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
def list_invoice_items(route, method_url, params, headers)
|
35
|
+
Data.mock_list_object(invoice_items.values, params)
|
36
|
+
end
|
37
|
+
|
38
|
+
def get_invoice_item(route, method_url, params, headers)
|
39
|
+
route =~ method_url
|
40
|
+
assert_existence :invoice_item, $1, invoice_items[$1]
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,177 @@
|
|
1
|
+
module StripeMock
|
2
|
+
module RequestHandlers
|
3
|
+
module Invoices
|
4
|
+
|
5
|
+
def Invoices.included(klass)
|
6
|
+
klass.add_handler 'post /v1/invoices', :new_invoice
|
7
|
+
klass.add_handler 'get /v1/invoices/upcoming', :upcoming_invoice
|
8
|
+
klass.add_handler 'get /v1/invoices/(.*)/lines', :get_invoice_line_items
|
9
|
+
klass.add_handler 'get /v1/invoices/(.*)', :get_invoice
|
10
|
+
klass.add_handler 'get /v1/invoices', :list_invoices
|
11
|
+
klass.add_handler 'post /v1/invoices/(.*)/pay', :pay_invoice
|
12
|
+
klass.add_handler 'post /v1/invoices/(.*)', :update_invoice
|
13
|
+
end
|
14
|
+
|
15
|
+
def new_invoice(route, method_url, params, headers)
|
16
|
+
id = new_id('in')
|
17
|
+
invoice_item = Data.mock_line_item()
|
18
|
+
invoices[id] = Data.mock_invoice([invoice_item], params.merge(:id => id))
|
19
|
+
end
|
20
|
+
|
21
|
+
def update_invoice(route, method_url, params, headers)
|
22
|
+
route =~ method_url
|
23
|
+
params.delete(:lines) if params[:lines]
|
24
|
+
assert_existence :invoice, $1, invoices[$1]
|
25
|
+
invoices[$1].merge!(params)
|
26
|
+
end
|
27
|
+
|
28
|
+
def list_invoices(route, method_url, params, headers)
|
29
|
+
params[:offset] ||= 0
|
30
|
+
params[:limit] ||= 10
|
31
|
+
|
32
|
+
result = invoices.clone
|
33
|
+
|
34
|
+
if params[:customer]
|
35
|
+
result.delete_if { |k,v| v[:customer] != params[:customer] }
|
36
|
+
end
|
37
|
+
|
38
|
+
Data.mock_list_object(result.values, params)
|
39
|
+
end
|
40
|
+
|
41
|
+
def get_invoice(route, method_url, params, headers)
|
42
|
+
route =~ method_url
|
43
|
+
assert_existence :invoice, $1, invoices[$1]
|
44
|
+
end
|
45
|
+
|
46
|
+
def get_invoice_line_items(route, method_url, params, headers)
|
47
|
+
route =~ method_url
|
48
|
+
assert_existence :invoice, $1, invoices[$1]
|
49
|
+
invoices[$1][:lines]
|
50
|
+
end
|
51
|
+
|
52
|
+
def pay_invoice(route, method_url, params, headers)
|
53
|
+
route =~ method_url
|
54
|
+
assert_existence :invoice, $1, invoices[$1]
|
55
|
+
charge = invoice_charge(invoices[$1])
|
56
|
+
invoices[$1].merge!(:paid => true, :attempted => true, :charge => charge[:id])
|
57
|
+
end
|
58
|
+
|
59
|
+
def upcoming_invoice(route, method_url, params, headers)
|
60
|
+
route =~ method_url
|
61
|
+
raise Stripe::InvalidRequestError.new('Missing required param: customer', nil, http_status: 400) if params[:customer].nil?
|
62
|
+
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
|
+
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
|
+
|
65
|
+
customer = customers[params[:customer]]
|
66
|
+
assert_existence :customer, params[:customer], customer
|
67
|
+
|
68
|
+
raise Stripe::InvalidRequestError.new("No upcoming invoices for customer: #{customer[:id]}", nil, http_status: 404) if customer[:subscriptions][:data].length == 0
|
69
|
+
|
70
|
+
subscription =
|
71
|
+
if params[:subscription]
|
72
|
+
customer[:subscriptions][:data].select{|s|s[:id] == params[:subscription]}.first
|
73
|
+
else
|
74
|
+
customer[:subscriptions][:data].min_by { |sub| sub[:current_period_end] }
|
75
|
+
end
|
76
|
+
|
77
|
+
if params[:subscription_proration_date] && !((subscription[:current_period_start]..subscription[:current_period_end]) === params[:subscription_proration_date])
|
78
|
+
raise Stripe::InvalidRequestError.new('Cannot specify proration date outside of current subscription period', nil, http_status: 400)
|
79
|
+
end
|
80
|
+
|
81
|
+
prorating = false
|
82
|
+
subscription_proration_date = nil
|
83
|
+
subscription_plan_id = params[:subscription_plan] || subscription[:plan][:id]
|
84
|
+
subscription_quantity = params[:subscription_quantity] || subscription[:quantity]
|
85
|
+
if subscription_plan_id != subscription[:plan][:id] || subscription_quantity != subscription[:quantity]
|
86
|
+
prorating = true
|
87
|
+
invoice_date = Time.now.to_i
|
88
|
+
subscription_plan = assert_existence :plan, subscription_plan_id, plans[subscription_plan_id.to_s]
|
89
|
+
preview_subscription = Data.mock_subscription
|
90
|
+
preview_subscription = resolve_subscription_changes(preview_subscription, [subscription_plan], customer, { trial_end: params[:subscription_trial_end] })
|
91
|
+
preview_subscription[:id] = subscription[:id]
|
92
|
+
preview_subscription[:quantity] = subscription_quantity
|
93
|
+
subscription_proration_date = params[:subscription_proration_date] || Time.now
|
94
|
+
else
|
95
|
+
preview_subscription = subscription
|
96
|
+
invoice_date = subscription[:current_period_end]
|
97
|
+
end
|
98
|
+
|
99
|
+
invoice_lines = []
|
100
|
+
|
101
|
+
if prorating
|
102
|
+
unused_amount = subscription[:plan][:amount] * subscription[:quantity] * (subscription[:current_period_end] - subscription_proration_date.to_i) / (subscription[:current_period_end] - subscription[:current_period_start])
|
103
|
+
invoice_lines << Data.mock_line_item(
|
104
|
+
id: new_id('ii'),
|
105
|
+
amount: -unused_amount,
|
106
|
+
description: 'Unused time',
|
107
|
+
plan: subscription[:plan],
|
108
|
+
period: {
|
109
|
+
start: subscription_proration_date.to_i,
|
110
|
+
end: subscription[:current_period_end]
|
111
|
+
},
|
112
|
+
quantity: subscription[:quantity],
|
113
|
+
proration: true
|
114
|
+
)
|
115
|
+
|
116
|
+
preview_plan = assert_existence :plan, params[:subscription_plan], plans[params[:subscription_plan]]
|
117
|
+
if preview_plan[:interval] == subscription[:plan][:interval] && preview_plan[:interval_count] == subscription[:plan][:interval_count] && params[:subscription_trial_end].nil?
|
118
|
+
remaining_amount = preview_plan[:amount] * subscription_quantity * (subscription[:current_period_end] - subscription_proration_date.to_i) / (subscription[:current_period_end] - subscription[:current_period_start])
|
119
|
+
invoice_lines << Data.mock_line_item(
|
120
|
+
id: new_id('ii'),
|
121
|
+
amount: remaining_amount,
|
122
|
+
description: 'Remaining time',
|
123
|
+
plan: preview_plan,
|
124
|
+
period: {
|
125
|
+
start: subscription_proration_date.to_i,
|
126
|
+
end: subscription[:current_period_end]
|
127
|
+
},
|
128
|
+
quantity: subscription_quantity,
|
129
|
+
proration: true
|
130
|
+
)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
subscription_line = get_mock_subscription_line_item(preview_subscription)
|
135
|
+
invoice_lines << subscription_line
|
136
|
+
|
137
|
+
Data.mock_invoice(invoice_lines,
|
138
|
+
id: new_id('in'),
|
139
|
+
customer: customer[:id],
|
140
|
+
discount: customer[:discount],
|
141
|
+
created: invoice_date,
|
142
|
+
starting_balance: customer[:account_balance],
|
143
|
+
subscription: preview_subscription[:id],
|
144
|
+
period_start: prorating ? invoice_date : preview_subscription[:current_period_start],
|
145
|
+
period_end: prorating ? invoice_date : preview_subscription[:current_period_end],
|
146
|
+
next_payment_attempt: preview_subscription[:current_period_end] + 3600 )
|
147
|
+
end
|
148
|
+
|
149
|
+
private
|
150
|
+
|
151
|
+
def get_mock_subscription_line_item(subscription)
|
152
|
+
Data.mock_line_item(
|
153
|
+
id: subscription[:id],
|
154
|
+
type: "subscription",
|
155
|
+
plan: subscription[:plan],
|
156
|
+
amount: subscription[:status] == 'trialing' ? 0 : subscription[:plan][:amount] * subscription[:quantity],
|
157
|
+
discountable: true,
|
158
|
+
quantity: subscription[:quantity],
|
159
|
+
period: {
|
160
|
+
start: subscription[:current_period_end],
|
161
|
+
end: get_ending_time(subscription[:current_period_start], subscription[:plan], 2)
|
162
|
+
})
|
163
|
+
end
|
164
|
+
|
165
|
+
## charge the customer on the invoice, if one does not exist, create
|
166
|
+
#anonymous charge
|
167
|
+
def invoice_charge(invoice)
|
168
|
+
begin
|
169
|
+
new_charge(nil, nil, {customer: invoice[:customer]["id"], amount: invoice[:amount_due], currency: StripeMock.default_currency}, nil)
|
170
|
+
rescue Stripe::InvalidRequestError
|
171
|
+
new_charge(nil, nil, {source: generate_card_token, amount: invoice[:amount_due], currency: StripeMock.default_currency}, nil)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module StripeMock
|
2
|
+
module RequestHandlers
|
3
|
+
module Orders
|
4
|
+
|
5
|
+
def Orders.included(klass)
|
6
|
+
klass.add_handler 'post /v1/orders', :new_order
|
7
|
+
klass.add_handler 'post /v1/orders/(.*)/pay', :pay_order
|
8
|
+
klass.add_handler 'post /v1/orders/(.*)', :update_order
|
9
|
+
klass.add_handler 'get /v1/orders/(.*)', :get_order
|
10
|
+
klass.add_handler 'get /v1/orders', :list_orders
|
11
|
+
end
|
12
|
+
|
13
|
+
def new_order(route, method_url, params, headers)
|
14
|
+
params[:id] ||= new_id('or')
|
15
|
+
order_items = []
|
16
|
+
|
17
|
+
unless params[:currency].to_s.size == 3
|
18
|
+
raise Stripe::InvalidRequestError.new('You must supply a currency', nil, http_status: 400)
|
19
|
+
end
|
20
|
+
|
21
|
+
if params[:items]
|
22
|
+
unless params[:items].is_a? Array
|
23
|
+
raise Stripe::InvalidRequestError.new('You must supply a list of items', nil, http_status: 400)
|
24
|
+
end
|
25
|
+
|
26
|
+
unless params[:items].first.is_a? Hash
|
27
|
+
raise Stripe::InvalidRequestError.new('You must supply an item', nil, http_status: 400)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
orders[ params[:id] ] = Data.mock_order(order_items, params)
|
32
|
+
|
33
|
+
orders[ params[:id] ]
|
34
|
+
end
|
35
|
+
|
36
|
+
def update_order(route, method_url, params, headers)
|
37
|
+
route =~ method_url
|
38
|
+
order = assert_existence :order, $1, orders[$1]
|
39
|
+
|
40
|
+
if params[:metadata]
|
41
|
+
if params[:metadata].empty?
|
42
|
+
order[:metadata] = {}
|
43
|
+
else
|
44
|
+
order[:metadata].merge(params[:metadata])
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
if %w(created paid canceled fulfilled returned).include? params[:status]
|
49
|
+
order[:status] = params[:status]
|
50
|
+
end
|
51
|
+
order
|
52
|
+
end
|
53
|
+
|
54
|
+
def get_order(route, method_url, params, headers)
|
55
|
+
route =~ method_url
|
56
|
+
assert_existence :order, $1, orders[$1]
|
57
|
+
end
|
58
|
+
|
59
|
+
def pay_order(route, method_url, params, headers)
|
60
|
+
route =~ method_url
|
61
|
+
order = assert_existence :order, $1, orders[$1]
|
62
|
+
|
63
|
+
if params[:source].blank? && params[:customer].blank?
|
64
|
+
raise Stripe::InvalidRequestError.new('You must supply a source or customer', nil, http_status: 400)
|
65
|
+
end
|
66
|
+
|
67
|
+
charge_id = new_id('ch')
|
68
|
+
charges[charge_id] = Data.mock_charge(id: charge_id)
|
69
|
+
order[:charge] = charge_id
|
70
|
+
order[:status] = "paid"
|
71
|
+
order
|
72
|
+
end
|
73
|
+
|
74
|
+
def list_orders(route, method_url, params, headers)
|
75
|
+
Data.mock_list_object(orders.values, params)
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,203 @@
|
|
1
|
+
module StripeMock
|
2
|
+
module RequestHandlers
|
3
|
+
module PaymentIntents
|
4
|
+
FAILED_TRANSACTION_AMOUNT = 3178
|
5
|
+
REQUIRES_ACTION_AMOUNT = 3184
|
6
|
+
REQUIRES_CAPTURE_AMOUNT = 3169
|
7
|
+
|
8
|
+
ALLOWED_PARAMS = [:description, :metadata, :receipt_email, :shipping, :destination, :payment_method, :payment_method_types, :setup_future_usage, :transfer_data, :amount, :currency]
|
9
|
+
|
10
|
+
def PaymentIntents.included(klass)
|
11
|
+
klass.add_handler 'post /v1/payment_intents', :new_payment_intent
|
12
|
+
klass.add_handler 'get /v1/payment_intents', :get_payment_intents
|
13
|
+
klass.add_handler 'get /v1/payment_intents/(.*)', :get_payment_intent
|
14
|
+
klass.add_handler 'post /v1/payment_intents/(.*)/confirm', :confirm_payment_intent
|
15
|
+
klass.add_handler 'post /v1/payment_intents/(.*)/capture', :capture_payment_intent
|
16
|
+
klass.add_handler 'post /v1/payment_intents/(.*)/cancel', :cancel_payment_intent
|
17
|
+
klass.add_handler 'post /v1/payment_intents/(.*)', :update_payment_intent
|
18
|
+
end
|
19
|
+
|
20
|
+
def new_payment_intent(route, method_url, params, headers)
|
21
|
+
id = new_id('pi')
|
22
|
+
|
23
|
+
ensure_payment_intent_required_params(params)
|
24
|
+
status = case params[:amount]
|
25
|
+
when REQUIRES_ACTION_AMOUNT then 'requires_action'
|
26
|
+
when FAILED_TRANSACTION_AMOUNT then 'requires_payment_method'
|
27
|
+
when REQUIRES_CAPTURE_AMOUNT then 'requires_capture'
|
28
|
+
else
|
29
|
+
'succeeded'
|
30
|
+
end
|
31
|
+
last_payment_error = params[:amount] == FAILED_TRANSACTION_AMOUNT ? last_payment_error_generator(code: 'card_declined', decline_code: 'insufficient_funds', message: 'Not enough funds.') : nil
|
32
|
+
next_action = params[:amount] == REQUIRES_ACTION_AMOUNT ? { type: "use_stripe_sdk" } : nil
|
33
|
+
payment_intents[id] = Data.mock_payment_intent(
|
34
|
+
params.merge(
|
35
|
+
id: id,
|
36
|
+
status: status,
|
37
|
+
last_payment_error: last_payment_error,
|
38
|
+
next_action: next_action,
|
39
|
+
charges: status == 'succeeded' ? charges_data(params[:amount], params[:currency]) : empty_charges
|
40
|
+
)
|
41
|
+
)
|
42
|
+
|
43
|
+
payment_intents[id].clone
|
44
|
+
end
|
45
|
+
|
46
|
+
def update_payment_intent(route, method_url, params, headers)
|
47
|
+
route =~ method_url
|
48
|
+
id = $1
|
49
|
+
|
50
|
+
payment_intent = assert_existence :payment_intent, id, payment_intents[id]
|
51
|
+
payment_intents[id] = Util.rmerge(payment_intent, params.select{ |k,v| ALLOWED_PARAMS.include?(k)})
|
52
|
+
end
|
53
|
+
|
54
|
+
def get_payment_intents(route, method_url, params, headers)
|
55
|
+
params[:offset] ||= 0
|
56
|
+
params[:limit] ||= 10
|
57
|
+
|
58
|
+
clone = payment_intents.clone
|
59
|
+
|
60
|
+
if params[:customer]
|
61
|
+
clone.delete_if { |k,v| v[:customer] != params[:customer] }
|
62
|
+
end
|
63
|
+
|
64
|
+
Data.mock_list_object(clone.values, params)
|
65
|
+
end
|
66
|
+
|
67
|
+
def get_payment_intent(route, method_url, params, headers)
|
68
|
+
route =~ method_url
|
69
|
+
payment_intent_id = $1 || params[:payment_intent]
|
70
|
+
payment_intent = assert_existence :payment_intent, payment_intent_id, payment_intents[payment_intent_id]
|
71
|
+
|
72
|
+
payment_intent = payment_intent.clone
|
73
|
+
payment_intent
|
74
|
+
end
|
75
|
+
|
76
|
+
def capture_payment_intent(route, method_url, params, headers)
|
77
|
+
route =~ method_url
|
78
|
+
payment_intent = assert_existence :payment_intent, $1, payment_intents[$1]
|
79
|
+
|
80
|
+
payment_intent[:status] = payment_intent[:amount] == FAILED_TRANSACTION_AMOUNT ? 'requires_payment_method' : 'succeeded'
|
81
|
+
payment_intent[:last_payment_error] = payment_intent[:status] == 'requires_payment_method' ? last_payment_error_generator(code: 'card_declined', decline_code: 'do_not_honor', message: 'Your card has been declined. Please contact your bank for more information.') : nil
|
82
|
+
payment_intent
|
83
|
+
end
|
84
|
+
|
85
|
+
def confirm_payment_intent(route, method_url, params, headers)
|
86
|
+
route =~ method_url
|
87
|
+
payment_intent = assert_existence :payment_intent, $1, payment_intents[$1]
|
88
|
+
|
89
|
+
payment_intent[:status] = 'succeeded'
|
90
|
+
payment_intent[:charges] = charges_data(payment_intent[:amount], payment_intent[:currency])
|
91
|
+
payment_intent
|
92
|
+
end
|
93
|
+
|
94
|
+
def cancel_payment_intent(route, method_url, params, headers)
|
95
|
+
route =~ method_url
|
96
|
+
payment_intent = assert_existence :payment_intent, $1, payment_intents[$1]
|
97
|
+
|
98
|
+
payment_intent[:status] = 'canceled'
|
99
|
+
payment_intent
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
def ensure_payment_intent_required_params(params)
|
105
|
+
if params[:amount].nil?
|
106
|
+
require_param(:amount)
|
107
|
+
elsif params[:currency].nil?
|
108
|
+
require_param(:currency)
|
109
|
+
elsif non_integer_charge_amount?(params)
|
110
|
+
raise Stripe::InvalidRequestError.new("Invalid integer: #{params[:amount]}", 'amount', http_status: 400)
|
111
|
+
elsif non_positive_charge_amount?(params)
|
112
|
+
raise Stripe::InvalidRequestError.new('Invalid positive integer', 'amount', http_status: 400)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def non_integer_charge_amount?(params)
|
117
|
+
params[:amount] && !params[:amount].is_a?(Integer)
|
118
|
+
end
|
119
|
+
|
120
|
+
def non_positive_charge_amount?(params)
|
121
|
+
params[:amount] && params[:amount] < 1
|
122
|
+
end
|
123
|
+
|
124
|
+
def charges_data(amount, currency)
|
125
|
+
payment_intent_charge_id = new_id('ch')
|
126
|
+
payment_intent_charge = Data.mock_charge(
|
127
|
+
id: payment_intent_charge_id,
|
128
|
+
amount: amount,
|
129
|
+
currency: currency
|
130
|
+
)
|
131
|
+
charges[payment_intent_charge_id] = payment_intent_charge
|
132
|
+
{
|
133
|
+
:data => [payment_intent_charge],
|
134
|
+
:object => 'list',
|
135
|
+
has_more: false,
|
136
|
+
total_count: 1,
|
137
|
+
url: "/v1/charges?payment_intent=pi_1EwXFB2eZvKYlo2CggNnFBo8"
|
138
|
+
}
|
139
|
+
end
|
140
|
+
|
141
|
+
def empty_charges()
|
142
|
+
{
|
143
|
+
object: "list",
|
144
|
+
data: [],
|
145
|
+
has_more: false,
|
146
|
+
total_count: 0,
|
147
|
+
url: "/v1/charges?payment_intent=pi_1EwXFB2eZvKYlo2CggNnFBo8"
|
148
|
+
}
|
149
|
+
end
|
150
|
+
|
151
|
+
def last_payment_error_generator(code:, message:, decline_code:)
|
152
|
+
{
|
153
|
+
code: code,
|
154
|
+
doc_url: "https://stripe.com/docs/error-codes/payment-intent-authentication-failure",
|
155
|
+
message: message,
|
156
|
+
decline_code: decline_code,
|
157
|
+
payment_method: {
|
158
|
+
id: "pm_1EwXFA2eZvKYlo2C0tlY091l",
|
159
|
+
object: "payment_method",
|
160
|
+
billing_details: {
|
161
|
+
address: {
|
162
|
+
city: nil,
|
163
|
+
country: nil,
|
164
|
+
line1: nil,
|
165
|
+
line2: nil,
|
166
|
+
postal_code: nil,
|
167
|
+
state: nil
|
168
|
+
},
|
169
|
+
email: nil,
|
170
|
+
name: "seller_08072019090000",
|
171
|
+
phone: nil
|
172
|
+
},
|
173
|
+
card: {
|
174
|
+
brand: "visa",
|
175
|
+
checks: {
|
176
|
+
address_line1_check: nil,
|
177
|
+
address_postal_code_check: nil,
|
178
|
+
cvc_check: "unchecked"
|
179
|
+
},
|
180
|
+
country: "US",
|
181
|
+
exp_month: 12,
|
182
|
+
exp_year: 2021,
|
183
|
+
fingerprint: "LQBhEmJnItuj3mxf",
|
184
|
+
funding: "credit",
|
185
|
+
generated_from: nil,
|
186
|
+
last4: "1629",
|
187
|
+
three_d_secure_usage: {
|
188
|
+
supported: true
|
189
|
+
},
|
190
|
+
wallet: nil
|
191
|
+
},
|
192
|
+
created: 1563208900,
|
193
|
+
customer: nil,
|
194
|
+
livemode: false,
|
195
|
+
metadata: {},
|
196
|
+
type: "card"
|
197
|
+
},
|
198
|
+
type: "invalid_request_error"
|
199
|
+
}
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|