public this repo is viewable by everyone
Description: Ruby wrapper around the Harvest API (http://www.getharvest.com/api)
Clone URL: git://github.com/bricooke/harvest-ruby.git
0.1.1. minimal documentation. support for expense_categories. fix 
duplicates reported in report. support getting the Retry-After
bricooke (author)
about 1 month ago
commit  afcce7c82561f7c1d9c385772aa2e11bea720259
tree    cfc0323dd4cc294fbe6dbc89fd1adb463d42306d
parent  5a5ef6d1f57704f4dec654dd2555c4e9ddf1cbd9
...
5
6
7
8
 
 
 
9
10
11
...
13
14
15
 
 
16
17
18
19
 
 
20
21
22
23
 
 
 
 
 
24
25
26
27
28
29
30
31
32
 
 
 
 
 
 
33
 
 
 
 
 
 
34
35
36
37
38
39
40
41
42
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
44
45
...
50
51
52
 
 
 
53
54
55
...
5
6
7
 
8
9
10
11
12
13
...
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
 
 
 
37
 
 
 
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
 
 
 
 
 
 
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
...
83
84
85
86
87
88
89
90
91
0
@@ -5,7 +5,9 @@ require 'activesupport'
0
 require File.dirname(__FILE__) + '/harvest_entry'
0
 
0
 class Harvest
0
- VERSION = '0.1.0'
0
+ VERSION = '0.1.1'
0
+ @tasks = []
0
+ @expenses = []
0
   
0
   def initialize(domain, email, password)
0
     @domain = domain
0
@@ -13,33 +15,64 @@ class Harvest
0
     @password = password
0
   end
0
 
0
+ # returns all the users created in this Harvest account
0
+ # see http://www.getharvest.com/api/people for data available
0
   def users(params={})
0
     request("/people", params).users
0
   end
0
 
0
+ # returns all the projects created in this Harvest account
0
+ # see http://www.getharvest.com/api/projects for data available
0
   def projects
0
     request("/projects").projects
0
   end
0
 
0
+ # returns all tasks and expenses for a given project or person
0
+ # in the given time period. The expenses and entries are
0
+ # mixed in the same array returned. Use .expense? to determine
0
+ # what type it is. Reference http://www.getharvest.com/api/reporting
0
+ # to get data available for each type
0
   def report(from, to, project_and_or_person_id)
0
     entries = []
0
- if project_and_or_person_id.has_key?(:project_id)
0
- entries += request("/projects/#{project_and_or_person_id[:project_id]}/entries?from=#{from.strftime("%Y%m%d")}&to=#{to.strftime("%Y%m%d")}").day_entries
0
- end
0
     
0
- if project_and_or_person_id.has_key?(:person_id)
0
- entries += request("/people/#{project_and_or_person_id[:person_id]}/entries?from=#{from.strftime("%Y%m%d")}&to=#{to.strftime("%Y%m%d")}").day_entries
0
- end
0
+ %w(entries expenses).each do |type|
0
+ if project_and_or_person_id.has_key?(:project_id)
0
+ t = request("/projects/#{project_and_or_person_id[:project_id]}/#{type}?from=#{from.strftime("%Y%m%d")}&to=#{to.strftime("%Y%m%d")}")
0
+ temp = (type == "entries" ? t.day_entries : t.expenses)
0
+ entries += temp.select {|entry| !(entries.any? {|match| match.id == entry.id })}
0
+ end
0
     
0
+ if project_and_or_person_id.has_key?(:person_id)
0
+ t = request("/people/#{project_and_or_person_id[:person_id]}/#{type}?from=#{from.strftime("%Y%m%d")}&to=#{to.strftime("%Y%m%d")}")
0
+ temp = (type == "entries" ? t.day_entries : t.expenses)
0
+ entries += temp.select {|entry| !(entries.any? {|match| match.id == entry.id })}
0
+ end
0
+ end
0
     entries
0
   end
0
   
0
- def tasks(task_id=nil)
0
- if task_id.nil?
0
- request("/tasks").tasks
0
- else
0
- request("/tasks/#{task_id}")
0
- end
0
+ # returns all tasks and caches the results
0
+ # see http://www.getharvest.com/api/tasks
0
+ def tasks
0
+ @tasks ||= request("/tasks").tasks
0
+ end
0
+
0
+ # return a specific task
0
+ # see http://www.getharvest.com/api/tasks
0
+ def task(id)
0
+ self.tasks.find {|t| t.id.to_i == id.to_i}
0
+ end
0
+
0
+ # returns all expense categories and caches the results
0
+ # see http://www.getharvest.com/api/expenses
0
+ def expense_categories
0
+ @expense_categories ||= request("/expense_categories").expense_categories
0
+ end
0
+
0
+ # returns a specific expense_category
0
+ # see http://www.getharvest.com/api/expenses
0
+ def expense_category(id)
0
+ self.expense_categories.find {|e| e.id.to_i == id.to_i}
0
   end
0
 
0
 private
0
@@ -50,6 +83,9 @@ private
0
     ret = nil
0
     Net::HTTP.new(@domain).start {|http|
0
       response = http.request(request)
0
+ if response.class == Net::HTTPServiceUnavailable
0
+ raise ArgumentError, "API Limit exceeded. Retry after #{response["Retry-After"].to_i/60} minutes."
0
+ end
0
       ret = HarvestEntry.new(XmlSimple.xml_in(response.body))
0
     }
0
     ret
...
15
16
17
 
 
 
 
 
 
 
 
 
18
19
20
...
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
0
@@ -15,6 +15,15 @@ class HarvestEntry
0
     end
0
   end
0
   
0
+ def expense?
0
+ begin
0
+ self.expense_category_id
0
+ true
0
+ rescue
0
+ false
0
+ end
0
+ end
0
+
0
   def method_missing(method, *args)
0
     method = method.to_s.gsub("_", "-").to_sym
0
     

Comments

    No one has commented yet.