class ActiveMerchant::Billing::QvalentGateway

Constants

CURRENCY_CODES
CVV_CODE_MAPPING
STANDARD_ERROR_CODE_MAPPING
SUCCESS_CODES

Public Class Methods

new(options = {}) click to toggle source
Calls superclass method ActiveMerchant::Billing::Gateway::new
# File lib/active_merchant/billing/gateways/qvalent.rb, line 19
def initialize(options = {})
  requires!(options, :username, :password, :merchant, :pem)
  super
end

Public Instance Methods

authorize(amount, payment_method, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/qvalent.rb, line 38
def authorize(amount, payment_method, options = {})
  post = {}
  add_invoice(post, amount, options)
  add_order_number(post, options)
  add_payment_method(post, payment_method)
  add_verification_value(post, payment_method)
  add_stored_credential_data(post, payment_method, options)
  add_customer_data(post, options)
  add_soft_descriptors(post, options)
  add_customer_reference(post, options)

  commit('preauth', post)
end
capture(amount, authorization, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/qvalent.rb, line 52
def capture(amount, authorization, options = {})
  post = {}
  add_invoice(post, amount, options)
  add_reference(post, authorization, options)
  add_customer_data(post, options)
  add_soft_descriptors(post, options)
  add_customer_reference(post, options)

  commit('captureWithoutAuth', post)
end
credit(amount, payment_method, options = {}) click to toggle source

Credit requires the merchant account to be enabled for “Adhoc Refunds”

# File lib/active_merchant/billing/gateways/qvalent.rb, line 76
def credit(amount, payment_method, options = {})
  post = {}
  add_invoice(post, amount, options)
  add_order_number(post, options)
  add_payment_method(post, payment_method)
  add_customer_data(post, options)
  add_soft_descriptors(post, options)
  add_customer_reference(post, options)

  commit('refund', post)
end
purchase(amount, payment_method, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/qvalent.rb, line 24
def purchase(amount, payment_method, options = {})
  post = {}
  add_invoice(post, amount, options)
  add_order_number(post, options)
  add_payment_method(post, payment_method)
  add_verification_value(post, payment_method)
  add_stored_credential_data(post, payment_method, options)
  add_customer_data(post, options)
  add_soft_descriptors(post, options)
  add_customer_reference(post, options)

  commit('capture', post)
end
refund(amount, authorization, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/qvalent.rb, line 63
def refund(amount, authorization, options = {})
  post = {}
  add_invoice(post, amount, options)
  add_reference(post, authorization, options)
  add_customer_data(post, options)
  add_soft_descriptors(post, options)
  post['order.ECI'] = options[:eci] || 'SSL'
  add_customer_reference(post, options)

  commit('refund', post)
end
scrub(transcript) click to toggle source
# File lib/active_merchant/billing/gateways/qvalent.rb, line 110
def scrub(transcript)
  transcript.
    gsub(%r((&?customer.password=)[^&]*), '\1[FILTERED]').
    gsub(%r((&?card.PAN=)[^&]*), '\1[FILTERED]').
    gsub(%r((&?card.CVN=)[^&]*), '\1[FILTERED]')
end
store(payment_method, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/qvalent.rb, line 98
def store(payment_method, options = {})
  post = {}
  add_payment_method(post, payment_method)
  add_card_reference(post, options)

  commit('registerAccount', post)
end
supports_scrubbing?() click to toggle source
# File lib/active_merchant/billing/gateways/qvalent.rb, line 106
def supports_scrubbing?
  true
end
void(authorization, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/qvalent.rb, line 88
def void(authorization, options = {})
  post = {}
  add_reference(post, authorization, options)
  add_customer_data(post, options)
  add_soft_descriptors(post, options)
  add_customer_reference(post, options)

  commit('reversal', post)
end

Private Instance Methods

add_card_reference(post, options) click to toggle source
# File lib/active_merchant/billing/gateways/qvalent.rb, line 194
def add_card_reference(post, options)
  post['customer.customerReferenceNumber'] = options[:customer_reference_number] || options[:order_id]
end
add_customer_data(post, options) click to toggle source
# File lib/active_merchant/billing/gateways/qvalent.rb, line 211
def add_customer_data(post, options)
  post['order.ipAddress'] = options[:ip] || '127.0.0.1'
  post['order.xid'] = options[:xid] if options[:xid]
  post['order.cavv'] = options[:cavv] if options[:cavv]
end
add_customer_reference(post, options) click to toggle source
# File lib/active_merchant/billing/gateways/qvalent.rb, line 198
def add_customer_reference(post, options)
  post['customer.customerReferenceNumber'] = options[:customer_reference_number] if options[:customer_reference_number]
end
add_invoice(post, money, options) click to toggle source
# File lib/active_merchant/billing/gateways/qvalent.rb, line 133
def add_invoice(post, money, options)
  post['order.amount'] = amount(money)
  post['card.currency'] = CURRENCY_CODES[options[:currency] || currency(money)]
end
add_order_number(post, options) click to toggle source
# File lib/active_merchant/billing/gateways/qvalent.rb, line 207
def add_order_number(post, options)
  post['customer.orderNumber'] = options[:order_id] || SecureRandom.uuid
end
add_payment_method(post, payment_method) click to toggle source
# File lib/active_merchant/billing/gateways/qvalent.rb, line 138
def add_payment_method(post, payment_method)
  post['card.cardHolderName'] = payment_method.name
  post['card.PAN'] = payment_method.number
  post['card.expiryYear'] = format(payment_method.year, :two_digits)
  post['card.expiryMonth'] = format(payment_method.month, :two_digits)
end
add_reference(post, authorization, options) click to toggle source
# File lib/active_merchant/billing/gateways/qvalent.rb, line 202
def add_reference(post, authorization, options)
  post['customer.originalOrderNumber'] = authorization
  add_order_number(post, options)
end
add_soft_descriptors(post, options) click to toggle source
# File lib/active_merchant/billing/gateways/qvalent.rb, line 123
def add_soft_descriptors(post, options)
  post['customer.merchantName'] = options[:customer_merchant_name] if options[:customer_merchant_name]
  post['customer.merchantStreetAddress'] = options[:customer_merchant_street_address] if options[:customer_merchant_street_address]
  post['customer.merchantLocation'] = options[:customer_merchant_location] if options[:customer_merchant_location]
  post['customer.merchantState'] = options[:customer_merchant_state] if options[:customer_merchant_state]
  post['customer.merchantCountry'] = options[:customer_merchant_country] if options[:customer_merchant_country]
  post['customer.merchantPostCode'] = options[:customer_merchant_post_code] if options[:customer_merchant_post_code]
  post['customer.subMerchantId'] = options[:customer_sub_merchant_id] if options[:customer_sub_merchant_id]
end
add_stored_credential_data(post, payment_method, options) click to toggle source
# File lib/active_merchant/billing/gateways/qvalent.rb, line 145
def add_stored_credential_data(post, payment_method, options)
  post['order.ECI'] = options[:eci] || eci(options)
  if (stored_credential = options[:stored_credential]) && %w(visa master).include?(payment_method.brand)
    post['card.posEntryMode'] = stored_credential[:initial_transaction] ? 'MANUAL' : 'STORED_CREDENTIAL'
    stored_credential_usage(post, payment_method, options) unless stored_credential[:initiator] && stored_credential[:initiator] == 'cardholder'
    post['order.authTraceId'] = stored_credential[:network_transaction_id] if stored_credential[:network_transaction_id]
  end
end
add_verification_value(post, payment_method) click to toggle source
# File lib/active_merchant/billing/gateways/qvalent.rb, line 190
def add_verification_value(post, payment_method)
  post['card.CVN'] = payment_method.verification_value
end
build_request(post) click to toggle source
# File lib/active_merchant/billing/gateways/qvalent.rb, line 251
def build_request(post)
  post.to_query + '&message.end'
end
commit(action, post) click to toggle source
# File lib/active_merchant/billing/gateways/qvalent.rb, line 217
def commit(action, post)
  post['customer.username'] = @options[:username]
  post['customer.password'] = @options[:password]
  post['customer.merchant'] = @options[:merchant]
  post['order.type'] = action

  data = build_request(post)
  raw = parse(ssl_post(url(action), data, headers))

  succeeded = success_from(raw['response.responseCode'])
  Response.new(
    succeeded,
    message_from(succeeded, raw),
    raw,
    authorization: raw['response.orderNumber'] || raw['response.customerReferenceNumber'],
    cvv_result: cvv_result(succeeded, raw),
    error_code: error_code_from(succeeded, raw),
    test: test?
  )
end
cvv_result(succeeded, raw) click to toggle source
# File lib/active_merchant/billing/gateways/qvalent.rb, line 238
def cvv_result(succeeded, raw)
  return unless succeeded

  code = CVV_CODE_MAPPING[raw['response.cvnResponse']] || raw['response.cvnResponse']
  CVVResult.new(code)
end
eci(options) click to toggle source
# File lib/active_merchant/billing/gateways/qvalent.rb, line 171
def eci(options)
  if options.dig(:stored_credential, :initial_transaction)
    'SSL'
  elsif options.dig(:stored_credential, :initiator) && options[:stored_credential][:initiator] == 'cardholder'
    'MTO'
  elsif options.dig(:stored_credential, :reason_type)
    case options[:stored_credential][:reason_type]
    when 'recurring'
      'REC'
    when 'installment'
      'INS'
    when 'unscheduled'
      'MTO'
    end
  else
    'SSL'
  end
end
error_code_from(succeeded, response) click to toggle source
# File lib/active_merchant/billing/gateways/qvalent.rb, line 300
def error_code_from(succeeded, response)
  succeeded ? nil : STANDARD_ERROR_CODE_MAPPING[response['response.responseCode']]
end
headers() click to toggle source
# File lib/active_merchant/billing/gateways/qvalent.rb, line 245
def headers
  {
    'Content-Type' => 'application/x-www-form-urlencoded'
  }
end
message_from(succeeded, response) click to toggle source
# File lib/active_merchant/billing/gateways/qvalent.rb, line 281
def message_from(succeeded, response)
  if succeeded
    'Succeeded'
  else
    response['response.text'] || 'Unable to read error message'
  end
end
parse(body) click to toggle source
# File lib/active_merchant/billing/gateways/qvalent.rb, line 259
def parse(body)
  result = {}
  body.to_s.each_line do |pair|
    result[$1] = $2 if pair.strip =~ /\A([^=]+)=(.+)\Z/im
  end
  result
end
parse_element(response, node) click to toggle source
# File lib/active_merchant/billing/gateways/qvalent.rb, line 267
def parse_element(response, node)
  if node.has_elements?
    node.elements.each { |element| parse_element(response, element) }
  else
    response[node.name.underscore.to_sym] = node.text
  end
end
stored_credential_usage(post, payment_method, options) click to toggle source
# File lib/active_merchant/billing/gateways/qvalent.rb, line 154
def stored_credential_usage(post, payment_method, options)
  return unless payment_method.brand == 'visa'

  stored_credential = options[:stored_credential]
  if stored_credential[:reason_type] == 'unscheduled'
    if stored_credential[:initiator] == 'merchant'
      post['card.storedCredentialUsage'] = 'UNSCHEDULED_MIT'
    elsif stored_credential[:initiator] == 'customer'
      post['card.storedCredentialUsage'] = 'UNSCHEDULED_CIT'
    end
  elsif stored_credential[:reason_type] == 'recurring'
    post['card.storedCredentialUsage'] = 'RECURRING'
  elsif stored_credential[:reason_type] == 'installment'
    post['card.storedCredentialUsage'] = 'INSTALLMENT'
  end
end
success_from(response) click to toggle source
# File lib/active_merchant/billing/gateways/qvalent.rb, line 277
def success_from(response)
  SUCCESS_CODES.include?(response)
end
url(action) click to toggle source
# File lib/active_merchant/billing/gateways/qvalent.rb, line 255
def url(action)
  (test? ? test_url : live_url)
end