diff --git a/lib/customer.rb b/lib/customer.rb index a295875811855cb47014614502405f4d23ff4041..5cf426a180217952b97f9c1fd8456c1cf9b1d9bb 100644 --- a/lib/customer.rb +++ b/lib/customer.rb @@ -4,10 +4,11 @@ require "forwardable" require_relative "./api" require_relative "./blather_ext" -require_relative "./customer_info" -require_relative "./customer_ogm" -require_relative "./customer_plan" require_relative "./customer_usage" +require_relative "./customer_plan" +require_relative "./customer_ogm" +require_relative "./customer_info" +require_relative "./customer_finacials" require_relative "./backend_sgx" require_relative "./ibr" require_relative "./payment_methods" @@ -27,6 +28,9 @@ class Customer def_delegators :@sgx, :register!, :registered?, :set_ogm_url, :fwd, :transcription_enabled def_delegators :@usage, :usage_report, :message_usage, :incr_message_usage + def_delegators :@financials, :payment_methods, :btc_addresses, + :add_btc_address, :declines, :mark_decline, + :transactions def initialize( customer_id, @@ -38,6 +42,7 @@ class Customer ) @plan = plan @usage = CustomerUsage.new(customer_id) + @financials = CustomerFinancials.new(customer_id) @customer_id = customer_id @jid = jid @balance = balance @@ -61,14 +66,6 @@ class Customer ) end - def payment_methods - BRAINTREE - .customer - .find(@customer_id) - .catch { OpenStruct.new(payment_methods: []) } - .then(PaymentMethods.method(:for_braintree_customer)) - end - def unused_invites promise = DB.query_defer(<<~SQL, [customer_id]) SELECT code FROM unused_invites WHERE creator_id=$1 @@ -105,23 +102,6 @@ class Customer sip_account.with_random_password.put end - def btc_addresses - REDIS.smembers("jmp_customer_btc_addresses-#{customer_id}") - end - - def add_btc_address - REDIS.spopsadd([ - "jmp_available_btc_addresses", - "jmp_customer_btc_addresses-#{customer_id}" - ]).then do |addr| - ELECTRUM.notify( - addr, - CONFIG[:electrum_notify_url].call(addr, customer_id) - ) - addr - end - end - def admin? CONFIG[:admins].include?(jid.to_s) end diff --git a/lib/customer_finacials.rb b/lib/customer_finacials.rb new file mode 100644 index 0000000000000000000000000000000000000000..a39dfa63ebaa958d5f4d51efb6a9f400e253236f --- /dev/null +++ b/lib/customer_finacials.rb @@ -0,0 +1,74 @@ +# frozen_string_literal: true + +class CustomerFinancials + def initialize(customer_id) + @customer_id = customer_id + end + + def payment_methods + BRAINTREE + .customer + .find(@customer_id) + .catch { OpenStruct.new(payment_methods: []) } + .then(PaymentMethods.method(:for_braintree_customer)) + end + + def btc_addresses + REDIS.smembers("jmp_customer_btc_addresses-#{@customer_id}") + end + + def add_btc_address + REDIS.spopsadd([ + "jmp_available_btc_addresses", + "jmp_customer_btc_addresses-#{@customer_id}" + ]).then do |addr| + ELECTRUM.notify( + addr, + CONFIG[:electrum_notify_url].call(addr, @customer_id) + ) + addr + end + end + + def declines + REDIS.get("jmp_pay_decline-#{@customer_id}") + end + + def mark_decline + REDIS.incr("jmp_pay_decline-#{@customer_id}").then do + REDIS.expire("jmp_pay_decline-#{@customer_id}", 60 * 60 * 24) + end + end + + class TransactionInfo + value_semantics do + transaction_id String + created_at Time + amount BigDecimal + note String + end + + def formatted_amount + "$%.4f" % amount + end + end + + TRANSACTIONS_SQL = <<~SQL + SELECT + transaction_id, + created_at, + amount, + note + FROM transactions WHERE customer_id = $1; + SQL + + def transactions + txns = DB.query_defer(TRANSACTIONS_SQL, [@customer_id]) + + txns.then do |rows| + rows.map { |row| + TransactionInfo.new(**row.transform_keys(&:to_sym)) + } + end + end +end diff --git a/lib/transaction.rb b/lib/transaction.rb index 5d55f8f5bed41c168815044e60bd66e93451d9c8..72b11324d3f4cc658f860e4a3a8988c5d4112ffc 100644 --- a/lib/transaction.rb +++ b/lib/transaction.rb @@ -4,7 +4,7 @@ require "bigdecimal" class Transaction def self.sale(customer, amount:, payment_method: nil) - REDIS.get("jmp_pay_decline-#{customer.customer_id}").then do |declines| + customer.declines.then do |declines| raise "too many declines" if declines.to_i >= 2 BRAINTREE.transaction.sale( @@ -20,9 +20,7 @@ class Transaction def self.decline_guard(customer, response) return if response.success? - REDIS.incr("jmp_pay_decline-#{customer.customer_id}").then do - REDIS.expire("jmp_pay_decline-#{customer.customer_id}", 60 * 60 * 24) - end + customer.mark_decline raise response.message end diff --git a/test/test_alt_top_up_form.rb b/test/test_alt_top_up_form.rb index 264c099e31ed8af8a2533cc29ac38f54b2d3603d..ab552d8559aa58f78dde9dde3a06690e17f22803 100644 --- a/test/test_alt_top_up_form.rb +++ b/test/test_alt_top_up_form.rb @@ -6,7 +6,7 @@ require "customer" class AltTopUpFormTest < Minitest::Test def test_for - Customer::REDIS.expect( + CustomerFinancials::REDIS.expect( :smembers, EMPromise.resolve([]), ["jmp_customer_btc_addresses-test"] @@ -19,7 +19,7 @@ class AltTopUpFormTest < Minitest::Test em :test_for def test_for_addresses - Customer::REDIS.expect( + CustomerFinancials::REDIS.expect( :smembers, EMPromise.resolve(["testaddr"]), ["jmp_customer_btc_addresses-test"] @@ -32,7 +32,7 @@ class AltTopUpFormTest < Minitest::Test em :test_for_addresses def test_for_cad - Customer::REDIS.expect( + CustomerFinancials::REDIS.expect( :smembers, EMPromise.resolve([]), ["jmp_customer_btc_addresses-test"] diff --git a/test/test_buy_account_credit_form.rb b/test/test_buy_account_credit_form.rb index 8268bddc140df60636ac642340406c752103beda..0c5300838e9824dfc179abddab33189ccd77cff3 100644 --- a/test/test_buy_account_credit_form.rb +++ b/test/test_buy_account_credit_form.rb @@ -17,7 +17,7 @@ class BuyAccountCreditFormTest < Minitest::Test def test_for braintree_customer = Minitest::Mock.new - Customer::BRAINTREE.expect(:customer, braintree_customer) + CustomerFinancials::BRAINTREE.expect(:customer, braintree_customer) braintree_customer.expect( :find, EMPromise.resolve(OpenStruct.new(payment_methods: [])), diff --git a/test/test_customer.rb b/test/test_customer.rb index 9a0836d929e44a6423c40368433c1b6e6809759f..360cf4876336e45130d676f7244c4fa993de70a5 100644 --- a/test/test_customer.rb +++ b/test/test_customer.rb @@ -5,13 +5,15 @@ require "customer" Customer::BLATHER = Minitest::Mock.new Customer::BRAINTREE = Minitest::Mock.new -Customer::ELECTRUM = Minitest::Mock.new Customer::REDIS = Minitest::Mock.new Customer::DB = Minitest::Mock.new Customer::IQ_MANAGER = Minitest::Mock.new CustomerPlan::DB = Minitest::Mock.new CustomerUsage::REDIS = Minitest::Mock.new CustomerUsage::DB = Minitest::Mock.new +CustomerFinancials::REDIS = Minitest::Mock.new +CustomerFinancials::ELECTRUM = Minitest::Mock.new +CustomerFinancials::BRAINTREE = Minitest::Mock.new class CustomerTest < Minitest::Test def test_bill_plan_activate @@ -191,7 +193,7 @@ class CustomerTest < Minitest::Test em :test_sip_account_error def test_btc_addresses - Customer::REDIS.expect( + CustomerFinancials::REDIS.expect( :smembers, EMPromise.resolve(["testaddr"]), ["jmp_customer_btc_addresses-test"] @@ -202,19 +204,19 @@ class CustomerTest < Minitest::Test em :test_btc_addresses def test_add_btc_address - Customer::REDIS.expect( + CustomerFinancials::REDIS.expect( :spopsadd, EMPromise.resolve("testaddr"), [["jmp_available_btc_addresses", "jmp_customer_btc_addresses-test"]] ) - Customer::ELECTRUM.expect( + CustomerFinancials::ELECTRUM.expect( :notify, EMPromise.resolve(nil), ["testaddr", "http://notify.example.com"] ) assert_equal "testaddr", customer.add_btc_address.sync - assert_mock Customer::REDIS - assert_mock Customer::ELECTRUM + assert_mock CustomerFinancials::REDIS + assert_mock CustomerFinancials::ELECTRUM end em :test_add_btc_address end diff --git a/test/test_low_balance.rb b/test/test_low_balance.rb index afa81d19b16eff60dcb856beccefb8a56bbfaacb..d639d44bb00709bbb849e86b7301db70f4732d33 100644 --- a/test/test_low_balance.rb +++ b/test/test_low_balance.rb @@ -5,7 +5,7 @@ require "low_balance" ExpiringLock::REDIS = Minitest::Mock.new CustomerPlan::REDIS = Minitest::Mock.new -Customer::REDIS = Minitest::Mock.new +CustomerFinancials::REDIS = Minitest::Mock.new class LowBalanceTest < Minitest::Test def test_for_locked @@ -24,7 +24,7 @@ class LowBalanceTest < Minitest::Test EMPromise.resolve(0), ["jmp_customer_low_balance-test"] ) - Customer::REDIS.expect( + CustomerFinancials::REDIS.expect( :smembers, EMPromise.resolve([]), ["jmp_customer_btc_addresses-test"] diff --git a/test/test_registration.rb b/test/test_registration.rb index 06ee38ab314259536b359c5414d857b4bc920186..00b75e51761fbad390c517783391c723f2df9f7f 100644 --- a/test/test_registration.rb +++ b/test/test_registration.rb @@ -254,7 +254,7 @@ class RegistrationTest < Minitest::Test end class PaymentTest < Minitest::Test - Customer::BRAINTREE = Minitest::Mock.new + CustomerFinancials::BRAINTREE = Minitest::Mock.new def test_for_bitcoin cust = Minitest::Mock.new(customer) @@ -273,7 +273,7 @@ class RegistrationTest < Minitest::Test def test_for_credit_card braintree_customer = Minitest::Mock.new - Customer::BRAINTREE.expect( + CustomerFinancials::BRAINTREE.expect( :customer, braintree_customer ) @@ -313,7 +313,7 @@ class RegistrationTest < Minitest::Test class BitcoinTest < Minitest::Test Registration::Payment::Bitcoin::BTC_SELL_PRICES = Minitest::Mock.new - Customer::REDIS = Minitest::Mock.new + CustomerFinancials::REDIS = Minitest::Mock.new def setup @customer = Minitest::Mock.new( @@ -330,7 +330,7 @@ class RegistrationTest < Minitest::Test end def test_write - Customer::REDIS.expect( + CustomerFinancials::REDIS.expect( :smembers, EMPromise.resolve([]), ["jmp_customer_btc_addresses-test"] diff --git a/test/test_transaction.rb b/test/test_transaction.rb index d87b7bd13e3785b5442f61271ab711d571b95777..69a4b0220f2573c34c157be566e88c9b3c7c7ccb 100644 --- a/test/test_transaction.rb +++ b/test/test_transaction.rb @@ -18,17 +18,17 @@ class TransactionTest < Minitest::Test ) def test_sale_fails - Transaction::REDIS.expect( + CustomerFinancials::REDIS.expect( :get, EMPromise.resolve("1"), ["jmp_pay_decline-test"] ) - Transaction::REDIS.expect( + CustomerFinancials::REDIS.expect( :incr, EMPromise.resolve(nil), ["jmp_pay_decline-test"] ) - Transaction::REDIS.expect( + CustomerFinancials::REDIS.expect( :expire, EMPromise.resolve(nil), ["jmp_pay_decline-test", 60 * 60 * 24] @@ -49,11 +49,12 @@ class TransactionTest < Minitest::Test payment_method: OpenStruct.new(token: "token") ).sync end + assert_mock CustomerFinancials::REDIS end em :test_sale_fails def test_sale - Transaction::REDIS.expect( + CustomerFinancials::REDIS.expect( :get, EMPromise.resolve("1"), ["jmp_pay_decline-test"] @@ -81,6 +82,7 @@ class TransactionTest < Minitest::Test payment_method: OpenStruct.new(token: "token") ).sync assert_kind_of Transaction, result + assert_mock CustomerFinancials::REDIS end em :test_sale