Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor: extract TimelogController#report to a new controller class
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@4232 e93f8b46-1217-0410-a6f0-8f06a7374b81
- Loading branch information
Showing
11 changed files
with
359 additions
and
272 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,209 @@ | ||
class TimeEntryReportsController < ApplicationController | ||
menu_item :issues | ||
before_filter :find_optional_project | ||
before_filter :load_available_criterias | ||
|
||
helper :sort | ||
include SortHelper | ||
helper :issues | ||
helper :timelog | ||
include TimelogHelper | ||
helper :custom_fields | ||
include CustomFieldsHelper | ||
|
||
def report | ||
@criterias = params[:criterias] || [] | ||
@criterias = @criterias.select{|criteria| @available_criterias.has_key? criteria} | ||
@criterias.uniq! | ||
@criterias = @criterias[0,3] | ||
|
||
@columns = (params[:columns] && %w(year month week day).include?(params[:columns])) ? params[:columns] : 'month' | ||
|
||
retrieve_date_range | ||
|
||
unless @criterias.empty? | ||
sql_select = @criterias.collect{|criteria| @available_criterias[criteria][:sql] + " AS " + criteria}.join(', ') | ||
sql_group_by = @criterias.collect{|criteria| @available_criterias[criteria][:sql]}.join(', ') | ||
sql_condition = '' | ||
|
||
if @project.nil? | ||
sql_condition = Project.allowed_to_condition(User.current, :view_time_entries) | ||
elsif @issue.nil? | ||
sql_condition = @project.project_condition(Setting.display_subprojects_issues?) | ||
else | ||
sql_condition = "#{Issue.table_name}.root_id = #{@issue.root_id} AND #{Issue.table_name}.lft >= #{@issue.lft} AND #{Issue.table_name}.rgt <= #{@issue.rgt}" | ||
end | ||
|
||
sql = "SELECT #{sql_select}, tyear, tmonth, tweek, spent_on, SUM(hours) AS hours" | ||
sql << " FROM #{TimeEntry.table_name}" | ||
sql << time_report_joins | ||
sql << " WHERE" | ||
sql << " (%s) AND" % sql_condition | ||
sql << " (spent_on BETWEEN '%s' AND '%s')" % [ActiveRecord::Base.connection.quoted_date(@from), ActiveRecord::Base.connection.quoted_date(@to)] | ||
sql << " GROUP BY #{sql_group_by}, tyear, tmonth, tweek, spent_on" | ||
|
||
@hours = ActiveRecord::Base.connection.select_all(sql) | ||
|
||
@hours.each do |row| | ||
case @columns | ||
when 'year' | ||
row['year'] = row['tyear'] | ||
when 'month' | ||
row['month'] = "#{row['tyear']}-#{row['tmonth']}" | ||
when 'week' | ||
row['week'] = "#{row['tyear']}-#{row['tweek']}" | ||
when 'day' | ||
row['day'] = "#{row['spent_on']}" | ||
end | ||
end | ||
|
||
@total_hours = @hours.inject(0) {|s,k| s = s + k['hours'].to_f} | ||
|
||
@periods = [] | ||
# Date#at_beginning_of_ not supported in Rails 1.2.x | ||
date_from = @from.to_time | ||
# 100 columns max | ||
while date_from <= @to.to_time && @periods.length < 100 | ||
case @columns | ||
when 'year' | ||
@periods << "#{date_from.year}" | ||
date_from = (date_from + 1.year).at_beginning_of_year | ||
when 'month' | ||
@periods << "#{date_from.year}-#{date_from.month}" | ||
date_from = (date_from + 1.month).at_beginning_of_month | ||
when 'week' | ||
@periods << "#{date_from.year}-#{date_from.to_date.cweek}" | ||
date_from = (date_from + 7.day).at_beginning_of_week | ||
when 'day' | ||
@periods << "#{date_from.to_date}" | ||
date_from = date_from + 1.day | ||
end | ||
end | ||
end | ||
|
||
respond_to do |format| | ||
format.html { render :layout => !request.xhr? } | ||
format.csv { send_data(report_to_csv(@criterias, @periods, @hours), :type => 'text/csv; header=present', :filename => 'timelog.csv') } | ||
end | ||
end | ||
|
||
private | ||
|
||
# TODO: duplicated in TimelogController | ||
def find_optional_project | ||
if !params[:issue_id].blank? | ||
@issue = Issue.find(params[:issue_id]) | ||
@project = @issue.project | ||
elsif !params[:project_id].blank? | ||
@project = Project.find(params[:project_id]) | ||
end | ||
deny_access unless User.current.allowed_to?(:view_time_entries, @project, :global => true) | ||
end | ||
|
||
# Retrieves the date range based on predefined ranges or specific from/to param dates | ||
# TODO: duplicated in TimelogController | ||
def retrieve_date_range | ||
@free_period = false | ||
@from, @to = nil, nil | ||
|
||
if params[:period_type] == '1' || (params[:period_type].nil? && !params[:period].nil?) | ||
case params[:period].to_s | ||
when 'today' | ||
@from = @to = Date.today | ||
when 'yesterday' | ||
@from = @to = Date.today - 1 | ||
when 'current_week' | ||
@from = Date.today - (Date.today.cwday - 1)%7 | ||
@to = @from + 6 | ||
when 'last_week' | ||
@from = Date.today - 7 - (Date.today.cwday - 1)%7 | ||
@to = @from + 6 | ||
when '7_days' | ||
@from = Date.today - 7 | ||
@to = Date.today | ||
when 'current_month' | ||
@from = Date.civil(Date.today.year, Date.today.month, 1) | ||
@to = (@from >> 1) - 1 | ||
when 'last_month' | ||
@from = Date.civil(Date.today.year, Date.today.month, 1) << 1 | ||
@to = (@from >> 1) - 1 | ||
when '30_days' | ||
@from = Date.today - 30 | ||
@to = Date.today | ||
when 'current_year' | ||
@from = Date.civil(Date.today.year, 1, 1) | ||
@to = Date.civil(Date.today.year, 12, 31) | ||
end | ||
elsif params[:period_type] == '2' || (params[:period_type].nil? && (!params[:from].nil? || !params[:to].nil?)) | ||
begin; @from = params[:from].to_s.to_date unless params[:from].blank?; rescue; end | ||
begin; @to = params[:to].to_s.to_date unless params[:to].blank?; rescue; end | ||
@free_period = true | ||
else | ||
# default | ||
end | ||
|
||
@from, @to = @to, @from if @from && @to && @from > @to | ||
@from ||= (TimeEntry.earilest_date_for_project(@project) || Date.today) | ||
@to ||= (TimeEntry.latest_date_for_project(@project) || Date.today) | ||
end | ||
|
||
def load_available_criterias | ||
@available_criterias = { 'project' => {:sql => "#{TimeEntry.table_name}.project_id", | ||
:klass => Project, | ||
:label => :label_project}, | ||
'version' => {:sql => "#{Issue.table_name}.fixed_version_id", | ||
:klass => Version, | ||
:label => :label_version}, | ||
'category' => {:sql => "#{Issue.table_name}.category_id", | ||
:klass => IssueCategory, | ||
:label => :field_category}, | ||
'member' => {:sql => "#{TimeEntry.table_name}.user_id", | ||
:klass => User, | ||
:label => :label_member}, | ||
'tracker' => {:sql => "#{Issue.table_name}.tracker_id", | ||
:klass => Tracker, | ||
:label => :label_tracker}, | ||
'activity' => {:sql => "#{TimeEntry.table_name}.activity_id", | ||
:klass => TimeEntryActivity, | ||
:label => :label_activity}, | ||
'issue' => {:sql => "#{TimeEntry.table_name}.issue_id", | ||
:klass => Issue, | ||
:label => :label_issue} | ||
} | ||
|
||
# Add list and boolean custom fields as available criterias | ||
custom_fields = (@project.nil? ? IssueCustomField.for_all : @project.all_issue_custom_fields) | ||
custom_fields.select {|cf| %w(list bool).include? cf.field_format }.each do |cf| | ||
@available_criterias["cf_#{cf.id}"] = {:sql => "(SELECT c.value FROM #{CustomValue.table_name} c WHERE c.custom_field_id = #{cf.id} AND c.customized_type = 'Issue' AND c.customized_id = #{Issue.table_name}.id)", | ||
:format => cf.field_format, | ||
:label => cf.name} | ||
end if @project | ||
|
||
# Add list and boolean time entry custom fields | ||
TimeEntryCustomField.find(:all).select {|cf| %w(list bool).include? cf.field_format }.each do |cf| | ||
@available_criterias["cf_#{cf.id}"] = {:sql => "(SELECT c.value FROM #{CustomValue.table_name} c WHERE c.custom_field_id = #{cf.id} AND c.customized_type = 'TimeEntry' AND c.customized_id = #{TimeEntry.table_name}.id)", | ||
:format => cf.field_format, | ||
:label => cf.name} | ||
end | ||
|
||
# Add list and boolean time entry activity custom fields | ||
TimeEntryActivityCustomField.find(:all).select {|cf| %w(list bool).include? cf.field_format }.each do |cf| | ||
@available_criterias["cf_#{cf.id}"] = {:sql => "(SELECT c.value FROM #{CustomValue.table_name} c WHERE c.custom_field_id = #{cf.id} AND c.customized_type = 'Enumeration' AND c.customized_id = #{TimeEntry.table_name}.activity_id)", | ||
:format => cf.field_format, | ||
:label => cf.name} | ||
end | ||
|
||
call_hook(:controller_timelog_available_criterias, { :available_criterias => @available_criterias, :project => @project }) | ||
@available_criterias | ||
end | ||
|
||
def time_report_joins | ||
sql = '' | ||
sql << " LEFT JOIN #{Issue.table_name} ON #{TimeEntry.table_name}.issue_id = #{Issue.table_name}.id" | ||
sql << " LEFT JOIN #{Project.table_name} ON #{TimeEntry.table_name}.project_id = #{Project.table_name}.id" | ||
# TODO: rename hook | ||
call_hook(:controller_timelog_time_report_joins, {:sql => sql} ) | ||
sql | ||
end | ||
|
||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.