harvested 0.6.2 → 0.6.3

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/lib/harvest/base.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  module Harvest
2
2
  class Base
3
3
  attr_reader :request, :credentials
4
-
4
+
5
5
  # @see Harvest.client
6
6
  # @see Harvest.hardy_client
7
7
  def initialize(subdomain, username, password, options = {})
@@ -9,7 +9,7 @@ module Harvest
9
9
  @credentials = Credentials.new(subdomain, username, password, options[:ssl])
10
10
  raise InvalidCredentials unless credentials.valid?
11
11
  end
12
-
12
+
13
13
  # All API actions surrounding accounts
14
14
  #
15
15
  # == Examples
@@ -19,76 +19,76 @@ module Harvest
19
19
  def account
20
20
  @account ||= Harvest::API::Account.new(credentials)
21
21
  end
22
-
22
+
23
23
  # All API Actions surrounding Clients
24
- #
24
+ #
25
25
  # == Examples
26
26
  # harvest.clients.all() # Returns all clients in the system
27
- #
27
+ #
28
28
  # harvest.clients.find(100) # Returns the client with id = 100
29
- #
29
+ #
30
30
  # client = Harvest::Client.new(:name => 'SuprCorp')
31
31
  # saved_client = harvest.clients.create(client) # returns a saved version of Harvest::Client
32
- #
32
+ #
33
33
  # client = harvest.clients.find(205)
34
34
  # client.name = 'SuprCorp LTD.'
35
35
  # updated_client = harvest.clients.update(client) # returns an updated version of Harvest::Client
36
- #
36
+ #
37
37
  # client = harvest.clients.find(205)
38
38
  # harvest.clients.delete(client) # returns 205
39
- #
39
+ #
40
40
  # client = harvest.clients.find(301)
41
41
  # deactivated_client = harvest.clients.deactivate(client) # returns an updated deactivated client
42
42
  # activated_client = harvest.clients.activate(client) # returns an updated activated client
43
- #
43
+ #
44
44
  # @see Harvest::Behavior::Crud
45
45
  # @see Harvest::Behavior::Activatable
46
46
  # @return [Harvest::API::Clients]
47
47
  def clients
48
48
  @clients ||= Harvest::API::Clients.new(credentials)
49
49
  end
50
-
50
+
51
51
  # All API Actions surrounding Client Contacts
52
- #
52
+ #
53
53
  # == Examples
54
54
  # harvest.contacts.all() # Returns all contacts in the system
55
55
  # harvest.contacts.all(10) # Returns all contacts for the client id=10 in the system
56
- #
56
+ #
57
57
  # harvest.contacts.find(100) # Returns the contact with id = 100
58
- #
58
+ #
59
59
  # contact = Harvest::Contact.new(:first_name => 'Jane', :last_name => 'Doe', :client_id => 10)
60
60
  # saved_contact = harvest.contacts.create(contact) # returns a saved version of Harvest::Contact
61
- #
61
+ #
62
62
  # contact = harvest.contacts.find(205)
63
63
  # contact.first_name = 'Jilly'
64
64
  # updated_contact = harvest.contacts.update(contact) # returns an updated version of Harvest::Contact
65
- #
65
+ #
66
66
  # contact = harvest.contacts.find(205)
67
67
  # harvest.contacts.delete(contact) # returns 205
68
- #
68
+ #
69
69
  # @see Harvest::Behavior::Crud
70
70
  # @return [Harvest::API::Contacts]
71
71
  def contacts
72
72
  @contacts ||= Harvest::API::Contacts.new(credentials)
73
73
  end
74
-
74
+
75
75
  # All API Actions surrounding Projects
76
- #
76
+ #
77
77
  # == Examples
78
78
  # harvest.projects.all() # Returns all projects in the system
79
- #
79
+ #
80
80
  # harvest.projects.find(100) # Returns the project with id = 100
81
- #
81
+ #
82
82
  # project = Harvest::Project.new(:name => 'SuprGlu' :client_id => 10)
83
83
  # saved_project = harvest.projects.create(project) # returns a saved version of Harvest::Project
84
- #
84
+ #
85
85
  # project = harvest.projects.find(205)
86
86
  # project.name = 'SuprSticky'
87
87
  # updated_project = harvest.projects.update(project) # returns an updated version of Harvest::Project
88
- #
88
+ #
89
89
  # project = harvest.project.find(205)
90
90
  # harvest.projects.delete(project) # returns 205
91
- #
91
+ #
92
92
  # project = harvest.projects.find(301)
93
93
  # deactivated_project = harvest.projects.deactivate(project) # returns an updated deactivated project
94
94
  # activated_project = harvest.projects.activate(project) # returns an updated activated project
@@ -102,67 +102,67 @@ module Harvest
102
102
  def projects
103
103
  @projects ||= Harvest::API::Projects.new(credentials)
104
104
  end
105
-
105
+
106
106
  # All API Actions surrounding Tasks
107
- #
107
+ #
108
108
  # == Examples
109
109
  # harvest.tasks.all() # Returns all tasks in the system
110
- #
110
+ #
111
111
  # harvest.tasks.find(100) # Returns the task with id = 100
112
- #
112
+ #
113
113
  # task = Harvest::Task.new(:name => 'Server Administration' :default => true)
114
114
  # saved_task = harvest.tasks.create(task) # returns a saved version of Harvest::Task
115
- #
115
+ #
116
116
  # task = harvest.tasks.find(205)
117
117
  # task.name = 'Server Administration'
118
118
  # updated_task = harvest.tasks.update(task) # returns an updated version of Harvest::Task
119
- #
119
+ #
120
120
  # task = harvest.task.find(205)
121
121
  # harvest.tasks.delete(task) # returns 205
122
- #
122
+ #
123
123
  # @see Harvest::Behavior::Crud
124
124
  # @return [Harvest::API::Tasks]
125
125
  def tasks
126
126
  @tasks ||= Harvest::API::Tasks.new(credentials)
127
127
  end
128
-
128
+
129
129
  # All API Actions surrounding Users
130
- #
130
+ #
131
131
  # == Examples
132
132
  # harvest.users.all() # Returns all users in the system
133
- #
133
+ #
134
134
  # harvest.users.find(100) # Returns the user with id = 100
135
- #
135
+ #
136
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)
140
140
  # user.email = 'edgar@ruth.com'
141
141
  # updated_user = harvest.users.update(user) # returns an updated version of Harvest::User
142
- #
142
+ #
143
143
  # user = harvest.users.find(205)
144
144
  # harvest.users.delete(user) # returns 205
145
- #
145
+ #
146
146
  # user = harvest.users.find(301)
147
147
  # deactivated_user = harvest.users.deactivate(user) # returns an updated deactivated user
148
148
  # activated_user = harvest.users.activate(user) # returns an updated activated user
149
- #
149
+ #
150
150
  # user = harvest.users.find(401)
151
151
  # harvest.users.reset_password(user) # will trigger the reset password feature of harvest and shoot the user an email
152
- #
152
+ #
153
153
  # @see Harvest::Behavior::Crud
154
154
  # @see Harvest::Behavior::Activatable
155
155
  # @return [Harvest::API::Users]
156
156
  def users
157
157
  @users ||= Harvest::API::Users.new(credentials)
158
158
  end
159
-
159
+
160
160
  # All API Actions surrounding assigning tasks to projects
161
- #
161
+ #
162
162
  # == Examples
163
163
  # project = harvest.projects.find(101)
164
164
  # harvest.task_assignments.all(project) # returns all tasks assigned to the project (as Harvest::TaskAssignment)
165
- #
165
+ #
166
166
  # project = harvest.projects.find(201)
167
167
  # harvest.task_assignments.find(project, 5) # returns the task assignment with ID 5 that is assigned to the project
168
168
  #
@@ -184,13 +184,13 @@ module Harvest
184
184
  def task_assignments
185
185
  @task_assignments ||= Harvest::API::TaskAssignments.new(credentials)
186
186
  end
187
-
187
+
188
188
  # All API Actions surrounding assigning users to projects
189
- #
189
+ #
190
190
  # == Examples
191
191
  # project = harvest.projects.find(101)
192
192
  # harvest.user_assignments.all(project) # returns all users assigned to the project (as Harvest::UserAssignment)
193
- #
193
+ #
194
194
  # project = harvest.projects.find(201)
195
195
  # harvest.user_assignments.find(project, 5) # returns the user assignment with ID 5 that is assigned to the project
196
196
  #
@@ -212,21 +212,21 @@ module Harvest
212
212
  def user_assignments
213
213
  @user_assignments ||= Harvest::API::UserAssignments.new(credentials)
214
214
  end
215
-
215
+
216
216
  # All API Actions surrounding managing expense categories
217
217
  #
218
218
  # == Examples
219
219
  # harvest.expense_categories.all() # Returns all expense categories in the system
220
- #
220
+ #
221
221
  # harvest.expense_categories.find(100) # Returns the expense category with id = 100
222
- #
222
+ #
223
223
  # category = Harvest::ExpenseCategory.new(:name => 'Mileage', :unit_price => 0.485)
224
224
  # saved_category = harvest.expense_categories.create(category) # returns a saved version of Harvest::ExpenseCategory
225
- #
225
+ #
226
226
  # category = harvest.clients.find(205)
227
227
  # category.name = 'Travel'
228
228
  # updated_category = harvest.expense_categories.update(category) # returns an updated version of Harvest::ExpenseCategory
229
- #
229
+ #
230
230
  # category = harvest.expense_categories.find(205)
231
231
  # harvest.expense_categories.delete(category) # returns 205
232
232
  #
@@ -235,22 +235,22 @@ module Harvest
235
235
  def expense_categories
236
236
  @expense_categories ||= Harvest::API::ExpenseCategories.new(credentials)
237
237
  end
238
-
238
+
239
239
  # All API Actions surrounding expenses
240
240
  #
241
241
  # == Examples
242
242
  # harvest.expenses.all() # Returns all expenses for the current week
243
243
  # harvest.expenses.all(Time.parse('11/12/2009')) # returns all expenses for the week of 11/12/2009
244
- #
244
+ #
245
245
  # harvest.expenses.find(100) # Returns the expense with id = 100
246
246
  def expenses
247
247
  @expenses ||= Harvest::API::Expenses.new(credentials)
248
248
  end
249
-
249
+
250
250
  def time
251
251
  @time ||= Harvest::API::Time.new(credentials)
252
252
  end
253
-
253
+
254
254
  def reports
255
255
  @reports ||= Harvest::API::Reports.new(credentials)
256
256
  end
@@ -262,5 +262,27 @@ module Harvest
262
262
  def invoices
263
263
  @invoices ||= Harvest::API::Invoices.new(credentials)
264
264
  end
265
+
266
+ # All API Actions surrounding invoice payments
267
+ #
268
+ # == Examples
269
+ # invoice = harvest.invoices.find(100)
270
+ # harvest.invoice_payments.all(invoice) # returns all payments for the invoice (as Harvest::InvoicePayment)
271
+ #
272
+ # invoice = harvest.invoices.find(100)
273
+ # harvest.invoice_payments.find(invoice, 5) # returns the payment with ID 5 that is assigned to the invoice
274
+ #
275
+ # invoice = harvest.invoices.find(100)
276
+ # payment = Harvest::InvoicePayment.new(:invoice_id => invoice.id)
277
+ # saved_payment = harvest.invoice_payments.create(payment) # returns a saved version of the payment
278
+ #
279
+ # invoice = harvest.invoices.find(100)
280
+ # payment = harvest.invoice_payments.find(invoice, 5)
281
+ # harvest.invoice_payments.delete(payment) # returns 5
282
+ #
283
+ # @return [Harvest::API::InvoicePayments]
284
+ def invoice_payments
285
+ @invoice_payments ||= Harvest::API::InvoicePayments.new(credentials)
286
+ end
265
287
  end
266
- end
288
+ end
@@ -19,6 +19,7 @@ module Harvest
19
19
  #
20
20
  # @return [Harvest::BaseModel] the model depends on where you're calling it from (e.g. Harvest::Client from Harvest::Base#clients)
21
21
  def find(id, user = nil)
22
+ raise "id required" unless id
22
23
  response = request(:get, credentials, "#{api_model.api_path}/#{id}", :query => of_user_query(user))
23
24
  api_model.parse(response.parsed_response).first
24
25
  end
@@ -57,4 +58,4 @@ module Harvest
57
58
  end
58
59
  end
59
60
  end
60
- end
61
+ end
@@ -13,12 +13,12 @@ module Harvest
13
13
  end
14
14
 
15
15
  def spent_at=(date)
16
- self["spent_at"] = (String === date ? Time.parse(date) : date)
16
+ self["spent_at"] = Date.parse(date.to_s)
17
17
  end
18
18
 
19
19
  def as_json(args = {})
20
20
  super(args).to_hash.stringify_keys.tap do |hash|
21
- hash[json_root].update("spent_at" => (spent_at.nil? ? nil : spent_at.to_time.xmlschema))
21
+ hash[json_root].update("spent_at" => (spent_at.nil? ? nil : spent_at.xmlschema))
22
22
  hash[json_root].delete("has_receipt")
23
23
  hash[json_root].delete("receipt_url")
24
24
  end
@@ -1,4 +1,41 @@
1
1
  module Harvest
2
+
3
+ # == Fields
4
+ # [+due_at+] when the invoice is due
5
+ # [+due_at_human_format+] when the invoice is due in human representation (e.g., due upon receipt) overrides +due_at+
6
+ # [+client_id+] (REQUIRED) the client id of the invoice
7
+ # [+currency+] the invoice currency
8
+ # [+issued_at+] when the invoice was issued
9
+ # [+subject+] subject line for the invoice
10
+ # [+notes+] notes on the invoice
11
+ # [+number+] invoice number
12
+ # [+kind+] (REQUIRED) the type of the invoice +free_form|project|task|people|detailed+
13
+ # [+projects_to_invoice+] comma separated project ids to gather data from
14
+ # [+import_hours+] import hours from +project|task|people|detailed+ one of +yes|no+
15
+ # [+import_expenses+] import expenses from +project|task|people|detailed+ one of +yes|no+
16
+ # [+period_start+] start of the invoice period
17
+ # [+period_end+] end of the invoice period
18
+ # [+expense_period_start+] start of the invoice expense period
19
+ # [+expense_period_end+] end of the invoice expense period
20
+ # [+csv_line_items+] csv formatted line items for the invoice +kind,description,quantity,unit_price,amount,taxed,taxed2,project_id+
21
+ # [+created_at+] (READONLY) when the invoice was created
22
+ # [+updated_at+] (READONLY) when the invoice was updated
23
+ # [+id+] (READONLY) the id of the invoice
24
+ # [+amount+] (READONLY) the amount of the invoice
25
+ # [+due_amount+] (READONLY) the amount due on the invoice
26
+ # [+created_by_id+] who created the invoice
27
+ # [+purchase_order+] purchase order number/text
28
+ # [+client_key+] unique client key
29
+ # [+state+] (READONLY) state of the invoice
30
+ # [+tax+] applied tax percentage
31
+ # [+tax2+] applied tax 2 percentage
32
+ # [+tax_amount+] amount to tax
33
+ # [+tax_amount2+] amount to tax 2
34
+ # [+discount_amount+] discount amount to apply to invoice
35
+ # [+discount_type+] discount type
36
+ # [+recurring_invoice_id+] the id of the original invoice
37
+ # [+estimate_id+] id of the related estimate
38
+ # [+retainer_id+] id of the related retainer
2
39
  class Invoice < Hashie::Mash
3
40
  include Harvest::Model
4
41
 
@@ -6,14 +43,24 @@ module Harvest
6
43
 
7
44
  attr_reader :line_items
8
45
 
9
- def self.json_root; "doc"; end
10
- # skip_json_root true
46
+ def self.parse(json)
47
+ parsed = String === json ? JSON.parse(json) : json
48
+ invoices = Array.wrap(parsed).map {|attrs| new(attrs["invoices"])}
49
+ invoice = Array.wrap(parsed).map {|attrs| new(attrs["invoice"])}
50
+ if invoices.first && invoices.first.length > 0
51
+ invoices
52
+ else
53
+ invoice
54
+ end
55
+ end
11
56
 
12
57
  def initialize(args = {}, _ = nil)
13
- @line_items = []
14
- args = args.to_hash.stringify_keys
15
- self.line_items = args.delete("csv_line_items")
16
- self.line_items = args.delete("line_items")
58
+ if args
59
+ args = args.to_hash.stringify_keys
60
+ self.line_items = args.delete("csv_line_items")
61
+ self.line_items = args.delete("line_items")
62
+ self.line_items = [] if self.line_items.nil?
63
+ end
17
64
  super
18
65
  end
19
66
 
@@ -48,21 +95,10 @@ module Harvest
48
95
  else
49
96
  header = %w(kind description quantity unit_price amount taxed taxed2 project_id)
50
97
 
51
- # writing this in stdlib so we don't force 1.8 users to install FasterCSV and make gem dependencies wierd
52
- if RUBY_VERSION =~ /1.8/
53
- csv_data = ""
54
- CSV.generate_row(header, header.size, csv_data)
98
+ CSV.generate do |csv|
99
+ csv << header
55
100
  line_items.each do |item|
56
- row_data = header.inject([]) {|row, attr| row << item[attr] }
57
- CSV.generate_row(row_data, row_data.size, csv_data)
58
- end
59
- csv_data
60
- else
61
- CSV.generate do |csv|
62
- csv << header
63
- line_items.each do |item|
64
- csv << header.inject([]) {|row, attr| row << item[attr] }
65
- end
101
+ csv << header.inject([]) {|row, attr| row << item[attr] }
66
102
  end
67
103
  end
68
104
  end
@@ -0,0 +1,8 @@
1
+ module Harvest
2
+ class InvoicePayment < Hashie::Mash
3
+ include Harvest::Model
4
+
5
+ api_path '/payments'
6
+ def self.json_root; 'payment'; end
7
+ end
8
+ end
@@ -13,12 +13,12 @@ module Harvest
13
13
  end
14
14
 
15
15
  def spent_at=(date)
16
- self["spent_at"] = (String === date ? Time.parse(date) : date)
16
+ self["spent_at"] = Date.parse(date.to_s)
17
17
  end
18
18
 
19
19
  def as_json(args = {})
20
20
  super(args).to_hash.stringify_keys.tap do |hash|
21
- hash.update("spent_at" => (spent_at.nil? ? nil : spent_at.to_time.xmlschema))
21
+ hash.update("spent_at" => (spent_at.nil? ? nil : spent_at.xmlschema))
22
22
  end
23
23
  end
24
24
  end