class ActiveMerchant::Billing::VindiciaGateway

For more information on the Vindicia Gateway please visit their website

The login and password are not the username and password you use to login to the Vindicia Merchant Portal.

Recurring Billing

AutoBills are an feature of Vindicia’s API that allows for creating and managing subscriptions.

For more information about Vindicia’s API and various other services visit their Resource Center

Public Class Methods

new(options = {}) click to toggle source

Creates a new VindiciaGateway

The gateway requires that a valid login and password be passed in the options hash.

Options

  • :login – Vindicia SOAP login (REQUIRED)

  • :password – Vindicia SOAP password (REQUIRED)

  • :api_version – Vindicia API Version - defaults to 3.6 (OPTIONAL)

  • :account_id – Account Id which all transactions will be run against. (REQUIRED)

  • :transaction_prefix – Prefix to order id for one-time transactions - defaults to ‘X’ (OPTIONAL

  • :min_chargeback_probability – Minimum score for chargebacks - defaults to 65 (OPTIONAL)

  • :cvn_success – Array of valid CVN Check return values - defaults to [M, P] (OPTIONAL)

  • :avs_success – Array of valid AVS Check return values - defaults to [X, Y, A, W, Z] (OPTIONAL)

Calls superclass method ActiveMerchant::Billing::Gateway::new
# File lib/active_merchant/billing/gateways/vindicia.rb, line 42
def initialize(options = {})
  requires!(options, :login, :password, :account_id)
  super

  @account_id = options[:account_id]

  @transaction_prefix = options[:transaction_prefix] || "X"

  @min_chargeback_probability = options[:min_chargeback_probability] || 65
  @cvn_success = options[:cvn_success] || %w{M P}
  @avs_success = options[:avs_success] || %w{X Y A W Z}

  @allowed_authorization_statuses = %w{Authorized}
end

Public Instance Methods

authorize(money, creditcard, options = {}) click to toggle source

Performs an authorization, which reserves the funds on the customer’s credit card, but does not charge the card.

Parameters

  • money – The amount to be authorized as an Integer value in cents.

  • creditcard – The CreditCard details for the transaction.

  • options – A hash of optional parameters.

# File lib/active_merchant/billing/gateways/vindicia.rb, line 79
def authorize(money, creditcard, options = {})
  vindicia_transaction = authorize_transaction(money, creditcard, options)
  response = check_transaction(vindicia_transaction)

  # if this response is under fraud review because of our AVS/CVV checks void the transaction
  if !response.success? && response.fraud_review? && !response.authorization.blank?
    void_response = void([vindicia_transaction[:transaction][:merchantTransactionId]], options)
    if void_response.success?
      return response
    else
      return void_response
    end
  end

  response
end
capture(money, identification, options = {}) click to toggle source

Captures the funds from an authorized transaction.

Parameters

  • money – The amount to be captured as an Integer value in cents.

  • identification – The authorization returned from the previous authorize request.

# File lib/active_merchant/billing/gateways/vindicia.rb, line 102
def capture(money, identification, options = {})
  response = post(:capture) do |xml|
    add_hash(xml, transactions: [{ merchantTransactionId: identification }])
  end

  if response[:return][:returnCode] != '200' || response[:qtyFail].to_i > 0
    return fail(response)
  end

  success(response, identification)
end
purchase(money, creditcard, options = {}) click to toggle source

Perform a purchase, which is essentially an authorization and capture in a single operation.

Parameters

  • money – The amount to be purchased as an Integer value in cents.

  • creditcard – The CreditCard details for the transaction.

  • options – A hash of optional parameters.

# File lib/active_merchant/billing/gateways/vindicia.rb, line 64
def purchase(money, creditcard, options = {})
  response = authorize(money, creditcard, options)
  return response if !response.success? || response.fraud_review?

  capture(money, response.authorization, options)
end
recurring(money, creditcard, options={}) click to toggle source

Perform a recurring billing, which is essentially a purchase and autobill setup in a single operation.

Parameters

  • money – The amount to be purchased as an Integer value in cents.

  • creditcard – The CreditCard details for the transaction.

  • options – A hash of parameters.

Options

  • :product_sku – The subscription product’s sku

  • :autobill_prefix – Prefix to order id for subscriptions - defaults to ‘A’ (OPTIONAL)

# File lib/active_merchant/billing/gateways/vindicia.rb, line 148
def recurring(money, creditcard, options={})
  ActiveMerchant.deprecated RECURRING_DEPRECATION_MESSAGE

  options[:recurring] = true
  @autobill_prefix = options[:autobill_prefix] || "A"

  response = authorize(money, creditcard, options)
  return response if !response.success? || response.fraud_review?

  capture_resp = capture(money, response.authorization, options)
  return capture_resp if !response.success?

  # Setting up a recurring AutoBill requires an associated product
  requires!(options, :product_sku)
  autobill_response = check_subscription(authorize_subscription(options.merge(:product_sku => options[:product_sku])))

  if autobill_response.success?
    autobill_response
  else
    # If the AutoBill fails to set-up, void the transaction and return it as the response
    void_response = void(capture_resp.authorization, options)
    if void_response.success?
      return autobill_response
    else
      return void_response
    end
  end
end
void(identification, options = {}) click to toggle source

Void a previous transaction

Parameters

  • identification - The authorization returned from the previous authorize request.

  • options - Extra options (currently only :ip used)

# File lib/active_merchant/billing/gateways/vindicia.rb, line 120
def void(identification, options = {})
  response = post(:cancel) do |xml|
    add_hash(xml, transactions: [{
      account: {merchantAccountId: @account_id},
      merchantTransactionId: identification,
      sourceIp: options[:ip]
    }])
  end

  if response[:return][:returnCode] == '200' && response[:qtyFail].to_i == 0
    success(response, identification)
  else
    fail(response)
  end
end

Private Instance Methods

add_account_data(parameters, options) click to toggle source
# File lib/active_merchant/billing/gateways/vindicia.rb, line 275
def add_account_data(parameters, options)
  parameters[:account] = { :merchantAccountId => @account_id }
  parameters[:sourceIp] = options[:ip] if options[:ip]
end
add_array(xml, elem, val) click to toggle source
# File lib/active_merchant/billing/gateways/vindicia.rb, line 185
def add_array(xml, elem, val)
  val.each do |v|
    add_element(xml, elem, v)
  end
end
add_customer_data(parameters, options) click to toggle source
# File lib/active_merchant/billing/gateways/vindicia.rb, line 280
def add_customer_data(parameters, options)
  parameters[:merchantTransactionId] = transaction_id(options[:order_id])
  parameters[:shippingAddress] = convert_am_address_to_vindicia(options[:shipping_address])

  # Transaction items must be provided for tax purposes
  requires!(options, :line_items)
  parameters[:transactionItems] = options[:line_items]

  if options[:recurring]
    parameters[:nameValues] = [{:name => 'merchantAutoBillIdentifier', :value => autobill_id(options[:order_id])}]
  end
end
add_element(xml, elem, val) click to toggle source
# File lib/active_merchant/billing/gateways/vindicia.rb, line 191
def add_element(xml, elem, val)
  if val.is_a?(Hash)
    xml.tag!(elem.to_s.camelize(:lower)) do |env|
      add_hash(env, val)
    end
  elsif val.is_a?(Array)
    add_array(xml, elem, val)
  else
    xml.tag!(elem.to_s.camelize(:lower), val.to_s)
  end
end
add_hash(xml, hash) click to toggle source
# File lib/active_merchant/billing/gateways/vindicia.rb, line 179
def add_hash(xml, hash)
  hash.each do |k,v|
    add_element(xml, k, v)
  end
end
add_payment_source(parameters, creditcard, options) click to toggle source
# File lib/active_merchant/billing/gateways/vindicia.rb, line 293
def add_payment_source(parameters, creditcard, options)
  parameters[:sourcePaymentMethod] = {
    :type => 'CreditCard',
    :creditCard => { :account => creditcard.number, :expirationDate => "%4d%02d" % [creditcard.year, creditcard.month] },
    :accountHolderName => creditcard.name,
    :nameValues => [{ :name => 'CVN', :value => creditcard.verification_value }],
    :billingAddress => convert_am_address_to_vindicia(options[:billing_address] || options[:address]),
    :customerSpecifiedType => creditcard.brand.capitalize,
    :active => !!options[:recurring]
  }
end
add_subscription_information(parameters, options) click to toggle source
# File lib/active_merchant/billing/gateways/vindicia.rb, line 329
def add_subscription_information(parameters, options)
  requires!(options, :product_sku)

  if options[:shipping_address]
    parameters[:account][:shipping_address] = options[:shipping_address]
  end

  parameters[:merchantAutoBillId] = autobill_id(options[:order_id])
  parameters[:product] = { :merchantProductId => options[:product_sku] }
end
authorize_subscription(options) click to toggle source
# File lib/active_merchant/billing/gateways/vindicia.rb, line 305
def authorize_subscription(options)
  parameters = {}

  add_account_data(parameters, options)
  add_subscription_information(parameters, options)

  post(:update, "AutoBill") do |xml|
    add_hash(xml, autobill: parameters, validatePaymentMethod: false, minChargebackProbability: 100)
  end
end
authorize_transaction(money, creditcard, options) click to toggle source
# File lib/active_merchant/billing/gateways/vindicia.rb, line 260
def authorize_transaction(money, creditcard, options)
  parameters = {
    :amount => amount(money),
    :currency => options[:currency] || currency(money)
  }

  add_account_data(parameters, options)
  add_customer_data(parameters, options)
  add_payment_source(parameters, creditcard, options)

  post(:auth) do |xml|
    add_hash(xml, transaction: parameters, minChargebackProbability: @min_chargeback_probability)
  end
end
autobill_id(order_id) click to toggle source
# File lib/active_merchant/billing/gateways/vindicia.rb, line 362
def autobill_id(order_id)
  "#{@autobill_prefix}#{order_id}"
end
check_avs(avs) click to toggle source
# File lib/active_merchant/billing/gateways/vindicia.rb, line 340
def check_avs(avs)
  avs.blank? || @avs_success.include?(avs)
end
check_cvn(cvn) click to toggle source
# File lib/active_merchant/billing/gateways/vindicia.rb, line 344
def check_cvn(cvn)
  cvn.blank? || @cvn_success.include?(cvn)
end
check_subscription(vindicia_transaction) click to toggle source
# File lib/active_merchant/billing/gateways/vindicia.rb, line 316
def check_subscription(vindicia_transaction)
  if vindicia_transaction[:return][:returnCode] == '200'
    if vindicia_transaction[:autobill] && vindicia_transaction[:autobill][:status] == "Active"
      success(vindicia_transaction,
              vindicia_transaction[:autobill][:merchantAutoBillId])
    else
      fail(vindicia_transaction)
    end
  else
    fail(vindicia_transaction)
  end
end
check_transaction(vindicia_transaction) click to toggle source
# File lib/active_merchant/billing/gateways/vindicia.rb, line 234
def check_transaction(vindicia_transaction)
  if vindicia_transaction[:return][:returnCode] == '200'
    status_log = vindicia_transaction[:transaction][:statusLog].first
    if status_log[:creditCardStatus]
      avs = status_log[:creditCardStatus][:avsCode]
      cvn = status_log[:creditCardStatus][:cvnCode]
    end

    if @allowed_authorization_statuses.include?(status_log[:status]) &&
      check_cvn(cvn) && check_avs(avs)

      success(vindicia_transaction,
              vindicia_transaction[:transaction][:merchantTransactionId],
              avs, cvn)
    else
      # If the transaction is authorized, but it didn't pass our AVS/CVV checks send the authorization along so
      # that is gets voided. Otherwise, send no authorization.
      fail(vindicia_transaction, avs, cvn, false,
           @allowed_authorization_statuses.include?(status_log[:status]) ? vindicia_transaction[:transaction][:merchantTransactionId] : "")
    end
  else
    # 406 = Chargeback risk score is higher than minChargebackProbability, transaction not authorized.
    fail(vindicia_transaction, nil, nil, vindicia_transaction[:return][:return_code] == '406')
  end
end
convert_am_address_to_vindicia(address) click to toggle source

Converts valid ActiveMerchant address hash to proper Vindicia format

# File lib/active_merchant/billing/gateways/vindicia.rb, line 371
def convert_am_address_to_vindicia(address)
  return if address.nil?

  convs = { :address1 => :addr1, :address2 => :addr2,
    :state => :district, :zip => :postalCode }

  vindicia_address = {}
  address.each do |key, val|
    vindicia_address[convs[key] || key] = val
  end
  vindicia_address
end
fail(response, avs_code = nil, cvn_code = nil, fraud_review = false, authorization = "") click to toggle source
# File lib/active_merchant/billing/gateways/vindicia.rb, line 354
def fail(response, avs_code = nil, cvn_code = nil, fraud_review = false, authorization = "")
  ActiveMerchant::Billing::Response.new(false, response[:return][:returnString], response,
                                        { :fraud_review => fraud_review || !authorization.blank?,
                                          :authorization => authorization, :test => test?,
                                          :avs_result => { :code => avs_code }, :cvv_result => cvn_code })

end
parse(response) click to toggle source
# File lib/active_merchant/billing/gateways/vindicia.rb, line 229
def parse(response)
  # Vindicia always returns in the form of request_type_response => { actual_response }
  Hash.from_xml(response)["Envelope"]["Body"].values.first.with_indifferent_access
end
post(action, kind="Transaction") { |xml| ... } click to toggle source
# File lib/active_merchant/billing/gateways/vindicia.rb, line 203
def post(action, kind="Transaction")
  xml = Builder::XmlMarkup.new
  xml.instruct!(:xml, :encoding => "UTF-8")
  xml.env :Envelope,
    "xmlns:xsd" => "http://www.w3.org/2001/XMLSchema",
    "xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance",
    "xmlns:tns" => "http://soap.vindicia.com/v3_6/#{kind}",
    "xmlns:env" => "http://schemas.xmlsoap.org/soap/envelope/" do

    xml.env :Body do
      xml.tns action.to_sym do
        xml.auth do
          xml.tag! :login, @options[:login]
          xml.tag! :password, @options[:password]
          xml.tag! :version, "3.6"
        end

        yield(xml)
      end
    end
  end

  url = (test? ? self.test_url : self.live_url)
  parse(ssl_post(url, xml.target!, "Content-Type" => "text/xml"))
end
success(response, authorization, avs_code = nil, cvn_code = nil) click to toggle source
# File lib/active_merchant/billing/gateways/vindicia.rb, line 348
def success(response, authorization, avs_code = nil, cvn_code = nil)
  ActiveMerchant::Billing::Response.new(true, response[:return][:returnString], response,
                                        { :fraud_review => false, :authorization => authorization, :test => test?,
                                          :avs_result => { :code => avs_code }, :cvv_result => cvn_code })
end
transaction_id(order_id) click to toggle source
# File lib/active_merchant/billing/gateways/vindicia.rb, line 366
def transaction_id(order_id)
  "#{@transaction_prefix}#{order_id}"
end