1# frozen_string_literal: true
2
3require "forwardable"
4
5require_relative "./api"
6require_relative "./blather_ext"
7require_relative "./customer_info"
8require_relative "./customer_ogm"
9require_relative "./customer_plan"
10require_relative "./customer_usage"
11require_relative "./backend_sgx"
12require_relative "./ibr"
13require_relative "./payment_methods"
14require_relative "./plan"
15require_relative "./proxied_jid"
16require_relative "./sip_account"
17
18class Customer
19 extend Forwardable
20
21 attr_reader :customer_id, :balance, :jid
22 def_delegators :@plan, :active?, :activate_plan_starting_now, :bill_plan,
23 :currency, :merchant_account, :plan_name, :auto_top_up_amount
24 def_delegators :@sgx, :register!, :registered?,
25 :fwd_timeout, :set_fwd_timeout, :catapult_flag
26 def_delegators :@usage, :usage_report, :message_usage, :incr_message_usage
27
28 def initialize(
29 customer_id,
30 jid,
31 plan: CustomerPlan.new(customer_id),
32 balance: BigDecimal(0),
33 sgx: BackendSgx.new(customer_id)
34 )
35 @plan = plan
36 @usage = CustomerUsage.new(customer_id)
37 @customer_id = customer_id
38 @jid = jid
39 @balance = balance
40 @sgx = sgx
41 end
42
43 def with_plan(plan_name)
44 self.class.new(
45 @customer_id,
46 @jid,
47 plan: @plan.with_plan_name(plan_name),
48 balance: @balance,
49 sgx: @sgx
50 )
51 end
52
53 def payment_methods
54 BRAINTREE
55 .customer
56 .find(@customer_id)
57 .catch { OpenStruct.new(payment_methods: []) }
58 .then(PaymentMethods.method(:for_braintree_customer))
59 end
60
61 def unused_invites
62 promise = DB.query_defer(<<~SQL, [customer_id])
63 SELECT code FROM unused_invites WHERE creator_id=$1
64 SQL
65 promise.then { |result| result.map { |row| row["code"] } }
66 end
67
68 def stanza_to(stanza)
69 stanza = stanza.dup
70 stanza.to = jid.with(resource: stanza.to&.resource)
71 stanza.from = stanza.from.with(domain: CONFIG[:component][:jid])
72 block_given? ? yield(stanza) : (BLATHER << stanza)
73 end
74
75 def stanza_from(stanza)
76 BLATHER << @sgx.stanza(stanza)
77 end
78
79 def fetch_vcard_temp(from_tel=nil)
80 iq = Blather::Stanza::Iq::Vcard.new(:get)
81 iq.from = Blather::JID.new(from_tel, CONFIG[:component][:jid])
82 stanza_to(iq, &IQ_MANAGER.method(:write)).then(&:vcard)
83 end
84
85 def ogm(from_tel=nil)
86 @sgx.ogm_url.then do |url|
87 CustomerOGM.for(url, -> { fetch_vcard_temp(from_tel) })
88 end
89 end
90
91 def sip_account
92 SipAccount.find(customer_id)
93 end
94
95 def reset_sip_account
96 SipAccount::New.new(username: customer_id).put.catch do
97 sip_account.then { |acct| acct.with_random_password.put }
98 end
99 end
100
101 def btc_addresses
102 REDIS.smembers("jmp_customer_btc_addresses-#{customer_id}")
103 end
104
105 def add_btc_address
106 REDIS.spopsadd([
107 "jmp_available_btc_addresses",
108 "jmp_customer_btc_addresses-#{customer_id}"
109 ]).then do |addr|
110 ELECTRUM.notify(addr, CONFIG[:electrum_notify_url].call(addr, customer_id))
111 addr
112 end
113 end
114
115 def admin?
116 CONFIG[:admins].include?(jid.to_s)
117 end
118
119 def api
120 API.for(self)
121 end
122
123 def admin_info
124 AdminInfo.for(self, @plan, expires_at)
125 end
126
127 def info
128 CustomerInfo.for(self, @plan, expires_at)
129 end
130
131 protected def_delegator :@plan, :expires_at
132end