stripe-ruby-mock 3.0.0 → 3.1.0

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 (137) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/rspec_tests.yml +38 -0
  3. data/.rspec +2 -1
  4. data/CHANGELOG.md +69 -0
  5. data/Gemfile +1 -0
  6. data/README.md +13 -5
  7. data/lib/stripe_mock/api/client.rb +1 -1
  8. data/lib/stripe_mock/api/errors.rb +3 -0
  9. data/lib/stripe_mock/api/instance.rb +1 -1
  10. data/lib/stripe_mock/api/webhooks.rb +66 -25
  11. data/lib/stripe_mock/client.rb +2 -1
  12. data/lib/stripe_mock/data/list.rb +42 -9
  13. data/lib/stripe_mock/data.rb +242 -31
  14. data/lib/stripe_mock/instance.rb +14 -3
  15. data/lib/stripe_mock/request_handlers/account_links.rb +15 -0
  16. data/lib/stripe_mock/request_handlers/accounts.rb +17 -6
  17. data/lib/stripe_mock/request_handlers/charges.rb +11 -4
  18. data/lib/stripe_mock/request_handlers/checkout_session.rb +179 -0
  19. data/lib/stripe_mock/request_handlers/customers.rb +35 -18
  20. data/lib/stripe_mock/request_handlers/ephemeral_key.rb +1 -1
  21. data/lib/stripe_mock/request_handlers/events.rb +30 -3
  22. data/lib/stripe_mock/request_handlers/express_login_links.rb +15 -0
  23. data/lib/stripe_mock/request_handlers/helpers/coupon_helpers.rb +6 -0
  24. data/lib/stripe_mock/request_handlers/helpers/subscription_helpers.rb +36 -12
  25. data/lib/stripe_mock/request_handlers/invoices.rb +10 -4
  26. data/lib/stripe_mock/request_handlers/payment_intents.rb +19 -1
  27. data/lib/stripe_mock/request_handlers/payment_methods.rb +10 -24
  28. data/lib/stripe_mock/request_handlers/plans.rb +1 -1
  29. data/lib/stripe_mock/request_handlers/prices.rb +62 -0
  30. data/lib/stripe_mock/request_handlers/promotion_codes.rb +43 -0
  31. data/lib/stripe_mock/request_handlers/refunds.rb +13 -2
  32. data/lib/stripe_mock/request_handlers/setup_intents.rb +16 -9
  33. data/lib/stripe_mock/request_handlers/sources.rb +12 -6
  34. data/lib/stripe_mock/request_handlers/subscriptions.rb +120 -21
  35. data/lib/stripe_mock/request_handlers/tokens.rb +6 -4
  36. data/lib/stripe_mock/request_handlers/transfers.rb +12 -1
  37. data/lib/stripe_mock/request_handlers/validators/param_validators.rb +33 -4
  38. data/lib/stripe_mock/server.rb +2 -2
  39. data/lib/stripe_mock/test_strategies/base.rb +62 -10
  40. data/lib/stripe_mock/version.rb +1 -1
  41. data/lib/stripe_mock/webhook_fixtures/account.updated.json +1 -1
  42. data/lib/stripe_mock/webhook_fixtures/balance.available.json +27 -15
  43. data/lib/stripe_mock/webhook_fixtures/charge.captured.json +143 -0
  44. data/lib/stripe_mock/webhook_fixtures/charge.dispute.created.json +63 -16
  45. data/lib/stripe_mock/webhook_fixtures/charge.failed.json +49 -120
  46. data/lib/stripe_mock/webhook_fixtures/charge.refund.updated.json +35 -0
  47. data/lib/stripe_mock/webhook_fixtures/charge.refunded.json +145 -50
  48. data/lib/stripe_mock/webhook_fixtures/charge.succeeded.json +114 -43
  49. data/lib/stripe_mock/webhook_fixtures/checkout.session.completed.json +79 -0
  50. data/lib/stripe_mock/webhook_fixtures/checkout.session.completed.payment_mode.json +53 -0
  51. data/lib/stripe_mock/webhook_fixtures/checkout.session.completed.setup_mode.json +45 -0
  52. data/lib/stripe_mock/webhook_fixtures/customer.created.json +37 -46
  53. data/lib/stripe_mock/webhook_fixtures/customer.deleted.json +36 -32
  54. data/lib/stripe_mock/webhook_fixtures/customer.source.created.json +31 -22
  55. data/lib/stripe_mock/webhook_fixtures/customer.source.updated.json +36 -25
  56. data/lib/stripe_mock/webhook_fixtures/customer.subscription.created.json +135 -47
  57. data/lib/stripe_mock/webhook_fixtures/customer.subscription.deleted.json +134 -45
  58. data/lib/stripe_mock/webhook_fixtures/customer.subscription.updated.json +135 -56
  59. data/lib/stripe_mock/webhook_fixtures/customer.updated.json +38 -47
  60. data/lib/stripe_mock/webhook_fixtures/invoice.created.json +176 -49
  61. data/lib/stripe_mock/webhook_fixtures/invoice.finalized.json +171 -0
  62. data/lib/stripe_mock/webhook_fixtures/invoice.paid.json +171 -0
  63. data/lib/stripe_mock/webhook_fixtures/invoice.payment_action_required.json +171 -0
  64. data/lib/stripe_mock/webhook_fixtures/invoice.payment_failed.json +149 -83
  65. data/lib/stripe_mock/webhook_fixtures/invoice.payment_succeeded.json +149 -90
  66. data/lib/stripe_mock/webhook_fixtures/invoice.upcoming.json +70 -0
  67. data/lib/stripe_mock/webhook_fixtures/invoice.updated.json +178 -50
  68. data/lib/stripe_mock/webhook_fixtures/invoiceitem.created.json +87 -13
  69. data/lib/stripe_mock/webhook_fixtures/invoiceitem.updated.json +88 -14
  70. data/lib/stripe_mock/webhook_fixtures/mandate.updated.json +34 -0
  71. data/lib/stripe_mock/webhook_fixtures/payment_intent.amount_capturable_updated.json +170 -0
  72. data/lib/stripe_mock/webhook_fixtures/payment_intent.canceled.json +73 -0
  73. data/lib/stripe_mock/webhook_fixtures/payment_intent.created.json +86 -0
  74. data/lib/stripe_mock/webhook_fixtures/payment_intent.payment_failed.json +225 -0
  75. data/lib/stripe_mock/webhook_fixtures/payment_intent.processing.json +162 -0
  76. data/lib/stripe_mock/webhook_fixtures/payment_intent.requires_action.json +191 -0
  77. data/lib/stripe_mock/webhook_fixtures/payment_intent.succeeded.json +196 -0
  78. data/lib/stripe_mock/webhook_fixtures/payment_link.created.json +47 -0
  79. data/lib/stripe_mock/webhook_fixtures/payment_link.updated.json +50 -0
  80. data/lib/stripe_mock/webhook_fixtures/payment_method.attached.json +63 -0
  81. data/lib/stripe_mock/webhook_fixtures/payment_method.detached.json +62 -0
  82. data/lib/stripe_mock/webhook_fixtures/payout.created.json +40 -0
  83. data/lib/stripe_mock/webhook_fixtures/payout.paid.json +40 -0
  84. data/lib/stripe_mock/webhook_fixtures/payout.updated.json +46 -0
  85. data/lib/stripe_mock/webhook_fixtures/plan.created.json +30 -13
  86. data/lib/stripe_mock/webhook_fixtures/plan.deleted.json +30 -13
  87. data/lib/stripe_mock/webhook_fixtures/plan.updated.json +34 -14
  88. data/lib/stripe_mock/webhook_fixtures/price.created.json +42 -0
  89. data/lib/stripe_mock/webhook_fixtures/price.deleted.json +42 -0
  90. data/lib/stripe_mock/webhook_fixtures/price.updated.json +48 -0
  91. data/lib/stripe_mock/webhook_fixtures/product.created.json +19 -13
  92. data/lib/stripe_mock/webhook_fixtures/product.deleted.json +20 -14
  93. data/lib/stripe_mock/webhook_fixtures/product.updated.json +24 -15
  94. data/lib/stripe_mock/webhook_fixtures/quote.accepted.json +92 -0
  95. data/lib/stripe_mock/webhook_fixtures/quote.canceled.json +92 -0
  96. data/lib/stripe_mock/webhook_fixtures/quote.created.json +92 -0
  97. data/lib/stripe_mock/webhook_fixtures/quote.finalized.json +92 -0
  98. data/lib/stripe_mock/webhook_fixtures/setup_intent.canceled.json +46 -0
  99. data/lib/stripe_mock/webhook_fixtures/setup_intent.created.json +51 -0
  100. data/lib/stripe_mock/webhook_fixtures/setup_intent.setup_failed.json +100 -0
  101. data/lib/stripe_mock/webhook_fixtures/setup_intent.succeeded.json +46 -0
  102. data/lib/stripe_mock/webhook_fixtures/subscription_schedule.canceled.json +119 -0
  103. data/lib/stripe_mock/webhook_fixtures/subscription_schedule.created.json +114 -0
  104. data/lib/stripe_mock/webhook_fixtures/subscription_schedule.released.json +111 -0
  105. data/lib/stripe_mock/webhook_fixtures/subscription_schedule.updated.json +125 -0
  106. data/lib/stripe_mock/webhook_fixtures/tax_rate.created.json +32 -0
  107. data/lib/stripe_mock/webhook_fixtures/tax_rate.updated.json +37 -0
  108. data/lib/stripe_mock.rb +7 -0
  109. data/spec/instance_spec.rb +7 -7
  110. data/spec/integration_examples/completing_checkout_sessions_example.rb +37 -0
  111. data/spec/list_spec.rb +38 -0
  112. data/spec/readme_spec.rb +1 -1
  113. data/spec/server_spec.rb +4 -2
  114. data/spec/shared_stripe_examples/account_examples.rb +9 -1
  115. data/spec/shared_stripe_examples/account_link_examples.rb +16 -0
  116. data/spec/shared_stripe_examples/balance_examples.rb +6 -0
  117. data/spec/shared_stripe_examples/card_token_examples.rb +17 -21
  118. data/spec/shared_stripe_examples/checkout_session_examples.rb +99 -0
  119. data/spec/shared_stripe_examples/customer_examples.rb +49 -23
  120. data/spec/shared_stripe_examples/express_login_link_examples.rb +12 -0
  121. data/spec/shared_stripe_examples/invoice_examples.rb +29 -8
  122. data/spec/shared_stripe_examples/payment_intent_examples.rb +84 -0
  123. data/spec/shared_stripe_examples/payment_method_examples.rb +336 -67
  124. data/spec/shared_stripe_examples/price_examples.rb +223 -0
  125. data/spec/shared_stripe_examples/product_examples.rb +1 -9
  126. data/spec/shared_stripe_examples/promotion_code_examples.rb +68 -0
  127. data/spec/shared_stripe_examples/refund_examples.rb +13 -0
  128. data/spec/shared_stripe_examples/setup_intent_examples.rb +17 -0
  129. data/spec/shared_stripe_examples/subscription_examples.rb +361 -9
  130. data/spec/shared_stripe_examples/transfer_examples.rb +10 -1
  131. data/spec/shared_stripe_examples/webhook_event_examples.rb +51 -5
  132. data/spec/spec_helper.rb +4 -0
  133. data/spec/stripe_mock_spec.rb +2 -2
  134. data/spec/support/stripe_examples.rb +8 -1
  135. data/stripe-ruby-mock.gemspec +7 -2
  136. metadata +73 -12
  137. data/.travis.yml +0 -28
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
  require 'securerandom'
3
3
 
4
- shared_examples 'Customer Subscriptions' do
4
+ shared_examples 'Customer Subscriptions with plans' do
5
5
  let(:gen_card_tk) { stripe_helper.generate_card_token }
6
6
 
7
7
  let(:product) { stripe_helper.create_product }
@@ -14,7 +14,7 @@ shared_examples 'Customer Subscriptions' do
14
14
  let(:free_plan) { stripe_helper.create_plan(id: 'free', product: product.id, amount: 0) }
15
15
 
16
16
  context "creating a new subscription" do
17
- it "adds a new subscription to customer with none using items", :live => true do
17
+ it "adds a new subscription to customer with none using items", live: true do
18
18
  plan
19
19
  customer = Stripe::Customer.create(source: gen_card_tk)
20
20
 
@@ -49,7 +49,7 @@ shared_examples 'Customer Subscriptions' do
49
49
  expect(subscriptions.data.first.metadata.example).to eq( "yes" )
50
50
  end
51
51
 
52
- it "adds a new subscription to customer with none", :live => true do
52
+ it "adds a new subscription to customer with none", live: true do
53
53
  plan
54
54
  customer = Stripe::Customer.create(source: gen_card_tk)
55
55
  subscriptions = Stripe::Subscription.list(customer: customer.id)
@@ -117,6 +117,33 @@ shared_examples 'Customer Subscriptions' do
117
117
  expect(subscriptions.data.first.metadata.example).to eq( "yes" )
118
118
  end
119
119
 
120
+ it "adds a new subscription with payment method provided as default" do
121
+ plan
122
+ customer = Stripe::Customer.create(source: gen_card_tk)
123
+ payment_method = Stripe::PaymentMethod.create(
124
+ type: 'card',
125
+ card: {
126
+ number: 4242_4242_4242_4242,
127
+ exp_month: 9,
128
+ exp_year: (Time.now.year + 5),
129
+ cvc: 999
130
+ }
131
+ )
132
+ sub = Stripe::Subscription.create(
133
+ plan: 'silver',
134
+ customer: customer,
135
+ metadata: { foo: "bar", example: "yes" },
136
+ collection_method: 'send_invoice',
137
+ default_payment_method: payment_method.id,
138
+ )
139
+
140
+ subscriptions = Stripe::Subscription.list(customer: customer.id)
141
+ expect(subscriptions.count).to eq(1)
142
+ expect(subscriptions.data.first.id).to eq(sub.id)
143
+ expect(subscriptions.data.first.collection_method).to eq('send_invoice')
144
+ expect(subscriptions.data.first.default_payment_method).to eq(payment_method.id)
145
+ end
146
+
120
147
  it "adds a new subscription to customer (string/symbol agnostic)" do
121
148
  customer = Stripe::Customer.create(source: gen_card_tk)
122
149
  subscriptions = Stripe::Subscription.list(customer: customer.id)
@@ -152,6 +179,7 @@ shared_examples 'Customer Subscriptions' do
152
179
  expect(subscriptions.data).to be_a(Array)
153
180
  expect(subscriptions.data.count).to eq(1)
154
181
  expect(subscriptions.data.first.discount).not_to be_nil
182
+ expect(subscriptions.data.first.discount.id).not_to be_nil
155
183
  expect(subscriptions.data.first.discount).to be_a(Stripe::Discount)
156
184
  expect(subscriptions.data.first.discount.coupon.id).to eq(coupon.id)
157
185
  end
@@ -168,6 +196,28 @@ shared_examples 'Customer Subscriptions' do
168
196
  }
169
197
  end
170
198
 
199
+ it "allows promotion code" do
200
+ customer = Stripe::Customer.create(source: gen_card_tk)
201
+ coupon = stripe_helper.create_coupon
202
+ promotion_code = Stripe::PromotionCode.create(coupon: coupon)
203
+
204
+ expect {
205
+ Stripe::Subscription.create(plan: plan.id, customer: customer.id, promotion_code: promotion_code.id)
206
+ }.not_to raise_error(Stripe::InvalidRequestError)
207
+ end
208
+
209
+ it "does not permit both coupon and promotion code" do
210
+ customer = Stripe::Customer.create(source: gen_card_tk)
211
+
212
+ expect {
213
+ Stripe::Subscription.create(plan: plan.id, customer: customer.id, coupon: "test", promotion_code: "test")
214
+ }.to raise_error { |e|
215
+ expect(e).to be_a Stripe::InvalidRequestError
216
+ expect(e.http_status).to eq(400)
217
+ expect(e.message).to eq("You may only specify one of these parameters: coupon, promotion_code")
218
+ }
219
+ end
220
+
171
221
  it "correctly sets quantity, application_fee_percent and tax_percent" do
172
222
  customer = Stripe::Customer.create(id: 'test_customer_sub', source: gen_card_tk)
173
223
 
@@ -183,6 +233,20 @@ shared_examples 'Customer Subscriptions' do
183
233
  expect(subscription.tax_percent).to eq(20)
184
234
  end
185
235
 
236
+ it "correctly sets pending invoice item interval" do
237
+ customer = Stripe::Customer.create(id: 'test_customer_sub', source: gen_card_tk)
238
+
239
+ subscription = Stripe::Subscription.create({
240
+ plan: plan.id,
241
+ customer: customer.id,
242
+ quantity: 2,
243
+ pending_invoice_item_interval: { interval: 'month', interval_count: 1 }
244
+ })
245
+
246
+ expect(subscription.pending_invoice_item_interval.interval).to eq 'month'
247
+ expect(subscription.pending_invoice_item_interval.interval_count).to eq 1
248
+ end
249
+
186
250
  it "correctly sets created when it's not provided as a parameter", live: true do
187
251
  customer = Stripe::Customer.create(source: gen_card_tk)
188
252
  subscription = Stripe::Subscription.create({ plan: plan.id, customer: customer.id })
@@ -249,6 +313,27 @@ shared_examples 'Customer Subscriptions' do
249
313
  expect(customer.subscriptions.count).to eq(0)
250
314
  end
251
315
 
316
+ it "creates a subscription when subscription's payment_behavior is default_incomplete" do
317
+ plan = stripe_helper.create_plan(id: 'enterprise', product: product.id, amount: 499)
318
+ customer = Stripe::Customer.create(id: 'cardless')
319
+
320
+ sub = Stripe::Subscription.create({ plan: plan.id, customer: customer.id, payment_behavior: 'default_incomplete' })
321
+ customer = Stripe::Customer.retrieve('cardless')
322
+
323
+ expect(customer.subscriptions.count).to eq(1)
324
+ expect(customer.subscriptions.data.first.id).to eq(sub.id)
325
+ expect(customer.subscriptions.data.first.status).to eq('incomplete')
326
+ end
327
+
328
+ it "allows setting transfer_data" do
329
+ customer = Stripe::Customer.create(id: 'test_customer_sub', source: gen_card_tk)
330
+
331
+ sub = Stripe::Subscription.create({ customer: customer.id, plan: plan.id, transfer_data: {destination: "acct_0000000000000000", amount_percent: 50} })
332
+
333
+ expect(sub.transfer_data.destination).to eq("acct_0000000000000000")
334
+ expect(sub.transfer_data.amount_percent).to eq(50)
335
+ end
336
+
252
337
  it "throws an error when subscribing a customer with no card" do
253
338
  plan = stripe_helper.create_plan(id: 'enterprise', product: product.id, amount: 499)
254
339
  customer = Stripe::Customer.create(id: 'cardless')
@@ -297,7 +382,7 @@ shared_examples 'Customer Subscriptions' do
297
382
  expect(sub.object).to eq('subscription')
298
383
  expect(sub.plan.to_hash).to eq(plan_with_trial.to_hash)
299
384
  expect(sub.trial_end - sub.trial_start).to eq(14 * 86400)
300
- expect(sub.billing_cycle_anchor).to be_nil
385
+ expect(sub.billing_cycle_anchor).to eq sub.trial_start
301
386
 
302
387
  customer = Stripe::Customer.retrieve(customer.id)
303
388
  subscriptions = Stripe::Subscription.list(customer: customer.id)
@@ -491,6 +576,45 @@ shared_examples 'Customer Subscriptions' do
491
576
  expect(subscription.items.data[1].plan.id).to eq plan2.id
492
577
  end
493
578
 
579
+ it 'sets current_period_end based on price week interval', live: true do
580
+ price = stripe_helper.create_price(recurring: {interval: 'week'})
581
+
582
+ subscription = Stripe::Subscription.create(
583
+ customer: Stripe::Customer.create(source: gen_card_tk).id,
584
+ items: [
585
+ {price: price.id, quantity: 1}
586
+ ]
587
+ )
588
+
589
+ expect(subscription.current_period_end).to eq (Time.now + (7 * 60 * 60 * 24)).to_i
590
+ end
591
+
592
+ it 'sets current_period_end based on price month interval', live: true do
593
+ price = stripe_helper.create_price(recurring: {interval: 'month'})
594
+
595
+ subscription = Stripe::Subscription.create(
596
+ customer: Stripe::Customer.create(source: gen_card_tk).id,
597
+ items: [
598
+ {price: price.id, quantity: 1}
599
+ ]
600
+ )
601
+
602
+ expect(subscription.current_period_end).to eq (DateTime.now >> 1).to_time.to_i
603
+ end
604
+
605
+ it 'sets current_period_end based on price year interval', live: true do
606
+ price = stripe_helper.create_price(recurring: {interval: 'year'})
607
+
608
+ subscription = Stripe::Subscription.create(
609
+ customer: Stripe::Customer.create(source: gen_card_tk).id,
610
+ items: [
611
+ {price: price.id, quantity: 1}
612
+ ]
613
+ )
614
+
615
+ expect(subscription.current_period_end).to eq (DateTime.now >> 12).to_time.to_i
616
+ end
617
+
494
618
  it 'add a new subscription to bill via an invoice' do
495
619
  product = stripe_helper.create_product(id: 'invoice_billing')
496
620
  plan = stripe_helper.create_plan(id: 'silver', product: product.id,
@@ -536,7 +660,7 @@ shared_examples 'Customer Subscriptions' do
536
660
  expect(sub1).to eq(sub2)
537
661
  end
538
662
 
539
- it "adds a new subscription to customer with different idempotency key", :live => true do
663
+ it "adds a new subscription to customer with different idempotency key", live: true do
540
664
  product = stripe_helper.create_product(name: 'Silver Product')
541
665
  plan = stripe_helper.create_plan(id: 'silver', product: product.id,
542
666
  amount: 4999, currency: 'usd')
@@ -592,6 +716,35 @@ shared_examples 'Customer Subscriptions' do
592
716
  expect(subscription.default_tax_rates.first.id).to eq(tax_rate.id)
593
717
  end
594
718
  end
719
+
720
+ it 'expands latest_invoice.payment_intent' do
721
+ customer = Stripe::Customer.create(source: gen_card_tk)
722
+ subscription = Stripe::Subscription.create({
723
+ customer: customer.id,
724
+ plan: plan.id,
725
+ expand: ['latest_invoice.payment_intent']
726
+ })
727
+
728
+ expect(subscription.latest_invoice.payment_intent.status).to eq('succeeded')
729
+
730
+ subscription = Stripe::Subscription.create({
731
+ customer: customer.id,
732
+ plan: plan.id,
733
+ expand: ['latest_invoice.payment_intent'],
734
+ payment_behavior: 'default_incomplete'
735
+ })
736
+
737
+ expect(subscription.latest_invoice.payment_intent.status).to eq('requires_payment_method')
738
+
739
+ subscription = Stripe::Subscription.create({
740
+ customer: customer.id,
741
+ plan: plan.id,
742
+ expand: ['latest_invoice.payment_intent'],
743
+ trial_period_days: 14
744
+ })
745
+
746
+ expect(subscription.latest_invoice.payment_intent).to be_nil
747
+ end
595
748
  end
596
749
 
597
750
  context "updating a subscription" do
@@ -720,6 +873,63 @@ shared_examples 'Customer Subscriptions' do
720
873
  expect(sub.canceled_at).to be_falsey
721
874
  end
722
875
 
876
+ it "updates a subscription's pending invoice item interval" do
877
+ customer = Stripe::Customer.create(id: 'test_customer_sub', source: gen_card_tk)
878
+
879
+ subscription = Stripe::Subscription.create({
880
+ plan: plan.id,
881
+ customer: customer.id,
882
+ quantity: 2,
883
+ pending_invoice_item_interval: { interval: 'month', interval_count: 1 }
884
+ })
885
+
886
+ expect(subscription.pending_invoice_item_interval.interval).to eq 'month'
887
+ expect(subscription.pending_invoice_item_interval.interval_count).to eq 1
888
+
889
+ subscription.pending_invoice_item_interval = { interval: 'week', interval_count: 3 }
890
+ subscription.save
891
+
892
+ expect(subscription.pending_invoice_item_interval.interval).to eq 'week'
893
+ expect(subscription.pending_invoice_item_interval.interval_count).to eq 3
894
+ end
895
+
896
+ it "updates a subscription's default payment method" do
897
+ plan
898
+ customer = Stripe::Customer.create(source: gen_card_tk)
899
+ payment_method_card = Stripe::PaymentMethod.create(
900
+ type: 'card',
901
+ card: {
902
+ number: 4242_4242_4242_4242,
903
+ exp_month: 9,
904
+ exp_year: (Time.now.year + 5),
905
+ cvc: 999
906
+ }
907
+ )
908
+ payment_method_sepa = Stripe::PaymentMethod.create(
909
+ type: 'sepa_debit',
910
+ sepa_debit: {iban: 'DE89370400440532013000'},
911
+ )
912
+ subscription = Stripe::Subscription.create(
913
+ plan: 'silver',
914
+ customer: customer,
915
+ metadata: { foo: "bar", example: "yes" },
916
+ default_payment_method: payment_method_card.id,
917
+ )
918
+
919
+ subscriptions = Stripe::Subscription.list(customer: customer)
920
+ expect(subscriptions.data.first.default_payment_method).to eq(payment_method_card.id)
921
+
922
+ Stripe::Subscription.update(
923
+ subscription.id,
924
+ default_payment_method: payment_method_sepa.id,
925
+ collection_method: 'send_invoice',
926
+ )
927
+
928
+ subscriptions = Stripe::Subscription.list(customer: customer)
929
+ expect(subscriptions.data.first.collection_method).to eq('send_invoice')
930
+ expect(subscriptions.data.first.default_payment_method).to eq(payment_method_sepa.id)
931
+ end
932
+
723
933
  it 'when adds coupon', live: true do
724
934
  coupon = stripe_helper.create_coupon
725
935
  customer = Stripe::Customer.create(source: gen_card_tk, plan: plan.id)
@@ -760,6 +970,23 @@ shared_examples 'Customer Subscriptions' do
760
970
  expect(subscription.discount).to be_nil
761
971
  end
762
972
 
973
+ it "throws an error when promotion code has an amount restriction" do
974
+ coupon = stripe_helper.create_coupon
975
+ promotion_code = Stripe::PromotionCode.create(
976
+ coupon: coupon, restrictions: {minimum_amount: 100, minimum_amount_currency: "USD"}
977
+ )
978
+ customer = Stripe::Customer.create(source: gen_card_tk, plan: plan.id)
979
+ subscription = Stripe::Subscription.retrieve(customer.subscriptions.data.first.id)
980
+
981
+ subscription.promotion_code = promotion_code.id
982
+
983
+ expect { subscription.save }.to raise_error { |e|
984
+ expect(e).to be_a Stripe::InvalidRequestError
985
+ expect(e.http_status).to eq(400)
986
+ expect(e.message).to_not be_nil
987
+ }
988
+ end
989
+
763
990
  it "throws an error when plan does not exist" do
764
991
  customer = Stripe::Customer.create(id: 'cardless', plan: free_plan.id)
765
992
 
@@ -932,12 +1159,24 @@ shared_examples 'Customer Subscriptions' do
932
1159
  expect(e.message).to eq("Invalid timestamp: must be an integer")
933
1160
  }
934
1161
  end
1162
+
1163
+ it "converts billing_cycle_anchor=now to a timestamp" do
1164
+ customer = Stripe::Customer.create(id: 'test_billing_anchor', plan: plan.id, source: gen_card_tk)
1165
+
1166
+ sub = Stripe::Subscription.retrieve(customer.subscriptions.data.first.id)
1167
+ sub.billing_cycle_anchor = 'now'
1168
+ sub.save
1169
+
1170
+ expect(sub.billing_cycle_anchor).to be_a(Integer)
1171
+ end
1172
+
1173
+
935
1174
  end
936
1175
 
937
1176
  context "cancelling a subscription" do
938
1177
  let(:customer) { Stripe::Customer.create(id: 'test_customer_sub', source: gen_card_tk, plan: plan.id) }
939
1178
 
940
- it "cancels a stripe customer's subscription", :live => true do
1179
+ it "cancels a stripe customer's subscription", live: true do
941
1180
  customer = Stripe::Customer.create(source: gen_card_tk, plan: plan.id)
942
1181
 
943
1182
  sub = Stripe::Subscription.retrieve(customer.subscriptions.data.first.id)
@@ -1017,7 +1256,7 @@ shared_examples 'Customer Subscriptions' do
1017
1256
  expect(customer.subscriptions.data.first.status).to eq('trialing')
1018
1257
  end
1019
1258
 
1020
- it "doesn't require a card when trial_end is present", :live => true do
1259
+ it "doesn't require a card when trial_end is present", live: true do
1021
1260
  plan = stripe_helper.create_plan(
1022
1261
  :amount => 2000,
1023
1262
  :product => product.id,
@@ -1049,7 +1288,7 @@ shared_examples 'Customer Subscriptions' do
1049
1288
  expect(subscription.items.object).to eq('list')
1050
1289
  expect(subscription.items.data.class).to eq(Array)
1051
1290
  expect(subscription.items.data.count).to eq(1)
1052
- expect(subscription.items.data.first.id).to eq('test_txn_default')
1291
+ expect(subscription.items.data.first.id).to include('test_si_')
1053
1292
  expect(subscription.items.data.first.created).to eq(1504716183)
1054
1293
  expect(subscription.items.data.first.object).to eq('subscription_item')
1055
1294
  expect(subscription.items.data.first.plan.amount).to eq(0)
@@ -1057,6 +1296,10 @@ shared_examples 'Customer Subscriptions' do
1057
1296
  expect(subscription.items.data.first.plan.currency).to eq('usd')
1058
1297
  expect(subscription.items.data.first.quantity).to eq(2)
1059
1298
  end
1299
+
1300
+ it "has a start_date attribute" do
1301
+ expect(subscription).to respond_to(:start_date)
1302
+ end
1060
1303
  end
1061
1304
 
1062
1305
  context "retrieve multiple subscriptions" do
@@ -1084,11 +1327,55 @@ shared_examples 'Customer Subscriptions' do
1084
1327
  expect(list.count).to eq(0)
1085
1328
  expect(list.data.length).to eq(0)
1086
1329
  end
1330
+
1331
+ it "does not include canceled subscriptions by default" do
1332
+ customer = Stripe::Customer.create(source: gen_card_tk)
1333
+ subscription = Stripe::Subscription.create({ plan: plan.id, customer: customer.id })
1334
+ subscription.delete
1335
+
1336
+ list = Stripe::Subscription.list({customer: customer.id})
1337
+
1338
+ expect(list.object).to eq("list")
1339
+ expect(list.data).to be_empty
1340
+ expect(list.data.length).to eq(0)
1341
+ end
1342
+
1343
+ it "filters out subscriptions based on their current_period", live: true do
1344
+ price = stripe_helper.create_price(recurring: { interval: 'month' })
1345
+ price2 = stripe_helper.create_price(recurring: { interval: 'year' })
1346
+
1347
+ subscription1 = Stripe::Subscription.create(
1348
+ customer: Stripe::Customer.create(source: gen_card_tk).id,
1349
+ items: [{ price: price.id, quantity: 1 }]
1350
+ )
1351
+ subscription2 = Stripe::Subscription.create(
1352
+ customer: Stripe::Customer.create(source: gen_card_tk).id,
1353
+ items: [{ price: price2.id, quantity: 1 }]
1354
+ )
1355
+
1356
+ list = Stripe::Subscription.list({ current_period_end: { gt: subscription1.current_period_end }})
1357
+ expect(list.data).to contain_exactly(subscription2)
1358
+
1359
+ list = Stripe::Subscription.list({ current_period_end: { gte: subscription1.current_period_end }})
1360
+ expect(list.data).to contain_exactly(subscription1, subscription2)
1361
+
1362
+ list = Stripe::Subscription.list({ current_period_end: { lt: subscription1.current_period_end }})
1363
+ expect(list.data).to be_empty
1364
+
1365
+ list = Stripe::Subscription.list({ current_period_end: { lte: subscription1.current_period_end }})
1366
+ expect(list.data).to contain_exactly(subscription1)
1367
+
1368
+ list = Stripe::Subscription.list({ current_period_start: subscription1.current_period_start })
1369
+ expect(list.data).to contain_exactly(subscription1, subscription2)
1370
+
1371
+ list = Stripe::Subscription.list({ current_period_end: subscription2.current_period_end })
1372
+ expect(list.data).to contain_exactly(subscription2)
1373
+ end
1087
1374
  end
1088
1375
 
1089
1376
  describe "metadata" do
1090
1377
 
1091
- it "creates a stripe customer and subscribes them to a plan with meta data", :live => true do
1378
+ it "creates a stripe customer and subscribes them to a plan with meta data", live: true do
1092
1379
 
1093
1380
  stripe_helper.
1094
1381
  create_plan(
@@ -1114,6 +1401,71 @@ shared_examples 'Customer Subscriptions' do
1114
1401
  expect(customer.subscriptions.first.plan.id).to eq('Sample5')
1115
1402
  expect(customer.subscriptions.first.metadata['foo']).to eq('bar')
1116
1403
  end
1404
+
1405
+ it "saves subscription item metadata" do
1406
+ stripe_helper.
1407
+ create_plan(
1408
+ :amount => 500,
1409
+ :interval => 'month',
1410
+ :product => product.id,
1411
+ :currency => 'usd',
1412
+ :id => 'Sample5'
1413
+ )
1414
+ customer = Stripe::Customer.create({
1415
+ email: 'johnny@appleseed.com',
1416
+ source: gen_card_tk
1417
+ })
1418
+
1419
+ subscription = Stripe::Subscription.create(
1420
+ customer: customer.id,
1421
+ items: [{plan: "Sample5", metadata: {foo: 'bar'}}],
1422
+ )
1423
+ expect(subscription.items.data[0].metadata.to_h).to eq(foo: 'bar')
1424
+ end
1117
1425
  end
1426
+ end
1427
+
1428
+ shared_examples 'Customer Subscriptions with prices' do
1429
+ let(:gen_card_tk) { stripe_helper.generate_card_token }
1430
+
1431
+ let(:product) { stripe_helper.create_product }
1432
+ let(:price) { stripe_helper.create_price(product: product.id, amount: 4999, currency: 'usd') }
1433
+
1434
+ context "creating a new subscription" do
1435
+ it "adds a new subscription to customer with none using items", live: true do
1436
+ customer = Stripe::Customer.create(source: gen_card_tk)
1437
+
1438
+ expect(customer.subscriptions.data).to be_empty
1439
+ expect(customer.subscriptions.count).to eq(0)
1440
+
1441
+ subscription = Stripe::Subscription.create({
1442
+ customer: customer.id,
1443
+ items: [{ price: price.id }],
1444
+ metadata: { foo: "bar", example: "yes" }
1445
+ })
1118
1446
 
1447
+ expect(subscription.object).to eq('subscription')
1448
+ expect(subscription.plan.to_hash).to eq(price.to_hash)
1449
+ expect(subscription.items.first.price.to_hash).to eq(price.to_hash)
1450
+ expect(subscription.metadata.foo).to eq("bar")
1451
+ expect(subscription.metadata.example).to eq("yes")
1452
+
1453
+ customer = Stripe::Customer.retrieve(customer.id)
1454
+ subscriptions = Stripe::Subscription.list(customer: customer.id)
1455
+ charges = Stripe::Charge.list(customer: customer.id)
1456
+
1457
+ expect(subscriptions.data).to_not be_empty
1458
+ expect(subscriptions.count).to eq(1)
1459
+ expect(subscriptions.data.length).to eq(1)
1460
+ expect(charges.data.length).to eq(1)
1461
+ expect(customer.currency).to eq("usd")
1462
+
1463
+ expect(subscriptions.data.first.id).to eq(subscription.id)
1464
+ expect(subscriptions.data.first.plan.to_hash).to eq(price.to_hash)
1465
+ expect(subscriptions.data.first.items.first.price.to_hash).to eq(price.to_hash)
1466
+ expect(subscriptions.data.first.customer).to eq(customer.id)
1467
+ expect(subscriptions.data.first.metadata.foo).to eq( "bar" )
1468
+ expect(subscriptions.data.first.metadata.example).to eq( "yes" )
1469
+ end
1470
+ end
1119
1471
  end
@@ -9,7 +9,7 @@ shared_examples 'Transfer API' do
9
9
  expect(transfer.id).to match /^test_tr/
10
10
  expect(transfer.amount).to eq(100)
11
11
  expect(transfer.amount_reversed).to eq(0)
12
- expect(transfer.balance_transaction).to eq('txn_2dyYXXP90MN26R')
12
+ expect(transfer.balance_transaction).to eq('test_txn_1')
13
13
  expect(transfer.created).to eq(1304114826)
14
14
  expect(transfer.currency).to eq('usd')
15
15
  expect(transfer.description).to eq('Transfer description')
@@ -30,6 +30,15 @@ shared_examples 'Transfer API' do
30
30
  expect(transfer.transfer_group).to eq("group_ch_164xRv2eZvKYlo2Clu1sIJWB")
31
31
  end
32
32
 
33
+ it "creates a balance transaction" do
34
+ destination = Stripe::Account.create(type: "custom", email: "#{SecureRandom.uuid}@example.com", id: "acct_12345", requested_capabilities: ['card_payments', 'platform_payments'])
35
+ transfer = Stripe::Transfer.create(amount: 100, currency: "usd", destination: destination.id)
36
+
37
+ bal_trans = Stripe::BalanceTransaction.retrieve(transfer.balance_transaction)
38
+ expect(bal_trans.amount).to eq(100)
39
+ expect(bal_trans.source).to eq(transfer.id)
40
+ end
41
+
33
42
  describe "listing transfers" do
34
43
  let(:destination) { Stripe::Account.create(type: "custom", email: "#{SecureRandom.uuid}@example.com", business_name: "MyCo") }
35
44
 
@@ -203,6 +203,52 @@ shared_examples 'Webhook Events API' do
203
203
  expect(events.map &:type).to include('invoiceitem.created', 'invoice.created', 'coupon.created')
204
204
  end
205
205
 
206
+ it "retrieves events with a created timestamp" do
207
+ timestamp = Time.now.to_i - 7200
208
+ customer_created_event = StripeMock.mock_webhook_event('customer.created', created: Time.now.to_i - 14_400)
209
+ plan_created_event = StripeMock.mock_webhook_event('plan.created', created: Time.now.to_i - 10_800)
210
+ coupon_created_event = StripeMock.mock_webhook_event('coupon.created', created: timestamp)
211
+ invoice_created_event = StripeMock.mock_webhook_event('invoice.created', created: Time.now.to_i - 3600)
212
+ invoice_item_created_event = StripeMock.mock_webhook_event('invoiceitem.created')
213
+
214
+ events = Stripe::Event.list(created: timestamp)
215
+ expect(events.count).to eq(1)
216
+ expect(events.map &:id).to match_array([coupon_created_event.id])
217
+ expect(events.map &:type).to match_array(['coupon.created'])
218
+
219
+ events = Stripe::Event.list(created: timestamp.to_s)
220
+ expect(events.count).to eq(1)
221
+ expect(events.map &:id).to match_array([coupon_created_event.id])
222
+ expect(events.map &:type).to match_array(['coupon.created'])
223
+ end
224
+
225
+ it "retrieves events with a created filter" do
226
+ timestamp1 = Time.now.to_i - 3600
227
+ timestamp2 = Time.now.to_i - 7200
228
+ timestamp3 = Time.now.to_i - 10_800
229
+ timestamp4 = Time.now.to_i - 14_400
230
+ customer_created_event = StripeMock.mock_webhook_event('customer.created', created: timestamp4)
231
+ plan_created_event = StripeMock.mock_webhook_event('plan.created', created: timestamp3)
232
+ coupon_created_event = StripeMock.mock_webhook_event('coupon.created', created: timestamp2)
233
+ invoice_created_event = StripeMock.mock_webhook_event('invoice.created', created: timestamp1)
234
+ invoice_item_created_event = StripeMock.mock_webhook_event('invoiceitem.created')
235
+
236
+ events = Stripe::Event.list(created: {gte: timestamp2, lte: timestamp1})
237
+ expect(events.count).to eq(2)
238
+ expect(events.map &:id).to match_array([coupon_created_event.id, invoice_created_event.id])
239
+ expect(events.map &:type).to match_array(['coupon.created', 'invoice.created'])
240
+
241
+ events = Stripe::Event.list(created: {gt: timestamp3})
242
+ expect(events.count).to eq(3)
243
+ expect(events.map &:id).to match_array([coupon_created_event.id, invoice_created_event.id, invoice_item_created_event.id])
244
+ expect(events.map &:type).to match_array(['coupon.created', 'invoice.created', 'invoiceitem.created'])
245
+
246
+ events = Stripe::Event.list(created: {lt: timestamp3.to_s})
247
+ expect(events.count).to eq(1)
248
+ expect(events.map &:id).to match_array([customer_created_event.id])
249
+ expect(events.map &:type).to match_array(['customer.created'])
250
+ end
251
+
206
252
  end
207
253
 
208
254
  describe 'Subscription events' do
@@ -211,7 +257,7 @@ shared_examples 'Webhook Events API' do
211
257
  expect(subscription_created_event).to be_a(Stripe::Event)
212
258
  expect(subscription_created_event.id).to_not be_nil
213
259
  expect(subscription_created_event.data.object.items.data.class).to be Array
214
- expect(subscription_created_event.data.object.items.data.length).to be 2
260
+ expect(subscription_created_event.data.object.items.data.length).to be 1
215
261
  expect(subscription_created_event.data.object.items.data.first).to respond_to(:plan)
216
262
  expect(subscription_created_event.data.object.items.data.first.id).to eq('si_00000000000000')
217
263
  end
@@ -221,7 +267,7 @@ shared_examples 'Webhook Events API' do
221
267
  expect(subscription_deleted_event).to be_a(Stripe::Event)
222
268
  expect(subscription_deleted_event.id).to_not be_nil
223
269
  expect(subscription_deleted_event.data.object.items.data.class).to be Array
224
- expect(subscription_deleted_event.data.object.items.data.length).to be 2
270
+ expect(subscription_deleted_event.data.object.items.data.length).to be 1
225
271
  expect(subscription_deleted_event.data.object.items.data.first).to respond_to(:plan)
226
272
  expect(subscription_deleted_event.data.object.items.data.first.id).to eq('si_00000000000000')
227
273
  end
@@ -231,7 +277,7 @@ shared_examples 'Webhook Events API' do
231
277
  expect(subscription_updated_event).to be_a(Stripe::Event)
232
278
  expect(subscription_updated_event.id).to_not be_nil
233
279
  expect(subscription_updated_event.data.object.items.data.class).to be Array
234
- expect(subscription_updated_event.data.object.items.data.length).to be 2
280
+ expect(subscription_updated_event.data.object.items.data.length).to be 1
235
281
  expect(subscription_updated_event.data.object.items.data.first).to respond_to(:plan)
236
282
  expect(subscription_updated_event.data.object.items.data.first.id).to eq('si_00000000000000')
237
283
  end
@@ -253,9 +299,9 @@ shared_examples 'Webhook Events API' do
253
299
  expect(invoice_payment_succeeded).to be_a(Stripe::Event)
254
300
  expect(invoice_payment_succeeded.id).to_not be_nil
255
301
  expect(invoice_payment_succeeded.data.object.lines.data.class).to be Array
256
- expect(invoice_payment_succeeded.data.object.lines.data.length).to be 2
302
+ expect(invoice_payment_succeeded.data.object.lines.data.length).to be 1
257
303
  expect(invoice_payment_succeeded.data.object.lines.data.first).to respond_to(:plan)
258
- expect(invoice_payment_succeeded.data.object.lines.data.first.id).to eq('sub_00000000000000')
304
+ expect(invoice_payment_succeeded.data.object.lines.data.first.id).to eq('il_000000000000000000000000')
259
305
  end
260
306
  end
261
307
  end
data/spec/spec_helper.rb CHANGED
@@ -5,6 +5,9 @@ require 'rspec'
5
5
  require 'stripe'
6
6
  require 'stripe_mock'
7
7
  require 'stripe_mock/server'
8
+ require 'dotenv'
9
+
10
+ Dotenv.load('.env')
8
11
 
9
12
  # Requires supporting ruby files with custom matchers and macros, etc,
10
13
  # in spec/support/ and its subdirectories.
@@ -33,6 +36,7 @@ RSpec.configure do |c|
33
36
  when '2.4.6' then ENV['STRIPE_TEST_SECRET_KEY_A']
34
37
  when '2.5.5' then ENV['STRIPE_TEST_SECRET_KEY_B']
35
38
  when '2.6.3' then ENV['STRIPE_TEST_SECRET_KEY_C']
39
+ when '2.7.0' then ENV['STRIPE_TEST_SECRET_KEY_D']
36
40
  end
37
41
  else
38
42
  api_key = ENV['STRIPE_TEST_SECRET_KEY']
@@ -35,8 +35,8 @@ describe StripeMock do
35
35
  StripeMock.stop
36
36
  StripeMock.start
37
37
 
38
- expect(StripeMock.instance.customers[:x]).to be_nil
39
- expect(StripeMock.instance.customers.keys.length).to eq(0)
38
+ expect(StripeMock.instance.customers[''][:x]).to be_nil
39
+ expect(StripeMock.instance.customers[''].keys.length).to eq(0)
40
40
  StripeMock.stop
41
41
  end
42
42