Skip to content

Commit

Permalink
Worldpay: Support apple pay recurring
Browse files Browse the repository at this point in the history
COMP-73

Adds support for Apple Pay MIT recurring

Test Summary
Local:

Unit:

Remote:
  • Loading branch information
KenderBolivarT committed Sep 18, 2024
1 parent 8e14454 commit d0d3311
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 8 deletions.
24 changes: 19 additions & 5 deletions lib/active_merchant/billing/gateways/worldpay.rb
Original file line number Diff line number Diff line change
Expand Up @@ -663,14 +663,18 @@ 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)
eci = eci_value(payment_method, options)
xml.eciIndicator eci if eci.present?
end
add_stored_credential_options(xml, options)
end
end

def should_send_payment_cryptogram?(options)
!(wallet_type_google_pay?(options) || (wallet_type_apple_pay?(options) && options[: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
Expand Down Expand Up @@ -1040,16 +1044,26 @@ 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) ||
wallet_type_apple_pay?(options)
end

def wallet_type_apple_pay?(options)
options[:wallet_type] == :apple_pay
end

def wallet_type_google_pay?(options)
options[:wallet_type] == :google_pay
end

def token_type_and_details(token)
Expand Down
37 changes: 34 additions & 3 deletions test/remote/gateways/remote_worldpay_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -115,17 +115,25 @@ def setup
sub_tax_id: '987-65-4321'
}
}
@apple_pay_network_token = network_tokenization_credit_card(
'4895370015293175',
@apple_pay_shared_network_token_options = {
month: 10,
year: Time.new.year + 2,
first_name: 'John',
last_name: 'Smith',
verification_value: '737',
payment_cryptogram: 'abc1234567890',
eci: '07',
transaction_id: 'abc123',
source: :apple_pay
}

@apple_pay_network_token = network_tokenization_credit_card(
'4895370015293175',
@apple_pay_shared_network_token_options.merge(payment_cryptogram: 'abc1234567890')
)

@apple_pay_network_token_without_payment_cryptogram = network_tokenization_credit_card(
'4895370015293175',
@apple_pay_shared_network_token_options
)

@google_pay_network_token = network_tokenization_credit_card(
Expand Down Expand Up @@ -669,6 +677,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, wallet_type: :apple_pay }))
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_without_payment_cryptogram, @options.merge(wallet_type: :apple_pay))
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)
Expand Down
28 changes: 28 additions & 0 deletions test/unit/gateways/worldpay_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,18 @@ def setup
eci: '05'
)

@apple_pay_network_token_without_payment_cryptogram = network_tokenization_credit_card(
'4895370015293175',
month: 10,
year: Time.new.year + 2,
first_name: 'John',
last_name: 'Smith',
verification_value: '737',
eci: '07',
transaction_id: 'abc123',
source: :apple_pay
)

@google_pay_network_token_without_eci = network_tokenization_credit_card(
'4444333322221111',
payment_cryptogram: 'EHuWW9PiBkWvqE5juRwDzAUFBAk=',
Expand Down Expand Up @@ -1588,6 +1600,22 @@ 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_pay_network_token_without_payment_cryptogram, @options)
end.check_request do |_endpoint, data, _headers|
assert_match %r(<EMVCO_TOKEN-SSL type="APPLEPAY">), 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 })
Expand Down

0 comments on commit d0d3311

Please sign in to comment.