From 917096eb4400f3e6247d719f6bd75759ef93be78 Mon Sep 17 00:00:00 2001 From: Stephen Paul Weber Date: Mon, 16 May 2022 14:21:14 -0500 Subject: [PATCH] Only allow one credit card transaction per customer per day --- lib/transaction.rb | 4 +++- test/test_transaction.rb | 13 +++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/transaction.rb b/lib/transaction.rb index 83e8e158ce158eaa3ccae3fb1dddf0a6de113290..58bfa3fa73aaa04a745b7fb76cc8cb9eb46ede84 100644 --- a/lib/transaction.rb +++ b/lib/transaction.rb @@ -18,9 +18,11 @@ class Transaction def self.resolve_payment_method(customer, payment_method) EMPromise.all([ + ExpiringLock.new("jmp_customer_credit_card_lock-#{customer.customer_id}") + .with(els: -> { raise "Too many transactions today" }) { nil }, customer.declines, payment_method || customer.payment_methods.then(&:default_payment_method) - ]).then do |(declines, selected_method)| + ]).then do |(_, declines, selected_method)| raise "Declined" if declines >= 2 raise "No valid payment method on file" unless selected_method diff --git a/test/test_transaction.rb b/test/test_transaction.rb index 5bb348dd711ad245fa489364f3e3caad42535ab9..4b18f928c731a6d13eaee51803273fdd33b189ae 100644 --- a/test/test_transaction.rb +++ b/test/test_transaction.rb @@ -7,6 +7,7 @@ require "transaction" Transaction::DB = Minitest::Mock.new Transaction::BRAINTREE = Minitest::Mock.new Transaction::REDIS = Minitest::Mock.new +ExpiringLock::REDIS = Minitest::Mock.new class TransactionTest < Minitest::Test FAKE_BRAINTREE_TRANSACTION = @@ -18,6 +19,11 @@ class TransactionTest < Minitest::Test ) def test_sale_fails + ExpiringLock::REDIS.expect( + :set, + EMPromise.resolve("OK"), + ["jmp_customer_credit_card_lock-test", Time, "EX", 86400, "NX"] + ) CustomerFinancials::REDIS.expect( :get, EMPromise.resolve("1"), @@ -50,10 +56,16 @@ class TransactionTest < Minitest::Test ).sync end assert_mock CustomerFinancials::REDIS + assert_mock ExpiringLock::REDIS end em :test_sale_fails def test_sale + ExpiringLock::REDIS.expect( + :set, + EMPromise.resolve("OK"), + ["jmp_customer_credit_card_lock-test", Time, "EX", 86400, "NX"] + ) CustomerFinancials::REDIS.expect( :get, EMPromise.resolve("1"), @@ -83,6 +95,7 @@ class TransactionTest < Minitest::Test ).sync assert_kind_of Transaction, result assert_mock CustomerFinancials::REDIS + assert_mock ExpiringLock::REDIS end em :test_sale