1# frozen_string_literal: true
2
3require "forwardable"
4
5require_relative "em"
6
7class CustomerPlan
8 extend Forwardable
9
10 attr_reader :expires_at
11 def_delegator :@plan, :name, :plan_name
12 def_delegators :@plan, :currency, :merchant_account, :monthly_price
13
14 def initialize(customer_id, plan: nil, expires_at: Time.now)
15 @customer_id = customer_id
16 @plan = plan || OpenStruct.new
17 @expires_at = expires_at
18 end
19
20 def active?
21 plan_name && @expires_at > Time.now
22 end
23
24 def with_plan_name(plan_name)
25 self.class.new(
26 @customer_id,
27 plan: Plan.for(plan_name),
28 expires_at: @expires_at
29 )
30 end
31
32 def auto_top_up_amount
33 REDIS.get("jmp_customer_auto_top_up_amount-#{@customer_id}").then(&:to_i)
34 end
35
36 def bill_plan
37 EM.promise_fiber do
38 DB.transaction do
39 charge_for_plan
40 add_one_month_to_current_plan unless activate_plan_starting_now
41 end
42 end
43 end
44
45 def activate_plan_starting_now
46 DB.exec(<<~SQL, [@customer_id, plan_name]).cmd_tuples.positive?
47 INSERT INTO plan_log
48 (customer_id, plan_name, date_range)
49 VALUES ($1, $2, tsrange(LOCALTIMESTAMP, LOCALTIMESTAMP + '1 month'))
50 ON CONFLICT DO NOTHING
51 SQL
52 end
53
54protected
55
56 def charge_for_plan
57 params = [
58 @customer_id,
59 "#{@customer_id}-bill-#{plan_name}-at-#{Time.now.to_i}",
60 -@plan.monthly_price
61 ]
62 DB.exec(<<~SQL, params)
63 INSERT INTO transactions
64 (customer_id, transaction_id, created_at, amount)
65 VALUES ($1, $2, LOCALTIMESTAMP, $3)
66 SQL
67 end
68
69 def add_one_month_to_current_plan
70 DB.exec(<<~SQL, [@customer_id])
71 UPDATE plan_log SET date_range=range_merge(
72 date_range,
73 tsrange(
74 LOCALTIMESTAMP,
75 GREATEST(upper(date_range), LOCALTIMESTAMP) + '1 month'
76 )
77 )
78 WHERE
79 customer_id=$1 AND
80 date_range && tsrange(LOCALTIMESTAMP, LOCALTIMESTAMP + '1 month')
81 SQL
82 end
83end