Notify customer on sucessful BTC deposit

Stephen Paul Weber created

Since BTC transactions can take some time, let the user know when it is done and
how much credit they got for their money.

Change summary

bin/process_pending_btc_transactions | 62 +++++++++++++++++++++++++----
1 file changed, 53 insertions(+), 9 deletions(-)

Detailed changes

bin/process_pending_btc_transactions 🔗

@@ -4,6 +4,11 @@
 # Usage: bin/process_pending-btc_transactions '{
 #        oxr_app_id = "",
 #        required_confirmations = 3,
+#        notify_using = {
+#          jid = "",
+#          password = "",
+#          target = \(tel: Text) -> "${tel}@cheogram.com"
+#        },
 #        electrum = env:ELECTRUM_CONFIG,
 #        plans = ./plans.dhall
 #        }'
@@ -16,11 +21,12 @@ require "nokogiri"
 require "pg"
 require "redis"
 
+require_relative "../lib/blather_notify"
 require_relative "../lib/electrum"
 
 CONFIG =
 	Dhall::Coder
-	.new(safe: Dhall::Coder::JSON_LIKE + [Symbol])
+	.new(safe: Dhall::Coder::JSON_LIKE + [Symbol, Proc])
 	.load(ARGV[0], transform_keys: :to_sym)
 
 REDIS = Redis.new
@@ -30,6 +36,11 @@ DB = PG.connect(dbname: "jmp")
 DB.type_map_for_results = PG::BasicTypeMapForResults.new(DB)
 DB.type_map_for_queries = PG::BasicTypeMapForQueries.new(DB)
 
+BlatherNotify.start(
+	CONFIG[:notify_using][:jid],
+	CONFIG[:notify_using][:password]
+)
+
 unless (cad_to_usd = REDIS.get("cad_to_usd")&.to_f)
 	oxr = Money::Bank::OpenExchangeRatesBank.new(Money::RatesStore::Memory.new)
 	oxr.app_id = CONFIG.fetch(:oxr_app_id)
@@ -70,6 +81,44 @@ class Plan
 	end
 end
 
+class Customer
+	def initialize(customer_id)
+		@customer_id = customer_id
+	end
+
+	def notify(body)
+		jid = REDIS.get("jmp_customer_jid-#{@customer_id}")
+		tel = REDIS.lindex("catapult_cred-#{jid}", 3)
+		BlatherNotify.say(
+			CONFIG[:notify_using][:target].call(tel.to_s),
+			body
+		)
+	end
+
+	def plan
+		Plan.for_customer(@customer_id)
+	end
+
+	def add_btc_credit(txid, fiat_amount)
+		DB.exec_params(<<-SQL, [@customer_id, txid, fiat_amount])
+			INSERT INTO transactions
+				(customer_id, transaction_id, amount, note)
+			VALUES
+					($1, $2, $3, 'Bitcoin payment')
+			ON CONFLICT (transaction_id) DO NOTHING
+		SQL
+		notify_btc_credit(txid, fiat_amount)
+	end
+
+	def notify_btc_credit(txid, fiat_amount)
+		tx_hash, = txid.split("/", 2)
+		notify(
+			"Your Bitcoin transaction has been added as $#{'%.4f' % fiat_amount} " \
+			"to your account.\n(txhash: #{tx_hash})"
+		)
+	end
+end
+
 REDIS.hgetall("pending_btc_transactions").each do |(txid, customer_id)|
 	tx_hash, address = txid.split("/", 2)
 	transaction = ELECTRUM.gettransaction(tx_hash)
@@ -80,16 +129,11 @@ REDIS.hgetall("pending_btc_transactions").each do |(txid, customer_id)|
 		next
 	end
 	DB.transaction do
-		plan = Plan.for_customer(customer_id)
+		customer = Customer.new(customer_id)
+		plan = customer.plan
 		if plan
 			amount = btc * btc_sell_price.fetch(plan.currency).round(4, :floor)
-			DB.exec_params(<<-SQL, [customer_id, txid, amount])
-				INSERT INTO transactions
-					(customer_id, transaction_id, amount, note)
-				VALUES
-						($1, $2, $3, 'Bitcoin payment')
-				ON CONFLICT (transaction_id) DO NOTHING
-			SQL
+			customer.add_btc_credit(txid, amount)
 		else
 			warn "No plan for #{customer_id} cannot save #{txid}"
 		end