From bb2a7b715e5a9bb79cc28a1fa82a73885030b088 Mon Sep 17 00:00:00 2001 From: KenderBolivarT Date: Wed, 18 Sep 2024 12:02:47 -0500 Subject: [PATCH] Worldpay: Support apple pay recurring COMP-73 Adds support for Apple Pay MIT recurring Test Summary Local: Unit: 125 tests, 702 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications 100% passed Remote: 111 tests, 479 assertions, 2 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications 98.1982% passed --- .../billing/gateways/worldpay.rb | 32 ++++++++++++++++--- test/remote/gateways/remote_worldpay_test.rb | 24 ++++++++++++++ test/unit/gateways/worldpay_test.rb | 17 ++++++++++ 3 files changed, 68 insertions(+), 5 deletions(-) diff --git a/lib/active_merchant/billing/gateways/worldpay.rb b/lib/active_merchant/billing/gateways/worldpay.rb index 48d938acd6b..9ab31cd6fd1 100644 --- a/lib/active_merchant/billing/gateways/worldpay.rb +++ b/lib/active_merchant/billing/gateways/worldpay.rb @@ -663,7 +663,7 @@ def add_network_tokenization_card(xml, payment_method, options) end name = card_holder_name(payment_method, options) xml.cardHolderName name if name.present? - xml.cryptogram payment_method.payment_cryptogram unless options[:wallet_type] == :google_pay + xml.cryptogram payment_method.payment_cryptogram if should_send_payment_cryptogram?(options, payment_method) eci = eci_value(payment_method, options) xml.eciIndicator eci if eci.present? end @@ -671,6 +671,16 @@ def add_network_tokenization_card(xml, payment_method, options) end end + def should_send_payment_cryptogram?(options, payment_method) + !( + wallet_type_google_pay?(options) || + ( + payment_method_apple_pay?(payment_method) && + options.dig(:stored_credential, :initiator) == 'merchant' + ) + ) + end + def add_card_or_token(xml, payment_method, options) xml.paymentDetails credit_fund_transfer_attribute(options) do if options[:payment_type] == :token @@ -1040,16 +1050,28 @@ def payment_details(payment_method, options = {}) when String token_type_and_details(payment_method) else - type = network_token?(payment_method) || options[:wallet_type] == :google_pay ? :network_token : :credit + type = network_token?(payment_method, options) ? :network_token : :credit { payment_type: type } end end - def network_token?(payment_method) - payment_method.respond_to?(:source) && + def network_token?(payment_method, options) + (payment_method.respond_to?(:source) && payment_method.respond_to?(:payment_cryptogram) && - payment_method.respond_to?(:eci) + payment_method.respond_to?(:eci)) || + wallet_type_google_pay?(options) || + payment_method_apple_pay?(payment_method) + end + + def payment_method_apple_pay?(payment_method) + return false unless payment_method.is_a?(NetworkTokenizationCreditCard) + + payment_method.source == :apple_pay + end + + def wallet_type_google_pay?(options) + options[:wallet_type] == :google_pay end def token_type_and_details(token) diff --git a/test/remote/gateways/remote_worldpay_test.rb b/test/remote/gateways/remote_worldpay_test.rb index f74e0372ea1..236de88d9fc 100644 --- a/test/remote/gateways/remote_worldpay_test.rb +++ b/test/remote/gateways/remote_worldpay_test.rb @@ -115,6 +115,7 @@ def setup sub_tax_id: '987-65-4321' } } + @apple_pay_network_token = network_tokenization_credit_card( '4895370015293175', month: 10, @@ -669,6 +670,29 @@ def test_successful_auth_and_capture_with_gateway_specific_recurring_stored_cred assert_success capture end + def test_successful_recurring_purchase_with_apple_pay_credentials + stored_credential_params = stored_credential(:initial, :recurring, :merchant) + assert auth = @gateway.authorize(@amount, @apple_pay_network_token, @options.merge({ stored_credential: stored_credential_params })) + assert_success auth + assert auth.authorization + assert auth.params['scheme_response'] + assert auth.params['transaction_identifier'] + + assert capture = @gateway.capture(@amount, auth.authorization, authorization_validated: true) + assert_success capture + + @options[:order_id] = generate_unique_id + @options[:stored_credential] = stored_credential(:used, :recurring, :merchant, network_transaction_id: auth.params['transaction_identifier']) + + assert next_auth = @gateway.authorize(@amount, @apple_pay_network_token, @options) + assert next_auth.authorization + assert next_auth.params['scheme_response'] + assert next_auth.params['transaction_identifier'] + + assert capture = @gateway.capture(@amount, next_auth.authorization, authorization_validated: true) + assert_success capture + end + def test_successful_authorize_with_3ds_with_normalized_stored_credentials session_id = generate_unique_id stored_credential_params = stored_credential(:initial, :unscheduled, :merchant) diff --git a/test/unit/gateways/worldpay_test.rb b/test/unit/gateways/worldpay_test.rb index ae60b8d8d68..fc0aa31195f 100644 --- a/test/unit/gateways/worldpay_test.rb +++ b/test/unit/gateways/worldpay_test.rb @@ -1588,6 +1588,23 @@ def test_authorize_prefers_options_for_ntid assert_success response end + def test_authorize_recurring_apple_pay_with_ntid + stored_credential_params = stored_credential(:used, :recurring, :merchant, network_transaction_id: '3812908490218390214124') + + @options.merge({ + stored_credential: stored_credential_params, + stored_credential_transaction_id: '000000000000020005060720116005060', + wallet_type: :apple_pay + }) + response = stub_comms do + @gateway.authorize(@amount, @apple_play_network_token, @options) + end.check_request do |_endpoint, data, _headers| + assert_match %r(), data + refute_match %r(), data + end.respond_with(successful_authorize_response) + assert_success response + end + def test_successful_inquire_with_order_id response = stub_comms do @gateway.inquire(nil, { order_id: @options[:order_id].to_s })