harvested 0.6.2 → 0.6.3

Sign up to get free protection for your applications and to get access to all the features.
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