@@ 1,6 1,7 @@
# frozen_string_literal: true
require "forwardable"
+require "value_semantics/monkey_patched"
require_relative "em"
require_relative "plan"
@@ 8,21 9,24 @@ require_relative "plan"
class CustomerPlan
extend Forwardable
- attr_reader :expires_at, :auto_top_up_amount, :monthly_overage_limit,
- :parent_customer_id
-
- def_delegator :@plan, :name, :plan_name
- def_delegators :@plan, :currency, :merchant_account, :monthly_price,
+ def_delegator :plan, :name, :plan_name
+ def_delegators :plan, :currency, :merchant_account, :monthly_price,
:minute_limit, :message_limit
- def self.for(customer_id, plan_name: nil, **kwargs)
- new(customer_id, plan: plan_name&.then(&Plan.method(:for)), **kwargs)
+ value_semantics do
+ customer_id String
+ plan Anything(), default: nil, coerce: true
+ expires_at Either(Time, nil), default_generator: -> { Time.now }
+ auto_top_up_amount Integer, default: 0
+ monthly_overage_limit Integer, default: 0
+ pending Bool(), default: false
+ parent_customer_id Either(String, nil), default: nil
end
def self.default(customer_id, jid)
config = CONFIG[:parented_domains][Blather::JID.new(jid).domain]
if config
- self.for(
+ new(
customer_id,
plan_name: config[:plan_name],
parent_customer_id: config[:customer_id]
@@ 33,7 37,7 @@ class CustomerPlan
end
def self.extract(customer_id, **kwargs)
- self.for(
+ new(
customer_id,
**kwargs.slice(
:plan_name, :expires_at, :parent_customer_id, :pending,
@@ 42,46 46,32 @@ class CustomerPlan
)
end
- def initialize(
- customer_id,
- plan: nil,
- expires_at: Time.now,
- auto_top_up_amount: 0,
- monthly_overage_limit: 0,
- pending: false, parent_customer_id: nil
- )
- @customer_id = customer_id
- @plan = plan || OpenStruct.new
- @expires_at = expires_at
- @auto_top_up_amount = auto_top_up_amount || 0
- @monthly_overage_limit = monthly_overage_limit || 0
- @pending = pending
- @parent_customer_id = parent_customer_id
+ def self.coerce_plan(plan_or_name_or_nil)
+ return OpenStruct.new unless plan_or_name_or_nil
+
+ Plan.for(plan_or_name_or_nil)
+ end
+
+ def initialize(customer_id=nil, **kwargs)
+ kwargs[:plan] = kwargs.delete(:plan_name) if kwargs.key?(:plan_name)
+ super(customer_id ? kwargs.merge(customer_id: customer_id) : kwargs)
end
def active?
- plan_name && @expires_at > Time.now
+ plan_name && expires_at > Time.now
end
def status
return :active if active?
- return :pending if @pending
+ return :pending if pending
:expired
end
- def with_plan_name(plan_name, **kwargs)
- self.class.new(
- @customer_id,
- plan: Plan.for(plan_name),
- expires_at: @expires_at, **kwargs
- )
- end
-
def verify_parent!
- return unless @parent_customer_id
+ return unless parent_customer_id
- result = DB.query(<<~SQL, [@parent_customer_id])
+ result = DB.query(<<~SQL, [parent_customer_id])
SELECT plan_name FROM customer_plans WHERE customer_id=$1
SQL
@@ 93,7 83,7 @@ class CustomerPlan
def save_plan!
verify_parent!
- DB.exec_defer(<<~SQL, [@customer_id, plan_name, @parent_customer_id])
+ DB.exec_defer(<<~SQL, [customer_id, plan_name, parent_customer_id])
INSERT INTO plan_log
(customer_id, plan_name, parent_customer_id, date_range)
VALUES (
@@ 122,7 112,7 @@ class CustomerPlan
def activate_plan_starting_now
verify_parent!
- activated = DB.exec(<<~SQL, [@customer_id, plan_name, @parent_customer_id])
+ activated = DB.exec(<<~SQL, [customer_id, plan_name, parent_customer_id])
INSERT INTO plan_log (customer_id, plan_name, date_range, parent_customer_id)
VALUES ($1, $2, tsrange(LOCALTIMESTAMP, LOCALTIMESTAMP + '1 month'), $3)
ON CONFLICT DO NOTHING
@@ 130,7 120,7 @@ class CustomerPlan
activated = activated.cmd_tuples.positive?
return false unless activated
- DB.exec(<<~SQL, [@customer_id])
+ DB.exec(<<~SQL, [customer_id])
DELETE FROM plan_log WHERE customer_id=$1 AND date_range << '[now,now]'
AND upper(date_range) - lower(date_range) < '2 seconds'
SQL
@@ 141,22 131,24 @@ class CustomerPlan
end
def activation_date
- DB.query_one(<<~SQL, @customer_id).then { |r| r[:start_date] }
+ DB.query_one(<<~SQL, customer_id).then { |r| r[:start_date] }
SELECT
MIN(LOWER(date_range)) AS start_date
FROM plan_log WHERE customer_id = $1;
SQL
end
+ protected :customer_id, :plan, :pending, :[]
+
protected
def charge_for_plan(note)
- raise "No plan setup" unless @plan
+ raise "No plan setup" unless plan
params = [
- @customer_id,
- "#{@customer_id}-bill-#{plan_name}-at-#{Time.now.to_i}",
- -@plan.monthly_price,
+ customer_id,
+ "#{customer_id}-bill-#{plan_name}-at-#{Time.now.to_i}",
+ -plan.monthly_price,
note
]
DB.exec(<<~SQL, params)
@@ 167,7 159,7 @@ protected
end
def add_one_month_to_current_plan
- DB.exec(<<~SQL, [@customer_id])
+ DB.exec(<<~SQL, [customer_id])
UPDATE plan_log SET date_range=range_merge(
date_range,
tsrange(