customer_info.rb

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