Merge branch 'limit-top-up-take-2'

Stephen Paul Weber created

* limit-top-up-take-2:
  Only one credit card transaction per customer per day

Change summary

lib/transaction.rb       | 13 +++++++++++--
test/test_transaction.rb | 40 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 51 insertions(+), 2 deletions(-)

Detailed changes

lib/transaction.rb 🔗

@@ -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

test/test_transaction.rb 🔗

@@ -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