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 "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