zillion 0.0.8 → 0.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.
- checksums.yaml +4 -4
- data/lib/zillion/plan.rb +38 -21
- data/spec/plans_spec.rb +211 -106
- data/zillion.gemspec +1 -1
- metadata +3 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 91b941a168263933e9486bb2e3ba9dacf45b3d65
|
4
|
+
data.tar.gz: 6eafd20870092fa550a2f44e816d9776660c5e51
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0e4be1ce406af366e61cfe47433d3a0f33637bf548bd1ac7706d9359397b062a7effa77909cd4b89a381452bbb6a86849481f083b45f1781f7a2a9327521a31e
|
7
|
+
data.tar.gz: 95e9d521a36ec5f21d4c921fc6693b39f379076eeb7f33f3a7c8a9c8414619a1a8fdc154eaffeaaccd4a5ade8670761ec99753c236e5a36d82a8d15cf41d9d71
|
data/lib/zillion/plan.rb
CHANGED
@@ -128,16 +128,16 @@ class TieredPlan < Plan
|
|
128
128
|
def amounts_for(counts)
|
129
129
|
tier = matching_tier_for(counts)
|
130
130
|
obj = {}
|
131
|
-
obj[tier.last.to_sym] = tier[1]
|
131
|
+
obj[tier.last.to_sym] = tier[1] # tier[1] is monthly cost
|
132
132
|
obj
|
133
133
|
end
|
134
134
|
|
135
135
|
def matching_tier_for(counts)
|
136
136
|
if tiers = matching_tiers_for(counts) and tiers.any?
|
137
|
-
#
|
138
|
-
tiers.
|
137
|
+
# sort by monthly cost and return highest (first) one
|
138
|
+
tiers.sort { |a, b| a[1] <=> b[1] }.last
|
139
139
|
else
|
140
|
-
raise "No matching tiers found for #{counts.inspect} in #{name} plan."
|
140
|
+
raise TierNotFoundError.new("No matching tiers found for #{counts.inspect} in #{name} plan.")
|
141
141
|
end
|
142
142
|
end
|
143
143
|
|
@@ -148,11 +148,6 @@ class TieredPlan < Plan
|
|
148
148
|
|
149
149
|
private
|
150
150
|
|
151
|
-
def matching_tiers_for(counts)
|
152
|
-
# sort by amount (format is [range, monthly_cost, index, type])
|
153
|
-
get_matching_tiers(counts).sort { |a, b| b[1] <=> a[1] }
|
154
|
-
end
|
155
|
-
|
156
151
|
def find_tier_for(tiers, units)
|
157
152
|
# raise "Units not set!" unless units
|
158
153
|
arr = tiers.select { |t| t[0].include?(units) }
|
@@ -168,10 +163,10 @@ class TieredPlan < Plan
|
|
168
163
|
|
169
164
|
def tier_groups
|
170
165
|
spec[:tiers].each_with_object({}) do |(key, list), obj|
|
171
|
-
obj[key] = list.map do |t|
|
166
|
+
obj[key.to_sym] = list.map do |t|
|
172
167
|
h = symbolize_keys(t)
|
173
168
|
[ h[:from]..h[:to], h[tier_cost_key] ]
|
174
|
-
end
|
169
|
+
end.sort { |a, b| a[0].last <=> b[0].last } # sort by last/highest item in range
|
175
170
|
end
|
176
171
|
end
|
177
172
|
|
@@ -179,10 +174,22 @@ class TieredPlan < Plan
|
|
179
174
|
:monthly_cost
|
180
175
|
end
|
181
176
|
|
182
|
-
|
177
|
+
# returns the last/highest existing tiers for the given keys
|
178
|
+
def last_existing_tier_for(key)
|
179
|
+
if found = tier_groups[key.to_sym]
|
180
|
+
found.last + [key]
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def matching_tiers_for(counts, fallback_to_highest_tier = false)
|
183
185
|
tier_groups.map do |key, tiers|
|
184
|
-
units = counts[key] or raise "Unit count required for #{key}"
|
185
|
-
|
186
|
+
units = counts[key] or raise MissingCountError.new("Unit count required for #{key}")
|
187
|
+
begin
|
188
|
+
find_tier_for(tiers, units.to_i) + [key]
|
189
|
+
rescue TierNotFoundError
|
190
|
+
raise unless fallback_to_highest_tier
|
191
|
+
last_existing_tier_for(key)
|
192
|
+
end
|
186
193
|
end.compact
|
187
194
|
end
|
188
195
|
|
@@ -194,11 +201,11 @@ end
|
|
194
201
|
|
195
202
|
class MeteredPlan < TieredPlan
|
196
203
|
|
197
|
-
def amounts_for(counts)
|
204
|
+
def amounts_for(counts, fallback_to_highest_tier = false)
|
198
205
|
obj = {}
|
199
|
-
matching_tiers_for(counts).map do |tier|
|
206
|
+
matching_tiers_for(counts, fallback_to_highest_tier).map do |tier|
|
200
207
|
units = units_for(tier.last, counts)
|
201
|
-
obj[tier.last.to_sym] = units * tier[1]
|
208
|
+
obj[tier.last.to_sym] = units * tier[1] # tier[1] is monthly unit cost
|
202
209
|
end
|
203
210
|
obj
|
204
211
|
end
|
@@ -207,6 +214,8 @@ class MeteredPlan < TieredPlan
|
|
207
214
|
counts[type]
|
208
215
|
end
|
209
216
|
|
217
|
+
private
|
218
|
+
|
210
219
|
def tier_cost_key
|
211
220
|
:monthly_unit_cost
|
212
221
|
end
|
@@ -219,7 +228,7 @@ class FixedMeteredPlan < MeteredPlan
|
|
219
228
|
spec[:monthly_fee] ? spec[:monthly_fee].to_f : 0
|
220
229
|
end
|
221
230
|
|
222
|
-
def amounts_for(counts)
|
231
|
+
def amounts_for(counts, fallback_to_highest_tier = false)
|
223
232
|
obj = super
|
224
233
|
obj[:base_fee] = base_fee
|
225
234
|
obj
|
@@ -256,6 +265,9 @@ class FixedMeteredPlan < MeteredPlan
|
|
256
265
|
# so we should reduce the count of actual units
|
257
266
|
units -= limits[type] if limits[type]
|
258
267
|
|
268
|
+
# but ensure we never go below zero
|
269
|
+
units = 0 if units < 0
|
270
|
+
|
259
271
|
units
|
260
272
|
end
|
261
273
|
|
@@ -263,12 +275,17 @@ class FixedMeteredPlan < MeteredPlan
|
|
263
275
|
:monthly_unit_cost
|
264
276
|
end
|
265
277
|
|
266
|
-
def
|
278
|
+
def matching_tiers_for(counts, fallback_to_highest_tier = false)
|
267
279
|
tier_groups.map do |key, tiers|
|
268
|
-
units = counts[key] or raise "Unit count required for #{key}"
|
280
|
+
units = counts[key] or raise MissingCountError.new("Unit count required for #{key}")
|
269
281
|
next if limits[key] and limits[key] >= units.to_i
|
270
282
|
|
271
|
-
|
283
|
+
begin
|
284
|
+
find_tier_for(tiers, units.to_i) + [key]
|
285
|
+
rescue TierNotFoundError
|
286
|
+
raise unless fallback_to_highest_tier
|
287
|
+
last_existing_tier_for(key)
|
288
|
+
end
|
272
289
|
end.compact
|
273
290
|
end
|
274
291
|
|
data/spec/plans_spec.rb
CHANGED
@@ -39,48 +39,48 @@ describe 'FreePlan' do
|
|
39
39
|
|
40
40
|
end
|
41
41
|
|
42
|
-
describe '#
|
42
|
+
describe '#available_for?(counts)' do
|
43
43
|
|
44
|
-
it 'returns
|
45
|
-
expect(plan.
|
44
|
+
it 'returns true if no limits' do
|
45
|
+
expect(plan.available_for?({ bananas: 100 }) ).to eql(true)
|
46
46
|
end
|
47
47
|
|
48
|
-
it '
|
48
|
+
it 'raises if not all units for limits are fed' do
|
49
49
|
other = FreePlan.new(limits: { bananas: 10 })
|
50
|
-
expect
|
50
|
+
expect { other.available_for?({ apples: 10 }) }.to raise_error(Zillion::Plan::MissingCountError)
|
51
51
|
end
|
52
52
|
|
53
|
-
it '
|
53
|
+
it 'returns false if limits/units match, but over the limit' do
|
54
54
|
other = FreePlan.new(limits: { bananas: 10 })
|
55
|
-
expect
|
55
|
+
expect(other.available_for?({ bananas: 20 })).to eql(false)
|
56
56
|
end
|
57
57
|
|
58
|
-
it '
|
58
|
+
it 'returns true if limits/units match, and within the limit' do
|
59
59
|
other = FreePlan.new(limits: { bananas: 10, apples: 10 })
|
60
|
-
expect
|
60
|
+
expect(other.available_for?({ bananas: 5, apples: 2 })).to eql(true)
|
61
61
|
end
|
62
62
|
|
63
63
|
end
|
64
64
|
|
65
|
-
describe '#
|
65
|
+
describe '#monthly_fee_for(counts)' do
|
66
66
|
|
67
|
-
it 'returns
|
68
|
-
expect(plan.
|
67
|
+
it 'returns 0 if no limits' do
|
68
|
+
expect(plan.monthly_fee_for({ apples: 10 })).to eql(0)
|
69
69
|
end
|
70
70
|
|
71
|
-
it '
|
71
|
+
it 'returns 0 if within limits' do
|
72
72
|
other = FreePlan.new(limits: { bananas: 10 })
|
73
|
-
expect
|
73
|
+
expect(other.monthly_fee_for({ bananas: 10 })).to eql(0)
|
74
74
|
end
|
75
75
|
|
76
|
-
it '
|
76
|
+
it 'raises if not within limits' do
|
77
77
|
other = FreePlan.new(limits: { bananas: 10 })
|
78
|
-
expect
|
78
|
+
expect { other.monthly_fee_for({ bananas: 11 }) }.to raise_error(Zillion::Plan::OverLimitsError)
|
79
79
|
end
|
80
80
|
|
81
|
-
it '
|
81
|
+
it 'raises if not all counts present' do
|
82
82
|
other = FreePlan.new(limits: { bananas: 10, apples: 10 })
|
83
|
-
expect
|
83
|
+
expect { other.monthly_fee_for({ apples: 5 }) }.to raise_error(Zillion::Plan::MissingCountError)
|
84
84
|
end
|
85
85
|
|
86
86
|
end
|
@@ -95,7 +95,7 @@ describe 'FixedPlan' do
|
|
95
95
|
|
96
96
|
it 'raises if monthly_fee not set' do
|
97
97
|
other = FixedPlan.new(limits: { bananas: 10 })
|
98
|
-
expect { other.monthly_fee }.to raise_error
|
98
|
+
expect { other.monthly_fee }.to raise_error(Zillion::Plan::InvalidFeeError)
|
99
99
|
end
|
100
100
|
|
101
101
|
it 'returns monthly_fee, if present' do
|
@@ -104,48 +104,48 @@ describe 'FixedPlan' do
|
|
104
104
|
|
105
105
|
end
|
106
106
|
|
107
|
-
describe '#
|
107
|
+
describe '#available_for?(counts)' do
|
108
108
|
|
109
|
-
it 'returns
|
110
|
-
expect(plan.
|
109
|
+
it 'returns true if no limits' do
|
110
|
+
expect(plan.available_for?({ bananas: 100 }) ).to eql(true)
|
111
111
|
end
|
112
112
|
|
113
|
-
it '
|
113
|
+
it 'raises not all units for limits are fed' do
|
114
114
|
other = FixedPlan.new(monthly_fee: 10, limits: { bananas: 10 })
|
115
|
-
expect
|
115
|
+
expect { other.available_for?({ apples: 10 }) }.to raise_error
|
116
116
|
end
|
117
117
|
|
118
|
-
it '
|
118
|
+
it 'returns false if limits/units match, but over the limit' do
|
119
119
|
other = FixedPlan.new(monthly_fee: 10, limits: { bananas: 10 })
|
120
|
-
expect
|
120
|
+
expect(other.available_for?({ bananas: 20 })).to eql(false)
|
121
121
|
end
|
122
122
|
|
123
|
-
it '
|
123
|
+
it 'returns true if limits/units match, and within the limit' do
|
124
124
|
other = FixedPlan.new(monthly_fee: 10, limits: { bananas: 10, apples: 10 })
|
125
|
-
expect
|
125
|
+
expect(other.available_for?({ bananas: 5, apples: 2 })).to eql(true)
|
126
126
|
end
|
127
127
|
|
128
128
|
end
|
129
129
|
|
130
|
-
describe '#
|
130
|
+
describe '#monthly_fee_for(counts)' do
|
131
131
|
|
132
|
-
it 'returns
|
133
|
-
expect(plan.
|
132
|
+
it 'returns monthly_fee if no limits' do
|
133
|
+
expect(plan.monthly_fee_for({ apples: 10 })).to eql(10.0)
|
134
134
|
end
|
135
135
|
|
136
|
-
it '
|
136
|
+
it 'returns monthly_fee if within limits' do
|
137
137
|
other = FixedPlan.new(monthly_fee: 10, limits: { bananas: 10 })
|
138
|
-
expect
|
138
|
+
expect(other.monthly_fee_for({ bananas: 10 })).to eql(10.0)
|
139
139
|
end
|
140
140
|
|
141
|
-
it '
|
141
|
+
it 'raises if not within limits' do
|
142
142
|
other = FixedPlan.new(monthly_fee: 10, limits: { bananas: 10 })
|
143
|
-
expect
|
143
|
+
expect { other.monthly_fee_for({ bananas: 11 }) }.to raise_error(Zillion::Plan::OverLimitsError)
|
144
144
|
end
|
145
145
|
|
146
|
-
it '
|
146
|
+
it 'raises if not all counts present' do
|
147
147
|
other = FixedPlan.new(monthly_fee: 10, limits: { bananas: 10, apples: 10 })
|
148
|
-
expect
|
148
|
+
expect { other.monthly_fee_for({ apples: 5 }) }.to raise_error(Zillion::Plan::MissingCountError)
|
149
149
|
end
|
150
150
|
|
151
151
|
end
|
@@ -160,8 +160,8 @@ describe 'TieredPlan', 'Single tier' do
|
|
160
160
|
limits: { bananas: 10 },
|
161
161
|
tiers: {
|
162
162
|
products: [
|
163
|
-
{ from: 0, to: 100, monthly_cost: 20 },
|
164
163
|
{ from: 101, to: 200, monthly_cost: 30 },
|
164
|
+
{ from: 0, to: 100, monthly_cost: 20 },
|
165
165
|
]
|
166
166
|
})
|
167
167
|
}
|
@@ -174,42 +174,42 @@ describe 'TieredPlan', 'Single tier' do
|
|
174
174
|
|
175
175
|
end
|
176
176
|
|
177
|
-
describe '#
|
177
|
+
describe '#available_for?(counts)' do
|
178
178
|
|
179
179
|
it 'raises if missing unit for tier' do
|
180
|
-
expect { plan.
|
180
|
+
expect { plan.available_for?({ bananas: 5 }) }.to raise_error(Zillion::Plan::MissingCountError)
|
181
181
|
end
|
182
182
|
|
183
183
|
it 'raises if missing unit for fixed limit' do
|
184
|
-
expect { plan.
|
184
|
+
expect { plan.available_for?({ products: 25 }) }.to raise_error(Zillion::Plan::MissingCountError)
|
185
185
|
end
|
186
186
|
|
187
187
|
it 'raises if not within limits' do
|
188
|
-
expect { plan.
|
188
|
+
expect { plan.available_for?({ bananas: 5, products: -5 }) }.to raise_error(Zillion::Plan::TierNotFoundError)
|
189
189
|
end
|
190
190
|
|
191
191
|
it 'returns monthly fee for tier if within its limit' do
|
192
|
-
expect(plan.
|
192
|
+
expect(plan.available_for?({ bananas: 5, products: 25 })).to eql(true)
|
193
193
|
end
|
194
194
|
|
195
195
|
end
|
196
196
|
|
197
|
-
describe '#
|
197
|
+
describe '#monthly_fee_for(counts)' do
|
198
198
|
|
199
199
|
it 'raises if missing unit for tier' do
|
200
|
-
expect { plan.
|
200
|
+
expect { plan.monthly_fee_for({ bananas: 5 }) }.to raise_error(Zillion::Plan::MissingCountError)
|
201
201
|
end
|
202
202
|
|
203
203
|
it 'raises if missing unit for fixed limit' do
|
204
|
-
expect { plan.
|
204
|
+
expect { plan.monthly_fee_for({ products: 25 }) }.to raise_error(Zillion::Plan::MissingCountError)
|
205
205
|
end
|
206
206
|
|
207
207
|
it 'raises if not within limits' do
|
208
|
-
expect { plan.
|
208
|
+
expect { plan.monthly_fee_for({ bananas: 5, products: -5 }) }.to raise_error(Zillion::Plan::TierNotFoundError)
|
209
209
|
end
|
210
210
|
|
211
211
|
it 'returns monthly fee for tier if within its limit' do
|
212
|
-
expect(plan.
|
212
|
+
expect(plan.monthly_fee_for({ bananas: 5, products: 25 })).to eql(20)
|
213
213
|
end
|
214
214
|
|
215
215
|
end
|
@@ -223,8 +223,8 @@ describe 'TieredPlan', 'Multiple tiers' do
|
|
223
223
|
limits: { bananas: 10 },
|
224
224
|
tiers: {
|
225
225
|
orders: [
|
226
|
+
{ from: 11, to: 20, monthly_cost: 35 },
|
226
227
|
{ from: 0, to: 10, monthly_cost: 15 },
|
227
|
-
{ from: 11, to: 20, monthly_cost: 35 }
|
228
228
|
],
|
229
229
|
products: [
|
230
230
|
{ from: 0, to: 100, monthly_cost: 20 },
|
@@ -241,42 +241,42 @@ describe 'TieredPlan', 'Multiple tiers' do
|
|
241
241
|
|
242
242
|
end
|
243
243
|
|
244
|
-
describe '#
|
244
|
+
describe '#available_for?(counts)' do
|
245
245
|
|
246
246
|
it 'raises if missing unit for tier' do
|
247
|
-
expect { plan.
|
247
|
+
expect { plan.available_for?({ bananas: 5 }) }.to raise_error(Zillion::Plan::MissingCountError)
|
248
248
|
end
|
249
249
|
|
250
250
|
it 'raises if missing unit for fixed limit' do
|
251
|
-
expect { plan.
|
251
|
+
expect { plan.available_for?({ products: 25 }) }.to raise_error(Zillion::Plan::MissingCountError)
|
252
252
|
end
|
253
253
|
|
254
254
|
it 'raises if not within limits' do
|
255
|
-
expect { plan.
|
255
|
+
expect { plan.available_for?({ bananas: 5, products: -5, orders: -1 }) }.to raise_error(Zillion::Plan::TierNotFoundError)
|
256
256
|
end
|
257
257
|
|
258
|
-
it 'returns
|
259
|
-
expect(plan.
|
258
|
+
it 'returns true if within tier limits' do
|
259
|
+
expect(plan.available_for?({ bananas: 5, orders: 5, products: 25 })).to eql(true)
|
260
260
|
end
|
261
261
|
|
262
262
|
end
|
263
263
|
|
264
|
-
describe '#
|
264
|
+
describe '#monthly_fee_for(counts)' do
|
265
265
|
|
266
266
|
it 'raises if missing unit for tier' do
|
267
|
-
expect { plan.
|
267
|
+
expect { plan.monthly_fee_for({ bananas: 5, products: 25 }) }.to raise_error(Zillion::Plan::MissingCountError)
|
268
268
|
end
|
269
269
|
|
270
270
|
it 'raises if missing unit for fixed limit' do
|
271
|
-
expect { plan.
|
271
|
+
expect { plan.monthly_fee_for({ products: 25 }) }.to raise_error(Zillion::Plan::MissingCountError)
|
272
272
|
end
|
273
273
|
|
274
274
|
it 'raises if not within limits' do
|
275
|
-
expect { plan.
|
275
|
+
expect { plan.monthly_fee_for({ bananas: 5, products: -5, orders: 0 }) }.to raise_error(Zillion::Plan::TierNotFoundError)
|
276
276
|
end
|
277
277
|
|
278
|
-
it 'returns
|
279
|
-
expect(plan.
|
278
|
+
it 'returns monthly fee for tier if within its limit' do
|
279
|
+
expect(plan.monthly_fee_for({ bananas: 1, orders: 5, products: 25 })).to eql(20)
|
280
280
|
end
|
281
281
|
|
282
282
|
end
|
@@ -290,8 +290,8 @@ describe 'MeteredPlan', 'Single tier' do
|
|
290
290
|
limits: { bananas: 10 },
|
291
291
|
tiers: {
|
292
292
|
products: [
|
293
|
+
{ from: 101, to: 200, monthly_unit_cost: 1.5 },
|
293
294
|
{ from: 0, to: 100, monthly_unit_cost: 2 },
|
294
|
-
{ from: 101, to: 200, monthly_unit_cost: 1.5 }
|
295
295
|
]
|
296
296
|
})
|
297
297
|
}
|
@@ -304,18 +304,38 @@ describe 'MeteredPlan', 'Single tier' do
|
|
304
304
|
|
305
305
|
end
|
306
306
|
|
307
|
+
describe '#available_for?(counts)' do
|
308
|
+
|
309
|
+
it 'raises if missing unit for tier' do
|
310
|
+
expect { plan.available_for?({ bananas: 5 }) }.to raise_error(Zillion::Plan::MissingCountError)
|
311
|
+
end
|
312
|
+
|
313
|
+
it 'raises if missing unit for fixed limit' do
|
314
|
+
expect { plan.available_for?({ products: 25 }) }.to raise_error(Zillion::Plan::MissingCountError)
|
315
|
+
end
|
316
|
+
|
317
|
+
it 'raises if not within limits' do
|
318
|
+
expect { plan.available_for?({ bananas: 5, products: -5 }) }.to raise_error(Zillion::Plan::TierNotFoundError)
|
319
|
+
end
|
320
|
+
|
321
|
+
it 'returns true if within its limit' do
|
322
|
+
expect(plan.available_for?({ bananas: 5, products: 25 })).to eql(true)
|
323
|
+
end
|
324
|
+
|
325
|
+
end
|
326
|
+
|
307
327
|
describe '#monthly_fee_for(counts)' do
|
308
328
|
|
309
329
|
it 'raises if missing unit for tier' do
|
310
|
-
expect { plan.monthly_fee_for({ bananas: 5 }) }.to raise_error
|
330
|
+
expect { plan.monthly_fee_for({ bananas: 5 }) }.to raise_error(Zillion::Plan::MissingCountError)
|
311
331
|
end
|
312
332
|
|
313
333
|
it 'raises if missing unit for fixed limit' do
|
314
|
-
expect { plan.monthly_fee_for({ products: 25 }) }.to raise_error
|
334
|
+
expect { plan.monthly_fee_for({ products: 25 }) }.to raise_error(Zillion::Plan::MissingCountError)
|
315
335
|
end
|
316
336
|
|
317
337
|
it 'raises if not within limits' do
|
318
|
-
expect { plan.monthly_fee_for({ bananas: 5, products: -5 }) }.to raise_error
|
338
|
+
expect { plan.monthly_fee_for({ bananas: 5, products: -5 }) }.to raise_error(Zillion::Plan::TierNotFoundError)
|
319
339
|
end
|
320
340
|
|
321
341
|
it 'returns monthly fee for tier if within its limit' do
|
@@ -324,26 +344,34 @@ describe 'MeteredPlan', 'Single tier' do
|
|
324
344
|
|
325
345
|
end
|
326
346
|
|
327
|
-
describe '#
|
347
|
+
describe '#amounts_for(counts)' do
|
328
348
|
|
329
349
|
it 'raises if missing unit for tier' do
|
330
|
-
expect { plan.
|
350
|
+
expect { plan.amounts_for({ bananas: 5 }) }.to raise_error(Zillion::Plan::MissingCountError)
|
331
351
|
end
|
332
352
|
|
333
|
-
it 'raises if
|
334
|
-
expect { plan.
|
353
|
+
it 'raises if not within limits' do
|
354
|
+
expect { plan.amounts_for({ bananas: 5, products: -5 }) }.to raise_error(Zillion::Plan::TierNotFoundError)
|
355
|
+
end
|
356
|
+
|
357
|
+
it 'returns amounts if within limits' do
|
358
|
+
expect(plan.amounts_for({ products: 25 })).to eql({ products: 50 })
|
335
359
|
end
|
336
360
|
|
337
361
|
it 'raises if not within limits' do
|
338
|
-
expect { plan.
|
362
|
+
expect { plan.amounts_for({ products: 250 }) }.to raise_error(Zillion::Plan::TierNotFoundError)
|
339
363
|
end
|
340
364
|
|
341
|
-
it '
|
342
|
-
expect
|
365
|
+
it 'doesnt raise if not within limits but second arg is true' do
|
366
|
+
expect { plan.amounts_for({ products: 250 }, true) }.not_to raise_error(Zillion::Plan::TierNotFoundError)
|
367
|
+
expect(plan.amounts_for({ products: 250 }, true)).to eql({ products: 375.0 })
|
343
368
|
end
|
344
369
|
|
345
|
-
|
370
|
+
it 'returns amounts if within limits' do
|
371
|
+
expect(plan.amounts_for({ bananas: 5, products: 25 })).to eql({ products: 50 })
|
372
|
+
end
|
346
373
|
|
374
|
+
end
|
347
375
|
|
348
376
|
end
|
349
377
|
|
@@ -372,18 +400,43 @@ describe 'MeteredPlan', 'Multiple tiers' do
|
|
372
400
|
|
373
401
|
end
|
374
402
|
|
375
|
-
|
403
|
+
|
404
|
+
describe '#available_for?(counts)' do
|
376
405
|
|
377
406
|
it 'raises if missing unit for tier' do
|
378
|
-
expect { plan.
|
407
|
+
expect { plan.available_for?({ bananas: 5 }) }.to raise_error(Zillion::Plan::MissingCountError)
|
379
408
|
end
|
380
409
|
|
381
410
|
it 'raises if missing unit for fixed limit' do
|
382
|
-
expect { plan.
|
411
|
+
expect { plan.available_for?({ products: 25 }) }.to raise_error(Zillion::Plan::MissingCountError)
|
383
412
|
end
|
384
413
|
|
385
414
|
it 'raises if not within limits' do
|
386
|
-
expect { plan.
|
415
|
+
expect { plan.available_for?({ bananas: 5, products: -5, orders: 1 }) }.to raise_error(Zillion::Plan::TierNotFoundError)
|
416
|
+
end
|
417
|
+
|
418
|
+
it 'returns true if within its limit' do
|
419
|
+
expect(plan.available_for?({ bananas: 5, orders: 5, products: 25 })).to eql(true)
|
420
|
+
end
|
421
|
+
|
422
|
+
end
|
423
|
+
|
424
|
+
describe '#monthly_fee_for(counts)' do
|
425
|
+
|
426
|
+
it 'raises if missing unit for tier' do
|
427
|
+
expect { plan.monthly_fee_for({ bananas: 5 }) }.to raise_error(Zillion::Plan::MissingCountError)
|
428
|
+
end
|
429
|
+
|
430
|
+
it 'raises if missing unit for fixed limit' do
|
431
|
+
expect { plan.monthly_fee_for({ products: 25 }) }.to raise_error(Zillion::Plan::MissingCountError)
|
432
|
+
end
|
433
|
+
|
434
|
+
it 'raises if below limits' do
|
435
|
+
expect { plan.monthly_fee_for({ bananas: 5, products: -5, orders: 10 }) }.to raise_error(Zillion::Plan::TierNotFoundError)
|
436
|
+
end
|
437
|
+
|
438
|
+
it 'raises if over limits' do
|
439
|
+
expect { plan.monthly_fee_for({ bananas: 5, products: 250, orders: 10 }) }.to raise_error(Zillion::Plan::TierNotFoundError)
|
387
440
|
end
|
388
441
|
|
389
442
|
it 'returns monthly fee for tier if within its limit' do
|
@@ -392,22 +445,31 @@ describe 'MeteredPlan', 'Multiple tiers' do
|
|
392
445
|
|
393
446
|
end
|
394
447
|
|
395
|
-
describe '#
|
448
|
+
describe '#amounts_for(counts)' do
|
396
449
|
|
397
450
|
it 'raises if missing unit for tier' do
|
398
|
-
expect { plan.
|
451
|
+
expect { plan.amounts_for({ bananas: 5 }) }.to raise_error(Zillion::Plan::MissingCountError)
|
399
452
|
end
|
400
453
|
|
401
|
-
it 'raises if
|
402
|
-
expect { plan.
|
454
|
+
it 'raises if not within limits' do
|
455
|
+
expect { plan.amounts_for({ bananas: 5, products: -5, orders: 1 }) }.to raise_error(Zillion::Plan::TierNotFoundError)
|
403
456
|
end
|
404
457
|
|
405
458
|
it 'raises if not within limits' do
|
406
|
-
expect { plan.
|
459
|
+
expect { plan.amounts_for({ products: 250, orders: 5, orders: 1 }) }.to raise_error(Zillion::Plan::TierNotFoundError)
|
407
460
|
end
|
408
461
|
|
409
|
-
it '
|
410
|
-
expect
|
462
|
+
it 'doesnt raise if not within limits but second arg is true' do
|
463
|
+
expect { plan.amounts_for({ products: 250, orders: 5 }, true) }.not_to raise_error(Zillion::Plan::TierNotFoundError)
|
464
|
+
expect(plan.amounts_for({ products: 250, orders: 5 }, true)).to eql({ orders: 15, products: 375.0 })
|
465
|
+
end
|
466
|
+
|
467
|
+
it 'returns amounts if within limits' do
|
468
|
+
expect(plan.amounts_for({ bananas: 5, products: 25, orders: 5 })).to eql({ orders: 15, products: 50 })
|
469
|
+
end
|
470
|
+
|
471
|
+
it 'returns amounts if within limits' do
|
472
|
+
expect(plan.amounts_for({ bananas: 5, products: 25, orders: 1 })).to eql({ orders: 3, products: 50 })
|
411
473
|
end
|
412
474
|
|
413
475
|
end
|
@@ -422,8 +484,8 @@ describe 'FixedMeteredPlan' do
|
|
422
484
|
limits: { bananas: 10, orders: 10, products: 10 },
|
423
485
|
tiers: {
|
424
486
|
orders: [
|
487
|
+
{ from: 16, to: 20, monthly_unit_cost: 1 },
|
425
488
|
{ from: 11, to: 15, monthly_unit_cost: 3 },
|
426
|
-
{ from: 16, to: 20, monthly_unit_cost: 1 }
|
427
489
|
],
|
428
490
|
products: [
|
429
491
|
{ from: 5, to: 100, monthly_unit_cost: 2 },
|
@@ -443,14 +505,53 @@ describe 'FixedMeteredPlan' do
|
|
443
505
|
|
444
506
|
end
|
445
507
|
|
508
|
+
|
509
|
+
describe '#available_for?(counts)' do
|
510
|
+
|
511
|
+
it 'raises if missing units for tier' do
|
512
|
+
expect { plan.available_for?({ bananas: 5 }) }.to raise_error(Zillion::Plan::MissingCountError)
|
513
|
+
end
|
514
|
+
|
515
|
+
it 'raises if missing unit for fixed limit' do
|
516
|
+
expect { plan.available_for?({ products: 25 }) }.to raise_error(Zillion::Plan::MissingCountError)
|
517
|
+
end
|
518
|
+
|
519
|
+
it 'doent explode if negative key for limit with tier' do
|
520
|
+
expect(plan.available_for?({ bananas: 5, orders: 5, products: -5 })).to eql(true)
|
521
|
+
end
|
522
|
+
|
523
|
+
it 'returns true if below fixed limits' do
|
524
|
+
expect(plan.available_for?({ bananas: 5, orders: 5, products: 5 })).to eql(true)
|
525
|
+
end
|
526
|
+
|
527
|
+
it 'returns true if below fixed limits, even if no matching tier exists' do
|
528
|
+
plan_opts[:tiers].delete(:products)
|
529
|
+
expect(plan.available_for?({ bananas: 5, orders: 5, products: 5 })).to eql(true)
|
530
|
+
end
|
531
|
+
|
532
|
+
it 'returns false if above fixed limit and no tier found' do
|
533
|
+
plan_opts[:tiers].delete(:products)
|
534
|
+
expect(plan.available_for?({ bananas: 5, orders: 5, products: 15 })).to eql(false)
|
535
|
+
end
|
536
|
+
|
537
|
+
it 'returns true if above fixed limit but within tier limit' do
|
538
|
+
expect(plan.available_for?({ bananas: 5, orders: 5, products: 15 })).to eql(true)
|
539
|
+
end
|
540
|
+
|
541
|
+
it 'returns true if above fixed limit but within tier limit' do
|
542
|
+
expect(plan.available_for?({ bananas: 5, orders: 15, products: 25 })).to eql(true)
|
543
|
+
end
|
544
|
+
|
545
|
+
end
|
546
|
+
|
446
547
|
describe '#monthly_fee_for(counts)' do
|
447
548
|
|
448
549
|
it 'raises if missing unit for tier' do
|
449
|
-
expect { plan.monthly_fee_for({ bananas: 5 }) }.to raise_error
|
550
|
+
expect { plan.monthly_fee_for({ bananas: 5 }) }.to raise_error(Zillion::Plan::MissingCountError)
|
450
551
|
end
|
451
552
|
|
452
553
|
it 'raises if missing unit for fixed limit' do
|
453
|
-
expect { plan.monthly_fee_for({ products: 5 }) }.to raise_error
|
554
|
+
expect { plan.monthly_fee_for({ products: 5 }) }.to raise_error(Zillion::Plan::MissingCountError)
|
454
555
|
end
|
455
556
|
|
456
557
|
it 'doent explode if negative key for tiered count, but under fixed limit' do
|
@@ -461,7 +562,7 @@ describe 'FixedMeteredPlan' do
|
|
461
562
|
expect(plan.monthly_fee_for({ bananas: 5, orders: 5, products: 5 })).to eql(10.0)
|
462
563
|
end
|
463
564
|
|
464
|
-
it 'returns monthly fee
|
565
|
+
it 'returns monthly fee if just within limit limits' do
|
465
566
|
expect(plan.monthly_fee_for({ bananas: 10, orders: 10, products: 10 })).to eql(10.0)
|
466
567
|
end
|
467
568
|
|
@@ -475,40 +576,44 @@ describe 'FixedMeteredPlan' do
|
|
475
576
|
|
476
577
|
end
|
477
578
|
|
478
|
-
describe '#available_for?(counts)' do
|
479
579
|
|
480
|
-
|
481
|
-
|
580
|
+
describe '#amounts_for(counts)' do
|
581
|
+
|
582
|
+
it 'raises if missing unit for tier' do
|
583
|
+
expect { plan.amounts_for({ bananas: 5 }) }.to raise_error(Zillion::Plan::MissingCountError)
|
482
584
|
end
|
483
585
|
|
484
586
|
it 'raises if missing unit for fixed limit' do
|
485
|
-
expect { plan.
|
587
|
+
expect { plan.amounts_for({ products: 5 }) }.to raise_error(Zillion::Plan::MissingCountError)
|
486
588
|
end
|
487
589
|
|
488
|
-
it '
|
489
|
-
expect
|
590
|
+
it 'raises if over limits' do
|
591
|
+
expect { plan.amounts_for({ orders: 1000, products: 5 }) }.to raise_error(Zillion::Plan::TierNotFoundError)
|
490
592
|
end
|
491
593
|
|
492
|
-
it '
|
493
|
-
expect
|
594
|
+
it 'doest raises if over limits but second arg is true' do
|
595
|
+
expect { plan.amounts_for({ orders: 1000, products: 5 }, true) }.not_to raise_error(Zillion::Plan::TierNotFoundError)
|
596
|
+
expect(plan.amounts_for({ orders: 1000, products: 5 }, true)).to eql({ orders: 990, base_fee: 10.0 })
|
494
597
|
end
|
495
598
|
|
496
|
-
it '
|
497
|
-
|
498
|
-
expect(plan.available_for?({ bananas: 5, orders: 5, products: 5 })).to eql(true)
|
599
|
+
it 'doesnt explode if negative key for tiered count, but under fixed limit' do
|
600
|
+
expect(plan.amounts_for({ bananas: 5, orders: 5, products: -5 })).to eql({ base_fee: 10.0 })
|
499
601
|
end
|
500
602
|
|
501
|
-
it 'returns
|
502
|
-
|
503
|
-
expect(plan.available_for?({ bananas: 5, orders: 5, products: 15 })).to eql(false)
|
603
|
+
it 'returns amounts for tier if below fixed limits' do
|
604
|
+
expect(plan.amounts_for({ bananas: 5, orders: 5, products: 5 })).to eql({ base_fee: 10.0 })
|
504
605
|
end
|
505
606
|
|
506
|
-
it 'returns
|
507
|
-
expect(plan.
|
607
|
+
it 'returns amounts if just within limit limits' do
|
608
|
+
expect(plan.amounts_for({ bananas: 10, orders: 10, products: 10 })).to eql({ base_fee: 10.0 })
|
508
609
|
end
|
509
610
|
|
510
|
-
it 'returns
|
511
|
-
expect(plan.
|
611
|
+
it 'returns amounts for tier if within its limit' do
|
612
|
+
expect(plan.amounts_for({ bananas: 5, orders: 5, products: 25 })).to eql({:products=>30, :base_fee=>10.0})
|
613
|
+
end
|
614
|
+
|
615
|
+
it 'returns amounts for tier if within its limit' do
|
616
|
+
expect(plan.amounts_for({ bananas: 5, orders: 15, products: 25 })).to eql({:orders=>15, :products=>30, :base_fee=>10.0})
|
512
617
|
end
|
513
618
|
|
514
619
|
end
|
data/zillion.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zillion
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tomás Pollak
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-07-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -78,9 +78,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
78
78
|
version: 1.3.6
|
79
79
|
requirements: []
|
80
80
|
rubyforge_project:
|
81
|
-
rubygems_version: 2.
|
81
|
+
rubygems_version: 2.6.13
|
82
82
|
signing_key:
|
83
83
|
specification_version: 4
|
84
84
|
summary: A model for SaaS plans with fixed, tiered and metered pricing.
|
85
85
|
test_files: []
|
86
|
-
has_rdoc:
|