stripe-ruby-mock 2.5.8 → 3.1.0.rc3

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.
Files changed (90) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -1
  3. data/.travis.yml +6 -9
  4. data/CHANGELOG.md +41 -0
  5. data/Gemfile +1 -0
  6. data/README.md +17 -11
  7. data/lib/stripe_mock.rb +8 -0
  8. data/lib/stripe_mock/api/client.rb +1 -1
  9. data/lib/stripe_mock/api/errors.rb +34 -28
  10. data/lib/stripe_mock/api/instance.rb +1 -1
  11. data/lib/stripe_mock/api/webhooks.rb +5 -0
  12. data/lib/stripe_mock/client.rb +2 -1
  13. data/lib/stripe_mock/data.rb +285 -16
  14. data/lib/stripe_mock/data/list.rb +42 -9
  15. data/lib/stripe_mock/instance.rb +18 -4
  16. data/lib/stripe_mock/request_handlers/account_links.rb +15 -0
  17. data/lib/stripe_mock/request_handlers/balance_transactions.rb +2 -2
  18. data/lib/stripe_mock/request_handlers/charges.rb +6 -4
  19. data/lib/stripe_mock/request_handlers/checkout.rb +15 -0
  20. data/lib/stripe_mock/request_handlers/checkout_session.rb +22 -0
  21. data/lib/stripe_mock/request_handlers/customers.rb +35 -18
  22. data/lib/stripe_mock/request_handlers/ephemeral_key.rb +1 -1
  23. data/lib/stripe_mock/request_handlers/express_login_links.rb +15 -0
  24. data/lib/stripe_mock/request_handlers/helpers/coupon_helpers.rb +5 -0
  25. data/lib/stripe_mock/request_handlers/helpers/subscription_helpers.rb +12 -7
  26. data/lib/stripe_mock/request_handlers/helpers/token_helpers.rb +1 -1
  27. data/lib/stripe_mock/request_handlers/invoices.rb +10 -4
  28. data/lib/stripe_mock/request_handlers/payment_intents.rb +182 -0
  29. data/lib/stripe_mock/request_handlers/payment_methods.rb +120 -0
  30. data/lib/stripe_mock/request_handlers/plans.rb +1 -1
  31. data/lib/stripe_mock/request_handlers/prices.rb +44 -0
  32. data/lib/stripe_mock/request_handlers/products.rb +1 -0
  33. data/lib/stripe_mock/request_handlers/setup_intents.rb +93 -0
  34. data/lib/stripe_mock/request_handlers/sources.rb +12 -6
  35. data/lib/stripe_mock/request_handlers/subscriptions.rb +45 -22
  36. data/lib/stripe_mock/request_handlers/tokens.rb +6 -4
  37. data/lib/stripe_mock/request_handlers/validators/param_validators.rb +123 -9
  38. data/lib/stripe_mock/server.rb +2 -2
  39. data/lib/stripe_mock/test_strategies/base.rb +67 -8
  40. data/lib/stripe_mock/test_strategies/live.rb +23 -12
  41. data/lib/stripe_mock/test_strategies/mock.rb +6 -2
  42. data/lib/stripe_mock/version.rb +1 -1
  43. data/lib/stripe_mock/webhook_fixtures/balance.available.json +6 -0
  44. data/lib/stripe_mock/webhook_fixtures/charge.failed.json +166 -38
  45. data/lib/stripe_mock/webhook_fixtures/customer.created.json +1 -0
  46. data/lib/stripe_mock/webhook_fixtures/customer.updated.json +1 -0
  47. data/lib/stripe_mock/webhook_fixtures/payment_intent.payment_failed.json +186 -0
  48. data/lib/stripe_mock/webhook_fixtures/payment_intent.succeeded.json +164 -0
  49. data/lib/stripe_mock/webhook_fixtures/product.created.json +34 -0
  50. data/lib/stripe_mock/webhook_fixtures/product.deleted.json +34 -0
  51. data/lib/stripe_mock/webhook_fixtures/product.updated.json +38 -0
  52. data/spec/instance_spec.rb +10 -12
  53. data/spec/list_spec.rb +38 -0
  54. data/spec/server_spec.rb +6 -3
  55. data/spec/shared_stripe_examples/account_examples.rb +1 -1
  56. data/spec/shared_stripe_examples/account_link_examples.rb +16 -0
  57. data/spec/shared_stripe_examples/balance_examples.rb +6 -0
  58. data/spec/shared_stripe_examples/balance_transaction_examples.rb +3 -3
  59. data/spec/shared_stripe_examples/bank_examples.rb +3 -3
  60. data/spec/shared_stripe_examples/card_examples.rb +4 -4
  61. data/spec/shared_stripe_examples/card_token_examples.rb +17 -21
  62. data/spec/shared_stripe_examples/charge_examples.rb +9 -22
  63. data/spec/shared_stripe_examples/checkout_examples.rb +47 -0
  64. data/spec/shared_stripe_examples/coupon_examples.rb +1 -1
  65. data/spec/shared_stripe_examples/customer_examples.rb +93 -53
  66. data/spec/shared_stripe_examples/dispute_examples.rb +2 -2
  67. data/spec/shared_stripe_examples/error_mock_examples.rb +8 -7
  68. data/spec/shared_stripe_examples/express_login_link_examples.rb +12 -0
  69. data/spec/shared_stripe_examples/external_account_examples.rb +3 -3
  70. data/spec/shared_stripe_examples/invoice_examples.rb +41 -39
  71. data/spec/shared_stripe_examples/invoice_item_examples.rb +1 -1
  72. data/spec/shared_stripe_examples/payment_intent_examples.rb +147 -0
  73. data/spec/shared_stripe_examples/payment_method_examples.rb +449 -0
  74. data/spec/shared_stripe_examples/payout_examples.rb +2 -2
  75. data/spec/shared_stripe_examples/plan_examples.rb +135 -92
  76. data/spec/shared_stripe_examples/price_examples.rb +183 -0
  77. data/spec/shared_stripe_examples/product_examples.rb +147 -0
  78. data/spec/shared_stripe_examples/refund_examples.rb +25 -21
  79. data/spec/shared_stripe_examples/setup_intent_examples.rb +68 -0
  80. data/spec/shared_stripe_examples/subscription_examples.rb +430 -318
  81. data/spec/shared_stripe_examples/subscription_items_examples.rb +3 -2
  82. data/spec/shared_stripe_examples/transfer_examples.rb +6 -6
  83. data/spec/shared_stripe_examples/webhook_event_examples.rb +11 -11
  84. data/spec/spec_helper.rb +7 -4
  85. data/spec/stripe_mock_spec.rb +4 -4
  86. data/spec/support/shared_contexts/stripe_validator_spec.rb +8 -0
  87. data/spec/support/stripe_examples.rb +9 -1
  88. data/stripe-ruby-mock.gemspec +8 -3
  89. metadata +72 -34
  90. data/spec/shared_stripe_examples/product_example.rb +0 -65
@@ -1,19 +1,17 @@
1
1
  module StripeMock
2
2
  module Data
3
3
  class List
4
- attr_reader :data, :limit, :offset, :starting_after, :ending_before
4
+ attr_reader :data, :limit, :offset, :starting_after, :ending_before, :active
5
5
 
6
6
  def initialize(data, options = {})
7
7
  @data = Array(data.clone)
8
8
  @limit = [[options[:limit] || 10, 100].min, 1].max # restrict @limit to 1..100
9
9
  @starting_after = options[:starting_after]
10
10
  @ending_before = options[:ending_before]
11
- if @data.first.is_a?(Hash) && @data.first[:created]
12
- @data.sort_by! { |x| x[:created] }
13
- @data.reverse!
14
- elsif @data.first.respond_to?(:created)
15
- @data.sort_by { |x| x.created }
16
- @data.reverse!
11
+ @active = options[:active]
12
+ if contains_stripe_objects?
13
+ prune_deleted_data
14
+ sort_data
17
15
  end
18
16
  end
19
17
 
@@ -53,14 +51,21 @@ module StripeMock
53
51
  (index || raise("No such object id: #{starting_after}")) + 1
54
52
  when ending_before
55
53
  index = data.index { |datum| datum[:id] == ending_before }
56
- (index || raise("No such object id: #{ending_before}")) - 1
54
+ (index || raise("No such object id: #{ending_before}")) - 1
57
55
  else
58
56
  0
59
57
  end
60
58
  end
61
59
 
62
60
  def data_page
63
- data[offset, limit]
61
+ filtered_data[offset, limit]
62
+ end
63
+
64
+ def filtered_data
65
+ filtered_data = data
66
+ filtered_data = filtered_data.select { |d| d[:active] == active } unless active.nil?
67
+
68
+ filtered_data
64
69
  end
65
70
 
66
71
  def object_types
@@ -68,6 +73,34 @@ module StripeMock
68
73
  "#{first_object.class.to_s.split('::')[-1].downcase}s"
69
74
  end
70
75
  end
76
+
77
+ def contains_stripe_objects?
78
+ return false if data.empty?
79
+
80
+ object = data.first
81
+ object.is_a?(Stripe::StripeObject) || (
82
+ object.is_a?(Hash) && [:created, :deleted].any? { |k| object.key?(k) }
83
+ )
84
+ end
85
+
86
+ def prune_deleted_data
87
+ data.reject! do |object|
88
+ (object.is_a?(Hash) && object[:deleted]) ||
89
+ (object.is_a?(Stripe::StripeObject) && object.deleted?)
90
+ end
91
+ end
92
+
93
+ def sort_data
94
+ # Reverse must follow sort to preserve existing test dependencies. The
95
+ # alternative would be to simply reverse lhs and rhs in the comparison,
96
+ # however, being a stable sort this breaks the existing dependency when
97
+ # more than one record share the same `created` value.
98
+ @data = data.sort { |lhs, rhs| sort_val(lhs) <=> sort_val(rhs) }.reverse
99
+ end
100
+
101
+ def sort_val(object)
102
+ object.is_a?(Stripe::StripeObject) ? object.created : object[:created]
103
+ end
71
104
  end
72
105
  end
73
106
  end
@@ -20,7 +20,12 @@ module StripeMock
20
20
  @@handlers.find {|h| method_url =~ h[:route] }
21
21
  end
22
22
 
23
+ include StripeMock::RequestHandlers::PaymentIntents
24
+ include StripeMock::RequestHandlers::PaymentMethods
25
+ include StripeMock::RequestHandlers::SetupIntents
23
26
  include StripeMock::RequestHandlers::ExternalAccounts
27
+ include StripeMock::RequestHandlers::AccountLinks
28
+ include StripeMock::RequestHandlers::ExpressLoginLinks
24
29
  include StripeMock::RequestHandlers::Accounts
25
30
  include StripeMock::RequestHandlers::Balance
26
31
  include StripeMock::RequestHandlers::BalanceTransactions
@@ -37,6 +42,7 @@ module StripeMock
37
42
  include StripeMock::RequestHandlers::InvoiceItems
38
43
  include StripeMock::RequestHandlers::Orders
39
44
  include StripeMock::RequestHandlers::Plans
45
+ include StripeMock::RequestHandlers::Prices
40
46
  include StripeMock::RequestHandlers::Products
41
47
  include StripeMock::RequestHandlers::Refunds
42
48
  include StripeMock::RequestHandlers::Recipients
@@ -46,11 +52,13 @@ module StripeMock
46
52
  include StripeMock::RequestHandlers::Payouts
47
53
  include StripeMock::RequestHandlers::EphemeralKey
48
54
  include StripeMock::RequestHandlers::TaxRates
55
+ include StripeMock::RequestHandlers::Checkout
56
+ include StripeMock::RequestHandlers::Checkout::Session
49
57
 
50
58
  attr_reader :accounts, :balance, :balance_transactions, :bank_tokens, :charges, :coupons, :customers,
51
- :disputes, :events, :invoices, :invoice_items, :orders, :plans, :recipients,
52
- :refunds, :transfers, :payouts, :subscriptions, :country_spec, :subscriptions_items,
53
- :products, :tax_rates
59
+ :disputes, :events, :invoices, :invoice_items, :orders, :payment_intents, :payment_methods,
60
+ :setup_intents, :plans, :prices, :recipients, :refunds, :transfers, :payouts, :subscriptions, :country_spec,
61
+ :subscriptions_items, :products, :tax_rates, :checkout_sessions
54
62
 
55
63
  attr_accessor :error_queue, :debug, :conversion_rate, :account_balance
56
64
 
@@ -60,15 +68,20 @@ module StripeMock
60
68
  @balance_transactions = Data.mock_balance_transactions(['txn_05RsQX2eZvKYlo2C0FRTGSSA','txn_15RsQX2eZvKYlo2C0ERTYUIA', 'txn_25RsQX2eZvKYlo2C0ZXCVBNM', 'txn_35RsQX2eZvKYlo2C0QAZXSWE', 'txn_45RsQX2eZvKYlo2C0EDCVFRT', 'txn_55RsQX2eZvKYlo2C0OIKLJUY', 'txn_65RsQX2eZvKYlo2C0ASDFGHJ', 'txn_75RsQX2eZvKYlo2C0EDCXSWQ', 'txn_85RsQX2eZvKYlo2C0UJMCDET', 'txn_95RsQX2eZvKYlo2C0EDFRYUI'])
61
69
  @bank_tokens = {}
62
70
  @card_tokens = {}
63
- @customers = {}
71
+ @customers = { Stripe.api_key => {} }
64
72
  @charges = {}
73
+ @payment_intents = {}
74
+ @payment_methods = {}
75
+ @setup_intents = {}
65
76
  @coupons = {}
66
77
  @disputes = Data.mock_disputes(['dp_05RsQX2eZvKYlo2C0FRTGSSA','dp_15RsQX2eZvKYlo2C0ERTYUIA', 'dp_25RsQX2eZvKYlo2C0ZXCVBNM', 'dp_35RsQX2eZvKYlo2C0QAZXSWE', 'dp_45RsQX2eZvKYlo2C0EDCVFRT', 'dp_55RsQX2eZvKYlo2C0OIKLJUY', 'dp_65RsQX2eZvKYlo2C0ASDFGHJ', 'dp_75RsQX2eZvKYlo2C0EDCXSWQ', 'dp_85RsQX2eZvKYlo2C0UJMCDET', 'dp_95RsQX2eZvKYlo2C0EDFRYUI'])
67
78
  @events = {}
68
79
  @invoices = {}
69
80
  @invoice_items = {}
70
81
  @orders = {}
82
+ @payment_methods = {}
71
83
  @plans = {}
84
+ @prices = {}
72
85
  @products = {}
73
86
  @recipients = {}
74
87
  @refunds = {}
@@ -78,6 +91,7 @@ module StripeMock
78
91
  @subscriptions_items = {}
79
92
  @country_spec = {}
80
93
  @tax_rates = {}
94
+ @checkout_sessions = {}
81
95
 
82
96
  @debug = false
83
97
  @error_queue = ErrorQueue.new
@@ -0,0 +1,15 @@
1
+ module StripeMock
2
+ module RequestHandlers
3
+ module AccountLinks
4
+
5
+ def AccountLinks.included(klass)
6
+ klass.add_handler 'post /v1/account_links', :new_account_link
7
+ end
8
+
9
+ def new_account_link(route, method_url, params, headers)
10
+ route =~ method_url
11
+ Data.mock_account_link(params)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -3,8 +3,8 @@ module StripeMock
3
3
  module BalanceTransactions
4
4
 
5
5
  def BalanceTransactions.included(klass)
6
- klass.add_handler 'get /v1/balance/history/(.*)', :get_balance_transaction
7
- klass.add_handler 'get /v1/balance/history', :list_balance_transactions
6
+ klass.add_handler 'get /v1/balance_transactions/(.*)', :get_balance_transaction
7
+ klass.add_handler 'get /v1/balance_transactions', :list_balance_transactions
8
8
  end
9
9
 
10
10
  def get_balance_transaction(route, method_url, params, headers)
@@ -12,7 +12,9 @@ module StripeMock
12
12
  klass.add_handler 'post /v1/charges/(.*)', :update_charge
13
13
  end
14
14
 
15
- def new_charge(route, method_url, params, headers)
15
+ def new_charge(route, method_url, params, headers = {})
16
+ stripe_account = headers && headers[:stripe_account] || Stripe.api_key
17
+
16
18
  if headers && headers[:idempotency_key]
17
19
  params[:idempotency_key] = headers[:idempotency_key]
18
20
  if charges.any?
@@ -29,7 +31,7 @@ module StripeMock
29
31
  # card id, not a token. in this case we'll find the card in the customer
30
32
  # object and return that.
31
33
  if params[:customer]
32
- params[:source] = get_card(customers[params[:customer]], params[:source])
34
+ params[:source] = get_card(customers[stripe_account][params[:customer]], params[:source])
33
35
  else
34
36
  params[:source] = get_card_or_bank_by_token(params[:source])
35
37
  end
@@ -37,7 +39,7 @@ module StripeMock
37
39
  raise Stripe::InvalidRequestError.new("Invalid token id: #{params[:source]}", 'card', http_status: 400)
38
40
  end
39
41
  elsif params[:customer]
40
- customer = customers[params[:customer]]
42
+ customer = customers[stripe_account][params[:customer]]
41
43
  if customer && customer[:default_source]
42
44
  params[:source] = get_card(customer, customer[:default_source])
43
45
  end
@@ -146,7 +148,7 @@ module StripeMock
146
148
  elsif non_positive_charge_amount?(params)
147
149
  raise Stripe::InvalidRequestError.new('Invalid positive integer', 'amount', http_status: 400)
148
150
  elsif params[:source].nil? && params[:customer].nil?
149
- raise Stripe::InvalidRequestError.new('Must provide source or customer.', http_status: nil)
151
+ raise Stripe::InvalidRequestError.new('Must provide source or customer.', nil, http_status: nil)
150
152
  end
151
153
  end
152
154
 
@@ -0,0 +1,15 @@
1
+ module StripeMock
2
+ module RequestHandlers
3
+ module Checkout
4
+ def Checkout.included(klass)
5
+ klass.add_handler 'post /v1/checkout/sessions', :new_session
6
+ end
7
+
8
+ def new_session(route, method_url, params, headers)
9
+ params[:id] ||= new_id('cs')
10
+
11
+ checkout_sessions[params[:id]] = Data.mock_checkout_session(params)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,22 @@
1
+ module StripeMock
2
+ module RequestHandlers
3
+ module Checkout
4
+ module Session
5
+ def Session.included(klass)
6
+ klass.add_handler 'get /v1/checkout/sessions/(.*)', :get_checkout_session
7
+ end
8
+
9
+ def get_checkout_session(route, method_url, params, headers)
10
+ route =~ method_url
11
+ checkout_session = assert_existence :checkout_session, $1, checkout_sessions[$1]
12
+
13
+ checkout_session = checkout_session.clone
14
+ if params[:expand]&.include?('setup_intent') && checkout_session[:setup_intent]
15
+ checkout_session[:setup_intent] = setup_intents[checkout_session[:setup_intent]]
16
+ end
17
+ checkout_session
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -12,6 +12,7 @@ module StripeMock
12
12
  end
13
13
 
14
14
  def new_customer(route, method_url, params, headers)
15
+ stripe_account = headers && headers[:stripe_account] || Stripe.api_key
15
16
  params[:id] ||= new_id('cus')
16
17
  sources = []
17
18
 
@@ -29,7 +30,8 @@ module StripeMock
29
30
  params[:default_source] = sources.first[:id]
30
31
  end
31
32
 
32
- customers[ params[:id] ] = Data.mock_customer(sources, params)
33
+ customers[stripe_account] ||= {}
34
+ customers[stripe_account][params[:id]] = Data.mock_customer(sources, params)
33
35
 
34
36
  if params[:plan]
35
37
  plan_id = params[:plan].to_s
@@ -40,26 +42,30 @@ module StripeMock
40
42
  end
41
43
 
42
44
  subscription = Data.mock_subscription({ id: new_id('su') })
43
- subscription = resolve_subscription_changes(subscription, [plan], customers[ params[:id] ], params)
44
- add_subscription_to_customer(customers[ params[:id] ], subscription)
45
+ subscription = resolve_subscription_changes(subscription, [plan], customers[stripe_account][params[:id]], params)
46
+ add_subscription_to_customer(customers[stripe_account][params[:id]], subscription)
45
47
  subscriptions[subscription[:id]] = subscription
46
48
  elsif params[:trial_end]
47
49
  raise Stripe::InvalidRequestError.new('Received unknown parameter: trial_end', nil, http_status: 400)
48
50
  end
49
51
 
50
52
  if params[:coupon]
51
- coupon = coupons[ params[:coupon] ]
53
+ coupon = coupons[params[:coupon]]
52
54
  assert_existence :coupon, params[:coupon], coupon
53
-
54
- add_coupon_to_object(customers[params[:id]], coupon)
55
+ add_coupon_to_object(customers[stripe_account][params[:id]], coupon)
55
56
  end
56
57
 
57
- customers[ params[:id] ]
58
+ customers[stripe_account][params[:id]]
58
59
  end
59
60
 
60
61
  def update_customer(route, method_url, params, headers)
62
+ stripe_account = headers && headers[:stripe_account] || Stripe.api_key
61
63
  route =~ method_url
62
- cus = assert_existence :customer, $1, customers[$1]
64
+ cus = assert_existence :customer, $1, customers[stripe_account][$1]
65
+
66
+ # get existing and pending metadata
67
+ metadata = cus.delete(:metadata) || {}
68
+ metadata_updates = params.delete(:metadata) || {}
63
69
 
64
70
  # Delete those params if their value is nil. Workaround of the problematic way Stripe serialize objects
65
71
  params.delete(:sources) if params[:sources] && params[:sources][:data].nil?
@@ -72,10 +78,13 @@ module StripeMock
72
78
  params.delete(:subscriptions) unless params[:subscriptions][:data].any?{ |v| !!v[:type]}
73
79
  end
74
80
  cus.merge!(params)
81
+ cus[:metadata] = {**metadata, **metadata_updates}
75
82
 
76
83
  if params[:source]
77
84
  if params[:source].is_a?(String)
78
85
  new_card = get_card_or_bank_by_token(params.delete(:source))
86
+ elsif params[:source].is_a?(Stripe::Token)
87
+ new_card = get_card_or_bank_by_token(params[:source][:id])
79
88
  elsif params[:source].is_a?(Hash)
80
89
  unless params[:source][:object] && params[:source][:number] && params[:source][:exp_month] && params[:source][:exp_year]
81
90
  raise Stripe::InvalidRequestError.new('You must supply a valid card', nil, http_status: 400)
@@ -87,31 +96,37 @@ module StripeMock
87
96
  end
88
97
 
89
98
  if params[:coupon]
90
- coupon = coupons[ params[:coupon] ]
91
- assert_existence :coupon, params[:coupon], coupon
99
+ if params[:coupon] == ''
100
+ delete_coupon_from_object(cus)
101
+ else
102
+ coupon = coupons[params[:coupon]]
103
+ assert_existence :coupon, params[:coupon], coupon
92
104
 
93
- add_coupon_to_object(cus, coupon)
105
+ add_coupon_to_object(cus, coupon)
106
+ end
94
107
  end
95
108
 
96
109
  cus
97
110
  end
98
111
 
99
112
  def delete_customer(route, method_url, params, headers)
113
+ stripe_account = headers && headers[:stripe_account] || Stripe.api_key
100
114
  route =~ method_url
101
- assert_existence :customer, $1, customers[$1]
115
+ assert_existence :customer, $1, customers[stripe_account][$1]
102
116
 
103
- customers[$1] = {
104
- id: customers[$1][:id],
117
+ customers[stripe_account][$1] = {
118
+ id: customers[stripe_account][$1][:id],
105
119
  deleted: true
106
120
  }
107
121
  end
108
122
 
109
123
  def get_customer(route, method_url, params, headers)
124
+ stripe_account = headers && headers[:stripe_account] || Stripe.api_key
110
125
  route =~ method_url
111
- customer = assert_existence :customer, $1, customers[$1]
126
+ customer = assert_existence :customer, $1, customers[stripe_account][$1]
112
127
 
113
128
  customer = customer.clone
114
- if params[:expand] == ['default_source']
129
+ if params[:expand] == ['default_source'] && customer[:sources][:data]
115
130
  customer[:default_source] = customer[:sources][:data].detect do |source|
116
131
  source[:id] == customer[:default_source]
117
132
  end
@@ -121,12 +136,14 @@ module StripeMock
121
136
  end
122
137
 
123
138
  def list_customers(route, method_url, params, headers)
124
- Data.mock_list_object(customers.values, params)
139
+ stripe_account = headers && headers[:stripe_account] || Stripe.api_key
140
+ Data.mock_list_object(customers[stripe_account]&.values, params)
125
141
  end
126
142
 
127
143
  def delete_customer_discount(route, method_url, params, headers)
144
+ stripe_account = headers && headers[:stripe_account] || Stripe.api_key
128
145
  route =~ method_url
129
- cus = assert_existence :customer, $1, customers[$1]
146
+ cus = assert_existence :customer, $1, customers[stripe_account][$1]
130
147
 
131
148
  cus[:discount] = nil
132
149
 
@@ -6,7 +6,7 @@ module StripeMock
6
6
  end
7
7
 
8
8
  def create_ephemeral_key(route, method_url, params, headers)
9
- Data.mock_ephemeral_key(params)
9
+ Data.mock_ephemeral_key(**params)
10
10
  end
11
11
  end
12
12
  end
@@ -0,0 +1,15 @@
1
+ module StripeMock
2
+ module RequestHandlers
3
+ module ExpressLoginLinks
4
+
5
+ def ExpressLoginLinks.included(klass)
6
+ klass.add_handler 'post /v1/accounts/(.*)/login_links', :new_account_login_link
7
+ end
8
+
9
+ def new_account_login_link(route, method_url, params, headers)
10
+ route =~ method_url
11
+ Data.mock_express_login_link(params)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -12,6 +12,11 @@ module StripeMock
12
12
  object[:discount] = Stripe::Discount.construct_from(discount_attrs)
13
13
  object
14
14
  end
15
+
16
+ def delete_coupon_from_object(object)
17
+ object[:discount] = nil
18
+ object
19
+ end
15
20
  end
16
21
  end
17
22
  end
@@ -11,12 +11,13 @@ module StripeMock
11
11
  items = options[:items]
12
12
  items = items.values if items.respond_to?(:values)
13
13
  subscription[:items][:data] = plans.map do |plan|
14
- if items && items.size == plans.size
15
- quantity = items &&
16
- items.detect { |item| item[:plan] == plan[:id] }[:quantity] || 1
17
- Data.mock_subscription_item({ plan: plan, quantity: quantity })
14
+ matching_item = items && items.detect { |item| [item[:price], item[:plan]].include? plan[:id] }
15
+ if matching_item
16
+ quantity = matching_item[:quantity] || 1
17
+ id = matching_item[:id] || new_id('si')
18
+ Data.mock_subscription_item({ plan: plan, quantity: quantity, id: id })
18
19
  else
19
- Data.mock_subscription_item({ plan: plan })
20
+ Data.mock_subscription_item({ plan: plan, id: new_id('si') })
20
21
  end
21
22
  end
22
23
  subscription
@@ -32,7 +33,7 @@ module StripeMock
32
33
  start_time = options[:current_period_start] || now
33
34
  params = { customer: cus[:id], current_period_start: start_time, created: created_time }
34
35
  params.merge!({ :plan => (plans.size == 1 ? plans.first : nil) })
35
- keys_to_merge = /application_fee_percent|quantity|metadata|tax_percent|billing|days_until_due/
36
+ keys_to_merge = /application_fee_percent|quantity|metadata|tax_percent|billing|days_until_due|default_tax_rates|pending_invoice_item_interval|default_payment_method|collection_method/
36
37
  params.merge! options.select {|k,v| k =~ keys_to_merge}
37
38
 
38
39
  if options[:cancel_at_period_end] == true
@@ -111,7 +112,11 @@ module StripeMock
111
112
 
112
113
  def total_items_amount(items)
113
114
  total = 0
114
- items.each { |i| total += (i[:quantity] || 1) * i[:plan][:amount] }
115
+ items.each do |item|
116
+ quantity = item[:quantity] || 1
117
+ amount = item[:plan][:unit_amount] || item[:plan][:amount]
118
+ total += quantity * amount
119
+ end
115
120
  total
116
121
  end
117
122
  end