M forms/customer_info_partial.rb => forms/customer_info_partial.rb +6 -0
@@ 26,4 26,10 @@ field(
value: "$%.4f" % @info.balance
)
+field(
+ var: "remaining_included_calling_credit",
+ label: "Remaining Included Calling Credit",
+ value: "$%.4f" % @info.remaining_included_calling_credit
+)
+
render @info.plan_info.template
M lib/customer.rb => lib/customer.rb +2 -1
@@ 27,7 27,8 @@ class Customer
:expires_at, :monthly_price, :save_plan!
def_delegators :@sgx, :deregister!, :register!, :registered?, :set_ogm_url,
:fwd, :transcription_enabled
- def_delegators :@usage, :usage_report, :message_usage, :incr_message_usage
+ def_delegators :@usage, :usage_report, :message_usage, :incr_message_usage,
+ :calling_charges_this_month
def_delegators :@financials, :payment_methods, :btc_addresses,
:add_btc_address, :declines, :mark_decline,
:transactions
M lib/customer_info.rb => lib/customer_info.rb +9 -1
@@ 80,6 80,8 @@ class CustomerInfo
tel Either(String, nil)
balance BigDecimal
cnam Either(String, nil)
+ calling_credit BigDecimal
+ calling_charges_this_month BigDecimal
end
def self.for(customer)
@@ 87,10 89,16 @@ class CustomerInfo
plan_info: PlanInfo.for(customer),
tel: customer.registered? ? customer.registered?.phone : nil,
balance: customer.balance,
- cnam: customer.tndetails.dig(:features, :lidb, :subscriber_information)
+ cnam: customer.tndetails.dig(:features, :lidb, :subscriber_information),
+ calling_credit: customer.minute_limit.to_d,
+ calling_charges_this_month: customer.calling_charges_this_month
).then(&method(:new))
end
+ def remaining_included_calling_credit
+ [calling_credit - calling_charges_this_month, 0].max
+ end
+
def form
FormTemplate.render("customer_info", info: self)
end
M lib/customer_usage.rb => lib/customer_usage.rb +8 -0
@@ 72,4 72,12 @@ class CustomerUsage
end
end
end
+
+ def calling_charges_this_month
+ DB.query_one(<<~SQL, @customer_id).then { |r| r[:charges] }
+ SELECT COALESCE(SUM(charge), 0) AS charges
+ FROM cdr_with_charge
+ WHERE customer_id=$1 AND start >= DATE_TRUNC('month', LOCALTIMESTAMP)
+ SQL
+ end
end
M test/test_customer_info.rb => test/test_customer_info.rb +86 -0
@@ 6,7 6,9 @@ require "trust_level_repo"
require "trust_level"
API::REDIS = FakeRedis.new
+CustomerPlan::DB = Minitest::Mock.new
CustomerPlan::REDIS = Minitest::Mock.new
+CustomerUsage::DB = Minitest::Mock.new
PlanInfo::DB = FakeDB.new(
["test"] => [
{
@@ 27,6 29,12 @@ class CustomerInfoTest < Minitest::Test
[String, "test"]
)
+ CustomerUsage::DB.expect(
+ :query_one,
+ EMPromise.resolve({ charges: 0.to_d }),
+ [String, "test"]
+ )
+
cust = customer(sgx: sgx, plan_name: "test_usd")
assert CustomerInfo.for(cust).sync.form
@@ 34,6 42,60 @@ class CustomerInfoTest < Minitest::Test
end
em :test_info_does_not_crash
+ def test_info_has_remaining_included_calling_credit
+ sgx = Minitest::Mock.new
+ sgx.expect(:registered?, false)
+
+ CustomerPlan::DB.expect(
+ :query_one,
+ EMPromise.resolve({ start_date: Time.now }),
+ [String, "test"]
+ )
+
+ CustomerUsage::DB.expect(
+ :query_one,
+ EMPromise.resolve({ charges: 0.044.to_d }),
+ [String, "test"]
+ )
+
+ cust = customer(sgx: sgx, plan_name: "test_usd")
+
+ assert_equal(
+ "$1.0000",
+ CustomerInfo.for(cust).sync.form
+ .field("remaining_included_calling_credit").value
+ )
+ assert_mock sgx
+ end
+ em :test_info_has_remaining_included_calling_credit
+
+ def test_info_out_of_remaining_included_calling_credit
+ sgx = Minitest::Mock.new
+ sgx.expect(:registered?, false)
+
+ CustomerPlan::DB.expect(
+ :query_one,
+ EMPromise.resolve({ start_date: Time.now }),
+ [String, "test"]
+ )
+
+ CustomerUsage::DB.expect(
+ :query_one,
+ EMPromise.resolve({ charges: 10.to_d }),
+ [String, "test"]
+ )
+
+ cust = customer(sgx: sgx, plan_name: "test_usd")
+
+ assert_equal(
+ "$0.0000",
+ CustomerInfo.for(cust).sync.form
+ .field("remaining_included_calling_credit").value
+ )
+ assert_mock sgx
+ end
+ em :test_info_out_of_remaining_included_calling_credit
+
def test_admin_info_does_not_crash
sgx = Minitest::Mock.new
sgx.expect(:registered?, false)
@@ 47,6 109,12 @@ class CustomerInfoTest < Minitest::Test
[String, "test"]
)
+ CustomerUsage::DB.expect(
+ :query_one,
+ EMPromise.resolve({ charges: 0.to_d }),
+ [String, "test"]
+ )
+
cust = customer(sgx: sgx, plan_name: "test_usd")
trust_repo = Minitest::Mock.new
@@ 69,6 137,12 @@ class CustomerInfoTest < Minitest::Test
[String, "test"]
)
+ CustomerUsage::DB.expect(
+ :query_one,
+ EMPromise.resolve({ charges: 0.to_d }),
+ [String, "test"]
+ )
+
cust = customer(sgx: sgx, plan_name: "test_usd")
call_attempt_repo = Minitest::Mock.new
@@ 92,6 166,12 @@ class CustomerInfoTest < Minitest::Test
em :test_admin_info_with_tel_does_not_crash
def test_inactive_info_does_not_crash
+ CustomerUsage::DB.expect(
+ :query_one,
+ EMPromise.resolve({ charges: 0.to_d }),
+ [String, "test"]
+ )
+
sgx = Minitest::Mock.new
sgx.expect(:registered?, false)
@@ 108,6 188,12 @@ class CustomerInfoTest < Minitest::Test
em :test_inactive_info_does_not_crash
def test_inactive_admin_info_does_not_crash
+ CustomerUsage::DB.expect(
+ :query_one,
+ EMPromise.resolve({ charges: 0.to_d }),
+ [String, "test"]
+ )
+
sgx = Minitest::Mock.new
sgx.expect(:registered?, false)
sgx.expect(:registered?, false)