stripe-ruby-mock 2.5.6 → 3.1.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -1
  3. data/.travis.yml +6 -9
  4. data/CHANGELOG.md +35 -0
  5. data/Gemfile +1 -0
  6. data/README.md +17 -11
  7. data/lib/stripe_mock.rb +11 -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 +7 -0
  12. data/lib/stripe_mock/client.rb +2 -1
  13. data/lib/stripe_mock/data.rb +323 -13
  14. data/lib/stripe_mock/data/list.rb +42 -9
  15. data/lib/stripe_mock/instance.rb +52 -5
  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 +13 -12
  19. data/lib/stripe_mock/request_handlers/checkout.rb +15 -0
  20. data/lib/stripe_mock/request_handlers/checkout_session.rb +16 -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 +14 -10
  25. data/lib/stripe_mock/request_handlers/helpers/subscription_helpers.rb +22 -7
  26. data/lib/stripe_mock/request_handlers/helpers/token_helpers.rb +1 -1
  27. data/lib/stripe_mock/request_handlers/invoices.rb +11 -5
  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 +44 -0
  33. data/lib/stripe_mock/request_handlers/refunds.rb +6 -3
  34. data/lib/stripe_mock/request_handlers/setup_intents.rb +93 -0
  35. data/lib/stripe_mock/request_handlers/sources.rb +12 -6
  36. data/lib/stripe_mock/request_handlers/subscription_items.rb +36 -0
  37. data/lib/stripe_mock/request_handlers/subscriptions.rb +82 -41
  38. data/lib/stripe_mock/request_handlers/tax_rates.rb +36 -0
  39. data/lib/stripe_mock/request_handlers/tokens.rb +8 -6
  40. data/lib/stripe_mock/request_handlers/validators/param_validators.rb +130 -9
  41. data/lib/stripe_mock/test_strategies/base.rb +68 -8
  42. data/lib/stripe_mock/test_strategies/live.rb +23 -12
  43. data/lib/stripe_mock/test_strategies/mock.rb +6 -2
  44. data/lib/stripe_mock/version.rb +1 -1
  45. data/lib/stripe_mock/webhook_fixtures/balance.available.json +6 -0
  46. data/lib/stripe_mock/webhook_fixtures/charge.dispute.funds_reinstated.json +88 -0
  47. data/lib/stripe_mock/webhook_fixtures/charge.dispute.funds_withdrawn.json +88 -0
  48. data/lib/stripe_mock/webhook_fixtures/charge.failed.json +166 -38
  49. data/lib/stripe_mock/webhook_fixtures/customer.created.json +1 -0
  50. data/lib/stripe_mock/webhook_fixtures/customer.updated.json +1 -0
  51. data/lib/stripe_mock/webhook_fixtures/invoice.created.json +2 -1
  52. data/lib/stripe_mock/webhook_fixtures/invoice.payment_succeeded.json +1 -1
  53. data/lib/stripe_mock/webhook_fixtures/invoice.updated.json +2 -1
  54. data/lib/stripe_mock/webhook_fixtures/payment_intent.payment_failed.json +186 -0
  55. data/lib/stripe_mock/webhook_fixtures/payment_intent.succeeded.json +164 -0
  56. data/lib/stripe_mock/webhook_fixtures/product.created.json +34 -0
  57. data/lib/stripe_mock/webhook_fixtures/product.deleted.json +34 -0
  58. data/lib/stripe_mock/webhook_fixtures/product.updated.json +38 -0
  59. data/spec/instance_spec.rb +10 -12
  60. data/spec/list_spec.rb +38 -0
  61. data/spec/server_spec.rb +6 -3
  62. data/spec/shared_stripe_examples/account_examples.rb +1 -1
  63. data/spec/shared_stripe_examples/account_link_examples.rb +16 -0
  64. data/spec/shared_stripe_examples/balance_examples.rb +6 -0
  65. data/spec/shared_stripe_examples/balance_transaction_examples.rb +3 -3
  66. data/spec/shared_stripe_examples/bank_examples.rb +3 -3
  67. data/spec/shared_stripe_examples/card_examples.rb +4 -4
  68. data/spec/shared_stripe_examples/card_token_examples.rb +17 -21
  69. data/spec/shared_stripe_examples/charge_examples.rb +32 -36
  70. data/spec/shared_stripe_examples/checkout_examples.rb +38 -0
  71. data/spec/shared_stripe_examples/coupon_examples.rb +1 -1
  72. data/spec/shared_stripe_examples/customer_examples.rb +103 -53
  73. data/spec/shared_stripe_examples/dispute_examples.rb +2 -2
  74. data/spec/shared_stripe_examples/error_mock_examples.rb +8 -7
  75. data/spec/shared_stripe_examples/express_login_link_examples.rb +12 -0
  76. data/spec/shared_stripe_examples/external_account_examples.rb +3 -3
  77. data/spec/shared_stripe_examples/invoice_examples.rb +43 -41
  78. data/spec/shared_stripe_examples/invoice_item_examples.rb +1 -1
  79. data/spec/shared_stripe_examples/payment_intent_examples.rb +147 -0
  80. data/spec/shared_stripe_examples/payment_method_examples.rb +449 -0
  81. data/spec/shared_stripe_examples/payout_examples.rb +2 -2
  82. data/spec/shared_stripe_examples/plan_examples.rb +135 -77
  83. data/spec/shared_stripe_examples/price_examples.rb +183 -0
  84. data/spec/shared_stripe_examples/product_examples.rb +155 -0
  85. data/spec/shared_stripe_examples/refund_examples.rb +41 -31
  86. data/spec/shared_stripe_examples/setup_intent_examples.rb +68 -0
  87. data/spec/shared_stripe_examples/subscription_examples.rb +546 -295
  88. data/spec/shared_stripe_examples/subscription_items_examples.rb +76 -0
  89. data/spec/shared_stripe_examples/tax_rate_examples.rb +42 -0
  90. data/spec/shared_stripe_examples/transfer_examples.rb +9 -9
  91. data/spec/shared_stripe_examples/webhook_event_examples.rb +11 -11
  92. data/spec/spec_helper.rb +7 -4
  93. data/spec/stripe_mock_spec.rb +4 -4
  94. data/spec/support/shared_contexts/stripe_validator_spec.rb +8 -0
  95. data/spec/support/stripe_examples.rb +12 -2
  96. data/stripe-ruby-mock.gemspec +8 -3
  97. metadata +81 -32
@@ -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
@@ -28,6 +33,7 @@ module StripeMock
28
33
  include StripeMock::RequestHandlers::Cards
29
34
  include StripeMock::RequestHandlers::Sources
30
35
  include StripeMock::RequestHandlers::Subscriptions # must be before Customers
36
+ include StripeMock::RequestHandlers::SubscriptionItems
31
37
  include StripeMock::RequestHandlers::Customers
32
38
  include StripeMock::RequestHandlers::Coupons
33
39
  include StripeMock::RequestHandlers::Disputes
@@ -36,6 +42,8 @@ module StripeMock
36
42
  include StripeMock::RequestHandlers::InvoiceItems
37
43
  include StripeMock::RequestHandlers::Orders
38
44
  include StripeMock::RequestHandlers::Plans
45
+ include StripeMock::RequestHandlers::Prices
46
+ include StripeMock::RequestHandlers::Products
39
47
  include StripeMock::RequestHandlers::Refunds
40
48
  include StripeMock::RequestHandlers::Recipients
41
49
  include StripeMock::RequestHandlers::Transfers
@@ -43,10 +51,14 @@ module StripeMock
43
51
  include StripeMock::RequestHandlers::CountrySpec
44
52
  include StripeMock::RequestHandlers::Payouts
45
53
  include StripeMock::RequestHandlers::EphemeralKey
54
+ include StripeMock::RequestHandlers::TaxRates
55
+ include StripeMock::RequestHandlers::Checkout
56
+ include StripeMock::RequestHandlers::Checkout::Session
46
57
 
47
58
  attr_reader :accounts, :balance, :balance_transactions, :bank_tokens, :charges, :coupons, :customers,
48
- :disputes, :events, :invoices, :invoice_items, :orders, :plans, :recipients,
49
- :refunds, :transfers, :payouts, :subscriptions, :country_spec, :subscriptions_items
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
50
62
 
51
63
  attr_accessor :error_queue, :debug, :conversion_rate, :account_balance
52
64
 
@@ -56,22 +68,30 @@ module StripeMock
56
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'])
57
69
  @bank_tokens = {}
58
70
  @card_tokens = {}
59
- @customers = {}
71
+ @customers = { Stripe.api_key => {} }
60
72
  @charges = {}
73
+ @payment_intents = {}
74
+ @payment_methods = {}
75
+ @setup_intents = {}
61
76
  @coupons = {}
62
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'])
63
78
  @events = {}
64
79
  @invoices = {}
65
80
  @invoice_items = {}
66
81
  @orders = {}
82
+ @payment_methods = {}
67
83
  @plans = {}
84
+ @prices = {}
85
+ @products = {}
68
86
  @recipients = {}
69
87
  @refunds = {}
70
88
  @transfers = {}
71
89
  @payouts = {}
72
90
  @subscriptions = {}
73
- @subscriptions_items = []
91
+ @subscriptions_items = {}
74
92
  @country_spec = {}
93
+ @tax_rates = {}
94
+ @checkout_sessions = {}
75
95
 
76
96
  @debug = false
77
97
  @error_queue = ErrorQueue.new
@@ -175,7 +195,8 @@ module StripeMock
175
195
  amount = params[:amount]
176
196
  unless amount.nil?
177
197
  # Fee calculation
178
- params[:fee] ||= (30 + (amount.abs * 0.029).ceil) * (amount > 0 ? 1 : -1)
198
+ calculate_fees(params) unless params[:fee]
199
+ params[:net] = amount - params[:fee]
179
200
  params[:amount] = amount * @conversion_rate
180
201
  end
181
202
  @balance_transactions[id] = Data.mock_balance_transaction(params.merge(id: id))
@@ -196,5 +217,31 @@ module StripeMock
196
217
  response = Struct.new(:data)
197
218
  response.new(hash)
198
219
  end
220
+
221
+ def calculate_fees(params)
222
+ application_fee = params[:application_fee] || 0
223
+ params[:fee] = processing_fee(params[:amount]) + application_fee
224
+ params[:fee_details] = [
225
+ {
226
+ amount: processing_fee(params[:amount]),
227
+ application: nil,
228
+ currency: params[:currency] || StripeMock.default_currency,
229
+ description: "Stripe processing fees",
230
+ type: "stripe_fee"
231
+ }
232
+ ]
233
+ if application_fee
234
+ params[:fee_details] << {
235
+ amount: application_fee,
236
+ currency: params[:currency] || StripeMock.default_currency,
237
+ description: "Application fee",
238
+ type: "application_fee"
239
+ }
240
+ end
241
+ end
242
+
243
+ def processing_fee(amount)
244
+ (30 + (amount.abs * 0.029).ceil) * (amount > 0 ? 1 : -1)
245
+ end
199
246
  end
200
247
  end
@@ -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,10 +12,15 @@ 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)
16
- if params[:idempotency_key] && charges.any?
17
- original_charge = charges.values.find { |c| c[:idempotency_key] == params[:idempotency_key]}
18
- return charges[original_charge[:id]] if original_charge
15
+ def new_charge(route, method_url, params, headers = {})
16
+ stripe_account = headers && headers[:stripe_account] || Stripe.api_key
17
+
18
+ if headers && headers[:idempotency_key]
19
+ params[:idempotency_key] = headers[:idempotency_key]
20
+ if charges.any?
21
+ original_charge = charges.values.find { |c| c[:idempotency_key] == headers[:idempotency_key]}
22
+ return charges[original_charge[:id]] if original_charge
23
+ end
19
24
  end
20
25
 
21
26
  id = new_id('ch')
@@ -26,7 +31,7 @@ module StripeMock
26
31
  # card id, not a token. in this case we'll find the card in the customer
27
32
  # object and return that.
28
33
  if params[:customer]
29
- params[:source] = get_card(customers[params[:customer]], params[:source])
34
+ params[:source] = get_card(customers[stripe_account][params[:customer]], params[:source])
30
35
  else
31
36
  params[:source] = get_card_or_bank_by_token(params[:source])
32
37
  end
@@ -34,14 +39,14 @@ module StripeMock
34
39
  raise Stripe::InvalidRequestError.new("Invalid token id: #{params[:source]}", 'card', http_status: 400)
35
40
  end
36
41
  elsif params[:customer]
37
- customer = customers[params[:customer]]
42
+ customer = customers[stripe_account][params[:customer]]
38
43
  if customer && customer[:default_source]
39
44
  params[:source] = get_card(customer, customer[:default_source])
40
45
  end
41
46
  end
42
47
 
43
48
  ensure_required_params(params)
44
- bal_trans_params = { amount: params[:amount], source: id }
49
+ bal_trans_params = { amount: params[:amount], source: id, application_fee: params[:application_fee] }
45
50
 
46
51
  balance_transaction_id = new_balance_transaction('txn', bal_trans_params)
47
52
 
@@ -143,7 +148,7 @@ module StripeMock
143
148
  elsif non_positive_charge_amount?(params)
144
149
  raise Stripe::InvalidRequestError.new('Invalid positive integer', 'amount', http_status: 400)
145
150
  elsif params[:source].nil? && params[:customer].nil?
146
- 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)
147
152
  end
148
153
  end
149
154
 
@@ -155,10 +160,6 @@ module StripeMock
155
160
  params[:amount] && params[:amount] < 1
156
161
  end
157
162
 
158
- def require_param(param)
159
- raise Stripe::InvalidRequestError.new("Missing required param: #{param}", param.to_s, http_status: 400)
160
- end
161
-
162
163
  def allowed_params(params)
163
164
  allowed = [:description, :metadata, :receipt_email, :fraud_details, :shipping, :destination]
164
165
 
@@ -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,16 @@
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
+ assert_existence :checkout_session, $1, checkout_sessions[$1]
12
+ end
13
+ end
14
+ end
15
+ end
16
+ 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_customer(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_customer(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