redmine_rate 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. data/COPYRIGHT.txt +18 -0
  2. data/CREDITS.txt +5 -0
  3. data/GPL.txt +339 -0
  4. data/README.rdoc +93 -0
  5. data/Rakefile +37 -0
  6. data/VERSION +1 -0
  7. data/app/controllers/rate_caches_controller.rb +35 -0
  8. data/app/controllers/rates_controller.rb +154 -0
  9. data/app/models/rate.rb +161 -0
  10. data/app/views/rate_caches/index.html.erb +21 -0
  11. data/app/views/rates/_form.html.erb +36 -0
  12. data/app/views/rates/_list.html.erb +42 -0
  13. data/app/views/rates/create.js.rjs +2 -0
  14. data/app/views/rates/create_error.js.rjs +5 -0
  15. data/app/views/rates/edit.html.erb +3 -0
  16. data/app/views/rates/index.html.erb +5 -0
  17. data/app/views/rates/new.html.erb +3 -0
  18. data/app/views/rates/show.html.erb +23 -0
  19. data/app/views/users/_membership_rate.html.erb +23 -0
  20. data/app/views/users/_rates.html.erb +17 -0
  21. data/assets/images/database_refresh.png +0 -0
  22. data/config/locales/de.yml +18 -0
  23. data/config/locales/en.yml +18 -0
  24. data/config/locales/fr.yml +20 -0
  25. data/config/locales/ru.yml +9 -0
  26. data/config/routes.rb +4 -0
  27. data/init.rb +49 -0
  28. data/lang/de.yml +9 -0
  29. data/lang/en.yml +9 -0
  30. data/lang/fr.yml +8 -0
  31. data/lib/rate_conversion.rb +16 -0
  32. data/lib/rate_memberships_hook.rb +15 -0
  33. data/lib/rate_project_hook.rb +106 -0
  34. data/lib/rate_sort_helper_patch.rb +102 -0
  35. data/lib/rate_time_entry_patch.rb +66 -0
  36. data/lib/rate_users_helper_patch.rb +37 -0
  37. data/lib/redmine_rate/hooks/plugin_timesheet_view_timesheets_report_header_tags_hook.rb +11 -0
  38. data/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_group_header_hook.rb +9 -0
  39. data/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_time_entry_hook.rb +18 -0
  40. data/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_time_entry_sum_hook.rb +17 -0
  41. data/lib/redmine_rate/hooks/plugin_timesheet_views_timesheets_time_entry_row_class_hook.rb +21 -0
  42. data/lib/redmine_rate/hooks/timesheet_hook_helper.rb +14 -0
  43. data/lib/redmine_rate/hooks/view_layouts_base_html_head_hook.rb +9 -0
  44. data/lib/tasks/cache.rake +13 -0
  45. data/lib/tasks/data.rake +163 -0
  46. data/rails/init.rb +1 -0
  47. data/test/functional/rates_controller_test.rb +401 -0
  48. data/test/integration/admin_panel_test.rb +81 -0
  49. data/test/integration/routing_test.rb +16 -0
  50. data/test/test_helper.rb +43 -0
  51. data/test/unit/lib/rate_time_entry_patch_test.rb +77 -0
  52. data/test/unit/lib/rate_users_helper_patch_test.rb +37 -0
  53. data/test/unit/lib/redmine_rate/hooks/plugin_timesheet_view_timesheets_report_header_tags_hook_test.rb +26 -0
  54. data/test/unit/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_group_header_hook_test.rb +26 -0
  55. data/test/unit/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_time_entry_hook_test.rb +47 -0
  56. data/test/unit/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_time_entry_sum_hook_test.rb +48 -0
  57. data/test/unit/lib/redmine_rate/hooks/plugin_timesheet_views_timesheets_time_entry_row_class_hook_test.rb +60 -0
  58. data/test/unit/rate_for_test.rb +74 -0
  59. data/test/unit/rate_test.rb +333 -0
  60. metadata +137 -0
@@ -0,0 +1,26 @@
1
+ require File.dirname(__FILE__) + '/../../../../test_helper'
2
+
3
+ class RedmineRate::Hooks::PluginTimesheetViewsTimesheetGroupHeaderTest < ActionController::TestCase
4
+ include Redmine::Hook::Helper
5
+
6
+ def controller
7
+ @controller ||= ApplicationController.new
8
+ @controller.response ||= ActionController::TestResponse.new
9
+ @controller
10
+ end
11
+
12
+ def request
13
+ @request ||= ActionController::TestRequest.new
14
+ end
15
+
16
+ def hook(args={})
17
+ call_hook :plugin_timesheet_views_timesheet_group_header, args
18
+ end
19
+
20
+ context "#plugin_timesheet_views_timesheet_group_header" do
21
+ should "render the cost table header" do
22
+ @response.body = hook
23
+ assert_select "th", :text => "Cost"
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,47 @@
1
+ require File.dirname(__FILE__) + '/../../../../test_helper'
2
+
3
+ class RedmineRate::Hooks::PluginTimesheetViewsTimesheetTimeEntryTest < ActionController::TestCase
4
+ include Redmine::Hook::Helper
5
+
6
+ def controller
7
+ @controller ||= ApplicationController.new
8
+ @controller.response ||= ActionController::TestResponse.new
9
+ @controller
10
+ end
11
+
12
+ def request
13
+ @request ||= ActionController::TestRequest.new
14
+ end
15
+
16
+ def hook(args={})
17
+ call_hook :plugin_timesheet_views_timesheet_time_entry, args
18
+ end
19
+
20
+ context "#plugin_timesheet_views_timesheet_time_entry" do
21
+ context "for users with view rate permission" do
22
+ should "render a cost cell showing the cost for the time entry" do
23
+ User.current = User.generate!(:admin => true)
24
+ rate = Rate.generate!(:amount => 100)
25
+ time_entry = TimeEntry.generate!(:hours => 2, :rate => rate)
26
+
27
+ @response.body = hook(:time_entry => time_entry)
28
+
29
+ assert_select 'td', :text => "$200.00"
30
+
31
+ end
32
+ end
33
+
34
+ context "for users without view rate permission" do
35
+ should "render an empty cost cell" do
36
+ User.current = nil
37
+ rate = Rate.generate!(:amount => 100)
38
+ time_entry = TimeEntry.generate!(:hours => 2, :rate => rate)
39
+
40
+ @response.body = hook(:time_entry => time_entry)
41
+
42
+ assert_select 'td', :text => '&nbsp;'
43
+
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,48 @@
1
+ require File.dirname(__FILE__) + '/../../../../test_helper'
2
+
3
+ class RedmineRate::Hooks::PluginTimesheetViewsTimesheetTimeEntrySumTest < ActionController::TestCase
4
+ include Redmine::Hook::Helper
5
+
6
+ def controller
7
+ @controller ||= ApplicationController.new
8
+ @controller.response ||= ActionController::TestResponse.new
9
+ @controller
10
+ end
11
+
12
+ def request
13
+ @request ||= ActionController::TestRequest.new
14
+ end
15
+
16
+ def hook(args={})
17
+ call_hook :plugin_timesheet_views_timesheet_time_entry_sum, args
18
+ end
19
+
20
+ context "#plugin_timesheet_views_timesheet_time_entry_sum" do
21
+ context "for users with view rate permission" do
22
+ should "render a cost cell showing the total cost for the time entries" do
23
+ User.current = User.generate!(:admin => true)
24
+ rate = Rate.generate!(:amount => 100)
25
+ time_entry1 = TimeEntry.generate!(:hours => 2, :rate => rate)
26
+ time_entry2 = TimeEntry.generate!(:hours => 10, :rate => rate)
27
+
28
+ @response.body = hook(:time_entries => [time_entry1, time_entry2])
29
+
30
+ assert_select 'td', :text => "$1,200.00"
31
+
32
+ end
33
+ end
34
+
35
+ context "for users without view rate permission" do
36
+ should "render an empty cost cell" do
37
+ User.current = nil
38
+ rate = Rate.generate!(:amount => 100)
39
+ time_entry = TimeEntry.generate!(:hours => 2, :rate => rate)
40
+
41
+ @response.body = hook(:time_entries => [time_entry])
42
+
43
+ assert_select 'td', :text => '$0.00'
44
+
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,60 @@
1
+ require File.dirname(__FILE__) + '/../../../../test_helper'
2
+
3
+ class RedmineRate::Hooks::PluginTimesheetViewsTimesheetsTimeEntryRowClassTest < ActionController::TestCase
4
+ include Redmine::Hook::Helper
5
+
6
+ def controller
7
+ @controller ||= ApplicationController.new
8
+ @controller.response ||= ActionController::TestResponse.new
9
+ @controller
10
+ end
11
+
12
+ def request
13
+ @request ||= ActionController::TestRequest.new
14
+ end
15
+
16
+ def hook(args={})
17
+ call_hook :plugin_timesheet_views_timesheets_time_entry_row_class, args
18
+ end
19
+
20
+ context "#plugin_timesheet_views_timesheets_time_entry_row_class" do
21
+ context "for users with view rate permission" do
22
+ setup do
23
+ User.current = User.generate!(:admin => true)
24
+ end
25
+
26
+ should "render a missing rate css class if the time entry has no cost" do
27
+ time_entry = TimeEntry.generate!(:hours => 2, :rate => nil)
28
+
29
+ assert_equal "missing-rate", hook(:time_entry => time_entry)
30
+ end
31
+
32
+ should "render nothing if the time entry has a cost" do
33
+ rate = Rate.generate!(:amount => 100)
34
+ time_entry = TimeEntry.generate!(:hours => 2, :rate => rate)
35
+
36
+ assert_equal "", hook(:time_entry => time_entry)
37
+ end
38
+ end
39
+
40
+ context "for users without view rate permission" do
41
+ setup do
42
+ User.current = nil
43
+ end
44
+
45
+ should "render nothing if the time entry has no cost" do
46
+ time_entry = TimeEntry.generate!(:hours => 2, :rate => nil)
47
+
48
+ assert_equal "", hook(:time_entry => time_entry)
49
+ end
50
+
51
+ should "render nothing if the time entry has a cost" do
52
+ rate = Rate.generate!(:amount => 100)
53
+ time_entry = TimeEntry.generate!(:hours => 2, :rate => rate)
54
+
55
+ assert_equal "", hook(:time_entry => time_entry)
56
+ end
57
+ end
58
+
59
+ end
60
+ end
@@ -0,0 +1,74 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ # Test cases for the main Rate#for API
4
+ class RateForTest < ActiveSupport::TestCase
5
+ context 'calculated for' do
6
+ setup do
7
+ @user = User.generate!
8
+ end
9
+
10
+ context 'a user with no Rates' do
11
+ should 'should return nil' do
12
+ assert_nil Rate.for(@user)
13
+ end
14
+ end
15
+
16
+ context 'a user with one default Rate' do
17
+ should 'should return the Rate if the Rate is effective today' do
18
+ rate = Rate.create!({ :user_id => @user.id, :amount => 100.0, :date_in_effect => Date.today})
19
+ assert_equal rate, Rate.for(@user)
20
+ end
21
+
22
+ should 'should return nil if the Rate is not effective yet' do
23
+ assert_nil Rate.for(@user)
24
+ end
25
+
26
+ should 'should return the same default Rate on all projects' do
27
+ project = Project.generate!
28
+ rate = Rate.create!({ :user_id => @user.id, :amount => 100.0, :date_in_effect => Date.today})
29
+ assert_equal rate, Rate.for(@user, project)
30
+ end
31
+ end
32
+
33
+ context 'a user with two default Rates' do
34
+ should 'should return the newest Rate before the todays date' do
35
+ rate = Rate.create!({ :user_id => @user.id, :amount => 100.0, :date_in_effect => Date.yesterday})
36
+ rate2 = Rate.create!({ :user_id => @user.id, :amount => 300.0, :date_in_effect => Date.today})
37
+ assert_equal rate2, Rate.for(@user)
38
+ end
39
+ end
40
+
41
+ context 'a user with a default Rate and Rate on a project' do
42
+ should 'should return the project Rate if its effective today' do
43
+ project = Project.generate!
44
+ rate = Rate.create!({ :user_id => @user.id, :project => project, :amount => 100.0, :date_in_effect => Date.yesterday})
45
+ rate2 = Rate.create!({ :user_id => @user.id, :amount => 300.0, :date_in_effect => Date.today})
46
+ assert_equal rate, Rate.for(@user, project)
47
+ end
48
+
49
+ should 'should return the default Rate if the project Rate isnt effective yet but the default Rate is' do
50
+ project = Project.generate!
51
+ rate = Rate.create!({ :user_id => @user.id, :project => project, :amount => 100.0, :date_in_effect => Date.tomorrow})
52
+ rate2 = Rate.create!({ :user_id => @user.id, :amount => 300.0, :date_in_effect => Date.today})
53
+ assert_equal rate2, Rate.for(@user, project)
54
+ end
55
+
56
+ should 'should return nil if neither Rate is effective yet' do
57
+ project = Project.generate!
58
+ rate = Rate.create!({ :user_id => @user.id, :project => project, :amount => 100.0, :date_in_effect => Date.tomorrow})
59
+ rate2 = Rate.create!({ :user_id => @user.id, :amount => 300.0, :date_in_effect => Date.tomorrow})
60
+ assert_nil Rate.for(@user, project)
61
+ end
62
+ end
63
+
64
+ context 'a user with two Rates on a project' do
65
+ should 'should return the newest Rate before the todays date' do
66
+ project = Project.generate!
67
+ rate = Rate.create!({ :user_id => @user.id, :project => project, :amount => 100.0, :date_in_effect => Date.yesterday})
68
+ rate2 = Rate.create!({ :user_id => @user.id, :project => project, :amount => 300.0, :date_in_effect => Date.today})
69
+ assert_equal rate2, Rate.for(@user, project)
70
+ end
71
+ end
72
+ end
73
+
74
+ end
@@ -0,0 +1,333 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class RateTest < ActiveSupport::TestCase
4
+ def rate_valid_attributes
5
+ {
6
+ :user => User.generate!,
7
+ :project => Project.generate!,
8
+ :date_in_effect => Date.new(Date.today.year, 1, 1),
9
+ :amount => 100.50
10
+ }
11
+ end
12
+
13
+ should_belong_to :project
14
+ should_belong_to :user
15
+ should_have_many :time_entries
16
+
17
+ should_validate_presence_of :user_id
18
+ should_validate_presence_of :date_in_effect
19
+ should_validate_numericality_of :amount
20
+
21
+
22
+ context '#locked?' do
23
+ should 'should be true if a Time Entry is associated' do
24
+ rate = Rate.new
25
+ rate.time_entries << TimeEntry.generate!
26
+ assert rate.locked?
27
+ end
28
+
29
+ should 'should be false if no Time Entries are associated' do
30
+ rate = Rate.new
31
+ assert ! rate.locked?
32
+ end
33
+ end
34
+
35
+
36
+ context '#unlocked?' do
37
+ should 'should be false if a Time Entry is associated' do
38
+ rate = Rate.new
39
+ rate.time_entries << TimeEntry.generate!
40
+ assert ! rate.unlocked?
41
+ end
42
+
43
+ should 'should be true if no Time Entries are associated' do
44
+ rate = Rate.new
45
+ assert rate.unlocked?
46
+ end
47
+
48
+ end
49
+
50
+ context '#save' do
51
+
52
+ should 'should save if a Rate is unlocked' do
53
+ rate = Rate.new(rate_valid_attributes)
54
+ assert rate.save
55
+ end
56
+
57
+ should 'should not save if a Rate is locked' do
58
+ rate = Rate.new(rate_valid_attributes)
59
+ rate.time_entries << TimeEntry.generate!
60
+ assert !rate.save
61
+ end
62
+ end
63
+
64
+
65
+
66
+
67
+ context '#destroy' do
68
+
69
+ should 'should destroy the Rate if should is unlocked' do
70
+ rate = Rate.create(rate_valid_attributes)
71
+ assert_difference('Rate.count', -1) do
72
+ rate.destroy
73
+ end
74
+
75
+ end
76
+
77
+ should 'should not destroy the Rate if should is locked' do
78
+ rate = Rate.create(rate_valid_attributes)
79
+ rate.time_entries << TimeEntry.generate!
80
+
81
+ assert_difference('Rate.count', 0) do
82
+ rate.destroy
83
+ end
84
+ end
85
+ end
86
+
87
+ context "after save" do
88
+ should "recalculate all of the cached cost of all Time Entries for the user" do
89
+ @user = User.generate!
90
+ @project = Project.generate!
91
+ @date = Date.today.to_s
92
+ @past_date = 1.month.ago.strftime('%Y-%m-%d')
93
+ @rate = Rate.generate!(:user => @user, :project => @project, :date_in_effect => @date, :amount => 200.0)
94
+ @time_entry1 = TimeEntry.generate!({:user => @user, :project => @project, :spent_on => @date, :hours => 10.0, :activity => TimeEntryActivity.generate!})
95
+ @time_entry2 = TimeEntry.generate!({:user => @user, :project => @project, :spent_on => @past_date, :hours => 20.0, :activity => TimeEntryActivity.generate!})
96
+
97
+
98
+ assert_equal 2000.00, @time_entry1.cost
99
+ assert_equal 0, @time_entry2.cost
100
+
101
+ @old_rate = Rate.generate!(:user => @user, :project => @project, :date_in_effect => 2.months.ago.strftime('%Y-%m-%d'), :amount => 10.0)
102
+
103
+ assert_equal 2000.00, TimeEntry.find(@time_entry1.id).cost
104
+ assert_equal 200.00, TimeEntry.find(@time_entry2.id).cost
105
+ end
106
+
107
+ end
108
+
109
+ context "after destroy" do
110
+ should "recalculate all of the cached cost of all Time Entries for the user" do
111
+ @user = User.generate!
112
+ @project = Project.generate!
113
+ @date = Date.today.to_s
114
+ @past_date = 1.month.ago.strftime('%Y-%m-%d')
115
+ @rate = Rate.generate!(:user => @user, :project => @project, :date_in_effect => @date, :amount => 200.0)
116
+ @old_rate = Rate.generate!(:user => @user, :project => @project, :date_in_effect => 2.months.ago.strftime('%Y-%m-%d'), :amount => 10.0)
117
+
118
+ @time_entry1 = TimeEntry.generate!({:user => @user, :project => @project, :spent_on => @date, :hours => 10.0, :activity => TimeEntryActivity.generate!})
119
+ @time_entry2 = TimeEntry.generate!({:user => @user, :project => @project, :spent_on => @past_date, :hours => 20.0, :activity => TimeEntryActivity.generate!})
120
+
121
+
122
+ assert_equal 2000.00, @time_entry1.cost
123
+ assert_equal 2000.00, @time_entry1.read_attribute(:cost)
124
+ assert_equal 200.0, @time_entry2.cost
125
+ assert_equal 200.0, @time_entry2.read_attribute(:cost)
126
+
127
+ @old_rate.destroy
128
+
129
+ assert_equal 2000.0, TimeEntry.find(@time_entry1.id).cost
130
+ assert_equal 0, TimeEntry.find(@time_entry2.id).cost
131
+ end
132
+
133
+ end
134
+
135
+ context '#for' do
136
+ setup do
137
+ @user = User.generate!
138
+ @project = Project.generate!
139
+ @date = '2009-01-01'
140
+ @date = Date.new(Date.today.year, 1, 1).to_s
141
+ @default_rate = Rate.generate!(:amount => 100.10, :date_in_effect => @date, :project => nil, :user => @user)
142
+ @rate = Rate.generate!(:amount => 50.50, :date_in_effect => @date, :project => @project, :user => @user)
143
+ end
144
+
145
+ context 'parameters' do
146
+ should 'should be passed user' do
147
+ assert_raises ArgumentError do
148
+ Rate.for
149
+ end
150
+ end
151
+
152
+ should 'can be passed an optional project' do
153
+ assert_nothing_raised do
154
+ Rate.for(@user)
155
+ end
156
+
157
+ assert_nothing_raised do
158
+ Rate.for(@user, @project)
159
+ end
160
+ end
161
+
162
+ should 'can be passed an optional date string' do
163
+ assert_nothing_raised do
164
+ Rate.for(@user)
165
+ end
166
+
167
+ assert_nothing_raised do
168
+ Rate.for(@user, nil, @date)
169
+ end
170
+ end
171
+
172
+ end
173
+
174
+ context 'returns' do
175
+ should 'a Rate object when there is a rate' do
176
+ assert_equal @rate, Rate.for(@user, @project, @date)
177
+ end
178
+
179
+ should 'a nil when there is no rate' do
180
+ assert @rate.destroy
181
+ assert @default_rate.destroy
182
+
183
+ assert_equal nil, Rate.for(@user, @project, @date)
184
+ end
185
+ end
186
+
187
+ context 'with a user, project, and date' do
188
+ should 'should find the rate for a user on the project before the date' do
189
+ assert_equal @rate, Rate.for(@user, @project, @date)
190
+ end
191
+
192
+ should 'should return the most recent rate found' do
193
+ assert_equal @rate, Rate.for(@user, @project, @date)
194
+ end
195
+
196
+ should 'should check for a default rate if no rate is found' do
197
+ assert @rate.destroy
198
+
199
+ assert_equal @default_rate, Rate.for(@user, @project, @date)
200
+ end
201
+
202
+ should 'should return nil if no set or default rate is found' do
203
+ assert @rate.destroy
204
+ assert @default_rate.destroy
205
+
206
+ assert_equal nil, Rate.for(@user, @project, @date)
207
+ end
208
+ end
209
+
210
+ context 'with a user and project' do
211
+ should 'should find the rate for a user on the project before today' do
212
+ assert_equal @rate, Rate.for(@user, @project)
213
+ end
214
+
215
+ should 'should return the most recent rate found' do
216
+ assert_equal @rate, Rate.for(@user, @project)
217
+ end
218
+
219
+ should 'should return nil if no set or default rate is found' do
220
+ assert @rate.destroy
221
+ assert @default_rate.destroy
222
+
223
+ assert_equal nil, Rate.for(@user, @project)
224
+ end
225
+ end
226
+
227
+ context 'with a user' do
228
+ should 'should find the rate without a project for a user on the project before today' do
229
+ assert_equal @default_rate, Rate.for(@user)
230
+ end
231
+
232
+ should 'should return the most recent rate found' do
233
+ assert_equal @default_rate, Rate.for(@user)
234
+ end
235
+
236
+ should 'should return nil if no set or default rate is found' do
237
+ assert @rate.destroy
238
+ assert @default_rate.destroy
239
+
240
+ assert_equal nil, Rate.for(@user)
241
+ end
242
+ end
243
+
244
+ should 'with an invalid user should raise an InvalidParameterException' do
245
+ object = Object.new
246
+ assert_raises Rate::InvalidParameterException do
247
+ Rate.for(object)
248
+ end
249
+ end
250
+
251
+ should 'with an invalid project should raise an InvalidParameterException' do
252
+ object = Object.new
253
+ assert_raises Rate::InvalidParameterException do
254
+ Rate.for(@user, object)
255
+ end
256
+ end
257
+
258
+ should 'with an invalid object for date should raise an InvalidParameterException' do
259
+ object = Object.new
260
+ assert_raises Rate::InvalidParameterException do
261
+ Rate.for(@user, @project, object)
262
+ end
263
+ end
264
+
265
+ should 'with an invalid date string should raise an InvalidParameterException' do
266
+ assert_raises Rate::InvalidParameterException do
267
+ Rate.for(@user, @project, '2000-13-40')
268
+ end
269
+ end
270
+
271
+ end
272
+
273
+ context "#update_all_time_entries_with_missing_cost" do
274
+ setup do
275
+ @user = User.generate!
276
+ @project = Project.generate!
277
+ @date = Date.today.to_s
278
+ @rate = Rate.generate!(:user => @user, :project => @project, :date_in_effect => @date, :amount => 200.0)
279
+ @time_entry1 = TimeEntry.generate!({:user => @user, :project => @project, :spent_on => @date, :hours => 10.0, :activity => TimeEntryActivity.generate!})
280
+ @time_entry2 = TimeEntry.generate!({:user => @user, :project => @project, :spent_on => @date, :hours => 20.0, :activity => TimeEntryActivity.generate!})
281
+ end
282
+
283
+ should "update the caches of all Time Entries" do
284
+ TimeEntry.update_all('cost = null')
285
+
286
+ # Check that cost is NULL in the database, which skips the caching
287
+ assert_equal 2, ActiveRecord::Base.connection.select_all('select count(*) as count from time_entries where cost IS NULL').first["count"].to_i
288
+
289
+ Rate.update_all_time_entries_with_missing_cost
290
+
291
+ assert_equal 0, ActiveRecord::Base.connection.select_all('select count(*) as count from time_entries where cost IS NULL').first["count"].to_i
292
+
293
+ end
294
+
295
+ should "timestamp a successful run" do
296
+ assert_equal nil, Setting.plugin_redmine_rate['last_caching_run']
297
+
298
+ Rate.update_all_time_entries_with_missing_cost
299
+
300
+ assert Setting.plugin_redmine_rate['last_caching_run'], "Last run not timestamped"
301
+ assert Time.parse(Setting.plugin_redmine_rate['last_caching_run']), "Last run timestamp not parseable"
302
+ end
303
+ end
304
+
305
+ context "#update_all_time_entries_to_refresh_cache" do
306
+ setup do
307
+ @user = User.generate!
308
+ @project = Project.generate!
309
+ @date = Date.today.to_s
310
+ @rate = Rate.generate!(:user => @user, :project => @project, :date_in_effect => @date, :amount => 200.0)
311
+ @time_entry1 = TimeEntry.generate!({:user => @user, :project => @project, :spent_on => @date, :hours => 10.0, :activity => TimeEntryActivity.generate!})
312
+ @time_entry2 = TimeEntry.generate!({:user => @user, :project => @project, :spent_on => @date, :hours => 20.0, :activity => TimeEntryActivity.generate!})
313
+ end
314
+
315
+ should "update the caches of all Time Entries" do
316
+ assert_equal 0, ActiveRecord::Base.connection.select_all('select count(*) as count from time_entries where cost IS NULL').first["count"].to_i
317
+
318
+ Rate.update_all_time_entries_to_refresh_cache
319
+
320
+ assert_equal 0, ActiveRecord::Base.connection.select_all('select count(*) as count from time_entries where cost IS NULL').first["count"].to_i
321
+
322
+ end
323
+
324
+ should "timestamp a successful run" do
325
+ assert_equal nil, Setting.plugin_redmine_rate['last_cache_clearing_run']
326
+
327
+ Rate.update_all_time_entries_to_refresh_cache
328
+
329
+ assert Setting.plugin_redmine_rate['last_cache_clearing_run'], "Last run not timestamped"
330
+ assert Time.parse(Setting.plugin_redmine_rate['last_cache_clearing_run']), "Last run timestamp not parseable"
331
+ end
332
+ end
333
+ end