@@ -1,158 +1,160 | |||||
1 | # redMine - project management software |
|
1 | # redMine - project management software | |
2 | # Copyright (C) 2006 Jean-Philippe Lang |
|
2 | # Copyright (C) 2006 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 | module TimelogHelper |
|
18 | module TimelogHelper | |
|
19 | include ApplicationHelper | |||
|
20 | ||||
19 | def render_timelog_breadcrumb |
|
21 | def render_timelog_breadcrumb | |
20 | links = [] |
|
22 | links = [] | |
21 | links << link_to(l(:label_project_all), {:project_id => nil, :issue_id => nil}) |
|
23 | links << link_to(l(:label_project_all), {:project_id => nil, :issue_id => nil}) | |
22 | links << link_to(h(@project), {:project_id => @project, :issue_id => nil}) if @project |
|
24 | links << link_to(h(@project), {:project_id => @project, :issue_id => nil}) if @project | |
23 | links << link_to_issue(@issue) if @issue |
|
25 | links << link_to_issue(@issue) if @issue | |
24 | breadcrumb links |
|
26 | breadcrumb links | |
25 | end |
|
27 | end | |
26 |
|
28 | |||
27 | def activity_collection_for_select_options |
|
29 | def activity_collection_for_select_options | |
28 | activities = Enumeration::get_values('ACTI') |
|
30 | activities = Enumeration::get_values('ACTI') | |
29 | collection = [] |
|
31 | collection = [] | |
30 | collection << [ "--- #{l(:actionview_instancetag_blank_option)} ---", '' ] unless activities.detect(&:is_default) |
|
32 | collection << [ "--- #{l(:actionview_instancetag_blank_option)} ---", '' ] unless activities.detect(&:is_default) | |
31 | activities.each { |a| collection << [a.name, a.id] } |
|
33 | activities.each { |a| collection << [a.name, a.id] } | |
32 | collection |
|
34 | collection | |
33 | end |
|
35 | end | |
34 |
|
36 | |||
35 | def select_hours(data, criteria, value) |
|
37 | def select_hours(data, criteria, value) | |
36 | data.select {|row| row[criteria] == value} |
|
38 | data.select {|row| row[criteria] == value} | |
37 | end |
|
39 | end | |
38 |
|
40 | |||
39 | def sum_hours(data) |
|
41 | def sum_hours(data) | |
40 | sum = 0 |
|
42 | sum = 0 | |
41 | data.each do |row| |
|
43 | data.each do |row| | |
42 | sum += row['hours'].to_f |
|
44 | sum += row['hours'].to_f | |
43 | end |
|
45 | end | |
44 | sum |
|
46 | sum | |
45 | end |
|
47 | end | |
46 |
|
48 | |||
47 | def options_for_period_select(value) |
|
49 | def options_for_period_select(value) | |
48 | options_for_select([[l(:label_all_time), 'all'], |
|
50 | options_for_select([[l(:label_all_time), 'all'], | |
49 | [l(:label_today), 'today'], |
|
51 | [l(:label_today), 'today'], | |
50 | [l(:label_yesterday), 'yesterday'], |
|
52 | [l(:label_yesterday), 'yesterday'], | |
51 | [l(:label_this_week), 'current_week'], |
|
53 | [l(:label_this_week), 'current_week'], | |
52 | [l(:label_last_week), 'last_week'], |
|
54 | [l(:label_last_week), 'last_week'], | |
53 | [l(:label_last_n_days, 7), '7_days'], |
|
55 | [l(:label_last_n_days, 7), '7_days'], | |
54 | [l(:label_this_month), 'current_month'], |
|
56 | [l(:label_this_month), 'current_month'], | |
55 | [l(:label_last_month), 'last_month'], |
|
57 | [l(:label_last_month), 'last_month'], | |
56 | [l(:label_last_n_days, 30), '30_days'], |
|
58 | [l(:label_last_n_days, 30), '30_days'], | |
57 | [l(:label_this_year), 'current_year']], |
|
59 | [l(:label_this_year), 'current_year']], | |
58 | value) |
|
60 | value) | |
59 | end |
|
61 | end | |
60 |
|
62 | |||
61 | def entries_to_csv(entries) |
|
63 | def entries_to_csv(entries) | |
62 | ic = Iconv.new(l(:general_csv_encoding), 'UTF-8') |
|
64 | ic = Iconv.new(l(:general_csv_encoding), 'UTF-8') | |
63 | decimal_separator = l(:general_csv_decimal_separator) |
|
65 | decimal_separator = l(:general_csv_decimal_separator) | |
64 | custom_fields = TimeEntryCustomField.find(:all) |
|
66 | custom_fields = TimeEntryCustomField.find(:all) | |
65 | export = StringIO.new |
|
67 | export = StringIO.new | |
66 | CSV::Writer.generate(export, l(:general_csv_separator)) do |csv| |
|
68 | CSV::Writer.generate(export, l(:general_csv_separator)) do |csv| | |
67 | # csv header fields |
|
69 | # csv header fields | |
68 | headers = [l(:field_spent_on), |
|
70 | headers = [l(:field_spent_on), | |
69 | l(:field_user), |
|
71 | l(:field_user), | |
70 | l(:field_activity), |
|
72 | l(:field_activity), | |
71 | l(:field_project), |
|
73 | l(:field_project), | |
72 | l(:field_issue), |
|
74 | l(:field_issue), | |
73 | l(:field_tracker), |
|
75 | l(:field_tracker), | |
74 | l(:field_subject), |
|
76 | l(:field_subject), | |
75 | l(:field_hours), |
|
77 | l(:field_hours), | |
76 | l(:field_comments) |
|
78 | l(:field_comments) | |
77 | ] |
|
79 | ] | |
78 | # Export custom fields |
|
80 | # Export custom fields | |
79 | headers += custom_fields.collect(&:name) |
|
81 | headers += custom_fields.collect(&:name) | |
80 |
|
82 | |||
81 | csv << headers.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end } |
|
83 | csv << headers.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end } | |
82 | # csv lines |
|
84 | # csv lines | |
83 | entries.each do |entry| |
|
85 | entries.each do |entry| | |
84 |
fields = [ |
|
86 | fields = [format_date(entry.spent_on), | |
85 | entry.user, |
|
87 | entry.user, | |
86 | entry.activity, |
|
88 | entry.activity, | |
87 | entry.project, |
|
89 | entry.project, | |
88 | (entry.issue ? entry.issue.id : nil), |
|
90 | (entry.issue ? entry.issue.id : nil), | |
89 | (entry.issue ? entry.issue.tracker : nil), |
|
91 | (entry.issue ? entry.issue.tracker : nil), | |
90 | (entry.issue ? entry.issue.subject : nil), |
|
92 | (entry.issue ? entry.issue.subject : nil), | |
91 | entry.hours.to_s.gsub('.', decimal_separator), |
|
93 | entry.hours.to_s.gsub('.', decimal_separator), | |
92 | entry.comments |
|
94 | entry.comments | |
93 | ] |
|
95 | ] | |
94 | fields += custom_fields.collect {|f| show_value(entry.custom_value_for(f)) } |
|
96 | fields += custom_fields.collect {|f| show_value(entry.custom_value_for(f)) } | |
95 |
|
97 | |||
96 | csv << fields.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end } |
|
98 | csv << fields.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end } | |
97 | end |
|
99 | end | |
98 | end |
|
100 | end | |
99 | export.rewind |
|
101 | export.rewind | |
100 | export |
|
102 | export | |
101 | end |
|
103 | end | |
102 |
|
104 | |||
103 | def format_criteria_value(criteria, value) |
|
105 | def format_criteria_value(criteria, value) | |
104 | value.blank? ? l(:label_none) : ((k = @available_criterias[criteria][:klass]) ? k.find_by_id(value.to_i) : format_value(value, @available_criterias[criteria][:format])) |
|
106 | value.blank? ? l(:label_none) : ((k = @available_criterias[criteria][:klass]) ? k.find_by_id(value.to_i) : format_value(value, @available_criterias[criteria][:format])) | |
105 | end |
|
107 | end | |
106 |
|
108 | |||
107 | def report_to_csv(criterias, periods, hours) |
|
109 | def report_to_csv(criterias, periods, hours) | |
108 | export = StringIO.new |
|
110 | export = StringIO.new | |
109 | CSV::Writer.generate(export, l(:general_csv_separator)) do |csv| |
|
111 | CSV::Writer.generate(export, l(:general_csv_separator)) do |csv| | |
110 | # Column headers |
|
112 | # Column headers | |
111 | headers = criterias.collect {|criteria| l(@available_criterias[criteria][:label]) } |
|
113 | headers = criterias.collect {|criteria| l(@available_criterias[criteria][:label]) } | |
112 | headers += periods |
|
114 | headers += periods | |
113 | headers << l(:label_total) |
|
115 | headers << l(:label_total) | |
114 | csv << headers.collect {|c| to_utf8(c) } |
|
116 | csv << headers.collect {|c| to_utf8(c) } | |
115 | # Content |
|
117 | # Content | |
116 | report_criteria_to_csv(csv, criterias, periods, hours) |
|
118 | report_criteria_to_csv(csv, criterias, periods, hours) | |
117 | # Total row |
|
119 | # Total row | |
118 | row = [ l(:label_total) ] + [''] * (criterias.size - 1) |
|
120 | row = [ l(:label_total) ] + [''] * (criterias.size - 1) | |
119 | total = 0 |
|
121 | total = 0 | |
120 | periods.each do |period| |
|
122 | periods.each do |period| | |
121 | sum = sum_hours(select_hours(hours, @columns, period.to_s)) |
|
123 | sum = sum_hours(select_hours(hours, @columns, period.to_s)) | |
122 | total += sum |
|
124 | total += sum | |
123 | row << (sum > 0 ? "%.2f" % sum : '') |
|
125 | row << (sum > 0 ? "%.2f" % sum : '') | |
124 | end |
|
126 | end | |
125 | row << "%.2f" %total |
|
127 | row << "%.2f" %total | |
126 | csv << row |
|
128 | csv << row | |
127 | end |
|
129 | end | |
128 | export.rewind |
|
130 | export.rewind | |
129 | export |
|
131 | export | |
130 | end |
|
132 | end | |
131 |
|
133 | |||
132 | def report_criteria_to_csv(csv, criterias, periods, hours, level=0) |
|
134 | def report_criteria_to_csv(csv, criterias, periods, hours, level=0) | |
133 | hours.collect {|h| h[criterias[level]].to_s}.uniq.each do |value| |
|
135 | hours.collect {|h| h[criterias[level]].to_s}.uniq.each do |value| | |
134 | hours_for_value = select_hours(hours, criterias[level], value) |
|
136 | hours_for_value = select_hours(hours, criterias[level], value) | |
135 | next if hours_for_value.empty? |
|
137 | next if hours_for_value.empty? | |
136 | row = [''] * level |
|
138 | row = [''] * level | |
137 | row << to_utf8(format_criteria_value(criterias[level], value)) |
|
139 | row << to_utf8(format_criteria_value(criterias[level], value)) | |
138 | row += [''] * (criterias.length - level - 1) |
|
140 | row += [''] * (criterias.length - level - 1) | |
139 | total = 0 |
|
141 | total = 0 | |
140 | periods.each do |period| |
|
142 | periods.each do |period| | |
141 | sum = sum_hours(select_hours(hours_for_value, @columns, period.to_s)) |
|
143 | sum = sum_hours(select_hours(hours_for_value, @columns, period.to_s)) | |
142 | total += sum |
|
144 | total += sum | |
143 | row << (sum > 0 ? "%.2f" % sum : '') |
|
145 | row << (sum > 0 ? "%.2f" % sum : '') | |
144 | end |
|
146 | end | |
145 | row << "%.2f" %total |
|
147 | row << "%.2f" %total | |
146 | csv << row |
|
148 | csv << row | |
147 |
|
149 | |||
148 | if criterias.length > level + 1 |
|
150 | if criterias.length > level + 1 | |
149 | report_criteria_to_csv(csv, criterias, periods, hours_for_value, level + 1) |
|
151 | report_criteria_to_csv(csv, criterias, periods, hours_for_value, level + 1) | |
150 | end |
|
152 | end | |
151 | end |
|
153 | end | |
152 | end |
|
154 | end | |
153 |
|
155 | |||
154 | def to_utf8(s) |
|
156 | def to_utf8(s) | |
155 | @ic ||= Iconv.new(l(:general_csv_encoding), 'UTF-8') |
|
157 | @ic ||= Iconv.new(l(:general_csv_encoding), 'UTF-8') | |
156 | begin; @ic.iconv(s.to_s); rescue; s.to_s; end |
|
158 | begin; @ic.iconv(s.to_s); rescue; s.to_s; end | |
157 | end |
|
159 | end | |
158 | end |
|
160 | end |
General Comments 0
You need to be logged in to leave comments.
Login now