harvested 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +23 -0
- data/HISTORY +16 -0
- data/MIT-LICENSE +20 -0
- data/README.md +67 -0
- data/Rakefile +52 -0
- data/VERSION +1 -0
- data/examples/basics.rb +35 -0
- data/examples/clear_account.rb +28 -0
- data/examples/task_assignments.rb +27 -0
- data/examples/user_assignments.rb +24 -0
- data/features/account.feature +7 -0
- data/features/client_contacts.feature +23 -0
- data/features/clients.feature +29 -0
- data/features/errors.feature +25 -0
- data/features/expense_categories.feature +21 -0
- data/features/expenses.feature +55 -0
- data/features/hardy_client.feature +40 -0
- data/features/projects.feature +39 -0
- data/features/reporting.feature +72 -0
- data/features/step_definitions/account_steps.rb +7 -0
- data/features/step_definitions/assignment_steps.rb +100 -0
- data/features/step_definitions/contact_steps.rb +11 -0
- data/features/step_definitions/debug_steps.rb +3 -0
- data/features/step_definitions/error_steps.rb +113 -0
- data/features/step_definitions/expenses_steps.rb +46 -0
- data/features/step_definitions/harvest_steps.rb +8 -0
- data/features/step_definitions/model_steps.rb +90 -0
- data/features/step_definitions/people_steps.rb +4 -0
- data/features/step_definitions/report_steps.rb +91 -0
- data/features/step_definitions/time_entry_steps.rb +40 -0
- data/features/support/env.rb +37 -0
- data/features/support/error_helpers.rb +18 -0
- data/features/support/fixtures/empty_clients.xml +2 -0
- data/features/support/fixtures/over_limit.xml +8 -0
- data/features/support/fixtures/receipt.png +0 -0
- data/features/support/fixtures/under_limit.xml +8 -0
- data/features/support/harvest_credentials.example.yml +4 -0
- data/features/support/harvest_helpers.rb +11 -0
- data/features/support/inflections.rb +9 -0
- data/features/task_assignment.feature +69 -0
- data/features/tasks.feature +25 -0
- data/features/time_tracking.feature +29 -0
- data/features/user_assignments.feature +33 -0
- data/features/users.feature +55 -0
- data/lib/harvest/api/account.rb +10 -0
- data/lib/harvest/api/base.rb +42 -0
- data/lib/harvest/api/clients.rb +10 -0
- data/lib/harvest/api/contacts.rb +19 -0
- data/lib/harvest/api/expense_categories.rb +9 -0
- data/lib/harvest/api/expenses.rb +28 -0
- data/lib/harvest/api/projects.rb +39 -0
- data/lib/harvest/api/reports.rb +39 -0
- data/lib/harvest/api/task_assignments.rb +32 -0
- data/lib/harvest/api/tasks.rb +9 -0
- data/lib/harvest/api/time.rb +32 -0
- data/lib/harvest/api/user_assignments.rb +32 -0
- data/lib/harvest/api/users.rb +15 -0
- data/lib/harvest/base.rb +59 -0
- data/lib/harvest/base_model.rb +34 -0
- data/lib/harvest/behavior/activatable.rb +21 -0
- data/lib/harvest/behavior/crud.rb +31 -0
- data/lib/harvest/client.rb +18 -0
- data/lib/harvest/contact.rb +16 -0
- data/lib/harvest/credentials.rb +21 -0
- data/lib/harvest/errors.rb +23 -0
- data/lib/harvest/expense.rb +19 -0
- data/lib/harvest/expense_category.rb +18 -0
- data/lib/harvest/hardy_client.rb +80 -0
- data/lib/harvest/project.rb +22 -0
- data/lib/harvest/rate_limit_status.rb +16 -0
- data/lib/harvest/task.rb +20 -0
- data/lib/harvest/task_assignment.rb +34 -0
- data/lib/harvest/time_entry.rb +41 -0
- data/lib/harvest/timezones.rb +150 -0
- data/lib/harvest/user.rb +40 -0
- data/lib/harvest/user_assignment.rb +34 -0
- data/lib/harvested.rb +31 -0
- data/spec/harvest/base_spec.rb +9 -0
- data/spec/harvest/credentials_spec.rb +22 -0
- data/spec/harvest/expense_spec.rb +15 -0
- data/spec/harvest/task_assignment_spec.rb +10 -0
- data/spec/harvest/time_entry_spec.rb +22 -0
- data/spec/harvest/user_assignment_spec.rb +10 -0
- data/spec/harvest/user_spec.rb +32 -0
- data/spec/spec.default.opts +1 -0
- data/spec/spec_helper.rb +10 -0
- metadata +243 -0
data/.gitignore
ADDED
@@ -0,0 +1,23 @@
|
|
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
|
+
|
22
|
+
## PROJECT::SPECIFIC
|
23
|
+
features/support/harvest_credentials.yml
|
data/HISTORY
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
0.3.0 - April 11, 2010
|
2
|
+
* Added users
|
3
|
+
* Added clients
|
4
|
+
* Added contacts
|
5
|
+
* Added expense categories
|
6
|
+
* Added expenses
|
7
|
+
* Added projects
|
8
|
+
* Added tasks
|
9
|
+
* Added task assignments
|
10
|
+
* Added user assignments
|
11
|
+
* Added time tracking
|
12
|
+
* Added reporting
|
13
|
+
* Added account information
|
14
|
+
* Added common errors
|
15
|
+
* Added Harvest#hardy_client
|
16
|
+
|
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,67 @@
|
|
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', :ssl => false) # you can enable SSL if your account supports it
|
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`
|
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', :ssl => false)
|
27
|
+
harvest.projects() # This will wait for the Rate Limit reset if you have gone over your limit
|
28
|
+
|
29
|
+
## Links
|
30
|
+
|
31
|
+
* [Harvest API Documentation](http://www.getharvest.com/api)
|
32
|
+
* [Source Code for Harvested](http://github.com/zmoazeni/harvested)
|
33
|
+
* [Pivotal Tracker for Harvested](http://www.pivotaltracker.com/projects/63260)
|
34
|
+
* [Mailing List for Harvested](http://groups.google.com/group/harvested)
|
35
|
+
|
36
|
+
## How to Contribute
|
37
|
+
|
38
|
+
If you find what looks like a bug:
|
39
|
+
|
40
|
+
1. Check the GitHub issue tracker to see if anyone else has had the same issue.
|
41
|
+
http://github.com/zmoazeni/harvested/issues/
|
42
|
+
2. If you don’t see anything, create an issue with information on how to reproduce it.
|
43
|
+
|
44
|
+
If you want to contribute an enhancement or a fix:
|
45
|
+
|
46
|
+
1. Fork the project on github http://github.com/zmoazeni/harvested
|
47
|
+
2. Make your changes with tests
|
48
|
+
3. Commit the changes without messing with the Rakefile, VERSION, or history
|
49
|
+
4. Send me a pull request
|
50
|
+
|
51
|
+
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.
|
52
|
+
|
53
|
+
## TODO
|
54
|
+
|
55
|
+
* Write Documentation
|
56
|
+
* Implement Invoices
|
57
|
+
* Allow Timer Toggling
|
58
|
+
|
59
|
+
Other Roadmap items can be found on [Pivotal Tracker](http://www.pivotaltracker.com/projects/63260)
|
60
|
+
|
61
|
+
## Notes on Harvest Estimates
|
62
|
+
|
63
|
+
Estimates aren't currently supported due to lack of an API. If this opens up, harvested will include them.
|
64
|
+
|
65
|
+
## Copyright
|
66
|
+
|
67
|
+
Copyright (c) 2010 Zach Moazeni. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "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 at http://www.getharvest.com/api}
|
10
|
+
gem.email = "zach.moazeni@gmail.com"
|
11
|
+
gem.homepage = "http://github.com/zmoazeni/harvested"
|
12
|
+
gem.authors = ["Zach Moazeni"]
|
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
|
26
|
+
|
27
|
+
require 'spec/rake/spectask'
|
28
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
29
|
+
spec.libs << 'lib' << 'spec'
|
30
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
31
|
+
end
|
32
|
+
|
33
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
34
|
+
spec.libs << 'lib' << 'spec'
|
35
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
36
|
+
spec.rcov = true
|
37
|
+
end
|
38
|
+
|
39
|
+
task :spec => :check_dependencies
|
40
|
+
|
41
|
+
begin
|
42
|
+
require 'cucumber/rake/task'
|
43
|
+
Cucumber::Rake::Task.new(:features)
|
44
|
+
|
45
|
+
task :features => :check_dependencies
|
46
|
+
rescue LoadError
|
47
|
+
task :features do
|
48
|
+
abort "Cucumber is not available. In order to run features, you must: sudo gem install cucumber"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
task :default => %w(spec features)
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.3.0
|
data/examples/basics.rb
ADDED
@@ -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, :ssl => false)
|
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, :ssl => false)
|
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, :ssl => false)
|
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, :ssl => false)
|
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,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"
|