From dabca132291e2c3d1ca03e272b2cd556956c2e84 Mon Sep 17 00:00:00 2001 From: Stephen Paul Weber Date: Tue, 18 May 2021 13:37:04 -0500 Subject: [PATCH] Break out CustomerPlan We had Plan and Customer but the relationship between the two lived entirely in Customer, which was growing quite large. Break that relationship out into its own concept and give it a name. --- lib/customer.rb | 66 +++++++---------------------------------- lib/customer_plan.rb | 69 +++++++++++++++++++++++++++++++++++++++++++ test/test_customer.rb | 19 ++++++------ 3 files changed, 89 insertions(+), 65 deletions(-) create mode 100644 lib/customer_plan.rb diff --git a/lib/customer.rb b/lib/customer.rb index f4f4186..9f087de 100644 --- a/lib/customer.rb +++ b/lib/customer.rb @@ -2,6 +2,7 @@ require "forwardable" +require_relative "./customer_plan" require_relative "./backend_sgx" require_relative "./ibr" require_relative "./payment_methods" @@ -29,8 +30,8 @@ class Customer extend Forwardable attr_reader :customer_id, :balance - def_delegator :@plan, :name, :plan_name - def_delegators :@plan, :currency, :merchant_account + def_delegators :@plan, :active?, :activate_plan_starting_now, :bill_plan, + :currency, :merchant_account, :plan_name def_delegators :@sgx, :register!, :registered? def initialize( @@ -40,8 +41,11 @@ class Customer balance: BigDecimal.new(0), sgx: BackendSgx.new(customer_id) ) - @plan = plan_name && Plan.for(plan_name) - @expires_at = expires_at + @plan = CustomerPlan.new( + customer_id, + plan: plan_name && Plan.for(plan_name), + expires_at: expires_at + ) @customer_id = customer_id @balance = balance @sgx = sgx @@ -51,29 +55,11 @@ class Customer self.class.new( @customer_id, balance: @balance, - expires_at: @expires_at, + expires_at: expires_at, plan_name: plan_name ) 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 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(LOCALTIMESTAMP, LOCALTIMESTAMP + '1 month')) - ON CONFLICT DO NOTHING - SQL - end - def payment_methods @payment_methods ||= BRAINTREE @@ -82,37 +68,5 @@ class Customer .then(PaymentMethods.method(:for_braintree_customer)) end - def active? - @plan && @expires_at > Time.now - 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 add_one_month_to_current_plan - DB.exec(<<~SQL, [@customer_id]) - UPDATE plan_log SET date_range=range_merge( - date_range, - tsrange( - LOCALTIMESTAMP, - GREATEST(upper(date_range), LOCALTIMESTAMP) + '1 month' - ) - ) - WHERE - customer_id=$1 AND - date_range && tsrange(LOCALTIMESTAMP, LOCALTIMESTAMP + '1 month') - SQL - end + protected def_delegator :@plan, :expires_at end diff --git a/lib/customer_plan.rb b/lib/customer_plan.rb new file mode 100644 index 0000000..6c31516 --- /dev/null +++ b/lib/customer_plan.rb @@ -0,0 +1,69 @@ +# frozen_string_literal: true + +require "forwardable" + +class CustomerPlan + extend Forwardable + + attr_reader :expires_at + def_delegator :@plan, :name, :plan_name + def_delegators :@plan, :currency, :merchant_account + + def initialize(customer_id, plan: nil, expires_at: Time.now) + @customer_id = customer_id + @plan = plan + @expires_at = expires_at + end + + def active? + @plan && @expires_at > Time.now + 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 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(LOCALTIMESTAMP, LOCALTIMESTAMP + '1 month')) + ON CONFLICT DO NOTHING + SQL + 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 add_one_month_to_current_plan + DB.exec(<<~SQL, [@customer_id]) + UPDATE plan_log SET date_range=range_merge( + date_range, + tsrange( + LOCALTIMESTAMP, + GREATEST(upper(date_range), LOCALTIMESTAMP) + '1 month' + ) + ) + WHERE + customer_id=$1 AND + date_range && tsrange(LOCALTIMESTAMP, LOCALTIMESTAMP + '1 month') + SQL + end +end diff --git a/test/test_customer.rb b/test/test_customer.rb index b2de096..4225b58 100644 --- a/test/test_customer.rb +++ b/test/test_customer.rb @@ -5,6 +5,7 @@ require "customer" Customer::REDIS = Minitest::Mock.new Customer::DB = Minitest::Mock.new +CustomerPlan::DB = Minitest::Mock.new class CustomerTest < Minitest::Test def test_for_jid @@ -49,11 +50,11 @@ class CustomerTest < Minitest::Test em :test_for_customer_id_not_found def test_bill_plan_activate - Customer::DB.expect(:transaction, nil) do |&block| + CustomerPlan::DB.expect(:transaction, nil) do |&block| block.call true end - Customer::DB.expect( + CustomerPlan::DB.expect( :exec, nil, [ @@ -65,22 +66,22 @@ class CustomerTest < Minitest::Test end ] ) - Customer::DB.expect( + CustomerPlan::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 + CustomerPlan::DB.verify end em :test_bill_plan_activate def test_bill_plan_update - Customer::DB.expect(:transaction, nil) do |&block| + CustomerPlan::DB.expect(:transaction, nil) do |&block| block.call true end - Customer::DB.expect( + CustomerPlan::DB.expect( :exec, nil, [ @@ -92,14 +93,14 @@ class CustomerTest < Minitest::Test end ] ) - Customer::DB.expect( + CustomerPlan::DB.expect( :exec, OpenStruct.new(cmd_tuples: 0), [String, ["test", "test_usd"]] ) - Customer::DB.expect(:exec, nil, [String, ["test"]]) + CustomerPlan::DB.expect(:exec, nil, [String, ["test"]]) Customer.new("test", plan_name: "test_usd").bill_plan.sync - Customer::DB.verify + CustomerPlan::DB.verify end em :test_bill_plan_update end -- 2.45.2