KEVIN LIN

Making your ideas come to clickable life!

User profile 4 img?x amz algorithm=aws4 hmac sha256&x amz credential=akiajyw2xiiyzdksbgja%2f20181212%2fus east 1%2fs3%2faws4 request&x amz date=20181212t002603z&x amz expires=900&x amz signedheaders=host&x amz signature=e3294d205f584e1b7d95f7b7900c616f96695a5472a6690a60a91afecea4a888

uTask Work History

uTask Start Date Project Status Manager Feedback

Software development, initially with writing unit tests for an API

Jul 26, 2018

In Progress

zack

N/A

Code Sample

Ruby

Implementing a service to be executed via background job (Resque, SideKiq, DelayedJob) to interface with a payment CGI/API

require 'rack/utils'
class APIProvider::APITransaction
  # Documentation for their API can be found at:
  # http://someapiservice.com/docs/api

  # Currently, all transactions except for those on production are not actually sent to the gateway
  # This can be set by setting the :adapter option to :http or :https on the adapter


  GATEWAY = "http://someapiservice.com/api/"
  CLIENT_VERSION = "Client/Version:2017.Jan"

  attr_accessor :response, :req, :params, :opts
  def initialize(trans_id, **opts)
    @response = nil
    @opts = opts
    @params = {
      "account_id": ENV["ACCOUNT_ID"],
      "code": ENV["TOKEN"],
      "transaction": trans_id
    }
    set_req_headers
  end

  # used to verify that a trans_id is valid and exists in the system.
  def verify_id
    req_params = @params.merge!({
      "pay_type": "C",
      # quiet transaction, nothing is sent to processor themselves
      "tran_type": "Q",
      "amount": "1.00",
      "description": "verification transaction",
    })

    @req.set_form_data(req_params)

    response = send_req(@req)
    response_handler(response)
  end

  def preauth(amount)
    raise ArgumentError,'Cannot be a negative amount' unless amount > 0.00

    req_params = @params.merge!({
        "pay_type": "C",
        "tran_type": "A",
        "amount": amount,
        "description": "pre-auth",
      })
    @req.set_form_data(req_params)

    response = send_req(@req)
    response_handler(response)
  end

  # make a charge
  def charge(amount)
    raise ArgumentError,'Cannot be a negative amount' unless amount > 0.00

    req_params = @params.merge!({
        "pay_type": "C",
        "tran_type": "S",
        "amount": amount,
        "description": "charge",
      })
    @req.set_form_data(req_params)

    response = send_req(@req)
    response_handler(response)
  end


  def capture(amount, orig_id)
    raise ArgumentError, "need preauth info to make a capture" if orig_id.blank?

    req_params = @params.merge!({
        "amount": amount,
        "orig_id": orig_id,
        "pay_type": "C",
        "tran_type": "D",
        "description": "pre-auth capture",
      })
    @req.set_form_data(req_params)

    response = send_req(@req)
    response_handler(response)
  end

  # refund a charge
  # functionality TBD
  def refund

  end

  private

  def send_req(req)
    @req ||= req
    @http.request(@req)
  end

  def response_handler(response)
    case response
    when Net::HTTPSuccess then
      # parse the response body and return the response
      Rack::Utils.parse_nested_query(response.body)
    when Net::HTTPUnknownResponse then
      # Per docs, HTTP 600 codes are usually failure on the user's part.
      return false
    else
      raise Exceptions::GatewayError.new("Could not reach gatewway.", self)
      # admin also notified via the exception handler module
    end
  end

  def set_req_headers(**opts)
    @uri = URI(GATEWAY)
    @req = Net::HTTP::Post.new(@uri)
    @req.initialize_http_header({"User-Agent" => CLIENT_VERSION })
    if set_https?
    # if on production environment use ssl and secure port for real transactions
      @uri.port = 1402
      @uri.scheme = "https"
      @http = Net::HTTP.new(@uri.host, @uri.port)
      @http.use_ssl = true
    else
    # if on any of the test servers, don't actually send anything
      @uri.port = 1401
      @http = Net::HTTP.new(@uri.host, @uri.port)
    end
  end

  def set_https?
    (opts[:adapter] == :https) || (Rails.env.production? && ENV['HEROKU_ENV'] == "production")
  end

Case Study

Code Refactor

Code was very poorly organized and test coverage was bad

Implementing service objects, rather than monolithic model code

Contact Me