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