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