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, :pem_password)
  super
end

Public Instance Methods

authorize(amount, payment_method, options={}) click to toggle source
# File lib/active_merchant/billing/gateways/qvalent.rb, line 37
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)

  commit('preauth', post)
end
capture(amount, authorization, options={}) click to toggle source
# File lib/active_merchant/billing/gateways/qvalent.rb, line 50
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)

  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 72
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)

  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)

  commit('capture', post)
end
refund(amount, authorization, options={}) click to toggle source
# File lib/active_merchant/billing/gateways/qvalent.rb, line 60
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'

  commit('refund', post)
end
scrub(transcript) click to toggle source
# File lib/active_merchant/billing/gateways/qvalent.rb, line 104
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 92
def store(payment_method, options = {})
  post = {}
  add_payment_method(post, payment_method)
  add_card_reference(post)

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

  commit('reversal', post)
end

Private Instance Methods

add_card_reference(post) click to toggle source
# File lib/active_merchant/billing/gateways/qvalent.rb, line 183
def add_card_reference(post)
  post['customer.customerReferenceNumber'] = options[:order_id]
end
add_customer_data(post, options) click to toggle source
# File lib/active_merchant/billing/gateways/qvalent.rb, line 196
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_invoice(post, money, options) click to toggle source
# File lib/active_merchant/billing/gateways/qvalent.rb, line 127
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 192
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 132
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 187
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 117
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 139
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 179
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 235
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 202
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 223
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 160
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 284
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 229
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 265
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 243
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 251
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 148
def stored_credential_usage(post, payment_method, options)
  return unless payment_method.brand == 'visa'
  stored_credential = options[:stored_credential]
  if stored_credential[:initial_transaction]
    post['card.storedCredentialUsage'] = 'INITIAL_STORAGE'
  elsif stored_credential[:reason_type] == ('recurring' || 'installment')
    post['card.storedCredentialUsage'] = 'RECURRING'
  elsif stored_credential[:reason_type] == 'unscheduled'
    post['card.storedCredentialUsage'] = 'UNSCHEDULED'
  end
end
success_from(response) click to toggle source
# File lib/active_merchant/billing/gateways/qvalent.rb, line 261
def success_from(response)
  SUCCESS_CODES.include?(response)
end
url(action) click to toggle source
# File lib/active_merchant/billing/gateways/qvalent.rb, line 239
def url(action)
  (test? ? test_url : live_url)
end