trust_level.rb

  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 max_top_up_amount
 36			0
 37		end
 38
 39		def write_cdr?
 40			false
 41		end
 42
 43		def support_call?(*)
 44			false
 45		end
 46
 47		def send_message?(*)
 48			false
 49		end
 50
 51		def validate_credit_card_transaction!(_amount, _declines)
 52			# Give a more ambiguous error so they don't know they're tombed.
 53			raise DeclinedError
 54		end
 55
 56		def create_subaccount?(*)
 57			false
 58		end
 59
 60		def to_s
 61			"Tomb"
 62		end
 63	end
 64
 65	class Basement
 66		TrustLevel.register do |manual:, settled_amount:, **|
 67			new if manual == "Basement" || (!manual && settled_amount < 10)
 68		end
 69
 70		def max_top_up_amount
 71			35
 72		end
 73
 74		def max_declines
 75			2
 76		end
 77
 78		def write_cdr?
 79			true
 80		end
 81
 82		def support_call?(rate, concurrency)
 83			rate <= 0.02 && concurrency < 1
 84		end
 85
 86		def send_message?(messages_today)
 87			messages_today < 40
 88		end
 89
 90		def validate_credit_card_transaction!(amount, declines)
 91			raise DeclinedError.new(declines, max_declines) if declines > max_declines
 92			return unless amount > max_top_up_amount
 93
 94			raise AmountTooHighError.new(amount, max_top_up_amount)
 95		end
 96
 97		def create_subaccount?(already_have)
 98			already_have < 2
 99		end
100
101		def to_s
102			"Basement"
103		end
104	end
105
106	class Paragon
107		TrustLevel.register do |manual:, settled_amount:, **|
108			new if manual == "Paragon" || (!manual && settled_amount > 60)
109		end
110
111		def max_top_up_amount
112			500
113		end
114
115		def max_declines
116			3
117		end
118
119		def write_cdr?
120			true
121		end
122
123		def support_call?(_, concurrency)
124			concurrency < 10
125		end
126
127		def send_message?(messages_today)
128			messages_today < 700
129		end
130
131		def validate_credit_card_transaction!(amount, declines)
132			raise DeclinedError.new(declines, max_declines) if declines > max_declines
133			return unless amount > max_top_up_amount
134
135			raise AmountTooHighError.new(amount, max_top_up_amount)
136		end
137
138		def create_subaccount?(already_have)
139			already_have < 10
140		end
141
142		def to_s
143			"Paragon"
144		end
145	end
146
147	class Olympias
148		TrustLevel.register do |manual:, **|
149			new if manual == "Olympias"
150		end
151
152		def write_cdr?
153			true
154		end
155
156		def support_call?(*)
157			true
158		end
159
160		def send_message?(*)
161			true
162		end
163
164		def validate_credit_card_transaction!(*) end
165
166		def create_subaccount?(*)
167			true
168		end
169
170		def to_s
171			"Olympias"
172		end
173	end
174
175	class Customer
176		TrustLevel.register do |manual:, plan_name:, **|
177			if manual && manual != "Customer"
178				Sentry.capture_message("Unknown TrustLevel: #{manual}")
179			end
180
181			new(plan_name)
182		end
183
184		EXPENSIVE_ROUTE = {
185			"usd_beta_unlimited-v20210223" => 0.9,
186			"USD" => 0.9,
187			"cad_beta_unlimited-v20210223" => 1.1,
188			"CAD" => 1.1
189		}.freeze
190
191		def initialize(plan_name)
192			@max_rate = EXPENSIVE_ROUTE.fetch(plan_name, 0.1)
193		end
194
195		def max_top_up_amount
196			130
197		end
198
199		def max_declines
200			2
201		end
202
203		def write_cdr?
204			true
205		end
206
207		def support_call?(rate, concurrency)
208			rate <= @max_rate && concurrency < 4
209		end
210
211		def send_message?(messages_today)
212			messages_today < 500
213		end
214
215		def validate_credit_card_transaction!(amount, declines)
216			raise DeclinedError.new(declines, max_declines) if declines > max_declines
217			return unless amount > max_top_up_amount
218
219			raise AmountTooHighError.new(amount, max_top_up_amount)
220		end
221
222		def create_subaccount?(already_have)
223			already_have < 2
224		end
225
226		def to_s
227			"Customer"
228		end
229	end
230end