diff --git a/bin/process_pending_btc_transactions b/bin/process_pending_btc_transactions index 99cf838a88cf7b2d855253412e45c08c21e2fda4..1fc8cbe4a5d3cb32ac0673be7dc96bda61430ee2 100755 --- a/bin/process_pending_btc_transactions +++ b/bin/process_pending_btc_transactions @@ -10,7 +10,8 @@ # target = \(tel: Text) -> "${tel}@cheogram.com" # }, # electrum = env:ELECTRUM_CONFIG, -# plans = ./plans.dhall +# plans = ./plans.dhall, +# activation_amount = 10000 # }' require "bigdecimal" @@ -63,19 +64,36 @@ btc_sell_price[:CAD] = BigDecimal.new( btc_sell_price[:USD] = btc_sell_price[:CAD] * cad_to_usd class Plan - def self.for_customer(customer_id) - row = DB.exec_params(<<-SQL, [customer_id]).first + def self.for_customer(customer) + row = DB.exec_params(<<-SQL, [customer.id]).first SELECT plan_name FROM customer_plans WHERE customer_id=$1 LIMIT 1 SQL - return unless row - plan = CONFIG[:plans].find { |p| p["plan_name"] = row["plan_name"] } - new(plan) if plan + from_name(customer, row&.[]("plan_name")) end - def initialize(plan) + def self.pending_for_customer(customer) + from_name( + customer, + REDIS.get("pending_plan_for-#{customer.id}"), + klass: Pending + ) + end + + def self.from_name(customer, plan_name, klass: Plan) + return unless plan_name + plan = CONFIG[:plans].find { |p| p[:name] == plan_name } + klass.new(customer, plan) if plan + end + + def initialize(customer, plan) + @customer = customer @plan = plan end + def name + @plan[:name] + end + def currency @plan[:currency] end @@ -84,6 +102,60 @@ class Plan bonus = (0.050167 * fiat_amount) - (currency == :CAD ? 1 : cad_to_usd) return bonus.round(4, :floor) if bonus > 0 end + + def price + BigDecimal.new(@plan[:monthly_price].to_i) * 0.0001 + end + + def insert(start:, expire:) + params = [@customer.id, name, start, expire] + DB.exec_params(<<-SQL, params) + INSERT INTO plan_log + (customer_id, plan_name, starts_at, expires_at) + VALUES + ($1, $2, $3, $4) + SQL + end + + def activate_any_pending_plan!; end + + class Pending < Plan + def initialize(customer, plan) + super + @go_until = Date.today >> 1 + end + + def activation_amount + camnt = BigDecimal.new(CONFIG[:activation_amount].to_i) * 0.0001 + [camnt, price].max + end + + def activate_any_pending_plan! + if @customer.balance < activation_amount + @customer.notify( + "Your account could not be activated because your " \ + "balance of $#{@customer.balance} is less that the " \ + "required activation amount of $#{activation_amount}. " \ + "Please buy more credit to have your account activated." + ) + else + charge_insert_notify + end + end + + protected + + def charge_insert_notify + @customer.add_transaction( + "activate_#{name}_until_#{@go_until}", + -price, + "Activate pending plan" + ) + insert(start: Date.today, expire: @go_until) + REDIS.del("pending_plan_for-#{@customer.id}") + # TODO: @customer.notify("Your account has been activated") + end + end end class Customer @@ -91,6 +163,10 @@ class Customer @customer_id = customer_id end + def id + @customer_id + end + def notify(body) jid = REDIS.get("jmp_customer_jid-#{@customer_id}") tel = REDIS.lindex("catapult_cred-#{jid}", 3) @@ -101,7 +177,18 @@ class Customer end def plan - Plan.for_customer(@customer_id) + Plan.for_customer(self) || pending_plan + end + + def pending_plan + Plan.pending_for_customer(self) + end + + def balance + result = DB.exec_params(<<-SQL, [@customer_id]).first&.[]("balance") + SELECT balance FROM balances WHERE customer_id=$1 + SQL + result || BigDecimal.new(0) end def add_btc_credit(txid, fiat_amount, cad_to_usd) @@ -122,8 +209,6 @@ class Customer ].compact.join) end -protected - def add_transaction(id, amount, note) DB.exec_params(<<-SQL, [@customer_id, id, amount, note]) INSERT INTO transactions @@ -146,13 +231,13 @@ REDIS.hgetall("pending_btc_transactions").each do |(txid, customer_id)| end DB.transaction do customer = Customer.new(customer_id) - plan = customer.plan - if plan + if (plan = customer.plan) amount = btc * btc_sell_price.fetch(plan.currency).round(4, :floor) customer.add_btc_credit(txid, amount, cad_to_usd) + customer.plan.activate_any_pending_plan! + REDIS.hdel("pending_btc_transactions", txid) else warn "No plan for #{customer_id} cannot save #{txid}" end end - REDIS.hdel("pending_btc_transactions", txid) end