Show Callability State in Customer Info

Christopher Vollick created

This shows relatively easily which class a given user finds themselves
in.

Whether they can't call because they have no balance, or if they have
lots of room, or if they're being asked.

Hopefully this will make it easier to tell at a glance if a calling
issue is due to a few things.

Change summary

forms/admin_info.rb        |  6 ++++++
lib/call_attempt.rb        | 21 +++++++++++++++++++--
lib/customer_info.rb       | 24 +++++++++++++++++++++++-
test/test_customer_info.rb |  2 ++
4 files changed, 50 insertions(+), 3 deletions(-)

Detailed changes

forms/admin_info.rb 🔗

@@ -45,6 +45,12 @@ if @admin_info.fwd.uri
 	)
 end
 
+field(
+	var: "call_info",
+	label: "Call Status",
+	value: @admin_info.call_info
+)
+
 field(
 	var: "api",
 	label: "API",

lib/call_attempt.rb 🔗

@@ -48,6 +48,10 @@ class CallAttempt
 		["#{direction}/connect", { locals: to_h }]
 	end
 
+	def to_s
+		"Allowed(max_minutes: #{max_minutes}, limit_remaining: #{limit_remaining})"
+	end
+
 	def create_call(fwd, *args, &block)
 		fwd.create_call(*args, &block)
 	end
@@ -119,6 +123,10 @@ class CallAttempt
 			[view]
 		end
 
+		def to_s
+			"Unsupported"
+		end
+
 		def create_call(*); end
 
 		def as_json(*)
@@ -135,8 +143,8 @@ class CallAttempt
 			self.for(rate: rate, **kwargs) if credit < rate * 10
 		end
 
-		def self.for(customer:, direction:, **kwargs)
-			LowBalance.for(customer).then(&:notify!).then do |amount|
+		def self.for(customer:, direction:, low_balance: LowBalance, **kwargs)
+			low_balance.for(customer).then(&:notify!).then do |amount|
 				if amount&.positive?
 					CallAttempt.for(
 						customer: customer.with_balance(customer.balance + amount),
@@ -165,6 +173,10 @@ class CallAttempt
 			[view, { locals: to_h }]
 		end
 
+		def to_s
+			"NoBalance"
+		end
+
 		def create_call(*); end
 
 		def as_json(*)
@@ -211,6 +223,11 @@ class CallAttempt
 			[view, { locals: to_h }]
 		end
 
+		def to_s
+			"AtLimit(max_minutes: #{max_minutes}, "\
+			"limit_remaining: #{limit_remaining})"
+		end
+
 		def create_call(fwd, *args, &block)
 			fwd.create_call(*args, &block)
 		end

lib/customer_info.rb 🔗

@@ -99,6 +99,7 @@ class AdminInfo
 		fwd Either(CustomerFwd, nil)
 		info CustomerInfo
 		api API
+		call_info String
 	end
 
 	def self.for(customer, plan)
@@ -107,10 +108,31 @@ class AdminInfo
 			customer_id: customer.customer_id,
 			fwd: customer.fwd,
 			info: CustomerInfo.for(customer, plan),
-			api: customer.api
+			api: customer.api,
+			call_info: call_info(customer)
 		).then(&method(:new))
 	end
 
+	class FakeLowBalance
+		def self.for(_)
+			self
+		end
+
+		def self.notify!
+			EMPromise.resolve(0)
+		end
+	end
+
+	def self.call_info(customer)
+		if customer.registered?
+			CallAttemptRepo.new
+				.find_outbound(customer, "+1", call_id: "", low_balance: FakeLowBalance)
+				.then(&:to_s)
+		else
+			EMPromise.resolve("No calling")
+		end
+	end
+
 	def form
 		FormTemplate.render("admin_info", admin_info: self)
 	end

test/test_customer_info.rb 🔗

@@ -37,6 +37,7 @@ class CustomerInfoTest < Minitest::Test
 		sgx.expect(:registered?, false)
 		fwd = CustomerFwd.for(uri: "tel:+12223334444", timeout: 15)
 		sgx.expect(:fwd, fwd)
+		sgx.expect(:registered?, false)
 
 		CustomerPlan::DB.expect(
 			:query_one,
@@ -69,6 +70,7 @@ class CustomerInfoTest < Minitest::Test
 	def test_inactive_admin_info_does_not_crash
 		sgx = Minitest::Mock.new
 		sgx.expect(:registered?, false)
+		sgx.expect(:registered?, false)
 		sgx.expect(:fwd, CustomerFwd::None.new(uri: nil, timeout: nil))
 
 		plan = CustomerPlan.new("test", plan: nil, expires_at: nil)