stripe-ruby-mock 2.5.6 → 3.1.0.rc2
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/.gitignore +1 -1
- data/.travis.yml +6 -9
- data/CHANGELOG.md +35 -0
- data/Gemfile +1 -0
- data/README.md +17 -11
- data/lib/stripe_mock.rb +11 -0
- data/lib/stripe_mock/api/client.rb +1 -1
- 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 +7 -0
- data/lib/stripe_mock/client.rb +2 -1
- data/lib/stripe_mock/data.rb +323 -13
- data/lib/stripe_mock/data/list.rb +42 -9
- data/lib/stripe_mock/instance.rb +52 -5
- data/lib/stripe_mock/request_handlers/account_links.rb +15 -0
- data/lib/stripe_mock/request_handlers/balance_transactions.rb +2 -2
- data/lib/stripe_mock/request_handlers/charges.rb +13 -12
- data/lib/stripe_mock/request_handlers/checkout.rb +15 -0
- data/lib/stripe_mock/request_handlers/checkout_session.rb +16 -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/express_login_links.rb +15 -0
- data/lib/stripe_mock/request_handlers/helpers/coupon_helpers.rb +14 -10
- data/lib/stripe_mock/request_handlers/helpers/subscription_helpers.rb +22 -7
- data/lib/stripe_mock/request_handlers/helpers/token_helpers.rb +1 -1
- data/lib/stripe_mock/request_handlers/invoices.rb +11 -5
- data/lib/stripe_mock/request_handlers/payment_intents.rb +182 -0
- data/lib/stripe_mock/request_handlers/payment_methods.rb +120 -0
- data/lib/stripe_mock/request_handlers/plans.rb +1 -1
- data/lib/stripe_mock/request_handlers/prices.rb +44 -0
- data/lib/stripe_mock/request_handlers/products.rb +44 -0
- data/lib/stripe_mock/request_handlers/refunds.rb +6 -3
- data/lib/stripe_mock/request_handlers/setup_intents.rb +93 -0
- data/lib/stripe_mock/request_handlers/sources.rb +12 -6
- data/lib/stripe_mock/request_handlers/subscription_items.rb +36 -0
- data/lib/stripe_mock/request_handlers/subscriptions.rb +82 -41
- data/lib/stripe_mock/request_handlers/tax_rates.rb +36 -0
- data/lib/stripe_mock/request_handlers/tokens.rb +8 -6
- data/lib/stripe_mock/request_handlers/validators/param_validators.rb +130 -9
- data/lib/stripe_mock/test_strategies/base.rb +68 -8
- 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/balance.available.json +6 -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.failed.json +166 -38
- data/lib/stripe_mock/webhook_fixtures/customer.created.json +1 -0
- data/lib/stripe_mock/webhook_fixtures/customer.updated.json +1 -0
- data/lib/stripe_mock/webhook_fixtures/invoice.created.json +2 -1
- data/lib/stripe_mock/webhook_fixtures/invoice.payment_succeeded.json +1 -1
- data/lib/stripe_mock/webhook_fixtures/invoice.updated.json +2 -1
- 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/lib/stripe_mock/webhook_fixtures/product.created.json +34 -0
- data/lib/stripe_mock/webhook_fixtures/product.deleted.json +34 -0
- data/lib/stripe_mock/webhook_fixtures/product.updated.json +38 -0
- data/spec/instance_spec.rb +10 -12
- data/spec/list_spec.rb +38 -0
- data/spec/server_spec.rb +6 -3
- data/spec/shared_stripe_examples/account_examples.rb +1 -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/balance_transaction_examples.rb +3 -3
- data/spec/shared_stripe_examples/bank_examples.rb +3 -3
- 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 +32 -36
- data/spec/shared_stripe_examples/checkout_examples.rb +38 -0
- data/spec/shared_stripe_examples/coupon_examples.rb +1 -1
- data/spec/shared_stripe_examples/customer_examples.rb +103 -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 +43 -41
- data/spec/shared_stripe_examples/invoice_item_examples.rb +1 -1
- data/spec/shared_stripe_examples/payment_intent_examples.rb +147 -0
- data/spec/shared_stripe_examples/payment_method_examples.rb +449 -0
- data/spec/shared_stripe_examples/payout_examples.rb +2 -2
- data/spec/shared_stripe_examples/plan_examples.rb +135 -77
- data/spec/shared_stripe_examples/price_examples.rb +183 -0
- data/spec/shared_stripe_examples/product_examples.rb +155 -0
- data/spec/shared_stripe_examples/refund_examples.rb +41 -31
- data/spec/shared_stripe_examples/setup_intent_examples.rb +68 -0
- data/spec/shared_stripe_examples/subscription_examples.rb +546 -295
- data/spec/shared_stripe_examples/subscription_items_examples.rb +76 -0
- data/spec/shared_stripe_examples/tax_rate_examples.rb +42 -0
- data/spec/shared_stripe_examples/transfer_examples.rb +9 -9
- data/spec/shared_stripe_examples/webhook_event_examples.rb +11 -11
- data/spec/spec_helper.rb +7 -4
- 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 +12 -2
- data/stripe-ruby-mock.gemspec +8 -3
- metadata +81 -32
@@ -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
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module StripeMock
|
2
|
+
module RequestHandlers
|
3
|
+
module Prices
|
4
|
+
|
5
|
+
def Prices.included(klass)
|
6
|
+
klass.add_handler 'post /v1/prices', :new_price
|
7
|
+
klass.add_handler 'post /v1/prices/(.*)', :update_price
|
8
|
+
klass.add_handler 'get /v1/prices/(.*)', :get_price
|
9
|
+
klass.add_handler 'get /v1/prices', :list_prices
|
10
|
+
end
|
11
|
+
|
12
|
+
def new_price(route, method_url, params, headers)
|
13
|
+
params[:id] ||= new_id('price')
|
14
|
+
validate_create_price_params(params)
|
15
|
+
prices[ params[:id] ] = Data.mock_price(params)
|
16
|
+
end
|
17
|
+
|
18
|
+
def update_price(route, method_url, params, headers)
|
19
|
+
route =~ method_url
|
20
|
+
assert_existence :price, $1, prices[$1]
|
21
|
+
prices[$1].merge!(params)
|
22
|
+
end
|
23
|
+
|
24
|
+
def get_price(route, method_url, params, headers)
|
25
|
+
route =~ method_url
|
26
|
+
assert_existence :price, $1, prices[$1]
|
27
|
+
end
|
28
|
+
|
29
|
+
def list_prices(route, method_url, params, headers)
|
30
|
+
limit = params[:limit] ? params[:limit] : 10
|
31
|
+
price_data = prices.values
|
32
|
+
validate_list_prices_params(params)
|
33
|
+
|
34
|
+
if params.key?(:lookup_keys)
|
35
|
+
price_data.select! do |price|
|
36
|
+
params[:lookup_keys].include?(price[:lookup_key])
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
Data.mock_list_object(price_data.first(limit), params.merge!(limit: limit))
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module StripeMock
|
2
|
+
module RequestHandlers
|
3
|
+
module Products
|
4
|
+
def self.included(base)
|
5
|
+
base.add_handler 'post /v1/products', :create_product
|
6
|
+
base.add_handler 'get /v1/products/(.*)', :retrieve_product
|
7
|
+
base.add_handler 'post /v1/products/(.*)', :update_product
|
8
|
+
base.add_handler 'get /v1/products', :list_products
|
9
|
+
base.add_handler 'delete /v1/products/(.*)', :destroy_product
|
10
|
+
end
|
11
|
+
|
12
|
+
def create_product(_route, _method_url, params, _headers)
|
13
|
+
params[:id] ||= new_id('prod')
|
14
|
+
validate_create_product_params(params)
|
15
|
+
products[params[:id]] = Data.mock_product(params)
|
16
|
+
end
|
17
|
+
|
18
|
+
def retrieve_product(route, method_url, _params, _headers)
|
19
|
+
id = method_url.match(route).captures.first
|
20
|
+
assert_existence :product, id, products[id]
|
21
|
+
end
|
22
|
+
|
23
|
+
def update_product(route, method_url, params, _headers)
|
24
|
+
id = method_url.match(route).captures.first
|
25
|
+
product = assert_existence :product, id, products[id]
|
26
|
+
|
27
|
+
product.merge!(params)
|
28
|
+
end
|
29
|
+
|
30
|
+
def list_products(_route, _method_url, params, _headers)
|
31
|
+
limit = params[:limit] || 10
|
32
|
+
Data.mock_list_object(products.values.take(limit), params)
|
33
|
+
end
|
34
|
+
|
35
|
+
def destroy_product(route, method_url, _params, _headers)
|
36
|
+
id = method_url.match(route).captures.first
|
37
|
+
assert_existence :product, id, products[id]
|
38
|
+
|
39
|
+
products.delete(id)
|
40
|
+
{ id: id, object: 'product', deleted: true }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -10,9 +10,12 @@ module StripeMock
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def new_refund(route, method_url, params, headers)
|
13
|
-
if
|
14
|
-
|
15
|
-
|
13
|
+
if headers && headers[:idempotency_key]
|
14
|
+
params[:idempotency_key] = headers[:idempotency_key]
|
15
|
+
if refunds.any?
|
16
|
+
original_refund = refunds.values.find { |c| c[:idempotency_key] == headers[:idempotency_key]}
|
17
|
+
return refunds[original_refund[:id]] if original_refund
|
18
|
+
end
|
16
19
|
end
|
17
20
|
|
18
21
|
charge = assert_existence :charge, params[:charge], charges[params[:charge]]
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module StripeMock
|
2
|
+
module RequestHandlers
|
3
|
+
module SetupIntents
|
4
|
+
ALLOWED_PARAMS = [
|
5
|
+
:confirm,
|
6
|
+
:customer,
|
7
|
+
:description,
|
8
|
+
:metadata,
|
9
|
+
:on_behalf_of,
|
10
|
+
:payment_method,
|
11
|
+
:payment_method_options,
|
12
|
+
:payment_method_types,
|
13
|
+
:return_url,
|
14
|
+
:usage
|
15
|
+
]
|
16
|
+
|
17
|
+
def SetupIntents.included(klass)
|
18
|
+
klass.add_handler 'post /v1/setup_intents', :new_setup_intent
|
19
|
+
klass.add_handler 'get /v1/setup_intents', :get_setup_intents
|
20
|
+
klass.add_handler 'get /v1/setup_intents/(.*)', :get_setup_intent
|
21
|
+
klass.add_handler 'post /v1/setup_intents/(.*)/confirm', :confirm_setup_intent
|
22
|
+
klass.add_handler 'post /v1/setup_intents/(.*)/cancel', :cancel_setup_intent
|
23
|
+
klass.add_handler 'post /v1/setup_intents/(.*)', :update_setup_intent
|
24
|
+
end
|
25
|
+
|
26
|
+
def new_setup_intent(route, method_url, params, headers)
|
27
|
+
id = new_id('si')
|
28
|
+
|
29
|
+
setup_intents[id] = Data.mock_setup_intent(
|
30
|
+
params.merge(
|
31
|
+
id: id
|
32
|
+
)
|
33
|
+
)
|
34
|
+
|
35
|
+
setup_intents[id].clone
|
36
|
+
end
|
37
|
+
|
38
|
+
def update_setup_intent(route, method_url, params, headers)
|
39
|
+
route =~ method_url
|
40
|
+
id = $1
|
41
|
+
|
42
|
+
setup_intent = assert_existence :setup_intent, id, setup_intents[id]
|
43
|
+
setup_intents[id] = Util.rmerge(setup_intent, params.select{ |k,v| ALLOWED_PARAMS.include?(k)})
|
44
|
+
end
|
45
|
+
|
46
|
+
def get_setup_intents(route, method_url, params, headers)
|
47
|
+
params[:offset] ||= 0
|
48
|
+
params[:limit] ||= 10
|
49
|
+
|
50
|
+
clone = setup_intents.clone
|
51
|
+
|
52
|
+
if params[:customer]
|
53
|
+
clone.delete_if { |k,v| v[:customer] != params[:customer] }
|
54
|
+
end
|
55
|
+
|
56
|
+
Data.mock_list_object(clone.values, params)
|
57
|
+
end
|
58
|
+
|
59
|
+
def get_setup_intent(route, method_url, params, headers)
|
60
|
+
route =~ method_url
|
61
|
+
setup_intent_id = $1 || params[:setup_intent]
|
62
|
+
setup_intent = assert_existence :setup_intent, setup_intent_id, setup_intents[setup_intent_id]
|
63
|
+
|
64
|
+
setup_intent = setup_intent.clone
|
65
|
+
setup_intent
|
66
|
+
end
|
67
|
+
|
68
|
+
def capture_setup_intent(route, method_url, params, headers)
|
69
|
+
route =~ method_url
|
70
|
+
setup_intent = assert_existence :setup_intent, $1, setup_intents[$1]
|
71
|
+
|
72
|
+
setup_intent[:status] = 'succeeded'
|
73
|
+
setup_intent
|
74
|
+
end
|
75
|
+
|
76
|
+
def confirm_setup_intent(route, method_url, params, headers)
|
77
|
+
route =~ method_url
|
78
|
+
setup_intent = assert_existence :setup_intent, $1, setup_intents[$1]
|
79
|
+
|
80
|
+
setup_intent[:status] = 'succeeded'
|
81
|
+
setup_intent
|
82
|
+
end
|
83
|
+
|
84
|
+
def cancel_setup_intent(route, method_url, params, headers)
|
85
|
+
route =~ method_url
|
86
|
+
setup_intent = assert_existence :setup_intent, $1, setup_intents[$1]
|
87
|
+
|
88
|
+
setup_intent[:status] = 'canceled'
|
89
|
+
setup_intent
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -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
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module StripeMock
|
2
|
+
module RequestHandlers
|
3
|
+
module SubscriptionItems
|
4
|
+
|
5
|
+
def SubscriptionItems.included(klass)
|
6
|
+
klass.add_handler 'get /v1/subscription_items', :retrieve_subscription_items
|
7
|
+
klass.add_handler 'post /v1/subscription_items/([^/]*)', :update_subscription_item
|
8
|
+
klass.add_handler 'post /v1/subscription_items', :create_subscription_items
|
9
|
+
end
|
10
|
+
|
11
|
+
def retrieve_subscription_items(route, method_url, params, headers)
|
12
|
+
route =~ method_url
|
13
|
+
|
14
|
+
require_param(:subscription) unless params[:subscription]
|
15
|
+
|
16
|
+
Data.mock_list_object(subscriptions_items, params)
|
17
|
+
end
|
18
|
+
|
19
|
+
def create_subscription_items(route, method_url, params, headers)
|
20
|
+
params[:id] ||= new_id('si')
|
21
|
+
|
22
|
+
require_param(:subscription) unless params[:subscription]
|
23
|
+
require_param(:plan) unless params[:plan]
|
24
|
+
|
25
|
+
subscriptions_items[params[:id]] = Data.mock_subscription_item(params.merge(plan: plans[params[:plan]]))
|
26
|
+
end
|
27
|
+
|
28
|
+
def update_subscription_item(route, method_url, params, headers)
|
29
|
+
route =~ method_url
|
30
|
+
|
31
|
+
subscription_item = assert_existence :subscription_item, $1, subscriptions_items[$1]
|
32
|
+
subscription_item.merge!(params.merge(plan: plans[params[:plan]]))
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -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))
|
@@ -60,7 +63,7 @@ module StripeMock
|
|
60
63
|
coupon = coupons[coupon_id]
|
61
64
|
|
62
65
|
if coupon
|
63
|
-
subscription
|
66
|
+
add_coupon_to_object(subscription, coupon)
|
64
67
|
else
|
65
68
|
raise Stripe::InvalidRequestError.new("No such coupon: #{coupon_id}", 'coupon', http_status: 400)
|
66
69
|
end
|
@@ -73,21 +76,20 @@ 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
|
80
|
+
if headers && headers[:idempotency_key]
|
81
|
+
if subscriptions.any?
|
82
|
+
original_subscription = subscriptions.values.find { |c| c[:idempotency_key] == headers[:idempotency_key]}
|
83
|
+
return subscriptions[original_subscription[:id]] if original_subscription
|
84
|
+
end
|
85
|
+
end
|
76
86
|
route =~ method_url
|
77
87
|
|
78
88
|
subscription_plans = get_subscription_plans_from_params(params)
|
79
89
|
|
80
90
|
customer = params[:customer]
|
81
91
|
customer_id = customer.is_a?(Stripe::Customer) ? customer[:id] : customer.to_s
|
82
|
-
customer = assert_existence :customer, customer_id, customers[customer_id]
|
83
|
-
|
84
|
-
if subscription_plans && customer
|
85
|
-
subscription_plans.each do |plan|
|
86
|
-
unless customer[:currency].to_s == plan[:currency].to_s
|
87
|
-
raise Stripe::InvalidRequestError.new("Customer's currency of #{customer[:currency]} does not match plan's currency of #{plan[:currency]}", 'currency', http_status: 400)
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
92
|
+
customer = assert_existence :customer, customer_id, customers[stripe_account][customer_id]
|
91
93
|
|
92
94
|
if params[:source]
|
93
95
|
new_card = get_card_by_token(params.delete(:source))
|
@@ -95,7 +97,7 @@ module StripeMock
|
|
95
97
|
customer[:default_source] = new_card[:id]
|
96
98
|
end
|
97
99
|
|
98
|
-
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)
|
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)
|
99
101
|
unknown_params = params.keys - allowed_params.map(&:to_sym)
|
100
102
|
if unknown_params.length > 0
|
101
103
|
raise Stripe::InvalidRequestError.new("Received unknown parameter: #{unknown_params.join}", unknown_params.first.to_s, http_status: 400)
|
@@ -103,6 +105,9 @@ module StripeMock
|
|
103
105
|
|
104
106
|
subscription = Data.mock_subscription({ id: (params[:id] || new_id('su')) })
|
105
107
|
subscription = resolve_subscription_changes(subscription, subscription_plans, customer, params)
|
108
|
+
if headers[:idempotency_key]
|
109
|
+
subscription[:idempotency_key] = headers[:idempotency_key]
|
110
|
+
end
|
106
111
|
|
107
112
|
# Ensure customer has card to charge if plan has no trial and is not free
|
108
113
|
# Note: needs updating for subscriptions with multiple plans
|
@@ -117,12 +122,21 @@ module StripeMock
|
|
117
122
|
coupon = coupons[coupon_id]
|
118
123
|
|
119
124
|
if coupon
|
120
|
-
subscription
|
125
|
+
add_coupon_to_object(subscription, coupon)
|
121
126
|
else
|
122
127
|
raise Stripe::InvalidRequestError.new("No such coupon: #{coupon_id}", 'coupon', http_status: 400)
|
123
128
|
end
|
124
129
|
end
|
125
130
|
|
131
|
+
if params[:trial_period_days]
|
132
|
+
subscription[:status] = 'trialing'
|
133
|
+
end
|
134
|
+
|
135
|
+
if params[:cancel_at_period_end]
|
136
|
+
subscription[:cancel_at_period_end] = true
|
137
|
+
subscription[:canceled_at] = Time.now.utc.to_i
|
138
|
+
end
|
139
|
+
|
126
140
|
subscriptions[subscription[:id]] = subscription
|
127
141
|
add_subscription_to_customer(customer, subscription)
|
128
142
|
|
@@ -136,14 +150,16 @@ module StripeMock
|
|
136
150
|
end
|
137
151
|
|
138
152
|
def retrieve_subscriptions(route, method_url, params, headers)
|
153
|
+
# stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
139
154
|
route =~ method_url
|
140
155
|
|
141
156
|
Data.mock_list_object(subscriptions.values, params)
|
142
|
-
#customer = assert_existence :customer, $1, customers[$1]
|
157
|
+
#customer = assert_existence :customer, $1, customers[stripe_account][$1]
|
143
158
|
#customer[:subscriptions]
|
144
159
|
end
|
145
160
|
|
146
161
|
def update_subscription(route, method_url, params, headers)
|
162
|
+
stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
147
163
|
route =~ method_url
|
148
164
|
|
149
165
|
subscription_id = $2 ? $2 : $1
|
@@ -151,7 +167,7 @@ module StripeMock
|
|
151
167
|
verify_active_status(subscription)
|
152
168
|
|
153
169
|
customer_id = subscription[:customer]
|
154
|
-
customer = assert_existence :customer, customer_id, customers[customer_id]
|
170
|
+
customer = assert_existence :customer, customer_id, customers[stripe_account][customer_id]
|
155
171
|
|
156
172
|
if params[:source]
|
157
173
|
new_card = get_card_by_token(params.delete(:source))
|
@@ -174,23 +190,35 @@ module StripeMock
|
|
174
190
|
|
175
191
|
coupon = coupons[coupon_id]
|
176
192
|
if coupon
|
177
|
-
subscription
|
193
|
+
add_coupon_to_object(subscription, coupon)
|
178
194
|
elsif coupon_id == ""
|
179
|
-
subscription[:discount] =
|
195
|
+
subscription[:discount] = nil
|
180
196
|
else
|
181
197
|
raise Stripe::InvalidRequestError.new("No such coupon: #{coupon_id}", 'coupon', http_status: 400)
|
182
198
|
end
|
183
199
|
end
|
184
|
-
verify_card_present(customer, subscription_plans.first, subscription)
|
185
200
|
|
186
|
-
if
|
201
|
+
if params[:trial_period_days]
|
202
|
+
subscription[:status] = 'trialing'
|
203
|
+
end
|
204
|
+
|
205
|
+
if params[:cancel_at_period_end]
|
206
|
+
subscription[:cancel_at_period_end] = true
|
207
|
+
subscription[:canceled_at] = Time.now.utc.to_i
|
208
|
+
elsif params.has_key?(:cancel_at_period_end)
|
187
209
|
subscription[:cancel_at_period_end] = false
|
188
210
|
subscription[:canceled_at] = nil
|
189
211
|
end
|
190
212
|
|
191
213
|
params[:current_period_start] = subscription[:current_period_start]
|
214
|
+
params[:trial_end] = params[:trial_end] || subscription[:trial_end]
|
215
|
+
|
216
|
+
plan_amount_was = subscription.dig(:plan, :amount)
|
217
|
+
|
192
218
|
subscription = resolve_subscription_changes(subscription, subscription_plans, customer, params)
|
193
219
|
|
220
|
+
verify_card_present(customer, subscription_plans.first, subscription, params) if plan_amount_was == 0 && subscription.dig(:plan, :amount) && subscription.dig(:plan, :amount) > 0
|
221
|
+
|
194
222
|
# delete the old subscription, replace with the new subscription
|
195
223
|
customer[:subscriptions][:data].reject! { |sub| sub[:id] == subscription[:id] }
|
196
224
|
customer[:subscriptions][:data] << subscription
|
@@ -199,13 +227,14 @@ module StripeMock
|
|
199
227
|
end
|
200
228
|
|
201
229
|
def cancel_subscription(route, method_url, params, headers)
|
230
|
+
stripe_account = headers && headers[:stripe_account] || Stripe.api_key
|
202
231
|
route =~ method_url
|
203
232
|
|
204
233
|
subscription_id = $2 ? $2 : $1
|
205
234
|
subscription = assert_existence :subscription, subscription_id, subscriptions[subscription_id]
|
206
235
|
|
207
236
|
customer_id = subscription[:customer]
|
208
|
-
customer = assert_existence :customer, customer_id, customers[customer_id]
|
237
|
+
customer = assert_existence :customer, customer_id, customers[stripe_account][customer_id]
|
209
238
|
|
210
239
|
cancel_params = { canceled_at: Time.now.utc.to_i }
|
211
240
|
cancelled_at_period_end = (params[:at_period_end] == true)
|
@@ -234,36 +263,48 @@ module StripeMock
|
|
234
263
|
elsif params[:items]
|
235
264
|
items = params[:items]
|
236
265
|
items = items.values if items.respond_to?(:values)
|
237
|
-
items.map { |item| item[:plan]
|
266
|
+
items.map { |item| item[:plan] ? item[:plan] : item[:price] }
|
238
267
|
else
|
239
268
|
[]
|
240
269
|
end
|
270
|
+
plan_ids.compact!
|
241
271
|
plan_ids.each do |plan_id|
|
242
272
|
assert_existence :plan, plan_id, plans[plan_id]
|
273
|
+
rescue Stripe::InvalidRequestError
|
274
|
+
assert_existence :price, plan_id, prices[plan_id]
|
243
275
|
end
|
244
|
-
plan_ids.map { |plan_id| plans[plan_id] }
|
276
|
+
plan_ids.map { |plan_id| plans[plan_id] || prices[plan_id]}
|
245
277
|
end
|
246
278
|
|
279
|
+
# Ensure customer has card to charge unless one of the following criterias is met:
|
280
|
+
# 1) is in trial
|
281
|
+
# 2) is free
|
282
|
+
# 3) has billing set to send invoice
|
247
283
|
def verify_card_present(customer, plan, subscription, params={})
|
248
|
-
if customer[:default_source]
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
284
|
+
return if customer[:default_source]
|
285
|
+
return if customer[:invoice_settings][:default_payment_method]
|
286
|
+
return if customer[:trial_end]
|
287
|
+
return if params[:trial_end]
|
288
|
+
return if subscription[:default_payment_method]
|
289
|
+
|
290
|
+
plan_trial_period_days = plan[:trial_period_days] || 0
|
291
|
+
plan_has_trial = plan_trial_period_days != 0 || plan[:amount] == 0 || plan[:trial_end]
|
292
|
+
return if plan && plan_has_trial
|
293
|
+
|
294
|
+
return if subscription && subscription[:trial_end] && subscription[:trial_end] != 'now'
|
295
|
+
|
296
|
+
if subscription[:items]
|
297
|
+
trial = subscription[:items][:data].none? do |item|
|
298
|
+
plan = item[:plan]
|
299
|
+
(plan[:trial_period_days].nil? || plan[:trial_period_days] == 0) &&
|
300
|
+
(plan[:trial_end].nil? || plan[:trial_end] == 'now')
|
263
301
|
end
|
264
|
-
|
265
|
-
raise Stripe::InvalidRequestError.new('You must supply a valid card xoxo', nil, http_status: 400)
|
302
|
+
return if trial
|
266
303
|
end
|
304
|
+
|
305
|
+
return if params[:billing] == 'send_invoice'
|
306
|
+
|
307
|
+
raise Stripe::InvalidRequestError.new('This customer has no attached payment source', nil, http_status: 400)
|
267
308
|
end
|
268
309
|
|
269
310
|
def verify_active_status(subscription)
|