1# frozen_string_literal: true
2
3require "forwardable"
4
5require_relative "./blather_ext"
6require_relative "./customer_plan"
7require_relative "./customer_usage"
8require_relative "./backend_sgx"
9require_relative "./ibr"
10require_relative "./payment_methods"
11require_relative "./plan"
12
13class Customer
14 def self.for_jid(jid)
15 REDIS.get("jmp_customer_id-#{jid}").then do |customer_id|
16 raise "No customer id" unless customer_id
17 for_customer_id(customer_id)
18 end
19 end
20
21 def self.for_customer_id(customer_id)
22 result = DB.query_defer(<<~SQL, [customer_id])
23 SELECT COALESCE(balance,0) AS balance, plan_name, expires_at
24 FROM customer_plans LEFT JOIN balances USING (customer_id)
25 WHERE customer_id=$1 LIMIT 1
26 SQL
27 result.then do |rows|
28 new(customer_id, **rows.first&.transform_keys(&:to_sym) || {})
29 end
30 end
31
32 def self.create(jid)
33 BRAINTREE.customer.create.then do |result|
34 raise "Braintree customer create failed" unless result.success?
35 cid = result.customer.id
36 REDIS.msetnx(
37 "jmp_customer_id-#{jid}", cid, "jmp_customer_jid-#{cid}", jid
38 ).then do |redis_result|
39 raise "Saving new customer to redis failed" unless redis_result == 1
40 new(cid)
41 end
42 end
43 end
44
45 extend Forwardable
46
47 attr_reader :customer_id, :balance
48 def_delegators :@plan, :active?, :activate_plan_starting_now, :bill_plan,
49 :currency, :merchant_account, :plan_name
50 def_delegators :@sgx, :register!, :registered?
51 def_delegator :@usage, :report, :usage_report
52
53 def initialize(
54 customer_id,
55 plan_name: nil,
56 expires_at: Time.now,
57 balance: BigDecimal.new(0),
58 sgx: BackendSgx.new(customer_id)
59 )
60 @plan = CustomerPlan.new(
61 customer_id,
62 plan: plan_name && Plan.for(plan_name),
63 expires_at: expires_at
64 )
65 @usage = CustomerUsage.new(customer_id)
66 @customer_id = customer_id
67 @balance = balance
68 @sgx = sgx
69 end
70
71 def with_plan(plan_name)
72 self.class.new(
73 @customer_id,
74 balance: @balance,
75 expires_at: expires_at,
76 plan_name: plan_name
77 )
78 end
79
80 def payment_methods
81 BRAINTREE
82 .customer
83 .find(@customer_id)
84 .then(PaymentMethods.method(:for_braintree_customer))
85 end
86
87 def jid
88 @jid ||= REDIS.get("jmp_customer_jid-#{customer_id}").then do |sjid|
89 Blather::JID.new(sjid)
90 end
91 end
92
93 def stanza_to(stanza)
94 jid.then do |jid|
95 stanza = stanza.dup
96 stanza.to = jid.with(resource: stanza.to&.resource)
97 stanza.from = stanza.from.with(domain: CONFIG[:component][:jid])
98 BLATHER << stanza
99 end
100 end
101
102 def stanza_from(stanza)
103 BLATHER << @sgx.stanza(stanza)
104 end
105
106 protected def_delegator :@plan, :expires_at
107end