harvested2 5.0.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.
Files changed (106) hide show
  1. checksums.yaml +7 -0
  2. data/.document +3 -0
  3. data/.gitignore +35 -0
  4. data/.rspec +1 -0
  5. data/.rubocop.yml +34 -0
  6. data/.ruby-version +1 -0
  7. data/.travis.yml +12 -0
  8. data/Gemfile +20 -0
  9. data/HISTORY.md +118 -0
  10. data/MIT-LICENSE +21 -0
  11. data/README.md +66 -0
  12. data/Rakefile +24 -0
  13. data/harvested2.gemspec +30 -0
  14. data/lib/ext/array.rb +52 -0
  15. data/lib/ext/date.rb +9 -0
  16. data/lib/ext/hash.rb +17 -0
  17. data/lib/ext/time.rb +5 -0
  18. data/lib/harvest/account.rb +13 -0
  19. data/lib/harvest/api/account.rb +25 -0
  20. data/lib/harvest/api/base.rb +72 -0
  21. data/lib/harvest/api/clients.rb +10 -0
  22. data/lib/harvest/api/company.rb +12 -0
  23. data/lib/harvest/api/contacts.rb +9 -0
  24. data/lib/harvest/api/expense_categories.rb +9 -0
  25. data/lib/harvest/api/expenses.rb +26 -0
  26. data/lib/harvest/api/invoice_categories.rb +9 -0
  27. data/lib/harvest/api/invoice_messages.rb +86 -0
  28. data/lib/harvest/api/invoice_payments.rb +41 -0
  29. data/lib/harvest/api/invoices.rb +9 -0
  30. data/lib/harvest/api/projects.rb +9 -0
  31. data/lib/harvest/api/task_assignments.rb +75 -0
  32. data/lib/harvest/api/tasks.rb +9 -0
  33. data/lib/harvest/api/time_entry.rb +19 -0
  34. data/lib/harvest/api/user_assignments.rb +75 -0
  35. data/lib/harvest/api/users.rb +10 -0
  36. data/lib/harvest/base.rb +333 -0
  37. data/lib/harvest/behavior/activatable.rb +31 -0
  38. data/lib/harvest/behavior/crud.rb +80 -0
  39. data/lib/harvest/client.rb +23 -0
  40. data/lib/harvest/company.rb +8 -0
  41. data/lib/harvest/contact.rb +20 -0
  42. data/lib/harvest/credentials.rb +34 -0
  43. data/lib/harvest/errors.rb +27 -0
  44. data/lib/harvest/expense.rb +54 -0
  45. data/lib/harvest/expense_category.rb +10 -0
  46. data/lib/harvest/hardy_client.rb +80 -0
  47. data/lib/harvest/invoice.rb +75 -0
  48. data/lib/harvest/invoice_category.rb +8 -0
  49. data/lib/harvest/invoice_message.rb +8 -0
  50. data/lib/harvest/invoice_payment.rb +8 -0
  51. data/lib/harvest/line_item.rb +21 -0
  52. data/lib/harvest/model.rb +133 -0
  53. data/lib/harvest/project.rb +41 -0
  54. data/lib/harvest/receipt.rb +12 -0
  55. data/lib/harvest/task.rb +21 -0
  56. data/lib/harvest/task_assignment.rb +27 -0
  57. data/lib/harvest/time_entry.rb +57 -0
  58. data/lib/harvest/timezones.rb +130 -0
  59. data/lib/harvest/user.rb +58 -0
  60. data/lib/harvest/user_assignment.rb +27 -0
  61. data/lib/harvest/version.rb +3 -0
  62. data/lib/harvested2.rb +96 -0
  63. data/spec/factories/client.rb +14 -0
  64. data/spec/factories/contact.rb +8 -0
  65. data/spec/factories/expense.rb +10 -0
  66. data/spec/factories/expenses_category.rb +7 -0
  67. data/spec/factories/invoice.rb +25 -0
  68. data/spec/factories/invoice_category.rb +5 -0
  69. data/spec/factories/invoice_message.rb +9 -0
  70. data/spec/factories/invoice_payment.rb +7 -0
  71. data/spec/factories/line_item.rb +9 -0
  72. data/spec/factories/project.rb +15 -0
  73. data/spec/factories/task.rb +8 -0
  74. data/spec/factories/task_assignment.rb +8 -0
  75. data/spec/factories/time_entry.rb +13 -0
  76. data/spec/factories/user.rb +19 -0
  77. data/spec/factories/user_assigment.rb +7 -0
  78. data/spec/functional/clients_spec.rb +105 -0
  79. data/spec/functional/errors_spec.rb +42 -0
  80. data/spec/functional/expenses_spec.rb +97 -0
  81. data/spec/functional/invoice_messages_spec.rb +48 -0
  82. data/spec/functional/invoice_payments_spec.rb +51 -0
  83. data/spec/functional/invoice_spec.rb +138 -0
  84. data/spec/functional/project_spec.rb +76 -0
  85. data/spec/functional/tasks_spec.rb +119 -0
  86. data/spec/functional/time_entries_spec.rb +87 -0
  87. data/spec/functional/users_spec.rb +72 -0
  88. data/spec/harvest/base_spec.rb +10 -0
  89. data/spec/harvest/basic_auth_credentials_spec.rb +12 -0
  90. data/spec/harvest/expense_category_spec.rb +5 -0
  91. data/spec/harvest/expense_spec.rb +18 -0
  92. data/spec/harvest/invoice_message_spec.rb +5 -0
  93. data/spec/harvest/invoice_payment_spec.rb +5 -0
  94. data/spec/harvest/invoice_spec.rb +5 -0
  95. data/spec/harvest/oauth_credentials_spec.rb +11 -0
  96. data/spec/harvest/project_spec.rb +5 -0
  97. data/spec/harvest/task_assignment_spec.rb +5 -0
  98. data/spec/harvest/task_spec.rb +5 -0
  99. data/spec/harvest/time_entry_spec.rb +23 -0
  100. data/spec/harvest/user_assignment_spec.rb +5 -0
  101. data/spec/harvest/user_spec.rb +34 -0
  102. data/spec/spec_helper.rb +22 -0
  103. data/spec/support/factory_bot.rb +5 -0
  104. data/spec/support/harvested_helpers.rb +28 -0
  105. data/spec/support/json_examples.rb +9 -0
  106. metadata +238 -0
@@ -0,0 +1,119 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'harvest tasks' do
4
+ let(:harvest) { Harvest.client(access_token: 'mytoken', account_id: '123') }
5
+
6
+ describe 'tasks' do
7
+ let(:task) { create(:task) }
8
+
9
+ context 'allows to add invoice tasks' do
10
+ before do
11
+ allow(harvest.tasks).to receive(:create)
12
+ .and_return(task)
13
+ end
14
+
15
+ it 'returns true' do
16
+ expect(task.default_hourly_rate).to eql(120)
17
+ expect(task.name).to eql('A crud task')
18
+ end
19
+ end
20
+
21
+ context 'allows to update invoice tasks' do
22
+ before do
23
+ allow(harvest.tasks).to receive(:update)
24
+ .and_return(task)
25
+ task.default_hourly_rate = 140
26
+ task = harvest.tasks.update(task)
27
+ end
28
+
29
+ it 'returns true' do
30
+ expect(task.default_hourly_rate).to eql(140)
31
+ end
32
+ end
33
+
34
+ context 'allows to remove invoice tasks' do
35
+ before do
36
+ allow(harvest.tasks).to receive(:delete).and_return([])
37
+ allow(harvest.tasks).to receive(:all).and_return([])
38
+ harvest.tasks.delete(task)
39
+ end
40
+
41
+ it 'returns true' do
42
+ expect(harvest.tasks.all.select do |t|
43
+ t.name == 'A crud task'
44
+ end).to eql([])
45
+ end
46
+ end
47
+ end
48
+
49
+ describe 'task assignments' do
50
+ let(:project) { create(:project) }
51
+ let(:task) do
52
+ create(:task, name: 'A task for joe', default_hourly_rate: 120)
53
+ end
54
+ let(:task_assignment) do
55
+ create(:task_assignment, project: project, task: task)
56
+ end
57
+
58
+ context 'allows to add invoice task assignments' do
59
+ before do
60
+ allow(harvest.task_assignments).to receive(:create)
61
+ .and_return(task)
62
+ end
63
+
64
+ it 'returns true' do
65
+ expect(task_assignment.hourly_rate).to eql(120)
66
+ end
67
+ end
68
+
69
+ context 'allows to update invoice task assignments' do
70
+ before do
71
+ allow(harvest.task_assignments).to receive(:update)
72
+ .and_return(task)
73
+ task_assignment.hourly_rate = 100
74
+ task = harvest.task_assignments.update(task_assignment)
75
+ end
76
+
77
+ it 'returns true' do
78
+ expect(task_assignment.hourly_rate).to eql(100)
79
+ end
80
+ end
81
+
82
+ context 'allows to remove invoice task assignments' do
83
+ before do
84
+ allow(harvest.task_assignments).to receive(:delete)
85
+ .and_return([])
86
+ allow(harvest.task_assignments).to receive(:all)
87
+ .and_return([task_assignment])
88
+ harvest.task_assignments.delete(task_assignment)
89
+ end
90
+
91
+ it 'returns true' do
92
+ expect(harvest.task_assignments.all(project).count).to eql(1)
93
+ end
94
+ end
95
+ end
96
+
97
+ describe 'projects' do
98
+ let(:project) { create(:project) }
99
+ let(:task) do
100
+ create(:task, name: 'A task for joe', default_hourly_rate: 120)
101
+ end
102
+ let(:task_assignment) do
103
+ create(:task_assignment, project: project, task: task)
104
+ end
105
+
106
+ context 'allows to add project and task' do
107
+ before do
108
+ allow(harvest.projects).to receive(:create_task)
109
+ .and_return(task)
110
+ allow(harvest.task_assignments).to receive(:all)
111
+ .and_return([task_assignment])
112
+ end
113
+
114
+ it 'returns true' do
115
+ expect(harvest.task_assignments.all(project).size).to eql(1)
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,87 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'harvest time tracking' do
4
+ let(:harvest) { Harvest.client(access_token: 'mytoken', account_id: '123') }
5
+
6
+ describe 'time entries' do
7
+ let(:time_entry) { create(:time_entry) }
8
+
9
+ context 'allows to add time entry' do
10
+ before do
11
+ allow(harvest.time_entries).to receive(:create)
12
+ .and_return(time_entry)
13
+ end
14
+
15
+ it 'returns true' do
16
+ expect(time_entry.notes).to eql('Test api support')
17
+ end
18
+ end
19
+
20
+ context 'allows to update time entry' do
21
+ before do
22
+ allow(harvest.time_entries).to receive(:update)
23
+ .and_return(time_entry)
24
+ time_entry.notes = 'New test api support'
25
+ time_entry = harvest.time_entries.update(time_entry)
26
+ end
27
+
28
+ it 'returns true' do
29
+ expect(time_entry.notes).to eql('New test api support')
30
+ end
31
+ end
32
+
33
+ context 'allows to remove time entry' do
34
+ before do
35
+ allow(harvest.time_entries).to receive(:delete).and_return([])
36
+ allow(harvest.time_entries).to receive(:all).and_return([])
37
+ harvest.time_entries.delete(time_entry)
38
+ end
39
+
40
+ it 'returns true' do
41
+ expect(harvest.time_entries.all.select do |t|
42
+ t.notes == 'New test api support'
43
+ end).to eql([])
44
+ end
45
+ end
46
+ end
47
+
48
+ describe 'toggle' do
49
+ let(:time_entry) { create(:time_entry, :started) }
50
+
51
+ before do
52
+ allow(harvest.time_entries).to receive(:toggle)
53
+ .and_return(time_entry)
54
+ end
55
+
56
+ it 'should be active' do
57
+ expect(time_entry.timer_started_at).not_to be_nil
58
+ end
59
+
60
+ it 'should be deactive' do
61
+ time_entry.timer_started_at = nil
62
+ time_entry = harvest.time_entries.toggle(time_entry)
63
+ expect(time_entry.timer_started_at).to be_nil
64
+ end
65
+
66
+ it 'should reactive a time_entry' do
67
+ time_entry = harvest.time_entries.toggle(time_entry)
68
+ expect(time_entry).not_to be_nil
69
+ end
70
+ end
71
+
72
+ describe 'projects' do
73
+ let(:user) { create(:user) }
74
+ let(:time_entry) { create(:time_entry) }
75
+
76
+ context 'allows to add project and task' do
77
+ before do
78
+ allow(harvest.time_entries).to receive(:trackable_projects)
79
+ .and_return([])
80
+ end
81
+
82
+ it 'returns true' do
83
+ expect(harvest.time_entries.trackable_projects(Time.now, user)).to eql([])
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,72 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'harvest users' do
4
+ let(:harvest) { Harvest.client(access_token: 'mytoken', account_id: '123') }
5
+
6
+ describe 'users' do
7
+ let(:user) { create(:user) }
8
+
9
+ context 'allows to add users' do
10
+ before do
11
+ allow(harvest.users).to receive(:create).and_return(user)
12
+ end
13
+
14
+ it 'returns true' do
15
+ expect(user.id).not_to be_nil
16
+ expect(user.first_name).to eql('Edgar')
17
+ expect(user.last_name).to eql('Ruth')
18
+ end
19
+ end
20
+
21
+ context 'allows to update users' do
22
+ before do
23
+ allow(harvest.users).to receive(:update).and_return(user)
24
+ user.first_name = 'Joey'
25
+ user = harvest.users.update(user)
26
+ end
27
+
28
+ it 'returns true' do
29
+ expect(user.first_name).to eql('Joey')
30
+ end
31
+ end
32
+
33
+ context 'allows to remove users' do
34
+ before do
35
+ allow(harvest.users).to receive(:delete).and_return([])
36
+ allow(harvest.users).to receive(:all).and_return([])
37
+ harvest.users.delete(user)
38
+ end
39
+
40
+ it 'returns true' do
41
+ expect(harvest.users.all.select do |u|
42
+ u.first_name == 'Joey'
43
+ end).to eql([])
44
+ end
45
+ end
46
+
47
+ context 'allows activating and deactivating users' do
48
+ let(:user) { create(:user, :active) }
49
+
50
+ before do
51
+ allow(harvest.users).to receive(:update)
52
+ .and_return(user)
53
+ end
54
+
55
+ it 'should be active' do
56
+ expect(user).to be_active
57
+ end
58
+
59
+ it 'should be deactive' do
60
+ user.is_active = false
61
+ user = harvest.users.update(user)
62
+ expect(user).not_to be_active
63
+ end
64
+
65
+ it 'should reactive a user' do
66
+ user.is_active = true
67
+ user = harvest.users.update(user)
68
+ expect(user).to be_active
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+
3
+ describe Harvest::Base do
4
+ describe 'username/password errors' do
5
+ it 'should raise error if missing credentials' do
6
+ lambda { Harvest::Base.new }
7
+ .should raise_error(/must provide either/i)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ describe Harvest::BasicAuthCredentials do
4
+ context '#set_authentication' do
5
+ it 'should set the headers Authorization' do
6
+ credentials = Harvest::BasicAuthCredentials.new(access_token: 'mytoken', account_id: '1')
7
+ credentials.set_authentication(options = {})
8
+
9
+ expect(options[:headers]['Authorization']).to eql('Bearer mytoken')
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe Harvest::ExpenseCategory do
4
+ it_behaves_like 'a json sanitizer', %w(cache_version)
5
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe Harvest::Expense do
4
+ it_behaves_like 'a json sanitizer', %w(cache_version)
5
+
6
+ describe "#spent_date" do
7
+ it "should parse strings" do
8
+ date = RUBY_VERSION =~ /1.8/ ? "12/01/2009" : "01/12/2009"
9
+ expense = Harvest::Expense.new(:spent_date => date)
10
+ expense.spent_date.should == Date.parse(date)
11
+ end
12
+
13
+ it "should accept times" do
14
+ expense = Harvest::Expense.new(:spent_date => Time.utc(2009, 12, 1))
15
+ expense.spent_date.should == Date.new(2009, 12, 1)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe Harvest::InvoiceMessage do
4
+ it_behaves_like 'a json sanitizer', %w(cache_version)
5
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe Harvest::InvoicePayment do
4
+ it_behaves_like 'a json sanitizer', %w(cache_version)
5
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe Harvest::Invoice do
4
+ it_behaves_like 'a json sanitizer', %w(cache_version)
5
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe Harvest::OAuthCredentials do
4
+ context '#set_authentication' do
5
+ it "should set the access token in the query" do
6
+ credentials = Harvest::OAuthCredentials.new(access_token: 'theaccesstoken')
7
+ credentials.set_authentication(options = {})
8
+ options[:query]['access_token'].should == 'theaccesstoken'
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe Harvest::Project do
4
+ it_behaves_like 'a json sanitizer', %w(cache_version)
5
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe Harvest::TaskAssignment do
4
+ it_behaves_like 'a json sanitizer', %w(cache_version)
5
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe Harvest::Task do
4
+ it_behaves_like 'a json sanitizer', %w(cache_version)
5
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe Harvest::TimeEntry do
4
+ context '#as_json' do
5
+ it 'builds a specialized hash' do
6
+ entry = Harvest::TimeEntry.new(:notes => 'the notes', :project_id => 'the project id', :task_id => 'the task id', :hours => 'the hours', :spent_date => Time.utc(2009, 12, 28))
7
+ entry.as_json.should == {"notes" => "the notes", "hours" => "the hours", "project_id" => "the project id", "task_id" => "the task id", "spent_date" => "2009-12-28"}
8
+ end
9
+ end
10
+
11
+ context "#spent_date" do
12
+ it "should parse strings" do
13
+ date = RUBY_VERSION =~ /1.8/ ? "12/01/2009" : "01/12/2009"
14
+ entry = Harvest::TimeEntry.new(:spent_date => date)
15
+ entry.spent_date.should == Date.parse(date)
16
+ end
17
+
18
+ it "should accept times" do
19
+ entry = Harvest::TimeEntry.new(:spent_date => Time.utc(2009, 12, 1))
20
+ entry.spent_date.should == Date.new(2009, 12, 1)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe Harvest::UserAssignment do
4
+ it_behaves_like 'a json sanitizer', %w(cache_version)
5
+ end
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+
3
+ describe Harvest::User do
4
+ it_behaves_like 'a json sanitizer', %w(cache_version)
5
+
6
+ describe "#timezone" do
7
+ it "should convert friendly timezone setting" do
8
+ p = Harvest::User.new(:timezone => :cst)
9
+ p.timezone.should == 'Central Time (US & Canada)'
10
+
11
+ p = Harvest::User.new(:timezone => :est)
12
+ p.timezone.should == 'Eastern Time (US & Canada)'
13
+
14
+ p = Harvest::User.new(:timezone => :mst)
15
+ p.timezone.should == 'Mountain Time (US & Canada)'
16
+
17
+ p = Harvest::User.new(:timezone => :pst)
18
+ p.timezone.should == 'Pacific Time (US & Canada)'
19
+
20
+ p = Harvest::User.new(:timezone => 'pst')
21
+ p.timezone.should == 'Pacific Time (US & Canada)'
22
+ end
23
+
24
+ it "should convert standard zones" do
25
+ p = Harvest::User.new(:timezone => 'america/chicago')
26
+ p.timezone.should == 'Central Time (US & Canada)'
27
+ end
28
+
29
+ it "should leave literal zones" do
30
+ p = Harvest::User.new(:timezone => 'Central Time (US & Canada)')
31
+ p.timezone.should == 'Central Time (US & Canada)'
32
+ end
33
+ end
34
+ end