customer_info.rb

  1# frozen_string_literal: true
  2
  3require "bigdecimal"
  4require "forwardable"
  5require "relative_time"
  6require "value_semantics/monkey_patched"
  7
  8require_relative "call_attempt_repo"
  9require_relative "customer"
 10require_relative "customer_plan"
 11require_relative "form_template"
 12require_relative "promise_hash"
 13require_relative "proxied_jid"
 14require_relative "subaccount"
 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		call_info String
115		trust_level String
116		backend_jid String
117		subaccounts ArrayOf(::Subaccount), default: []
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			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)
133				.then(&:from_jid).then(&:to_s),
134			subaccounts: Subaccount.get_subaccounts(customer.billing_customer_id)
135		).then(&method(:new))
136	end
137
138	class FakeLowBalance
139		def self.for(_)
140			self
141		end
142
143		def self.notify!
144			EMPromise.resolve(0)
145		end
146	end
147
148	def self.call_info(customer, call_attempt_repo)
149		if customer.registered?
150			call_attempt_repo
151				.find_outbound(customer, "+1", call_id: "dry_run")
152				.then(&:to_s)
153		else
154			EMPromise.resolve("No calling")
155		end
156	end
157
158	def form
159		FormTemplate.render("admin_info", admin_info: self)
160	end
161
162	def tel_link
163		[
164			"https://dashboard.bandwidth.com/portal/r/a",
165			CONFIG[:creds][:account],
166			"numbers/details",
167			info.tel.gsub(/\A\+1/, "")
168		].join("/")
169	end
170
171	def support_link
172		CONFIG[:support_link].call(backend_jid)
173	end
174end