##// END OF EJS Templates
Fixed: time entries created with the default activity even if a different one is specified (#1302)....
Jean-Philippe Lang -
r1519:846045fd0590
parent child
Show More
@@ -1,71 +1,73
1 1 # redMine - project management software
2 2 # Copyright (C) 2006-2008 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 class TimeEntry < ActiveRecord::Base
19 19 # could have used polymorphic association
20 20 # project association here allows easy loading of time entries at project level with one database trip
21 21 belongs_to :project
22 22 belongs_to :issue
23 23 belongs_to :user
24 24 belongs_to :activity, :class_name => 'Enumeration', :foreign_key => :activity_id
25 25
26 26 attr_protected :project_id, :user_id, :tyear, :tmonth, :tweek
27 27
28 28 validates_presence_of :user_id, :activity_id, :project_id, :hours, :spent_on
29 29 validates_numericality_of :hours, :allow_nil => true
30 30 validates_length_of :comments, :maximum => 255
31 31
32 32 def after_initialize
33 if new_record?
34 self.activity ||= Enumeration.default('ACTI')
33 if new_record? && self.activity.nil?
34 if default_activity = Enumeration.default('ACTI')
35 self.activity_id = default_activity.id
36 end
35 37 end
36 38 end
37 39
38 40 def before_validation
39 41 self.project = issue.project if issue && project.nil?
40 42 end
41 43
42 44 def validate
43 45 errors.add :hours, :activerecord_error_invalid if hours && (hours < 0 || hours >= 1000)
44 46 errors.add :project_id, :activerecord_error_invalid if project.nil?
45 47 errors.add :issue_id, :activerecord_error_invalid if (issue_id && !issue) || (issue && project!=issue.project)
46 48 end
47 49
48 50 def hours=(h)
49 51 write_attribute :hours, (h.is_a?(String) ? h.to_hours : h)
50 52 end
51 53
52 54 # tyear, tmonth, tweek assigned where setting spent_on attributes
53 55 # these attributes make time aggregations easier
54 56 def spent_on=(date)
55 57 super
56 58 self.tyear = spent_on ? spent_on.year : nil
57 59 self.tmonth = spent_on ? spent_on.month : nil
58 60 self.tweek = spent_on ? Date.civil(spent_on.year, spent_on.month, spent_on.day).cweek : nil
59 61 end
60 62
61 63 # Returns true if the time entry can be edited by usr, otherwise false
62 64 def editable_by?(usr)
63 65 (usr == user && usr.allowed_to?(:edit_own_time_entries, project)) || usr.allowed_to?(:edit_time_entries, project)
64 66 end
65 67
66 68 def self.visible_by(usr)
67 69 with_scope(:find => { :conditions => Project.allowed_to_condition(usr, :view_time_entries) }) do
68 70 yield
69 71 end
70 72 end
71 73 end
@@ -1,218 +1,220
1 1 # redMine - project management software
2 2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require File.dirname(__FILE__) + '/../test_helper'
19 19 require 'timelog_controller'
20 20
21 21 # Re-raise errors caught by the controller.
22 22 class TimelogController; def rescue_action(e) raise e end; end
23 23
24 24 class TimelogControllerTest < Test::Unit::TestCase
25 25 fixtures :projects, :enabled_modules, :roles, :members, :issues, :time_entries, :users, :trackers, :enumerations, :issue_statuses, :custom_fields, :custom_values
26 26
27 27 def setup
28 28 @controller = TimelogController.new
29 29 @request = ActionController::TestRequest.new
30 30 @response = ActionController::TestResponse.new
31 31 end
32 32
33 33 def test_get_edit
34 34 @request.session[:user_id] = 3
35 35 get :edit, :project_id => 1
36 36 assert_response :success
37 37 assert_template 'edit'
38 38 # Default activity selected
39 39 assert_tag :tag => 'option', :attributes => { :selected => 'selected' },
40 40 :content => 'Development'
41 41 end
42 42
43 43 def test_post_edit
44 44 @request.session[:user_id] = 3
45 45 post :edit, :project_id => 1,
46 46 :time_entry => {:comments => 'Some work on TimelogControllerTest',
47 :activity_id => '10',
47 # Not the default activity
48 :activity_id => '11',
48 49 :spent_on => '2008-03-14',
49 50 :issue_id => '1',
50 51 :hours => '7.3'}
51 52 assert_redirected_to 'projects/ecookbook/timelog/details'
52 53
53 54 i = Issue.find(1)
54 55 t = TimeEntry.find_by_comments('Some work on TimelogControllerTest')
55 56 assert_not_nil t
57 assert_equal 11, t.activity_id
56 58 assert_equal 7.3, t.hours
57 59 assert_equal 3, t.user_id
58 60 assert_equal i, t.issue
59 61 assert_equal i.project, t.project
60 62 end
61 63
62 64 def test_update
63 65 entry = TimeEntry.find(1)
64 66 assert_equal 1, entry.issue_id
65 67 assert_equal 2, entry.user_id
66 68
67 69 @request.session[:user_id] = 1
68 70 post :edit, :id => 1,
69 71 :time_entry => {:issue_id => '2',
70 72 :hours => '8'}
71 73 assert_redirected_to 'projects/ecookbook/timelog/details'
72 74 entry.reload
73 75
74 76 assert_equal 8, entry.hours
75 77 assert_equal 2, entry.issue_id
76 78 assert_equal 2, entry.user_id
77 79 end
78 80
79 81 def destroy
80 82 @request.session[:user_id] = 2
81 83 post :destroy, :id => 1
82 84 assert_redirected_to 'projects/ecookbook/timelog/details'
83 85 assert_nil TimeEntry.find_by_id(1)
84 86 end
85 87
86 88 def test_report_no_criteria
87 89 get :report, :project_id => 1
88 90 assert_response :success
89 91 assert_template 'report'
90 92 end
91 93
92 94 def test_report_all_time
93 95 get :report, :project_id => 1, :criterias => ['project', 'issue']
94 96 assert_response :success
95 97 assert_template 'report'
96 98 assert_not_nil assigns(:total_hours)
97 99 assert_equal "162.90", "%.2f" % assigns(:total_hours)
98 100 end
99 101
100 102 def test_report_all_time_by_day
101 103 get :report, :project_id => 1, :criterias => ['project', 'issue'], :columns => 'day'
102 104 assert_response :success
103 105 assert_template 'report'
104 106 assert_not_nil assigns(:total_hours)
105 107 assert_equal "162.90", "%.2f" % assigns(:total_hours)
106 108 assert_tag :tag => 'th', :content => '2007-03-12'
107 109 end
108 110
109 111 def test_report_one_criteria
110 112 get :report, :project_id => 1, :columns => 'week', :from => "2007-04-01", :to => "2007-04-30", :criterias => ['project']
111 113 assert_response :success
112 114 assert_template 'report'
113 115 assert_not_nil assigns(:total_hours)
114 116 assert_equal "8.65", "%.2f" % assigns(:total_hours)
115 117 end
116 118
117 119 def test_report_two_criterias
118 120 get :report, :project_id => 1, :columns => 'month', :from => "2007-01-01", :to => "2007-12-31", :criterias => ["member", "activity"]
119 121 assert_response :success
120 122 assert_template 'report'
121 123 assert_not_nil assigns(:total_hours)
122 124 assert_equal "162.90", "%.2f" % assigns(:total_hours)
123 125 end
124 126
125 127 def test_report_custom_field_criteria
126 128 get :report, :project_id => 1, :criterias => ['project', 'cf_1']
127 129 assert_response :success
128 130 assert_template 'report'
129 131 assert_not_nil assigns(:total_hours)
130 132 assert_not_nil assigns(:criterias)
131 133 assert_equal 2, assigns(:criterias).size
132 134 assert_equal "162.90", "%.2f" % assigns(:total_hours)
133 135 # Custom field column
134 136 assert_tag :tag => 'th', :content => 'Database'
135 137 # Custom field row
136 138 assert_tag :tag => 'td', :content => 'MySQL',
137 139 :sibling => { :tag => 'td', :attributes => { :class => 'hours' },
138 140 :child => { :tag => 'span', :attributes => { :class => 'hours hours-int' },
139 141 :content => '1' }}
140 142 end
141 143
142 144 def test_report_one_criteria_no_result
143 145 get :report, :project_id => 1, :columns => 'week', :from => "1998-04-01", :to => "1998-04-30", :criterias => ['project']
144 146 assert_response :success
145 147 assert_template 'report'
146 148 assert_not_nil assigns(:total_hours)
147 149 assert_equal "0.00", "%.2f" % assigns(:total_hours)
148 150 end
149 151
150 152 def test_report_csv_export
151 153 get :report, :project_id => 1, :columns => 'month', :from => "2007-01-01", :to => "2007-06-30", :criterias => ["project", "member", "activity"], :format => "csv"
152 154 assert_response :success
153 155 assert_equal 'text/csv', @response.content_type
154 156 lines = @response.body.chomp.split("\n")
155 157 # Headers
156 158 assert_equal 'Project,Member,Activity,2007-1,2007-2,2007-3,2007-4,2007-5,2007-6,Total', lines.first
157 159 # Total row
158 160 assert_equal 'Total,"","","","",154.25,8.65,"","",162.90', lines.last
159 161 end
160 162
161 163 def test_details_at_project_level
162 164 get :details, :project_id => 1
163 165 assert_response :success
164 166 assert_template 'details'
165 167 assert_not_nil assigns(:entries)
166 168 assert_equal 4, assigns(:entries).size
167 169 # project and subproject
168 170 assert_equal [1, 3], assigns(:entries).collect(&:project_id).uniq.sort
169 171 assert_not_nil assigns(:total_hours)
170 172 assert_equal "162.90", "%.2f" % assigns(:total_hours)
171 173 # display all time by default
172 174 assert_equal '2007-03-11'.to_date, assigns(:from)
173 175 assert_equal '2007-04-22'.to_date, assigns(:to)
174 176 end
175 177
176 178 def test_details_at_project_level_with_date_range
177 179 get :details, :project_id => 1, :from => '2007-03-20', :to => '2007-04-30'
178 180 assert_response :success
179 181 assert_template 'details'
180 182 assert_not_nil assigns(:entries)
181 183 assert_equal 3, assigns(:entries).size
182 184 assert_not_nil assigns(:total_hours)
183 185 assert_equal "12.90", "%.2f" % assigns(:total_hours)
184 186 assert_equal '2007-03-20'.to_date, assigns(:from)
185 187 assert_equal '2007-04-30'.to_date, assigns(:to)
186 188 end
187 189
188 190 def test_details_at_project_level_with_period
189 191 get :details, :project_id => 1, :period => '7_days'
190 192 assert_response :success
191 193 assert_template 'details'
192 194 assert_not_nil assigns(:entries)
193 195 assert_not_nil assigns(:total_hours)
194 196 assert_equal Date.today - 7, assigns(:from)
195 197 assert_equal Date.today, assigns(:to)
196 198 end
197 199
198 200 def test_details_at_issue_level
199 201 get :details, :issue_id => 1
200 202 assert_response :success
201 203 assert_template 'details'
202 204 assert_not_nil assigns(:entries)
203 205 assert_equal 2, assigns(:entries).size
204 206 assert_not_nil assigns(:total_hours)
205 207 assert_equal 154.25, assigns(:total_hours)
206 208 # display all time by default
207 209 assert_equal '2007-03-11'.to_date, assigns(:from)
208 210 assert_equal '2007-04-22'.to_date, assigns(:to)
209 211 end
210 212
211 213 def test_details_csv_export
212 214 get :details, :project_id => 1, :format => 'csv'
213 215 assert_response :success
214 216 assert_equal 'text/csv', @response.content_type
215 217 assert @response.body.include?("Date,User,Activity,Project,Issue,Tracker,Subject,Hours,Comment\n")
216 218 assert @response.body.include?("\n04/21/2007,redMine Admin,Design,eCookbook,3,Bug,Error 281 when updating a recipe,1.0,\"\"\n")
217 219 end
218 220 end
General Comments 0
You need to be logged in to leave comments. Login now