harvested 0.3.3 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +15 -0
- data/HISTORY +11 -0
- data/README.md +14 -6
- data/Rakefile +13 -31
- data/TODO +2 -0
- data/VERSION +1 -1
- data/examples/user_assignments.rb +1 -1
- data/harvested.gemspec +114 -126
- data/lib/ext/array.rb +52 -0
- data/lib/ext/date.rb +9 -0
- data/lib/ext/hash.rb +17 -0
- data/lib/ext/time.rb +5 -0
- data/lib/harvest/api/account.rb +8 -1
- data/lib/harvest/api/base.rb +32 -10
- data/lib/harvest/api/contacts.rb +1 -1
- data/lib/harvest/api/expenses.rb +3 -4
- data/lib/harvest/api/invoice_categories.rb +26 -0
- data/lib/harvest/api/invoices.rb +16 -0
- data/lib/harvest/api/projects.rb +2 -10
- data/lib/harvest/api/reports.rb +13 -16
- data/lib/harvest/api/task_assignments.rb +8 -6
- data/lib/harvest/api/tasks.rb +1 -1
- data/lib/harvest/api/time.rb +13 -13
- data/lib/harvest/api/user_assignments.rb +7 -5
- data/lib/harvest/base.rb +9 -1
- data/lib/harvest/behavior/activatable.rb +2 -2
- data/lib/harvest/behavior/crud.rb +15 -13
- data/lib/harvest/client.rb +18 -13
- data/lib/harvest/contact.rb +13 -11
- data/lib/harvest/errors.rb +6 -4
- data/lib/harvest/expense.rb +40 -14
- data/lib/harvest/expense_category.rb +10 -9
- data/lib/harvest/hardy_client.rb +1 -1
- data/lib/harvest/invoice.rb +103 -0
- data/lib/harvest/invoice_category.rb +18 -0
- data/lib/harvest/line_item.rb +12 -0
- data/lib/harvest/model.rb +120 -0
- data/lib/harvest/project.rb +55 -26
- data/lib/harvest/rate_limit_status.rb +9 -8
- data/lib/harvest/task.rb +17 -14
- data/lib/harvest/task_assignment.rb +27 -22
- data/lib/harvest/time_entry.rb +32 -30
- data/lib/harvest/user.rb +46 -22
- data/lib/harvest/user_assignment.rb +24 -17
- data/lib/harvested.rb +12 -5
- data/spec/functional/account_spec.rb +17 -0
- data/spec/functional/clients_spec.rb +58 -0
- data/spec/functional/errors_spec.rb +22 -0
- data/spec/functional/expenses_spec.rb +84 -0
- data/spec/functional/hardy_client_spec.rb +33 -0
- data/spec/functional/invoice_spec.rb +67 -0
- data/spec/functional/project_spec.rb +50 -0
- data/spec/functional/reporting_spec.rb +80 -0
- data/spec/functional/tasks_spec.rb +88 -0
- data/spec/functional/time_tracking_spec.rb +53 -0
- data/spec/functional/users_spec.rb +102 -0
- data/spec/harvest/base_spec.rb +1 -1
- data/spec/harvest/credentials_spec.rb +1 -1
- data/spec/harvest/expense_category_spec.rb +5 -0
- data/spec/harvest/expense_spec.rb +8 -5
- data/spec/harvest/invoice_spec.rb +47 -0
- data/spec/harvest/project_spec.rb +11 -0
- data/spec/harvest/task_assignment_spec.rb +4 -4
- data/spec/harvest/task_spec.rb +7 -0
- data/spec/harvest/time_entry_spec.rb +11 -10
- data/spec/harvest/user_assignment_spec.rb +3 -3
- data/spec/harvest/user_spec.rb +3 -1
- data/spec/spec_helper.rb +37 -6
- data/{features → spec}/support/harvest_credentials.example.yml +0 -1
- data/spec/support/harvested_helpers.rb +44 -0
- data/spec/support/json_examples.rb +11 -0
- data/spec/test_rubies +5 -0
- metadata +109 -85
- data/.gitignore +0 -28
- data/features/account.feature +0 -7
- data/features/client_contacts.feature +0 -23
- data/features/clients.feature +0 -29
- data/features/errors.feature +0 -25
- data/features/expense_categories.feature +0 -21
- data/features/expenses.feature +0 -55
- data/features/hardy_client.feature +0 -40
- data/features/projects.feature +0 -39
- data/features/reporting.feature +0 -72
- data/features/step_definitions/account_steps.rb +0 -7
- data/features/step_definitions/assignment_steps.rb +0 -100
- data/features/step_definitions/contact_steps.rb +0 -11
- data/features/step_definitions/debug_steps.rb +0 -3
- data/features/step_definitions/error_steps.rb +0 -113
- data/features/step_definitions/expenses_steps.rb +0 -46
- data/features/step_definitions/harvest_steps.rb +0 -8
- data/features/step_definitions/model_steps.rb +0 -90
- data/features/step_definitions/people_steps.rb +0 -4
- data/features/step_definitions/report_steps.rb +0 -91
- data/features/step_definitions/time_entry_steps.rb +0 -40
- data/features/support/env.rb +0 -37
- data/features/support/error_helpers.rb +0 -18
- data/features/support/fixtures/empty_clients.xml +0 -2
- data/features/support/fixtures/over_limit.xml +0 -8
- data/features/support/fixtures/receipt.png +0 -0
- data/features/support/fixtures/under_limit.xml +0 -8
- data/features/support/harvest_helpers.rb +0 -11
- data/features/support/inflections.rb +0 -9
- data/features/task_assignment.feature +0 -69
- data/features/tasks.feature +0 -25
- data/features/time_tracking.feature +0 -29
- data/features/user_assignments.feature +0 -33
- data/features/users.feature +0 -55
- data/lib/harvest/base_model.rb +0 -73
- data/spec/spec.default.opts +0 -1
data/lib/ext/date.rb
ADDED
data/lib/ext/hash.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# Shamelessly ripped from https://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/hash/keys.rb
|
2
|
+
|
3
|
+
unless Hash.respond_to?(:stringify_keys)
|
4
|
+
class Hash
|
5
|
+
# Return a new hash with all keys converted to strings.
|
6
|
+
def stringify_keys
|
7
|
+
dup.stringify_keys!
|
8
|
+
end
|
9
|
+
|
10
|
+
def stringify_keys!
|
11
|
+
keys.each do |key|
|
12
|
+
self[key.to_s] = delete(key)
|
13
|
+
end
|
14
|
+
self
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/ext/time.rb
ADDED
data/lib/harvest/api/account.rb
CHANGED
@@ -8,7 +8,14 @@ module Harvest
|
|
8
8
|
# @return [Harvest::RateLimitStatus]
|
9
9
|
def rate_limit_status
|
10
10
|
response = request(:get, credentials, '/account/rate_limit_status')
|
11
|
-
Harvest::RateLimitStatus.parse(response.body)
|
11
|
+
Harvest::RateLimitStatus.parse(response.body).first
|
12
|
+
end
|
13
|
+
|
14
|
+
# Returns the current logged in user
|
15
|
+
# @return [Harvest::User]
|
16
|
+
def who_am_i
|
17
|
+
response = request(:get, credentials, '/account/who_am_i')
|
18
|
+
Harvest::User.parse(response.body).first
|
12
19
|
end
|
13
20
|
end
|
14
21
|
end
|
data/lib/harvest/api/base.rb
CHANGED
@@ -2,11 +2,11 @@ module Harvest
|
|
2
2
|
module API
|
3
3
|
class Base
|
4
4
|
attr_reader :credentials
|
5
|
-
|
5
|
+
|
6
6
|
def initialize(credentials)
|
7
7
|
@credentials = credentials
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
10
|
class << self
|
11
11
|
def api_model(klass)
|
12
12
|
class_eval <<-END
|
@@ -16,27 +16,49 @@ module Harvest
|
|
16
16
|
END
|
17
17
|
end
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
protected
|
21
21
|
def request(method, credentials, path, options = {})
|
22
|
-
|
22
|
+
params = {}
|
23
|
+
params[:path] = path
|
24
|
+
params[:options] = options
|
25
|
+
params[:method] = method
|
26
|
+
|
27
|
+
response = HTTParty.send(method, "#{credentials.host}#{path}",
|
28
|
+
:query => options[:query],
|
29
|
+
:body => options[:body],
|
30
|
+
:format => :plain,
|
31
|
+
:headers => {
|
32
|
+
"Accept" => "application/json",
|
33
|
+
"Content-Type" => "application/json; charset=utf-8",
|
34
|
+
"Authorization" => "Basic #{credentials.basic_auth}",
|
35
|
+
"User-Agent" => "Harvestable/#{Harvest::VERSION}",
|
36
|
+
}.update(options[:headers] || {})
|
37
|
+
)
|
38
|
+
|
39
|
+
params[:response] = response.inspect.to_s
|
40
|
+
|
23
41
|
case response.code
|
24
42
|
when 200..201
|
25
43
|
response
|
26
44
|
when 400
|
27
|
-
raise Harvest::BadRequest.new(response)
|
45
|
+
raise Harvest::BadRequest.new(response, params)
|
28
46
|
when 404
|
29
|
-
raise Harvest::NotFound.new(response)
|
47
|
+
raise Harvest::NotFound.new(response, params)
|
30
48
|
when 500
|
31
|
-
raise Harvest::ServerError.new(response)
|
49
|
+
raise Harvest::ServerError.new(response, params)
|
32
50
|
when 502
|
33
|
-
raise Harvest::Unavailable.new(response)
|
51
|
+
raise Harvest::Unavailable.new(response, params)
|
34
52
|
when 503
|
35
|
-
raise Harvest::RateLimited.new(response)
|
53
|
+
raise Harvest::RateLimited.new(response, params)
|
36
54
|
else
|
37
|
-
raise Harvest::InformHarvest.new(response)
|
55
|
+
raise Harvest::InformHarvest.new(response, params)
|
38
56
|
end
|
39
57
|
end
|
58
|
+
|
59
|
+
def of_user_query(user)
|
60
|
+
query = user.nil? ? {} : {"of_user" => user.to_i}
|
61
|
+
end
|
40
62
|
end
|
41
63
|
end
|
42
64
|
end
|
data/lib/harvest/api/contacts.rb
CHANGED
data/lib/harvest/api/expenses.rb
CHANGED
@@ -5,13 +5,12 @@ module Harvest
|
|
5
5
|
|
6
6
|
include Harvest::Behavior::Crud
|
7
7
|
|
8
|
-
def all(date = ::Time.now)
|
8
|
+
def all(date = ::Time.now, user = nil)
|
9
9
|
date = ::Time.parse(date) if String === date
|
10
|
-
response = request(:get, credentials, "#{api_model.api_path}/#{date.yday}/#{date.year}")
|
11
|
-
api_model.parse(response.
|
10
|
+
response = request(:get, credentials, "#{api_model.api_path}/#{date.yday}/#{date.year}", :query => of_user_query(user))
|
11
|
+
api_model.parse(response.parsed_response)
|
12
12
|
end
|
13
13
|
|
14
|
-
|
15
14
|
# This is currently broken, but will come back to it
|
16
15
|
def attach(expense, filename, receipt)
|
17
16
|
body = ""
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Harvest
|
2
|
+
module API
|
3
|
+
class InvoiceCategories < Base
|
4
|
+
api_model Harvest::InvoiceCategory
|
5
|
+
include Harvest::Behavior::Crud
|
6
|
+
|
7
|
+
def find(*)
|
8
|
+
raise "find is unsupported for InvoiceCategories"
|
9
|
+
end
|
10
|
+
|
11
|
+
def create(model)
|
12
|
+
model = api_model.wrap(model)
|
13
|
+
response = request(:post, credentials, "#{api_model.api_path}", :body => model.to_json)
|
14
|
+
id = response.headers["location"].match(/\/.*\/(\d+)/)[1]
|
15
|
+
all.detect {|c| c.id == id.to_i }
|
16
|
+
end
|
17
|
+
|
18
|
+
def update(model, user = nil)
|
19
|
+
model = api_model.wrap(model)
|
20
|
+
request(:put, credentials, "#{api_model.api_path}/#{model.to_i}", :body => model.to_json, :query => of_user_query(user))
|
21
|
+
all.detect {|c| c.id == model.id }
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Harvest
|
2
|
+
module API
|
3
|
+
class Invoices < Base
|
4
|
+
api_model Harvest::Invoice
|
5
|
+
include Harvest::Behavior::Crud
|
6
|
+
|
7
|
+
def create(*)
|
8
|
+
raise "Creating and updating invoices are not implemented due to API issues"
|
9
|
+
end
|
10
|
+
|
11
|
+
def update(*)
|
12
|
+
raise "Creating and updating invoices are not implemented due to API issues"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/harvest/api/projects.rb
CHANGED
@@ -13,8 +13,8 @@ module Harvest
|
|
13
13
|
#
|
14
14
|
# @return [Harvest::Project]
|
15
15
|
def create_task(project, task_name)
|
16
|
-
response = request(:post, credentials, "/projects/#{project.to_i}/task_assignments/add_with_create_new_task", :body =>
|
17
|
-
id = response.headers["location"].
|
16
|
+
response = request(:post, credentials, "/projects/#{project.to_i}/task_assignments/add_with_create_new_task", :body => {"task" => {"name" => task_name}}.to_json)
|
17
|
+
id = response.headers["location"].match(/\/.*\/(\d+)\/.*\/(\d+)/)[1]
|
18
18
|
find(id)
|
19
19
|
end
|
20
20
|
|
@@ -41,14 +41,6 @@ module Harvest
|
|
41
41
|
end
|
42
42
|
project
|
43
43
|
end
|
44
|
-
|
45
|
-
private
|
46
|
-
def task_xml(name)
|
47
|
-
builder = Builder::XmlMarkup.new
|
48
|
-
builder.task do |t|
|
49
|
-
t.name(name)
|
50
|
-
end
|
51
|
-
end
|
52
44
|
end
|
53
45
|
end
|
54
46
|
end
|
data/lib/harvest/api/reports.rb
CHANGED
@@ -2,38 +2,35 @@ module Harvest
|
|
2
2
|
module API
|
3
3
|
class Reports < Base
|
4
4
|
|
5
|
-
def time_by_project(project, start_date, end_date,
|
5
|
+
def time_by_project(project, start_date, end_date, options = {})
|
6
6
|
query = {:from => start_date.strftime("%Y%m%d"), :to => end_date.strftime("%Y%m%d")}
|
7
|
-
query[:user_id] = user.to_i if user
|
7
|
+
query[:user_id] = options[:user].to_i if options[:user]
|
8
|
+
query[:billable] = (options[:billable] ? "yes" : "no") unless options[:billable].nil?
|
8
9
|
|
9
10
|
response = request(:get, credentials, "/projects/#{project.to_i}/entries", :query => query)
|
10
|
-
Harvest::TimeEntry.parse(
|
11
|
+
Harvest::TimeEntry.parse(JSON.parse(response.body).map {|h| h["day_entry"]})
|
11
12
|
end
|
12
13
|
|
13
|
-
def time_by_user(user, start_date, end_date,
|
14
|
+
def time_by_user(user, start_date, end_date, options = {})
|
14
15
|
query = {:from => start_date.strftime("%Y%m%d"), :to => end_date.strftime("%Y%m%d")}
|
15
|
-
query[:project_id] = project.to_i if project
|
16
|
+
query[:project_id] = options[:project].to_i if options[:project]
|
17
|
+
query[:billable] = (options[:billable] ? "yes" : "no") unless options[:billable].nil?
|
16
18
|
|
17
19
|
response = request(:get, credentials, "/people/#{user.to_i}/entries", :query => query)
|
18
|
-
Harvest::TimeEntry.parse(
|
20
|
+
Harvest::TimeEntry.parse(JSON.parse(response.body).map {|h| h["day_entry"]})
|
19
21
|
end
|
20
22
|
|
21
23
|
def expenses_by_user(user, start_date, end_date)
|
22
24
|
query = {:from => start_date.strftime("%Y%m%d"), :to => end_date.strftime("%Y%m%d")}
|
23
25
|
|
24
26
|
response = request(:get, credentials, "/people/#{user.to_i}/expenses", :query => query)
|
25
|
-
Harvest::Expense.parse(response.
|
27
|
+
Harvest::Expense.parse(response.parsed_response)
|
26
28
|
end
|
27
29
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
%w(day-entry adjustment-record created-at project-id spent-at task-id timer-started-at updated-at user-id).each do |dash_field|
|
33
|
-
xml = xml.gsub(dash_field, dash_field.gsub("-", "_"))
|
34
|
-
end
|
35
|
-
xml
|
36
|
-
end
|
30
|
+
def projects_by_client(client)
|
31
|
+
response = request(:get, credentials, "/projects?client=#{client.to_i}")
|
32
|
+
Harvest::Project.parse(response.parsed_response)
|
33
|
+
end
|
37
34
|
end
|
38
35
|
end
|
39
36
|
end
|
@@ -4,27 +4,29 @@ module Harvest
|
|
4
4
|
|
5
5
|
def all(project)
|
6
6
|
response = request(:get, credentials, "/projects/#{project.to_i}/task_assignments")
|
7
|
-
Harvest::TaskAssignment.parse(response.
|
7
|
+
Harvest::TaskAssignment.parse(response.parsed_response)
|
8
8
|
end
|
9
9
|
|
10
10
|
def find(project, id)
|
11
11
|
response = request(:get, credentials, "/projects/#{project.to_i}/task_assignments/#{id}")
|
12
|
-
Harvest::TaskAssignment.parse(response.
|
12
|
+
Harvest::TaskAssignment.parse(response.parsed_response).first
|
13
13
|
end
|
14
14
|
|
15
15
|
def create(task_assignment)
|
16
|
-
|
17
|
-
|
16
|
+
task_assignment = Harvest::TaskAssignment.wrap(task_assignment)
|
17
|
+
response = request(:post, credentials, "/projects/#{task_assignment.project_id}/task_assignments", :body => task_assignment.task_as_json.to_json)
|
18
|
+
id = response.headers["location"].match(/\/.*\/(\d+)\/.*\/(\d+)/)[2]
|
18
19
|
find(task_assignment.project_id, id)
|
19
20
|
end
|
20
21
|
|
21
22
|
def update(task_assignment)
|
22
|
-
|
23
|
+
task_assignment = Harvest::TaskAssignment.wrap(task_assignment)
|
24
|
+
request(:put, credentials, "/projects/#{task_assignment.project_id}/task_assignments/#{task_assignment.to_i}", :body => task_assignment.to_json)
|
23
25
|
find(task_assignment.project_id, task_assignment.id)
|
24
26
|
end
|
25
27
|
|
26
28
|
def delete(task_assignment)
|
27
|
-
request(:delete, credentials, "/projects/#{task_assignment.project_id}/task_assignments/#{task_assignment.to_i}")
|
29
|
+
response = request(:delete, credentials, "/projects/#{task_assignment.project_id}/task_assignments/#{task_assignment.to_i}")
|
28
30
|
task_assignment.id
|
29
31
|
end
|
30
32
|
end
|
data/lib/harvest/api/tasks.rb
CHANGED
data/lib/harvest/api/time.rb
CHANGED
@@ -2,29 +2,29 @@ module Harvest
|
|
2
2
|
module API
|
3
3
|
class Time < Base
|
4
4
|
|
5
|
-
def find(id)
|
6
|
-
response = request(:get, credentials, "/daily/show/#{id}")
|
7
|
-
Harvest::TimeEntry.parse(response.
|
5
|
+
def find(id, user = nil)
|
6
|
+
response = request(:get, credentials, "/daily/show/#{id.to_i}", :query => of_user_query(user))
|
7
|
+
Harvest::TimeEntry.parse(response.parsed_response).first
|
8
8
|
end
|
9
9
|
|
10
|
-
def all(date = ::Time.now)
|
10
|
+
def all(date = ::Time.now, user = nil)
|
11
11
|
date = ::Time.parse(date) if String === date
|
12
|
-
response = request(:get, credentials, "/daily/#{date.yday}/#{date.year}")
|
13
|
-
Harvest::TimeEntry.parse(response.body)
|
12
|
+
response = request(:get, credentials, "/daily/#{date.yday}/#{date.year}", :query => of_user_query(user))
|
13
|
+
Harvest::TimeEntry.parse(JSON.parse(response.body)["day_entries"])
|
14
14
|
end
|
15
15
|
|
16
16
|
def create(entry)
|
17
|
-
response = request(:post, credentials, '/daily/add', :body => entry.
|
18
|
-
Harvest::TimeEntry.parse(response.
|
17
|
+
response = request(:post, credentials, '/daily/add', :body => entry.to_json)
|
18
|
+
Harvest::TimeEntry.parse(response.parsed_response).first
|
19
19
|
end
|
20
20
|
|
21
|
-
def update(entry)
|
22
|
-
request(:put, credentials, "/daily/update/#{entry.to_i}", :body => entry.
|
23
|
-
find(entry.id)
|
21
|
+
def update(entry, user = nil)
|
22
|
+
request(:put, credentials, "/daily/update/#{entry.to_i}", :body => entry.to_json, :query => of_user_query(user))
|
23
|
+
find(entry.id, user)
|
24
24
|
end
|
25
25
|
|
26
|
-
def delete(entry)
|
27
|
-
request(:delete, credentials, "/daily/delete/#{entry.to_i}")
|
26
|
+
def delete(entry, user = nil)
|
27
|
+
request(:delete, credentials, "/daily/delete/#{entry.to_i}", :query => of_user_query(user))
|
28
28
|
entry.id
|
29
29
|
end
|
30
30
|
end
|
@@ -4,22 +4,24 @@ module Harvest
|
|
4
4
|
|
5
5
|
def all(project)
|
6
6
|
response = request(:get, credentials, "/projects/#{project.to_i}/user_assignments")
|
7
|
-
Harvest::UserAssignment.parse(response.
|
7
|
+
Harvest::UserAssignment.parse(response.parsed_response)
|
8
8
|
end
|
9
9
|
|
10
10
|
def find(project, id)
|
11
11
|
response = request(:get, credentials, "/projects/#{project.to_i}/user_assignments/#{id}")
|
12
|
-
Harvest::UserAssignment.parse(response.
|
12
|
+
Harvest::UserAssignment.parse(response.parsed_response).first
|
13
13
|
end
|
14
14
|
|
15
15
|
def create(user_assignment)
|
16
|
-
|
17
|
-
|
16
|
+
user_assignment = Harvest::UserAssignment.wrap(user_assignment)
|
17
|
+
response = request(:post, credentials, "/projects/#{user_assignment.project_id}/user_assignments", :body => user_assignment.user_as_json.to_json)
|
18
|
+
id = response.headers["location"].match(/\/.*\/(\d+)\/.*\/(\d+)/)[2]
|
18
19
|
find(user_assignment.project_id, id)
|
19
20
|
end
|
20
21
|
|
21
22
|
def update(user_assignment)
|
22
|
-
|
23
|
+
user_assignment = Harvest::UserAssignment.wrap(user_assignment)
|
24
|
+
request(:put, credentials, "/projects/#{user_assignment.project_id}/user_assignments/#{user_assignment.id}", :body => user_assignment.to_json)
|
23
25
|
find(user_assignment.project_id, user_assignment.id)
|
24
26
|
end
|
25
27
|
|
data/lib/harvest/base.rb
CHANGED
@@ -133,7 +133,7 @@ module Harvest
|
|
133
133
|
#
|
134
134
|
# harvest.users.find(100) # Returns the user with id = 100
|
135
135
|
#
|
136
|
-
# user = Harvest::User.new(:first_name => 'Edgar', :last_name => 'Ruth', :email => 'edgar@ruth.com', :password => 'mypassword', :
|
136
|
+
# user = Harvest::User.new(:first_name => 'Edgar', :last_name => 'Ruth', :email => 'edgar@ruth.com', :password => 'mypassword', :timezone => :cst, :admin => false, :telephone => '444-4444')
|
137
137
|
# saved_user = harvest.users.create(user) # returns a saved version of Harvest::User
|
138
138
|
#
|
139
139
|
# user = harvest.users.find(205)
|
@@ -254,5 +254,13 @@ module Harvest
|
|
254
254
|
def reports
|
255
255
|
@reports ||= Harvest::API::Reports.new(credentials)
|
256
256
|
end
|
257
|
+
|
258
|
+
def invoice_categories
|
259
|
+
@invoice_categories ||= Harvest::API::InvoiceCategories.new(credentials)
|
260
|
+
end
|
261
|
+
|
262
|
+
def invoices
|
263
|
+
@invoices ||= Harvest::API::Invoices.new(credentials)
|
264
|
+
end
|
257
265
|
end
|
258
266
|
end
|
@@ -10,7 +10,7 @@ module Harvest
|
|
10
10
|
def deactivate(model)
|
11
11
|
if model.active?
|
12
12
|
request(:post, credentials, "#{api_model.api_path}/#{model.to_i}/toggle")
|
13
|
-
model.
|
13
|
+
model.is_active = false
|
14
14
|
end
|
15
15
|
model
|
16
16
|
end
|
@@ -22,7 +22,7 @@ module Harvest
|
|
22
22
|
def activate(model)
|
23
23
|
if !model.active?
|
24
24
|
request(:post, credentials, "#{api_model.api_path}/#{model.to_i}/toggle")
|
25
|
-
model.
|
25
|
+
model.is_active = true
|
26
26
|
end
|
27
27
|
model
|
28
28
|
end
|
@@ -3,9 +3,9 @@ module Harvest
|
|
3
3
|
module Crud
|
4
4
|
# Retrieves all items
|
5
5
|
# @return [Array<Harvest::BaseModel>] an array of models depending on where you're calling it from (e.g. [Harvest::Client] from Harvest::Base#clients)
|
6
|
-
def all
|
7
|
-
response = request(:get, credentials, api_model.api_path)
|
8
|
-
api_model.parse(response.
|
6
|
+
def all(user = nil)
|
7
|
+
response = request(:get, credentials, api_model.api_path, :query => of_user_query(user))
|
8
|
+
api_model.parse(response.parsed_response)
|
9
9
|
end
|
10
10
|
|
11
11
|
# Retrieves an item by id
|
@@ -17,25 +17,27 @@ module Harvest
|
|
17
17
|
# @param [Harvest::BaseModel] id you can pass a model and it will return a refreshed version
|
18
18
|
#
|
19
19
|
# @return [Harvest::BaseModel] the model depends on where you're calling it from (e.g. Harvest::Client from Harvest::Base#clients)
|
20
|
-
def find(id)
|
21
|
-
response = request(:get, credentials, "#{api_model.api_path}/#{id}")
|
22
|
-
api_model.parse(response.
|
20
|
+
def find(id, user = nil)
|
21
|
+
response = request(:get, credentials, "#{api_model.api_path}/#{id}", :query => of_user_query(user))
|
22
|
+
api_model.parse(response.parsed_response).first
|
23
23
|
end
|
24
24
|
|
25
25
|
# Creates an item
|
26
26
|
# @param [Harvest::BaseModel] model the item you want to create
|
27
27
|
# @return [Harvest::BaseModel] the created model depending on where you're calling it from (e.g. Harvest::Client from Harvest::Base#clients)
|
28
28
|
def create(model)
|
29
|
-
|
30
|
-
|
31
|
-
|
29
|
+
model = api_model.wrap(model)
|
30
|
+
response = request(:post, credentials, "#{api_model.api_path}", :body => model.to_json)
|
31
|
+
id = response.headers["location"].match(/\/.*\/(\d+)/)[1]
|
32
|
+
find(id, model.impersonated_user_id)
|
32
33
|
end
|
33
34
|
|
34
35
|
# Updates an item
|
35
36
|
# @param [Harvest::BaseModel] model the model you want to update
|
36
37
|
# @return [Harvest::BaseModel] the created model depending on where you're calling it from (e.g. Harvest::Client from Harvest::Base#clients)
|
37
|
-
def update(model)
|
38
|
-
|
38
|
+
def update(model, user = nil)
|
39
|
+
model = api_model.wrap(model)
|
40
|
+
request(:put, credentials, "#{api_model.api_path}/#{model.to_i}", :body => model.to_json, :query => of_user_query(user))
|
39
41
|
find(model.id)
|
40
42
|
end
|
41
43
|
|
@@ -48,8 +50,8 @@ module Harvest
|
|
48
50
|
# @param [String] id the String version of the id of the item you want to delete
|
49
51
|
#
|
50
52
|
# @return [Integer] the id of the item deleted
|
51
|
-
def delete(model)
|
52
|
-
request(:delete, credentials, "#{api_model.api_path}/#{model.to_i}")
|
53
|
+
def delete(model, user = nil)
|
54
|
+
request(:delete, credentials, "#{api_model.api_path}/#{model.to_i}", :query => of_user_query(user))
|
53
55
|
model.to_i
|
54
56
|
end
|
55
57
|
end
|