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
@@ -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": 1381080561,
@@ -6,100 +6,107 @@
6
6
  "object": "event",
7
7
  "data": {
8
8
  "object": {
9
- "date": 1394018368,
10
9
  "id": "in_00000000000000",
11
- "period_start": 1394018368,
12
- "period_end": 1394018368,
10
+ "object": "invoice",
11
+ "amount_due": 999,
12
+ "application_fee": null,
13
+ "attempt_count": 1,
14
+ "attempted": true,
15
+ "charge": "ch_18EcOcLrgDIZ7iq8TaNlErVv",
16
+ "closed": true,
17
+ "currency": "eur",
18
+ "customer": "cus_00000000000000",
19
+ "date": 1464084258,
20
+ "description": null,
21
+ "discount": null,
22
+ "ending_balance": 0,
23
+ "forgiven": false,
13
24
  "lines": {
14
- "object": "list",
15
- "count": 3,
16
- "url": "/v1/invoices/in_00000000000000/lines",
17
- "data": [
18
- {
19
- "id": "ii_00000000000000",
20
- "object": "line_item",
21
- "type": "invoiceitem",
22
- "livemode": false,
23
- "amount": 19000,
24
- "currency": "usd",
25
- "proration": true,
26
- "period": {
27
- "start": 1393765661,
28
- "end": 1393765661
29
- },
30
- "quantity": null,
31
- "plan": null,
32
- "description": "Remaining time on Platinum after 02 Mar 2014",
33
- "metadata": {}
25
+ "data": [{
26
+ "id": "sub_00000000000000",
27
+ "object": "line_item",
28
+ "amount": 50,
29
+ "currency": "eur",
30
+ "description": null,
31
+ "discountable": true,
32
+ "livemode": true,
33
+ "metadata": {},
34
+ "period": {
35
+ "start": 1500637196,
36
+ "end": 1532173196
34
37
  },
35
- {
36
- "id": "ii_00000000000001",
37
- "object": "line_item",
38
- "type": "invoiceitem",
38
+ "plan": {
39
+ "id": "platinum",
40
+ "object": "plan",
41
+ "amount": 500,
42
+ "created": 1499943145,
43
+ "currency": "eur",
44
+ "interval": "month",
45
+ "interval_count": 1,
39
46
  "livemode": false,
40
- "amount": -9000,
41
- "currency": "usd",
42
- "proration": true,
43
- "period": {
44
- "start": 1393765661,
45
- "end": 1393765661
46
- },
47
- "quantity": null,
48
- "plan": null,
49
- "description": "Unused time on Gold after 05 Mar 2014",
50
- "metadata": {}
47
+ "metadata": {},
48
+ "name": "New Plan Test",
49
+ "statement_descriptor": null,
50
+ "trial_period_days": null
51
+ },
52
+ "proration": false,
53
+ "quantity": 1,
54
+ "subscription": null,
55
+ "subscription_item": "si_18ZfWyLrgDIZ7iq8fSlSNGIV",
56
+ "type": "subscription"
57
+ },
58
+ {
59
+ "id": "sub_00000000000000",
60
+ "object": "line_item",
61
+ "amount": 50,
62
+ "currency": "eur",
63
+ "description": null,
64
+ "discountable": true,
65
+ "livemode": true,
66
+ "metadata": {},
67
+ "period": {
68
+ "start": 1500637196,
69
+ "end": 1532173196
51
70
  },
52
- {
53
- "id": "su_00000000000000",
54
- "object": "line_item",
55
- "type": "subscription",
71
+ "plan": {
72
+ "id": "gold",
73
+ "object": "plan",
74
+ "amount": 300,
75
+ "created": 1499943155,
76
+ "currency": "eur",
77
+ "interval": "month",
78
+ "interval_count": 1,
56
79
  "livemode": false,
57
- "amount": 20000,
58
- "currency": "usd",
59
- "proration": false,
60
- "period": {
61
- "start": 1383759053,
62
- "end": 1386351053
63
- },
64
- "quantity": 1,
65
- "plan": {
66
- "interval": "month",
67
- "name": "Platinum",
68
- "created": 1300000000,
69
- "amount": 20000,
70
- "currency": "usd",
71
- "id": "platinum",
72
- "object": "plan",
73
- "livemode": false,
74
- "interval_count": 1,
75
- "trial_period_days": null,
76
- "metadata": {}
77
- },
78
- "description": null,
79
- "metadata": null
80
- }
81
- ]
80
+ "metadata": {},
81
+ "name": "New gold Plan Test",
82
+ "statement_descriptor": null,
83
+ "trial_period_days": null
84
+ },
85
+ "proration": false,
86
+ "quantity": 1,
87
+ "subscription": null,
88
+ "subscription_item": "si_18ZfWyLrgDIZ7iq8fSlSNGIV",
89
+ "type": "subscription"
90
+ }],
91
+ "total_count": 1,
92
+ "object": "list",
93
+ "url": "/v1/invoices/in_18EcOcLrgDIZ7iq8zsDkunZ0/lines"
82
94
  },
83
- "subtotal": 30000,
84
- "total": 30000,
85
- "customer": "cus_00000000000000",
86
- "object": "invoice",
87
- "attempted": true,
88
- "closed": true,
89
- "paid": true,
90
95
  "livemode": false,
91
- "attempt_count": 1,
92
- "amount_due": 0,
93
- "currency": "usd",
94
- "starting_balance": 0,
95
- "ending_balance": 0,
96
- "next_payment_attempt": null,
97
- "charge": "ch_00000000000000",
98
- "discount": null,
99
- "application_fee": null,
100
- "subscription": "su_00000000000000",
101
96
  "metadata": {},
102
- "description": null
97
+ "next_payment_attempt": null,
98
+ "paid": true,
99
+ "period_end": 1464084258,
100
+ "period_start": 1464084258,
101
+ "receipt_number": null,
102
+ "starting_balance": 0,
103
+ "statement_descriptor": null,
104
+ "subscription": "sub_00000000000000",
105
+ "subtotal": 999,
106
+ "tax": null,
107
+ "tax_percent": null,
108
+ "total": 999,
109
+ "webhooks_delivered_at": 1464084258
103
110
  }
104
111
  }
105
112
  }
@@ -49,6 +49,14 @@ shared_examples 'Account API' do
49
49
 
50
50
  expect(account.support_phone).to eq '1234567'
51
51
  end
52
+
53
+ it 'raises when sending an empty tos date' do
54
+ account = Stripe::Account.retrieve
55
+ account.tos_acceptance.date = nil
56
+ expect {
57
+ account.save
58
+ }.to raise_error
59
+ end
52
60
  end
53
61
 
54
62
  it 'deauthorizes the stripe account', live: false do
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ shared_examples 'Balance API' do
4
+
5
+ it "retrieves a stripe balance" do
6
+ StripeMock.set_account_balance(2000)
7
+ balance = Stripe::Balance.retrieve()
8
+ expect(balance.available[0].amount).to eq(2000)
9
+ end
10
+
11
+ end
@@ -199,4 +199,31 @@ shared_examples 'Bank API' do
199
199
  end
200
200
  end
201
201
 
202
+ describe 'Stripe::Token creation from bank account' do
203
+ it 'generates token from bank account informations' do
204
+ token = Stripe::Token.create({
205
+ bank_account: {
206
+ account_number: "4222222222222222",
207
+ routing_number: "123456",
208
+ bank_name: "Fake bank"
209
+ }
210
+ })
211
+
212
+ cus = Stripe::Customer.create(source: token.id)
213
+ bank_account = cus.sources.data.first
214
+ expect(bank_account.bank_name).to eq('Fake bank')
215
+ end
216
+
217
+ it 'generates token from existing bank account token' do
218
+ bank_token = StripeMock.generate_bank_token(bank_name: 'Fake bank')
219
+ cus = Stripe::Customer.create(source: bank_token)
220
+ token = Stripe::Token.create({ customer: cus.id, bank_account: cus.sources.first.id })
221
+ cus.sources.create(source: token.id)
222
+ cus = Stripe::Customer.retrieve(cus.id)
223
+ expect(cus.sources.data.count).to eq 2
224
+ cus.sources.data.each do |source|
225
+ expect(source.bank_name).to eq('Fake bank')
226
+ end
227
+ end
228
+ end
202
229
  end
@@ -3,6 +3,8 @@ require 'pp'
3
3
 
4
4
  shared_examples 'Dispute API' do
5
5
 
6
+ let(:stripe_helper) { StripeMock.create_test_helper }
7
+
6
8
  it "returns an error if dispute does not exist" do
7
9
  dispute_id = 'dp_xxxxxxxxxxxxxxxxxxxxxxxx'
8
10
 
@@ -85,4 +87,12 @@ shared_examples 'Dispute API' do
85
87
 
86
88
  end
87
89
 
90
+ it "creates a dispute" do
91
+ card_token = stripe_helper.generate_card_token(last4: "1123", exp_month: 11, exp_year: 2099)
92
+ charge = Stripe::Charge.create(amount: 1000, currency: "usd", source: card_token)
93
+ stripe_dispute_id = stripe_helper.upsert_stripe_object(:dispute, {amount: charge.amount, charge: charge.id})
94
+ stripe_dispute = Stripe::Dispute.retrieve(stripe_dispute_id)
95
+ expect(stripe_dispute.charge).to eq(charge.id)
96
+ end
97
+
88
98
  end
@@ -248,18 +248,71 @@ shared_examples 'Invoice API' do
248
248
 
249
249
  [false, true].each do |with_trial|
250
250
  describe "prorating a subscription with a new plan, with_trial: #{with_trial}" do
251
- let!(:new_plan) { Stripe::Plan.create(id: '100y', amount: 10000, interval: 'year', name: '100y', currency: 'usd') }
251
+ let(:new_monthly_plan) { @teardown_monthly_plan = true; Stripe::Plan.create(id: '100m', amount: 100_00, interval: 'month', name: '100m', currency: 'usd') }
252
+ let(:new_yearly_plan) { @teardown_yearly_plan = true; Stripe::Plan.create(id: '100y', amount: 100_00, interval: 'year', name: '100y', currency: 'usd') }
252
253
 
253
- it 'prorates', live: true do
254
+ it 'prorates while maintaining billing interval', live: true do
254
255
  # Given
255
256
  proration_date = Time.now + 5 * 24 * 3600 # 5 days later
256
257
  new_quantity = 2
257
258
  unused_amount = plan.amount * quantity * (subscription.current_period_end - proration_date.to_i) / (subscription.current_period_end - subscription.current_period_start)
258
- prorated_amount_due = new_plan.amount * new_quantity - unused_amount
259
+ remaining_amount = new_monthly_plan.amount * new_quantity * (subscription.current_period_end - proration_date.to_i) / (subscription.current_period_end - subscription.current_period_start)
260
+ prorated_amount_due = new_monthly_plan.amount * new_quantity - unused_amount + remaining_amount
259
261
  credit_balance = 1000
260
262
  customer.account_balance = -credit_balance
261
263
  customer.save
262
- query = { customer: customer.id, subscription: subscription.id, subscription_plan: new_plan.id, subscription_proration_date: proration_date.to_i, subscription_quantity: new_quantity }
264
+ query = { customer: customer.id, subscription: subscription.id, subscription_plan: new_monthly_plan.id, subscription_proration_date: proration_date.to_i, subscription_quantity: new_quantity }
265
+ query[:subscription_trial_end] = (DateTime.now >> 1).to_time.to_i if with_trial
266
+
267
+ # When
268
+ upcoming = Stripe::Invoice.upcoming(query)
269
+
270
+ # Then
271
+ expect(upcoming).to be_a Stripe::Invoice
272
+ expect(upcoming.customer).to eq(customer.id)
273
+ if with_trial
274
+ expect(upcoming.amount_due).to be_within(1).of 0
275
+ else
276
+ expect(upcoming.amount_due).to be_within(1).of prorated_amount_due - credit_balance
277
+ end
278
+ expect(upcoming.starting_balance).to eq -credit_balance
279
+ expect(upcoming.ending_balance).to be_nil
280
+ expect(upcoming.subscription).to eq(subscription.id)
281
+
282
+ if with_trial
283
+ expect(upcoming.lines.data.length).to eq(2)
284
+ else
285
+ expect(upcoming.lines.data.length).to eq(3)
286
+ end
287
+
288
+ expect(upcoming.lines.data[0].proration).to be_truthy
289
+ expect(upcoming.lines.data[0].plan.id).to eq '50m'
290
+ expect(upcoming.lines.data[0].amount).to be_within(1).of -unused_amount
291
+ expect(upcoming.lines.data[0].quantity).to eq quantity
292
+
293
+ unless with_trial
294
+ expect(upcoming.lines.data[1].proration).to be_truthy
295
+ expect(upcoming.lines.data[1].plan.id).to eq '100m'
296
+ expect(upcoming.lines.data[1].amount).to be_within(1).of remaining_amount
297
+ expect(upcoming.lines.data[1].quantity).to eq new_quantity
298
+ end
299
+
300
+ expect(upcoming.lines.data.last.proration).to be_falsey
301
+ expect(upcoming.lines.data.last.plan.id).to eq '100m'
302
+ expect(upcoming.lines.data.last.amount).to eq with_trial ? 0 : 20000
303
+ expect(upcoming.lines.data.last.quantity).to eq new_quantity
304
+ end
305
+
306
+ it 'prorates while changing billing intervals', live: true do
307
+ # Given
308
+ proration_date = Time.now + 5 * 24 * 3600 # 5 days later
309
+ new_quantity = 2
310
+ unused_amount = plan.amount * quantity * (subscription.current_period_end - proration_date.to_i) / (subscription.current_period_end - subscription.current_period_start)
311
+ prorated_amount_due = new_yearly_plan.amount * new_quantity - unused_amount
312
+ credit_balance = 1000
313
+ customer.account_balance = -credit_balance
314
+ customer.save
315
+ query = { customer: customer.id, subscription: subscription.id, subscription_plan: new_yearly_plan.id, subscription_proration_date: proration_date.to_i, subscription_quantity: new_quantity }
263
316
  query[:subscription_trial_end] = (DateTime.now >> 1).to_time.to_i if with_trial
264
317
 
265
318
  # When
@@ -276,17 +329,20 @@ shared_examples 'Invoice API' do
276
329
  expect(upcoming.starting_balance).to eq -credit_balance
277
330
  expect(upcoming.ending_balance).to be_nil
278
331
  expect(upcoming.subscription).to eq(subscription.id)
332
+
279
333
  expect(upcoming.lines.data[0].proration).to be_truthy
280
334
  expect(upcoming.lines.data[0].plan.id).to eq '50m'
281
335
  expect(upcoming.lines.data[0].amount).to be_within(1).of -unused_amount
282
336
  expect(upcoming.lines.data[0].quantity).to eq quantity
337
+
283
338
  expect(upcoming.lines.data[1].proration).to be_falsey
284
339
  expect(upcoming.lines.data[1].plan.id).to eq '100y'
285
340
  expect(upcoming.lines.data[1].amount).to eq with_trial ? 0 : 20000
286
341
  expect(upcoming.lines.data[1].quantity).to eq new_quantity
287
342
  end
288
343
 
289
- after { new_plan.delete }
344
+ after { new_monthly_plan.delete rescue nil if @teardown_monthly_plan }
345
+ after { new_yearly_plan.delete rescue nil if @teardown_yearly_plan }
290
346
  end
291
347
  end
292
348
 
@@ -362,6 +418,12 @@ shared_examples 'Invoice API' do
362
418
  expect(@upcoming.subscription).to eq(@shortsub.id)
363
419
  end
364
420
 
421
+ it 'does not store the stripe invoice in memory since its only a preview', with_subscription: true do
422
+ invoice = Stripe::Invoice.upcoming(customer: customer.id)
423
+ data = test_data_source(:invoices)
424
+ expect(data[invoice.id]).to be_nil
425
+ end
426
+
365
427
  context 'retrieving invoice line items' do
366
428
  it 'returns all line items for created invoice' do
367
429
  invoice = Stripe::Invoice.create(customer: customer.id)
@@ -378,7 +440,7 @@ shared_examples 'Invoice API' do
378
440
  plan = stripe_helper.create_plan()
379
441
  subscription = Stripe::Subscription.create(plan: plan.id, customer: customer.id)
380
442
  upcoming = Stripe::Invoice.upcoming(customer: customer.id)
381
- line_items = upcoming.lines.all
443
+ line_items = upcoming.lines
382
444
 
383
445
  expect(upcoming).to be_a Stripe::Invoice
384
446
  expect(line_items.count).to eq(1)