Skip to content

Commit

Permalink
Mercado Pago: add idempotency key field
Browse files Browse the repository at this point in the history
  • Loading branch information
yunnydang committed Aug 26, 2024
1 parent 6b59d76 commit 1549bec
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
* Decidir & Braintree: Scrub cryptogram and card number [almalee24] #5220
* Naranja: Update valid number check to include luhn10 [DustinHaefele] #5217
* Cybersource: Add apple_pay with discover. [DustinHaefele] #5213
* MercadoPago: Add idempotency key field [yunnydang] #5229

== Version 1.137.0 (August 2, 2024)
* Unlock dependency on `rexml` to allow fixing a CVE (#5181).
Expand Down
13 changes: 12 additions & 1 deletion lib/active_merchant/billing/gateways/mercado_pago.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ def refund(money, authorization, options = {})
post = {}
authorization, original_amount = authorization.split('|')
post[:amount] = amount(money).to_f if original_amount && original_amount.to_f > amount(money).to_f
add_idempotency_key(post, options)
commit('refund', "payments/#{authorization}/refunds", post)
end

Expand Down Expand Up @@ -105,6 +106,7 @@ def purchase_request(money, payment, options = {})
add_net_amount(post, options)
add_taxes(post, options)
add_notification_url(post, options)
add_idempotency_key(post, options)
add_3ds(post, options)
post[:binary_mode] = options.fetch(:binary_mode, true) unless options[:execute_threed]
post
Expand Down Expand Up @@ -212,6 +214,10 @@ def add_net_amount(post, options)
post[:net_amount] = Float(options[:net_amount]) if options[:net_amount]
end

def add_idempotency_key(post, options)
post[:idempotency_key] = options[:idempotency_key] if options[:idempotency_key]
end

def add_notification_url(post, options)
post[:notification_url] = options[:notification_url] if options[:notification_url]
end
Expand Down Expand Up @@ -301,7 +307,11 @@ def authorization_from(response, params)
end

def post_data(parameters = {})
parameters.clone.tap { |p| p.delete(:device_id) }.to_json
params = parameters.clone.tap do |p|
p.delete(:device_id)
p.delete(:idempotency_key)
end
params.to_json
end

def inquire_path(authorization, options)
Expand Down Expand Up @@ -340,6 +350,7 @@ def headers(options = {})
'Content-Type' => 'application/json'
}
headers['X-meli-session-id'] = options[:device_id] if options[:device_id]
headers['X-Idempotency-Key'] = options[:idempotency_key] if options[:idempotency_key]
headers
end

Expand Down
18 changes: 18 additions & 0 deletions test/remote/gateways/remote_mercado_pago_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,12 @@ def test_successful_purchase_with_notification_url
assert_equal 'https://www.spreedly.com/', response.params['notification_url']
end

def test_successful_purchase_with_idempotency_key
response = @gateway.purchase(@amount, @credit_card, @options.merge(idempotency_key: '0d5020ed-1af6-469c-ae06-c3bec19954bb'))
assert_success response
assert_equal 'accredited', response.message
end

def test_successful_purchase_with_payer
response = @gateway.purchase(@amount, @credit_card, @options.merge({ payer: @payer }))
assert_success response
Expand Down Expand Up @@ -157,6 +163,12 @@ def test_successful_authorize_and_capture
assert_equal 'accredited', capture.message
end

def test_successful_authorize_with_idempotency_key
response = @gateway.authorize(@amount, @credit_card, @options.merge(idempotency_key: '0d5020ed-1af6-469c-ae06-c3bec19954bb'))
assert_success response
assert_equal 'accredited', response.message
end

def test_successful_authorize_and_capture_with_elo
auth = @gateway.authorize(@amount, @elo_credit_card, @options)
assert_success auth
Expand Down Expand Up @@ -312,6 +324,12 @@ def test_successful_verify
assert_match %r{pending_capture}, response.message
end

def test_successful_verify_with_idempotency_key
response = @gateway.verify(@credit_card, @options.merge(idempotency_key: '0d5020ed-1af6-469c-ae06-c3bec19954bb'))
assert_success response
assert_match %r{pending_capture}, response.message
end

def test_successful_verify_with_amount
@options[:amount] = 200
response = @gateway.verify(@credit_card, @options)
Expand Down
17 changes: 17 additions & 0 deletions test/unit/gateways/mercado_pago_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,23 @@ def test_includes_deviceid_header
assert_success response
end

def test_includes_idempotency_key_header
@options[:idempotency_key] = '12345'
@gateway.expects(:ssl_post).with(anything, anything, { 'Content-Type' => 'application/json' }).returns(successful_purchase_response)
@gateway.expects(:ssl_post).with(anything, anything, { 'Content-Type' => 'application/json', 'X-Idempotency-Key' => '12345' }).returns(successful_purchase_response)

response = @gateway.purchase(@amount, @credit_card, @options)
assert_success response
end

def test_includes_idempotency_key_header_for_refund
@options[:idempotency_key] = '12345'
@gateway.expects(:ssl_post).with(anything, anything, { 'Content-Type' => 'application/json', 'X-Idempotency-Key' => '12345' }).returns(successful_refund_response)

response = @gateway.refund(@amount, 'authorization|1.0', @options)
assert_success response
end

def test_includes_additional_data
@options[:additional_info] = { 'foo' => 'bar', 'baz' => 'quux' }
response = stub_comms do
Expand Down

0 comments on commit 1549bec

Please sign in to comment.