stripe-ruby-mock 2.5.0 → 2.5.1

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 (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,