Project

General

Profile

Patch #1028 ยป cleanup_timelog.diff

Rocco Stanzione, 2008-04-09 21:54

View differences:

app/controllers/timelog_controller.rb (working copy)
30 30
  include CustomFieldsHelper
31 31
  
32 32
  def report
33
    @available_criterias = { 'project' => {:sql => "#{TimeEntry.table_name}.project_id",
33
    @available_criteria = { 'project' => {:sql => "#{TimeEntry.table_name}.project_id",
34 34
                                          :klass => Project,
35 35
                                          :label => :label_project},
36 36
                             'version' => {:sql => "#{Issue.table_name}.fixed_version_id",
......
53 53
                                         :label => :label_issue}
54 54
                           }
55 55
    
56
    # Add list and boolean custom fields as available criterias
56
    # Add list and boolean custom fields as available criteria
57 57
    @project.all_custom_fields.select {|cf| %w(list bool).include? cf.field_format }.each do |cf|
58
      @available_criterias["cf_#{cf.id}"] = {:sql => "(SELECT c.value FROM custom_values c WHERE c.custom_field_id = #{cf.id} AND c.customized_type = 'Issue' AND c.customized_id = issues.id)",
58
      @available_criteria["cf_#{cf.id}"] = {:sql => "(SELECT c.value FROM custom_values c WHERE c.custom_field_id = #{cf.id} AND c.customized_type = 'Issue' AND c.customized_id = issues.id)",
59 59
                                             :format => cf.field_format,
60 60
                                             :label => cf.name}
61 61
    end
62 62
    
63
    @criterias = params[:criterias] || []
64
    @criterias = @criterias.select{|criteria| @available_criterias.has_key? criteria}
65
    @criterias.uniq!
66
    @criterias = @criterias[0,3]
63
    @criteria = params[:criteria] || []
64
    @criteria = @criteria.select{|criterion| @available_criteria.has_key? criterion}
65
    @criteria.uniq!
66
    @criteria = @criteria[0,3]
67 67
    
68 68
    @columns = (params[:columns] && %w(year month week day).include?(params[:columns])) ? params[:columns] : 'month'
69 69
    
70 70
    retrieve_date_range
71 71
    
72
    unless @criterias.empty?
73
      sql_select = @criterias.collect{|criteria| @available_criterias[criteria][:sql] + " AS " + criteria}.join(', ')
74
      sql_group_by = @criterias.collect{|criteria| @available_criterias[criteria][:sql]}.join(', ')
72
    unless @criteria.empty?
73
      sql_select = @criteria.collect{|criterion| @available_criteria[criterion][:sql] + " AS " + criterion}.join(', ')
74
      sql_group_by = @criteria.collect{|criterion| @available_criteria[criterion][:sql]}.join(', ')
75 75
      
76 76
      sql = "SELECT #{sql_select}, tyear, tmonth, tweek, spent_on, SUM(hours) AS hours"
77 77
      sql << " FROM #{TimeEntry.table_name}"
......
123 123
    
124 124
    respond_to do |format|
125 125
      format.html { render :layout => !request.xhr? }
126
      format.csv  { send_data(report_to_csv(@criterias, @periods, @hours).read, :type => 'text/csv; header=present', :filename => 'timelog.csv') }
126
      format.csv  { send_data(report_to_csv(@criteria, @periods, @hours).read, :type => 'text/csv; header=present', :filename => 'timelog.csv') }
127 127
    end
128 128
  end
129 129
  
app/helpers/timelog_helper.rb (working copy)
16 16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17 17

  
18 18
module TimelogHelper
19
  def select_hours(data, criteria, value)
20
    data.select {|row| row[criteria] == value}
19
  def select_hours(data, criterion, value)
20
    data.select {|row| row[criterion] == value}
21 21
  end
22 22
  
23 23
  def sum_hours(data)
......
77 77
    export
78 78
  end
79 79
  
80
  def format_criteria_value(criteria, value)
81
    value.blank? ? l(:label_none) : ((k = @available_criterias[criteria][:klass]) ? k.find_by_id(value.to_i) : format_value(value, @available_criterias[criteria][:format]))
80
  def format_criterion_value(criterion, value)
81
    value.blank? ? l(:label_none) : ((k = @available_criteria[criterion][:klass]) ? k.find_by_id(value.to_i) : format_value(value, @available_criteria[criterion][:format]))
82 82
  end
83 83
  
84
  def report_to_csv(criterias, periods, hours)
84
  def report_to_csv(criteria, periods, hours)
85 85
    export = StringIO.new
86 86
    CSV::Writer.generate(export, l(:general_csv_separator)) do |csv|
87 87
      # Column headers
88
      headers = criterias.collect {|criteria| l(@available_criterias[criteria][:label]) }
88
      headers = criteria.collect {|criterion| l(@available_criteria[criterion][:label]) }
89 89
      headers += periods
90 90
      headers << l(:label_total)
91 91
      csv << headers.collect {|c| to_utf8(c) }
92 92
      # Content
93
      report_criteria_to_csv(csv, criterias, periods, hours)
93
      report_criteria_to_csv(csv, criteria, periods, hours)
94 94
      # Total row
95
      row = [ l(:label_total) ] + [''] * (criterias.size - 1)
95
      row = [ l(:label_total) ] + [''] * (criteria.size - 1)
96 96
      total = 0
97 97
      periods.each do |period|
98 98
        sum = sum_hours(select_hours(hours, @columns, period.to_s))
......
106 106
    export
107 107
  end
108 108
  
109
  def report_criteria_to_csv(csv, criterias, periods, hours, level=0)
110
    hours.collect {|h| h[criterias[level]].to_s}.uniq.each do |value|
111
      hours_for_value = select_hours(hours, criterias[level], value)
109
  def report_criteria_to_csv(csv, criteria, periods, hours, level=0)
110
    hours.collect {|h| h[criteria[level]].to_s}.uniq.each do |value|
111
      hours_for_value = select_hours(hours, criteria[level], value)
112 112
      next if hours_for_value.empty?
113 113
      row = [''] * level
114
      row << to_utf8(format_criteria_value(criterias[level], value))
115
      row += [''] * (criterias.length - level - 1)
114
      row << to_utf8(format_criterion_value(criteria[level], value))
115
      row += [''] * (criteria.length - level - 1)
116 116
      total = 0
117 117
      periods.each do |period|
118 118
        sum = sum_hours(select_hours(hours_for_value, @columns, period.to_s))
......
122 122
      row << "%.2f" %total
123 123
      csv << row
124 124
      
125
      if criterias.length > level + 1
126
        report_criteria_to_csv(csv, criterias, periods, hours_for_value, level + 1)
125
      if criteria.length > level + 1
126
        report_criteria_to_csv(csv, criteria, periods, hours_for_value, level + 1)
127 127
      end
128 128
    end
129 129
  end
app/views/timelog/report.rhtml (working copy)
5 5
<h2><%= l(:label_spent_time) %></h2>
6 6

  
7 7
<% form_remote_tag(:url => {}, :update => 'content') do %>
8
  <% @criterias.each do |criteria| %>
9
    <%= hidden_field_tag 'criterias[]', criteria, :id => nil %>
8
  <% @criteria.each do |criterion| %>
9
    <%= hidden_field_tag 'criteria[]', criterion, :id => nil %>
10 10
  <% end %>
11 11
  <%= hidden_field_tag 'project_id', params[:project_id] %>
12 12
  <%= render :partial => 'date_range' %>
......
17 17
                                                                            [l(:label_day_plural).titleize, 'day']], @columns),
18 18
                                                        :onchange => "this.form.onsubmit();" %>
19 19

  
20
  <%= l(:button_add) %>: <%= select_tag('criterias[]', options_for_select([[]] + (@available_criterias.keys - @criterias).collect{|k| [l(@available_criterias[k][:label]), k]}),
20
  <%= l(:button_add) %>: <%= select_tag('criteria[]', options_for_select([[]] + (@available_criteria.keys - @criteria).collect{|k| [l(@available_criteria[k][:label]), k]}),
21 21
                                                          :onchange => "this.form.onsubmit();",
22 22
                                                          :style => 'width: 200px',
23 23
                                                          :id => nil,
24
                                                          :disabled => (@criterias.length >= 3)) %>
24
                                                          :disabled => (@criteria.length >= 3)) %>
25 25
     <%= link_to_remote l(:button_clear), {:url => {:project_id => @project, :period_type => params[:period_type], :period => params[:period], :from => @from, :to => @to, :columns => @columns},
26 26
                                           :update => 'content'
27 27
                                          }, :class => 'icon icon-reload' %></p>
28 28
<% end %>
29 29

  
30
<% unless @criterias.empty? %>
30
<% unless @criteria.empty? %>
31 31
<div class="total-hours">
32 32
<p><%= l(:label_total) %>: <%= html_hours(lwr(:label_f_hour, @total_hours)) %></p>
33 33
</div>
......
36 36
<table class="list" id="time-report">
37 37
<thead>
38 38
<tr>
39
<% @criterias.each do |criteria| %>
40
  <th><%= l(@available_criterias[criteria][:label]) %></th>
39
<% @criteria.each do |criterion| %>
40
  <th><%= l(@available_criteria[criterion][:label]) %></th>
41 41
<% end %>
42 42
<% columns_width = (40 / (@periods.length+1)).to_i %>
43 43
<% @periods.each do |period| %>
......
47 47
</tr>
48 48
</thead>
49 49
<tbody>
50
<%= render :partial => 'report_criteria', :locals => {:criterias => @criterias, :hours => @hours, :level => 0} %>
50
<%= render :partial => 'report_criteria', :locals => {:criteria => @criteria, :hours => @hours, :level => 0} %>
51 51
  <tr class="total">
52 52
  <td><%= l(:label_total) %></td>
53
  <%= '<td></td>' * (@criterias.size - 1) %>
53
  <%= '<td></td>' * (@criteria.size - 1) %>
54 54
  <% total = 0 -%>
55 55
  <% @periods.each do |period| -%>
56 56
    <% sum = sum_hours(select_hours(@hours, @columns, period.to_s)); total += sum -%>
app/views/timelog/_report_criteria.rhtml (working copy)
1
<% @hours.collect {|h| h[criterias[level]].to_s}.uniq.each do |value| %>
2
<% hours_for_value = select_hours(hours, criterias[level], value) -%>
1
<% @hours.collect {|h| h[criteria[level]].to_s}.uniq.each do |value| %>
2
<% hours_for_value = select_hours(hours, criteria[level], value) -%>
3 3
<% next if hours_for_value.empty? -%>
4
<tr class="<%= cycle('odd', 'even') %> <%= 'last-level' unless criterias.length > level+1 %>">
4
<tr class="<%= cycle('odd', 'even') %> <%= 'last-level' unless criteria.length > level+1 %>">
5 5
<%= '<td></td>' * level %>
6
<td><%= format_criteria_value(criterias[level], value) %></td>
7
<%= '<td></td>' * (criterias.length - level - 1) -%>
6
<td><%= format_criterion_value(criteria[level], value) %></td>
7
<%= '<td></td>' * (criteria.length - level - 1) -%>
8 8
  <% total = 0 -%>
9 9
  <% @periods.each do |period| -%>
10 10
    <% sum = sum_hours(select_hours(hours_for_value, @columns, period.to_s)); total += sum -%>
......
12 12
  <% end -%>
13 13
  <td class="hours"><%= html_hours("%.2f" % total) if total > 0 %></td>
14 14
</tr>
15
<% if criterias.length > level+1 -%>
16
  <%= render(:partial => 'report_criteria', :locals => {:criterias => criterias, :hours => hours_for_value, :level => (level + 1)}) %>
15
<% if criteria.length > level+1 -%>
16
  <%= render(:partial => 'report_criteria', :locals => {:criteria => criteria, :hours => hours_for_value, :level => (level + 1)}) %>
17 17
<% end -%>
18 18

  
19 19
<% end %>
test/functional/timelog_controller_test.rb (working copy)
80 80
  end
81 81

  
82 82
  def test_report_all_time
83
    get :report, :project_id => 1, :criterias => ['project', 'issue']
83
    get :report, :project_id => 1, :criteria => ['project', 'issue']
84 84
    assert_response :success
85 85
    assert_template 'report'
86 86
    assert_not_nil assigns(:total_hours)
......
88 88
  end
89 89

  
90 90
  def test_report_all_time_by_day
91
    get :report, :project_id => 1, :criterias => ['project', 'issue'], :columns => 'day'
91
    get :report, :project_id => 1, :criteria => ['project', 'issue'], :columns => 'day'
92 92
    assert_response :success
93 93
    assert_template 'report'
94 94
    assert_not_nil assigns(:total_hours)
......
96 96
    assert_tag :tag => 'th', :content => '2007-03-12'
97 97
  end
98 98
  
99
  def test_report_one_criteria
100
    get :report, :project_id => 1, :columns => 'week', :from => "2007-04-01", :to => "2007-04-30", :criterias => ['project']
99
  def test_report_one_criterion
100
    get :report, :project_id => 1, :columns => 'week', :from => "2007-04-01", :to => "2007-04-30", :criteria => ['project']
101 101
    assert_response :success
102 102
    assert_template 'report'
103 103
    assert_not_nil assigns(:total_hours)
104 104
    assert_equal "8.65", "%.2f" % assigns(:total_hours)
105 105
  end
106 106
  
107
  def test_report_two_criterias
108
    get :report, :project_id => 1, :columns => 'month', :from => "2007-01-01", :to => "2007-12-31", :criterias => ["member", "activity"]
107
  def test_report_two_criteria
108
    get :report, :project_id => 1, :columns => 'month', :from => "2007-01-01", :to => "2007-12-31", :criteria => ["member", "activity"]
109 109
    assert_response :success
110 110
    assert_template 'report'
111 111
    assert_not_nil assigns(:total_hours)
112 112
    assert_equal "162.90", "%.2f" % assigns(:total_hours)
113 113
  end
114 114
  
115
  def test_report_custom_field_criteria
116
    get :report, :project_id => 1, :criterias => ['project', 'cf_1']
115
  def test_report_custom_field_criterion
116
    get :report, :project_id => 1, :criteria => ['project', 'cf_1']
117 117
    assert_response :success
118 118
    assert_template 'report'
119 119
    assert_not_nil assigns(:total_hours)
120
    assert_not_nil assigns(:criterias)
121
    assert_equal 2, assigns(:criterias).size
120
    assert_not_nil assigns(:criteria)
121
    assert_equal 2, assigns(:criteria).size
122 122
    assert_equal "162.90", "%.2f" % assigns(:total_hours)
123 123
    # Custom field column
124 124
    assert_tag :tag => 'th', :content => 'Database'
......
129 129
                                                                                     :content => '1' }}
130 130
  end
131 131
  
132
  def test_report_one_criteria_no_result
133
    get :report, :project_id => 1, :columns => 'week', :from => "1998-04-01", :to => "1998-04-30", :criterias => ['project']
132
  def test_report_one_criterion_no_result
133
    get :report, :project_id => 1, :columns => 'week', :from => "1998-04-01", :to => "1998-04-30", :criteria => ['project']
134 134
    assert_response :success
135 135
    assert_template 'report'
136 136
    assert_not_nil assigns(:total_hours)
......
138 138
  end
139 139
 
140 140
  def test_report_csv_export
141
    get :report, :project_id => 1, :columns => 'month', :from => "2007-01-01", :to => "2007-06-30", :criterias => ["project", "member", "activity"], :format => "csv"
141
    get :report, :project_id => 1, :columns => 'month', :from => "2007-01-01", :to => "2007-06-30", :criteria => ["project", "member", "activity"], :format => "csv"
142 142
    assert_response :success
143 143
    assert_equal 'text/csv', @response.content_type
144 144
    lines = @response.body.chomp.split("\n")
    (1-1/1)