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.
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