From 3a71f5f536c020915f10b5faf82504965674b4c8 Mon Sep 17 00:00:00 2001 From: Stephen Paul Weber Date: Mon, 23 May 2022 09:15:30 -0500 Subject: [PATCH] Limit size of credit card transaction by trust level --- lib/transaction.rb | 14 +++++++------ lib/trust_level.rb | 16 +++++++++++++++ test/test_transaction.rb | 44 +++++++++++++++++++++++++++++++++++++--- 3 files changed, 65 insertions(+), 9 deletions(-) diff --git a/lib/transaction.rb b/lib/transaction.rb index ff8ce7b..2c56271 100644 --- a/lib/transaction.rb +++ b/lib/transaction.rb @@ -2,27 +2,29 @@ require "bigdecimal" +require_relative "trust_level_repo" + class Transaction def self.sale(customer, amount:, payment_method: nil) - resolve_payment_method(customer, payment_method).then do |selected_method| + resolve_payment_method(customer, payment_method, amount).then do |selected| BRAINTREE.transaction.sale( amount: amount, merchant_account_id: customer.merchant_account, options: { submit_for_settlement: true }, - payment_method_token: selected_method.token + payment_method_token: selected.token ).then do |response| new(decline_guard(customer, response)) end end end - def self.resolve_payment_method(customer, payment_method) + def self.resolve_payment_method(customer, payment_method, amount) EMPromise.all([ REDIS.exists("jmp_customer_credit_card_lock-#{customer.customer_id}"), - customer.declines, + TrustLevelRepo.new.find(customer), customer.declines, payment_method || customer.payment_methods.then(&:default_payment_method) - ]).then do |(lock, declines, selected_method)| - raise "Declined" if declines >= 2 + ]).then do |(lock, tl, declines, selected_method)| + raise "Declined" unless tl.credit_card_transaction?(amount, declines) raise "Too many payments recently" if lock == 1 raise "No valid payment method on file" unless selected_method diff --git a/lib/trust_level.rb b/lib/trust_level.rb index 8719521..b37e2b0 100644 --- a/lib/trust_level.rb +++ b/lib/trust_level.rb @@ -40,6 +40,10 @@ module TrustLevel false end + def credit_card_transaction?(*) + false + end + def to_s "Tomb" end @@ -58,6 +62,10 @@ module TrustLevel messages_today < 200 end + def credit_card_transaction?(amount, declines) + amount <= 35 && declines <= 2 + end + def to_s "Basement" end @@ -76,6 +84,10 @@ module TrustLevel messages_today < 700 end + def credit_card_transaction?(amount, declines) + amount <= 500 && declines <= 3 + end + def to_s "Paragon" end @@ -107,6 +119,10 @@ module TrustLevel messages_today < 500 end + def credit_card_transaction?(amount, declines) + amount <= 100 && declines <= 2 + end + def to_s "Customer" end diff --git a/test/test_transaction.rb b/test/test_transaction.rb index e6a02c6..f2b2725 100644 --- a/test/test_transaction.rb +++ b/test/test_transaction.rb @@ -7,6 +7,8 @@ require "transaction" Transaction::DB = Minitest::Mock.new Transaction::BRAINTREE = Minitest::Mock.new Transaction::REDIS = Minitest::Mock.new +TrustLevelRepo::REDIS = Minitest::Mock.new +TrustLevelRepo::DB = Minitest::Mock.new class TransactionTest < Minitest::Test FAKE_BRAINTREE_TRANSACTION = @@ -23,6 +25,16 @@ class TransactionTest < Minitest::Test EMPromise.resolve(0), ["jmp_customer_credit_card_lock-test"] ) + TrustLevelRepo::REDIS.expect( + :get, + EMPromise.resolve("Customer"), + ["jmp_customer_trust_level-test"] + ) + TrustLevelRepo::DB.expect( + :query_one, + EMPromise.resolve({}), + [String, "test", Hash] + ) CustomerFinancials::REDIS.expect( :get, EMPromise.resolve("1"), @@ -50,12 +62,14 @@ class TransactionTest < Minitest::Test assert_raises("declined") do Transaction.sale( customer(plan_name: "test_usd"), - amount: 123, + amount: 99, payment_method: OpenStruct.new(token: "token") ).sync end assert_mock CustomerFinancials::REDIS assert_mock Transaction::REDIS + assert_mock TrustLevelRepo::REDIS + assert_mock TrustLevelRepo::DB end em :test_sale_fails @@ -65,6 +79,16 @@ class TransactionTest < Minitest::Test EMPromise.resolve(1), ["jmp_customer_credit_card_lock-test"] ) + TrustLevelRepo::REDIS.expect( + :get, + EMPromise.resolve("Customer"), + ["jmp_customer_trust_level-test"] + ) + TrustLevelRepo::DB.expect( + :query_one, + EMPromise.resolve({}), + [String, "test", Hash] + ) CustomerFinancials::REDIS.expect( :get, EMPromise.resolve("0"), @@ -79,6 +103,8 @@ class TransactionTest < Minitest::Test end assert_mock CustomerFinancials::REDIS assert_mock Transaction::REDIS + assert_mock TrustLevelRepo::REDIS + assert_mock TrustLevelRepo::DB end em :test_sale_locked @@ -88,6 +114,16 @@ class TransactionTest < Minitest::Test EMPromise.resolve(0), ["jmp_customer_credit_card_lock-test"] ) + TrustLevelRepo::REDIS.expect( + :get, + EMPromise.resolve("Customer"), + ["jmp_customer_trust_level-test"] + ) + TrustLevelRepo::DB.expect( + :query_one, + EMPromise.resolve({}), + [String, "test", Hash] + ) CustomerFinancials::REDIS.expect( :get, EMPromise.resolve("1"), @@ -104,7 +140,7 @@ class TransactionTest < Minitest::Test ) ), [{ - amount: 123, + amount: 99, payment_method_token: "token", merchant_account_id: "merchant_usd", options: { submit_for_settlement: true } @@ -117,12 +153,14 @@ class TransactionTest < Minitest::Test ) result = Transaction.sale( customer(plan_name: "test_usd"), - amount: 123, + amount: 99, payment_method: OpenStruct.new(token: "token") ).sync assert_kind_of Transaction, result assert_mock CustomerFinancials::REDIS assert_mock Transaction::REDIS + assert_mock TrustLevelRepo::REDIS + assert_mock TrustLevelRepo::DB end em :test_sale -- 2.45.2