Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adyen: Update to support normalized stored credential fields #3182

Merged
merged 1 commit into from
Mar 26, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
* Adyen: Pass phone, statement, device_fingerprint [curiousepic] #3178
* Adyen: Fix adding phone from billing address [curiousepic] #3179
* Fix partial or missing address exceptions [molbrown] #3180
Adyen: Update to support normalized stored credential fields [molbrown] #3182

== Version 1.91.0 (February 22, 2019)
* WorldPay: Pull CVC and AVS Result from Response [nfarve] #3106
Expand Down
22 changes: 19 additions & 3 deletions lib/active_merchant/billing/gateways/adyen.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def authorize(money, payment, options={})
add_invoice(post, money, options)
add_payment(post, payment)
add_extra_data(post, payment, options)
add_shopper_interaction(post, payment, options)
add_stored_credentials(post, payment, options)
add_address(post, options)
add_installments(post, options) if options[:installments]
add_3ds(post, options)
Expand Down Expand Up @@ -82,6 +82,7 @@ def store(credit_card, options={})
add_invoice(post, 0, options)
add_payment(post, credit_card)
add_extra_data(post, credit_card, options)
add_stored_credentials(post, credit_card, options)
add_recurring_contract(post, options)
add_address(post, options)
commit('authorise', post, options)
Expand Down Expand Up @@ -177,8 +178,13 @@ def add_risk_data(post, options)
end
end

def add_stored_credentials(post, payment, options)
add_shopper_interaction(post, payment, options)
add_recurring_processing_model(post, options)
end

def add_shopper_interaction(post, payment, options={})
if (payment.respond_to?(:verification_value) && payment.verification_value) || payment.is_a?(NetworkTokenizationCreditCard)
if options.dig(:stored_credential, :initial_transaction) || (payment.respond_to?(:verification_value) && payment.verification_value) || payment.is_a?(NetworkTokenizationCreditCard)
Copy link
Contributor

@curiousepic curiousepic Mar 26, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could .dig replace the AND in the second condition?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wish! payment is not a hash, so it cannot.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

orite

shopper_interaction = 'Ecommerce'
else
shopper_interaction = 'ContAuth'
Expand All @@ -187,6 +193,17 @@ def add_shopper_interaction(post, payment, options={})
post[:shopperInteraction] = options[:shopper_interaction] || shopper_interaction
end

def add_recurring_processing_model(post, options)
return unless options.dig(:stored_credential, :reason_type) || options[:recurring_processing_model]
if options.dig(:stored_credential, :reason_type) && options[:stored_credential][:reason_type] == 'unscheduled'
recurring_processing_model = 'CardOnFile'
else
recurring_processing_model = 'Subscription'
end

post[:recurringProcessingModel] = options[:recurring_processing_model] || recurring_processing_model
end

def add_address(post, options)
return unless post[:card]&.kind_of?(Hash)
if (address = options[:billing_address] || options[:address]) && address[:country]
Expand All @@ -206,7 +223,6 @@ def add_invoice(post, money, options)
currency: options[:currency] || currency(money)
}
post[:amount] = amount
post[:recurringProcessingModel] = options[:recurring_processing_model] if options[:recurring_processing_model]
end

def add_invoice_for_modification(post, money, options)
Expand Down
2 changes: 1 addition & 1 deletion test/remote/gateways/remote_adyen_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def setup
shopper_reference: 'John Smith',
billing_address: address(),
order_id: '123',
recurring_processing_model: 'CardOnFile'
stored_credential: {reason_type: 'unscheduled'}
}
end

Expand Down
35 changes: 34 additions & 1 deletion test/unit/gateways/adyen_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,21 @@ def setup
shopper_reference: 'John Smith',
order_id: '345123',
installments: 2,
recurring_processing_model: 'CardOnFile'
stored_credential: {reason_type: 'unscheduled'}
}

@normalized_initial_stored_credential = {
stored_credential: {
initial_transaction: true,
reason_type: 'unscheduled'
}
}

@normalized_stored_credential = {
stored_credential: {
initial_transaction: false,
reason_type: 'recurring'
}
}
end

Expand Down Expand Up @@ -189,6 +203,25 @@ def test_risk_data_complex_data
end.respond_with(successful_authorize_response)
end

def test_successful_authorize_with_normalized_stored_credentials
@credit_card.verification_value = nil
stub_comms do
@gateway.authorize(50, @credit_card, @options.merge(@normalized_stored_credential))
end.check_request do |endpoint, data, headers|
assert_match(/"shopperInteraction":"ContAuth"/, data)
assert_match(/"recurringProcessingModel":"Subscription"/, data)
end.respond_with(successful_authorize_response)
end

def test_successful_initial_authorize_with_normalized_stored_credentials
stub_comms do
@gateway.authorize(50, @credit_card, @options.merge(@normalized_initial_stored_credential))
end.check_request do |endpoint, data, headers|
assert_match(/"shopperInteraction":"Ecommerce"/, data)
assert_match(/"recurringProcessingModel":"CardOnFile"/, data)
end.respond_with(successful_authorize_response)
end

def test_failed_purchase
@gateway.expects(:ssl_post).returns(failed_purchase_response)

Expand Down