stripe-rails 2.0.0.pre → 2.3.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.
- checksums.yaml +4 -4
- data/.github/pull_request_template.md +12 -1
- data/.github/workflows/ruby.yml +4 -1
- data/Changelog.md +28 -1
- data/README.md +44 -6
- data/Rakefile +0 -0
- data/config/routes.rb +0 -1
- data/gemfiles/rails60.gemfile +19 -0
- data/lib/generators/stripe/install_generator.rb +1 -0
- data/lib/generators/templates/prices.rb +46 -0
- data/lib/stripe/callbacks.rb +2 -0
- data/lib/stripe/coupons.rb +2 -1
- data/lib/stripe/engine.rb +5 -5
- data/lib/stripe/prices.rb +189 -0
- data/lib/stripe/rails.rb +1 -0
- data/lib/stripe/rails/tasks.rake +11 -2
- data/lib/stripe/rails/version.rb +1 -1
- data/test/coupon_builder_spec.rb +1 -0
- data/test/dummy/config/stripe/prices.rb +59 -0
- data/test/dummy_apis_controller_spec.rb +1 -1
- data/test/events_controller_spec.rb +22 -3
- data/test/fixtures/stripe_prices.json +7 -0
- data/test/plan_builder_spec.rb +1 -1
- data/test/price_builder_spec.rb +594 -0
- data/test/stripe_initializers_spec.rb +47 -4
- metadata +17 -8
data/lib/stripe/rails.rb
CHANGED
data/lib/stripe/rails/tasks.rake
CHANGED
@@ -30,6 +30,15 @@ namespace :stripe do
|
|
30
30
|
Stripe::Coupons.reset!
|
31
31
|
end
|
32
32
|
|
33
|
-
|
34
|
-
|
33
|
+
task 'prices:prepare' => 'environment' do
|
34
|
+
Stripe::Prices.put!
|
35
|
+
end
|
36
|
+
|
37
|
+
desc 'delete and redefine all prices defined in config/stripe/prices.rb'
|
38
|
+
task 'prices:reset!' => 'environment' do
|
39
|
+
Stripe::Prices.reset!
|
40
|
+
end
|
41
|
+
|
42
|
+
desc "create all plans and coupons defined in config/stripe/{products|plans|prices|coupons}.rb"
|
43
|
+
task 'prepare' => ['products:prepare', 'plans:prepare', 'prices:prepare', 'coupons:prepare']
|
35
44
|
end
|
data/lib/stripe/rails/version.rb
CHANGED
data/test/coupon_builder_spec.rb
CHANGED
@@ -0,0 +1,59 @@
|
|
1
|
+
Stripe.price :gold do |price|
|
2
|
+
price.name = 'Solid Gold'
|
3
|
+
price.unit_amount = 699
|
4
|
+
price.recurring = {
|
5
|
+
interval: 'month'
|
6
|
+
}
|
7
|
+
end
|
8
|
+
|
9
|
+
Stripe.price "Solid Gold".to_sym do |price|
|
10
|
+
price.constant_name = 'SOLID_GOLD'
|
11
|
+
price.name = 'Solid Gold'
|
12
|
+
price.unit_amount = 699
|
13
|
+
price.recurring = {
|
14
|
+
interval: 'month'
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
Stripe.price :alternative_currency do |price|
|
19
|
+
price.name = 'Alternative Currency'
|
20
|
+
price.unit_amount = 699
|
21
|
+
price.recurring = {
|
22
|
+
interval: 'month'
|
23
|
+
}
|
24
|
+
price.currency = 'cad'
|
25
|
+
end
|
26
|
+
|
27
|
+
Stripe.price :metered do |price|
|
28
|
+
price.name = 'Metered'
|
29
|
+
price.unit_amount = 699
|
30
|
+
price.recurring = {
|
31
|
+
interval: 'month',
|
32
|
+
aggregate_usage: 'max',
|
33
|
+
usage_type: 'metered'
|
34
|
+
}
|
35
|
+
price.billing_scheme = 'per_unit'
|
36
|
+
end
|
37
|
+
|
38
|
+
Stripe.price :tiered do |price|
|
39
|
+
price.name = 'Tiered'
|
40
|
+
price.billing_scheme = 'tiered'
|
41
|
+
# interval must be either 'day', 'week', 'month' or 'year'
|
42
|
+
price.recurring = {
|
43
|
+
interval: 'month',
|
44
|
+
interval_count: 2,
|
45
|
+
aggregate_usage: 'max',
|
46
|
+
usage_type: 'metered'
|
47
|
+
}
|
48
|
+
price.tiers = [
|
49
|
+
{
|
50
|
+
unit_amount: 1500,
|
51
|
+
up_to: 10
|
52
|
+
},
|
53
|
+
{
|
54
|
+
unit_amount: 1000,
|
55
|
+
up_to: 'inf'
|
56
|
+
}
|
57
|
+
]
|
58
|
+
price.tiers_mode = 'graduated'
|
59
|
+
end
|
@@ -10,6 +10,10 @@ describe Stripe::EventsController do
|
|
10
10
|
end
|
11
11
|
|
12
12
|
describe 'the events interface' do
|
13
|
+
subject { post '/stripe/events', params.to_json }
|
14
|
+
|
15
|
+
before { stripe_events_stub }
|
16
|
+
|
13
17
|
let(:params) {
|
14
18
|
{
|
15
19
|
id: 'evt_00000000000000',
|
@@ -17,14 +21,29 @@ describe Stripe::EventsController do
|
|
17
21
|
data: {object: 'customer'},
|
18
22
|
}
|
19
23
|
}
|
20
|
-
|
21
|
-
before do
|
24
|
+
let(:stripe_events_stub) do
|
22
25
|
stub_request(:get, "https://api.stripe.com/v1/events/evt_00000000000000").
|
23
26
|
to_return(status: 200, body: Stripe::Event.construct_from(params).to_json, headers: {})
|
24
27
|
end
|
25
|
-
subject { post '/stripe/events', params.to_json }
|
26
28
|
|
27
29
|
it { _(subject).must_be :ok? }
|
30
|
+
|
31
|
+
it 'should call the stripe_events_stub' do
|
32
|
+
subject
|
33
|
+
assert_requested(stripe_events_stub)
|
34
|
+
end
|
35
|
+
|
36
|
+
describe 'when signing_secret is nil' do
|
37
|
+
before do
|
38
|
+
header 'Stripe-Signature', 't=1537832721,v1=123,v0=123'
|
39
|
+
app.config.stripe.signing_secret = nil
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should call the stripe_events_stub' do
|
43
|
+
subject
|
44
|
+
assert_requested(stripe_events_stub)
|
45
|
+
end
|
46
|
+
end
|
28
47
|
end
|
29
48
|
|
30
49
|
describe 'signed webhooks' do
|
data/test/plan_builder_spec.rb
CHANGED
@@ -140,7 +140,7 @@ describe 'building plans' do
|
|
140
140
|
}).must_raise Stripe::InvalidConfigurationError
|
141
141
|
end
|
142
142
|
|
143
|
-
it 'denies aggregate_usage if usage type is
|
143
|
+
it 'denies aggregate_usage if usage type is licensed' do
|
144
144
|
_(lambda {
|
145
145
|
Stripe.plan :broken do |plan|
|
146
146
|
plan.name = 'Acme as a service'
|
@@ -0,0 +1,594 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'building prices' do
|
4
|
+
describe 'simply' do
|
5
|
+
before do
|
6
|
+
Stripe.price :lite do |price|
|
7
|
+
price.name = 'Acme as a service LITE'
|
8
|
+
price.unit_amount = 699
|
9
|
+
price.recurring = {
|
10
|
+
interval: 'month',
|
11
|
+
interval_count: 3,
|
12
|
+
usage_type: 'metered',
|
13
|
+
aggregate_usage: 'sum'
|
14
|
+
}
|
15
|
+
price.metadata = {:number_of_awesome_things => 5}
|
16
|
+
price.statement_descriptor = 'Acme Lite'
|
17
|
+
price.active = true
|
18
|
+
price.nickname = 'lite'
|
19
|
+
price.billing_scheme = 'per_unit'
|
20
|
+
price.tiers_mode = 'graduated'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
after { Stripe::Prices.send(:remove_const, :LITE) }
|
25
|
+
|
26
|
+
it 'is accessible via id' do
|
27
|
+
_(Stripe::Prices::LITE).wont_be_nil
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'is accessible via collection' do
|
31
|
+
_(Stripe::Prices.all).must_include Stripe::Prices::LITE
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'is accessible via hash lookup (symbol/string agnostic)' do
|
35
|
+
_(Stripe::Prices[:lite]).must_equal Stripe::Prices::LITE
|
36
|
+
_(Stripe::Prices['lite']).must_equal Stripe::Prices::LITE
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'sets the lookup key' do
|
40
|
+
_(Stripe::Prices::LITE.lookup_key).must_equal 'lite'
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'accepts a billing interval of a day' do
|
44
|
+
Stripe.price :daily do |price|
|
45
|
+
price.name = 'Acme as a service daily'
|
46
|
+
price.unit_amount = 100
|
47
|
+
price.recurring = {
|
48
|
+
interval: 'day'
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
_(Stripe::Prices::DAILY).wont_be_nil
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'denies a billing interval of a day and excessive intervals' do
|
56
|
+
_(lambda {
|
57
|
+
Stripe.price :broken do |price|
|
58
|
+
price.name = 'Acme as a service daily'
|
59
|
+
price.unit_amount = 100
|
60
|
+
price.recurring = {
|
61
|
+
interval: 'day',
|
62
|
+
interval_count: 366
|
63
|
+
}
|
64
|
+
end
|
65
|
+
}).must_raise Stripe::InvalidConfigurationError
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'accepts a billing interval of a week' do
|
69
|
+
Stripe.price :weekly do |price|
|
70
|
+
price.name = 'Acme as a service weekly'
|
71
|
+
price.unit_amount = 100
|
72
|
+
price.recurring = {
|
73
|
+
interval: 'week'
|
74
|
+
}
|
75
|
+
end
|
76
|
+
|
77
|
+
_(Stripe::Prices::WEEKLY).wont_be_nil
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'denies a billing interval of a week and excessive intervals' do
|
81
|
+
_(lambda {
|
82
|
+
Stripe.price :broken do |price|
|
83
|
+
price.name = 'Acme as a service weekly'
|
84
|
+
price.unit_amount = 100
|
85
|
+
price.recurring = {
|
86
|
+
interval: 'week',
|
87
|
+
interval_count: 53
|
88
|
+
}
|
89
|
+
end
|
90
|
+
}).must_raise Stripe::InvalidConfigurationError
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'accepts a billing interval of a month' do
|
94
|
+
Stripe.price :monthly do |price|
|
95
|
+
price.name = 'Acme as a service monthly'
|
96
|
+
price.unit_amount = 400
|
97
|
+
price.recurring = {
|
98
|
+
interval: 'month'
|
99
|
+
}
|
100
|
+
end
|
101
|
+
|
102
|
+
_(Stripe::Prices::MONTHLY).wont_be_nil
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'denies a billing interval of a month and excessive intervals' do
|
106
|
+
_(lambda {
|
107
|
+
Stripe.price :broken do |price|
|
108
|
+
price.name = 'Acme as a service monthly'
|
109
|
+
price.unit_amount = 400
|
110
|
+
price.recurring = {
|
111
|
+
interval: 'month',
|
112
|
+
interval_count: 13
|
113
|
+
}
|
114
|
+
end
|
115
|
+
}).must_raise Stripe::InvalidConfigurationError
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'accepts a billing interval of a year' do
|
119
|
+
Stripe.price :yearly do |price|
|
120
|
+
price.name = 'Acme as a service yearly'
|
121
|
+
price.unit_amount = 4800
|
122
|
+
price.recurring = {
|
123
|
+
interval: 'year'
|
124
|
+
}
|
125
|
+
end
|
126
|
+
|
127
|
+
_(Stripe::Prices::YEARLY).wont_be_nil
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'denies a billing interval of a year and excessive intervals' do
|
131
|
+
_(lambda {
|
132
|
+
Stripe.price :broken do |price|
|
133
|
+
price.name = 'Acme as a service yearly'
|
134
|
+
price.unit_amount = 4800
|
135
|
+
price.recurring = {
|
136
|
+
interval: 'year',
|
137
|
+
interval_count: 2
|
138
|
+
}
|
139
|
+
end
|
140
|
+
}).must_raise Stripe::InvalidConfigurationError
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'denies arbitrary billing intervals' do
|
144
|
+
_(lambda {
|
145
|
+
Stripe.price :broken do |price|
|
146
|
+
price.name = 'Acme as a service BROKEN'
|
147
|
+
price.unit_amount = 999
|
148
|
+
price.recurring = {
|
149
|
+
interval: 'anything'
|
150
|
+
}
|
151
|
+
end
|
152
|
+
}).must_raise Stripe::InvalidConfigurationError
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'accepts empty recurring options' do
|
156
|
+
Stripe.price :singular do |price|
|
157
|
+
price.name = 'Acme as a service one time'
|
158
|
+
price.unit_amount = 888
|
159
|
+
end
|
160
|
+
|
161
|
+
_(Stripe::Prices::SINGULAR).wont_be_nil
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'accepts a statement descriptor' do
|
165
|
+
Stripe.price :described do |price|
|
166
|
+
price.name = 'Acme as a service'
|
167
|
+
price.unit_amount = 999
|
168
|
+
price.recurring = {
|
169
|
+
interval: 'month'
|
170
|
+
}
|
171
|
+
price.statement_descriptor = 'ACME Monthly'
|
172
|
+
end
|
173
|
+
|
174
|
+
_(Stripe::Prices::DESCRIBED).wont_be_nil
|
175
|
+
end
|
176
|
+
|
177
|
+
it 'denies statement descriptors that are too long' do
|
178
|
+
_(lambda {
|
179
|
+
Stripe.price :described do |price|
|
180
|
+
price.name = 'Acme as a service'
|
181
|
+
price.unit_amount = 999
|
182
|
+
price.recurring = {
|
183
|
+
interval: 'month'
|
184
|
+
}
|
185
|
+
price.statement_descriptor = 'ACME as a Service Monthly'
|
186
|
+
end
|
187
|
+
}).must_raise Stripe::InvalidConfigurationError
|
188
|
+
end
|
189
|
+
|
190
|
+
it 'denies invalid values for active' do
|
191
|
+
_(lambda {
|
192
|
+
Stripe.price :broken do |price|
|
193
|
+
price.name = 'Acme as a service'
|
194
|
+
price.unit_amount = 999
|
195
|
+
price.recurring = {
|
196
|
+
interval: 'month'
|
197
|
+
}
|
198
|
+
price.active = 'whatever'
|
199
|
+
end
|
200
|
+
}).must_raise Stripe::InvalidConfigurationError
|
201
|
+
end
|
202
|
+
|
203
|
+
it 'denies invalid values for usage_type' do
|
204
|
+
_(lambda {
|
205
|
+
Stripe.price :broken do |price|
|
206
|
+
price.name = 'Acme as a service'
|
207
|
+
price.unit_amount = 999
|
208
|
+
price.recurring = {
|
209
|
+
interval: 'month',
|
210
|
+
usage_type: 'whatever'
|
211
|
+
}
|
212
|
+
end
|
213
|
+
}).must_raise Stripe::InvalidConfigurationError
|
214
|
+
end
|
215
|
+
|
216
|
+
it 'denies invalid values for aggregate_usage' do
|
217
|
+
_(lambda {
|
218
|
+
Stripe.price :broken do |price|
|
219
|
+
price.name = 'Acme as a service'
|
220
|
+
price.unit_amount = 999
|
221
|
+
price.recurring = {
|
222
|
+
interval: 'month',
|
223
|
+
aggregate_usage: 'whatever'
|
224
|
+
}
|
225
|
+
end
|
226
|
+
}).must_raise Stripe::InvalidConfigurationError
|
227
|
+
end
|
228
|
+
|
229
|
+
it 'denies aggregate_usage if usage type is licensed' do
|
230
|
+
_(lambda {
|
231
|
+
Stripe.price :broken do |price|
|
232
|
+
price.name = 'Acme as a service'
|
233
|
+
price.unit_amount = 999
|
234
|
+
price.recurring = {
|
235
|
+
interval: 'month',
|
236
|
+
usage_type: 'licensed',
|
237
|
+
aggregate_usage: 'sum'
|
238
|
+
}
|
239
|
+
end
|
240
|
+
}).must_raise Stripe::InvalidConfigurationError
|
241
|
+
end
|
242
|
+
|
243
|
+
|
244
|
+
it 'denies invalid values for billing_scheme' do
|
245
|
+
_(lambda {
|
246
|
+
Stripe.price :broken do |price|
|
247
|
+
price.name = 'Acme as a service'
|
248
|
+
price.unit_amount = 999
|
249
|
+
price.recurring = {
|
250
|
+
interval: 'month'
|
251
|
+
}
|
252
|
+
price.billing_scheme = 'whatever'
|
253
|
+
end
|
254
|
+
}).must_raise Stripe::InvalidConfigurationError
|
255
|
+
end
|
256
|
+
|
257
|
+
it 'denies invalid values for tiers_mode' do
|
258
|
+
_(lambda {
|
259
|
+
Stripe.price :broken do |price|
|
260
|
+
price.name = 'Acme as a service'
|
261
|
+
price.unit_amount = 999
|
262
|
+
price.recurring = {
|
263
|
+
interval: 'month'
|
264
|
+
}
|
265
|
+
price.tiers_mode = 'whatever'
|
266
|
+
end
|
267
|
+
}).must_raise Stripe::InvalidConfigurationError
|
268
|
+
end
|
269
|
+
|
270
|
+
describe 'name and product id validation' do
|
271
|
+
it 'should be valid when using just the product id' do
|
272
|
+
Stripe.price :prodded do |price|
|
273
|
+
price.product_id = 'acme'
|
274
|
+
price.unit_amount = 999
|
275
|
+
price.recurring = {
|
276
|
+
interval: 'month'
|
277
|
+
}
|
278
|
+
end
|
279
|
+
_(Stripe::Prices::PRODDED).wont_be_nil
|
280
|
+
end
|
281
|
+
|
282
|
+
it 'should be invalid when using both name and product id' do
|
283
|
+
_(lambda {
|
284
|
+
Stripe.price :broken do |price|
|
285
|
+
price.name = 'Acme as a service'
|
286
|
+
price.product_id = 'acme'
|
287
|
+
price.unit_amount = 999
|
288
|
+
price.recurring = {
|
289
|
+
interval: 'month'
|
290
|
+
}
|
291
|
+
end
|
292
|
+
}).must_raise Stripe::InvalidConfigurationError
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
describe 'uploading' do
|
297
|
+
include FixtureLoader
|
298
|
+
|
299
|
+
describe 'when none exists on stripe.com' do
|
300
|
+
before do
|
301
|
+
Stripe::Price.stubs(:list).returns(Stripe::Price.construct_from(data: []))
|
302
|
+
|
303
|
+
stub_request(:get, "https://api.stripe.com/v1/prices").
|
304
|
+
with(headers: { 'Authorization'=>'Bearer XYZ',}).
|
305
|
+
to_return(status: 200, body: load_request_fixture('stripe_prices.json'))
|
306
|
+
end
|
307
|
+
|
308
|
+
it 'creates the price online' do
|
309
|
+
Stripe::Price.expects(:create).with(
|
310
|
+
:lookup_key => 'gold',
|
311
|
+
:nickname => 'gold',
|
312
|
+
:currency => 'usd',
|
313
|
+
:product_data => {
|
314
|
+
:name => 'Solid Gold',
|
315
|
+
:statement_descriptor => nil
|
316
|
+
},
|
317
|
+
:unit_amount => 699,
|
318
|
+
:recurring => {
|
319
|
+
:interval => 'month'
|
320
|
+
}
|
321
|
+
)
|
322
|
+
Stripe::Prices::GOLD.put!
|
323
|
+
end
|
324
|
+
|
325
|
+
it 'creates a price with an alternative currency' do
|
326
|
+
Stripe::Price.expects(:create).with(
|
327
|
+
:lookup_key => 'alternative_currency',
|
328
|
+
:nickname => 'alternative_currency',
|
329
|
+
:currency => 'cad',
|
330
|
+
:product_data => {
|
331
|
+
:name => 'Alternative Currency',
|
332
|
+
:statement_descriptor => nil
|
333
|
+
},
|
334
|
+
:unit_amount => 699,
|
335
|
+
:recurring => {
|
336
|
+
:interval => 'month'
|
337
|
+
}
|
338
|
+
)
|
339
|
+
Stripe::Prices::ALTERNATIVE_CURRENCY.put!
|
340
|
+
end
|
341
|
+
|
342
|
+
it 'creates a metered price' do
|
343
|
+
Stripe::Price.expects(:create).with(
|
344
|
+
:lookup_key => 'metered',
|
345
|
+
:nickname => 'metered',
|
346
|
+
:currency => 'usd',
|
347
|
+
:product_data => {
|
348
|
+
:name => 'Metered',
|
349
|
+
:statement_descriptor => nil,
|
350
|
+
},
|
351
|
+
:unit_amount => 699,
|
352
|
+
:recurring => {
|
353
|
+
:interval => 'month',
|
354
|
+
:usage_type => 'metered',
|
355
|
+
:aggregate_usage => 'max',
|
356
|
+
},
|
357
|
+
:billing_scheme => 'per_unit'
|
358
|
+
)
|
359
|
+
Stripe::Prices::METERED.put!
|
360
|
+
end
|
361
|
+
|
362
|
+
it 'creates a tiered price' do
|
363
|
+
Stripe::Price.expects(:create).with(
|
364
|
+
:lookup_key => 'tiered',
|
365
|
+
:nickname => 'tiered',
|
366
|
+
:currency => 'usd',
|
367
|
+
:product_data => {
|
368
|
+
:name => 'Tiered',
|
369
|
+
:statement_descriptor => nil,
|
370
|
+
},
|
371
|
+
:recurring => {
|
372
|
+
:interval => 'month',
|
373
|
+
:interval_count => 2,
|
374
|
+
:usage_type => 'metered',
|
375
|
+
:aggregate_usage => 'max'
|
376
|
+
},
|
377
|
+
:billing_scheme => 'tiered',
|
378
|
+
:tiers => [
|
379
|
+
{
|
380
|
+
:unit_amount => 1500,
|
381
|
+
:up_to => 10
|
382
|
+
},
|
383
|
+
{
|
384
|
+
:unit_amount => 1000,
|
385
|
+
:up_to => 'inf'
|
386
|
+
}
|
387
|
+
],
|
388
|
+
:tiers_mode => 'graduated'
|
389
|
+
)
|
390
|
+
Stripe::Prices::TIERED.put!
|
391
|
+
end
|
392
|
+
|
393
|
+
describe 'when passed invalid arguments for tiered pricing' do
|
394
|
+
it 'raises a Stripe::InvalidConfigurationError when billing tiers are invalid' do
|
395
|
+
lambda {
|
396
|
+
Stripe.price "Bad Tiers".to_sym do |price|
|
397
|
+
price.name = 'Acme as a service BAD TIERS'
|
398
|
+
price.constant_name = 'BAD_TIERS'
|
399
|
+
price.recurring = {
|
400
|
+
interval: 'month',
|
401
|
+
interval_count: 1,
|
402
|
+
usage_type: 'metered',
|
403
|
+
aggregate_usage: 'sum'
|
404
|
+
}
|
405
|
+
price.tiers_mode = 'graduated'
|
406
|
+
price.billing_scheme = 'per_unit'
|
407
|
+
price.tiers = [
|
408
|
+
{
|
409
|
+
unit_amount: 1500,
|
410
|
+
up_to: 10
|
411
|
+
},
|
412
|
+
{
|
413
|
+
unit_amount: 1000,
|
414
|
+
}
|
415
|
+
]
|
416
|
+
end
|
417
|
+
}.must_raise Stripe::InvalidConfigurationError
|
418
|
+
end
|
419
|
+
|
420
|
+
it 'raises a Stripe::InvalidConfigurationError when billing tiers is not an array' do
|
421
|
+
lambda {
|
422
|
+
Stripe.price "Bad Tiers".to_sym do |price|
|
423
|
+
price.name = 'Acme as a service BAD TIERS'
|
424
|
+
price.constant_name = 'BAD_TIERS'
|
425
|
+
price.recurring = {
|
426
|
+
interval: 'month',
|
427
|
+
interval_count: 1,
|
428
|
+
usage_type: 'metered',
|
429
|
+
aggregate_usage: 'sum'
|
430
|
+
}
|
431
|
+
price.tiers_mode = 'graduated'
|
432
|
+
price.billing_scheme = 'per_unit'
|
433
|
+
price.tiers = {
|
434
|
+
unit_amount: 1500,
|
435
|
+
up_to: 10
|
436
|
+
}
|
437
|
+
end
|
438
|
+
}.must_raise Stripe::InvalidConfigurationError
|
439
|
+
end
|
440
|
+
end
|
441
|
+
|
442
|
+
describe 'when using a product id' do
|
443
|
+
before do
|
444
|
+
Stripe::Prices::GOLD.product_id = 'prod_XXXXXXXXXXXXXX'
|
445
|
+
Stripe::Prices::GOLD.name = nil
|
446
|
+
end
|
447
|
+
after do
|
448
|
+
Stripe::Prices::GOLD.product_id = nil
|
449
|
+
Stripe::Prices::GOLD.name = 'Solid Gold'
|
450
|
+
end
|
451
|
+
|
452
|
+
it 'creates the price online with the product id' do
|
453
|
+
Stripe::Price.expects(:create).with(
|
454
|
+
:lookup_key => 'gold',
|
455
|
+
:nickname => 'gold',
|
456
|
+
:currency => 'usd',
|
457
|
+
:product => 'prod_XXXXXXXXXXXXXX',
|
458
|
+
:unit_amount => 699,
|
459
|
+
:recurring => {
|
460
|
+
:interval => 'month'
|
461
|
+
}
|
462
|
+
)
|
463
|
+
Stripe::Prices::GOLD.put!
|
464
|
+
end
|
465
|
+
end
|
466
|
+
end
|
467
|
+
|
468
|
+
describe 'when it is already present on stripe.com' do
|
469
|
+
before do
|
470
|
+
Stripe::Prices::GOLD.product_id = nil
|
471
|
+
Stripe::Price.stubs(:list).returns(Stripe::Price.construct_from(
|
472
|
+
data: [{
|
473
|
+
:lookup_key => 'gold',
|
474
|
+
:product => 'prod_XXXXXXXXXXXXXX'
|
475
|
+
}]))
|
476
|
+
end
|
477
|
+
after do
|
478
|
+
Stripe::Prices::GOLD.product_id = nil
|
479
|
+
end
|
480
|
+
|
481
|
+
|
482
|
+
it 'is a no-op on put!' do
|
483
|
+
Stripe::Price.expects(:create).never
|
484
|
+
Stripe::Prices::GOLD.put!
|
485
|
+
end
|
486
|
+
|
487
|
+
it 'transfers lookup key on reset!' do
|
488
|
+
Stripe::Price.expects(:create).with(
|
489
|
+
:lookup_key => 'gold',
|
490
|
+
:transfer_lookup_key => true,
|
491
|
+
:nickname => 'gold',
|
492
|
+
:currency => 'usd',
|
493
|
+
:product => 'prod_XXXXXXXXXXXXXX',
|
494
|
+
:unit_amount => 699,
|
495
|
+
:recurring => {
|
496
|
+
:interval => 'month'
|
497
|
+
}
|
498
|
+
)
|
499
|
+
|
500
|
+
Stripe::Prices::GOLD.reset!
|
501
|
+
end
|
502
|
+
end
|
503
|
+
end
|
504
|
+
end
|
505
|
+
|
506
|
+
describe 'with missing mandatory values' do
|
507
|
+
it 'raises an exception after configuring it' do
|
508
|
+
_(-> { Stripe.price(:bad) {} }).must_raise Stripe::InvalidConfigurationError
|
509
|
+
end
|
510
|
+
end
|
511
|
+
|
512
|
+
describe 'with custom constant name' do
|
513
|
+
before do
|
514
|
+
Stripe.price "Lite price".to_sym do |price|
|
515
|
+
price.name = 'Acme as a service LITE'
|
516
|
+
price.constant_name = 'LITE_PRICE'
|
517
|
+
price.unit_amount = 699
|
518
|
+
price.recurring = {
|
519
|
+
interval: 'month',
|
520
|
+
interval_count: 3,
|
521
|
+
usage_type: 'metered',
|
522
|
+
aggregate_usage: 'sum'
|
523
|
+
}
|
524
|
+
price.metadata = {:number_of_awesome_things => 5}
|
525
|
+
price.statement_descriptor = 'Acme Lite'
|
526
|
+
price.active = true
|
527
|
+
price.nickname = 'lite'
|
528
|
+
price.billing_scheme = 'per_unit'
|
529
|
+
price.tiers_mode = 'graduated'
|
530
|
+
end
|
531
|
+
end
|
532
|
+
|
533
|
+
after { Stripe::Prices.send(:remove_const, :LITE_PRICE) }
|
534
|
+
|
535
|
+
it 'is accessible via upcased constant_name' do
|
536
|
+
_(Stripe::Prices::LITE_PRICE).wont_be_nil
|
537
|
+
end
|
538
|
+
|
539
|
+
it 'is accessible via collection' do
|
540
|
+
_(Stripe::Prices.all).must_include Stripe::Prices::LITE_PRICE
|
541
|
+
end
|
542
|
+
|
543
|
+
it 'is accessible via hash lookup (symbol/string agnostic)' do
|
544
|
+
_(Stripe::Prices[:lite_price]).must_equal Stripe::Prices::LITE_PRICE
|
545
|
+
_(Stripe::Prices['lite_price']).must_equal Stripe::Prices::LITE_PRICE
|
546
|
+
end
|
547
|
+
|
548
|
+
describe 'constant name validation' do
|
549
|
+
it 'should be invalid when providing a constant name that can not be used for Ruby constant' do
|
550
|
+
_(lambda {
|
551
|
+
Stripe.price "Lite price".to_sym do |price|
|
552
|
+
price.name = 'Acme as a service LITE'
|
553
|
+
price.constant_name = 'LITE PRICE'
|
554
|
+
price.unit_amount = 999
|
555
|
+
price.recurring = {
|
556
|
+
interval: 'month'
|
557
|
+
}
|
558
|
+
end
|
559
|
+
}).must_raise Stripe::InvalidConfigurationError
|
560
|
+
end
|
561
|
+
end
|
562
|
+
|
563
|
+
describe 'uploading' do
|
564
|
+
include FixtureLoader
|
565
|
+
|
566
|
+
describe 'when none exists on stripe.com' do
|
567
|
+
before do
|
568
|
+
Stripe::Price.stubs(:list).returns(Stripe::Price.construct_from(data: []))
|
569
|
+
|
570
|
+
stub_request(:get, "https://api.stripe.com/v1/prices").
|
571
|
+
with(headers: { 'Authorization'=>'Bearer XYZ',}).
|
572
|
+
to_return(status: 200, body: load_request_fixture('stripe_prices.json'))
|
573
|
+
end
|
574
|
+
|
575
|
+
it 'creates the price online' do
|
576
|
+
Stripe::Price.expects(:create).with(
|
577
|
+
:lookup_key => "Solid Gold",
|
578
|
+
:nickname => "Solid Gold",
|
579
|
+
:currency => 'usd',
|
580
|
+
:product_data => {
|
581
|
+
:name => 'Solid Gold',
|
582
|
+
:statement_descriptor => nil
|
583
|
+
},
|
584
|
+
:unit_amount => 699,
|
585
|
+
:recurring => {
|
586
|
+
:interval => 'month'
|
587
|
+
}
|
588
|
+
)
|
589
|
+
Stripe::Prices::SOLID_GOLD.put!
|
590
|
+
end
|
591
|
+
end
|
592
|
+
end
|
593
|
+
end
|
594
|
+
end
|