module ActiveMerchant #:nodoc: module Billing #:nodoc: class PayJunctionV2Gateway < Gateway self.display_name = 'PayJunction' self.homepage_url = 'https://www.payjunction.com/' self.test_url = 'https://api.payjunctionlabs.com/transactions' self.live_url = 'https://api.payjunction.com/transactions' self.supported_countries = ['US'] self.default_currency = 'USD' self.money_format = :dollars self.supported_cardtypes = [:visa, :master, :american_express, :discover] def initialize(options={}) requires!(options, :api_login, :api_password, :api_key) super end def purchase(amount, payment_method, options={}) post = {} add_invoice(post, amount, options) add_payment_method(post, payment_method) commit('purchase', post) end def authorize(amount, payment_method, options={}) post = {} post[:status] = 'HOLD' add_invoice(post, amount, options) add_payment_method(post, payment_method) commit('authorize', post) end def capture(amount, authorization, options={}) post = {} post[:status] = 'CAPTURE' post[:transactionId] = authorization add_invoice(post, amount, options) commit('capture', post) end def void(authorization, options={}) post = {} post[:status] = 'VOID' post[:transactionId] = authorization commit('void', post) end def refund(amount, authorization, options={}) post = {} post[:action] = 'REFUND' post[:transactionId] = authorization add_invoice(post, amount, options) commit('refund', post) end def credit(amount, payment_method, options={}) post = {} post[:action] = 'REFUND' add_invoice(post, amount, options) add_payment_method(post, payment_method) commit('credit', post) 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 end def store(payment_method, options = {}) verify(payment_method, options) end def supports_scrubbing? true end def scrub(transcript) transcript. gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]'). gsub(%r((X-Pj-Application-Key: )[\w-]+), '\1[FILTERED]'). gsub(%r((cardNumber=)\d+), '\1[FILTERED]'). gsub(%r((cardCvv=)\d+), '\1[FILTERED]') end private def add_invoice(post, money, options) post[:amountBase] = amount(money) if money post[:invoiceNumber] = options[:order_id] if options[:order_id] end def add_payment_method(post, payment_method) if payment_method.is_a? Integer post[:transactionId] = payment_method else post[:cardNumber] = payment_method.number post[:cardExpMonth] = format(payment_method.month, :two_digits) post[:cardExpYear] = format(payment_method.year, :four_digits) post[:cardCvv] = payment_method.verification_value end end def commit(action, params) response = begin parse(ssl_invoke(action, params)) rescue ResponseError => e parse(e.response.body) end success = success_from(response) Response.new( success, message_from(response), response, authorization: success ? authorization_from(response) : nil, error_code: success ? nil : error_from(response), test: test? ) end def ssl_invoke(action, params) if ['purchase', 'authorize', 'refund', 'credit'].include?(action) ssl_post(url(), post_data(params), headers) else ssl_request(:put, url(params), post_data(params), headers) end end def headers { 'Authorization' => 'Basic ' + Base64.encode64("#{@options[:api_login]}:#{@options[:api_password]}").strip, 'Content-Type' => 'application/x-www-form-urlencoded;charset=UTF-8', 'Accept' => 'application/json', 'X-PJ-Application-Key' => @options[:api_key].to_s } end def post_data(params) params.map { |k, v| "#{k}=#{CGI.escape(v.to_s)}" }.join('&') end def url(params={}) test? ? "#{test_url}/#{params[:transactionId]}" : "#{live_url}/#{params[:transactionId]}" end def parse(body) JSON.parse(body) rescue JSON::ParserError message = 'Invalid JSON response received from PayJunctionV2Gateway. Please contact PayJunctionV2Gateway if you continue to receive this message.' message += " (The raw response returned by the API was #{body.inspect})" { 'errors' => [{ 'message' => message }] } end def success_from(response) return response['response']['approved'] if response['response'] false end def message_from(response) return response['response']['message'] if response['response'] response['errors']&.inject('') { |message, error| error['message'] + '|' + message } end def authorization_from(response) response['transactionId'] end def error_from(response) response['response']['code'] if response['response'] end end end end