~singpolyma/sgx-jmp

12cc57d6c87dcf590cb5f58d51174d9610aaecaf — Stephen Paul Weber 1 year, 11 days ago 92d5648
Method to bill the plan of a Customer

Bills their balance for the cost of one month of plan.
Activates the plan by insert into plan_log, unless already active in which case
extends current plan by one month.
3 files changed, 106 insertions(+), 0 deletions(-)

M lib/customer.rb
M lib/plan.rb
M test/test_customer.rb
M lib/customer.rb => lib/customer.rb +47 -0
@@ 52,6 52,14 @@ class Customer
		)
	end

	def bill_plan
		EM.promise_fiber do
			DB.transaction do
				charge_for_plan
				add_one_month_to_current_plan unless activate_plan_starting_now
			end
		end
	end

	def payment_methods
		@payment_methods ||=


@@ 72,4 80,43 @@ class Customer
			result&.respond_to?(:registered?) && result&.registered?
		end
	end

protected

	def charge_for_plan
		params = [
			@customer_id,
			"#{@customer_id}-bill-#{plan_name}-at-#{Time.now.to_i}",
			-@plan.monthly_price
		]
		DB.exec(<<~SQL, params)
			INSERT INTO transactions
				(customer_id, transaction_id, created_at, amount)
			VALUES ($1, $2, LOCALTIMESTAMP, $3)
		SQL
	end

	def activate_plan_starting_now
		DB.exec(<<~SQL, [@customer_id, plan_name]).cmd_tuples.positive?
			INSERT INTO plan_log
				(customer_id, plan_name, date_range)
			VALUES ($1, $2, tsrange('now', LOCALTIMESTAMP + '1 month'))
			ON CONFLICT DO NOTHING
		SQL
	end

	def add_one_month_to_current_plan
		DB.exec(<<~SQL, [@customer_id])
			UPDATE plan_log SET date_range=range_merge(
				date_range,
				tsrange(
					'now',
					GREATEST(upper(date_range), LOCALTIMESTAMP) + '1 month'
				)
			)
			WHERE
				customer_id=$1 AND
				date_range && tsrange('now', LOCALTIMESTAMP + '1 month')
		SQL
	end
end

M lib/plan.rb => lib/plan.rb +4 -0
@@ 20,6 20,10 @@ class Plan
		@plan[:currency]
	end

	def monthly_price
		BigDecimal.new(@plan[:monthly_price]) / 1000
	end

	def merchant_account
		CONFIG[:braintree][:merchant_accounts].fetch(currency) do
			raise "No merchant account for this currency"

M test/test_customer.rb => test/test_customer.rb +55 -0
@@ 47,4 47,59 @@ class CustomerTest < Minitest::Test
		assert_equal BigDecimal.new(0), customer.balance
	end
	em :test_for_customer_id_not_found

	def test_bill_plan_activate
		Customer::DB.expect(:transaction, nil) do |&block|
			block.call
			true
		end
		Customer::DB.expect(
			:exec,
			nil,
			[
				String,
				Matching.new do |params|
					params[0] == "test" &&
					params[1].is_a?(String) &&
					BigDecimal.new(-1) == params[2]
				end
			]
		)
		Customer::DB.expect(
			:exec,
			OpenStruct.new(cmd_tuples: 1),
			[String, ["test", "test_usd"]]
		)
		Customer.new("test", plan_name: "test_usd").bill_plan.sync
		Customer::DB.verify
	end
	em :test_bill_plan_activate

	def test_bill_plan_update
		Customer::DB.expect(:transaction, nil) do |&block|
			block.call
			true
		end
		Customer::DB.expect(
			:exec,
			nil,
			[
				String,
				Matching.new do |params|
					params[0] == "test" &&
					params[1].is_a?(String) &&
					BigDecimal.new(-1) == params[2]
				end
			]
		)
		Customer::DB.expect(
			:exec,
			OpenStruct.new(cmd_tuples: 0),
			[String, ["test", "test_usd"]]
		)
		Customer::DB.expect(:exec, nil, [String, ["test"]])
		Customer.new("test", plan_name: "test_usd").bill_plan.sync
		Customer::DB.verify
	end
	em :test_bill_plan_update
end