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.
- data/COPYRIGHT.txt +18 -0
- data/CREDITS.txt +5 -0
- data/GPL.txt +339 -0
- data/README.rdoc +93 -0
- data/Rakefile +37 -0
- data/VERSION +1 -0
- data/app/controllers/rate_caches_controller.rb +35 -0
- data/app/controllers/rates_controller.rb +154 -0
- data/app/models/rate.rb +161 -0
- data/app/views/rate_caches/index.html.erb +21 -0
- data/app/views/rates/_form.html.erb +36 -0
- data/app/views/rates/_list.html.erb +42 -0
- data/app/views/rates/create.js.rjs +2 -0
- data/app/views/rates/create_error.js.rjs +5 -0
- data/app/views/rates/edit.html.erb +3 -0
- data/app/views/rates/index.html.erb +5 -0
- data/app/views/rates/new.html.erb +3 -0
- data/app/views/rates/show.html.erb +23 -0
- data/app/views/users/_membership_rate.html.erb +23 -0
- data/app/views/users/_rates.html.erb +17 -0
- data/assets/images/database_refresh.png +0 -0
- data/config/locales/de.yml +18 -0
- data/config/locales/en.yml +18 -0
- data/config/locales/fr.yml +20 -0
- data/config/locales/ru.yml +9 -0
- data/config/routes.rb +4 -0
- data/init.rb +49 -0
- data/lang/de.yml +9 -0
- data/lang/en.yml +9 -0
- data/lang/fr.yml +8 -0
- data/lib/rate_conversion.rb +16 -0
- data/lib/rate_memberships_hook.rb +15 -0
- data/lib/rate_project_hook.rb +106 -0
- data/lib/rate_sort_helper_patch.rb +102 -0
- data/lib/rate_time_entry_patch.rb +66 -0
- data/lib/rate_users_helper_patch.rb +37 -0
- data/lib/redmine_rate/hooks/plugin_timesheet_view_timesheets_report_header_tags_hook.rb +11 -0
- data/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_group_header_hook.rb +9 -0
- data/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_time_entry_hook.rb +18 -0
- data/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_time_entry_sum_hook.rb +17 -0
- data/lib/redmine_rate/hooks/plugin_timesheet_views_timesheets_time_entry_row_class_hook.rb +21 -0
- data/lib/redmine_rate/hooks/timesheet_hook_helper.rb +14 -0
- data/lib/redmine_rate/hooks/view_layouts_base_html_head_hook.rb +9 -0
- data/lib/tasks/cache.rake +13 -0
- data/lib/tasks/data.rake +163 -0
- data/rails/init.rb +1 -0
- data/test/functional/rates_controller_test.rb +401 -0
- data/test/integration/admin_panel_test.rb +81 -0
- data/test/integration/routing_test.rb +16 -0
- data/test/test_helper.rb +43 -0
- data/test/unit/lib/rate_time_entry_patch_test.rb +77 -0
- data/test/unit/lib/rate_users_helper_patch_test.rb +37 -0
- data/test/unit/lib/redmine_rate/hooks/plugin_timesheet_view_timesheets_report_header_tags_hook_test.rb +26 -0
- data/test/unit/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_group_header_hook_test.rb +26 -0
- data/test/unit/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_time_entry_hook_test.rb +47 -0
- data/test/unit/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_time_entry_sum_hook_test.rb +48 -0
- data/test/unit/lib/redmine_rate/hooks/plugin_timesheet_views_timesheets_time_entry_row_class_hook_test.rb +60 -0
- data/test/unit/rate_for_test.rb +74 -0
- data/test/unit/rate_test.rb +333 -0
- metadata +137 -0
data/test/unit/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_group_header_hook_test.rb
ADDED
@@ -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
|
data/test/unit/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_time_entry_hook_test.rb
ADDED
@@ -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 => ' '
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/test/unit/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_time_entry_sum_hook_test.rb
ADDED
@@ -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
|