From 0ef60a260a81f3554c8d4078efc485b33a6f6673 Mon Sep 17 00:00:00 2001 From: Stephen Paul Weber Date: Mon, 17 Jan 2022 11:43:50 -0500 Subject: [PATCH] auto_top_up_amount and monthly_overage_limit from CustomerRepo Move load of auto_top_up_amount to the repo, and load monthly_overage_limit in the same operation. --- lib/customer.rb | 3 ++- lib/customer_info.rb | 20 ++++++--------- lib/customer_plan.rb | 21 +++++++++++----- lib/customer_repo.rb | 51 ++++++++++++++++++++++++-------------- lib/low_balance.rb | 20 +++++++-------- test/test_customer_info.rb | 12 --------- test/test_helper.rb | 28 +++++++++++---------- test/test_low_balance.rb | 16 +++--------- 8 files changed, 85 insertions(+), 86 deletions(-) diff --git a/lib/customer.rb b/lib/customer.rb index 9292cbb1a1a1882bc92bd071d7afe3fdefdb679a..70a22172cd59121df56b09bc119d8494bda42a45 100644 --- a/lib/customer.rb +++ b/lib/customer.rb @@ -22,7 +22,8 @@ class Customer attr_reader :customer_id, :balance, :jid, :tndetails def_delegators :@plan, :active?, :activate_plan_starting_now, :bill_plan, - :currency, :merchant_account, :plan_name, :auto_top_up_amount + :currency, :merchant_account, :plan_name, + :auto_top_up_amount, :monthly_overage_limit def_delegators :@sgx, :register!, :registered?, :set_ogm_url, :fwd, :transcription_enabled def_delegators :@usage, :usage_report, :message_usage, :incr_message_usage diff --git a/lib/customer_info.rb b/lib/customer_info.rb index 80f9d05f8a07cea2bf6a44de7bc9d9eb119f531d..a6167bbaf4ce99eb64d5bea67a676658575bd1f1 100644 --- a/lib/customer_info.rb +++ b/lib/customer_info.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require "bigdecimal" +require "forwardable" require "relative_time" require "value_semantics/monkey_patched" require_relative "proxied_jid" @@ -8,17 +9,15 @@ require_relative "customer_plan" require_relative "form_template" class PlanInfo + extend Forwardable + + def_delegators :plan, :expires_at, :auto_top_up_amount + def self.for(plan) return EMPromise.resolve(NoPlan.new) unless plan&.plan_name - EMPromise.all([ - plan.activation_date, - plan.auto_top_up_amount - ]).then do |adate, atua| - new( - plan: plan, start_date: adate, - auto_top_up_amount: atua - ) + plan.activation_date.then do |adate| + new(plan: plan, start_date: adate) end end @@ -39,11 +38,6 @@ class PlanInfo value_semantics do plan CustomerPlan start_date Time - auto_top_up_amount Integer - end - - def expires_at - plan.expires_at end def template diff --git a/lib/customer_plan.rb b/lib/customer_plan.rb index 5aa356983a37703ba683ec57b992efb505248af1..3a58df0adda342680a847eb1a911eac54f40d08d 100644 --- a/lib/customer_plan.rb +++ b/lib/customer_plan.rb @@ -3,19 +3,32 @@ require "forwardable" require_relative "em" +require_relative "plan" class CustomerPlan extend Forwardable - attr_reader :expires_at + attr_reader :expires_at, :auto_top_up_amount, :monthly_overage_limit def_delegator :@plan, :name, :plan_name def_delegators :@plan, :currency, :merchant_account, :monthly_price - def initialize(customer_id, plan: nil, expires_at: Time.now) + def self.for(customer_id, plan_name: nil, **kwargs) + new(customer_id, plan: plan_name&.then(&Plan.method(:for)), **kwargs) + end + + def initialize( + customer_id, + plan: nil, + expires_at: Time.now, + auto_top_up_amount: 0, + monthly_overage_limit: 0 + ) @customer_id = customer_id @plan = plan || OpenStruct.new @expires_at = expires_at + @auto_top_up_amount = auto_top_up_amount + @monthly_overage_limit = monthly_overage_limit end def active? @@ -30,10 +43,6 @@ class CustomerPlan ) end - def auto_top_up_amount - REDIS.get("jmp_customer_auto_top_up_amount-#{@customer_id}").then(&:to_i) - end - def bill_plan EM.promise_fiber do DB.transaction do diff --git a/lib/customer_repo.rb b/lib/customer_repo.rb index ca04200b37b3297bb44b5e61c25804ffcab16acb..64a9c91917dd80046d913d9466cf06eb9fb45eb3 100644 --- a/lib/customer_repo.rb +++ b/lib/customer_repo.rb @@ -65,10 +65,8 @@ class CustomerRepo @bandwidth_tn_repo.put_lidb_name(customer.registered?.phone, lidb_name) end - def put_transcription_enabled(customer, transcription_enabled) - @sgx_repo.put_transcription_enabled( - customer.customer_id, transcription_enabled - ) + def put_transcription_enabled(customer, enabled) + @sgx_repo.put_transcription_enabled(customer.customer_id, enabled) end def put_fwd(customer, customer_fwd) @@ -82,14 +80,17 @@ protected TrivialBackendSgxRepo.new.get(customer_id).with(registered?: false) end - def hydrate_plan(customer_id, raw_customer) - raw_customer.dup.tap do |data| - data[:plan] = CustomerPlan.new( - customer_id, - plan: data.delete(:plan_name)&.then(&Plan.method(:for)), - expires_at: data.delete(:expires_at) - ) - end + def mget(*keys) + @redis.mget(keys).then { |values| Hash[keys.zip(values)] } + end + + def fetch_redis(customer_id) + mget( + "jmp_customer_auto_top_up_amount-#{customer_id}", + "jmp_customer_monthly_overage_limit-#{customer_id}" + ).then { |r| + r.transform_keys { |k| k.match(/^jmp_customer_([^-]+)/)[1].to_sym } + } end SQL = <<~SQL @@ -98,6 +99,20 @@ protected WHERE customer_id=$1 LIMIT 1 SQL + def fetch_sql(customer_id) + @db.query_defer(SQL, [customer_id]).then do |rows| + rows.first&.transform_keys(&:to_sym) || { balance: 0 } + end + end + + def fetch_all(customer_id) + EMPromise.all([ + @sgx_repo.get(customer_id), + fetch_sql(customer_id), + fetch_redis(customer_id) + ]).then { |sgx, sql, redis| [sgx, sql.merge(redis)] } + end + def tndetails(sgx) return unless sgx.registered? @@ -105,14 +120,14 @@ protected end def find_inner(customer_id, jid) - result = @db.query_defer(SQL, [customer_id]) - EMPromise.all([@sgx_repo.get(customer_id), result]).then do |(sgx, rows)| - data = hydrate_plan( - customer_id, rows.first&.transform_keys(&:to_sym) || {} - ) + fetch_all(customer_id).then do |(sgx, data)| Customer.new( customer_id, Blather::JID.new(jid), - sgx: sgx, tndetails: tndetails(sgx), **data + sgx: sgx, balance: data[:balance], tndetails: tndetails(sgx), + plan: CustomerPlan.for( + customer_id, + **data.delete_if { |(k, _)| k == :balance } + ) ) end end diff --git a/lib/low_balance.rb b/lib/low_balance.rb index c97341a2fd29d590a3784023410b18bb42534308..4f93b3c8f4c8befca90a0bc973648da75482da2e 100644 --- a/lib/low_balance.rb +++ b/lib/low_balance.rb @@ -11,15 +11,13 @@ class LowBalance "jmp_customer_low_balance-#{customer.customer_id}", expiry: 60 * 60 * 24 * 7 ).with(-> { Locked.new }) do - customer.auto_top_up_amount.then do |auto_top_up_amount| - for_auto_top_up_amount(customer, auto_top_up_amount) - end + for_auto_top_up_amount(customer) end end - def self.for_auto_top_up_amount(customer, auto_top_up_amount) - if auto_top_up_amount.positive? - AutoTopUp.new(customer, auto_top_up_amount) + def self.for_auto_top_up_amount(customer) + if customer.auto_top_up_amount.positive? + AutoTopUp.new(customer) else customer.btc_addresses.then do |btc_addresses| new(customer, btc_addresses) @@ -49,15 +47,17 @@ class LowBalance end class AutoTopUp - def initialize(customer, auto_top_up_amount) + def initialize(customer) @customer = customer - @auto_top_up_amount = auto_top_up_amount @message = Blather::Stanza::Message.new @message.from = CONFIG[:notify_from] end def sale - Transaction.sale(@customer, amount: @auto_top_up_amount).then do |tx| + Transaction.sale( + @customer, + amount: @customer.auto_top_up_amount + ).then do |tx| tx.insert.then { tx } end end @@ -70,7 +70,7 @@ class LowBalance }.catch { |e| @message.body = "Automatic top-up transaction for " \ - "$#{@auto_top_up_amount} failed: #{e.message}" + "$#{customer.auto_top_up_amount} failed: #{e.message}" }.then { @customer.stanza_to(@message) } end end diff --git a/test/test_customer_info.rb b/test/test_customer_info.rb index 7398cc1e6995bf9c1f5d40b405b9e7a6d9ebd341..3e6aae1c13bfa54b14aca941f54ce535a20aa8f6 100644 --- a/test/test_customer_info.rb +++ b/test/test_customer_info.rb @@ -19,12 +19,6 @@ class CustomerInfoTest < Minitest::Test sgx = Minitest::Mock.new sgx.expect(:registered?, false) - CustomerPlan::REDIS.expect( - :get, - EMPromise.resolve(nil), - ["jmp_customer_auto_top_up_amount-test"] - ) - CustomerPlan::DB.expect( :query_defer, EMPromise.resolve([{ "start_date" => Time.now }]), @@ -44,12 +38,6 @@ class CustomerInfoTest < Minitest::Test fwd = CustomerFwd.for(uri: "tel:+12223334444", timeout: 15) sgx.expect(:fwd, fwd) - CustomerPlan::REDIS.expect( - :get, - EMPromise.resolve(nil), - ["jmp_customer_auto_top_up_amount-test"] - ) - CustomerPlan::DB.expect( :query_defer, EMPromise.resolve([{ "start_date" => Time.now }]), diff --git a/test/test_helper.rb b/test/test_helper.rb index 3fda227d414caa2a0c8bc9aa2e8f351d931950ef..c8f0acdec0c820f4b87d52d6578c308d7196c59f 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -39,19 +39,21 @@ require "tel_selections" $VERBOSE = nil Sentry.init -def customer(customer_id="test", plan_name: nil, **kwargs) - jid = kwargs.delete(:jid) || Blather::JID.new("#{customer_id}@example.net") - if plan_name - expires_at = kwargs.delete(:expires_at) || Time.now - plan = CustomerPlan.new( - customer_id, - plan: Plan.for(plan_name), - expires_at: expires_at - ) - Customer.new(customer_id, jid, plan: plan, **kwargs) - else - Customer.new(customer_id, jid, **kwargs) - end +def customer( + customer_id="test", + plan_name: nil, + jid: Blather::JID.new("#{customer_id}@example.net"), + expires_at: Time.now, + auto_top_up_amount: 0, + **kwargs +) + plan = CustomerPlan.for( + customer_id, + plan_name: plan_name, + expires_at: expires_at, + auto_top_up_amount: auto_top_up_amount + ) + Customer.new(customer_id, jid, plan: plan, **kwargs) end CONFIG = { diff --git a/test/test_low_balance.rb b/test/test_low_balance.rb index cee6101473de26db7f9b822bdb9264ae04fe6b95..86f794bde135d15403d1a921edcad0a2d98d77a8 100644 --- a/test/test_low_balance.rb +++ b/test/test_low_balance.rb @@ -24,11 +24,6 @@ class LowBalanceTest < Minitest::Test EMPromise.resolve(0), ["jmp_customer_low_balance-test"] ) - CustomerPlan::REDIS.expect( - :get, - EMPromise.resolve(nil), - ["jmp_customer_auto_top_up_amount-test"] - ) Customer::REDIS.expect( :smembers, EMPromise.resolve([]), @@ -53,11 +48,6 @@ class LowBalanceTest < Minitest::Test EMPromise.resolve(0), ["jmp_customer_low_balance-test"] ) - CustomerPlan::REDIS.expect( - :get, - EMPromise.resolve("15"), - ["jmp_customer_auto_top_up_amount-test"] - ) ExpiringLock::REDIS.expect( :setex, EMPromise.resolve(nil), @@ -65,7 +55,7 @@ class LowBalanceTest < Minitest::Test ) assert_kind_of( LowBalance::AutoTopUp, - LowBalance.for(customer).sync + LowBalance.for(customer(auto_top_up_amount: 15)).sync ) assert_mock ExpiringLock::REDIS end @@ -75,8 +65,8 @@ class LowBalanceTest < Minitest::Test LowBalance::AutoTopUp::Transaction = Minitest::Mock.new def setup - @customer = customer - @auto_top_up = LowBalance::AutoTopUp.new(@customer, 100) + @customer = customer(auto_top_up_amount: 100) + @auto_top_up = LowBalance::AutoTopUp.new(@customer) end def test_notify!