From 8a105335a7b549fc29754ac70b06be841782088c Mon Sep 17 00:00:00 2001 From: ajawadmirza Date: Fri, 17 Jun 2022 12:31:15 +0500 Subject: [PATCH] Plexo: update `verify` implementation. Updated `verify` implementation to send request on plexo API endpoint along with test cases. [SER-106](https://spreedly.atlassian.net/browse/SER-106) Unit: 5213 tests, 75902 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications 100% passed Rubocop: 743 files inspected, no offenses detected Remote: 18 tests, 100 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications 100% passed Closes #4462 --- CHANGELOG | 1 + lib/active_merchant/billing/gateways/plexo.rb | 26 ++- test/remote/gateways/remote_plexo_test.rb | 13 +- test/unit/gateways/plexo_test.rb | 176 +++++++++++++++++- 4 files changed, 194 insertions(+), 22 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 518067fc256..a102fcbd51f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -42,6 +42,7 @@ * Airwallex: Update `referrer_data` field [drkjc] #4455 * Simetrik: Update `order_id` and `description` to be top level fields [simetrik-frank] #4451 * Plexo: Update `ip`, `description`, and `email` fields request format and scrub method to not filter cardholder name and reference id [ajawadmirza] #4457 +* Plexo: Update `verify` implementation and add `verify_amount` field [ajawadmirza] #4462 == Version 1.126.0 (April 15th, 2022) * Moneris: Add 3DS MPI field support [esmitperez] #4373 diff --git a/lib/active_merchant/billing/gateways/plexo.rb b/lib/active_merchant/billing/gateways/plexo.rb index 7c69d145dfd..bfd00f8ea0a 100644 --- a/lib/active_merchant/billing/gateways/plexo.rb +++ b/lib/active_merchant/billing/gateways/plexo.rb @@ -11,7 +11,8 @@ class PlexoGateway < Gateway self.homepage_url = 'https://www.plexo.com.uy' self.display_name = 'Plexo' - APPENDED_URLS = %w(captures refunds cancellations) + APPENDED_URLS = %w(captures refunds cancellations verify) + AMOUNT_IN_RESPONSE = %w(authonly /verify) def initialize(options = {}) requires!(options, :client_id, :api_key) @@ -38,7 +39,7 @@ def authorize(money, payment, options = {}) add_payment_method(post, payment, options) add_items(post, options[:items]) add_metadata(post, options[:metadata]) - add_amount(money, post, options[:amount_details]) + add_amount(money, post, options) add_browser_details(post, options) add_capture_type(post, options) @@ -74,10 +75,19 @@ def void(authorization, options = {}) end def verify(credit_card, options = {}) - MultiResponse.run(:use_first_response) do |r| - r.process { authorize(100, credit_card, options) } - r.process(:ignore_result) { void(r.authorization, options) } - end + post = {} + post[:ReferenceId] = options[:reference_id] || generate_unique_id + post[:MerchantId] = options[:merchant_id] || @credentials[:merchant_id] + post[:StatementDescriptor] = options[:statement_descriptor] if options[:statement_descriptor] + post[:CustomerId] = options[:customer_id] if options[:customer_id] + money = options[:verify_amount].to_i || 100 + + add_payment_method(post, credit_card, options) + add_metadata(post, options[:metadata]) + add_amount(money, post, options) + add_browser_details(post, options) + + commit('/verify', post) end def supports_scrubbing? @@ -144,7 +154,7 @@ def add_amount(money, post, amount_options) post[:Amount][:Currency] = amount_options[:currency] || self.default_currency post[:Amount][:Total] = amount(money) post[:Amount][:Details] = {} - add_amount_details(post[:Amount][:Details], amount_options) + add_amount_details(post[:Amount][:Details], amount_options[:amount_details]) if amount_options[:amount_details] end def add_amount_details(amount_details, options) @@ -229,7 +239,7 @@ def commit(action, parameters) base_url = (test? ? test_url : live_url) url = build_url(action, base_url) response = parse(ssl_post(url, parameters.to_json, header(parameters))) - response = reorder_amount_fields(response) if action == 'authonly' + response = reorder_amount_fields(response) if AMOUNT_IN_RESPONSE.include?(action) Response.new( success_from(response), diff --git a/test/remote/gateways/remote_plexo_test.rb b/test/remote/gateways/remote_plexo_test.rb index 1aab64deb8b..8679428e86b 100644 --- a/test/remote/gateways/remote_plexo_test.rb +++ b/test/remote/gateways/remote_plexo_test.rb @@ -126,7 +126,13 @@ def test_failed_void end def test_successful_verify - response = @gateway.verify(@credit_card, @options.merge(@cancel_options)) + response = @gateway.verify(@credit_card, @options) + assert_success response + assert_equal 'You have been mocked.', response.message + end + + def test_successful_verify_with_custom_amount + response = @gateway.verify(@credit_card, @options.merge({ verify_amount: '400' })) assert_success response assert_equal 'You have been mocked.', response.message end @@ -134,9 +140,8 @@ def test_successful_verify def test_failed_verify response = @gateway.verify(@declined_card, @options) assert_failure response - assert_equal 'You have been mocked.', response.message - assert_equal '96', response.error_code - assert_equal 'denied', response.params['status'] + assert_equal 'The selected payment state is not valid.', response.message + assert_equal 400, response.error_code end def test_invalid_login diff --git a/test/unit/gateways/plexo_test.rb b/test/unit/gateways/plexo_test.rb index ab9985abfba..de9543a7cd5 100644 --- a/test/unit/gateways/plexo_test.rb +++ b/test/unit/gateways/plexo_test.rb @@ -130,7 +130,6 @@ def test_successful_authorize_with_extra_options def test_successful_authorize_with_amount_fields amount_fields = { - currency: 'USD', taxed_amount: '100', tip_amount: '32', discount_amount: '10', @@ -142,10 +141,10 @@ def test_successful_authorize_with_amount_fields } } response = stub_comms do - @gateway.authorize(@amount, @credit_card, @options.merge({ amount_details: amount_fields })) + @gateway.authorize(@amount, @credit_card, @options.merge({ amount_details: amount_fields, currency: 'USD' })) end.check_request do |_endpoint, data, _headers| request = JSON.parse(data) - assert_equal request['Amount']['Currency'], amount_fields[:currency] + assert_equal request['Amount']['Currency'], 'USD' assert_equal request['Amount']['Details']['TaxedAmount'], amount_fields[:taxed_amount] assert_equal request['Amount']['Details']['TipAmount'], amount_fields[:tip_amount] assert_equal request['Amount']['Details']['DiscountAmount'], amount_fields[:discount_amount] @@ -243,22 +242,24 @@ def test_failed_void end def test_successful_verify - @gateway.expects(:ssl_post).times(2).returns(successful_authorize_response, successful_capture_response) + @gateway.expects(:ssl_post).returns(successful_verify_response) response = @gateway.verify(@credit_card, @options) assert_success response assert_equal 'You have been mocked.', response.message end - def test_successful_verify_with_failed_void - @gateway.expects(:ssl_post).times(2).returns(successful_authorize_response, failed_void_response) - - response = @gateway.verify(@credit_card, @options) - assert_success response + def test_successful_verify_with_custom_amount + stub_comms do + @gateway.verify(@credit_card, @options.merge({ verify_amount: '900' })) + end.check_request do |_endpoint, data, _headers| + request = JSON.parse(data) + assert_equal request['Amount']['Total'], '9.00' + end.respond_with(successful_verify_response) end def test_failed_verify - @gateway.expects(:ssl_post).returns(failed_authorize_response) + @gateway.expects(:ssl_post).returns(failed_verify_response) response = @gateway.verify(@credit_card, @options) assert_failure response @@ -610,4 +611,159 @@ def failed_void_response } RESPONSE end + + def successful_verify_response + <<~RESPONSE + { + "id": "62ac2c5eaf353be57867f977", + "token": "7220c5cc-4b57-43e6-ae91-3fd3f3e8d49f", + "referenceId": "e7dbc06224f646ad8e63ec1c6e670a39", + "status": "approved", + "processingMethod": "api", + "browserDetails": { + "DeviceFingerprint": "12345", + "IpAddress": "127.0.0.1" + }, + "createdAt": "2022-06-17T07:25:18.1421498Z", + "merchant": { + "id": 3243, + "name": "spreedly", + "settings": { + "id": 41363, + "issuerId": 4, + "issuer": { + "id": 4, + "code": "mastercard", + "name": "MASTERCARD", + "type": "online" + }, + "metadata": { + "ProviderCommerceNumber": "153289", + "TerminalNumber": "1K153289", + "SoftDescriptor": "VTEX-Testing", + "PaymentProcessorId": "oca" + }, + "paymentProcessor": { + "acquirer": "oca", + "settings": { + "commerce": { + "fields": [ + { + "name": "ProviderCommerceNumber", + "type": 2049 + }, + { + "name": "TerminalNumber", + "type": 2051 + } + ] + }, + "fingerprint": { + "name": "cybersource-oca" + }, + "fields": [ + { + "name": "Email", + "type": 261 + }, + { + "name": "FirstName", + "type": 271 + }, + { + "name": "LastName", + "type": 272 + }, + { + "name": "CVC", + "type": 33154 + } + ] + } + } + }, + "clientId": 221 + }, + "client": { + "id": 221, + "name": "Spreedly", + "tier": 2, + "sessionTimeInSeconds": 36000 + }, + "paymentMethod": { + "type": "card", + "card": { + "name": "555555XXXXXX4444", + "bin": "555555", + "last4": "4444", + "expMonth": 12, + "expYear": 24, + "cardholder": { + "firstName": "Santiago", + "lastName": "Navatta", + "email": "snavatta@plexo.com.uy" + }, + "fingerprint": "36e2219cc4734a61af258905c1c59ba4" + }, + "issuer": { + "id": "mastercard", + "name": "MasterCard", + "pictureUrl": "https://static.plexo.com.uy/issuers/4.svg", + "type": "online" + }, + "processor": { + "acquirer": "oca" + } + }, + "installments": 1, + "amount": { + "currency": "UYU", + "total": 20 + }, + "items": [ + { + "referenceId": "997d4aafe29b4421ac52a3ddf5b28dfd", + "name": "card-verification", + "quantity": 1, + "price": 20 + } + ], + "capture": { + "method": "manual", + "delay": 0 + }, + "metadata": { + "One": "abc" + }, + "transactions": [ + { + "id": "62ac2c5eaf353be57867f97b", + "uniqueId": "987256610059481088", + "parentId": "7220c5cc-4b57-43e6-ae91-3fd3f3e8d49f", + "referenceId": "e7dbc06224f646ad8e63ec1c6e670a39", + "type": "authorization", + "status": "approved", + "createdAt": "2022-06-17T07:25:18.1796516Z", + "processedAt": "2022-06-17T07:25:18.1796366Z", + "resultCode": "0", + "resultMessage": "You have been mocked.", + "authorization": "12133", + "ticket": "111111", + "amount": 20 + } + ] + } + RESPONSE + end + + def failed_verify_response + <<~RESPONSE + { + "code": "invalid-transaction-state", + "message": "The selected payment state is not valid.", + "type": "api-error", + "status": 400 + } + RESPONSE + end end