From bb9f4f1daf70f170db0d1420ceae49f5b7ebb4c1 Mon Sep 17 00:00:00 2001 From: Stephen Paul Weber Date: Mon, 25 Apr 2022 15:18:25 -0500 Subject: [PATCH] Send 3DS id when making a transaction --- lib/customer_finacials.rb | 13 +++++++++++-- lib/payment_method.rb | 29 ++++++++++++++++++++++++++++ lib/payment_methods.rb | 6 ++++-- lib/transaction.rb | 7 +++---- test/test_buy_account_credit_form.rb | 3 +++ test/test_payment_methods.rb | 29 ++++++++++++++++++++++++---- test/test_registration.rb | 3 +++ test/test_transaction.rb | 5 +++-- 8 files changed, 81 insertions(+), 14 deletions(-) create mode 100644 lib/payment_method.rb diff --git a/lib/customer_finacials.rb b/lib/customer_finacials.rb index 07c33ea..e2353be 100644 --- a/lib/customer_finacials.rb +++ b/lib/customer_finacials.rb @@ -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 diff --git a/lib/payment_method.rb b/lib/payment_method.rb new file mode 100644 index 0000000..fea2133 --- /dev/null +++ b/lib/payment_method.rb @@ -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 diff --git a/lib/payment_methods.rb b/lib/payment_methods.rb index 2bbf08a..8ea008f 100644 --- a/lib/payment_methods.rb +++ b/lib/payment_methods.rb @@ -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 diff --git a/lib/transaction.rb b/lib/transaction.rb index 83e8e15..9bf759e 100644 --- a/lib/transaction.rb +++ b/lib/transaction.rb @@ -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 diff --git a/test/test_buy_account_credit_form.rb b/test/test_buy_account_credit_form.rb index 4b052ef..fbcdd51 100644 --- a/test/test_buy_account_credit_form.rb +++ b/test/test_buy_account_credit_form.rb @@ -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: [])), diff --git a/test/test_payment_methods.rb b/test/test_payment_methods.rb index 0971e7b..f5d79e1 100644 --- a/test/test_payment_methods.rb +++ b/test/test_payment_methods.rb @@ -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 diff --git a/test/test_registration.rb b/test/test_registration.rb index fb68154..ff19b67 100644 --- a/test/test_registration.rb +++ b/test/test_registration.rb @@ -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: [])), diff --git a/test/test_transaction.rb b/test/test_transaction.rb index 5bb348d..6a0d10f 100644 --- a/test/test_transaction.rb +++ b/test/test_transaction.rb @@ -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 -- 2.34.5