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