stripe-ruby-mock 3.0.1 → 3.1.0

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 (137) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/rspec_tests.yml +38 -0
  3. data/.rspec +2 -1
  4. data/CHANGELOG.md +62 -15
  5. data/Gemfile +1 -0
  6. data/README.md +5 -3
  7. data/lib/stripe_mock/api/client.rb +1 -1
  8. data/lib/stripe_mock/api/instance.rb +1 -1
  9. data/lib/stripe_mock/api/webhooks.rb +66 -25
  10. data/lib/stripe_mock/client.rb +2 -1
  11. data/lib/stripe_mock/data/list.rb +31 -6
  12. data/lib/stripe_mock/data.rb +201 -30
  13. data/lib/stripe_mock/instance.rb +12 -3
  14. data/lib/stripe_mock/request_handlers/account_links.rb +15 -0
  15. data/lib/stripe_mock/request_handlers/accounts.rb +17 -6
  16. data/lib/stripe_mock/request_handlers/charges.rb +11 -4
  17. data/lib/stripe_mock/request_handlers/checkout_session.rb +179 -0
  18. data/lib/stripe_mock/request_handlers/customers.rb +22 -13
  19. data/lib/stripe_mock/request_handlers/ephemeral_key.rb +1 -1
  20. data/lib/stripe_mock/request_handlers/events.rb +30 -3
  21. data/lib/stripe_mock/request_handlers/express_login_links.rb +15 -0
  22. data/lib/stripe_mock/request_handlers/helpers/coupon_helpers.rb +1 -0
  23. data/lib/stripe_mock/request_handlers/helpers/subscription_helpers.rb +36 -12
  24. data/lib/stripe_mock/request_handlers/invoices.rb +10 -4
  25. data/lib/stripe_mock/request_handlers/payment_intents.rb +13 -2
  26. data/lib/stripe_mock/request_handlers/payment_methods.rb +11 -4
  27. data/lib/stripe_mock/request_handlers/prices.rb +62 -0
  28. data/lib/stripe_mock/request_handlers/promotion_codes.rb +43 -0
  29. data/lib/stripe_mock/request_handlers/refunds.rb +13 -2
  30. data/lib/stripe_mock/request_handlers/setup_intents.rb +16 -9
  31. data/lib/stripe_mock/request_handlers/sources.rb +12 -6
  32. data/lib/stripe_mock/request_handlers/subscriptions.rb +120 -21
  33. data/lib/stripe_mock/request_handlers/tokens.rb +6 -4
  34. data/lib/stripe_mock/request_handlers/transfers.rb +12 -1
  35. data/lib/stripe_mock/request_handlers/validators/param_validators.rb +33 -4
  36. data/lib/stripe_mock/server.rb +2 -2
  37. data/lib/stripe_mock/test_strategies/base.rb +62 -10
  38. data/lib/stripe_mock/version.rb +1 -1
  39. data/lib/stripe_mock/webhook_fixtures/account.updated.json +1 -1
  40. data/lib/stripe_mock/webhook_fixtures/balance.available.json +27 -15
  41. data/lib/stripe_mock/webhook_fixtures/charge.captured.json +143 -0
  42. data/lib/stripe_mock/webhook_fixtures/charge.dispute.created.json +63 -16
  43. data/lib/stripe_mock/webhook_fixtures/charge.failed.json +49 -120
  44. data/lib/stripe_mock/webhook_fixtures/charge.refund.updated.json +35 -0
  45. data/lib/stripe_mock/webhook_fixtures/charge.refunded.json +145 -50
  46. data/lib/stripe_mock/webhook_fixtures/charge.succeeded.json +114 -43
  47. data/lib/stripe_mock/webhook_fixtures/checkout.session.completed.json +79 -0
  48. data/lib/stripe_mock/webhook_fixtures/checkout.session.completed.payment_mode.json +53 -0
  49. data/lib/stripe_mock/webhook_fixtures/checkout.session.completed.setup_mode.json +45 -0
  50. data/lib/stripe_mock/webhook_fixtures/customer.created.json +37 -46
  51. data/lib/stripe_mock/webhook_fixtures/customer.deleted.json +36 -32
  52. data/lib/stripe_mock/webhook_fixtures/customer.source.created.json +31 -22
  53. data/lib/stripe_mock/webhook_fixtures/customer.source.updated.json +36 -25
  54. data/lib/stripe_mock/webhook_fixtures/customer.subscription.created.json +135 -47
  55. data/lib/stripe_mock/webhook_fixtures/customer.subscription.deleted.json +134 -45
  56. data/lib/stripe_mock/webhook_fixtures/customer.subscription.updated.json +135 -56
  57. data/lib/stripe_mock/webhook_fixtures/customer.updated.json +38 -47
  58. data/lib/stripe_mock/webhook_fixtures/invoice.created.json +176 -49
  59. data/lib/stripe_mock/webhook_fixtures/invoice.finalized.json +171 -0
  60. data/lib/stripe_mock/webhook_fixtures/invoice.paid.json +171 -0
  61. data/lib/stripe_mock/webhook_fixtures/invoice.payment_action_required.json +171 -0
  62. data/lib/stripe_mock/webhook_fixtures/invoice.payment_failed.json +149 -83
  63. data/lib/stripe_mock/webhook_fixtures/invoice.payment_succeeded.json +149 -90
  64. data/lib/stripe_mock/webhook_fixtures/invoice.upcoming.json +70 -0
  65. data/lib/stripe_mock/webhook_fixtures/invoice.updated.json +178 -50
  66. data/lib/stripe_mock/webhook_fixtures/invoiceitem.created.json +87 -13
  67. data/lib/stripe_mock/webhook_fixtures/invoiceitem.updated.json +88 -14
  68. data/lib/stripe_mock/webhook_fixtures/mandate.updated.json +34 -0
  69. data/lib/stripe_mock/webhook_fixtures/payment_intent.amount_capturable_updated.json +170 -0
  70. data/lib/stripe_mock/webhook_fixtures/payment_intent.canceled.json +73 -0
  71. data/lib/stripe_mock/webhook_fixtures/payment_intent.created.json +86 -0
  72. data/lib/stripe_mock/webhook_fixtures/payment_intent.payment_failed.json +225 -0
  73. data/lib/stripe_mock/webhook_fixtures/payment_intent.processing.json +162 -0
  74. data/lib/stripe_mock/webhook_fixtures/payment_intent.requires_action.json +191 -0
  75. data/lib/stripe_mock/webhook_fixtures/payment_intent.succeeded.json +196 -0
  76. data/lib/stripe_mock/webhook_fixtures/payment_link.created.json +47 -0
  77. data/lib/stripe_mock/webhook_fixtures/payment_link.updated.json +50 -0
  78. data/lib/stripe_mock/webhook_fixtures/payment_method.attached.json +63 -0
  79. data/lib/stripe_mock/webhook_fixtures/payment_method.detached.json +62 -0
  80. data/lib/stripe_mock/webhook_fixtures/payout.created.json +40 -0
  81. data/lib/stripe_mock/webhook_fixtures/payout.paid.json +40 -0
  82. data/lib/stripe_mock/webhook_fixtures/payout.updated.json +46 -0
  83. data/lib/stripe_mock/webhook_fixtures/plan.created.json +30 -13
  84. data/lib/stripe_mock/webhook_fixtures/plan.deleted.json +30 -13
  85. data/lib/stripe_mock/webhook_fixtures/plan.updated.json +34 -14
  86. data/lib/stripe_mock/webhook_fixtures/price.created.json +42 -0
  87. data/lib/stripe_mock/webhook_fixtures/price.deleted.json +42 -0
  88. data/lib/stripe_mock/webhook_fixtures/price.updated.json +48 -0
  89. data/lib/stripe_mock/webhook_fixtures/product.created.json +19 -13
  90. data/lib/stripe_mock/webhook_fixtures/product.deleted.json +20 -14
  91. data/lib/stripe_mock/webhook_fixtures/product.updated.json +24 -15
  92. data/lib/stripe_mock/webhook_fixtures/quote.accepted.json +92 -0
  93. data/lib/stripe_mock/webhook_fixtures/quote.canceled.json +92 -0
  94. data/lib/stripe_mock/webhook_fixtures/quote.created.json +92 -0
  95. data/lib/stripe_mock/webhook_fixtures/quote.finalized.json +92 -0
  96. data/lib/stripe_mock/webhook_fixtures/setup_intent.canceled.json +46 -0
  97. data/lib/stripe_mock/webhook_fixtures/setup_intent.created.json +51 -0
  98. data/lib/stripe_mock/webhook_fixtures/setup_intent.setup_failed.json +100 -0
  99. data/lib/stripe_mock/webhook_fixtures/setup_intent.succeeded.json +46 -0
  100. data/lib/stripe_mock/webhook_fixtures/subscription_schedule.canceled.json +119 -0
  101. data/lib/stripe_mock/webhook_fixtures/subscription_schedule.created.json +114 -0
  102. data/lib/stripe_mock/webhook_fixtures/subscription_schedule.released.json +111 -0
  103. data/lib/stripe_mock/webhook_fixtures/subscription_schedule.updated.json +125 -0
  104. data/lib/stripe_mock/webhook_fixtures/tax_rate.created.json +32 -0
  105. data/lib/stripe_mock/webhook_fixtures/tax_rate.updated.json +37 -0
  106. data/lib/stripe_mock.rb +7 -1
  107. data/spec/instance_spec.rb +7 -7
  108. data/spec/integration_examples/completing_checkout_sessions_example.rb +37 -0
  109. data/spec/list_spec.rb +23 -0
  110. data/spec/readme_spec.rb +1 -1
  111. data/spec/server_spec.rb +4 -2
  112. data/spec/shared_stripe_examples/account_examples.rb +9 -1
  113. data/spec/shared_stripe_examples/account_link_examples.rb +16 -0
  114. data/spec/shared_stripe_examples/balance_examples.rb +6 -0
  115. data/spec/shared_stripe_examples/card_token_examples.rb +17 -21
  116. data/spec/shared_stripe_examples/checkout_session_examples.rb +99 -0
  117. data/spec/shared_stripe_examples/customer_examples.rb +11 -13
  118. data/spec/shared_stripe_examples/express_login_link_examples.rb +12 -0
  119. data/spec/shared_stripe_examples/invoice_examples.rb +29 -8
  120. data/spec/shared_stripe_examples/payment_intent_examples.rb +74 -0
  121. data/spec/shared_stripe_examples/payment_method_examples.rb +336 -67
  122. data/spec/shared_stripe_examples/price_examples.rb +223 -0
  123. data/spec/shared_stripe_examples/product_examples.rb +1 -9
  124. data/spec/shared_stripe_examples/promotion_code_examples.rb +68 -0
  125. data/spec/shared_stripe_examples/refund_examples.rb +13 -0
  126. data/spec/shared_stripe_examples/setup_intent_examples.rb +17 -0
  127. data/spec/shared_stripe_examples/subscription_examples.rb +327 -9
  128. data/spec/shared_stripe_examples/transfer_examples.rb +10 -1
  129. data/spec/shared_stripe_examples/webhook_event_examples.rb +51 -5
  130. data/spec/spec_helper.rb +4 -0
  131. data/spec/stripe_mock_spec.rb +2 -2
  132. data/spec/support/stripe_examples.rb +8 -2
  133. data/stripe-ruby-mock.gemspec +7 -2
  134. metadata +72 -15
  135. data/.travis.yml +0 -28
  136. data/lib/stripe_mock/request_handlers/checkout.rb +0 -15
  137. data/spec/shared_stripe_examples/checkout_examples.rb +0 -19
@@ -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,8 +42,8 @@ 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)
@@ -50,15 +52,16 @@ module StripeMock
50
52
  if params[:coupon]
51
53
  coupon = coupons[params[:coupon]]
52
54
  assert_existence :coupon, params[:coupon], coupon
53
- add_coupon_to_object(customers[params[:id]], coupon)
55
+ add_coupon_to_object(customers[stripe_account][params[:id]], coupon)
54
56
  end
55
57
 
56
- customers[params[:id]]
58
+ customers[stripe_account][params[:id]]
57
59
  end
58
60
 
59
61
  def update_customer(route, method_url, params, headers)
62
+ stripe_account = headers && headers[:stripe_account] || Stripe.api_key
60
63
  route =~ method_url
61
- cus = assert_existence :customer, $1, customers[$1]
64
+ cus = assert_existence :customer, $1, customers[stripe_account][$1]
62
65
 
63
66
  # get existing and pending metadata
64
67
  metadata = cus.delete(:metadata) || {}
@@ -80,6 +83,8 @@ module StripeMock
80
83
  if params[:source]
81
84
  if params[:source].is_a?(String)
82
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])
83
88
  elsif params[:source].is_a?(Hash)
84
89
  unless params[:source][:object] && params[:source][:number] && params[:source][:exp_month] && params[:source][:exp_year]
85
90
  raise Stripe::InvalidRequestError.new('You must supply a valid card', nil, http_status: 400)
@@ -105,21 +110,23 @@ module StripeMock
105
110
  end
106
111
 
107
112
  def delete_customer(route, method_url, params, headers)
113
+ stripe_account = headers && headers[:stripe_account] || Stripe.api_key
108
114
  route =~ method_url
109
- assert_existence :customer, $1, customers[$1]
115
+ assert_existence :customer, $1, customers[stripe_account][$1]
110
116
 
111
- customers[$1] = {
112
- id: customers[$1][:id],
117
+ customers[stripe_account][$1] = {
118
+ id: customers[stripe_account][$1][:id],
113
119
  deleted: true
114
120
  }
115
121
  end
116
122
 
117
123
  def get_customer(route, method_url, params, headers)
124
+ stripe_account = headers && headers[:stripe_account] || Stripe.api_key
118
125
  route =~ method_url
119
- customer = assert_existence :customer, $1, customers[$1]
126
+ customer = assert_existence :customer, $1, customers[stripe_account][$1]
120
127
 
121
128
  customer = customer.clone
122
- if params[:expand] == ['default_source']
129
+ if params[:expand] == ['default_source'] && customer[:sources][:data]
123
130
  customer[:default_source] = customer[:sources][:data].detect do |source|
124
131
  source[:id] == customer[:default_source]
125
132
  end
@@ -129,12 +136,14 @@ module StripeMock
129
136
  end
130
137
 
131
138
  def list_customers(route, method_url, params, headers)
132
- 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)
133
141
  end
134
142
 
135
143
  def delete_customer_discount(route, method_url, params, headers)
144
+ stripe_account = headers && headers[:stripe_account] || Stripe.api_key
136
145
  route =~ method_url
137
- cus = assert_existence :customer, $1, customers[$1]
146
+ cus = assert_existence :customer, $1, customers[stripe_account][$1]
138
147
 
139
148
  cus[:discount] = nil
140
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
@@ -4,7 +4,7 @@ module StripeMock
4
4
 
5
5
  def Events.included(klass)
6
6
  klass.add_handler 'get /v1/events/(.*)', :retrieve_event
7
- klass.add_handler 'get /v1/events', :list_events
7
+ klass.add_handler 'get /v1/events', :list_events
8
8
  end
9
9
 
10
10
  def retrieve_event(route, method_url, params, headers)
@@ -13,9 +13,36 @@ module StripeMock
13
13
  end
14
14
 
15
15
  def list_events(route, method_url, params, headers)
16
- Data.mock_list_object(events.values, params)
16
+ values = filter_by_created(events.values, params: params)
17
+ Data.mock_list_object(values, params)
17
18
  end
18
-
19
+
20
+ private
21
+
22
+ def filter_by_created(event_list, params:)
23
+ if params[:created].nil?
24
+ return event_list
25
+ end
26
+
27
+ if params[:created].is_a?(Hash)
28
+ if params[:created][:gt]
29
+ event_list = event_list.select { |event| event[:created] > params[:created][:gt].to_i }
30
+ end
31
+ if params[:created][:gte]
32
+ event_list = event_list.select { |event| event[:created] >= params[:created][:gte].to_i }
33
+ end
34
+ if params[:created][:lt]
35
+ event_list = event_list.select { |event| event[:created] < params[:created][:lt].to_i }
36
+ end
37
+ if params[:created][:lte]
38
+ event_list = event_list.select { |event| event[:created] <= params[:created][:lte].to_i }
39
+ end
40
+ else
41
+ event_list = event_list.select { |event| event[:created] == params[:created].to_i }
42
+ end
43
+ event_list
44
+ end
45
+
19
46
  end
20
47
  end
21
48
  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
@@ -7,6 +7,7 @@ module StripeMock
7
7
  attrs[:coupon] = coupon
8
8
  attrs[:start] = Time.now.to_i
9
9
  attrs[:end] = (DateTime.now >> coupon[:duration_in_months].to_i).to_time.to_i if coupon[:duration] == 'repeating'
10
+ attrs[:id] = new_id("di")
10
11
  end
11
12
 
12
13
  object[:discount] = Stripe::Discount.construct_from(discount_attrs)
@@ -11,12 +11,17 @@ 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
+ matching_item[:quantity] ||= 1
17
+ matching_item[:id] ||= new_id('si')
18
+ params = matching_item.merge(plan: plan)
19
+ params[:price] = plan if plan[:object] == "price"
20
+ Data.mock_subscription_item(params)
18
21
  else
19
- Data.mock_subscription_item({ plan: plan })
22
+ params = { plan: plan, id: new_id('si') }
23
+ params[:price] = plan if plan[:object] == "price"
24
+ Data.mock_subscription_item(params)
20
25
  end
21
26
  end
22
27
  subscription
@@ -32,7 +37,7 @@ module StripeMock
32
37
  start_time = options[:current_period_start] || now
33
38
  params = { customer: cus[:id], current_period_start: start_time, created: created_time }
34
39
  params.merge!({ :plan => (plans.size == 1 ? plans.first : nil) })
35
- keys_to_merge = /application_fee_percent|quantity|metadata|tax_percent|billing|days_until_due|default_tax_rates|pending_invoice_item_interval/
40
+ 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
41
  params.merge! options.select {|k,v| k =~ keys_to_merge}
37
42
 
38
43
  if options[:cancel_at_period_end] == true
@@ -45,10 +50,10 @@ module StripeMock
45
50
 
46
51
  if (((plan && plan[:trial_period_days]) || 0) == 0 && options[:trial_end].nil?) || options[:trial_end] == "now"
47
52
  end_time = options[:billing_cycle_anchor] || get_ending_time(start_time, plan)
48
- params.merge!({status: 'active', current_period_end: end_time, trial_start: nil, trial_end: nil, billing_cycle_anchor: options[:billing_cycle_anchor]})
53
+ params.merge!({status: 'active', current_period_end: end_time, trial_start: nil, trial_end: nil, billing_cycle_anchor: options[:billing_cycle_anchor] || created_time})
49
54
  else
50
55
  end_time = options[:trial_end] || (Time.now.utc.to_i + plan[:trial_period_days]*86400)
51
- params.merge!({status: 'trialing', current_period_end: end_time, trial_start: start_time, trial_end: end_time, billing_cycle_anchor: nil})
56
+ params.merge!({status: 'trialing', current_period_end: end_time, trial_start: start_time, trial_end: end_time, billing_cycle_anchor: options[:billing_cycle_anchor] || created_time})
52
57
  end
53
58
 
54
59
  params
@@ -85,11 +90,13 @@ module StripeMock
85
90
  def get_ending_time(start_time, plan, intervals = 1)
86
91
  return start_time unless plan
87
92
 
88
- case plan[:interval]
93
+ interval = plan[:interval] || plan.dig(:recurring, :interval)
94
+ interval_count = plan[:interval_count] || plan.dig(:recurring, :interval_count) || 1
95
+ case interval
89
96
  when "week"
90
- start_time + (604800 * (plan[:interval_count] || 1) * intervals)
97
+ start_time + (604800 * (interval_count) * intervals)
91
98
  when "month"
92
- (Time.at(start_time).to_datetime >> ((plan[:interval_count] || 1) * intervals)).to_time.to_i
99
+ (Time.at(start_time).to_datetime >> ((interval_count) * intervals)).to_time.to_i
93
100
  when "year"
94
101
  (Time.at(start_time).to_datetime >> (12 * intervals)).to_time.to_i # max period is 1 year
95
102
  else
@@ -111,9 +118,26 @@ module StripeMock
111
118
 
112
119
  def total_items_amount(items)
113
120
  total = 0
114
- items.each { |i| total += (i[:quantity] || 1) * i[:plan][:amount] }
121
+ items.each do |item|
122
+ quantity = item[:quantity] || 1
123
+ amount = item[:plan][:unit_amount] || item[:plan][:amount]
124
+ total += quantity * amount
125
+ end
115
126
  total
116
127
  end
128
+
129
+ def filter_by_timestamp(subscriptions, field:, value:)
130
+ if value.is_a?(Hash)
131
+ operator_mapping = { gt: :>, gte: :>=, lt: :<, lte: :<= }
132
+ subscriptions.filter do |sub|
133
+ sub[field].public_send(operator_mapping[value.keys[0]], value.values[0])
134
+ end
135
+ else
136
+ subscriptions.filter do |sub|
137
+ sub[field] == value
138
+ end
139
+ end
140
+ end
117
141
  end
118
142
  end
119
143
  end
@@ -53,16 +53,22 @@ module StripeMock
53
53
  route =~ method_url
54
54
  assert_existence :invoice, $1, invoices[$1]
55
55
  charge = invoice_charge(invoices[$1])
56
- invoices[$1].merge!(:paid => true, :attempted => true, :charge => charge[:id])
56
+ invoices[$1].merge!(
57
+ :paid => true,
58
+ :status => "paid",
59
+ :attempted => true,
60
+ :charge => charge[:id],
61
+ )
57
62
  end
58
63
 
59
- def upcoming_invoice(route, method_url, params, headers)
64
+ def upcoming_invoice(route, method_url, params, headers = {})
65
+ stripe_account = headers && headers[:stripe_account] || Stripe.api_key
60
66
  route =~ method_url
61
- raise Stripe::InvalidRequestError.new('Missing required param: customer', nil, http_status: 400) if params[:customer].nil?
67
+ raise Stripe::InvalidRequestError.new('Missing required param: customer if subscription is not provided', nil, http_status: 400) if params[:customer].nil? && params[:subscription].nil?
62
68
  raise Stripe::InvalidRequestError.new('When previewing changes to a subscription, you must specify either `subscription` or `subscription_items`', nil, http_status: 400) if !params[:subscription_proration_date].nil? && params[:subscription].nil? && params[:subscription_plan].nil?
63
69
  raise Stripe::InvalidRequestError.new('Cannot specify proration date without specifying a subscription', nil, http_status: 400) if !params[:subscription_proration_date].nil? && params[:subscription].nil?
64
70
 
65
- customer = customers[params[:customer]]
71
+ customer = customers[stripe_account][params[:customer]]
66
72
  assert_existence :customer, params[:customer], customer
67
73
 
68
74
  raise Stripe::InvalidRequestError.new("No upcoming invoices for customer: #{customer[:id]}", nil, http_status: 404) if customer[:subscriptions][:data].length == 0
@@ -81,6 +81,10 @@ module StripeMock
81
81
  route =~ method_url
82
82
  payment_intent = assert_existence :payment_intent, $1, payment_intents[$1]
83
83
 
84
+ if params[:payment_method]
85
+ payment_intent[:payment_method] = params[:payment_method]
86
+ end
87
+
84
88
  succeeded_payment_intent(payment_intent)
85
89
  end
86
90
 
@@ -169,12 +173,19 @@ module StripeMock
169
173
  payment_intent[:status] = 'succeeded'
170
174
  btxn = new_balance_transaction('txn', { source: payment_intent[:id] })
171
175
 
172
- payment_intent[:charges][:data] << Data.mock_charge(
176
+ charge_id = new_id('ch')
177
+
178
+ charges[charge_id] = Data.mock_charge(
179
+ id: charge_id,
173
180
  balance_transaction: btxn,
181
+ payment_intent: payment_intent[:id],
174
182
  amount: payment_intent[:amount],
175
- currency: payment_intent[:currency]
183
+ currency: payment_intent[:currency],
184
+ payment_method: payment_intent[:payment_method]
176
185
  )
177
186
 
187
+ payment_intent[:charges][:data] << charges[charge_id].clone
188
+
178
189
  payment_intent
179
190
  end
180
191
  end
@@ -51,14 +51,15 @@ module StripeMock
51
51
 
52
52
  Data.mock_list_object(clone.values, params)
53
53
  end
54
-
54
+
55
55
  # post /v1/payment_methods/:id/attach
56
56
  def attach_payment_method(route, method_url, params, headers)
57
+ stripe_account = headers && headers[:stripe_account] || Stripe.api_key
57
58
  allowed_params = [:customer]
58
59
 
59
60
  id = method_url.match(route)[1]
60
61
 
61
- assert_existence :customer, params[:customer], customers[params[:customer]]
62
+ assert_existence :customer, params[:customer], customers[stripe_account][params[:customer]]
62
63
 
63
64
  payment_method = assert_existence :payment_method, id, payment_methods[id]
64
65
  payment_methods[id] = Util.rmerge(payment_method, params.select { |k, _v| allowed_params.include?(k) })
@@ -78,6 +79,10 @@ module StripeMock
78
79
  # post /v1/payment_methods/:id
79
80
  def update_payment_method(route, method_url, params, headers)
80
81
  allowed_params = [:billing_details, :card, :metadata]
82
+ disallowed_params = params.keys - allowed_params
83
+ unless disallowed_params.empty?
84
+ raise Stripe::InvalidRequestError.new("Received unknown parameter: #{disallowed_params.first}", disallowed_params.first)
85
+ end
81
86
 
82
87
  id = method_url.match(route)[1]
83
88
 
@@ -86,6 +91,7 @@ module StripeMock
86
91
  if payment_method[:customer].nil?
87
92
  raise Stripe::InvalidRequestError.new(
88
93
  'You must save this PaymentMethod to a customer before you can update it.',
94
+ nil,
89
95
  http_status: 400
90
96
  )
91
97
  end
@@ -103,14 +109,15 @@ module StripeMock
103
109
 
104
110
  if invalid_type?(params[:type])
105
111
  raise Stripe::InvalidRequestError.new(
106
- 'Invalid type: must be one of card or card_present',
112
+ 'Invalid type: must be one of card, ideal or sepa_debit',
113
+ nil,
107
114
  http_status: 400
108
115
  )
109
116
  end
110
117
  end
111
118
 
112
119
  def invalid_type?(type)
113
- !['card', 'card_present'].include?(type)
120
+ !%w(card ideal sepa_debit).include?(type)
114
121
  end
115
122
  end
116
123
  end
@@ -0,0 +1,62 @@
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
+
15
+ if params[:product_data]
16
+ params[:product] = create_product(nil, nil, params[:product_data], nil)[:id] unless params[:product]
17
+ params.delete(:product_data)
18
+ end
19
+
20
+ validate_create_price_params(params)
21
+ prices[ params[:id] ] = Data.mock_price(params)
22
+ end
23
+
24
+ def update_price(route, method_url, params, headers)
25
+ route =~ method_url
26
+ assert_existence :price, $1, prices[$1]
27
+ prices[$1].merge!(params)
28
+ end
29
+
30
+ def get_price(route, method_url, params, headers)
31
+ route =~ method_url
32
+ assert_existence :price, $1, prices[$1]
33
+ end
34
+
35
+ def list_prices(route, method_url, params, headers)
36
+ limit = params[:limit] ? params[:limit] : 10
37
+ price_data = prices.values
38
+ validate_list_prices_params(params)
39
+
40
+ if params.key?(:lookup_keys)
41
+ price_data.select! do |price|
42
+ params[:lookup_keys].include?(price[:lookup_key])
43
+ end
44
+ end
45
+
46
+ if params.key?(:currency)
47
+ price_data.select! do |price|
48
+ params[:currency] == price[:currency]
49
+ end
50
+ end
51
+
52
+ if params.key?(:product)
53
+ price_data.select! do |price|
54
+ params[:product] == price[:product]
55
+ end
56
+ end
57
+
58
+ Data.mock_list_object(price_data.first(limit), params.merge!(limit: limit))
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,43 @@
1
+ module StripeMock
2
+ module RequestHandlers
3
+ module PromotionCodes
4
+
5
+ def PromotionCodes.included(klass)
6
+ klass.add_handler 'post /v1/promotion_codes', :new_promotion_code
7
+ klass.add_handler 'post /v1/promotion_codes/([^/]*)', :update_promotion_code
8
+ klass.add_handler 'get /v1/promotion_codes/([^/]*)', :get_promotion_code
9
+ klass.add_handler 'get /v1/promotion_codes', :list_promotion_code
10
+ end
11
+
12
+ def new_promotion_code(route, method_url, params, headers)
13
+ params[:id] ||= new_id("promo")
14
+ raise Stripe::InvalidRequestError.new("Missing required param: coupon", "promotion_code", http_status: 400) unless params[:coupon]
15
+
16
+ if params[:restrictions]
17
+ if params[:restrictions][:minimum_amount] && !params[:restrictions][:minimum_amount_currency]
18
+ raise Stripe::InvalidRequestError.new(
19
+ "You must pass minimum_amount_currency when passing minimum_amount", "minimum_amount_currency", http_status: 400
20
+ )
21
+ end
22
+ end
23
+
24
+ promotion_codes[ params[:id] ] = Data.mock_promotion_code(params)
25
+ end
26
+
27
+ def update_promotion_code(route, method_url, params, headers)
28
+ route =~ method_url
29
+ assert_existence :promotion_code, $1, promotion_codes[$1]
30
+ promotion_codes[$1].merge!(params)
31
+ end
32
+
33
+ def get_promotion_code(route, method_url, params, headers)
34
+ route =~ method_url
35
+ assert_existence :promotion_code, $1, promotion_codes[$1]
36
+ end
37
+
38
+ def list_promotion_code(route, method_url, params, headers)
39
+ Data.mock_list_object(promotion_codes.values, params)
40
+ end
41
+ end
42
+ end
43
+ end
@@ -18,7 +18,18 @@ module StripeMock
18
18
  end
19
19
  end
20
20
 
21
- charge = assert_existence :charge, params[:charge], charges[params[:charge]]
21
+ if params[:payment_intent]
22
+ payment_intent = assert_existence(
23
+ :payment_intent,
24
+ params[:payment_intent],
25
+ payment_intents[params[:payment_intent]]
26
+ )
27
+ charge = {}
28
+ else
29
+ charge = assert_existence :charge, params[:charge], charges[params[:charge]]
30
+ payment_intent = {}
31
+ end
32
+ params[:amount] ||= payment_intent[:amount]
22
33
  params[:amount] ||= charge[:amount]
23
34
  id = new_id('re')
24
35
  bal_trans_params = {
@@ -32,7 +43,7 @@ module StripeMock
32
43
  :id => id,
33
44
  :charge => charge[:id],
34
45
  )
35
- add_refund_to_charge(refund, charge)
46
+ add_refund_to_charge(refund, charge) unless charge.empty?
36
47
  refunds[id] = refund
37
48
 
38
49
  if params[:expand] == ['balance_transaction']
@@ -15,20 +15,22 @@ module StripeMock
15
15
  ]
16
16
 
17
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
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
24
  end
25
25
 
26
26
  def new_setup_intent(route, method_url, params, headers)
27
27
  id = new_id('si')
28
+ status = params[:payment_method] ? 'requires_action' : 'requires_payment_method'
28
29
 
29
30
  setup_intents[id] = Data.mock_setup_intent(
30
31
  params.merge(
31
- id: id
32
+ id: id,
33
+ status: status
32
34
  )
33
35
  )
34
36
 
@@ -40,7 +42,7 @@ module StripeMock
40
42
  id = $1
41
43
 
42
44
  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)})
45
+ setup_intents[id] = Util.rmerge(setup_intent, params.select { |k, v| ALLOWED_PARAMS.include?(k) })
44
46
  end
45
47
 
46
48
  def get_setup_intents(route, method_url, params, headers)
@@ -50,7 +52,7 @@ module StripeMock
50
52
  clone = setup_intents.clone
51
53
 
52
54
  if params[:customer]
53
- clone.delete_if { |k,v| v[:customer] != params[:customer] }
55
+ clone.delete_if { |k, v| v[:customer] != params[:customer] }
54
56
  end
55
57
 
56
58
  Data.mock_list_object(clone.values, params)
@@ -62,6 +64,11 @@ module StripeMock
62
64
  setup_intent = assert_existence :setup_intent, setup_intent_id, setup_intents[setup_intent_id]
63
65
 
64
66
  setup_intent = setup_intent.clone
67
+
68
+ if params[:expand]&.include?("payment_method")
69
+ setup_intent[:payment_method] = assert_existence :payment_method, setup_intent[:payment_method], payment_methods[setup_intent[:payment_method]]
70
+ end
71
+
65
72
  setup_intent
66
73
  end
67
74
 
@@ -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