customer_plan.rb

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