class ActiveMerchant::Billing::CardStreamGateway

Constants

AVS_POSTAL_MATCH

0 - No additional information available. 1 - Postcode not checked. 2 - Postcode matched. 4 - Postcode not matched. 8 - Postcode partially matched.

AVS_STREET_MATCH

0 - No additional information available. 1 - Address numeric not checked. 2 - Address numeric matched. 4 - Address numeric not matched. 8 - Address numeric partially matched.

CURRENCY_CODES
CVV_CODE
THREEDSECURE_REQUIRED_DEPRECATION_MESSAGE

Public Class Methods

new(options = {}) click to toggle source
Calls superclass method ActiveMerchant::Billing::Gateway::new
# File lib/active_merchant/billing/gateways/card_stream.rb, line 141
def initialize(options = {})
  requires!(options, :login, :shared_secret)
  @threeds_required = false
  if options[:threeDSRequired]
    ActiveMerchant.deprecated(THREEDSECURE_REQUIRED_DEPRECATION_MESSAGE)
    @threeds_required = options[:threeDSRequired]
  end
  super
end

Public Instance Methods

authorize(money, credit_card_or_reference, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/card_stream.rb, line 151
def authorize(money, credit_card_or_reference, options = {})
  post = {}
  add_pair(post, :captureDelay, -1)
  add_amount(post, money, options)
  add_invoice(post, credit_card_or_reference, money, options)
  add_credit_card_or_reference(post, credit_card_or_reference)
  add_customer_data(post, options)
  add_remote_address(post, options)
  commit('SALE', post)
end
capture(money, authorization, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/card_stream.rb, line 173
def capture(money, authorization, options = {})
  post = {}
  add_pair(post, :xref, authorization)
  add_pair(post, :amount, amount(money), :required => true)
  add_remote_address(post, options)

  commit('CAPTURE', post)
end
purchase(money, credit_card_or_reference, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/card_stream.rb, line 162
def purchase(money, credit_card_or_reference, options = {})
  post = {}
  add_pair(post, :captureDelay, 0)
  add_amount(post, money, options)
  add_invoice(post, credit_card_or_reference, money, options)
  add_credit_card_or_reference(post, credit_card_or_reference)
  add_customer_data(post, options)
  add_remote_address(post, options)
  commit('SALE', post)
end
refund(money, authorization, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/card_stream.rb, line 182
def refund(money, authorization, options = {})
  post = {}
  add_pair(post, :xref, authorization)
  add_amount(post, money, options)
  add_remote_address(post, options)
  response = commit('REFUND_SALE', post)

  return response if response.success?
  return response unless options[:force_full_refund_if_unsettled]

  if response.params['responseCode'] == '65541'
    void(authorization, options)
  else
    response
  end
end
scrub(transcript) click to toggle source
# File lib/active_merchant/billing/gateways/card_stream.rb, line 217
def scrub(transcript)
  transcript.
    gsub(%r((Authorization: Basic )\w+), '\1[FILTERED]').
    gsub(%r((cardNumber=)\d+), '\1[FILTERED]').
    gsub(%r((CVV=)\d+), '\1[FILTERED]')
end
supports_scrubbing?() click to toggle source
# File lib/active_merchant/billing/gateways/card_stream.rb, line 213
def supports_scrubbing?
  true
end
verify(creditcard, options={}) click to toggle source
# File lib/active_merchant/billing/gateways/card_stream.rb, line 206
def verify(creditcard, options={})
  MultiResponse.run(:use_first_response) do |r|
    r.process { authorize(100, creditcard, options) }
    r.process(:ignore_result) { void(r.authorization, options) }
  end
end
void(authorization, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/card_stream.rb, line 199
def void(authorization, options = {})
  post = {}
  add_pair(post, :xref, authorization)
  add_remote_address(post, options)
  commit('CANCEL', post)
end

Private Instance Methods

add_amount(post, money, options) click to toggle source
# File lib/active_merchant/billing/gateways/card_stream.rb, line 226
def add_amount(post, money, options)
  add_pair(post, :amount, amount(money), :required => true)
  add_pair(post, :currencyCode, currency_code(options[:currency] || currency(money)))
end
add_credit_card(post, credit_card) click to toggle source
# File lib/active_merchant/billing/gateways/card_stream.rb, line 272
def add_credit_card(post, credit_card)
  add_pair(post, :customerName, credit_card.name, :required => true)
  add_pair(post, :cardNumber, credit_card.number, :required => true)
  add_pair(post, :cardExpiryMonth, format(credit_card.month, :two_digits), :required => true)
  add_pair(post, :cardExpiryYear, format(credit_card.year, :two_digits), :required => true)
  add_pair(post, :cardCVV, credit_card.verification_value)
end
add_credit_card_or_reference(post, credit_card_or_reference) click to toggle source
# File lib/active_merchant/billing/gateways/card_stream.rb, line 260
def add_credit_card_or_reference(post, credit_card_or_reference)
  if credit_card_or_reference.respond_to?(:number)
    add_credit_card(post, credit_card_or_reference)
  else
    add_reference(post, credit_card_or_reference.to_s)
  end
end
add_customer_data(post, options) click to toggle source
# File lib/active_merchant/billing/gateways/card_stream.rb, line 231
def add_customer_data(post, options)
  add_pair(post, :customerEmail, options[:email])
  if (address = options[:billing_address] || options[:address])
    add_pair(post, :customerAddress, "#{address[:address1]} #{address[:address2]}".strip)
    add_pair(post, :customerPostCode, address[:zip])
    add_pair(post, :customerPhone, options[:phone])
    add_pair(post, :customerCountryCode, address[:country] || 'GB')
  else
    add_pair(post, :customerCountryCode, 'GB')
  end
end
add_hmac(post) click to toggle source
# File lib/active_merchant/billing/gateways/card_stream.rb, line 292
def add_hmac(post)
  result = post.sort.collect { |key, value| "#{key}=#{normalize_line_endings(CGI.escape(value.to_s))}" }.join('&')
  result = Digest::SHA512.hexdigest("#{result}#{@options[:shared_secret]}")

  add_pair(post, :signature, result)
end
add_invoice(post, credit_card_or_reference, money, options) click to toggle source
# File lib/active_merchant/billing/gateways/card_stream.rb, line 243
def add_invoice(post, credit_card_or_reference, money, options)
  add_pair(post, :transactionUnique, options[:order_id], :required => true)
  add_pair(post, :orderRef, options[:description] || options[:order_id], :required => true)
  add_pair(post, :statementNarrative1, options[:merchant_name]) if options[:merchant_name]
  add_pair(post, :statementNarrative2, options[:dynamic_descriptor]) if options[:dynamic_descriptor]
  if credit_card_or_reference.respond_to?(:number)
    if ['american_express', 'diners_club'].include?(card_brand(credit_card_or_reference).to_s)
      add_pair(post, :item1Quantity, 1)
      add_pair(post, :item1Description, (options[:description] || options[:order_id]).slice(0, 15))
      add_pair(post, :item1GrossValue, amount(money))
    end
  end

  add_pair(post, :type, options[:type] || '1')
  add_threeds_required(post, options)
end
add_pair(post, key, value, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/card_stream.rb, line 361
def add_pair(post, key, value, options = {})
  post[key] = value if !value.blank? || options[:required]
end
add_reference(post, reference) click to toggle source
# File lib/active_merchant/billing/gateways/card_stream.rb, line 268
def add_reference(post, reference)
  add_pair(post, :xref, reference, :required => true)
end
add_remote_address(post, options={}) click to toggle source
# File lib/active_merchant/billing/gateways/card_stream.rb, line 284
def add_remote_address(post, options={})
  add_pair(post, :remoteAddress, options[:ip] || '1.1.1.1')
end
add_threeds_required(post, options) click to toggle source
# File lib/active_merchant/billing/gateways/card_stream.rb, line 280
def add_threeds_required(post, options)
  add_pair(post, :threeDSRequired, options[:threeds_required] || @threeds_required ? 'Y' : 'N')
end
avs_from(response) click to toggle source
# File lib/active_merchant/billing/gateways/card_stream.rb, line 332
def avs_from(response)
  postal_match = AVS_POSTAL_MATCH[response[:avscv2ResponseCode].to_s[1, 1]]
  street_match = AVS_STREET_MATCH[response[:avscv2ResponseCode].to_s[2, 1]]

  code = if postal_match == 'Y' && street_match == 'Y'
           'M'
         elsif postal_match == 'Y'
           'P'
         elsif street_match == 'Y'
           'A'
         else
           'I'
  end

  AVSResult.new({
    :code => code,
    :postal_match => postal_match,
    :street_match => street_match
  })
end
commit(action, parameters) click to toggle source
# File lib/active_merchant/billing/gateways/card_stream.rb, line 310
def commit(action, parameters)
  parameters.update(:countryCode => self.supported_countries[0]) unless ['CAPTURE', 'CANCEL'].include?(action)
  parameters.update(
    :merchantID => @options[:login],
    :action => action
  )
  # adds a signature to the post hash/array
  add_hmac(parameters)

  response = parse(ssl_post(self.live_url, post_data(action, parameters)))

  Response.new(
    response[:responseCode] == '0',
    response[:responseCode] == '0' ? 'APPROVED' : response[:responseMessage],
    response,
    :test => test?,
    :authorization => response[:xref],
    :cvv_result => CVV_CODE[response[:avscv2ResponseCode].to_s[0, 1]],
    :avs_result => avs_from(response)
  )
end
currency_code(currency) click to toggle source
# File lib/active_merchant/billing/gateways/card_stream.rb, line 353
def currency_code(currency)
  CURRENCY_CODES[currency]
end
normalize_line_endings(str) click to toggle source
# File lib/active_merchant/billing/gateways/card_stream.rb, line 288
def normalize_line_endings(str)
  str.gsub(/%0D%0A|%0A%0D|%0D/, '%0A')
end
parse(body) click to toggle source
# File lib/active_merchant/billing/gateways/card_stream.rb, line 299
def parse(body)
  result = {}
  pairs = body.split('&')
  pairs.each do |pair|
    a = pair.split('=')
    # because some value pairs don't have a value
    result[a[0].to_sym] = a[1] == nil ? '' : CGI.unescape(a[1])
  end
  result
end
post_data(action, parameters = {}) click to toggle source
# File lib/active_merchant/billing/gateways/card_stream.rb, line 357
def post_data(action, parameters = {})
  parameters.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join('&')
end