customer_plan.rb

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