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