class ActiveMerchant::Billing::FlexChargeGateway

Constants

ENDPOINTS_MAPPING
SUCCESS_MESSAGES

Public Class Methods

new(options = {}) click to toggle source
Calls superclass method ActiveMerchant::Billing::Gateway::new
# File lib/active_merchant/billing/gateways/flex_charge.rb, line 27
def initialize(options = {})
  requires!(options, :app_key, :app_secret, :site_id, :mid)
  super
end

Public Instance Methods

add_metadata(post, options) click to toggle source
# File lib/active_merchant/billing/gateways/flex_charge.rb, line 118
def add_metadata(post, options)
  post[:Source] = 'Spreedly'
  post[:ExtraData] = options[:extra_data] if options[:extra_data].present?
end
authorize(money, credit_card, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/flex_charge.rb, line 49
def authorize(money, credit_card, options = {})
  options[:transactionType] = 'Authorization'
  purchase(money, credit_card, options)
end
capture(money, authorization, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/flex_charge.rb, line 54
def capture(money, authorization, options = {})
  order_id, currency = authorization.split('#')
  post = {
    idempotencyKey: options[:idempotency_key] || SecureRandom.uuid,
    orderId: order_id,
    amount: money,
    currency: currency
  }

  commit(:capture, post, authorization)
end
inquire(authorization, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/flex_charge.rb, line 113
def inquire(authorization, options = {})
  order_id, _currency = authorization.split('#')
  commit(:inquire, {}, order_id, :get)
end
purchase(money, credit_card, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/flex_charge.rb, line 32
def purchase(money, credit_card, options = {})
  post = { transactionType: options.fetch(:transactionType, 'Purchase') }

  add_merchant_data(post, options)
  add_base_data(post, options)
  add_invoice(post, money, credit_card, options)
  add_mit_data(post, options)
  add_payment_method(post, credit_card, address(options), options)
  add_address(post, credit_card, address(options), :billingInformation)
  add_address(post, credit_card, options[:shipping_address], :shippingInformation)
  add_customer_data(post, options)
  add_three_ds(post, options)
  add_metadata(post, options)

  commit(:purchase, post)
end
refund(money, authorization, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/flex_charge.rb, line 66
def refund(money, authorization, options = {})
  order_id, _currency = authorization.split('#')
  self.money_format = :dollars
  commit(:refund, { amountToRefund: localized_amount(money, 2).to_f }, order_id)
end
scrub(transcript) click to toggle source
# File lib/active_merchant/billing/gateways/flex_charge.rb, line 99
def scrub(transcript)
  transcript.
    gsub(%r((Authorization: Bearer )[a-zA-Z0-9._-]+)i, '\1[FILTERED]').
    gsub(%r(("AppKey\\?"\s*:\s*\\?")[^"]*)i, '\1[FILTERED]').
    gsub(%r(("AppSecret\\?"\s*:\s*\\?")[^"]*)i, '\1[FILTERED]').
    gsub(%r(("accessToken\\?"\s*:\s*\\?")[^"]*)i, '\1[FILTERED]').
    gsub(%r(("mid\\?"\s*:\s*\\?")[^"]*)i, '\1[FILTERED]').
    gsub(%r(("siteId\\?"\s*:\s*\\?")[^"]*)i, '\1[FILTERED]').
    gsub(%r(("environment\\?"\s*:\s*\\?")[^"]*)i, '\1[FILTERED]').
    gsub(%r(("number\\?"\s*:\s*\\?")[^"]*)i, '\1[FILTERED]').
    gsub(%r(("cardNumber\\?"\s*:\s*\\?")[^"]*)i, '\1[FILTERED]').
    gsub(%r(("verification_value\\?":\\?")\d+), '\1[FILTERED]')
end
store(credit_card, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/flex_charge.rb, line 77
def store(credit_card, options = {})
  first_name, last_name = names_from_address(address(options), credit_card)

  post = {
    payment_method: {
      credit_card: {
        first_name: first_name,
        last_name: last_name,
        month: credit_card.month,
        year: credit_card.year,
        number: credit_card.number,
        verification_value: credit_card.verification_value
      }.compact
    }
  }
  commit(:store, post)
end
supports_scrubbing?() click to toggle source
# File lib/active_merchant/billing/gateways/flex_charge.rb, line 95
def supports_scrubbing?
  true
end
void(authorization, options = {}) click to toggle source
# File lib/active_merchant/billing/gateways/flex_charge.rb, line 72
def void(authorization, options = {})
  order_id, _currency = authorization.split('#')
  commit(:void, {}, order_id)
end

Private Instance Methods

access_token_valid?() click to toggle source
# File lib/active_merchant/billing/gateways/flex_charge.rb, line 240
def access_token_valid?
  @options[:access_token].present? && @options.fetch(:token_expires, 0) > DateTime.now.strftime('%Q').to_i
end
add_address(post, payment, address, address_type) click to toggle source
# File lib/active_merchant/billing/gateways/flex_charge.rb, line 169
def add_address(post, payment, address, address_type)
  return unless address.present?

  first_name, last_name = names_from_address(address, payment)

  post[address_type] = {
    firstName: first_name,
    lastName: last_name,
    country: address[:country],
    phone: address[:phone],
    countryCode: address[:country],
    addressLine1: address[:address1],
    state: address[:state],
    city: address[:city],
    zipCode: address[:zip]
  }.compact
end
add_base_data(post, options) click to toggle source
# File lib/active_merchant/billing/gateways/flex_charge.rb, line 150
def add_base_data(post, options)
  post[:isDeclined] = cast_bool(options[:is_declined])
  post[:orderId] = options[:order_id]
  post[:idempotencyKey] = options[:idempotency_key] || SecureRandom.uuid
  post[:senseKey] = options[:sense_key]
end
add_customer_data(post, options) click to toggle source
# File lib/active_merchant/billing/gateways/flex_charge.rb, line 165
def add_customer_data(post, options)
  post[:payer] = { email: options[:email] || 'NA', phone: phone_from(options) }.compact
end
add_invoice(post, money, credit_card, options) click to toggle source
# File lib/active_merchant/billing/gateways/flex_charge.rb, line 187
def add_invoice(post, money, credit_card, options)
  post[:transaction] = {
    id: options[:order_id],
    dynamicDescriptor: options[:description],
    timestamp: Time.now.utc.iso8601,
    timezoneUtcOffset: options[:timezone_utc_offset],
    amount: money,
    currency: (options[:currency] || currency(money)),
    responseCode: options[:response_code],
    responseCodeSource: options[:response_code_source] || '',
    avsResultCode: options[:avs_result_code],
    cvvResultCode: options[:cvv_result_code],
    cavvResultCode: options[:cavv_result_code],
    cardNotPresent: credit_card.is_a?(String) ? false : credit_card.verification_value.blank?
  }.compact
end
add_merchant_data(post, options) click to toggle source
# File lib/active_merchant/billing/gateways/flex_charge.rb, line 145
def add_merchant_data(post, options)
  post[:siteId] = @options[:site_id]
  post[:mid] = @options[:mid]
end
add_mit_data(post, options) click to toggle source
# File lib/active_merchant/billing/gateways/flex_charge.rb, line 157
def add_mit_data(post, options)
  return if options[:is_mit].nil?

  post[:isMIT] = cast_bool(options[:is_mit])
  post[:isRecurring] = cast_bool(options[:is_recurring])
  post[:expiryDateUtc] = options[:mit_expiry_date_utc]
end
add_payment_method(post, credit_card, address, options) click to toggle source
# File lib/active_merchant/billing/gateways/flex_charge.rb, line 204
def add_payment_method(post, credit_card, address, options)
  payment_method = case credit_card
                   when String
                     { Token: true, cardNumber: credit_card }
                   when CreditCard
                     if credit_card.number
                       {
                         holderName: credit_card.name,
                         cardType: 'CREDIT',
                         cardBrand: credit_card.brand&.upcase,
                         cardCountry: address[:country],
                         expirationMonth: credit_card.month,
                         expirationYear: credit_card.year,
                         cardBinNumber: credit_card.number[0..5],
                         cardLast4Digits: credit_card.number[-4..-1],
                         cardNumber: credit_card.number,
                         Token: false
                       }
                     else
                       {}
                     end
                   end
  post[:paymentMethod] = payment_method.compact
end
add_three_ds(post, options) click to toggle source
# File lib/active_merchant/billing/gateways/flex_charge.rb, line 129
def add_three_ds(post, options)
  return unless three_d_secure = options[:three_d_secure]

  post[:threeDSecure] = {
    threeDsVersion: three_d_secure[:version],
    EcommerceIndicator: three_d_secure[:eci],
    authenticationValue: three_d_secure[:cavv],
    directoryServerTransactionId:  three_d_secure[:ds_transaction_id],
    xid: three_d_secure[:xid],
    authenticationValueAlgorithm: three_d_secure[:cavv_algorithm],
    directoryResponseStatus: three_d_secure[:directory_response_status],
    authenticationResponseStatus: three_d_secure[:authentication_response_status],
    enrolled: three_d_secure[:enrolled]
  }
end
address(options) click to toggle source
# File lib/active_merchant/billing/gateways/flex_charge.rb, line 125
def address(options)
  options[:billing_address] || options[:address] || {}
end
api_request(action, post, authorization = nil, method = :post) click to toggle source
# File lib/active_merchant/billing/gateways/flex_charge.rb, line 295
def api_request(action, post, authorization = nil, method = :post)
  response = parse ssl_request(method, url(action, authorization), post.to_json, headers)

  Response.new(
    success_from(action, response),
    message_from(response),
    response,
    authorization: authorization_from(action, response, post),
    test: test?,
    error_code: error_code_from(action, response)
  )
rescue ResponseError => e
  response = parse(e.response.body)
  # if current access_token is invalid then clean it
  if e.response.code == '401'
    @options[:access_token] = ''
    @options[:new_credentials] = true
  end
  Response.new(false, message_from(response), response, test: test?)
end
authorization_from(action, response, options) click to toggle source
# File lib/active_merchant/billing/gateways/flex_charge.rb, line 330
def authorization_from(action, response, options)
  if action == :store
    response.dig(:transaction, :payment_method, :token)
  elsif success_from(action, response)
    [response[:orderId], options[:currency] || default_currency].compact.join('#')
  end
end
cast_bool(value) click to toggle source
# File lib/active_merchant/billing/gateways/flex_charge.rb, line 342
def cast_bool(value)
  ![false, 0, '', '0', 'f', 'F', 'false', 'FALSE'].include?(value)
end
commit(action, post, authorization = nil, method = :post) click to toggle source
# File lib/active_merchant/billing/gateways/flex_charge.rb, line 284
def commit(action, post, authorization = nil, method = :post)
  MultiResponse.run do |r|
    r.process { fetch_access_token } unless access_token_valid?
    r.process do
      api_request(action, post, authorization, method).tap do |response|
        response.params.merge!(@options.slice(:access_token, :token_expires)) if @options[:new_credentials]
      end
    end
  end
end
error_code_from(action, response) click to toggle source
# File lib/active_merchant/billing/gateways/flex_charge.rb, line 338
def error_code_from(action, response)
  (response[:statusName] || response[:status]) unless success_from(action, response)
end
fetch_access_token() click to toggle source
# File lib/active_merchant/billing/gateways/flex_charge.rb, line 244
def fetch_access_token
  params = { AppKey: @options[:app_key], AppSecret: @options[:app_secret] }
  response = parse(ssl_post(url(:authenticate), params.to_json, headers))

  @options[:access_token] = response[:accessToken]
  @options[:token_expires] = response[:expires]
  @options[:new_credentials] = true

  Response.new(
    response[:accessToken].present?,
    message_from(response),
    response,
    test: test?,
    error_code: response[:statusCode]
  )
rescue ResponseError => e
  raise OAuthResponseError.new(e)
end
headers() click to toggle source
# File lib/active_merchant/billing/gateways/flex_charge.rb, line 267
def headers
  { 'Content-Type' => 'application/json' }.tap do |headers|
    headers['Authorization'] = "Bearer #{@options[:access_token]}" if @options[:access_token]
  end
end
message_from(response) click to toggle source
# File lib/active_merchant/billing/gateways/flex_charge.rb, line 326
def message_from(response)
  response[:title] || response[:responseMessage] || response[:statusName] || response[:status]
end
names_from_address(address, payment_method) click to toggle source
# File lib/active_merchant/billing/gateways/flex_charge.rb, line 229
def names_from_address(address, payment_method)
  split_names(address[:name]).tap do |names|
    names[0] = payment_method&.first_name unless names[0].present? || payment_method.is_a?(String)
    names[1] = payment_method&.last_name unless names[1].present? || payment_method.is_a?(String)
  end
end
parse(body) click to toggle source
# File lib/active_merchant/billing/gateways/flex_charge.rb, line 273
def parse(body)
  body = '{}' if body.blank?

  JSON.parse(body).with_indifferent_access
rescue JSON::ParserError
  {
    errors: body,
    status: 'Unable to parse JSON response'
  }.with_indifferent_access
end
phone_from(options) click to toggle source
# File lib/active_merchant/billing/gateways/flex_charge.rb, line 236
def phone_from(options)
  options[:phone] || options.dig(:billing_address, :phone_number)
end
success_from(action, response) click to toggle source
# File lib/active_merchant/billing/gateways/flex_charge.rb, line 316
def success_from(action, response)
  case action
  when :store then response.dig(:transaction, :payment_method, :token).present?
  when :inquire then response[:id].present? && SUCCESS_MESSAGES.include?(response[:statusName])
  when :void then response.empty?
  else
    response[:success] && SUCCESS_MESSAGES.include?(response[:status])
  end
end
url(action, id = nil) click to toggle source
# File lib/active_merchant/billing/gateways/flex_charge.rb, line 263
def url(action, id = nil)
  "#{test? ? test_url : live_url}#{ENDPOINTS_MAPPING[action] % id}"
end