##// END OF EJS Templates
Fixed: time report doesn't take account of the project for time calculations...
Jean-Philippe Lang -
r572:184be9d0e3af
parent child
Show More
@@ -1,173 +1,174
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class TimelogController < ApplicationController
18 class TimelogController < ApplicationController
19 layout 'base'
19 layout 'base'
20
20
21 before_filter :find_project
21 before_filter :find_project
22 before_filter :authorize, :only => :edit
22 before_filter :authorize, :only => :edit
23 before_filter :check_project_privacy, :except => :edit
23 before_filter :check_project_privacy, :except => :edit
24
24
25 helper :sort
25 helper :sort
26 include SortHelper
26 include SortHelper
27
27
28 def report
28 def report
29 @available_criterias = { 'version' => {:sql => "#{Issue.table_name}.fixed_version_id",
29 @available_criterias = { 'version' => {:sql => "#{Issue.table_name}.fixed_version_id",
30 :values => @project.versions,
30 :values => @project.versions,
31 :label => :label_version},
31 :label => :label_version},
32 'category' => {:sql => "#{Issue.table_name}.category_id",
32 'category' => {:sql => "#{Issue.table_name}.category_id",
33 :values => @project.issue_categories,
33 :values => @project.issue_categories,
34 :label => :field_category},
34 :label => :field_category},
35 'member' => {:sql => "#{TimeEntry.table_name}.user_id",
35 'member' => {:sql => "#{TimeEntry.table_name}.user_id",
36 :values => @project.users,
36 :values => @project.users,
37 :label => :label_member},
37 :label => :label_member},
38 'tracker' => {:sql => "#{Issue.table_name}.tracker_id",
38 'tracker' => {:sql => "#{Issue.table_name}.tracker_id",
39 :values => Tracker.find(:all),
39 :values => Tracker.find(:all),
40 :label => :label_tracker},
40 :label => :label_tracker},
41 'activity' => {:sql => "#{TimeEntry.table_name}.activity_id",
41 'activity' => {:sql => "#{TimeEntry.table_name}.activity_id",
42 :values => Enumeration::get_values('ACTI'),
42 :values => Enumeration::get_values('ACTI'),
43 :label => :label_activity}
43 :label => :label_activity}
44 }
44 }
45
45
46 @criterias = params[:criterias] || []
46 @criterias = params[:criterias] || []
47 @criterias = @criterias.select{|criteria| @available_criterias.has_key? criteria}
47 @criterias = @criterias.select{|criteria| @available_criterias.has_key? criteria}
48 @criterias.uniq!
48 @criterias.uniq!
49
49
50 @columns = (params[:period] && %w(year month week).include?(params[:period])) ? params[:period] : 'month'
50 @columns = (params[:period] && %w(year month week).include?(params[:period])) ? params[:period] : 'month'
51
51
52 if params[:date_from]
52 if params[:date_from]
53 begin; @date_from = params[:date_from].to_date; rescue; end
53 begin; @date_from = params[:date_from].to_date; rescue; end
54 end
54 end
55 if params[:date_to]
55 if params[:date_to]
56 begin; @date_to = params[:date_to].to_date; rescue; end
56 begin; @date_to = params[:date_to].to_date; rescue; end
57 end
57 end
58 @date_from ||= Date.civil(Date.today.year, 1, 1)
58 @date_from ||= Date.civil(Date.today.year, 1, 1)
59 @date_to ||= Date.civil(Date.today.year, Date.today.month+1, 1) - 1
59 @date_to ||= Date.civil(Date.today.year, Date.today.month+1, 1) - 1
60
60
61 unless @criterias.empty?
61 unless @criterias.empty?
62 sql_select = @criterias.collect{|criteria| @available_criterias[criteria][:sql] + " AS " + criteria}.join(', ')
62 sql_select = @criterias.collect{|criteria| @available_criterias[criteria][:sql] + " AS " + criteria}.join(', ')
63 sql_group_by = @criterias.collect{|criteria| @available_criterias[criteria][:sql]}.join(', ')
63 sql_group_by = @criterias.collect{|criteria| @available_criterias[criteria][:sql]}.join(', ')
64
64
65 sql = "SELECT #{sql_select}, tyear, tmonth, tweek, SUM(hours) AS hours"
65 sql = "SELECT #{sql_select}, tyear, tmonth, tweek, SUM(hours) AS hours"
66 sql << " FROM #{TimeEntry.table_name} LEFT JOIN #{Issue.table_name} ON #{TimeEntry.table_name}.issue_id = #{Issue.table_name}.id"
66 sql << " FROM #{TimeEntry.table_name} LEFT JOIN #{Issue.table_name} ON #{TimeEntry.table_name}.issue_id = #{Issue.table_name}.id"
67 sql << " WHERE spent_on BETWEEN '%s' AND '%s'" % [ActiveRecord::Base.connection.quoted_date(@date_from.to_time), ActiveRecord::Base.connection.quoted_date(@date_to.to_time)]
67 sql << " WHERE #{TimeEntry.table_name}.project_id = %s" % @project.id
68 sql << " AND spent_on BETWEEN '%s' AND '%s'" % [ActiveRecord::Base.connection.quoted_date(@date_from.to_time), ActiveRecord::Base.connection.quoted_date(@date_to.to_time)]
68 sql << " GROUP BY #{sql_group_by}, tyear, tmonth, tweek"
69 sql << " GROUP BY #{sql_group_by}, tyear, tmonth, tweek"
69
70
70 @hours = ActiveRecord::Base.connection.select_all(sql)
71 @hours = ActiveRecord::Base.connection.select_all(sql)
71
72
72 @hours.each do |row|
73 @hours.each do |row|
73 case @columns
74 case @columns
74 when 'year'
75 when 'year'
75 row['year'] = row['tyear']
76 row['year'] = row['tyear']
76 when 'month'
77 when 'month'
77 row['month'] = "#{row['tyear']}-#{row['tmonth']}"
78 row['month'] = "#{row['tyear']}-#{row['tmonth']}"
78 when 'week'
79 when 'week'
79 row['week'] = "#{row['tyear']}-#{row['tweek']}"
80 row['week'] = "#{row['tyear']}-#{row['tweek']}"
80 end
81 end
81 end
82 end
82 end
83 end
83
84
84 @periods = []
85 @periods = []
85 date_from = @date_from
86 date_from = @date_from
86 # 100 columns max
87 # 100 columns max
87 while date_from < @date_to && @periods.length < 100
88 while date_from < @date_to && @periods.length < 100
88 case @columns
89 case @columns
89 when 'year'
90 when 'year'
90 @periods << "#{date_from.year}"
91 @periods << "#{date_from.year}"
91 date_from = date_from >> 12
92 date_from = date_from >> 12
92 when 'month'
93 when 'month'
93 @periods << "#{date_from.year}-#{date_from.month}"
94 @periods << "#{date_from.year}-#{date_from.month}"
94 date_from = date_from >> 1
95 date_from = date_from >> 1
95 when 'week'
96 when 'week'
96 @periods << "#{date_from.year}-#{date_from.cweek}"
97 @periods << "#{date_from.year}-#{date_from.cweek}"
97 date_from = date_from + 7
98 date_from = date_from + 7
98 end
99 end
99 end
100 end
100
101
101 render :layout => false if request.xhr?
102 render :layout => false if request.xhr?
102 end
103 end
103
104
104 def details
105 def details
105 sort_init 'spent_on', 'desc'
106 sort_init 'spent_on', 'desc'
106 sort_update
107 sort_update
107
108
108 @entries = (@issue ? @issue : @project).time_entries.find(:all, :include => [:activity, :user, {:issue => [:tracker, :assigned_to, :priority]}], :order => sort_clause)
109 @entries = (@issue ? @issue : @project).time_entries.find(:all, :include => [:activity, :user, {:issue => [:tracker, :assigned_to, :priority]}], :order => sort_clause)
109
110
110 @total_hours = @entries.inject(0) { |sum,entry| sum + entry.hours }
111 @total_hours = @entries.inject(0) { |sum,entry| sum + entry.hours }
111 @owner_id = logged_in_user ? logged_in_user.id : 0
112 @owner_id = logged_in_user ? logged_in_user.id : 0
112
113
113 send_csv and return if 'csv' == params[:export]
114 send_csv and return if 'csv' == params[:export]
114 render :action => 'details', :layout => false if request.xhr?
115 render :action => 'details', :layout => false if request.xhr?
115 end
116 end
116
117
117 def edit
118 def edit
118 render_404 and return if @time_entry && @time_entry.user != logged_in_user
119 render_404 and return if @time_entry && @time_entry.user != logged_in_user
119 @time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => logged_in_user, :spent_on => Date.today)
120 @time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => logged_in_user, :spent_on => Date.today)
120 @time_entry.attributes = params[:time_entry]
121 @time_entry.attributes = params[:time_entry]
121 if request.post? and @time_entry.save
122 if request.post? and @time_entry.save
122 flash[:notice] = l(:notice_successful_update)
123 flash[:notice] = l(:notice_successful_update)
123 redirect_to :action => 'details', :project_id => @time_entry.project, :issue_id => @time_entry.issue
124 redirect_to :action => 'details', :project_id => @time_entry.project, :issue_id => @time_entry.issue
124 return
125 return
125 end
126 end
126 @activities = Enumeration::get_values('ACTI')
127 @activities = Enumeration::get_values('ACTI')
127 end
128 end
128
129
129 private
130 private
130 def find_project
131 def find_project
131 if params[:id]
132 if params[:id]
132 @time_entry = TimeEntry.find(params[:id])
133 @time_entry = TimeEntry.find(params[:id])
133 @project = @time_entry.project
134 @project = @time_entry.project
134 elsif params[:issue_id]
135 elsif params[:issue_id]
135 @issue = Issue.find(params[:issue_id])
136 @issue = Issue.find(params[:issue_id])
136 @project = @issue.project
137 @project = @issue.project
137 elsif params[:project_id]
138 elsif params[:project_id]
138 @project = Project.find(params[:project_id])
139 @project = Project.find(params[:project_id])
139 else
140 else
140 render_404
141 render_404
141 return false
142 return false
142 end
143 end
143 end
144 end
144
145
145 def send_csv
146 def send_csv
146 ic = Iconv.new(l(:general_csv_encoding), 'UTF-8')
147 ic = Iconv.new(l(:general_csv_encoding), 'UTF-8')
147 export = StringIO.new
148 export = StringIO.new
148 CSV::Writer.generate(export, l(:general_csv_separator)) do |csv|
149 CSV::Writer.generate(export, l(:general_csv_separator)) do |csv|
149 # csv header fields
150 # csv header fields
150 headers = [l(:field_spent_on),
151 headers = [l(:field_spent_on),
151 l(:field_user),
152 l(:field_user),
152 l(:field_activity),
153 l(:field_activity),
153 l(:field_issue),
154 l(:field_issue),
154 l(:field_hours),
155 l(:field_hours),
155 l(:field_comments)
156 l(:field_comments)
156 ]
157 ]
157 csv << headers.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end }
158 csv << headers.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end }
158 # csv lines
159 # csv lines
159 @entries.each do |entry|
160 @entries.each do |entry|
160 fields = [l_date(entry.spent_on),
161 fields = [l_date(entry.spent_on),
161 entry.user.name,
162 entry.user.name,
162 entry.activity.name,
163 entry.activity.name,
163 (entry.issue ? entry.issue.id : nil),
164 (entry.issue ? entry.issue.id : nil),
164 entry.hours,
165 entry.hours,
165 entry.comments
166 entry.comments
166 ]
167 ]
167 csv << fields.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end }
168 csv << fields.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end }
168 end
169 end
169 end
170 end
170 export.rewind
171 export.rewind
171 send_data(export.read, :type => 'text/csv; header=present', :filename => 'export.csv')
172 send_data(export.read, :type => 'text/csv; header=present', :filename => 'export.csv')
172 end
173 end
173 end
174 end
General Comments 0
You need to be logged in to leave comments. Login now