redmine_rate 0.2.0

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 (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