reji 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +14 -0
  3. data/.gitattributes +4 -0
  4. data/.gitignore +15 -0
  5. data/.travis.yml +28 -0
  6. data/Appraisals +17 -0
  7. data/Gemfile +8 -0
  8. data/Gemfile.lock +133 -0
  9. data/LICENSE +20 -0
  10. data/README.md +1285 -0
  11. data/Rakefile +21 -0
  12. data/app/controllers/reji/payment_controller.rb +31 -0
  13. data/app/controllers/reji/webhook_controller.rb +170 -0
  14. data/app/views/payment.html.erb +228 -0
  15. data/app/views/receipt.html.erb +250 -0
  16. data/bin/setup +12 -0
  17. data/config/routes.rb +6 -0
  18. data/gemfiles/rails_5.0.gemfile +13 -0
  19. data/gemfiles/rails_5.1.gemfile +13 -0
  20. data/gemfiles/rails_5.2.gemfile +13 -0
  21. data/gemfiles/rails_6.0.gemfile +13 -0
  22. data/lib/generators/reji/install/install_generator.rb +69 -0
  23. data/lib/generators/reji/install/templates/db/migrate/add_reji_to_users.rb.erb +16 -0
  24. data/lib/generators/reji/install/templates/db/migrate/create_subscription_items.rb.erb +19 -0
  25. data/lib/generators/reji/install/templates/db/migrate/create_subscriptions.rb.erb +22 -0
  26. data/lib/generators/reji/install/templates/reji.rb +36 -0
  27. data/lib/reji.rb +75 -0
  28. data/lib/reji/billable.rb +13 -0
  29. data/lib/reji/concerns/interacts_with_payment_behavior.rb +33 -0
  30. data/lib/reji/concerns/manages_customer.rb +113 -0
  31. data/lib/reji/concerns/manages_invoices.rb +136 -0
  32. data/lib/reji/concerns/manages_payment_methods.rb +202 -0
  33. data/lib/reji/concerns/manages_subscriptions.rb +91 -0
  34. data/lib/reji/concerns/performs_charges.rb +36 -0
  35. data/lib/reji/concerns/prorates.rb +38 -0
  36. data/lib/reji/configuration.rb +59 -0
  37. data/lib/reji/engine.rb +4 -0
  38. data/lib/reji/errors.rb +66 -0
  39. data/lib/reji/invoice.rb +243 -0
  40. data/lib/reji/invoice_line_item.rb +98 -0
  41. data/lib/reji/payment.rb +61 -0
  42. data/lib/reji/payment_method.rb +32 -0
  43. data/lib/reji/subscription.rb +567 -0
  44. data/lib/reji/subscription_builder.rb +206 -0
  45. data/lib/reji/subscription_item.rb +97 -0
  46. data/lib/reji/tax.rb +48 -0
  47. data/lib/reji/version.rb +5 -0
  48. data/reji.gemspec +32 -0
  49. data/spec/dummy/app/models/user.rb +21 -0
  50. data/spec/dummy/application.rb +53 -0
  51. data/spec/dummy/config/database.yml +11 -0
  52. data/spec/dummy/db/schema.rb +40 -0
  53. data/spec/feature/charges_spec.rb +67 -0
  54. data/spec/feature/customer_spec.rb +23 -0
  55. data/spec/feature/invoices_spec.rb +73 -0
  56. data/spec/feature/multiplan_subscriptions_spec.rb +319 -0
  57. data/spec/feature/payment_methods_spec.rb +149 -0
  58. data/spec/feature/pending_updates_spec.rb +77 -0
  59. data/spec/feature/subscriptions_spec.rb +650 -0
  60. data/spec/feature/webhooks_spec.rb +162 -0
  61. data/spec/spec_helper.rb +27 -0
  62. data/spec/support/feature_helpers.rb +39 -0
  63. data/spec/unit/customer_spec.rb +54 -0
  64. data/spec/unit/invoice_line_item_spec.rb +72 -0
  65. data/spec/unit/invoice_spec.rb +192 -0
  66. data/spec/unit/payment_spec.rb +33 -0
  67. data/spec/unit/subscription_spec.rb +103 -0
  68. metadata +237 -0
@@ -0,0 +1,11 @@
1
+ development:
2
+ adapter: sqlite3
3
+ database: db/development.sqlite3
4
+ pool: 5
5
+ timeout: 5000
6
+
7
+ test:
8
+ adapter: sqlite3
9
+ database: ":memory:"
10
+ pool: 5
11
+ timeout: 5000
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ ActiveRecord::Schema.define(version: 2020_01_01_00_00_00) do
4
+ create_table 'subscription_items', force: true do |t|
5
+ t.bigint 'subscription_id', null: false
6
+ t.string 'stripe_id', null: false
7
+ t.string 'stripe_plan', null: false
8
+ t.integer 'quantity', null: false
9
+ t.datetime 'created_at', precision: 6, null: false
10
+ t.datetime 'updated_at', precision: 6, null: false
11
+ t.index ['stripe_id'], name: 'index_subscription_items_on_stripe_id'
12
+ t.index ['subscription_id', 'stripe_plan'], name: 'index_subscription_items_on_subscription_id_and_stripe_plan', unique: true
13
+ end
14
+
15
+ create_table 'subscriptions', force: true do |t|
16
+ t.bigint 'user_id', null: false
17
+ t.string 'name', null: false
18
+ t.string 'stripe_id', null: false
19
+ t.string 'stripe_status', null: false
20
+ t.string 'stripe_plan'
21
+ t.integer 'quantity'
22
+ t.timestamp 'trial_ends_at'
23
+ t.timestamp 'ends_at'
24
+ t.datetime 'created_at', precision: 6, null: false
25
+ t.datetime 'updated_at', precision: 6, null: false
26
+ t.index ['user_id', 'stripe_status'], name: 'index_subscriptions_on_user_id_and_stripe_status'
27
+ end
28
+
29
+ create_table 'users', force: true do |t|
30
+ t.string 'email', default: '', null: false
31
+ t.string 'stripe_id'
32
+ t.string 'card_brand'
33
+ t.string 'card_last_four', limit: 4
34
+ t.timestamp 'trial_ends_at'
35
+ t.datetime 'created_at', precision: 6, null: false
36
+ t.datetime 'updated_at', precision: 6, null: false
37
+ t.index ['email'], name: 'index_users_on_email', unique: true
38
+ end
39
+ end
40
+
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe 'charges', type: :request do
6
+ it 'test_customer_can_be_charged' do
7
+ user = create_customer('customer_can_be_charged')
8
+ user.create_as_stripe_customer
9
+
10
+ response = user.charge(1000, 'pm_card_visa')
11
+
12
+ expect(response).to be_an_instance_of(Reji::Payment)
13
+ expect(response.raw_amount).to eq(1000)
14
+ expect(response.customer).to eq(user.stripe_id)
15
+ end
16
+
17
+ it 'test_non_stripe_customer_can_be_charged' do
18
+ user = create_customer('non_stripe_customer_can_be_charged')
19
+
20
+ response = user.charge(1000, 'pm_card_visa')
21
+
22
+ expect(response).to be_an_instance_of(Reji::Payment)
23
+ expect(response.raw_amount).to eq(1000)
24
+ expect(response.customer).to eq(user.stripe_id)
25
+ end
26
+
27
+ it 'test_customer_can_be_charged_and_invoiced_immediately' do
28
+ user = create_customer('customer_can_be_charged_and_invoiced_immediately')
29
+ user.create_as_stripe_customer
30
+ user.update_default_payment_method('pm_card_visa')
31
+
32
+ user.invoice_for('Rails Reji', 1000)
33
+
34
+ invoice = user.invoices.first
35
+
36
+ expect(invoice.total).to eq('$10.00')
37
+ expect(invoice.invoice_items.first.as_stripe_invoice_line_item.description).to eq('Rails Reji')
38
+ end
39
+
40
+ it 'test_customer_can_be_refunded' do
41
+ user = create_customer('customer_can_be_refunded')
42
+ user.create_as_stripe_customer
43
+ user.update_default_payment_method('pm_card_visa')
44
+
45
+ invoice = user.invoice_for('Rails Reji', 1000)
46
+ refund = user.refund(invoice.payment_intent)
47
+
48
+ expect(refund.amount).to eq(1000)
49
+ end
50
+
51
+ it 'test_charging_may_require_an_extra_action' do
52
+ user = create_customer('charging_may_require_an_extra_action')
53
+ user.create_as_stripe_customer
54
+
55
+ begin
56
+ user.charge(1000, 'pm_card_threeDSecure2Required')
57
+
58
+ raise RSpec::Expectations::ExpectationNotMetError.new('Expected exception PaymentActionRequiredError was not thrown.')
59
+ rescue Reji::PaymentActionRequiredError => e
60
+ # Assert that the payment needs an extra action.
61
+ expect(e.payment.requires_action).to be true
62
+
63
+ # Assert that the payment was for the correct amount.
64
+ expect(e.payment.raw_amount).to eq(1000)
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe 'customer', type: :request do
6
+ it 'test_customers_in_stripe_can_be_updated' do
7
+ user = create_customer('customers_in_stripe_can_be_updated')
8
+ user.create_as_stripe_customer
9
+
10
+ customer = user.update_stripe_customer({:description => 'Van Cam'})
11
+
12
+ expect(customer.description).to eq('Van Cam')
13
+ end
14
+
15
+ # it 'test_customers_can_generate_a_billing_portal_url' do
16
+ # user = create_customer('customers_in_stripe_can_be_updated')
17
+ # user.create_as_stripe_customer
18
+
19
+ # url = user.billing_portal_url('https://example.com')
20
+
21
+ # expect(url).to start_with('https://billing.stripe.com/session/')
22
+ # end
23
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe 'invoices', type: :request do
6
+ it 'test_require_stripe_customer_for_invoicing' do
7
+ user = create_customer('require_stripe_customer_for_invoicing')
8
+
9
+ expect {
10
+ user.invoice
11
+ }.to raise_error(Reji::InvalidCustomerError)
12
+ end
13
+
14
+ it 'test_invoicing_fails_with_nothing_to_invoice' do
15
+ user = create_customer('invoicing_fails_with_nothing_to_invoice')
16
+ user.create_as_stripe_customer
17
+ user.update_default_payment_method('pm_card_visa')
18
+
19
+ response = user.invoice
20
+
21
+ expect(response).to be false
22
+ end
23
+
24
+ it 'test_customer_can_be_invoiced' do
25
+ user = create_customer('customer_can_be_invoiced')
26
+ user.create_as_stripe_customer
27
+ user.update_default_payment_method('pm_card_visa')
28
+
29
+ response = user.invoice_for('Rails Reji', 1000)
30
+
31
+ expect(response).to be_an_instance_of(Reji::Invoice)
32
+ expect(response.raw_total).to eq(1000)
33
+ end
34
+
35
+ it 'test_find_invoice_by_id' do
36
+ user = create_customer('find_invoice_by_id')
37
+ user.create_as_stripe_customer
38
+ user.update_default_payment_method('pm_card_visa')
39
+
40
+ invoice = user.invoice_for('Rails Reji', 1000)
41
+
42
+ invoice = user.find_invoice(invoice.id)
43
+
44
+ expect(invoice).to be_an_instance_of(Reji::Invoice)
45
+ expect(invoice.raw_total).to eq(1000)
46
+ end
47
+
48
+ it 'throws_an_exception_if_the_invoice_does_not_belong_to_the_user' do
49
+ user = create_customer('it_throws_an_exception_if_the_invoice_does_not_belong_to_the_user')
50
+ user.create_as_stripe_customer
51
+ other_user = create_customer('other_user')
52
+ other_user.create_as_stripe_customer
53
+ user.update_default_payment_method('pm_card_visa')
54
+ invoice = user.invoice_for('Rails Reji', 1000)
55
+
56
+ expect {
57
+ other_user.find_invoice(invoice.id)
58
+ }.to raise_error(Reji::InvalidInvoiceError, "The invoice `#{invoice.id}` does not belong to this customer `#{other_user.stripe_id}`.")
59
+ end
60
+
61
+ it 'test_find_invoice_by_id_or_fail' do
62
+ user = create_customer('find_invoice_by_id_or_fail')
63
+ user.create_as_stripe_customer
64
+ other_user = create_customer('other_user')
65
+ other_user.create_as_stripe_customer
66
+ user.update_default_payment_method('pm_card_visa')
67
+ invoice = user.invoice_for('Rails Reji', 1000)
68
+
69
+ expect {
70
+ other_user.find_invoice_or_fail(invoice.id)
71
+ }.to raise_error(Reji::AccessDeniedHttpError)
72
+ end
73
+ end
@@ -0,0 +1,319 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe 'multiplan subscriptions', type: :request do
6
+ before(:all) do
7
+ @product_id = "#{stripe_prefix}product-1-#{SecureRandom.hex(5)}"
8
+ @plan_id = "#{stripe_prefix}monthly-10-#{SecureRandom.hex(5)}"
9
+ @other_plan_id = "#{stripe_prefix}monthly-10-#{SecureRandom.hex(5)}"
10
+ @premium_plan_id = "#{stripe_prefix}monthly-20-premium-#{SecureRandom.hex(5)}"
11
+
12
+ Stripe::Product.create({
13
+ :id => @product_id,
14
+ :name => 'Rails Reji Test Product',
15
+ :type => 'service',
16
+ })
17
+
18
+ Stripe::Plan.create({
19
+ :id => @plan_id,
20
+ :nickname => 'Monthly $10',
21
+ :currency => 'USD',
22
+ :interval => 'month',
23
+ :billing_scheme => 'per_unit',
24
+ :amount => 1000,
25
+ :product => @product_id,
26
+ })
27
+
28
+ Stripe::Plan.create({
29
+ :id => @other_plan_id,
30
+ :nickname => 'Monthly $10 Other',
31
+ :currency => 'USD',
32
+ :interval => 'month',
33
+ :billing_scheme => 'per_unit',
34
+ :amount => 1000,
35
+ :product => @product_id,
36
+ })
37
+
38
+ Stripe::Plan.create({
39
+ :id => @premium_plan_id,
40
+ :nickname => 'Monthly $20 Premium',
41
+ :currency => 'USD',
42
+ :interval => 'month',
43
+ :billing_scheme => 'per_unit',
44
+ :amount => 2000,
45
+ :product => @product_id,
46
+ })
47
+
48
+ @tax_rate_id = Stripe::TaxRate.create({
49
+ :display_name => 'VAT',
50
+ :description => 'VAT Belgium',
51
+ :jurisdiction => 'BE',
52
+ :percentage => 21,
53
+ :inclusive => false,
54
+ }).id
55
+ end
56
+
57
+ after(:all) do
58
+ delete_stripe_resource(Stripe::Plan.retrieve(@plan_id))
59
+ delete_stripe_resource(Stripe::Plan.retrieve(@other_plan_id))
60
+ delete_stripe_resource(Stripe::Plan.retrieve(@premium_plan_id))
61
+ delete_stripe_resource(Stripe::Product.retrieve(@product_id))
62
+ end
63
+
64
+ it 'test_customers_can_have_multiplan_subscriptions' do
65
+ user = create_customer('customers_can_have_multiplan_subscriptions')
66
+
67
+ user.plan_tax_rates = {@other_plan_id => [@tax_rate_id]}
68
+
69
+ subscription = user.new_subscription('main', [@plan_id, @other_plan_id])
70
+ .plan(@premium_plan_id, 5)
71
+ .quantity(10, @plan_id)
72
+ .create('pm_card_visa')
73
+
74
+ expect(user.subscribed('main', @plan_id)).to be true
75
+ expect(user.on_plan(@plan_id)).to be true
76
+
77
+ item = subscription.find_item_or_fail(@plan_id)
78
+ other_item = subscription.find_item_or_fail(@other_plan_id)
79
+ premium_item = subscription.find_item_or_fail(@premium_plan_id)
80
+
81
+ expect(subscription.items.count).to eq(3)
82
+ expect(item.stripe_plan).to eq(@plan_id)
83
+ expect(item.quantity).to eq(10)
84
+ expect(other_item.stripe_plan).to eq(@other_plan_id)
85
+ expect(other_item.quantity).to eq(1)
86
+ expect(premium_item.stripe_plan).to eq(@premium_plan_id)
87
+ expect(premium_item.quantity).to eq(5)
88
+ end
89
+
90
+ it 'test_customers_can_add_plans' do
91
+ user = create_customer('customers_can_add_plans')
92
+
93
+ subscription = user.new_subscription('main', @plan_id).create('pm_card_visa')
94
+
95
+ subscription.add_plan(@other_plan_id, 5)
96
+
97
+ expect(user.on_plan(@plan_id)).to be true
98
+ expect(user.on_plan(@premium_plan_id)).to be false
99
+
100
+ item = subscription.find_item_or_fail(@plan_id)
101
+ other_item = subscription.find_item_or_fail(@other_plan_id)
102
+
103
+ expect(subscription.items.count).to eq(2)
104
+ expect(item.stripe_plan).to eq(@plan_id)
105
+ expect(item.quantity).to eq(1)
106
+ expect(other_item.stripe_plan).to eq(@other_plan_id)
107
+ expect(other_item.quantity).to eq(5)
108
+ end
109
+
110
+ it 'test_customers_can_remove_plans' do
111
+ user = create_customer('customers_can_remove_plans')
112
+
113
+ subscription = user.new_subscription(
114
+ 'main', [@plan_id, @other_plan_id]
115
+ ).create('pm_card_visa')
116
+
117
+ expect(subscription.items.count).to eq(2)
118
+
119
+ subscription.remove_plan(@plan_id)
120
+
121
+ expect(subscription.items.count).to eq(1)
122
+ end
123
+
124
+ it 'test_customers_cannot_remove_the_last_plan' do
125
+ user = create_customer('customers_cannot_remove_the_last_plan')
126
+
127
+ subscription = self.create_subscription_with_single_plan(user)
128
+
129
+ expect {
130
+ subscription.remove_plan(@plan_id)
131
+ }.to raise_error(Reji::SubscriptionUpdateFailureError)
132
+ end
133
+
134
+ it 'test_multiplan_subscriptions_can_be_resumed' do
135
+ user = create_customer('multiplan_subscriptions_can_be_resumed')
136
+
137
+ subscription = user.new_subscription(
138
+ 'main', [@plan_id, @other_plan_id]
139
+ ).create('pm_card_visa')
140
+
141
+ subscription.cancel
142
+
143
+ expect(subscription.active).to be true
144
+ expect(subscription.on_grace_period).to be true
145
+
146
+ subscription.resume
147
+
148
+ expect(subscription.active).to be true
149
+ expect(subscription.on_grace_period).to be false
150
+ end
151
+
152
+ it 'test_plan_is_required_when_updating_quantities_for_multiplan_subscriptions' do
153
+ user = create_customer('plan_is_required_when_updating_quantities_for_multiplan_subscriptions')
154
+
155
+ subscription = self.create_subscription_with_multiple_plans(user)
156
+
157
+ expect {
158
+ subscription.update_quantity(5)
159
+ }.to raise_error(ArgumentError)
160
+ end
161
+
162
+ it 'test_subscription_item_quantities_can_be_updated' do
163
+ user = create_customer('subscription_item_quantities_can_be_updated')
164
+
165
+ subscription = user.new_subscription(
166
+ 'main', [@plan_id, @other_plan_id]
167
+ ).create('pm_card_visa')
168
+
169
+ subscription.update_quantity(5, @other_plan_id)
170
+
171
+ item = subscription.find_item_or_fail(@other_plan_id)
172
+
173
+ expect(item.quantity).to eq(5)
174
+ end
175
+
176
+ it 'test_subscription_item_quantities_can_be_incremented' do
177
+ user = create_customer('subscription_item_quantities_can_be_incremented')
178
+
179
+ subscription = user.new_subscription(
180
+ 'main', [@plan_id, @other_plan_id]
181
+ ).create('pm_card_visa')
182
+
183
+ subscription.increment_quantity(3, @other_plan_id)
184
+
185
+ item = subscription.find_item_or_fail(@other_plan_id)
186
+
187
+ expect(item.quantity).to eq(4)
188
+
189
+ item.increment_quantity(3)
190
+
191
+ expect(item.quantity).to eq(7)
192
+ end
193
+
194
+ it 'test_subscription_item_quantities_can_be_decremented' do
195
+ user = create_customer('subscription_item_quantities_can_be_decremented')
196
+
197
+ subscription = user.new_subscription(
198
+ 'main', [@plan_id, @other_plan_id]
199
+ ).quantity(5, @other_plan_id).create('pm_card_visa')
200
+
201
+ subscription.decrement_quantity(2, @other_plan_id)
202
+
203
+ item = subscription.find_item_or_fail(@other_plan_id)
204
+
205
+ expect(item.quantity).to eq(3)
206
+
207
+ item.decrement_quantity(2)
208
+
209
+ expect(item.quantity).to eq(1)
210
+ end
211
+
212
+ it 'test_multiple_plans_can_be_swapped' do
213
+ user = create_customer('multiple_plans_can_be_swapped')
214
+
215
+ subscription = user.new_subscription('main', @plan_id).create('pm_card_visa')
216
+
217
+ subscription.swap([@other_plan_id, @premium_plan_id])
218
+
219
+ plans = subscription.items.pluck(:stripe_plan)
220
+
221
+ expect(plans.count).to eq(2)
222
+ expect(plans).to contain_exactly(@other_plan_id, @premium_plan_id)
223
+ end
224
+
225
+ it 'test_subscription_items_can_swap_plans' do
226
+ user = create_customer('subscription_items_can_swap_plans')
227
+
228
+ subscription = user.new_subscription('main', @plan_id).create('pm_card_visa')
229
+
230
+ item = subscription.items.first.swap(@other_plan_id, {:quantity => 3})
231
+
232
+ expect(subscription.items.count).to eq(1)
233
+ expect(subscription.stripe_plan).to eq(@other_plan_id)
234
+ expect(item.stripe_plan).to eq(@other_plan_id)
235
+ expect(item.quantity).to eq(3)
236
+ end
237
+
238
+ it 'test_subscription_item_changes_can_be_prorated' do
239
+ user = create_customer('subscription_item_changes_can_be_prorated')
240
+
241
+ subscription = user.new_subscription('main', @premium_plan_id).create('pm_card_visa')
242
+
243
+ invoice = user.invoices.first
244
+
245
+ expect(invoice.raw_total).to eq(2000)
246
+
247
+ subscription.no_prorate.add_plan(@other_plan_id)
248
+
249
+ # Assert that no new invoice was created because of no prorating.
250
+ expect(user.invoices.first.id).to eq(invoice.id)
251
+
252
+ subscription.add_plan_and_invoice(@plan_id)
253
+
254
+ # Assert that a new invoice was created because of no prorating.
255
+ invoice = user.invoices.first
256
+ expect(invoice.raw_total).to eq(1000)
257
+ expect(user.upcoming_invoice.raw_total).to eq(4000)
258
+
259
+ subscription.no_prorate.remove_plan(@premium_plan_id)
260
+
261
+ # Assert that no new invoice was created because of no prorating.
262
+ expect(user.invoices.first.id).to eq(invoice.id)
263
+ expect(user.upcoming_invoice.raw_total).to eq(2000)
264
+ end
265
+
266
+ it 'test_subscription_item_quantity_changes_can_be_prorated' do
267
+ user = create_customer('subscription_item_quantity_changes_can_be_prorated')
268
+
269
+ subscription = user.new_subscription('main', [@plan_id, @other_plan_id])
270
+ .quantity(3, @other_plan_id)
271
+ .create('pm_card_visa')
272
+
273
+ invoice = user.invoices.first
274
+
275
+ expect(invoice.raw_total).to eq(4000)
276
+
277
+ subscription.no_prorate.update_quantity(1, @other_plan_id)
278
+
279
+ expect(user.upcoming_invoice.raw_total).to eq(2000)
280
+ end
281
+
282
+ protected
283
+
284
+ # Create a subscription with a single plan.
285
+ def create_subscription_with_single_plan(user)
286
+ subscription = user.subscriptions.create({
287
+ :name => 'main',
288
+ :stripe_id => 'sub_foo',
289
+ :stripe_plan => @plan_id,
290
+ :quantity => 1,
291
+ :stripe_status => 'active',
292
+ })
293
+
294
+ subscription.items.create({
295
+ :stripe_id => 'it_foo',
296
+ :stripe_plan => @plan_id,
297
+ :quantity => 1,
298
+ })
299
+
300
+ subscription
301
+ end
302
+
303
+ # Create a subscription with multiple plans.
304
+ def create_subscription_with_multiple_plans(user)
305
+ subscription = self.create_subscription_with_single_plan(user)
306
+
307
+ subscription.stripe_plan = nil
308
+ subscription.quantity = nil
309
+ subscription.save
310
+
311
+ subscription.items.new({
312
+ :stripe_id => 'it_foo',
313
+ :stripe_plan => @other_plan_id,
314
+ :quantity => 1,
315
+ })
316
+
317
+ subscription
318
+ end
319
+ end