@@ 18,10 18,12 @@ class Transaction
def self.resolve_payment_method(customer, payment_method)
EMPromise.all([
+ REDIS.exists("jmp_customer_credit_card_lock-#{customer.customer_id}"),
customer.declines,
payment_method || customer.payment_methods.then(&:default_payment_method)
- ]).then do |(declines, selected_method)|
+ ]).then do |(lock, declines, selected_method)|
raise "Declined" if declines >= 2
+ raise "Too many payments recently" if lock == 1
raise "No valid payment method on file" unless selected_method
selected_method
@@ 29,7 31,14 @@ class Transaction
end
def self.decline_guard(customer, response)
- return response.transaction if response.success?
+ if response.success?
+ REDIS.setex(
+ "jmp_customer_credit_card_lock-#{customer.customer_id}",
+ 60 * 60 * 24,
+ "1"
+ )
+ return response.transaction
+ end
customer.mark_decline
raise response.message
@@ 18,6 18,11 @@ class TransactionTest < Minitest::Test
)
def test_sale_fails
+ Transaction::REDIS.expect(
+ :exists,
+ EMPromise.resolve(0),
+ ["jmp_customer_credit_card_lock-test"]
+ )
CustomerFinancials::REDIS.expect(
:get,
EMPromise.resolve("1"),
@@ 50,10 55,39 @@ class TransactionTest < Minitest::Test
).sync
end
assert_mock CustomerFinancials::REDIS
+ assert_mock Transaction::REDIS
end
em :test_sale_fails
+ def test_sale_locked
+ Transaction::REDIS.expect(
+ :exists,
+ EMPromise.resolve(1),
+ ["jmp_customer_credit_card_lock-test"]
+ )
+ CustomerFinancials::REDIS.expect(
+ :get,
+ EMPromise.resolve("0"),
+ ["jmp_pay_decline-test"]
+ )
+ assert_raises("locked") do
+ Transaction.sale(
+ customer(plan_name: "test_usd"),
+ amount: 123,
+ payment_method: OpenStruct.new(token: "token")
+ ).sync
+ end
+ assert_mock CustomerFinancials::REDIS
+ assert_mock Transaction::REDIS
+ end
+ em :test_sale_locked
+
def test_sale
+ Transaction::REDIS.expect(
+ :exists,
+ EMPromise.resolve(0),
+ ["jmp_customer_credit_card_lock-test"]
+ )
CustomerFinancials::REDIS.expect(
:get,
EMPromise.resolve("1"),
@@ 76,6 110,11 @@ class TransactionTest < Minitest::Test
options: { submit_for_settlement: true }
}]
)
+ Transaction::REDIS.expect(
+ :setex,
+ EMPromise.resolve(1),
+ ["jmp_customer_credit_card_lock-test", 86400, "1"]
+ )
result = Transaction.sale(
customer(plan_name: "test_usd"),
amount: 123,
@@ 83,6 122,7 @@ class TransactionTest < Minitest::Test
).sync
assert_kind_of Transaction, result
assert_mock CustomerFinancials::REDIS
+ assert_mock Transaction::REDIS
end
em :test_sale