require 'active_merchant/billing/gateways/first_pay/first_pay_common' module ActiveMerchant #:nodoc: module Billing #:nodoc: class FirstPayJsonGateway < Gateway include FirstPayCommon ACTIONS = { purchase: 'Sale', authorize: 'Auth', capture: 'Settle', refund: 'Refund', void: 'Void' }.freeze WALLET_TYPES = { apple_pay: 'ApplePay', google_pay: 'GooglePay' }.freeze self.test_url = 'https://secure-v.1stPaygateway.net/secure/RestGW/Gateway/Transaction/' self.live_url = 'https://secure.1stPaygateway.net/secure/RestGW/Gateway/Transaction/' # Creates a new FirstPayJsonGateway # # The gateway requires two values for connection to be passed # in the +options+ hash. # # ==== Options # # * :merchant_key -- FirstPay's merchant_key (REQUIRED) # * :processor_id -- FirstPay's processor_id or processorId (REQUIRED) def initialize(options = {}) requires!(options, :merchant_key, :processor_id) super end def purchase(money, payment, options = {}) post = {} add_invoice(post, money, options) add_payment(post, payment, options) add_address(post, payment, options) commit(:purchase, post) end def authorize(money, payment, options = {}) post = {} add_invoice(post, money, options) add_payment(post, payment, options) add_address(post, payment, options) commit(:authorize, post) end def capture(money, authorization, options = {}) post = {} add_invoice(post, money, options) add_reference(post, authorization) commit(:capture, post) end def refund(money, authorization, options = {}) post = {} add_invoice(post, money, options) add_reference(post, authorization) commit(:refund, post) end def void(authorization, options = {}) post = {} add_reference(post, authorization) commit(:void, post) end def scrub(transcript) transcript. gsub(%r(("processorId\\?"\s*:\s*\\?")[^"]*)i, '\1[FILTERED]'). gsub(%r(("merchantKey\\?"\s*:\s*\\?")[^"]*)i, '\1[FILTERED]'). gsub(%r(("cardNumber\\?"\s*:\s*\\?")[^"]*)i, '\1[FILTERED]'). gsub(%r(("paymentCryptogram\\?"\s*:\s*\\?")[^"]*)i, '\1[FILTERED]'). gsub(%r(("cvv\\?"\s*:\s*\\?)[^,]*)i, '\1[FILTERED]') end private def add_address(post, creditcard, options) if address = options[:billing_address] || options[:address] post[:ownerName] = address[:name] post[:ownerStreet] = address[:address1] post[:ownerCity] = address[:city] post[:ownerState] = address[:state] post[:ownerZip] = address[:zip] post[:ownerCountry] = address[:country] end end def add_invoice(post, money, options) post[:orderId] = options[:order_id] post[:transactionAmount] = amount(money) end def add_payment(post, payment, options) post[:cardNumber] = payment.number post[:cardExpMonth] = payment.month post[:cardExpYear] = format(payment.year, :two_digits) post[:cvv] = payment.verification_value post[:recurring] = options[:recurring] if options[:recurring] post[:recurringStartDate] = options[:recurring_start_date] if options[:recurring_start_date] post[:recurringEndDate] = options[:recurring_end_date] if options[:recurring_end_date] case payment when NetworkTokenizationCreditCard post[:walletType] = WALLET_TYPES[payment.source] other_fields = post[:otherFields] = {} other_fields[:paymentCryptogram] = payment.payment_cryptogram other_fields[:eciIndicator] = payment.eci || '07' when CreditCard post[:cvv] = payment.verification_value end end def add_reference(post, authorization) post[:refNumber] = authorization end def commit(action, parameters) response = parse(api_request(base_url + ACTIONS[action], post_data(parameters))) Response.new( success_from(response), message_from(response), response, authorization: authorization_from(response), error_code: error_code_from(response), test: test? ) end def base_url test? ? self.test_url : self.live_url end def api_request(url, data) ssl_post(url, data, headers) rescue ResponseError => e e.response.body end def parse(data) JSON.parse data end def headers { 'Content-Type' => 'application/json' } end def format_messages(messages) return unless messages.present? messages.map { |message| message['message'] || message }.join('; ') end def success_from(response) response['isSuccess'] end def message_from(response) format_messages(response['errorMessages'] + response['validationFailures']) || response['data']['authResponse'] end def error_code_from(response) return 'isError' if response['isError'] return 'validationHasFailed' if response['validationHasFailed'] end def authorization_from(response) response.dig('data', 'referenceNumber') || '' end def post_data(params) params.merge({ processorId: @options[:processor_id], merchantKey: @options[:merchant_key] }).to_json end end end end