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