customer_info.rb

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