M lib/customer_finacials.rb => lib/customer_finacials.rb +11 -2
@@ 11,8 11,11 @@ class CustomerFinancials
.customer
.find(@customer_id)
.catch { OpenStruct.new(payment_methods: []) },
- REDIS.smembers("block_credit_cards")
- ]).then { |(braintree, badcards)| PaymentMethods.for(braintree, badcards) }
+ REDIS.smembers("block_credit_cards"),
+ three_d_secure
+ ]).then do |(braintree, badcards, three_d)|
+ PaymentMethods.for(braintree, badcards, three_d)
+ end
end
def btc_addresses
@@ 42,6 45,12 @@ class CustomerFinancials
end
end
+ def three_d_secure
+ REDIS.hgetall(
+ "jmp_customer_three_d_secure_authentication_id-#{@customer_id}"
+ ).then { |all| Hash[*all] }
+ end
+
class TransactionInfo
value_semantics do
transaction_id String
A lib/payment_method.rb => lib/payment_method.rb +29 -0
@@ 0,0 1,29 @@
+# frozen_string_literal: true
+
+require "delegate"
+
+class PaymentMethod < SimpleDelegator
+ def self.for(method, three_d_secure={})
+ three_d = three_d_secure[method.token]
+ return ThreeDSecure.new(method, three_d) if three_d
+
+ new(method)
+ end
+
+ def transaction_details
+ {
+ payment_method_token: token
+ }
+ end
+
+ class ThreeDSecure < PaymentMethod
+ def initialize(method, three_d)
+ super(method)
+ @three_d = three_d
+ end
+
+ def transaction_details
+ super.merge(three_d_secure_authentication_id: @three_d)
+ end
+ end
+end
M lib/payment_methods.rb => lib/payment_methods.rb +4 -2
@@ 1,14 1,16 @@
# frozen_string_literal: true
+require_relative "payment_method"
+
class PaymentMethods
- def self.for(braintree_customer, badcards)
+ def self.for(braintree_customer, badcards, three_d_secure)
methods = braintree_customer.payment_methods.reject { |m|
badcards.include?(m.unique_number_identifier)
}
if methods.empty?
Empty.new
else
- new(methods)
+ new(methods.map { |m| PaymentMethod.for(m, three_d_secure) })
end
end
M lib/transaction.rb => lib/transaction.rb +3 -4
@@ 5,12 5,11 @@ require "bigdecimal"
class Transaction
def self.sale(customer, amount:, payment_method: nil)
resolve_payment_method(customer, payment_method).then do |selected_method|
- BRAINTREE.transaction.sale(
+ BRAINTREE.transaction.sale(selected_method.transaction_details.merge(
amount: amount,
merchant_account_id: customer.merchant_account,
- options: { submit_for_settlement: true },
- payment_method_token: selected_method.token
- ).then do |response|
+ options: { submit_for_settlement: true }
+ )).then do |response|
new(decline_guard(customer, response))
end
end
M test/test_buy_account_credit_form.rb => test/test_buy_account_credit_form.rb +3 -0
@@ 20,6 20,9 @@ class BuyAccountCreditFormTest < Minitest::Test
braintree_customer = Minitest::Mock.new
CustomerFinancials::BRAINTREE.expect(:customer, braintree_customer)
CustomerFinancials::REDIS.expect(:smembers, [], ["block_credit_cards"])
+ CustomerFinancials::REDIS.expect(
+ :hgetall, [], ["jmp_customer_three_d_secure_authentication_id-test"]
+ )
braintree_customer.expect(
:find,
EMPromise.resolve(OpenStruct.new(payment_methods: [])),
M test/test_payment_methods.rb => test/test_payment_methods.rb +25 -4
@@ 7,12 7,16 @@ class PaymentMethodsTest < Minitest::Test
def test_for
braintree_customer = Minitest::Mock.new
braintree_customer.expect(:payment_methods, [
- OpenStruct.new(card_type: "Test", last_4: "1234")
+ OpenStruct.new(card_type: "Test", last_4: "1234", token: "wut")
])
- methods = PaymentMethods.for(braintree_customer, [])
+ methods = PaymentMethods.for(braintree_customer, [], {})
assert_kind_of PaymentMethods, methods
assert_equal 1, methods.to_a.length
refute methods.empty?
+ assert_equal(
+ { payment_method_token: "wut" },
+ methods.fetch(0).transaction_details
+ )
end
def test_for_badcards
@@ 24,16 28,33 @@ class PaymentMethodsTest < Minitest::Test
unique_number_identifier: "wut"
)
])
- methods = PaymentMethods.for(braintree_customer, ["wut"])
+ methods = PaymentMethods.for(braintree_customer, ["wut"], {})
assert_kind_of PaymentMethods, methods
assert_equal 0, methods.to_a.length
assert methods.empty?
end
+ def test_for_three_d_secure
+ braintree_customer = Minitest::Mock.new
+ braintree_customer.expect(:payment_methods, [
+ OpenStruct.new(
+ card_type: "Test",
+ last_4: "1234",
+ token: "wut"
+ )
+ ])
+ methods = PaymentMethods.for(braintree_customer, [], { "wut" => "hai" })
+ assert_kind_of PaymentMethods, methods
+ assert_equal(
+ { payment_method_token: "wut", three_d_secure_authentication_id: "hai" },
+ methods.fetch(0).transaction_details
+ )
+ end
+
def test_for_no_methods
braintree_customer = Minitest::Mock.new
braintree_customer.expect(:payment_methods, [])
- methods = PaymentMethods.for(braintree_customer, [])
+ methods = PaymentMethods.for(braintree_customer, [], {})
assert_kind_of PaymentMethods, methods
assert_raises do
methods.to_list_single
M test/test_registration.rb => test/test_registration.rb +3 -0
@@ 267,6 267,9 @@ class RegistrationTest < Minitest::Test
braintree_customer
)
CustomerFinancials::REDIS.expect(:smembers, [], ["block_credit_cards"])
+ CustomerFinancials::REDIS.expect(
+ :hgetall, [], ["jmp_customer_three_d_secure_authentication_id-test"]
+ )
braintree_customer.expect(
:find,
EMPromise.resolve(OpenStruct.new(payment_methods: [])),
M test/test_transaction.rb => test/test_transaction.rb +3 -2
@@ 3,6 3,7 @@
require "test_helper"
require "customer"
require "transaction"
+require "payment_method"
Transaction::DB = Minitest::Mock.new
Transaction::BRAINTREE = Minitest::Mock.new
@@ 46,7 47,7 @@ class TransactionTest < Minitest::Test
Transaction.sale(
customer(plan_name: "test_usd"),
amount: 123,
- payment_method: OpenStruct.new(token: "token")
+ payment_method: PaymentMethod.for(OpenStruct.new(token: "token"))
).sync
end
assert_mock CustomerFinancials::REDIS
@@ 79,7 80,7 @@ class TransactionTest < Minitest::Test
result = Transaction.sale(
customer(plan_name: "test_usd"),
amount: 123,
- payment_method: OpenStruct.new(token: "token")
+ payment_method: PaymentMethod.for(OpenStruct.new(token: "token"))
).sync
assert_kind_of Transaction, result
assert_mock CustomerFinancials::REDIS