class ActiveMerchant::Billing::DatatransGateway

Constants

CREDIT_CARD_SOURCE
DEVICE_SOURCE

Public Class Methods

new(options = {}) click to toggle source
Calls superclass method ActiveMerchant::Billing::Gateway::new
# File lib/active_merchant/billing/gateways/datatrans.rb, line 28
def initialize(options = {})
  requires!(options, :merchant_id, :password)
  @merchant_id, @password = options.values_at(:merchant_id, :password)
  super
end

Public Instance Methods

authorize(money, payment, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/datatrans.rb, line 45
def authorize(money, payment, options = {})
  post = { refno: options.fetch(:order_id, '') }
  add_payment_method(post, payment)
  add_3ds_data(post, payment, options)
  add_currency_amount(post, money, options)
  add_billing_address(post, options)
  post[:autoSettle] = options[:auto_settle] if options[:auto_settle]
  commit('authorize', post)
end
capture(money, authorization, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/datatrans.rb, line 55
def capture(money, authorization, options = {})
  post = { refno: options.fetch(:order_id, '') }
  transaction_id = authorization.split('|').first
  add_currency_amount(post, money, options)
  commit('settle', post, { transaction_id: transaction_id })
end
purchase(money, payment, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/datatrans.rb, line 34
def purchase(money, payment, options = {})
  authorize(money, payment, options.merge(auto_settle: true))
end
refund(money, authorization, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/datatrans.rb, line 62
def refund(money, authorization, options = {})
  post = { refno: options.fetch(:order_id, '') }
  transaction_id = authorization.split('|').first
  add_currency_amount(post, money, options)
  commit('credit', post, { transaction_id: transaction_id })
end
scrub(transcript) click to toggle source
# File lib/active_merchant/billing/gateways/datatrans.rb, line 101
def scrub(transcript)
  transcript.
    gsub(%r((Authorization: Basic )[\w =]+), '\1[FILTERED]').
    gsub(%r((\"number\\":\\")\d+), '\1[FILTERED]\2').
    gsub(%r((\"cvv\\":\\")\d+), '\1[FILTERED]\2')
end
store(payment_method, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/datatrans.rb, line 75
def store(payment_method, options = {})
  exp_year = format(payment_method.year, :two_digits)
  exp_month = format(payment_method.month, :two_digits)

  post = {
    requests: [
      {
        type: 'CARD',
        pan: payment_method.number,
        expiryMonth: exp_month,
        expiryYear: exp_year
      }
    ]
  }
  commit('tokenize', post, { expiry_month: exp_month, expiry_year: exp_year })
end
supports_scrubbing?() click to toggle source
# File lib/active_merchant/billing/gateways/datatrans.rb, line 97
def supports_scrubbing?
  true
end
unstore(authorization, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/datatrans.rb, line 92
def unstore(authorization, options = {})
  data_alias = authorization.split('|')[2]
  commit('delete_alias', {}, { alias_id: data_alias }, :delete)
end
verify(payment, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/datatrans.rb, line 38
def verify(payment, options = {})
  MultiResponse.run(:use_first_response) do |r|
    r.process { authorize(100, payment, options) }
    r.process(:ignore_result) { void(r.authorization, options) }
  end
end
void(authorization, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/datatrans.rb, line 69
def void(authorization, options = {})
  post = {}
  transaction_id = authorization.split('|').first
  commit('cancel', post, { transaction_id: transaction_id })
end

Private Instance Methods

add_3ds_data(post, payment_method, options) click to toggle source
# File lib/active_merchant/billing/gateways/datatrans.rb, line 140
def add_3ds_data(post, payment_method, options)
  return unless three_d_secure = options[:three_d_secure]

  three_ds =
    {
      "3D":
        {
          eci: three_d_secure[:eci],
          xid: three_d_secure[:xid],
          threeDSTransactionId: three_d_secure[:ds_transaction_id],
          cavv: three_d_secure[:cavv],
          threeDSVersion: three_d_secure[:version],
          cavvAlgorithm: three_d_secure[:cavv_algorithm],
          directoryResponse: three_d_secure[:directory_response_status],
          authenticationResponse: three_d_secure[:authentication_response_status],
          transStatusReason: three_d_secure[:trans_status_reason]
        }.compact
    }

  post[:card].merge!(three_ds)
end
add_billing_address(post, options) click to toggle source
# File lib/active_merchant/billing/gateways/datatrans.rb, line 168
def add_billing_address(post, options)
  return unless billing_address = options[:billing_address]

  post[:billing] = {
    name: billing_address[:name],
    street: billing_address[:address1],
    street2: billing_address[:address2],
    city: billing_address[:city],
    country: country_code(billing_address[:country]),
    phoneNumber: billing_address[:phone],
    zipCode: billing_address[:zip],
    email: options[:email]
  }.compact
end
add_currency_amount(post, money, options) click to toggle source
# File lib/active_merchant/billing/gateways/datatrans.rb, line 183
def add_currency_amount(post, money, options)
  post[:currency] = (options[:currency] || currency(money))
  post[:amount] = amount(money)
end
add_payment_method(post, payment_method) click to toggle source
# File lib/active_merchant/billing/gateways/datatrans.rb, line 110
def add_payment_method(post, payment_method)
  case payment_method
  when String
    token, exp_month, exp_year = payment_method.split('|')[2..4]
    card = {
      type: 'ALIAS',
      alias: token,
      expiryMonth: exp_month,
      expiryYear: exp_year
    }
  when NetworkTokenizationCreditCard
    card = {
      type: DEVICE_SOURCE[payment_method.source] ? 'DEVICE_TOKEN' : 'NETWORK_TOKEN',
      tokenType: DEVICE_SOURCE[payment_method.source] || CREDIT_CARD_SOURCE[card_brand(payment_method)],
      token: payment_method.number,
      cryptogram: payment_method.payment_cryptogram,
      expiryMonth: format(payment_method.month, :two_digits),
      expiryYear: format(payment_method.year, :two_digits)
    }
  when CreditCard
    card = {
      number: payment_method.number,
      cvv: payment_method.verification_value.to_s,
      expiryMonth: format(payment_method.month, :two_digits),
      expiryYear: format(payment_method.year, :two_digits)
    }
  end
  post[:card] = card
end
authorization_from(response, action, options) click to toggle source
# File lib/active_merchant/billing/gateways/datatrans.rb, line 252
def authorization_from(response, action, options)
  token_array = [response.dig('responses', 0, 'alias'), options[:expiry_month], options[:expiry_year]].join('|') if action == 'tokenize'

  auth = [response['transactionId'], response['acquirerAuthorizationCode'], token_array].join('|')
  return auth unless auth == '||'
end
commit(action, post, options = {}, method = :post) click to toggle source
# File lib/active_merchant/billing/gateways/datatrans.rb, line 188
def commit(action, post, options = {}, method = :post)
  response = parse(ssl_request(method, url(action, options), post.to_json, headers))
  succeeded = success_from(action, response)

  Response.new(
    succeeded,
    message_from(succeeded, response),
    response,
    authorization: authorization_from(response, action, options),
    test: test?,
    error_code: error_code_from(response)
  )
rescue ResponseError => e
  response = parse(e.response.body)
  Response.new(false, message_from(false, response), response, test: test?, error_code: error_code_from(response))
end
country_code(country) click to toggle source
# File lib/active_merchant/billing/gateways/datatrans.rb, line 162
def country_code(country)
  Country.find(country).code(:alpha3).value if country
rescue InvalidCountryCodeError
  nil
end
error_code_from(response) click to toggle source
# File lib/active_merchant/billing/gateways/datatrans.rb, line 265
def error_code_from(response)
  response.dig('error', 'code')
end
handle_response(response) click to toggle source
# File lib/active_merchant/billing/gateways/datatrans.rb, line 269
def handle_response(response)
  case response.code.to_i
  when 200...300
    response.body || { response_code: response.code.to_i }.to_json
  else
    raise ResponseError.new(response)
  end
end
headers() click to toggle source
# File lib/active_merchant/billing/gateways/datatrans.rb, line 217
def headers
  {
    'Content-Type' => 'application/json; charset=UTF-8',
    'Authorization' => "Basic #{Base64.strict_encode64("#{@merchant_id}:#{@password}")}"
  }
end
message_from(succeeded, response) click to toggle source
# File lib/active_merchant/billing/gateways/datatrans.rb, line 259
def message_from(succeeded, response)
  return if succeeded

  response.dig('error', 'message')
end
parse(response) click to toggle source
# File lib/active_merchant/billing/gateways/datatrans.rb, line 205
def parse(response)
  JSON.parse response
rescue JSON::ParserError
  msg = 'Invalid JSON response received from Datatrans. Please contact them for support if you continue to receive this message.'
  msg += "  (The raw response returned by the API was #{response.inspect})"
  {
    'successful' => false,
    'response' => {},
    'errors' => [msg]
  }
end
success_from(action, response) click to toggle source
# File lib/active_merchant/billing/gateways/datatrans.rb, line 237
def success_from(action, response)
  case action
  when 'authorize', 'credit'
    response.include?('transactionId') && response.include?('acquirerAuthorizationCode')
  when 'settle', 'cancel'
    response.dig('response_code') == 204
  when 'tokenize'
    response.dig('responses', 0, 'alias') && response.dig('overview', 'failed') == 0
  when 'delete_alias'
    response.dig('response_code') == 204
  else
    false
  end
end
url(endpoint, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/datatrans.rb, line 224
def url(endpoint, options = {})
  case endpoint
  when 'settle', 'credit', 'cancel'
    "#{test? ? test_url : live_url}transactions/#{options[:transaction_id]}/#{endpoint}"
  when 'tokenize'
    "#{test? ? test_url : live_url}aliases/#{endpoint}"
  when 'delete_alias'
    "#{test? ? test_url : live_url}aliases/#{options[:alias_id]}"
  else
    "#{test? ? test_url : live_url}transactions/#{endpoint}"
  end
end