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
@@ -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)