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	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