1# frozen_string_literal: true
2
3require "delegate"
4
5module TrustLevel
6 def self.for(
7 customer:, settled_amount: 0, manual: nil,
8 activated: nil, invited: false, activater: nil
9 )
10 @levels.each do |level|
11 tl = level.call(
12 customer: customer,
13 settled_amount: settled_amount, activated: activated,
14 manual: manual, invited: invited, activater: activater
15 )
16 return manual ? Manual.new(tl) : tl if tl
17 end
18
19 raise "No TrustLevel matched"
20 end
21
22 def self.register(&maybe_mk)
23 @levels ||= []
24 @levels << maybe_mk
25 end
26
27 class Manual < SimpleDelegator
28 def to_s
29 "Manual(#{super})"
30 end
31 end
32
33 class Tomb
34 TrustLevel.register do |manual:, **|
35 new if manual == "Tomb"
36 end
37
38 def invite?
39 false
40 end
41
42 def write_cdr?
43 false
44 end
45
46 def support_call?(*)
47 false
48 end
49
50 def send_message?(*)
51 false
52 end
53
54 # Validates a credit card transaction for a Tomb trust level user.
55 # Users at this level cannot make credit card transactions.
56 # @param _amount [BigDecimal] The amount of the transaction (ignored).
57 # @param _declines [Integer] The number of recent declines (ignored).
58 # @raise [DeclinedError] Always raised to prevent transactions.
59 def validate_credit_card_transaction!(_amount, _declines)
60 # Give a more ambiguous error so they don't know they're tombed.
61 raise DeclinedError
62 end
63
64 def create_subaccount?(*)
65 false
66 end
67
68 def to_s
69 "Tomb"
70 end
71
72 # The maximum amount a user at Tomb trust level can top up.
73 # @return [Integer] Always 0 for Tomb level.
74 def max_top_up_amount
75 0
76 end
77 end
78
79 class Cellar
80 TrustLevel.register do |manual:, activated:, invited:, activater:, **|
81 new if manual == "Cellar" || (!manual && !activater && !invited && \
82 (!activated || activated > Time.parse("2026-03-03 16:30")))
83 end
84
85 def invite?
86 false
87 end
88
89 def write_cdr?
90 true
91 end
92
93 def support_call?(*)
94 false
95 end
96
97 def send_message?(*)
98 false
99 end
100
101 def validate_credit_card_transaction!(amount, declines)
102 raise DeclinedError.new(declines, max_declines) if declines > max_declines
103 return unless amount > max_top_up_amount
104
105 raise AmountTooHighError.new(amount, max_top_up_amount)
106 end
107
108 def create_subaccount?(*)
109 false
110 end
111
112 def to_s
113 "Cellar"
114 end
115
116 def max_top_up_amount
117 35
118 end
119
120 protected
121
122 def max_declines
123 2
124 end
125 end
126
127 class Basement
128 TrustLevel.register do |manual:, settled_amount:, **|
129 new if manual == "Basement" || (!manual && settled_amount < 10)
130 end
131
132 def invite?
133 true
134 end
135
136 def write_cdr?
137 true
138 end
139
140 def support_call?(rate, concurrency)
141 rate <= 0.02 && concurrency < 1
142 end
143
144 def send_message?(messages_today)
145 messages_today < 40
146 end
147
148 # Validates a credit card transaction for a Basement trust level user.
149 # @param amount [BigDecimal] The amount of the transaction.
150 # @param declines [Integer] The number of recent declines for the customer.
151 # @raise [DeclinedError] if the number of declines exceeds `max_declines`.
152 # @raise [AmountTooHighError] if the transaction amount exceeds
153 # `max_top_up_amount`.
154 def validate_credit_card_transaction!(amount, declines)
155 raise DeclinedError.new(declines, max_declines) if declines > max_declines
156 return unless amount > max_top_up_amount
157
158 raise AmountTooHighError.new(amount, max_top_up_amount)
159 end
160
161 def create_subaccount?(already_have)
162 already_have < 2
163 end
164
165 def to_s
166 "Basement"
167 end
168
169 # The maximum amount a user at Basement trust level can top up.
170 # @return [Integer]
171 def max_top_up_amount
172 35
173 end
174
175 protected
176
177 # The maximum number of credit card declines allowed for a Basement user
178 # before further transactions are blocked.
179 # @return [Integer]
180 def max_declines
181 2
182 end
183 end
184
185 class Paragon
186 TrustLevel.register do |manual:, settled_amount:, **|
187 new if manual == "Paragon" || (!manual && settled_amount > 60)
188 end
189
190 def invite?
191 true
192 end
193
194 def write_cdr?
195 true
196 end
197
198 def support_call?(_, concurrency)
199 concurrency < 10 ? :anyroute : false
200 end
201
202 def send_message?(messages_today)
203 messages_today < 700
204 end
205
206 # Validates a credit card transaction for a Paragon trust level user.
207 # @param amount [BigDecimal] The amount of the transaction.
208 # @param declines [Integer] The number of recent declines for the customer.
209 # @raise [DeclinedError] if the number of declines exceeds `max_declines`.
210 # @raise [AmountTooHighError] if the transaction amount exceeds
211 # `max_top_up_amount`.
212 def validate_credit_card_transaction!(amount, declines)
213 raise DeclinedError.new(declines, max_declines) if declines > max_declines
214 return unless amount > max_top_up_amount
215
216 raise AmountTooHighError.new(amount, max_top_up_amount)
217 end
218
219 def create_subaccount?(already_have)
220 already_have < 10
221 end
222
223 def to_s
224 "Paragon"
225 end
226
227 # The maximum amount a user at Paragon trust level can top up.
228 # @return [Integer]
229 def max_top_up_amount
230 500
231 end
232
233 protected
234
235 # The maximum number of credit card declines allowed for a Paragon user
236 # before further transactions are blocked.
237 # @return [Integer]
238 def max_declines
239 3
240 end
241 end
242
243 class Olympias
244 TrustLevel.register do |manual:, **|
245 new if manual == "Olympias"
246 end
247
248 def invite?
249 true
250 end
251
252 def write_cdr?
253 true
254 end
255
256 def support_call?(*)
257 :anyroute
258 end
259
260 def send_message?(*)
261 true
262 end
263
264 # Validates a credit card transaction for an Olympias trust level user.
265 # Users at this level have no restrictions on credit card transactions
266 # through this method.
267 # @return [void]
268 def validate_credit_card_transaction!(*) end
269
270 def create_subaccount?(*)
271 true
272 end
273
274 def to_s
275 "Olympias"
276 end
277 end
278
279 class Customer
280 TrustLevel.register do |manual:, customer:, **|
281 if manual && manual != "Customer"
282 Sentry.capture_message("Unknown TrustLevel: #{manual}")
283 end
284
285 new(customer.plan_name)
286 end
287
288 EXPENSIVE_ROUTE = {
289 "usd_beta_unlimited-v20210223" => 0.9,
290 "USD" => 0.9,
291 "cad_beta_unlimited-v20210223" => 1.1,
292 "CAD" => 1.1
293 }.freeze
294
295 def initialize(plan_name)
296 @max_rate = EXPENSIVE_ROUTE.fetch(plan_name, 0.1)
297 end
298
299 def invite?
300 true
301 end
302
303 def write_cdr?
304 true
305 end
306
307 def support_call?(rate, concurrency)
308 rate <= @max_rate && concurrency < 4 ? :anyroute : false
309 end
310
311 def send_message?(messages_today)
312 messages_today < 500
313 end
314
315 # Validates a credit card transaction for a Customer trust level user.
316 # @param amount [BigDecimal] The amount of the transaction.
317 # @param declines [Integer] The number of recent declines for the customer.
318 # @raise [DeclinedError] if the number of declines exceeds `max_declines`.
319 # @raise [AmountTooHighError] if the transaction amount exceeds
320 # `max_top_up_amount`.
321 def validate_credit_card_transaction!(amount, declines)
322 raise DeclinedError.new(declines, max_declines) if declines > max_declines
323 return unless amount > max_top_up_amount
324
325 raise AmountTooHighError.new(amount, max_top_up_amount)
326 end
327
328 def create_subaccount?(already_have)
329 already_have < 2
330 end
331
332 def to_s
333 "Customer"
334 end
335
336 # The maximum amount a user at Customer trust level can top up.
337 # @return [Integer]
338 def max_top_up_amount
339 130
340 end
341
342 protected
343
344 # The maximum number of credit card declines allowed for a Customer user
345 # before further transactions are blocked.
346 # @return [Integer]
347 def max_declines
348 2
349 end
350 end
351end