quilted-harvested 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. data/.document +3 -0
  2. data/.gitignore +25 -0
  3. data/HISTORY +19 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.md +68 -0
  6. data/Rakefile +25 -0
  7. data/VERSION +1 -0
  8. data/examples/basics.rb +35 -0
  9. data/examples/clear_account.rb +28 -0
  10. data/examples/task_assignments.rb +27 -0
  11. data/examples/user_assignments.rb +24 -0
  12. data/features/account.feature +7 -0
  13. data/features/client_contacts.feature +23 -0
  14. data/features/clients.feature +29 -0
  15. data/features/errors.feature +25 -0
  16. data/features/expense_categories.feature +21 -0
  17. data/features/expenses.feature +55 -0
  18. data/features/hardy_client.feature +40 -0
  19. data/features/projects.feature +39 -0
  20. data/features/reporting.feature +72 -0
  21. data/features/step_definitions/account_steps.rb +7 -0
  22. data/features/step_definitions/assignment_steps.rb +100 -0
  23. data/features/step_definitions/contact_steps.rb +11 -0
  24. data/features/step_definitions/debug_steps.rb +3 -0
  25. data/features/step_definitions/error_steps.rb +113 -0
  26. data/features/step_definitions/expenses_steps.rb +46 -0
  27. data/features/step_definitions/harvest_steps.rb +8 -0
  28. data/features/step_definitions/model_steps.rb +90 -0
  29. data/features/step_definitions/people_steps.rb +4 -0
  30. data/features/step_definitions/report_steps.rb +91 -0
  31. data/features/step_definitions/time_entry_steps.rb +40 -0
  32. data/features/support/env.rb +37 -0
  33. data/features/support/error_helpers.rb +18 -0
  34. data/features/support/fixtures/empty_clients.xml +2 -0
  35. data/features/support/fixtures/over_limit.xml +8 -0
  36. data/features/support/fixtures/receipt.png +0 -0
  37. data/features/support/fixtures/under_limit.xml +8 -0
  38. data/features/support/harvest_credentials.example.yml +4 -0
  39. data/features/support/harvest_helpers.rb +11 -0
  40. data/features/support/inflections.rb +9 -0
  41. data/features/task_assignment.feature +69 -0
  42. data/features/tasks.feature +25 -0
  43. data/features/time_tracking.feature +29 -0
  44. data/features/user_assignments.feature +33 -0
  45. data/features/users.feature +55 -0
  46. data/harvested.gemspec +159 -0
  47. data/lib/harvest/api/account.rb +15 -0
  48. data/lib/harvest/api/base.rb +42 -0
  49. data/lib/harvest/api/clients.rb +10 -0
  50. data/lib/harvest/api/contacts.rb +19 -0
  51. data/lib/harvest/api/expense_categories.rb +9 -0
  52. data/lib/harvest/api/expenses.rb +28 -0
  53. data/lib/harvest/api/projects.rb +54 -0
  54. data/lib/harvest/api/reports.rb +39 -0
  55. data/lib/harvest/api/task_assignments.rb +32 -0
  56. data/lib/harvest/api/tasks.rb +9 -0
  57. data/lib/harvest/api/time.rb +32 -0
  58. data/lib/harvest/api/user_assignments.rb +32 -0
  59. data/lib/harvest/api/users.rb +21 -0
  60. data/lib/harvest/base.rb +258 -0
  61. data/lib/harvest/base_model.rb +73 -0
  62. data/lib/harvest/behavior/activatable.rb +31 -0
  63. data/lib/harvest/behavior/crud.rb +57 -0
  64. data/lib/harvest/client.rb +30 -0
  65. data/lib/harvest/contact.rb +29 -0
  66. data/lib/harvest/credentials.rb +21 -0
  67. data/lib/harvest/errors.rb +23 -0
  68. data/lib/harvest/expense.rb +19 -0
  69. data/lib/harvest/expense_category.rb +18 -0
  70. data/lib/harvest/hardy_client.rb +80 -0
  71. data/lib/harvest/project.rb +56 -0
  72. data/lib/harvest/rate_limit_status.rb +28 -0
  73. data/lib/harvest/task.rb +30 -0
  74. data/lib/harvest/task_assignment.rb +34 -0
  75. data/lib/harvest/time_entry.rb +42 -0
  76. data/lib/harvest/timezones.rb +149 -0
  77. data/lib/harvest/user.rb +66 -0
  78. data/lib/harvest/user_assignment.rb +34 -0
  79. data/lib/harvested.rb +62 -0
  80. data/spec/harvest/base_spec.rb +9 -0
  81. data/spec/harvest/credentials_spec.rb +22 -0
  82. data/spec/harvest/expense_spec.rb +15 -0
  83. data/spec/harvest/task_assignment_spec.rb +10 -0
  84. data/spec/harvest/time_entry_spec.rb +22 -0
  85. data/spec/harvest/user_assignment_spec.rb +10 -0
  86. data/spec/harvest/user_spec.rb +32 -0
  87. data/spec/spec.default.opts +1 -0
  88. data/spec/spec_helper.rb +10 -0
  89. metadata +264 -0
data/.document ADDED
@@ -0,0 +1,3 @@
1
+ README.md
2
+ lib/**/*.rb
3
+ MIT-LICENSE
data/.gitignore ADDED
@@ -0,0 +1,25 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+ spec.opts
21
+ doc
22
+ .yardoc
23
+
24
+ ## PROJECT::SPECIFIC
25
+ features/support/harvest_credentials.yml
data/HISTORY ADDED
@@ -0,0 +1,19 @@
1
+ 0.3.1 - October 14, 2010
2
+ * Updated docs removing :ssl => false since Harvest released SSL to everyone
3
+ * Added department to the User model (Steve McKinney)
4
+ 0.3.0 - April 11, 2010
5
+ * Added users
6
+ * Added clients
7
+ * Added contacts
8
+ * Added expense categories
9
+ * Added expenses
10
+ * Added projects
11
+ * Added tasks
12
+ * Added task assignments
13
+ * Added user assignments
14
+ * Added time tracking
15
+ * Added reporting
16
+ * Added account information
17
+ * Added common errors
18
+ * Added Harvest#hardy_client
19
+
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Zach Moazeni
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,68 @@
1
+ # Harvested: A Ruby Harvest API
2
+
3
+ This is a Ruby wrapper for the [Harvest API](http://www.getharvest.com/).
4
+
5
+ ## Installation
6
+
7
+ gem install harvested
8
+
9
+ ## Examples
10
+
11
+ harvest = Harvest.client('yoursubdomain', 'yourusername', 'yourpassword')
12
+ harvest.projects() # list out projects
13
+
14
+ client = Harvest::Client.new(:name => "Billable Company LTD.")
15
+ client = harvest.clients.create(client)
16
+ harvest.clients.find(client.id) # returns a Harvest::Client
17
+
18
+ You can find more examples in `/examples` and in the documentation for Harvest::Base
19
+
20
+ ## Hardy Client
21
+
22
+ The guys at Harvest built a great API, but there are always dangers in writing code that depends on an API. For example, HTTP Timeouts, Occasional Bad Gateways, and Rate Limiting issues need to be accounted for.
23
+
24
+ Using `Harvested#client` your code needs to handle all these situations. However you can also use `Harvested#hardy_client` which will retry errors and wait for Rate Limit resets.
25
+
26
+ harvest = Harvest.hardy_client('yoursubdomain', 'yourusername', 'yourpassword')
27
+ harvest.projects() # This will wait for the Rate Limit reset if you have gone over your limit
28
+
29
+ ## Links
30
+
31
+ * [Harvested Documentation](http://rdoc.info/projects/zmoazeni/harvested)
32
+ * [Harvest API Documentation](http://www.getharvest.com/api)
33
+ * [Source Code for Harvested](http://github.com/zmoazeni/harvested)
34
+ * [Pivotal Tracker for Harvested](http://www.pivotaltracker.com/projects/63260)
35
+ * [Mailing List for Harvested](http://groups.google.com/group/harvested)
36
+
37
+ ## How to Contribute
38
+
39
+ If you find what looks like a bug:
40
+
41
+ 1. Check the GitHub issue tracker to see if anyone else has had the same issue.
42
+ http://github.com/zmoazeni/harvested/issues/
43
+ 2. If you don’t see anything, create an issue with information on how to reproduce it.
44
+
45
+ If you want to contribute an enhancement or a fix:
46
+
47
+ 1. Fork the project on github http://github.com/zmoazeni/harvested
48
+ 2. Make your changes with tests
49
+ 3. Commit the changes without messing with the Rakefile, VERSION, or history
50
+ 4. Send me a pull request
51
+
52
+ Note on running tests: most cucumber features run against a live Harvest account. To run the suite, sign up for a free trial account and fill out `/features/support/harvest_credentials.yml` *(a sample harvest_credentials.example.yml has been included)*. The tests use the hardy_client so they will wait for a rate limit reset when they detect the limit has been hit.
53
+
54
+ ## TODO
55
+
56
+ * Write Documentation
57
+ * Implement Invoices
58
+ * Allow Timer Toggling
59
+
60
+ Other Roadmap items can be found on [Pivotal Tracker](http://www.pivotaltracker.com/projects/63260)
61
+
62
+ ## Notes on Harvest Estimates
63
+
64
+ Estimates aren't currently supported due to lack of an API. If this opens up, harvested will include them.
65
+
66
+ ## Copyright
67
+
68
+ Copyright (c) 2010 Zach Moazeni. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,25 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "quilted-harvested"
8
+ gem.summary = %Q{A Ruby Wrapper for the Harvest API http://www.getharvest.com/}
9
+ gem.description = %Q{Harvested wraps the Harvest API concisely without the use of Rails dependencies. More information about the Harvest API can be found on their website (http://www.getharvest.com/api). For support hit up the Mailing List (http://groups.google.com/group/harvested)}
10
+ gem.email = "michelle@quilted.coop"
11
+ gem.homepage = "http://github.com/quilted/harvested"
12
+ gem.authors = ["Zach Moazeni, Michelle Moon Lee (updated)"]
13
+ gem.add_development_dependency "rspec", ">= 1.2.9"
14
+ gem.add_development_dependency "cucumber", ">= 0"
15
+ gem.add_development_dependency "ruby-debug", ">= 0"
16
+ gem.add_development_dependency "fakeweb", ">= 0"
17
+ gem.add_dependency "httparty", ">= 0"
18
+ gem.add_dependency "happymapper", ">= 0"
19
+ gem.add_dependency "builder", ">= 0"
20
+ end
21
+ Jeweler::GemcutterTasks.new
22
+ rescue LoadError => e
23
+ p e
24
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
25
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.3.1
@@ -0,0 +1,35 @@
1
+ require "harvested"
2
+
3
+ subdomain = 'yoursubdomain'
4
+ username = 'yourusername'
5
+ password = 'yourpassword'
6
+
7
+ harvest = Harvest.hardy_client(subdomain, username, password)
8
+
9
+ # Print out all users, clients, and projects on the account
10
+ puts "Users:"
11
+ harvest.users.all.each {|u| p u }
12
+
13
+ puts "Clients:"
14
+ harvest.clients.all.each {|c| p c }
15
+
16
+ puts "Projects:"
17
+ harvest.projects.all.each {|project| p project }
18
+
19
+ # Create a Client add a Project to that Client, Add a Task to the Project, track some Time against the Project/Task, and then Run a report against all time I've submitted
20
+
21
+ client = Harvest::Client.new(:name => 'SuprCorp')
22
+ client = harvest.clients.create(client)
23
+
24
+ project = Harvest::Project.new(:name => 'SuprGlu', :client_id => client.id, :notes => 'Some notes about this project')
25
+ project = harvest.projects.create(project)
26
+
27
+ harvest.projects.create_task(project, 'Bottling Glue')
28
+ task_assignment = harvest.task_assignments.all(project).first
29
+
30
+ time_entry = Harvest::TimeEntry.new(:notes => 'Bottled glue today', :hours => 8, :spent_at => "04/11/2010", :project_id => project.id, :task_id => task_assignment.task_id)
31
+ time_entry = harvest.time.create(time_entry)
32
+
33
+ entries = harvest.reports.time_by_project(project, Time.parse("04/11/2010"), Time.parse("04/12/2010"))
34
+ puts "Entries:"
35
+ entries.each {|e| p e}
@@ -0,0 +1,28 @@
1
+ # This is commented out because it can be very dangerous if run against a production account
2
+
3
+ # require "harvested"
4
+ #
5
+ # subdomain = 'yoursubdomain'
6
+ # username = 'yourusername'
7
+ # password = 'yourpassword'
8
+ #
9
+ # api = Harvest.hardy_client(subdomain, username, password)
10
+ #
11
+ # raise "Are you sure you want to do this? (comment out this exception if so)"
12
+ #
13
+ # api.users.all.each do |u|
14
+ # api.users.delete(u) if u.email != username
15
+ # end
16
+ # my_user = api.users.all.first
17
+ #
18
+ # api.reports.time_by_user(my_user, Time.parse('01/01/2000'), Time.now).each do |time|
19
+ # api.time.delete(time)
20
+ # end
21
+ #
22
+ # api.reports.expenses_by_user(my_user, Time.parse('01/01/2000'), Time.now).each do |time|
23
+ # api.expenses.delete(time)
24
+ # end
25
+ #
26
+ # %w(expenses expense_categories projects contacts clients tasks).each do |collection|
27
+ # api.send(collection).all.each {|m| api.send(collection).delete(m) }
28
+ # end
@@ -0,0 +1,27 @@
1
+ require "harvested"
2
+
3
+ subdomain = 'yoursubdomain'
4
+ username = 'yourusername'
5
+ password = 'yourpassword'
6
+
7
+ harvest = Harvest.hardy_client(subdomain, username, password)
8
+
9
+ # Create a Client add a Project to that Client
10
+
11
+ client = Harvest::Client.new(:name => 'SuprCorp')
12
+ client = harvest.clients.create(client)
13
+
14
+ project = Harvest::Project.new(:name => 'SuprGlu', :client_id => client.id, :notes => 'Some notes about this project')
15
+ project = harvest.projects.create(project)
16
+
17
+ # You can create an assign a task in one call
18
+ harvest.projects.create_task(project, 'Bottling Glue')
19
+ puts "Assigned the task 'Bottling Glue' to the project 'SuprGlu'"
20
+
21
+ # You can explicitly create the task and then assign it
22
+ task = Harvest::Task.new(:name => 'Packaging Glue', :hourly_rate => 30, :billable => true)
23
+ task = harvest.tasks.create(task)
24
+
25
+ task_assignment = Harvest::TaskAssignment.new(:task_id => task.id, :project_id => project.id)
26
+ task_assignment = harvest.task_assignments.create(task_assignment)
27
+ puts "Assigned the task 'Packaging Glue' to the project 'SuprGlu'"
@@ -0,0 +1,24 @@
1
+ require "harvested"
2
+
3
+ subdomain = 'yoursubdomain'
4
+ username = 'userusername'
5
+ password = 'yourpassword'
6
+
7
+ harvest = Harvest.hardy_client(subdomain, username, password)
8
+
9
+ # Create a Client, Project, and a User then assign that User to that Project
10
+
11
+ client = Harvest::Client.new(:name => 'SuprCorp')
12
+ client = harvest.clients.create(client)
13
+
14
+ project = Harvest::Project.new(:name => 'SuprGlu', :client_id => client.id, :notes => 'Some notes about this project')
15
+ project = harvest.projects.create(project)
16
+
17
+ harvest.projects.create_task(project, 'Bottling Glue')
18
+
19
+ user = Harvest::User.new(:first_name => 'Jane', :last_name => 'Doe', :email => 'jane@doe.com', :timezone => :est, :password => 'secure', :password_confirmation => 'secure')
20
+ user = harvest.users.create(user)
21
+
22
+ user_assignment = Harvest::UserAssignment.new(:user_id => user.id, :project_id => project.id)
23
+ harvest.user_assignments.create(user_assignment)
24
+ puts 'Assigned Jane Doe to the project "SuprGlu"'
@@ -0,0 +1,7 @@
1
+ @clean
2
+ Feature: Account API
3
+
4
+ Scenario: Requesting Rate Limit
5
+ Given I am using the credentials from "./support/harvest_credentials.yml"
6
+ When I request the current rate limit I should get the following:
7
+ | max_calls | 40 |
@@ -0,0 +1,23 @@
1
+ @clean
2
+ Feature: Managing Client Contacts
3
+
4
+ Scenario: Adding, Updating, and Removing a Contact
5
+ Given I am using the credentials from "./support/harvest_credentials.yml"
6
+ And I create a client with the following:
7
+ | name | Client Contacts |
8
+ | details | Building API Widgets across the country |
9
+ When I create a contact for the client "Client Contacts" with the following:
10
+ | email | jane@doe.com |
11
+ | first_name | Jane |
12
+ | last_name | Doe |
13
+ | phone_office | 555.123.4567 |
14
+ | phone_mobile | 555.333.1111 |
15
+ | fax | 555.222.1111 |
16
+ Then there should be a contact "jane@doe.com"
17
+ And there should be a contact "jane@doe.com" for the client "Client Contacts"
18
+ When I update the contact "jane@doe.com" with the following:
19
+ | last_name | Smith |
20
+ Then the contact "jane@doe.com" should have the following attributes:
21
+ | last_name | Smith |
22
+ When I delete the contact "jane@doe.com"
23
+ Then there should not be a contact "jane@doe.com"
@@ -0,0 +1,29 @@
1
+ @clean
2
+ Feature: Managing Clients
3
+
4
+ Scenario: Adding, Updating, and Removing a Client
5
+ Given I am using the credentials from "./support/harvest_credentials.yml"
6
+ When I create a client with the following:
7
+ | name | Client |
8
+ | details | Building API Widgets across the country |
9
+ Then there should be a client "Client"
10
+ When I update the client "Client" with the following:
11
+ | name | Updated Client |
12
+ | details | Building API Widgets in the Midwest |
13
+ Then the client "Updated Client" should have the following attributes:
14
+ | details | Building API Widgets in the Midwest |
15
+ When I delete the client "Updated Client"
16
+ Then there should not be a client "Updated Client"
17
+
18
+ Scenario: Activating and Deactivating a Client
19
+ Given I am using the credentials from "./support/harvest_credentials.yml"
20
+ When I create a client with the following:
21
+ | name | Client |
22
+ | details | Building API Widgets across the country |
23
+ Then the client "Client" should be activated
24
+ When I deactivate the client "Client"
25
+ Then the client "Client" should be deactivated
26
+ When I activate the client "Client"
27
+ Then the client "Client" should be activated
28
+ Then I delete the client "Client"
29
+
@@ -0,0 +1,25 @@
1
+ @disconnected
2
+ Feature: Handling Harvest Errors
3
+
4
+ Scenario: Raising Bad Responses
5
+ Given I am using the credentials from "./support/harvest_credentials.yml"
6
+
7
+ Given the next request will receive a bad request response
8
+ When I make a request with the standard client
9
+ Then a 400 error should be raised
10
+
11
+ Given the next request will receive a not found response
12
+ When I make a request with the standard client
13
+ Then a 404 error should be raised
14
+
15
+ Given the next request will receive a bad gateway response
16
+ When I make a request with the standard client
17
+ Then a 502 error should be raised
18
+
19
+ Given the next request will receive a server error response
20
+ When I make a request with the standard client
21
+ Then a 500 error should be raised
22
+
23
+ Given the next request will receive a rate limit response
24
+ When I make a request with the standard client
25
+ Then a 503 error should be raised
@@ -0,0 +1,21 @@
1
+ @clean
2
+ Feature: Expense Categories
3
+
4
+ Scenario: Adding, Updating, and Removing an Expense Category
5
+ Given I am using the credentials from "./support/harvest_credentials.yml"
6
+ When I create an expense category with the following:
7
+ | name | Mileage |
8
+ | unit_name | Miles |
9
+ | unit_price | 0.485 |
10
+ Then there should be an expense category "Mileage"
11
+ When I update the expense category "Mileage" with the following:
12
+ | unit_name | Kilometers |
13
+ | deactivated | true |
14
+ | unit_price | 1.2 |
15
+ Then the expense category "Mileage" should have the following attributes:
16
+ | unit_name | Kilometers |
17
+ | unit_price | 1.2 |
18
+ | deactivated | true |
19
+ | active? | false |
20
+ When I delete the expense category "Mileage"
21
+ Then there should not be an expense category "Mileage"
@@ -0,0 +1,55 @@
1
+ @clean
2
+ Feature: Expenses
3
+
4
+ Scenario: Adding, Updating, and Removing an Expenses
5
+ Given I am using the credentials from "./support/harvest_credentials.yml"
6
+ When I create an expense category with the following:
7
+ | name | Mileage |
8
+ | unit_name | Miles |
9
+ | unit_price | 0.485 |
10
+ Then there should be an expense category "Mileage"
11
+ When I create a client with the following:
12
+ | name | Expense Client |
13
+ When I create a project for the client "Expense Client" with the following:
14
+ | name | Test Project |
15
+ When I create an expense for the project "Test Project" with the category "Mileage" with the following:
16
+ | notes | Drive to Chicago |
17
+ | total_cost | 75.00 |
18
+ | spent_at | 12/28/2009 |
19
+ Then there should be an expense "Drive to Chicago" on "12/28/2009"
20
+ And the expense "Drive to Chicago" on "12/28/2009" should have the following attributes:
21
+ | total_cost | 75.0 |
22
+ | units | 1 |
23
+ When I update the expense "Drive to Chicago" on "12/28/2009" with the following:
24
+ | total_cost | 50 |
25
+ Then the expense "Drive to Chicago" on "12/28/2009" should have the following attributes:
26
+ | total_cost | 50.0 |
27
+ | units | 1 |
28
+ When I update the expense "Drive to Chicago" on "12/28/2009" with the following:
29
+ | total_cost | |
30
+ | units | 3 |
31
+ Then the expense "Drive to Chicago" on "12/28/2009" should have the following attributes:
32
+ | total_cost | 1.46 |
33
+ | units | 3 |
34
+ When I delete the expense "Drive to Chicago" on "12/28/2009"
35
+ Then there should not be an expense "Drive to Chicago" on "12/28/2009"
36
+
37
+ @wip
38
+ Scenario: Attaching a receipt to an Expense
39
+ Given I am using the credentials from "./support/harvest_credentials.yml"
40
+ When I create an expense category with the following:
41
+ | name | Mileage |
42
+ | unit_name | Miles |
43
+ | unit_price | 0.485 |
44
+ Then there should be an expense category "Mileage"
45
+ When I create a client with the following:
46
+ | name | Expense Client |
47
+ When I create a project for the client "Expense Client" with the following:
48
+ | name | Test Project |
49
+ When I create an expense for the project "Test Project" with the category "Mileage" with the following:
50
+ | notes | Drive to Chicago |
51
+ | total_cost | 75.00 |
52
+ | spent_at | 12/28/2009 |
53
+ Then there should be an expense "Drive to Chicago" on "12/28/2009"
54
+ When I attach the receipt "./support/fixtures/receipt.png" to the expense "Drive to Chicago" on "12/28/2009"
55
+ Then there should be a receipt "./support/fixtures/receipt.png" attached to the expense "Drive to Chicago" on "12/28/2009"
@@ -0,0 +1,40 @@
1
+ @disconnected
2
+ Feature: Hardy Client
3
+
4
+ Background:
5
+ Given I am using the credentials from "./support/harvest_credentials.yml"
6
+ And the rate limit status indicates I'm under my limit
7
+
8
+ Scenario: Hardy Client waiting for Rate Limit resets
9
+ Given the next request will receive a rate limit response with a refresh in 5 seconds
10
+ When I make a request with the hardy client
11
+ Then the hardy client should wait 5 seconds for the rate limit to reset
12
+ And I should be able to make a request again
13
+
14
+ Scenario: Hardy Client waiting for Rate Limit resets
15
+ Given the next request will receive a rate limit response without a refresh set
16
+ When I make a request with the hardy client
17
+ Then the hardy client should wait 16 seconds for the rate limit to reset
18
+ And I should be able to make a request again
19
+
20
+ Scenario: Hardy Client retrying Bad Gateway responses
21
+ Given the next 2 requests will receive a bad gateway response
22
+ When I make a request with the hardy client
23
+ Then no errors should be raised
24
+
25
+ Scenario: Hardy Client retrying HTTP Errors
26
+ Given the next 2 requests will receive an HTTP Error
27
+ When I make a request with the hardy client
28
+ Then no errors should be raised
29
+
30
+ Scenario: Hardy Client stop retrying Bad Gateway responses
31
+ Given the next 6 requests will receive a bad gateway response
32
+ When I make a request with the hardy client
33
+ Then a 502 error should be raised
34
+
35
+ Scenario: Check rate limit before retrying bad gateway requests
36
+ Given the next request will receive a bad gateway response
37
+ And the rate limit status indicates I'm over my limit
38
+ When I make a request with the hardy client
39
+ Then the hardy client should wait 16 seconds for the rate limit to reset
40
+ And I should be able to make a request again
@@ -0,0 +1,39 @@
1
+ @clean
2
+ Feature: Managing Projects
3
+
4
+ Scenario: Adding, Updating, and Removing a Project
5
+ Given I am using the credentials from "./support/harvest_credentials.yml"
6
+ When I create a client with the following:
7
+ | name | Client Projects |
8
+ | details | Building API Widgets across the country |
9
+ When I create a project for the client "Client Projects" with the following:
10
+ | name | Test Project |
11
+ | active | true |
12
+ | notes | project to test the api |
13
+ Then there should be a project "Test Project"
14
+ When I update the project "Test Project" with the following:
15
+ | name | Updated Project |
16
+ | code | new-code |
17
+ | bill_by | Project |
18
+ | hourly_rate | 150 |
19
+ Then the project "Updated Project" should have the following attributes:
20
+ | code | new-code |
21
+ | bill_by | Project |
22
+ | hourly_rate | 150.0 |
23
+ When I delete the project "Updated Project"
24
+ Then there should not be a project "Updated Project"
25
+
26
+ Scenario: Activating and Deactivating a Project
27
+ Given I am using the credentials from "./support/harvest_credentials.yml"
28
+ And I create a client with the following:
29
+ | name | Client Projects |
30
+ | details | Building API Widgets across the country |
31
+ And I create a project for the client "Client Projects" with the following:
32
+ | name | Test Project |
33
+ | active | true |
34
+ | notes | project to test the api |
35
+ Then the project "Test Project" should be activated
36
+ When I deactivate the project "Test Project"
37
+ Then the project "Test Project" should be deactivated
38
+ When I activate the project "Test Project"
39
+ Then the project "Test Project" should be activated
@@ -0,0 +1,72 @@
1
+ @clean
2
+ Feature: Harvest Reporting
3
+
4
+ Background:
5
+ Given I am using the credentials from "./support/harvest_credentials.yml"
6
+ And I create a client with the following:
7
+ | name | Report Client |
8
+ | details | Client to run reports |
9
+ And I create a project for the client "Report Client" with the following:
10
+ | name | Report Project1 |
11
+ And I create a project for the client "Report Client" with the following:
12
+ | name | Report Project2 |
13
+
14
+ Scenario: Time Entry Reporting
15
+ Given I create a task with the following:
16
+ | name | Report Task |
17
+ | billable | true |
18
+ | hourly_rate | 120 |
19
+ And I assign the task "Report Task" to the project "Report Project1"
20
+ And I assign the task "Report Task" to the project "Report Project2"
21
+ And I create a time entry for the project "Report Project1" and the task "Report Task" with the following:
22
+ | notes | project1 time |
23
+ | hours | 2.0 |
24
+ | spent_at | 12/28/2009 |
25
+ And I create a time entry for the project "Report Project2" and the task "Report Task" with the following:
26
+ | notes | project2 time |
27
+ | hours | 2.0 |
28
+ | spent_at | 12/28/2009 |
29
+ When I run a project report for "Report Project1" for "12/20/2009" and "12/30/2009" the following entries should be returned:
30
+ | project1 time |
31
+ When I run a project report for "Report Project1" for "12/20/2009" and "12/30/2009" the following entries should not be returned:
32
+ | project2 time |
33
+ When I run a a project report for "Report Project1" for "12/20/2009" and "12/30/2009" filtered by my user the following entries should be returned:
34
+ | project1 time |
35
+ When I run a a project report for "Report Project1" for "12/20/2009" and "12/30/2009" filtered by my user the following entries should not be returned:
36
+ | project2 time |
37
+ When I run a people report for my user for "12/20/2009" and "12/30/2009" the following entries should be returned:
38
+ | project1 time |
39
+ | project2 time |
40
+
41
+ @wip
42
+ Scenario: People Reports filtered by Project
43
+ Given I create a task with the following:
44
+ | name | Report Task |
45
+ | billable | true |
46
+ | hourly_rate | 120 |
47
+ And I assign the task "Report Task" to the project "Report Project1"
48
+ And I assign the task "Report Task" to the project "Report Project2"
49
+ And I create a time entry for the project "Report Project1" and the task "Report Task" with the following:
50
+ | notes | project1 time |
51
+ | hours | 2.0 |
52
+ | spent_at | 12/28/2009 |
53
+ And I create a time entry for the project "Report Project2" and the task "Report Task" with the following:
54
+ | notes | project2 time |
55
+ | hours | 2.0 |
56
+ | spent_at | 12/28/2009 |
57
+ When I run a people report for my user for "12/20/2009" and "12/30/2009" filtered by the project "Report Project1" the following entries should be returned:
58
+ | project1 time |
59
+ When I run a people report for my user for "12/20/2009" and "12/30/2009" filtered by the project "Report Project1" the following entries should not be returned:
60
+ | project2 time |
61
+
62
+ Scenario: Expenses by People
63
+ Given I create an expense category with the following:
64
+ | name | Conference |
65
+ | unit_name | Ticket |
66
+ | unit_price | 300 |
67
+ And I create an expense for the project "Report Project1" with the category "Conference" with the following:
68
+ | notes | RubyConf |
69
+ | total_cost | 300 |
70
+ | spent_at | 12/28/2009 |
71
+ When I run an expense report for my user for "12/20/2009" and "12/30/2009" the following entries should be returned:
72
+ | RubyConf |
@@ -0,0 +1,7 @@
1
+ When 'I request the current rate limit I should get the following:' do |table|
2
+ rate_limit_status = harvest_api.account.rate_limit_status
3
+ table.rows_hash.each do |key, value|
4
+ rate_limit_status.send(key).to_s.should == value
5
+ end
6
+ end
7
+