harvested2 5.0.3

Sign up to get free protection for your applications and to get access to all the features.
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,42 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'harvest errors' do
4
+ let(:harvest) { Harvest.client(access_token: 'mytoken', account_id: '123') }
5
+
6
+ before { WebMock.disable_net_connect! }
7
+
8
+ context 'wraps errors' do
9
+ it 'sould returns a Harvest::BadRequest error' do
10
+ stub_request(:get, /\/clients/).to_return({ status: ['400', 'Bad Request']},
11
+ { body: '[]', status: 200})
12
+ expect { harvest.clients.all }.to raise_error(Harvest::BadRequest)
13
+ end
14
+
15
+ it 'sould returns a Harvest::NotFound error' do
16
+ stub_request(:get, /\/clients/)
17
+ .to_return({ status: ['404', 'Not Found'] }, { body: '[]', status: 200})
18
+ expect { harvest.clients.all }.to raise_error(Harvest::NotFound)
19
+ end
20
+
21
+ it 'sould returns a Harvest::ServerError error' do
22
+ stub_request(:get, /\/clients/)
23
+ .to_return({ status: ['500', 'Server Error'] },
24
+ { body: '[]', status: 200 })
25
+ expect { harvest.clients.all }.to raise_error(Harvest::ServerError)
26
+ end
27
+
28
+ it 'sould returns a Harvest::Unavailable error' do
29
+ stub_request(:get, /\/clients/)
30
+ .to_return({ status: ['502', 'Bad Gateway'] },
31
+ { body: '[]', status: 200 })
32
+ expect { harvest.clients.all }.to raise_error(Harvest::Unavailable)
33
+ end
34
+
35
+ it 'sould returns a Harvest::RateLimited error' do
36
+ stub_request(:get, /\/clients/)
37
+ .to_return({ status: ['503', 'Rate Limited'] },
38
+ { body: '[]', status: 200 })
39
+ expect { harvest.clients.all }.to raise_error(Harvest::RateLimited)
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,97 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'harvest expenses' do
4
+ let(:harvest) { Harvest.client(access_token: 'mytoken', account_id: '123') }
5
+
6
+ describe 'categories' do
7
+ let(:expense_category) { create(:expense_category) }
8
+ let(:expense_category_attributes) do
9
+ FactoryBot.attributes_for(:expense_category)
10
+ end
11
+
12
+ context 'allows to add clients' do
13
+ before do
14
+ allow(harvest.expense_categories).to receive(:create)
15
+ .and_return(expense_category)
16
+ end
17
+
18
+ it 'returns true' do
19
+ expect(expense_category.name).to eql('Mileage')
20
+ end
21
+ end
22
+
23
+ context 'allows to update clients' do
24
+ before do
25
+ allow(harvest.expense_categories).to receive(:update)
26
+ .and_return(expense_category)
27
+ expense_category.name = 'Travel'
28
+ expense_category = harvest.expense_categories.update(expense_category)
29
+ end
30
+
31
+ it 'returns true' do
32
+ expect(expense_category.name).to eql('Travel')
33
+ end
34
+ end
35
+
36
+ context 'allows to delete clients' do
37
+ before do
38
+ allow(harvest.expense_categories).to receive(:delete).and_return([])
39
+ allow(harvest.expense_categories).to receive(:all).and_return([])
40
+ harvest.expense_categories.delete(expense_category)
41
+ end
42
+
43
+ it 'returns true' do
44
+ expect(harvest.expense_categories.all.select do |e|
45
+ e.name == 'Travel'
46
+ end).to eql([])
47
+ end
48
+ end
49
+ end
50
+
51
+ describe 'expenses' do
52
+ let(:client) { create(:client) }
53
+ let(:project) { create(:project, client: client) }
54
+ let(:expense_category) { create(:expense_category) }
55
+ let(:expense) do
56
+ create(:expense, project: project, expense_category: expense_category)
57
+ end
58
+
59
+ context 'allows to add expense' do
60
+ before do
61
+ allow(harvest.expenses).to receive(:create)
62
+ .and_return(expense)
63
+ end
64
+
65
+ it 'returns true' do
66
+ expect(expense.notes).to eql('Drive to Chicago')
67
+ end
68
+ end
69
+
70
+ context 'allows to update expense' do
71
+ before do
72
+ allow(harvest.expenses).to receive(:update)
73
+ .and_return(expense)
74
+ expense.notes = 'Off to Chicago'
75
+ expense = harvest.expenses.update(expense)
76
+ end
77
+
78
+ it 'returns true' do
79
+ expect(expense.notes).to eql('Off to Chicago')
80
+ end
81
+ end
82
+
83
+ context 'allows to delete clients' do
84
+ before do
85
+ allow(harvest.expenses).to receive(:delete).and_return([])
86
+ allow(harvest.expenses).to receive(:all).and_return([])
87
+ harvest.expenses.delete(expense)
88
+ end
89
+
90
+ it 'returns true' do
91
+ expect(harvest.expenses.all(Time.utc(2009, 12, 28)).select do |e|
92
+ e.notes == 'Off to Chicago'
93
+ end).to eql([])
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'harvest invoice messages' do
4
+ let(:harvest) { Harvest.client(access_token: 'mytoken', account_id: '123') }
5
+
6
+ describe 'invoice messages' do
7
+ let(:invoice) { create(:invoice) }
8
+ let(:invoice_message) { create(:invoice_message) }
9
+
10
+ context 'allows to add invoice_messages' do
11
+ before do
12
+ allow(harvest.invoice_messages).to receive(:create)
13
+ .and_return(invoice_message)
14
+ end
15
+
16
+ it 'returns true' do
17
+ expect(invoice_message.body).to eql('The message body goes here')
18
+ end
19
+ end
20
+
21
+ context 'allows to update invoice_messages' do
22
+ before do
23
+ allow(harvest.invoice_messages).to receive(:update)
24
+ .and_return(invoice_message)
25
+ invoice_message.body = 'New body text'
26
+ invoice_message = harvest.invoice_messages.update(invoice_message)
27
+ end
28
+
29
+ it 'returns true' do
30
+ expect(invoice_message.body).to eql('New body text')
31
+ end
32
+ end
33
+
34
+ context 'allows to remove invoice_messages' do
35
+ before do
36
+ allow(harvest.invoice_messages).to receive(:delete).and_return([])
37
+ allow(harvest.invoice_messages).to receive(:all).and_return([])
38
+ harvest.invoice_messages.delete(invoice_message)
39
+ end
40
+
41
+ it 'returns true' do
42
+ expect(harvest.invoice_messages.all.select do |i|
43
+ i.body == 'New body text'
44
+ end).to eql([])
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'harvest invoice payments' do
4
+ let(:harvest) { Harvest.client(access_token: 'mytoken', account_id: '123') }
5
+
6
+ describe 'invoice payments' do
7
+ let(:invoice) { create(:invoice) }
8
+ let(:invoice_payment) { create(:invoice_payment, amount: invoice.amount) }
9
+ let(:invoice_payment_attributes) do
10
+ FactoryBot.attributes_for(:invoice_payment)
11
+ end
12
+
13
+ context 'allows to add invoice_payments' do
14
+ before do
15
+ allow(harvest.invoice_payments).to receive(:create)
16
+ .and_return(invoice_payment)
17
+ end
18
+
19
+ it 'returns true' do
20
+ expect(invoice_payment.amount).to eql(invoice.amount)
21
+ end
22
+ end
23
+
24
+ context 'allows to update invoice_payments' do
25
+ before do
26
+ allow(harvest.invoice_payments).to receive(:update)
27
+ .and_return(invoice_payment)
28
+ invoice_payment.amount = 200
29
+ invoice_payment = harvest.invoice_payments.update(invoice_payment)
30
+ end
31
+
32
+ it 'returns true' do
33
+ expect(invoice_payment.amount).to eql(200)
34
+ end
35
+ end
36
+
37
+ context 'allows to remove invoice_payments' do
38
+ before do
39
+ allow(harvest.invoice_payments).to receive(:delete).and_return([])
40
+ allow(harvest.invoice_payments).to receive(:all).and_return([])
41
+ harvest.invoice_payments.delete(invoice_payment)
42
+ end
43
+
44
+ it 'returns true' do
45
+ expect(harvest.invoice_payments.all.select do |i|
46
+ i.amount == 200
47
+ end).to eql([])
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,138 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'harvest invoices' do
4
+ let(:harvest) { Harvest.client(access_token: 'mytoken', account_id: '123') }
5
+
6
+ describe 'categories' do
7
+ let(:invoice_category) { create(:invoice_category) }
8
+
9
+ context 'allows to add invoice categories' do
10
+ before do
11
+ allow(harvest.invoice_categories).to receive(:create)
12
+ .and_return(invoice_category)
13
+ end
14
+
15
+ it 'returns true' do
16
+ expect(invoice_category.name).to eql('New Category')
17
+ end
18
+ end
19
+
20
+ context 'allows to update invoice categories' do
21
+ before do
22
+ allow(harvest.invoice_categories).to receive(:update)
23
+ .and_return(invoice_category)
24
+ invoice_category.name = 'Updated Category'
25
+ invoice_category = harvest.invoice_categories.update(invoice_category)
26
+ end
27
+
28
+ it 'returns true' do
29
+ expect(invoice_category.name).to eql('Updated Category')
30
+ end
31
+ end
32
+
33
+ context 'allows to remove invoice categories' do
34
+ before do
35
+ allow(harvest.invoice_categories).to receive(:delete).and_return([])
36
+ allow(harvest.invoice_categories).to receive(:all).and_return([])
37
+ harvest.invoice_categories.delete(invoice_category)
38
+ end
39
+
40
+ it 'returns true' do
41
+ expect(harvest.invoice_categories.all.select do |p|
42
+ p.name == 'Updated Category'
43
+ end).to eql([])
44
+ end
45
+ end
46
+ end
47
+
48
+ describe 'invoices' do
49
+ let(:invoice_category) { create(:invoice_category) }
50
+ let(:invoice) { create(:invoice) }
51
+ let(:line_item) { create(:line_item) }
52
+
53
+ context 'allows to add invoice invoices' do
54
+ before do
55
+ allow(harvest.invoices).to receive(:create)
56
+ .and_return(invoice)
57
+ end
58
+
59
+ it 'returns true' do
60
+ expect(invoice.subject)
61
+ .to eql("Invoice for Joe's Stream Cleaning")
62
+ expect(invoice.amount).to eql(2400.0)
63
+ expect(invoice.line_items.size).to eql(0)
64
+ end
65
+ end
66
+
67
+ context 'allows to update invoices' do
68
+ before do
69
+ allow(harvest.invoices).to receive(:update)
70
+ .and_return(invoice)
71
+ invoice.subject = 'Updated Invoice for Joe'
72
+ invoice.line_items << line_item
73
+ invoice.update_line_items = true
74
+ invoice.amount = 4800.0
75
+ invoice = harvest.invoices.update(invoice)
76
+ end
77
+
78
+ it 'returns true' do
79
+ expect(invoice.subject).to eql('Updated Invoice for Joe')
80
+ expect(invoice.amount).to eql(4800.0)
81
+ expect(invoice.line_items.size).to eql(1)
82
+ end
83
+ end
84
+
85
+ context 'allows to remove invoices' do
86
+ before do
87
+ allow(harvest.invoices).to receive(:delete).and_return([])
88
+ allow(harvest.invoices).to receive(:all).and_return([])
89
+ harvest.invoices.delete(invoice)
90
+ end
91
+
92
+ it 'returns true' do
93
+ expect(harvest.invoices.all.select do |i|
94
+ i.number == '1000'
95
+ end).to eql([])
96
+ end
97
+ end
98
+ end
99
+
100
+ describe 'read' do
101
+ let(:invoice_category) { create(:invoice_category) }
102
+ let(:invoice) { create(:invoice) }
103
+ let(:line_item) { create(:line_item) }
104
+ let(:invoice_attributes) { FactoryBot.attributes_for(:invoice) }
105
+ let(:invoices) { [invoice] }
106
+
107
+ context 'allows finding one invoice with parameters' do
108
+ before do
109
+ allow(harvest.invoices).to receive(:create)
110
+ .and_return(invoice)
111
+ allow(harvest.invoices).to receive(:find)
112
+ .and_return(invoice)
113
+ allow(harvest.invoices).to receive(:all).and_return(invoices)
114
+
115
+ invoice = harvest.invoices.create(invoice_attributes)
116
+ invoice.line_items << line_item
117
+ result = harvest.invoices.find(invoice.id)
118
+ end
119
+
120
+ it 'returns a specific invoice' do
121
+ expect(invoice.subject).to eql("Invoice for Joe's Stream Cleaning")
122
+ expect(invoice.amount).to eql(2400.0)
123
+ expect(invoice.line_items.size).to eql(1)
124
+ expect(invoice.due_at).to eql('2011-03-31')
125
+ expect(invoices.count).to eql(1)
126
+ end
127
+
128
+ it 'returns invoices' do
129
+ invoices = harvest.invoices.all(status: 'draft')
130
+ expect(invoice.subject).to eql("Invoice for Joe's Stream Cleaning")
131
+ expect(invoice.amount).to eql(2400.0)
132
+ expect(invoice.line_items.size).to eql(1)
133
+ expect(invoice.due_at).to eql('2011-03-31')
134
+ expect(invoices.count).to eql(1)
135
+ end
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,76 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'harvest projects' do
4
+ let(:harvest) { Harvest.client(access_token: 'mytoken', account_id: '123') }
5
+
6
+ describe 'projects' do
7
+ let(:client) { create(:client) }
8
+ let(:project) { create(:project, client: client) }
9
+ let(:project_attributes) { FactoryBot.attributes_for(:project) }
10
+
11
+ context 'allows to add projects' do
12
+ before do
13
+ allow(harvest.projects).to receive(:create).and_return(project)
14
+ project = harvest.projects.create(project_attributes)
15
+ end
16
+
17
+ it 'should return true' do
18
+ expect(project.name).to eql('Project Test')
19
+ end
20
+ end
21
+
22
+ context 'allows to update projects' do
23
+ before do
24
+ allow(harvest.projects).to receive(:update).and_return(project)
25
+ project.name = 'Updated Project'
26
+ project = harvest.projects.update(project)
27
+ end
28
+
29
+ it 'should return true' do
30
+ expect(project.name).to eql('Updated Project')
31
+ end
32
+ end
33
+
34
+ context 'allows to remove projects' do
35
+ before do
36
+ allow(harvest.projects).to receive(:delete).and_return([])
37
+ allow(harvest.projects).to receive(:all).and_return([])
38
+ harvest.projects.delete(project)
39
+ end
40
+
41
+ it 'returns true' do
42
+ expect(harvest.projects.all.select do |p|
43
+ p.name == 'Updated Project'
44
+ end).to eql([])
45
+ end
46
+ end
47
+ end
48
+
49
+ describe 'clients' do
50
+ context 'allows activating and deactivating clients' do
51
+ let(:active_project) { create(:project, :active) }
52
+ let(:deactive_project) { create(:project, :deactive) }
53
+
54
+ before do
55
+ allow(harvest.projects).to receive(:deactivate)
56
+ .and_return(deactive_project)
57
+ allow(harvest.projects).to receive(:activate)
58
+ .and_return(active_project)
59
+ end
60
+
61
+ it 'should be active' do
62
+ expect(active_project).to be_active
63
+ end
64
+
65
+ it 'should be deactive' do
66
+ project = harvest.projects.deactivate(project)
67
+ expect(deactive_project).not_to be_active
68
+ end
69
+
70
+ it 'should reactive a project' do
71
+ project = harvest.projects.activate(project)
72
+ expect(active_project).to be_active
73
+ end
74
+ end
75
+ end
76
+ end