stripe-ruby-mock 2.3.1 → 2.5.8

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 (106) hide show
  1. checksums.yaml +4 -4
  2. data/.env +2 -0
  3. data/.travis.yml +8 -4
  4. data/README.md +12 -5
  5. data/lib/stripe_mock/api/account_balance.rb +14 -0
  6. data/lib/stripe_mock/api/client.rb +4 -4
  7. data/lib/stripe_mock/api/conversion_rate.rb +14 -0
  8. data/lib/stripe_mock/api/errors.rb +25 -13
  9. data/lib/stripe_mock/api/instance.rb +16 -6
  10. data/lib/stripe_mock/api/webhooks.rb +8 -1
  11. data/lib/stripe_mock/client.rb +18 -2
  12. data/lib/stripe_mock/data/list.rb +14 -2
  13. data/lib/stripe_mock/data.rb +398 -58
  14. data/lib/stripe_mock/instance.rb +105 -9
  15. data/lib/stripe_mock/request_handlers/accounts.rb +41 -2
  16. data/lib/stripe_mock/request_handlers/balance.rb +17 -0
  17. data/lib/stripe_mock/request_handlers/balance_transactions.rb +18 -2
  18. data/lib/stripe_mock/request_handlers/charges.rb +44 -33
  19. data/lib/stripe_mock/request_handlers/country_spec.rb +22 -0
  20. data/lib/stripe_mock/request_handlers/coupons.rb +5 -4
  21. data/lib/stripe_mock/request_handlers/customers.rb +29 -11
  22. data/lib/stripe_mock/request_handlers/ephemeral_key.rb +13 -0
  23. data/lib/stripe_mock/request_handlers/external_accounts.rb +55 -0
  24. data/lib/stripe_mock/request_handlers/helpers/bank_account_helpers.rb +1 -1
  25. data/lib/stripe_mock/request_handlers/helpers/card_helpers.rb +9 -7
  26. data/lib/stripe_mock/request_handlers/helpers/coupon_helpers.rb +10 -6
  27. data/lib/stripe_mock/request_handlers/helpers/external_account_helpers.rb +49 -0
  28. data/lib/stripe_mock/request_handlers/helpers/subscription_helpers.rb +59 -16
  29. data/lib/stripe_mock/request_handlers/helpers/token_helpers.rb +3 -2
  30. data/lib/stripe_mock/request_handlers/invoices.rb +93 -14
  31. data/lib/stripe_mock/request_handlers/orders.rb +5 -5
  32. data/lib/stripe_mock/request_handlers/payouts.rb +32 -0
  33. data/lib/stripe_mock/request_handlers/plans.rb +1 -0
  34. data/lib/stripe_mock/request_handlers/products.rb +43 -0
  35. data/lib/stripe_mock/request_handlers/recipients.rb +12 -0
  36. data/lib/stripe_mock/request_handlers/refunds.rb +91 -0
  37. data/lib/stripe_mock/request_handlers/subscription_items.rb +36 -0
  38. data/lib/stripe_mock/request_handlers/subscriptions.rb +101 -39
  39. data/lib/stripe_mock/request_handlers/tax_rates.rb +36 -0
  40. data/lib/stripe_mock/request_handlers/tokens.rb +9 -3
  41. data/lib/stripe_mock/request_handlers/transfers.rb +11 -5
  42. data/lib/stripe_mock/request_handlers/validators/param_validators.rb +15 -1
  43. data/lib/stripe_mock/server.rb +14 -1
  44. data/lib/stripe_mock/test_strategies/base.rb +10 -5
  45. data/lib/stripe_mock/test_strategies/live.rb +5 -0
  46. data/lib/stripe_mock/test_strategies/mock.rb +8 -0
  47. data/lib/stripe_mock/util.rb +8 -2
  48. data/lib/stripe_mock/version.rb +1 -1
  49. data/lib/stripe_mock/webhook_fixtures/account.external_account.created.json +27 -0
  50. data/lib/stripe_mock/webhook_fixtures/account.external_account.deleted.json +27 -0
  51. data/lib/stripe_mock/webhook_fixtures/account.external_account.updated.json +27 -0
  52. data/lib/stripe_mock/webhook_fixtures/account.updated.json +1 -1
  53. data/lib/stripe_mock/webhook_fixtures/charge.dispute.funds_reinstated.json +88 -0
  54. data/lib/stripe_mock/webhook_fixtures/charge.dispute.funds_withdrawn.json +88 -0
  55. data/lib/stripe_mock/webhook_fixtures/charge.updated.json +58 -0
  56. data/lib/stripe_mock/webhook_fixtures/customer.subscription.created.json +40 -10
  57. data/lib/stripe_mock/webhook_fixtures/customer.subscription.deleted.json +39 -10
  58. data/lib/stripe_mock/webhook_fixtures/customer.subscription.trial_will_end.json +39 -10
  59. data/lib/stripe_mock/webhook_fixtures/customer.subscription.updated.json +40 -11
  60. data/lib/stripe_mock/webhook_fixtures/invoice.created.json +3 -2
  61. data/lib/stripe_mock/webhook_fixtures/invoice.payment_failed.json +1 -1
  62. data/lib/stripe_mock/webhook_fixtures/invoice.payment_succeeded.json +92 -85
  63. data/lib/stripe_mock/webhook_fixtures/invoice.updated.json +3 -2
  64. data/lib/stripe_mock/webhook_fixtures/plan.created.json +1 -1
  65. data/lib/stripe_mock/webhook_fixtures/plan.deleted.json +1 -1
  66. data/lib/stripe_mock/webhook_fixtures/plan.updated.json +1 -1
  67. data/lib/stripe_mock.rb +15 -0
  68. data/spec/api/instance_spec.rb +30 -0
  69. data/spec/instance_spec.rb +54 -4
  70. data/spec/integration_examples/prepare_error_examples.rb +6 -6
  71. data/spec/list_spec.rb +27 -10
  72. data/spec/readme_spec.rb +2 -0
  73. data/spec/server_spec.rb +7 -3
  74. data/spec/shared_stripe_examples/account_examples.rb +46 -0
  75. data/spec/shared_stripe_examples/balance_examples.rb +11 -0
  76. data/spec/shared_stripe_examples/balance_transaction_examples.rb +28 -0
  77. data/spec/shared_stripe_examples/bank_examples.rb +28 -1
  78. data/spec/shared_stripe_examples/card_examples.rb +23 -5
  79. data/spec/shared_stripe_examples/card_token_examples.rb +1 -0
  80. data/spec/shared_stripe_examples/charge_examples.rb +131 -26
  81. data/spec/shared_stripe_examples/country_specs_examples.rb +18 -0
  82. data/spec/shared_stripe_examples/coupon_examples.rb +8 -2
  83. data/spec/shared_stripe_examples/customer_examples.rb +90 -0
  84. data/spec/shared_stripe_examples/dispute_examples.rb +19 -8
  85. data/spec/shared_stripe_examples/ephemeral_key_examples.rb +17 -0
  86. data/spec/shared_stripe_examples/error_mock_examples.rb +15 -5
  87. data/spec/shared_stripe_examples/external_account_examples.rb +170 -0
  88. data/spec/shared_stripe_examples/extra_features_examples.rb +2 -0
  89. data/spec/shared_stripe_examples/invoice_examples.rb +314 -51
  90. data/spec/shared_stripe_examples/payout_examples.rb +68 -0
  91. data/spec/shared_stripe_examples/plan_examples.rb +47 -4
  92. data/spec/shared_stripe_examples/product_example.rb +65 -0
  93. data/spec/shared_stripe_examples/recipient_examples.rb +13 -7
  94. data/spec/shared_stripe_examples/refund_examples.rb +453 -84
  95. data/spec/shared_stripe_examples/subscription_examples.rb +477 -32
  96. data/spec/shared_stripe_examples/subscription_items_examples.rb +75 -0
  97. data/spec/shared_stripe_examples/tax_rate_examples.rb +42 -0
  98. data/spec/shared_stripe_examples/transfer_examples.rb +72 -23
  99. data/spec/shared_stripe_examples/webhook_event_examples.rb +74 -5
  100. data/spec/spec_helper.rb +7 -6
  101. data/spec/stripe_mock_spec.rb +16 -3
  102. data/spec/support/stripe_examples.rb +8 -1
  103. data/spec/util_spec.rb +35 -1
  104. data/stripe-ruby-mock.gemspec +1 -1
  105. metadata +44 -8
  106. data/ChangeLog.rdoc +0 -4
@@ -52,7 +52,7 @@ shared_examples 'Invoice API' do
52
52
  end
53
53
 
54
54
  it "stores all invoices in memory" do
55
- expect(Stripe::Invoice.all.map(&:id)).to eq([@invoice.id, @invoice2.id])
55
+ expect(Stripe::Invoice.all.map(&:id).sort).to eq([@invoice.id, @invoice2.id].sort)
56
56
  end
57
57
 
58
58
  it "defaults count to 10 invoices" do
@@ -76,57 +76,111 @@ shared_examples 'Invoice API' do
76
76
  context "paying an invoice" do
77
77
  before do
78
78
  @invoice = Stripe::Invoice.create
79
- @invoice.pay
80
79
  end
81
80
 
82
81
  it 'updates attempted and paid flags' do
82
+ @invoice = @invoice.pay
83
83
  expect(@invoice.attempted).to eq(true)
84
84
  expect(@invoice.paid).to eq(true)
85
85
  end
86
86
 
87
+ it 'creates a new charge object' do
88
+ expect{ @invoice.pay }.to change { Stripe::Charge.list.data.count }.by 1
89
+ end
90
+
87
91
  it 'sets the charge attribute' do
92
+ @invoice = @invoice.pay
88
93
  expect(@invoice.charge).to be_a String
89
94
  expect(@invoice.charge.length).to be > 0
90
95
  end
96
+
97
+ it 'charges the invoice customers default card' do
98
+ customer = Stripe::Customer.create({
99
+ source: stripe_helper.generate_card_token
100
+ })
101
+ customer_invoice = Stripe::Invoice.create({customer: customer})
102
+
103
+ customer_invoice.pay
104
+
105
+ expect(Stripe::Charge.list.data.first.customer).to eq customer.id
106
+ end
91
107
  end
92
108
 
93
109
  context "retrieving upcoming invoice" do
94
- before do
95
- @customer = Stripe::Customer.create(email: 'johnny@appleseed.com', source: stripe_helper.generate_card_token)
96
- end
110
+ let(:customer) { Stripe::Customer.create(source: stripe_helper.generate_card_token) }
111
+ let(:coupon_amtoff) { stripe_helper.create_coupon(id: '100OFF', currency: 'usd', amount_off: 100_00, duration: 'repeating', duration_in_months: 6) }
112
+ let(:coupon_pctoff) { stripe_helper.create_coupon(id: '50%OFF', currency: 'usd', percent_off: 50, amount_off: nil, duration: 'repeating', duration_in_months: 6) }
113
+ let(:plan) { stripe_helper.create_plan(id: '50m', amount: 50_00, interval: 'month', name: '50m', currency: 'usd') }
114
+ let(:quantity) { 3 }
115
+ let(:subscription) { Stripe::Subscription.create(plan: plan.id, customer: customer.id, quantity: quantity) }
116
+
117
+ before(with_customer: true) { customer }
118
+ before(with_coupon_amtoff: true) { coupon_amtoff }
119
+ before(with_coupon_pctoff: true) { coupon_pctoff }
120
+ before(with_discount_amtoff: true) { customer.coupon = coupon_amtoff.id; customer.save }
121
+ before(with_discount_pctoff: true) { customer.coupon = coupon_pctoff.id; customer.save }
122
+ before(with_plan: true) { plan }
123
+ before(with_subscription: true) { subscription }
124
+
125
+ # after { subscription.delete rescue nil if @teardown_subscription }
126
+ # after { plan.delete rescue nil if @teardown_plan }
127
+ # after { coupon_pctoff.delete rescue nil if @teardown_coupon_pctoff }
128
+ # after { coupon_amtoff.delete rescue nil if @teardown_coupon_amtoff }
129
+ # after { customer.delete rescue nil if @teardown_customer }
130
+
131
+ describe 'parameter validation' do
132
+ it 'fails without parameters' do
133
+ expect { Stripe::Invoice.upcoming() }.to raise_error {|e|
134
+ expect(e).to be_a(ArgumentError) }
135
+ end
97
136
 
98
- it 'fails without parameters' do
99
- expect { Stripe::Invoice.upcoming() }.to raise_error {|e|
100
- expect(e).to be_a(ArgumentError) }
101
- end
137
+ it 'fails without a valid customer' do
138
+ expect { Stripe::Invoice.upcoming(customer: 'whatever') }.to raise_error {|e|
139
+ expect(e).to be_a(Stripe::InvalidRequestError)
140
+ expect(e.message).to eq('No such customer: whatever') }
141
+ end
102
142
 
103
- it 'fails without a valid customer' do
104
- expect { Stripe::Invoice.upcoming(customer: 'whatever') }.to raise_error {|e|
105
- expect(e).to be_a(Stripe::InvalidRequestError)
106
- expect(e.message).to eq('No such customer: whatever') }
107
- end
143
+ it 'fails without a customer parameter' do
144
+ expect { Stripe::Invoice.upcoming(gazebo: 'raindance') }.to raise_error {|e|
145
+ expect(e).to be_a(Stripe::InvalidRequestError)
146
+ expect(e.http_status).to eq(400)
147
+ expect(e.message).to eq('Missing required param: customer') }
148
+ end
108
149
 
109
- it 'fails without a customer parameter' do
110
- expect { Stripe::Invoice.upcoming(gazebo: 'raindance') }.to raise_error {|e|
111
- expect(e).to be_a(Stripe::InvalidRequestError)
112
- expect(e.http_status).to eq(400)
113
- expect(e.message).to eq('Missing required param: customer') }
150
+ it 'fails without a subscription' do
151
+ expect { Stripe::Invoice.upcoming(customer: customer.id) }.to raise_error {|e|
152
+ expect(e).to be_a(Stripe::InvalidRequestError)
153
+ expect(e.http_status).to eq(404)
154
+ expect(e.message).to eq("No upcoming invoices for customer: #{customer.id}") }
155
+ end
114
156
  end
115
157
 
116
- it 'fails without a subscription' do
117
- expect { Stripe::Invoice.upcoming(customer: @customer.id) }.to raise_error {|e|
118
- expect(e).to be_a(Stripe::InvalidRequestError)
119
- expect(e.http_status).to eq(404)
120
- expect(e.message).to eq("No upcoming invoices for customer: #{@customer.id}") }
158
+ describe 'parameter validation' do
159
+ it 'fails without a subscription or subscription plan if subscription proration date is specified', live: true do
160
+ expect { Stripe::Invoice.upcoming(customer: customer.id, subscription_proration_date: Time.now.to_i) }.to raise_error do |e|
161
+ expect(e).to be_a Stripe::InvalidRequestError
162
+ expect(e.http_status).to eq 400
163
+ expect(e.message).to eq 'When previewing changes to a subscription, you must specify either `subscription` or `subscription_items`'
164
+ end
165
+ end
166
+
167
+ it 'fails without a subscription if proration date is specified', live: true, with_subscription: true do
168
+ expect { Stripe::Invoice.upcoming(customer: customer.id, subscription_plan: plan.id, subscription_proration_date: Time.now.to_i) }.to raise_error do |e|
169
+ expect(e).to be_a Stripe::InvalidRequestError
170
+ expect(e.http_status).to eq 400
171
+ expect(e.message).to eq 'Cannot specify proration date without specifying a subscription'
172
+ end
173
+ end
121
174
  end
122
175
 
123
- it 'works when customer has a subscription', :live => true do
124
- plan = stripe_helper.create_plan(:id => 'has_sub')
125
- subscription = Stripe::Subscription.create(plan: plan.id, customer: @customer.id)
126
- upcoming = Stripe::Invoice.upcoming(customer: @customer.id)
176
+ it 'considers current subscription', live: true, with_subscription: true do
177
+ # When
178
+ upcoming = Stripe::Invoice.upcoming(customer: customer.id)
127
179
 
180
+ # Then
128
181
  expect(upcoming).to be_a Stripe::Invoice
129
- expect(upcoming.customer).to eq(@customer.id)
182
+ expect(upcoming.customer).to eq(customer.id)
183
+ expect(upcoming.amount_due).to eq plan.amount * quantity
130
184
  expect(upcoming.total).to eq(upcoming.lines.data[0].amount)
131
185
  expect(upcoming.period_end).to eq(upcoming.lines.data[0].period.start)
132
186
  expect(Time.at(upcoming.period_start).to_datetime >> 1).to eq(Time.at(upcoming.period_end).to_datetime) # +1 month
@@ -135,10 +189,213 @@ shared_examples 'Invoice API' do
135
189
  expect(upcoming.subscription).to eq(subscription.id)
136
190
  end
137
191
 
192
+ describe 'discounts' do
193
+ it 'considers a $ off discount', live: true, with_discount_amtoff: true, with_subscription: true do
194
+ # When
195
+ upcoming = Stripe::Invoice.upcoming(customer: customer.id)
196
+
197
+ # Then
198
+ expect(upcoming.discount).not_to be_nil
199
+ expect(upcoming.discount.coupon.id).to eq '100OFF'
200
+ expect(upcoming.discount.customer).to eq customer.id
201
+ expect(upcoming.discount.start).to be_within(5).of Time.now.to_i
202
+ expect(upcoming.discount.end).to be_within(5).of (Time.now.to_datetime >> 6).to_time.to_i
203
+ expect(upcoming.amount_due).to eq plan.amount * quantity - 100_00
204
+ expect(upcoming.subtotal).to eq(upcoming.lines.data[0].amount)
205
+ expect(upcoming.total).to eq upcoming.subtotal - 100_00
206
+ end
207
+
208
+ it 'considers a % off discount', live: true, with_discount_pctoff: true, with_subscription: true do
209
+ # When
210
+ upcoming = Stripe::Invoice.upcoming(customer: customer.id)
211
+
212
+ # Then
213
+ expect(upcoming.discount).not_to be_nil
214
+ expect(upcoming.discount.coupon.id).to eq '50%OFF'
215
+ expect(upcoming.discount.customer).to eq customer.id
216
+ expect(upcoming.discount.start).to be_within(5).of Time.now.to_i
217
+ expect(upcoming.discount.end).to be_within(5).of (Time.now.to_datetime >> 6).to_time.to_i
218
+ expect(upcoming.amount_due).to eq (plan.amount * quantity) * 0.5
219
+ expect(upcoming.subtotal).to eq(upcoming.lines.data[0].amount)
220
+ expect(upcoming.total).to eq upcoming.subtotal * 0.5
221
+ end
222
+ end
223
+
224
+ describe 'proration' do
225
+ shared_examples 'failing when proration date is outside of the subscription current period' do
226
+ it 'fails', live: true do
227
+ expect { Stripe::Invoice.upcoming(
228
+ customer: customer.id,
229
+ subscription: subscription.id,
230
+ subscription_plan: plan.id,
231
+ subscription_quantity: quantity,
232
+ subscription_proration_date: proration_date.to_i,
233
+ subscription_trial_end: nil
234
+ ) }.to raise_error {|e|
235
+ expect(e).to be_a(Stripe::InvalidRequestError)
236
+ expect(e.http_status).to eq(400)
237
+ expect(e.message).to eq('Cannot specify proration date outside of current subscription period') }
238
+ end
239
+ end
240
+
241
+ it_behaves_like 'failing when proration date is outside of the subscription current period' do
242
+ let(:proration_date) { subscription.current_period_start - 1 }
243
+ end
244
+
245
+ it_behaves_like 'failing when proration date is outside of the subscription current period' do
246
+ let(:proration_date) { subscription.current_period_end + 1 }
247
+ end
248
+
249
+ [false, true].each do |with_trial|
250
+ describe "prorating a subscription with a new plan, with_trial: #{with_trial}" do
251
+ let(:new_monthly_plan) { stripe_helper.create_plan(id: '100m', amount: 100_00, interval: 'month', name: '100m', currency: 'usd') }
252
+ let(:new_yearly_plan) { stripe_helper.create_plan(id: '100y', amount: 100_00, interval: 'year', name: '100y', currency: 'usd') }
253
+ let(:plan) { stripe_helper.create_plan(id: '50m', amount: 50_00, interval: 'month', name: '50m', currency: 'usd') }
254
+
255
+ it 'prorates while maintaining billing interval', live: true do
256
+ # Given
257
+ proration_date = Time.now + 5 * 24 * 3600 # 5 days later
258
+ new_quantity = 2
259
+ unused_amount = plan.amount * quantity * (subscription.current_period_end - proration_date.to_i) / (subscription.current_period_end - subscription.current_period_start)
260
+ remaining_amount = new_monthly_plan.amount * new_quantity * (subscription.current_period_end - proration_date.to_i) / (subscription.current_period_end - subscription.current_period_start)
261
+ prorated_amount_due = new_monthly_plan.amount * new_quantity - unused_amount + remaining_amount
262
+ credit_balance = 1000
263
+ customer.account_balance = -credit_balance
264
+ customer.save
265
+ query = { customer: customer.id, subscription: subscription.id, subscription_plan: new_monthly_plan.id, subscription_proration_date: proration_date.to_i, subscription_quantity: new_quantity }
266
+ query[:subscription_trial_end] = (DateTime.now >> 1).to_time.to_i if with_trial
267
+
268
+ # When
269
+ upcoming = Stripe::Invoice.upcoming(query)
270
+
271
+ # Then
272
+ expect(upcoming).to be_a Stripe::Invoice
273
+ expect(upcoming.customer).to eq(customer.id)
274
+ if with_trial
275
+ expect(upcoming.amount_due).to be_within(1).of 0
276
+ else
277
+ expect(upcoming.amount_due).to be_within(1).of prorated_amount_due - credit_balance
278
+ end
279
+ expect(upcoming.starting_balance).to eq -credit_balance
280
+ expect(upcoming.ending_balance).to be_nil
281
+ expect(upcoming.subscription).to eq(subscription.id)
282
+
283
+ if with_trial
284
+ expect(upcoming.lines.data.length).to eq(2)
285
+ else
286
+ expect(upcoming.lines.data.length).to eq(3)
287
+ end
288
+
289
+ expect(upcoming.lines.data[0].proration).to be_truthy
290
+ expect(upcoming.lines.data[0].plan.id).to eq '50m'
291
+ expect(upcoming.lines.data[0].amount).to be_within(1).of -unused_amount
292
+ expect(upcoming.lines.data[0].quantity).to eq quantity
293
+
294
+ unless with_trial
295
+ expect(upcoming.lines.data[1].proration).to be_truthy
296
+ expect(upcoming.lines.data[1].plan.id).to eq '100m'
297
+ expect(upcoming.lines.data[1].amount).to be_within(1).of remaining_amount
298
+ expect(upcoming.lines.data[1].quantity).to eq new_quantity
299
+ end
300
+
301
+ expect(upcoming.lines.data.last.proration).to be_falsey
302
+ expect(upcoming.lines.data.last.plan.id).to eq '100m'
303
+ expect(upcoming.lines.data.last.amount).to eq with_trial ? 0 : 20000
304
+ expect(upcoming.lines.data.last.quantity).to eq new_quantity
305
+ end
306
+
307
+ it 'prorates while changing billing intervals', live: true do
308
+ # Given
309
+ proration_date = Time.now + 5 * 24 * 3600 # 5 days later
310
+ new_quantity = 2
311
+ unused_amount = plan.amount * quantity * (subscription.current_period_end - proration_date.to_i) / (subscription.current_period_end - subscription.current_period_start)
312
+ prorated_amount_due = new_yearly_plan.amount * new_quantity - unused_amount
313
+ credit_balance = 1000
314
+ customer.account_balance = -credit_balance
315
+ customer.save
316
+ query = { customer: customer.id, subscription: subscription.id, subscription_plan: new_yearly_plan.id, subscription_proration_date: proration_date.to_i, subscription_quantity: new_quantity }
317
+ query[:subscription_trial_end] = (DateTime.now >> 1).to_time.to_i if with_trial
318
+
319
+ # When
320
+ upcoming = Stripe::Invoice.upcoming(query)
321
+
322
+ # Then
323
+ expect(upcoming).to be_a Stripe::Invoice
324
+ expect(upcoming.customer).to eq(customer.id)
325
+ if with_trial
326
+ expect(upcoming.amount_due).to eq 0
327
+ else
328
+ expect(upcoming.amount_due).to be_within(1).of prorated_amount_due - credit_balance
329
+ end
330
+ expect(upcoming.starting_balance).to eq -credit_balance
331
+ expect(upcoming.ending_balance).to be_nil
332
+ expect(upcoming.subscription).to eq(subscription.id)
333
+
334
+ expect(upcoming.lines.data[0].proration).to be_truthy
335
+ expect(upcoming.lines.data[0].plan.id).to eq '50m'
336
+ expect(upcoming.lines.data[0].amount).to be_within(1).of -unused_amount
337
+ expect(upcoming.lines.data[0].quantity).to eq quantity
338
+
339
+ expect(upcoming.lines.data[1].proration).to be_falsey
340
+ expect(upcoming.lines.data[1].plan.id).to eq '100y'
341
+ expect(upcoming.lines.data[1].amount).to eq with_trial ? 0 : 20000
342
+ expect(upcoming.lines.data[1].quantity).to eq new_quantity
343
+ end
344
+
345
+ # after { new_monthly_plan.delete rescue nil if @teardown_monthly_plan }
346
+ # after { new_yearly_plan.delete rescue nil if @teardown_yearly_plan }
347
+ end
348
+ end
349
+
350
+ shared_examples 'no proration is done' do
351
+ it 'generates a preview without performing an actual proration', live: true do
352
+ expect(preview.subtotal).to eq 150_00
353
+ # this is a future invoice (generted at the end of the current subscription cycle), rather than a proration invoice
354
+ expect(preview.created).to be_within(1).of subscription.current_period_end
355
+ expect(preview.period_start).to eq subscription.current_period_start
356
+ expect(preview.period_end).to eq subscription.current_period_end
357
+ expect(preview.lines.count).to eq 1
358
+ line = preview.lines.first
359
+ expect(line.type).to eq 'subscription'
360
+ expect(line.amount).to eq 150_00
361
+ # line period is for the NEXT subscription cycle
362
+ expect(line.period.start).to be_within(1).of subscription.current_period_end
363
+ expect(Time.at(line.period.end).month).to be_within(1).of (Time.at(subscription.current_period_end).to_datetime >> 1).month # +1 month
364
+ end
365
+ end
366
+
367
+ describe 'upcoming invoice with no proration parameters specified' do
368
+ let(:preview) do
369
+ Stripe::Invoice.upcoming(
370
+ customer: customer.id,
371
+ subscription: subscription.id
372
+ )
373
+ end
374
+
375
+ it_behaves_like 'no proration is done'
376
+ end
377
+
378
+ describe 'upcoming invoice with same subscription plan and quantity specified' do
379
+ let(:preview) do
380
+ proration_date = Time.now + 60
381
+ Stripe::Invoice.upcoming(
382
+ customer: customer.id,
383
+ subscription: subscription.id,
384
+ subscription_plan: plan.id,
385
+ subscription_quantity: quantity,
386
+ subscription_proration_date: proration_date.to_i,
387
+ subscription_trial_end: nil
388
+ )
389
+ end
390
+
391
+ it_behaves_like 'no proration is done'
392
+ end
393
+ end
394
+
138
395
  it 'sets the start and end of billing periods correctly when plan has an interval_count' do
139
396
  @oddplan = stripe_helper.create_plan(interval: "week", interval_count: 11)
140
- @subscription = Stripe::Subscription.create(plan: @oddplan.id, customer: @customer.id)
141
- @upcoming = Stripe::Invoice.upcoming(customer: @customer.id)
397
+ @subscription = Stripe::Subscription.create(plan: @oddplan.id, customer: customer.id)
398
+ @upcoming = Stripe::Invoice.upcoming(customer: customer.id)
142
399
 
143
400
  expect(@upcoming.period_start + 6652800).to eq(@upcoming.period_end) # 6652800 = +11 weeks
144
401
  expect(@upcoming.period_end).to eq(@upcoming.lines.data[0].period.start)
@@ -151,20 +408,26 @@ shared_examples 'Invoice API' do
151
408
  @plainplan = stripe_helper.create_plan(id: 'b') # 1 month sub
152
409
  @longplan = stripe_helper.create_plan(id: 'c', interval: "year") # 1 year sub
153
410
 
154
- @plainsub = Stripe::Subscription.create(plan: @plainplan.id, customer: @customer.id)
155
- @shortsub = Stripe::Subscription.create(plan: @shortplan.id, customer: @customer.id)
156
- @longsub = Stripe::Subscription.create(plan: @longplan.id, customer: @customer.id)
411
+ @plainsub = Stripe::Subscription.create(plan: @plainplan.id, customer: customer.id)
412
+ @shortsub = Stripe::Subscription.create(plan: @shortplan.id, customer: customer.id)
413
+ @longsub = Stripe::Subscription.create(plan: @longplan.id, customer: customer.id)
157
414
 
158
- @upcoming = Stripe::Invoice.upcoming(customer: @customer.id)
415
+ @upcoming = Stripe::Invoice.upcoming(customer: customer.id)
159
416
 
160
417
  expect(@upcoming.period_start + 604800).to eq(@upcoming.period_end) # 604800 = 1 week
161
418
  expect(@upcoming.period_end + 604800).to eq(@upcoming.lines.data[0].period.end) # 604800 = 1 week
162
419
  expect(@upcoming.subscription).to eq(@shortsub.id)
163
420
  end
164
421
 
422
+ it 'does not store the stripe invoice in memory since its only a preview', with_subscription: true do
423
+ invoice = Stripe::Invoice.upcoming(customer: customer.id)
424
+ data = test_data_source(:invoices)
425
+ expect(data[invoice.id]).to be_nil
426
+ end
427
+
165
428
  context 'retrieving invoice line items' do
166
429
  it 'returns all line items for created invoice' do
167
- invoice = Stripe::Invoice.create(customer: @customer.id)
430
+ invoice = Stripe::Invoice.create(customer: customer.id)
168
431
  line_items = invoice.lines.all
169
432
 
170
433
  expect(invoice).to be_a Stripe::Invoice
@@ -176,9 +439,9 @@ shared_examples 'Invoice API' do
176
439
 
177
440
  it 'returns all line items for upcoming invoice' do
178
441
  plan = stripe_helper.create_plan()
179
- subscription = Stripe::Subscription.create(plan: plan.id, customer: @customer.id)
180
- upcoming = Stripe::Invoice.upcoming(customer: @customer.id)
181
- line_items = upcoming.lines.all
442
+ subscription = Stripe::Subscription.create(plan: plan.id, customer: customer.id)
443
+ upcoming = Stripe::Invoice.upcoming(customer: customer.id)
444
+ line_items = upcoming.lines
182
445
 
183
446
  expect(upcoming).to be_a Stripe::Invoice
184
447
  expect(line_items.count).to eq(1)
@@ -192,8 +455,8 @@ shared_examples 'Invoice API' do
192
455
 
193
456
  it 'for one month plan on the 1st' do
194
457
  @plan = stripe_helper.create_plan()
195
- @sub = Stripe::Subscription.create(plan: @plan.id, customer: @customer.id, current_period_start: Time.utc(2014,1,1,12).to_i)
196
- @upcoming = Stripe::Invoice.upcoming(customer: @customer.id)
458
+ @sub = Stripe::Subscription.create(plan: @plan.id, customer: customer.id, current_period_start: Time.utc(2014,1,1,12).to_i)
459
+ @upcoming = Stripe::Invoice.upcoming(customer: customer.id)
197
460
 
198
461
  expect(Time.at(@upcoming.period_start)).to eq(Time.utc(2014,1,1,12))
199
462
  expect(Time.at(@upcoming.period_end)).to eq(Time.utc(2014,2,1,12))
@@ -203,8 +466,8 @@ shared_examples 'Invoice API' do
203
466
 
204
467
  it 'for one year plan on the 1st' do
205
468
  @plan = stripe_helper.create_plan(interval: "year")
206
- @sub = Stripe::Subscription.create(plan: @plan.id, customer: @customer.id, current_period_start: Time.utc(2012,1,1,12).to_i)
207
- @upcoming = Stripe::Invoice.upcoming(customer: @customer.id)
469
+ @sub = Stripe::Subscription.create(plan: @plan.id, customer: customer.id, current_period_start: Time.utc(2012,1,1,12).to_i)
470
+ @upcoming = Stripe::Invoice.upcoming(customer: customer.id)
208
471
 
209
472
  expect(Time.at(@upcoming.period_start)).to eq(Time.utc(2012,1,1,12))
210
473
  expect(Time.at(@upcoming.period_end)).to eq(Time.utc(2013,1,1,12))
@@ -214,8 +477,8 @@ shared_examples 'Invoice API' do
214
477
 
215
478
  it 'for one month plan on the 31st' do
216
479
  @plan = stripe_helper.create_plan()
217
- @sub = Stripe::Subscription.create(plan: @plan.id, customer: @customer.id, current_period_start: Time.utc(2014,1,31,12).to_i)
218
- @upcoming = Stripe::Invoice.upcoming(customer: @customer.id)
480
+ @sub = Stripe::Subscription.create(plan: @plan.id, customer: customer.id, current_period_start: Time.utc(2014,1,31,12).to_i)
481
+ @upcoming = Stripe::Invoice.upcoming(customer: customer.id)
219
482
 
220
483
  expect(Time.at(@upcoming.period_start)).to eq(Time.utc(2014,1,31,12))
221
484
  expect(Time.at(@upcoming.period_end)).to eq(Time.utc(2014,2,28,12))
@@ -225,8 +488,8 @@ shared_examples 'Invoice API' do
225
488
 
226
489
  it 'for one year plan on feb. 29th' do
227
490
  @plan = stripe_helper.create_plan(interval: "year")
228
- @sub = Stripe::Subscription.create(plan: @plan.id, customer: @customer.id, current_period_start: Time.utc(2012,2,29,12).to_i)
229
- @upcoming = Stripe::Invoice.upcoming(customer: @customer.id)
491
+ @sub = Stripe::Subscription.create(plan: @plan.id, customer: customer.id, current_period_start: Time.utc(2012,2,29,12).to_i)
492
+ @upcoming = Stripe::Invoice.upcoming(customer: customer.id)
230
493
 
231
494
  expect(Time.at(@upcoming.period_start)).to eq(Time.utc(2012,2,29,12))
232
495
  expect(Time.at(@upcoming.period_end)).to eq(Time.utc(2013,2,28,12))
@@ -236,8 +499,8 @@ shared_examples 'Invoice API' do
236
499
 
237
500
  it 'for two month plan on dec. 31st' do
238
501
  @plan = stripe_helper.create_plan(interval_count: 2)
239
- @sub = Stripe::Subscription.create(plan: @plan.id, customer: @customer.id, current_period_start: Time.utc(2013,12,31,12).to_i)
240
- @upcoming = Stripe::Invoice.upcoming(customer: @customer.id)
502
+ @sub = Stripe::Subscription.create(plan: @plan.id, customer: customer.id, current_period_start: Time.utc(2013,12,31,12).to_i)
503
+ @upcoming = Stripe::Invoice.upcoming(customer: customer.id)
241
504
 
242
505
  expect(Time.at(@upcoming.period_start)).to eq(Time.utc(2013,12,31,12))
243
506
  expect(Time.at(@upcoming.period_end)).to eq(Time.utc(2014, 2,28,12))
@@ -247,8 +510,8 @@ shared_examples 'Invoice API' do
247
510
 
248
511
  it 'for three month plan on nov. 30th' do
249
512
  @plan = stripe_helper.create_plan(interval_count: 3)
250
- @sub = Stripe::Subscription.create(plan: @plan.id, customer: @customer.id, current_period_start: Time.utc(2013,11,30,12).to_i)
251
- @upcoming = Stripe::Invoice.upcoming(customer: @customer.id)
513
+ @sub = Stripe::Subscription.create(plan: @plan.id, customer: customer.id, current_period_start: Time.utc(2013,11,30,12).to_i)
514
+ @upcoming = Stripe::Invoice.upcoming(customer: customer.id)
252
515
 
253
516
  expect(Time.at(@upcoming.period_start)).to eq(Time.utc(2013,11,30,12))
254
517
  expect(Time.at(@upcoming.period_end)).to eq(Time.utc(2014, 2,28,12))
@@ -0,0 +1,68 @@
1
+ require 'spec_helper'
2
+
3
+ shared_examples 'Payout API' do
4
+
5
+ it "creates a stripe payout" do
6
+ payout = Stripe::Payout.create(amount: "100", currency: "usd")
7
+
8
+ expect(payout.id).to match(/^test_po/)
9
+ expect(payout.amount).to eq('100')
10
+ expect(payout.currency).to eq('usd')
11
+ expect(payout.metadata.to_hash).to eq({})
12
+ end
13
+
14
+ describe "listing payouts" do
15
+ before do
16
+ 3.times do
17
+ Stripe::Payout.create(amount: "100", currency: "usd")
18
+ end
19
+ end
20
+
21
+ it "without params retrieves all tripe payouts" do
22
+ expect(Stripe::Payout.all.count).to eq(3)
23
+ end
24
+
25
+ it "accepts a limit param" do
26
+ expect(Stripe::Payout.all(limit: 2).count).to eq(2)
27
+ end
28
+ end
29
+
30
+ it "retrieves a stripe payout" do
31
+ original = Stripe::Payout.create(amount: "100", currency: "usd")
32
+ payout = Stripe::Payout.retrieve(original.id)
33
+
34
+ expect(payout.id).to eq(original.id)
35
+ expect(payout.amount).to eq(original.amount)
36
+ expect(payout.currency).to eq(original.currency)
37
+ expect(payout.metadata.to_hash).to eq(original.metadata.to_hash)
38
+ end
39
+
40
+ it "cannot retrieve a payout that doesn't exist" do
41
+ expect { Stripe::Payout.retrieve('nope') }.to raise_error {|e|
42
+ expect(e).to be_a Stripe::InvalidRequestError
43
+ expect(e.param).to eq('payout')
44
+ expect(e.http_status).to eq(404)
45
+ }
46
+ end
47
+
48
+ it 'when amount is not integer', live: true do
49
+ expect { Stripe::Payout.create(amount: '400.2',
50
+ currency: 'usd',
51
+ description: 'Payout for test@example.com') }.to raise_error { |e|
52
+ expect(e).to be_a Stripe::InvalidRequestError
53
+ expect(e.param).to eq('amount')
54
+ expect(e.http_status).to eq(400)
55
+ }
56
+ end
57
+
58
+ it 'when amount is negative', live: true do
59
+ expect { Stripe::Payout.create(amount: '-400',
60
+ currency: 'usd',
61
+ description: 'Payout for test@example.com') }.to raise_error { |e|
62
+ expect(e).to be_a Stripe::InvalidRequestError
63
+ expect(e.param).to eq('amount')
64
+ expect(e.message).to match(/^Invalid.*integer/)
65
+ expect(e.http_status).to eq(400)
66
+ }
67
+ end
68
+ end
@@ -9,6 +9,9 @@ shared_examples 'Plan API' do
9
9
  :amount => 9900,
10
10
  :currency => 'USD',
11
11
  :interval => 1,
12
+ :product => {
13
+ :name => 'A product'
14
+ },
12
15
  :metadata => {
13
16
  :description => "desc text",
14
17
  :info => "info text"
@@ -30,20 +33,40 @@ shared_examples 'Plan API' do
30
33
  end
31
34
 
32
35
 
36
+ it "creates a stripe plan without specifying ID" do
37
+ plan = Stripe::Plan.create(
38
+ :name => 'The Mock Plan',
39
+ :amount => 9900,
40
+ :currency => 'USD',
41
+ :interval => 1,
42
+ :product => {
43
+ :name => 'A product'
44
+ }
45
+ )
46
+
47
+ expect(plan.id).to match(/^test_plan/)
48
+ end
49
+
33
50
  it "stores a created stripe plan in memory" do
34
51
  plan = Stripe::Plan.create(
35
52
  :id => 'pid_2',
36
53
  :name => 'The Memory Plan',
37
54
  :amount => 1100,
38
55
  :currency => 'USD',
39
- :interval => 1
56
+ :interval => 1,
57
+ :product => {
58
+ :name => 'A product'
59
+ }
40
60
  )
41
61
  plan2 = Stripe::Plan.create(
42
62
  :id => 'pid_3',
43
63
  :name => 'The Bonk Plan',
44
64
  :amount => 7777,
45
65
  :currency => 'USD',
46
- :interval => 1
66
+ :interval => 1,
67
+ :product => {
68
+ :name => 'A product'
69
+ }
47
70
  )
48
71
  data = test_data_source(:plans)
49
72
  expect(data[plan.id]).to_not be_nil
@@ -118,6 +141,20 @@ shared_examples 'Plan API' do
118
141
  expect(all.count).to eq(100)
119
142
  end
120
143
 
144
+ it 'validates the amount' do
145
+ expect {
146
+ Stripe::Plan.create(
147
+ :id => 'pid_1',
148
+ :name => 'The Mock Plan',
149
+ :amount => 99.99,
150
+ :currency => 'USD',
151
+ :interval => 'month',
152
+ :product => {
153
+ :name => 'A product'
154
+ }
155
+ )
156
+ }.to raise_error(Stripe::InvalidRequestError, "Invalid integer: 99.99")
157
+ end
121
158
 
122
159
  describe "Validation", :live => true do
123
160
  let(:params) { stripe_helper.create_plan_params }
@@ -126,10 +163,16 @@ shared_examples 'Plan API' do
126
163
  describe "Required Parameters" do
127
164
  after do
128
165
  params.delete(@name)
129
- expect { subject }.to raise_error(Stripe::InvalidRequestError, "Missing required param: #{@name}.")
166
+ message =
167
+ if @name == :amount
168
+ "Plans require an `#{@name}` parameter to be set."
169
+ else
170
+ "Missing required param: #{@name}."
171
+ end
172
+ expect { subject }.to raise_error(Stripe::InvalidRequestError, message)
130
173
  end
131
174
 
132
- it("requires a name") { @name = :name }
175
+ it("requires a product") { @name = :product }
133
176
  it("requires an amount") { @name = :amount }
134
177
  it("requires a currency") { @name = :currency }
135
178
  it("requires an interval") { @name = :interval }