stripe-ruby-mock 2.5.0 → 2.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/lib/stripe_mock.rb +3 -0
  4. data/lib/stripe_mock/api/account_balance.rb +14 -0
  5. data/lib/stripe_mock/api/webhooks.rb +2 -0
  6. data/lib/stripe_mock/client.rb +4 -0
  7. data/lib/stripe_mock/data.rb +78 -3
  8. data/lib/stripe_mock/instance.rb +21 -4
  9. data/lib/stripe_mock/request_handlers/accounts.rb +18 -2
  10. data/lib/stripe_mock/request_handlers/balance.rb +17 -0
  11. data/lib/stripe_mock/request_handlers/helpers/subscription_helpers.rb +27 -6
  12. data/lib/stripe_mock/request_handlers/invoices.rb +20 -4
  13. data/lib/stripe_mock/request_handlers/payouts.rb +32 -0
  14. data/lib/stripe_mock/request_handlers/subscriptions.rb +65 -9
  15. data/lib/stripe_mock/request_handlers/tokens.rb +6 -0
  16. data/lib/stripe_mock/request_handlers/validators/param_validators.rb +7 -1
  17. data/lib/stripe_mock/server.rb +4 -0
  18. data/lib/stripe_mock/util.rb +8 -2
  19. data/lib/stripe_mock/version.rb +1 -1
  20. data/lib/stripe_mock/webhook_fixtures/account.updated.json +1 -1
  21. data/lib/stripe_mock/webhook_fixtures/charge.updated.json +58 -0
  22. data/lib/stripe_mock/webhook_fixtures/customer.subscription.created.json +40 -10
  23. data/lib/stripe_mock/webhook_fixtures/customer.subscription.deleted.json +39 -10
  24. data/lib/stripe_mock/webhook_fixtures/customer.subscription.trial_will_end.json +39 -10
  25. data/lib/stripe_mock/webhook_fixtures/customer.subscription.updated.json +39 -10
  26. data/lib/stripe_mock/webhook_fixtures/invoice.payment_succeeded.json +92 -85
  27. data/spec/shared_stripe_examples/account_examples.rb +8 -0
  28. data/spec/shared_stripe_examples/balance_examples.rb +11 -0
  29. data/spec/shared_stripe_examples/bank_examples.rb +27 -0
  30. data/spec/shared_stripe_examples/dispute_examples.rb +10 -0
  31. data/spec/shared_stripe_examples/invoice_examples.rb +68 -6
  32. data/spec/shared_stripe_examples/payout_examples.rb +68 -0
  33. data/spec/shared_stripe_examples/plan_examples.rb +7 -1
  34. data/spec/shared_stripe_examples/subscription_examples.rb +132 -2
  35. data/spec/shared_stripe_examples/webhook_event_examples.rb +69 -0
  36. data/spec/support/stripe_examples.rb +2 -0
  37. data/spec/util_spec.rb +35 -1
  38. metadata +10 -2
@@ -0,0 +1,32 @@
1
+ module StripeMock
2
+ module RequestHandlers
3
+ module Payouts
4
+
5
+ def Payouts.included(klass)
6
+ klass.add_handler 'post /v1/payouts', :new_payout
7
+ klass.add_handler 'get /v1/payouts', :list_payouts
8
+ klass.add_handler 'get /v1/payouts/(.*)', :get_payout
9
+ end
10
+
11
+ def new_payout(route, method_url, params, headers)
12
+ id = new_id('po')
13
+
14
+ unless params[:amount].is_a?(Integer) || (params[:amount].is_a?(String) && /^\d+$/.match(params[:amount]))
15
+ raise Stripe::InvalidRequestError.new("Invalid integer: #{params[:amount]}", 'amount', http_status: 400)
16
+ end
17
+
18
+ payouts[id] = Data.mock_payout(params.merge :id => id)
19
+ end
20
+
21
+ def list_payouts(route, method_url, params, headers)
22
+ Data.mock_list_object(payouts.clone.values, params)
23
+ end
24
+
25
+ def get_payout(route, method_url, params, headers)
26
+ route =~ method_url
27
+ assert_existence :payout, $1, payouts[$1]
28
+ payouts[$1] ||= Data.mock_payout(:id => $1)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -32,10 +32,22 @@ module StripeMock
32
32
  customer[:subscriptions]
33
33
  end
34
34
 
35
+ def plan_id_from_params(params)
36
+ if params[:plan]
37
+ params[:plan].to_s
38
+ elsif params[:items]
39
+ item = params[:items].values.find { |item| item[:plan] }
40
+ if item
41
+ item[:plan].to_s
42
+ end
43
+ end
44
+ end
45
+
35
46
  def create_customer_subscription(route, method_url, params, headers)
36
47
  route =~ method_url
37
48
 
38
- plan_id = params[:plan].to_s
49
+ plan_id = plan_id_from_params(params)
50
+
39
51
  plan = assert_existence :plan, plan_id, plans[plan_id]
40
52
 
41
53
  customer = assert_existence :customer, $1, customers[$1]
@@ -70,26 +82,35 @@ module StripeMock
70
82
  subscriptions[subscription[:id]] = subscription
71
83
  add_subscription_to_customer(customer, subscription)
72
84
 
85
+ clear_top_level_plan_if_multiple_items(subscription)
86
+
73
87
  subscriptions[subscription[:id]]
74
88
  end
75
89
 
76
90
  def create_subscription(route, method_url, params, headers)
77
91
  route =~ method_url
78
92
 
79
- plan_id = params[:plan].to_s
80
- plan = assert_existence :plan, plan_id, plans[plan_id]
93
+ plan_id = plan_id_from_params(params)
94
+
95
+ plan = plan_id ? assert_existence(:plan, plan_id, plans[plan_id]) : nil
81
96
 
82
97
  customer = params[:customer]
83
98
  customer_id = customer.is_a?(Stripe::Customer) ? customer[:id] : customer.to_s
84
99
  customer = assert_existence :customer, customer_id, customers[customer_id]
85
100
 
101
+ if plan && customer
102
+ unless customer[:currency] == plan[:currency]
103
+ raise Stripe::InvalidRequestError.new('lol', 'currency', http_status: 400)
104
+ end
105
+ end
106
+
86
107
  if params[:source]
87
108
  new_card = get_card_by_token(params.delete(:source))
88
109
  add_card_to_object(:customer, new_card, customer)
89
110
  customer[:default_source] = new_card[:id]
90
111
  end
91
112
 
92
- allowed_params = %w(customer application_fee_percent coupon items metadata plan quantity source tax_percent trial_end trial_period_days current_period_start)
113
+ allowed_params = %w(customer application_fee_percent coupon items metadata plan quantity source tax_percent trial_end trial_period_days current_period_start created)
93
114
  unknown_params = params.keys - allowed_params.map(&:to_sym)
94
115
  if unknown_params.length > 0
95
116
  raise Stripe::InvalidRequestError.new("Received unknown parameter: #{unknown_params.join}", unknown_params.first.to_s, http_status: 400)
@@ -97,6 +118,7 @@ module StripeMock
97
118
 
98
119
  subscription = Data.mock_subscription({ id: (params[:id] || new_id('su')) })
99
120
  subscription.merge!(custom_subscription_params(plan, customer, params))
121
+ subscription[:items][:data] = mock_subscription_items(params[:items].values) if params[:items]
100
122
 
101
123
  # Ensure customer has card to charge if plan has no trial and is not free
102
124
  verify_card_present(customer, plan, subscription, params)
@@ -119,6 +141,8 @@ module StripeMock
119
141
  subscriptions[subscription[:id]] = subscription
120
142
  add_subscription_to_customer(customer, subscription)
121
143
 
144
+ clear_top_level_plan_if_multiple_items(subscription)
145
+
122
146
  subscriptions[subscription[:id]]
123
147
  end
124
148
 
@@ -153,10 +177,20 @@ module StripeMock
153
177
  end
154
178
 
155
179
  # expand the plan for addition to the customer object
156
- plan_name =
157
- params[:plan].is_a?(String) ? params[:plan] : subscription[:plan][:id]
180
+ plan_id = plan_id_from_params(params)
181
+
182
+ unless plan_id
183
+ plan_id = if subscription[:plan]
184
+ subscription[:plan][:id]
185
+ elsif subscription[:items]
186
+ row = subscription[:items][:data].find { |item| item[:plan] }
187
+ if row
188
+ row[:plan][:id]
189
+ end
190
+ end
191
+ end
158
192
 
159
- plan = plans[plan_name]
193
+ plan = plans[plan_id]
160
194
 
161
195
  if params[:coupon]
162
196
  coupon_id = params[:coupon]
@@ -174,7 +208,7 @@ module StripeMock
174
208
  end
175
209
  end
176
210
 
177
- assert_existence :plan, plan_name, plan
211
+ assert_existence :plan, plan_id, plan
178
212
  params[:plan] = plan if params[:plan]
179
213
  verify_card_present(customer, plan, subscription)
180
214
 
@@ -190,6 +224,8 @@ module StripeMock
190
224
  customer[:subscriptions][:data].reject! { |sub| sub[:id] == subscription[:id] }
191
225
  customer[:subscriptions][:data] << subscription
192
226
 
227
+ clear_top_level_plan_if_multiple_items(subscription)
228
+
193
229
  subscription
194
230
  end
195
231
 
@@ -223,8 +259,28 @@ module StripeMock
223
259
 
224
260
  private
225
261
 
262
+ def clear_top_level_plan_if_multiple_items(subscription)
263
+ subscription[:plan] = nil if subscription[:items][:data].size > 1
264
+ end
265
+
226
266
  def verify_card_present(customer, plan, subscription, params={})
227
- if customer[:default_source].nil? && customer[:trial_end].nil? && (plan[:trial_period_days]||0)==0 && plan[:amount] != 0 && plan[:trial_end].nil? && params[:trial_end].nil? && (subscription.nil? || subscription[:trial_end].nil? || subscription[:trial_end] == 'now')
267
+ if customer[:default_source].nil? && customer[:trial_end].nil? &&
268
+ (plan.nil? ||
269
+ ((plan[:trial_period_days] || 0) == 0 &&
270
+ plan[:amount] != 0 &&
271
+ plan[:trial_end].nil?)) &&
272
+ params[:trial_end].nil? &&
273
+ (subscription.nil? || subscription[:trial_end].nil? || subscription[:trial_end] == 'now')
274
+
275
+ if subscription[:items]
276
+ trial = subscription[:items][:data].none? do |item|
277
+ plan = item[:plan]
278
+ (plan[:trial_period_days].nil? || plan[:trial_period_days] == 0) &&
279
+ (plan[:trial_end].nil? || plan[:trial_end] == 'now')
280
+ end
281
+ return if trial
282
+ end
283
+
228
284
  raise Stripe::InvalidRequestError.new('You must supply a valid card xoxo', nil, http_status: 400)
229
285
  end
230
286
  end
@@ -31,6 +31,12 @@ module StripeMock
31
31
  params[:card][:fingerprint] = StripeMock::Util.fingerprint(params[:card][:number])
32
32
  params[:card][:last4] = params[:card][:number][-4,4]
33
33
  customer_card = params[:card]
34
+ elsif params[:bank_account].is_a?(String)
35
+ customer = assert_existence :customer, cus_id, customers[cus_id]
36
+
37
+ # params[:bank_account] is an id; grab it from the db
38
+ bank_account = verify_bank_account(customer, params[:bank_account])
39
+ assert_existence :bank_account, params[:bank_account], bank_account
34
40
  elsif params[:bank_account]
35
41
  # params[:card] is a hash of cc info; "Sanitize" the card number
36
42
  bank_account = params[:bank_account]
@@ -6,7 +6,13 @@ module StripeMock
6
6
  params[:id] = params[:id].to_s
7
7
 
8
8
  @base_strategy.create_plan_params.keys.each do |name|
9
- raise Stripe::InvalidRequestError.new("Missing required param: #{name}.", name) if params[name].nil?
9
+ message =
10
+ if name == :amount
11
+ "Plans require an `#{name}` parameter to be set."
12
+ else
13
+ "Missing required param: #{name}."
14
+ end
15
+ raise Stripe::InvalidRequestError.new(message, name) if params[name].nil?
10
16
  end
11
17
 
12
18
  if plans[ params[:id] ]
@@ -69,6 +69,10 @@ module StripeMock
69
69
  @instance.conversion_rate = value
70
70
  end
71
71
 
72
+ def set_account_balance(value)
73
+ @instance.account_balance = value
74
+ end
75
+
72
76
  def error_queue
73
77
  @instance.error_queue
74
78
  end
@@ -9,8 +9,14 @@ module StripeMock
9
9
  if oldval.is_a?(Array) && newval.is_a?(Array)
10
10
  oldval.fill(nil, oldval.length...newval.length)
11
11
  oldval.zip(newval).map {|elems|
12
- elems[1].nil? ? elems[0] : rmerge(elems[0], elems[1])
13
- }
12
+ if elems[1].nil?
13
+ elems[0]
14
+ elsif elems[1].is_a?(Hash) && elems[1].is_a?(Hash)
15
+ rmerge(elems[0], elems[1])
16
+ else
17
+ [elems[0], elems[1]].compact
18
+ end
19
+ }.flatten
14
20
  elsif oldval.is_a?(Hash) && newval.is_a?(Hash)
15
21
  rmerge(oldval, newval)
16
22
  else
@@ -1,4 +1,4 @@
1
1
  module StripeMock
2
2
  # stripe-ruby-mock version
3
- VERSION = "2.5.0"
3
+ VERSION = "2.5.1"
4
4
  end
@@ -11,7 +11,7 @@
11
11
  "statement_descriptor": "TEST",
12
12
  "details_submitted": true,
13
13
  "charge_enabled": false,
14
- "transfer_enabled": false,
14
+ "payouts_enabled": false,
15
15
  "currencies_supported": [
16
16
  "USD"
17
17
  ],
@@ -0,0 +1,58 @@
1
+ {
2
+ "created": 1326853478,
3
+ "livemode": false,
4
+ "id": "evt_00000000000000",
5
+ "type": "charge.updated",
6
+ "object": "event",
7
+ "data": {
8
+ "object": {
9
+ "id": "ch_00000000000000",
10
+ "object": "charge",
11
+ "created": 1380933505,
12
+ "livemode": false,
13
+ "paid": true,
14
+ "amount": 1000,
15
+ "currency": "usd",
16
+ "refunded": false,
17
+ "source": {
18
+ "id": "cc_00000000000000",
19
+ "object": "card",
20
+ "last4": "4242",
21
+ "type": "Visa",
22
+ "brand": "Visa",
23
+ "exp_month": 12,
24
+ "exp_year": 2013,
25
+ "fingerprint": "wXWJT135mEK107G8",
26
+ "customer": "cus_00000000000000",
27
+ "country": "US",
28
+ "name": "Actual Nothing",
29
+ "address_line1": null,
30
+ "address_line2": null,
31
+ "address_city": null,
32
+ "address_state": null,
33
+ "address_zip": null,
34
+ "address_country": null,
35
+ "cvc_check": null,
36
+ "address_line1_check": null,
37
+ "address_zip_check": null
38
+ },
39
+ "captured": true,
40
+ "refunds": {
41
+
42
+ },
43
+ "balance_transaction": "txn_00000000000000",
44
+ "failure_message": null,
45
+ "failure_code": null,
46
+ "amount_refunded": 0,
47
+ "customer": "cus_00000000000000",
48
+ "invoice": "in_00000000000000",
49
+ "description": "Sample description" ,
50
+ "dispute": null,
51
+ "metadata": {
52
+ }
53
+ },
54
+ "previous_attributes": {
55
+ "description": null
56
+ }
57
+ }
58
+ }
@@ -7,16 +7,46 @@
7
7
  "data": {
8
8
  "object": {
9
9
  "id": "su_00000000000000",
10
- "plan": {
11
- "interval": "month",
12
- "name": "Member's Club",
13
- "amount": 100,
14
- "currency": "usd",
15
- "id": "fkx0AFo_00000000000000",
16
- "object": "plan",
17
- "livemode": false,
18
- "interval_count": 1,
19
- "trial_period_days": null
10
+ "items": {
11
+ "object": "list",
12
+ "data": [
13
+ {
14
+ "id": "si_00000000000000",
15
+ "object": "subscription_item",
16
+ "created": 1497881783,
17
+ "plan": {
18
+ "interval": "month",
19
+ "name": "Member's Club",
20
+ "amount": 100,
21
+ "currency": "usd",
22
+ "id": "fkx0AFo_00000000000000",
23
+ "object": "plan",
24
+ "livemode": false,
25
+ "interval_count": 1,
26
+ "trial_period_days": null,
27
+ "metadata": {}
28
+ },
29
+ "quantity": 1
30
+ },
31
+ {
32
+ "id": "si_00000000000001",
33
+ "object": "subscription_item",
34
+ "created": 1497881788,
35
+ "plan": {
36
+ "interval": "month",
37
+ "name": "Vistor's Club",
38
+ "amount": 200,
39
+ "currency": "eur",
40
+ "id": "fkx0AFo_00000000000001",
41
+ "object": "plan",
42
+ "livemode": false,
43
+ "interval_count": 1,
44
+ "trial_period_days": null,
45
+ "metadata": {}
46
+ },
47
+ "quantity": 5
48
+ }
49
+ ]
20
50
  },
21
51
  "object": "subscription",
22
52
  "start": 1381080557,
@@ -7,16 +7,45 @@
7
7
  "data": {
8
8
  "object": {
9
9
  "id": "su_00000000000000",
10
- "plan": {
11
- "interval": "month",
12
- "name": "Member's Club",
13
- "amount": 100,
14
- "currency": "usd",
15
- "id": "fkx0AFo_00000000000000",
16
- "object": "plan",
17
- "livemode": false,
18
- "interval_count": 1,
19
- "trial_period_days": null
10
+ "items": {
11
+ "object": "list",
12
+ "data": [{
13
+ "id": "si_00000000000000",
14
+ "object": "subscription_item",
15
+ "created": 1497881783,
16
+ "plan": {
17
+ "interval": "month",
18
+ "name": "Member's Club",
19
+ "amount": 100,
20
+ "currency": "usd",
21
+ "id": "fkx0AFo_00000000000000",
22
+ "object": "plan",
23
+ "livemode": false,
24
+ "interval_count": 1,
25
+ "trial_period_days": null,
26
+ "metadata": {}
27
+ },
28
+ "quantity": 1
29
+ },
30
+ {
31
+ "id": "si_00000000000001",
32
+ "object": "subscription_item",
33
+ "created": 1497881788,
34
+ "plan": {
35
+ "interval": "month",
36
+ "name": "Vistor's Club",
37
+ "amount": 200,
38
+ "currency": "eur",
39
+ "id": "fkx0AFo_00000000000001",
40
+ "object": "plan",
41
+ "livemode": false,
42
+ "interval_count": 1,
43
+ "trial_period_days": null,
44
+ "metadata": {}
45
+ },
46
+ "quantity": 5
47
+ }
48
+ ]
20
49
  },
21
50
  "object": "subscription",
22
51
  "start": 1381080564,
@@ -7,16 +7,45 @@
7
7
  "data": {
8
8
  "object": {
9
9
  "id": "su_00000000000000",
10
- "plan": {
11
- "interval": "month",
12
- "name": "Member's Club",
13
- "amount": 100,
14
- "currency": "usd",
15
- "id": "fkx0AFo_00000000000000",
16
- "object": "plan",
17
- "livemode": false,
18
- "interval_count": 1,
19
- "trial_period_days": null
10
+ "items": {
11
+ "object": "list",
12
+ "data": [{
13
+ "id": "si_00000000000000",
14
+ "object": "subscription_item",
15
+ "created": 1497881783,
16
+ "plan": {
17
+ "interval": "month",
18
+ "name": "Member's Club",
19
+ "amount": 100,
20
+ "currency": "usd",
21
+ "id": "fkx0AFo_00000000000000",
22
+ "object": "plan",
23
+ "livemode": false,
24
+ "interval_count": 1,
25
+ "trial_period_days": null,
26
+ "metadata": {}
27
+ },
28
+ "quantity": 1
29
+ },
30
+ {
31
+ "id": "si_00000000000001",
32
+ "object": "subscription_item",
33
+ "created": 1497881788,
34
+ "plan": {
35
+ "interval": "month",
36
+ "name": "Vistor's Club",
37
+ "amount": 200,
38
+ "currency": "eur",
39
+ "id": "fkx0AFo_00000000000001",
40
+ "object": "plan",
41
+ "livemode": false,
42
+ "interval_count": 1,
43
+ "trial_period_days": null,
44
+ "metadata": {}
45
+ },
46
+ "quantity": 5
47
+ }
48
+ ]
20
49
  },
21
50
  "object": "subscription",
22
51
  "start": 1381080623,