class Harvesting::Client

A client for the Harvest API (version 2.0)

Constants

DEFAULT_HOST

Attributes

access_token[RW]
account_id[RW]

Public Class Methods

new(access_token: ENV['HARVEST_ACCESS_TOKEN'], account_id: ENV['HARVEST_ACCOUNT_ID']) click to toggle source

Returns a new instance of `Client`

client = Client.new(access_token: "12345678", account_id: "98764")

@param [Hash] opts the options to create an API client @option opts [String] :access_token Harvest access token @option opts [String] :account_id Harvest account id

# File lib/harvesting/client.rb, line 20
def initialize(access_token: ENV['HARVEST_ACCESS_TOKEN'], account_id: ENV['HARVEST_ACCOUNT_ID'])
  @access_token = access_token.to_s
  @account_id = account_id.to_s

  if @account_id.length == 0 || @access_token.length == 0
    raise ArgumentError.new("Access token and account id are required. Access token: '#{@access_token}'. Account ID: '#{@account_id}'.")
  end
end

Public Instance Methods

clients(opts = {}) click to toggle source

@return [Harvesting::Models::Clients]

# File lib/harvesting/client.rb, line 35
def clients(opts = {})
  Harvesting::Models::Clients.new(get("clients", opts), opts, harvest_client: self)
end
contacts() click to toggle source

@return [Array<Harvesting::Models::Contact>]

# File lib/harvesting/client.rb, line 40
def contacts
  get("contacts")["contacts"].map do |result|
    Harvesting::Models::Contact.new(result, harvest_client: self)
  end
end
create(entity) click to toggle source

Creates an `entity` in your Harvest account.

@param entity [Harvesting::Models::Base] A new record in your Harvest account @return [Harvesting::Models::Base] A subclass of `Harvesting::Models::Base` updated with the response from Harvest

# File lib/harvesting/client.rb, line 89
def create(entity)
  url = "#{DEFAULT_HOST}/#{entity.path}"
  uri = URI(url)
  response = http_response(:post, uri, body: entity.to_hash)
  entity.attributes = JSON.parse(response.body)
  entity
end
delete(entity) click to toggle source

It removes an `entity` from your Harvest account.

@param entity [Harvesting::Models::Base] A record to be removed from your Harvest account @return [Hash] @raise [UnprocessableRequest] When HTTP response is not 200 OK

# File lib/harvesting/client.rb, line 114
def delete(entity)
  url = "#{DEFAULT_HOST}/#{entity.path}"
  uri = URI(url)
  response = http_response(:delete, uri)
  raise UnprocessableRequest.new(response.to_s) unless response.code.to_i == 200
  
  JSON.parse(response.body)
end
get(path, opts = {}) click to toggle source

Performs a GET request and returned the parsed JSON as a Hash.

@param path [String] path to be combined with `DEFAULT_HOST` @param opts [Hash] key/values will get passed as HTTP (GET) parameters @return [Hash]

# File lib/harvesting/client.rb, line 128
def get(path, opts = {})
  url = "#{DEFAULT_HOST}/#{path}"
  url += "?#{opts.map {|k, v| "#{k}=#{v}"}.join("&")}" if opts.any?
  uri = URI(url)
  response = http_response(:get, uri)
  JSON.parse(response.body)
end
invoices(opts = {}) click to toggle source

@return [Array<Harvesting::Models::Invoice>]

# File lib/harvesting/client.rb, line 67
def invoices(opts = {})
  Harvesting::Models::Invoices.new(get("invoices", opts), opts, harvest_client: self)
end
me() click to toggle source

@return [Harvesting::Models::User]

# File lib/harvesting/client.rb, line 30
def me
  Harvesting::Models::User.new(get("users/me"), harvest_client: self)
end
projects(opts = {}) click to toggle source

@return [Harvesting::Models::Projects]

# File lib/harvesting/client.rb, line 52
def projects(opts = {})
  Harvesting::Models::Projects.new(get("projects", opts), opts, harvest_client: self)
end
task_assignments(opts = {}) click to toggle source

@return [Harvesting::Models::ProjectTaskAssignments]

# File lib/harvesting/client.rb, line 79
def task_assignments(opts = {})
  project_id = opts.delete(:project_id)
  path = project_id.nil? ? "task_assignments" : "projects/#{project_id}/task_assignments"
  Harvesting::Models::ProjectTaskAssignments.new(get(path, opts), opts, harvest_client: self)
end
tasks(opts = {}) click to toggle source

@return [Harvesting::Models::Tasks]

# File lib/harvesting/client.rb, line 57
def tasks(opts = {})
  Harvesting::Models::Tasks.new(get("tasks", opts), opts, harvest_client: self)
end
time_entries(opts = {}) click to toggle source

@return [Harvesting::Models::TimeEntries]

# File lib/harvesting/client.rb, line 47
def time_entries(opts = {})
  Harvesting::Models::TimeEntries.new(get("time_entries", opts), opts, harvest_client: self)
end
update(entity) click to toggle source

Updates an `entity` in your Harvest account.

@param entity [Harvesting::Models::Base] An existing record in your Harvest account @return [Harvesting::Models::Base] A subclass of `Harvesting::Models::Base` updated with the response from Harvest

# File lib/harvesting/client.rb, line 101
def update(entity)
  url = "#{DEFAULT_HOST}/#{entity.path}"
  uri = URI(url)
  response = http_response(:patch, uri, body: entity.to_hash)
  entity.attributes = JSON.parse(response.body)
  entity
end
user_assignments(opts = {}) click to toggle source

@return [Harvesting::Models::ProjectUserAssignments]

# File lib/harvesting/client.rb, line 72
def user_assignments(opts = {})
  project_id = opts.delete(:project_id)
  path = project_id.nil? ? "user_assignments" : "projects/#{project_id}/user_assignments"
  Harvesting::Models::ProjectUserAssignments.new(get(path, opts), opts, harvest_client: self)
end
users(opts = {}) click to toggle source

@return [Harvesting::Models::Users]

# File lib/harvesting/client.rb, line 62
def users(opts = {})
  Harvesting::Models::Users.new(get("users", opts), opts, harvest_client: self)
end

Private Instance Methods

auth_error?(response) click to toggle source
# File lib/harvesting/client.rb, line 158
def auth_error?(response)
  response.code.to_i == 403 || response.code.to_i == 401
end
http_response(method, uri, opts = {}) click to toggle source
# File lib/harvesting/client.rb, line 138
def http_response(method, uri, opts = {})
  response = nil

  http = HTTP["User-Agent" => "Harvesting Ruby Gem",
              "Authorization" => "Bearer #{@access_token}",
              "Harvest-Account-ID" => @account_id]
  params = {}
  if opts[:body]
    params[:json] = opts[:body]
  end
  response = http.send(method, uri, params)

  raise Harvesting::AuthenticationError.new(response.to_s) if auth_error?(response)
  raise Harvesting::UnprocessableRequest.new(response.to_s) if response.code.to_i == 422
  raise Harvesting::RequestNotFound.new(uri) if response.code.to_i == 404
  raise Harvesting::RateLimitExceeded.new(response.to_s) if response.code.to_i == 429

  response
end