diff --git a/lib/active_merchant/billing/gateways/xpay.rb b/lib/active_merchant/billing/gateways/xpay.rb new file mode 100644 index 00000000000..4a504e34ea2 --- /dev/null +++ b/lib/active_merchant/billing/gateways/xpay.rb @@ -0,0 +1,136 @@ +module ActiveMerchant #:nodoc: + module Billing #:nodoc: + class XpayGateway < Gateway + self.display_name = 'XPay Gateway' + self.homepage_url = 'https://developer.nexi.it/en' + + self.test_url = 'https://stg-ta.nexigroup.com/api/phoenix-0.0/psp/api/v1/' + self.live_url = 'https://xpay.nexigroup.com/api/phoenix-0.0/psp/api/v1/' + + self.supported_countries = %w(AT BE CY EE FI FR DE GR IE IT LV LT LU MT PT SK SI ES BG HR DK NO PL RO RO SE CH HU) + self.default_currency = 'EUR' + self.currencies_without_fractions = %w(BGN HRK DKK NOK GBP PLN CZK RON SEK CHF HUF) + self.money_format = :cents + self.supported_cardtypes = %i[visa master maestro american_express jcb] + + ENDPOINTS_MAPPING = { + purchase: 'orders/2steps/payment', + authorize: 'orders/2steps/init', + capture: 'captures', + verify: 'orders/card_verification', + void: 'cancels', + refund: 'refunds' + } + + def initialize(options = {}) + requires!(options, :api_key) + @api_key = options[:api_key] + super + end + + def purchase(amount, payment_method, options = {}) + post = {} + commit('purchase', post, options) + end + + def authorize(amount, payment_method, options = {}) + post = {} + add_auth_purchase(post, money, payment, options) + commit('authorize', post, options) + end + + def capture(amount, authorization, options = {}) + post = {} + commit('capture', post, options) + end + + def void(authorization, options = {}) + post = {} + commit('void', post, options) + end + + def refund(amount, authorization, options = {}) + post = {} + commit('refund', post, options) + end + + def verify(credit_card, options = {}) + post = {} + commit('verify', post, options) + end + + def supports_scrubbing? + true + end + + def scrub(transcript) end + + private + + def add_invoice(post, money, options) end + + def add_payment_method(post, payment_method) end + + def add_reference(post, authorization) end + + def add_auth_purchase(post, money, payment, options) end + + def commit(action, params, options) + begin + url = build_request_url(action) + response = ssl_post(url, params.to_json, request_headers(params, options)) + rescue ResponseError => e + response = e.response.body + response = JSON.parse(response) + end + + Response.new( + success_from(response), + message_from(response), + response, + authorization: authorization_from, + avs_result: AVSResult.new(code: response['some_avs_result_key']), + cvv_result: CVVResult.new(response['some_cvv_result_key']), + test: test?, + error_code: error_code_from(response) + ) + end + + def request_headers(post, options) + headers = { + 'Content-Type' => 'application/json', + 'X-Api-Key' => @api_key, + 'Correlation-Id' => options[:order][:order_id] || SecureRandom.uuid + } + headers + end + + def build_request_url(action, id = nil) + base_url = test? ? test_url : live_url + endpoint = ENDPOINTS_MAPPING[action.to_sym] + endpoint = id.present? ? '/operations/' + endpoint + %{/{#{id}}} : endpoint + base_url + endpoint + end + + def success_from(response) + response == 'SUCCESS' + end + + def message_from(succeeded, response) + if succeeded + 'Succeeded' + else + response[:some_key] + end + end + + def authorization_from(response) + response.dig('latest_payment_attempt', 'payment_intent_id') + end + + def error_code_from(response) + response['provider_original_response_code'] || response['code'] unless success_from(response) + end + end + end +end diff --git a/test/fixtures.yml b/test/fixtures.yml index c1db9c47cbf..d468580c32e 100644 --- a/test/fixtures.yml +++ b/test/fixtures.yml @@ -1474,3 +1474,6 @@ worldpay_us: acctid: MPNAB subid: SPREE merchantpin: "1234567890" + +x_pay: + api_key: 2d708950-50a1-434e-9a93-5d3ae2f1dd9f diff --git a/test/remote/gateways/remote_xpay_test.rb b/test/remote/gateways/remote_xpay_test.rb new file mode 100644 index 00000000000..0f6161fe24e --- /dev/null +++ b/test/remote/gateways/remote_xpay_test.rb @@ -0,0 +1,16 @@ +require 'test_helper' + +class RemoteRapydTest < Test::Unit::TestCase + def setup + @gateway = XpayGateway.new(fixtures(:x_pay)) + @amount = 200 + @credit_card = credit_card('4111111111111111') + @options = {} + end + + def test_successful_purchase + response = @gateway.purchase(@amount, @credit_card, @options) + assert_success response + assert_match 'The payment was paid', response.message + end +end diff --git a/test/unit/gateways/xpay_test.rb b/test/unit/gateways/xpay_test.rb new file mode 100644 index 00000000000..b9274b63411 --- /dev/null +++ b/test/unit/gateways/xpay_test.rb @@ -0,0 +1,21 @@ +require 'test_helper' + +class XpayTest < Test::Unit::TestCase + include CommStub + + def setup + @gateway = XpayGateway.new( + api_key: 'some api key' + ) + @credit_card = credit_card + @amount = 100 + end + + def test_supported_countries + assert_equal %w(AT BE CY EE FI FR DE GR IE IT LV LT LU MT PT SK SI ES BG HR DK NO PL RO RO SE CH HU), XpayGateway.supported_countries + end + + def test_supported_cardtypes + assert_equal %i[visa master maestro american_express jcb], @gateway.supported_cardtypes + end +end