class SpookAndPay::Providers::Braintree

Constants

ERROR_CODE_MAPPING

Maps the error codes returned by Braintree to a triple of target, type and field used by the SubmissionError class.

The key is the error code from Braintree. The first entry in the triple is the specific portion of the transaction that has the error. The second is the type of error and the third is the field — if any — it applies to.

FORM_FIELD_NAMES

Attributes

adapter[R]

Public Class Methods

new(env, config) click to toggle source

@param Hash config @option config String :merchant_id @option config String :public_key @option config String :private_key

Calls superclass method SpookAndPay::Providers::Base::new
# File lib/spook_and_pay/providers/braintree.rb, line 18
def initialize(env, config)
  @adapter = SpookAndPay::Adapters::Braintree.new(
    env,
    config[:merchant_id],
    config[:public_key],
    config[:private_key]
  )

  super(env, config)
end

Public Instance Methods

capture_transaction(id) click to toggle source
# File lib/spook_and_pay/providers/braintree.rb, line 110
def capture_transaction(id)
  result = adapter.capture(transaction_id(id))
  generate_result(result)
end
confirm_payment_submission(query_string, opts = {}) click to toggle source

Confirms the submission of payment details to the provider.

@param String query_string @return SpookAndPay::Result

# File lib/spook_and_pay/providers/braintree.rb, line 67
def confirm_payment_submission(query_string, opts = {})
  result = adapter.confirm(query_string)

  case result
  when ::Braintree::SuccessfulResult
    SpookAndPay::Result.new(
      true,
      result,
      :credit_card => extract_credit_card(result.transaction.credit_card_details, true, false),
      :transaction => extract_transaction(result.transaction)
    )
  when ::Braintree::ErrorResult
    SpookAndPay::Result.new(
      false,
      result,
      :credit_card => extract_credit_card(result.params[:transaction][:credit_card], false, false),
      :transaction => extract_transaction(result.params[:transaction]),
      :errors => extract_errors(result)
    )
  end
end
credit_card(id) click to toggle source
# File lib/spook_and_pay/providers/braintree.rb, line 89
def credit_card(id)
  result = adapter.credit_card(id)
  extract_credit_card(result, true, false) if result
end
credit_card_from_transaction(id) click to toggle source
# File lib/spook_and_pay/providers/braintree.rb, line 94
def credit_card_from_transaction(id)
  _id = id.is_a?(String) ? id : id.id
  result = adapter.transaction(_id)
  extract_credit_card(result.credit_card_details, true, false)
end
partially_refund_transaction(id, amount) click to toggle source
# File lib/spook_and_pay/providers/braintree.rb, line 120
def partially_refund_transaction(id, amount)
  result = adapter.partially_refund(transaction_id(id), amount)
  generate_result(result)
end
prepare_payment_submission(redirect_url, opts = {}) click to toggle source

Braintree specific version of this method. Can be used to either authorize a payment — and capture it later — or submit a payment for settlement immediately. This is done via the type param.

Because Braintree accepts payment details and processes payment in a single step, this method must also be provided with an amount.

@param String redirect_url @param Hash opts @option opts [true, false] :vault @option opts [:purchase, :authorize] :type @option opts [String, Numeric] :amount @return Hash

# File lib/spook_and_pay/providers/braintree.rb, line 42
def prepare_payment_submission(redirect_url, opts = {})
  payload = {
    :transaction  => {:type => 'sale', :amount => opts[:amount]},
    :redirect_url => redirect_url
  }

  if opts[:vault]
    (payload[:transaction][:options] ||= {})[:store_in_vault] = true
  end

  if opts[:type] == :purchase
    (payload[:transaction][:options] ||= {})[:submit_for_settlement] = true
  end

  {
    :url            => adapter.transparent_redirect_url,
    :hidden_fields  => {:tr_data => adapter.transaction_data(payload)},
    :field_names    => self.class::FORM_FIELD_NAMES
  }
end
purchase_via_credit_card(id, amount) click to toggle source
# File lib/spook_and_pay/providers/braintree.rb, line 100
def purchase_via_credit_card(id, amount)
  result = adapter.credit_card_purchase(credit_card_id(id), amount)
  generate_result(result)
end
refund_transaction(id) click to toggle source
# File lib/spook_and_pay/providers/braintree.rb, line 115
def refund_transaction(id)
  result = adapter.refund(transaction_id(id))
  generate_result(result)
end
transaction(id) click to toggle source
# File lib/spook_and_pay/providers/braintree.rb, line 105
def transaction(id)
  result = adapter.transaction(id)
  extract_transaction(result) if result
end
void_transaction(id) click to toggle source
# File lib/spook_and_pay/providers/braintree.rb, line 125
def void_transaction(id)
  result = adapter.void(transaction_id(id))
  generate_result(result)
end

Private Instance Methods

card_expired?(month, year) click to toggle source

Checks to see if a credit card has expired.

@param Number month @param Number year @return [true, false]

# File lib/spook_and_pay/providers/braintree.rb, line 235
def card_expired?(month, year)
  now = Time.now
  year < now.year or (year == now.year and month < now.month)
end
coerce_transaction_status(status) click to toggle source

Coerces the status into a value expected by the Transaction class.

@param [String, nil] status @return [String, nil]

# File lib/spook_and_pay/providers/braintree.rb, line 278
def coerce_transaction_status(status)
  case status
  when 'submitted_for_settlement' then 'settling'
  else status
  end
end
coerce_transaction_success(status) click to toggle source

Based on the status of a transaction, make some determination of how of whether or not is is successful.

@param String status @return [true, false]

@todo Expand this to be more robust.

# File lib/spook_and_pay/providers/braintree.rb, line 292
def coerce_transaction_success(status)
  case status
  when 'authorized' then true
  else false
  end
end
extract_credit_card(card, valid, expired) click to toggle source

Extracts credit card details from a payload extracted from a result. It could be either a Hash, Braintree::CreditCard or Braintree::Transaction::CreditCardDetails. BOO!

@param [Hash, Braintree::CreditCard, Braintree::Transaction::CreditCardDetails] card @param [true, false] valid @param [true, false] expired @return SpookAndPay::CreditCard

@todo figure out validity and expiry ourselves

# File lib/spook_and_pay/providers/braintree.rb, line 201
def extract_credit_card(card, valid, expired)
  opts = case card
  when Hash
    {
      :token            => card[:token],
      :card_type        => card[:card_type],
      :number           => card[:last_4],
      :name             => card[:cardholder_name],
      :expiration_month => card[:expiration_month],
      :expiration_year  => card[:expiration_year],
      :expired          => card_expired?(card[:expiration_month].to_i, card[:expiration_year].to_i),
      :valid            => true # We have to assume it's valid, since BT won't say
    }
  else
    {
      :token            => card.token,
      :card_type        => card.card_type,
      :number           => card.last_4,
      :name             => card.cardholder_name,
      :expiration_month => card.expiration_month,
      :expiration_year  => card.expiration_year,
      :expired          => card_expired?(card.expiration_month.to_i, card.expiration_year.to_i),
      :valid            => true # We have to assume it's valid, since BT won't say
    }
  end

  SpookAndPay::CreditCard.new(self, opts.delete(:token), opts)
end
extract_errors(result) click to toggle source

Extracts errors from the collection returned by Brain tree and coerces them into an array of SubmissionError.

@param Braintree:ErrorResult result @return Array<SpookAndPay::Providers::Base::SubmissionError>

# File lib/spook_and_pay/providers/braintree.rb, line 157
def extract_errors(result)
  result.errors.map do |e|
    mapping = ERROR_CODE_MAPPING[e.code]
    if mapping
      SubmissionError.new(*mapping, e)
    else
      SubmissionError.new(:unknown, :unknown, :unknown, e)
    end
  end
end
extract_transaction(result, payload = {}) click to toggle source

Extracts transaction details from whatever payload is passed in. This might be Hash or a Braintree:Transaction.

@param [Hash, Braintree::Transaction] result @param [true, false] successful @param Hash payload @return SpookAndPay::Transaction

@todo Coerce type into what we know is valid

# File lib/spook_and_pay/providers/braintree.rb, line 249
def extract_transaction(result, payload = {})
  case result
  when Hash
    SpookAndPay::Transaction.new(
      self,
      result[:id],
      coerce_transaction_status(result[:status]),
      result,
      :type       => result[:type].to_sym,
      :created_at => result[:created_at],
      :amount     => result[:amount]
    )
  else
    SpookAndPay::Transaction.new(
      self,
      result.id,
      coerce_transaction_status(result.status),
      result,
      :type       => result.type.to_sym,
      :created_at => result.created_at,
      :amount     => result.amount
    )
  end
end
generate_result(result) click to toggle source

A generic method for generating results on actions. It doesn't capture anything action specific i.e. it might need to be replaced later.

@param [Braintree::SuccessfulResult, Braintree:ErrorResult] result @return SpookAndPay::Result

# File lib/spook_and_pay/providers/braintree.rb, line 173
def generate_result(result)
  case result
  when ::Braintree::SuccessfulResult
    SpookAndPay::Result.new(
      true,
      result,
      :credit_card => extract_credit_card(result.transaction.credit_card_details, true, false),
      :transaction => extract_transaction(result.transaction)
    )
  when ::Braintree::ErrorResult
    SpookAndPay::Result.new(
      false,
      result,
      :errors => extract_errors(result)
    )
  end
end