call_attempt_repo.rb

 1# frozen_string_literal: true
 2
 3require "value_semantics/monkey_patched"
 4require "lazy_object"
 5
 6require_relative "call_attempt"
 7require_relative "trust_level_repo"
 8
 9class CallAttemptRepo
10	value_semantics do
11		db    Anything(), default: LazyObject.new { DB }
12		redis Anything(), default: LazyObject.new { REDIS }
13	end
14
15	def find_outbound(customer, to, **kwargs)
16		find(
17			customer,
18			to,
19			direction: :outbound,
20			from: customer.registered?.phone,
21			to: to,
22			**kwargs
23		)
24	end
25
26	def find_inbound(customer, from, **kwargs)
27		find(
28			customer,
29			from,
30			direction: :inbound,
31			from: from,
32			to: customer.registered?.phone,
33			**kwargs
34		)
35	end
36
37protected
38
39	def find(customer, other_tel, direction:, **kwargs)
40		EMPromise.all([
41			find_rate(customer.plan_name, other_tel, direction),
42			find_usage(customer.customer_id),
43			TrustLevelRepo.new(db: db, redis: redis).find(customer)
44		]).then do |(rate, usage, trust_level)|
45			CallAttempt.for(
46				customer, rate, usage, trust_level, direction: direction, **kwargs
47			)
48		end
49	end
50
51	def find_usage(customer_id)
52		db.query_one(<<~SQL, customer_id, default: { a: 0 }).then { |r| r[:a] }
53			SELECT COALESCE(SUM(charge), 0) AS a FROM cdr_with_charge
54			WHERE
55				customer_id=$1 AND
56				start > DATE_TRUNC('month', LOCALTIMESTAMP)
57		SQL
58	end
59
60	def find_rate(plan_name, other_tel, direction)
61		promise = db.query_one(<<~SQL, plan_name, other_tel, direction)
62			SELECT rate FROM call_rates
63			WHERE
64				plan_name=$1 AND
65				$2 LIKE prefix || '%' AND
66				direction=$3
67			ORDER BY prefix DESC
68			LIMIT 1
69		SQL
70		promise.then { |row| row&.dig(:rate) }
71	end
72end