1# frozen_string_literal: true
2
3require "bigdecimal"
4require "forwardable"
5require "relative_time"
6require "value_semantics/monkey_patched"
7
8require_relative "api"
9require_relative "call_attempt_repo"
10require_relative "customer"
11require_relative "customer_plan"
12require_relative "form_template"
13require_relative "promise_hash"
14require_relative "proxied_jid"
15
16class PlanInfo
17 extend Forwardable
18
19 def_delegators :customer, :expires_at, :auto_top_up_amount
20
21 def self.for(customer)
22 return EMPromise.resolve(NoPlan.new) unless customer&.plan_name
23
24 PromiseHash.all(
25 customer: customer,
26 start_date: customer.activation_date,
27 calling_charges_this_month: customer.calling_charges_this_month
28 ).then(method(:new))
29 end
30
31 class NoPlan
32 def template
33 FormTemplate.new("")
34 end
35
36 def admin_template
37 FormTemplate.new("")
38 end
39
40 def status
41 "Transitional"
42 end
43 end
44
45 value_semantics do
46 method_missing :customer, Customer
47 start_date Time
48 calling_charges_this_month BigDecimal
49 end
50
51 def template
52 FormTemplate.for("plan_info", plan_info: self)
53 end
54
55 def admin_template
56 FormTemplate.for("admin_plan_info", plan_info: self)
57 end
58
59 def monthly_price
60 "$%.4f / month" % customer.monthly_price
61 end
62
63 def relative_start_date
64 RelativeTime.in_words(start_date)
65 end
66
67 def formatted_start_date
68 start_date.strftime("%Y-%m-%d %H:%M:%S")
69 end
70
71 def currency
72 (customer.currency || "No Currency").to_s
73 end
74
75 def status
76 customer.status.to_s.capitalize
77 end
78
79 def remaining_included_calling_credit
80 [customer.minute_limit.to_d - calling_charges_this_month, 0].max
81 end
82end
83
84class CustomerInfo
85 value_semantics do
86 plan_info Either(PlanInfo, PlanInfo::NoPlan)
87 tel Either(String, nil)
88 balance BigDecimal
89 cnam Either(String, nil)
90 end
91
92 def self.for(customer)
93 PromiseHash.all(
94 plan_info: PlanInfo.for(customer),
95 tel: customer.registered? ? customer.registered?.phone : nil,
96 balance: customer.balance,
97 cnam: customer.tndetails.dig(:features, :lidb, :subscriber_information)
98 ).then(&method(:new))
99 end
100
101 def form
102 FormTemplate.render("customer_info", info: self)
103 end
104end
105
106class AdminInfo
107 value_semantics do
108 jid ProxiedJID, coerce: ProxiedJID.method(:new)
109 customer_id String
110 fwd Either(CustomerFwd, nil)
111 info CustomerInfo
112 api API
113 call_info String
114 trust_level String
115 backend_jid String
116 end
117
118 def self.for(
119 customer,
120 trust_level_repo: TrustLevelRepo.new,
121 call_attempt_repo: CallAttemptRepo.new,
122 backend_repo: TrivialBackendSgxRepo.new
123 )
124 PromiseHash.all(
125 jid: customer.jid,
126 customer_id: customer.customer_id,
127 fwd: customer.fwd,
128 info: CustomerInfo.for(customer),
129 api: API.for(customer),
130 call_info: call_info(customer, call_attempt_repo),
131 trust_level: trust_level_repo.find(customer).then(&:to_s),
132 backend_jid: backend_repo.get(customer.customer_id).from_jid.to_s
133 ).then(&method(:new))
134 end
135
136 class FakeLowBalance
137 def self.for(_)
138 self
139 end
140
141 def self.notify!
142 EMPromise.resolve(0)
143 end
144 end
145
146 def self.call_info(customer, call_attempt_repo)
147 if customer.registered?
148 call_attempt_repo
149 .find_outbound(customer, "+1", call_id: "dry_run")
150 .then(&:to_s)
151 else
152 EMPromise.resolve("No calling")
153 end
154 end
155
156 def form
157 FormTemplate.render("admin_info", admin_info: self)
158 end
159
160 def tel_link
161 [
162 "https://dashboard.bandwidth.com/portal/r/a",
163 CONFIG[:creds][:account],
164 "numbers/details",
165 info.tel.gsub(/\A\+1/, "")
166 ].join("/")
167 end
168
169 def support_link
170 CONFIG[:support_link].call(backend_jid)
171 end
172end