@@ -0,0 +1,65 | |||||
|
1 | # Redmine - project management software | |||
|
2 | # Copyright (C) 2006-2012 Jean-Philippe Lang | |||
|
3 | # | |||
|
4 | # This program is free software; you can redistribute it and/or | |||
|
5 | # modify it under the terms of the GNU General Public License | |||
|
6 | # as published by the Free Software Foundation; either version 2 | |||
|
7 | # of the License, or (at your option) any later version. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
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 | |||
|
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
|
17 | ||||
|
18 | class TimeEntryQuery < Query | |||
|
19 | ||||
|
20 | self.queried_class = TimeEntry | |||
|
21 | ||||
|
22 | self.available_columns = [ | |||
|
23 | QueryColumn.new(:project, :sortable => "#{Project.table_name}.name", :groupable => true), | |||
|
24 | QueryColumn.new(:spent_on, :sortable => ["#{TimeEntry.table_name}.spent_on", "#{TimeEntry.table_name}.created_on"]), | |||
|
25 | QueryColumn.new(:user, :sortable => lambda {User.fields_for_order_statement}, :groupable => true), | |||
|
26 | QueryColumn.new(:activity, :sortable => "#{TimeEntryActivity.table_name}.position", :groupable => true), | |||
|
27 | QueryColumn.new(:issue, :sortable => "#{Issue.table_name}.id"), | |||
|
28 | QueryColumn.new(:comments), | |||
|
29 | QueryColumn.new(:hours, :sortable => "#{TimeEntry.table_name}.hours"), | |||
|
30 | ] | |||
|
31 | ||||
|
32 | def initialize(attributes=nil, *args) | |||
|
33 | super attributes | |||
|
34 | self.filters ||= {} | |||
|
35 | add_filter('spent_on', '*') unless filters.present? | |||
|
36 | end | |||
|
37 | ||||
|
38 | def available_filters | |||
|
39 | return @available_filters if @available_filters | |||
|
40 | @available_filters = { | |||
|
41 | "spent_on" => { :type => :date_past, :order => 0 } | |||
|
42 | } | |||
|
43 | @available_filters.each do |field, options| | |||
|
44 | options[:name] ||= l(options[:label] || "field_#{field}".gsub(/_id$/, '')) | |||
|
45 | end | |||
|
46 | @available_filters | |||
|
47 | end | |||
|
48 | ||||
|
49 | def default_columns_names | |||
|
50 | @default_columns_names ||= [:project, :spent_on, :user, :activity, :issue, :comments, :hours] | |||
|
51 | end | |||
|
52 | ||||
|
53 | # Accepts :from/:to params as shortcut filters | |||
|
54 | def build_from_params(params) | |||
|
55 | super | |||
|
56 | if params[:from].present? && params[:to].present? | |||
|
57 | add_filter('spent_on', '><', [params[:from], params[:to]]) | |||
|
58 | elsif params[:from].present? | |||
|
59 | add_filter('spent_on', '>=', [params[:from]]) | |||
|
60 | elsif params[:to].present? | |||
|
61 | add_filter('spent_on', '<=', [params[:to]]) | |||
|
62 | end | |||
|
63 | self | |||
|
64 | end | |||
|
65 | end |
@@ -36,24 +36,14 class TimelogController < ApplicationController | |||||
36 | include TimelogHelper |
|
36 | include TimelogHelper | |
37 | helper :custom_fields |
|
37 | helper :custom_fields | |
38 | include CustomFieldsHelper |
|
38 | include CustomFieldsHelper | |
|
39 | helper :queries | |||
39 |
|
40 | |||
40 | def index |
|
41 | def index | |
41 | sort_init 'spent_on', 'desc' |
|
42 | @query = TimeEntryQuery.build_from_params(params, :name => '_') | |
42 | sort_update 'spent_on' => ['spent_on', "#{TimeEntry.table_name}.created_on"], |
|
43 | scope = time_entry_scope | |
43 | 'user' => 'user_id', |
|
|||
44 | 'activity' => 'activity_id', |
|
|||
45 | 'project' => "#{Project.table_name}.name", |
|
|||
46 | 'issue' => 'issue_id', |
|
|||
47 | 'hours' => 'hours' |
|
|||
48 |
|
44 | |||
49 | retrieve_date_range |
|
45 | sort_init(@query.sort_criteria.empty? ? [['spent_on', 'desc']] : @query.sort_criteria) | |
50 |
|
46 | sort_update(@query.sortable_columns) | ||
51 | scope = TimeEntry.visible.spent_between(@from, @to) |
|
|||
52 | if @issue |
|
|||
53 | scope = scope.on_issue(@issue) |
|
|||
54 | elsif @project |
|
|||
55 | scope = scope.on_project(@project, Setting.display_subprojects_issues?) |
|
|||
56 | end |
|
|||
57 |
|
47 | |||
58 | respond_to do |format| |
|
48 | respond_to do |format| | |
59 | format.html { |
|
49 | format.html { | |
@@ -100,8 +90,10 class TimelogController < ApplicationController | |||||
100 | end |
|
90 | end | |
101 |
|
91 | |||
102 | def report |
|
92 | def report | |
103 | retrieve_date_range |
|
93 | @query = TimeEntryQuery.build_from_params(params, :name => '_') | |
104 | @report = Redmine::Helpers::TimeReport.new(@project, @issue, params[:criteria], params[:columns], @from, @to) |
|
94 | scope = time_entry_scope | |
|
95 | ||||
|
96 | @report = Redmine::Helpers::TimeReport.new(@project, @issue, params[:criteria], params[:columns], scope) | |||
105 |
|
97 | |||
106 | respond_to do |format| |
|
98 | respond_to do |format| | |
107 | format.html { render :layout => !request.xhr? } |
|
99 | format.html { render :layout => !request.xhr? } | |
@@ -291,6 +283,17 private | |||||
291 | end |
|
283 | end | |
292 | end |
|
284 | end | |
293 |
|
285 | |||
|
286 | # Returns the TimeEntry scope for index and report actions | |||
|
287 | def time_entry_scope | |||
|
288 | scope = TimeEntry.visible.where(@query.statement) | |||
|
289 | if @issue | |||
|
290 | scope = scope.on_issue(@issue) | |||
|
291 | elsif @project | |||
|
292 | scope = scope.on_project(@project, Setting.display_subprojects_issues?) | |||
|
293 | end | |||
|
294 | scope | |||
|
295 | end | |||
|
296 | ||||
294 | # Retrieves the date range based on predefined ranges or specific from/to param dates |
|
297 | # Retrieves the date range based on predefined ranges or specific from/to param dates | |
295 | def retrieve_date_range |
|
298 | def retrieve_date_range | |
296 | @free_period = false |
|
299 | @free_period = false |
@@ -117,7 +117,13 class Query < ActiveRecord::Base | |||||
117 | "><t+"=> :label_in_the_next_days, |
|
117 | "><t+"=> :label_in_the_next_days, | |
118 | "t+" => :label_in, |
|
118 | "t+" => :label_in, | |
119 | "t" => :label_today, |
|
119 | "t" => :label_today, | |
|
120 | "ld" => :label_yesterday, | |||
120 | "w" => :label_this_week, |
|
121 | "w" => :label_this_week, | |
|
122 | "lw" => :label_last_week, | |||
|
123 | "l2w" => [:label_last_n_weeks, :count => 2], | |||
|
124 | "m" => :label_this_month, | |||
|
125 | "lm" => :label_last_month, | |||
|
126 | "y" => :label_this_year, | |||
121 | ">t-" => :label_less_than_ago, |
|
127 | ">t-" => :label_less_than_ago, | |
122 | "<t-" => :label_more_than_ago, |
|
128 | "<t-" => :label_more_than_ago, | |
123 | "><t-"=> :label_in_the_past_days, |
|
129 | "><t-"=> :label_in_the_past_days, | |
@@ -135,8 +141,8 class Query < ActiveRecord::Base | |||||
135 | :list_status => [ "o", "=", "!", "c", "*" ], |
|
141 | :list_status => [ "o", "=", "!", "c", "*" ], | |
136 | :list_optional => [ "=", "!", "!*", "*" ], |
|
142 | :list_optional => [ "=", "!", "!*", "*" ], | |
137 | :list_subprojects => [ "*", "!*", "=" ], |
|
143 | :list_subprojects => [ "*", "!*", "=" ], | |
138 | :date => [ "=", ">=", "<=", "><", "<t+", ">t+", "><t+", "t+", "t", "w", ">t-", "<t-", "><t-", "t-", "!*", "*" ], |
|
144 | :date => [ "=", ">=", "<=", "><", "<t+", ">t+", "><t+", "t+", "t", "ld", "w", "lw", "l2w", "m", "lm", "y", ">t-", "<t-", "><t-", "t-", "!*", "*" ], | |
139 | :date_past => [ "=", ">=", "<=", "><", ">t-", "<t-", "><t-", "t-", "t", "w", "!*", "*" ], |
|
145 | :date_past => [ "=", ">=", "<=", "><", ">t-", "<t-", "><t-", "t-", "t", "ld", "w", "lw", "l2w", "m", "lm", "y", "!*", "*" ], | |
140 | :string => [ "=", "~", "!", "!~", "!*", "*" ], |
|
146 | :string => [ "=", "~", "!", "!~", "!*", "*" ], | |
141 | :text => [ "~", "!~", "!*", "*" ], |
|
147 | :text => [ "~", "!~", "!*", "*" ], | |
142 | :integer => [ "=", ">=", "<=", "><", "!*", "*" ], |
|
148 | :integer => [ "=", ">=", "<=", "><", "!*", "*" ], | |
@@ -173,6 +179,11 class Query < ActiveRecord::Base | |||||
173 | self |
|
179 | self | |
174 | end |
|
180 | end | |
175 |
|
181 | |||
|
182 | # Builds a new query from the given params and attributes | |||
|
183 | def self.build_from_params(params, attributes={}) | |||
|
184 | new(attributes).build_from_params(params) | |||
|
185 | end | |||
|
186 | ||||
176 | def validate_query_filters |
|
187 | def validate_query_filters | |
177 | filters.each_key do |field| |
|
188 | filters.each_key do |field| | |
178 | if values_for(field) |
|
189 | if values_for(field) | |
@@ -195,7 +206,7 class Query < ActiveRecord::Base | |||||
195 | # filter requires one or more values |
|
206 | # filter requires one or more values | |
196 | (values_for(field) and !values_for(field).first.blank?) or |
|
207 | (values_for(field) and !values_for(field).first.blank?) or | |
197 | # filter doesn't require any value |
|
208 | # filter doesn't require any value | |
198 | ["o", "c", "!*", "*", "t", "w"].include? operator_for(field) |
|
209 | ["o", "c", "!*", "*", "t", "ld", "w", "lw", "l2w", "m", "lm", "y"].include? operator_for(field) | |
199 | end if filters |
|
210 | end if filters | |
200 | end |
|
211 | end | |
201 |
|
212 | |||
@@ -218,7 +229,7 class Query < ActiveRecord::Base | |||||
218 |
|
229 | |||
219 | # Returns a hash of localized labels for all filter operators |
|
230 | # Returns a hash of localized labels for all filter operators | |
220 | def self.operators_labels |
|
231 | def self.operators_labels | |
221 | operators.inject({}) {|h, operator| h[operator.first] = l(operator.last); h} |
|
232 | operators.inject({}) {|h, operator| h[operator.first] = l(*operator.last); h} | |
222 | end |
|
233 | end | |
223 |
|
234 | |||
224 | # Returns a representation of the available filters for JSON serialization |
|
235 | # Returns a representation of the available filters for JSON serialization | |
@@ -245,7 +256,7 class Query < ActiveRecord::Base | |||||
245 | @all_projects_values = values |
|
256 | @all_projects_values = values | |
246 | end |
|
257 | end | |
247 |
|
258 | |||
248 | def add_filter(field, operator, values) |
|
259 | def add_filter(field, operator, values=nil) | |
249 | # values must be an array |
|
260 | # values must be an array | |
250 | return unless values.nil? || values.is_a?(Array) |
|
261 | return unless values.nil? || values.is_a?(Array) | |
251 | # check if field is defined as an available filter |
|
262 | # check if field is defined as an available filter | |
@@ -612,12 +623,39 class Query < ActiveRecord::Base | |||||
612 | when "t" |
|
623 | when "t" | |
613 | # = today |
|
624 | # = today | |
614 | sql = relative_date_clause(db_table, db_field, 0, 0) |
|
625 | sql = relative_date_clause(db_table, db_field, 0, 0) | |
|
626 | when "ld" | |||
|
627 | # = yesterday | |||
|
628 | sql = relative_date_clause(db_table, db_field, -1, -1) | |||
615 | when "w" |
|
629 | when "w" | |
616 | # = this week |
|
630 | # = this week | |
617 | first_day_of_week = l(:general_first_day_of_week).to_i |
|
631 | first_day_of_week = l(:general_first_day_of_week).to_i | |
618 | day_of_week = Date.today.cwday |
|
632 | day_of_week = Date.today.cwday | |
619 | days_ago = (day_of_week >= first_day_of_week ? day_of_week - first_day_of_week : day_of_week + 7 - first_day_of_week) |
|
633 | days_ago = (day_of_week >= first_day_of_week ? day_of_week - first_day_of_week : day_of_week + 7 - first_day_of_week) | |
620 | sql = relative_date_clause(db_table, db_field, - days_ago, - days_ago + 6) |
|
634 | sql = relative_date_clause(db_table, db_field, - days_ago, - days_ago + 6) | |
|
635 | when "lw" | |||
|
636 | # = last week | |||
|
637 | first_day_of_week = l(:general_first_day_of_week).to_i | |||
|
638 | day_of_week = Date.today.cwday | |||
|
639 | days_ago = (day_of_week >= first_day_of_week ? day_of_week - first_day_of_week : day_of_week + 7 - first_day_of_week) | |||
|
640 | sql = relative_date_clause(db_table, db_field, - days_ago - 7, - days_ago - 1) | |||
|
641 | when "l2w" | |||
|
642 | # = last 2 weeks | |||
|
643 | first_day_of_week = l(:general_first_day_of_week).to_i | |||
|
644 | day_of_week = Date.today.cwday | |||
|
645 | days_ago = (day_of_week >= first_day_of_week ? day_of_week - first_day_of_week : day_of_week + 7 - first_day_of_week) | |||
|
646 | sql = relative_date_clause(db_table, db_field, - days_ago - 14, - days_ago - 1) | |||
|
647 | when "m" | |||
|
648 | # = this month | |||
|
649 | date = Date.today | |||
|
650 | sql = date_clause(db_table, db_field, date.beginning_of_month, date.end_of_month) | |||
|
651 | when "lm" | |||
|
652 | # = last month | |||
|
653 | date = Date.today.prev_month | |||
|
654 | sql = date_clause(db_table, db_field, date.beginning_of_month, date.end_of_month) | |||
|
655 | when "y" | |||
|
656 | # = this year | |||
|
657 | date = Date.today | |||
|
658 | sql = date_clause(db_table, db_field, date.beginning_of_year, date.end_of_year) | |||
621 | when "~" |
|
659 | when "~" | |
622 | sql = "LOWER(#{db_table}.#{db_field}) LIKE '%#{connection.quote_string(value.first.to_s.downcase)}%'" |
|
660 | sql = "LOWER(#{db_table}.#{db_field}) LIKE '%#{connection.quote_string(value.first.to_s.downcase)}%'" | |
623 | when "!~" |
|
661 | when "!~" |
@@ -1,42 +1,23 | |||||
1 | <fieldset id="date-range" class="collapsible"> |
|
1 | <div id="query_form_content" class="hide-when-print"> | |
2 | <legend onclick="toggleFieldset(this);"><%= l(:label_date_range) %></legend> |
|
2 | <fieldset id="filters" class="collapsible <%= @query.new_record? ? "" : "collapsed" %>"> | |
3 | <div> |
|
3 | <legend onclick="toggleFieldset(this);"><%= l(:label_filter_plural) %></legend> | |
4 | <p> |
|
4 | <div style="<%= @query.new_record? ? "" : "display: none;" %>"> | |
5 | <%= label_tag "period_type_list", l(:description_date_range_list), :class => "hidden-for-sighted" %> |
|
5 | <%= render :partial => 'queries/filters', :locals => {:query => @query} %> | |
6 | <%= radio_button_tag 'period_type', '1', !@free_period, :onclick => '$("#from,#to").attr("disabled", true);$("#period").removeAttr("disabled");', :id => "period_type_list"%> |
|
6 | </div> | |
7 | <%= select_tag 'period', options_for_period_select(params[:period]), |
|
|||
8 | :onchange => 'this.form.submit();', |
|
|||
9 | :onfocus => '$("#period_type_1").attr("checked", true);', |
|
|||
10 | :disabled => @free_period %> |
|
|||
11 | </p> |
|
|||
12 | <p> |
|
|||
13 | <%= label_tag "period_type_interval", l(:description_date_range_interval), :class => "hidden-for-sighted" %> |
|
|||
14 | <%= radio_button_tag 'period_type', '2', @free_period, :onclick => '$("#from,#to").removeAttr("disabled");$("#period").attr("disabled", true);', :id => "period_type_interval" %> |
|
|||
15 | <%= l(:label_date_from_to, |
|
|||
16 | :start => ((label_tag "from", l(:description_date_from), :class => "hidden-for-sighted") + |
|
|||
17 | text_field_tag('from', @from, :size => 10, :disabled => !@free_period) + calendar_for('from')), |
|
|||
18 | :end => ((label_tag "to", l(:description_date_to), :class => "hidden-for-sighted") + |
|
|||
19 | text_field_tag('to', @to, :size => 10, :disabled => !@free_period) + calendar_for('to'))).html_safe %> |
|
|||
20 | </p> |
|
|||
21 | </div> |
|
|||
22 | </fieldset> |
|
7 | </fieldset> | |
23 | <p class="buttons"> |
|
8 | </div> | |
|
9 | ||||
|
10 | <p class="buttons hide-when-print"> | |||
24 | <%= link_to_function l(:button_apply), '$("#query_form").submit()', :class => 'icon icon-checked' %> |
|
11 | <%= link_to_function l(:button_apply), '$("#query_form").submit()', :class => 'icon icon-checked' %> | |
25 |
<%= link_to l(:button_clear), {: |
|
12 | <%= link_to l(:button_clear), {:project_id => @project, :issue_id => @issue}, :class => 'icon icon-reload' %> | |
26 | </p> |
|
13 | </p> | |
27 |
|
14 | |||
28 | <div class="tabs"> |
|
15 | <div class="tabs"> | |
29 | <% url_params = @free_period ? { :from => @from, :to => @to } : { :period => params[:period] } %> |
|
16 | <% query_params = params.slice(:f, :op, :v, :sort) %> | |
30 | <ul> |
|
17 | <ul> | |
31 |
<li><%= link_to(l(:label_details), |
|
18 | <li><%= link_to(l(:label_details), query_params.merge({:controller => 'timelog', :action => 'index', :project_id => @project, :issue_id => @issue }), | |
32 | :class => (action_name == 'index' ? 'selected' : nil)) %></li> |
|
19 | :class => (action_name == 'index' ? 'selected' : nil)) %></li> | |
33 |
<li><%= link_to(l(:label_report), |
|
20 | <li><%= link_to(l(:label_report), query_params.merge({:controller => 'timelog', :action => 'report', :project_id => @project, :issue_id => @issue}), | |
34 | :class => (action_name == 'report' ? 'selected' : nil)) %></li> |
|
21 | :class => (action_name == 'report' ? 'selected' : nil)) %></li> | |
35 | </ul> |
|
22 | </ul> | |
36 | </div> |
|
23 | </div> | |
37 |
|
||||
38 | <%= javascript_tag do %> |
|
|||
39 | $('#from, #to').change(function(){ |
|
|||
40 | $('#period_type_interval').attr('checked', true); $('#from,#to').removeAttr('disabled'); $('#period').attr('disabled', true); |
|
|||
41 | }); |
|
|||
42 | <% end %> |
|
@@ -18,9 +18,9 | |||||
18 | module Redmine |
|
18 | module Redmine | |
19 | module Helpers |
|
19 | module Helpers | |
20 | class TimeReport |
|
20 | class TimeReport | |
21 |
attr_reader :criteria, :columns |
|
21 | attr_reader :criteria, :columns, :hours, :total_hours, :periods | |
22 |
|
22 | |||
23 |
def initialize(project, issue, criteria, columns, |
|
23 | def initialize(project, issue, criteria, columns, time_entry_scope) | |
24 | @project = project |
|
24 | @project = project | |
25 | @issue = issue |
|
25 | @issue = issue | |
26 |
|
26 | |||
@@ -30,8 +30,7 module Redmine | |||||
30 | @criteria = @criteria[0,3] |
|
30 | @criteria = @criteria[0,3] | |
31 |
|
31 | |||
32 | @columns = (columns && %w(year month week day).include?(columns)) ? columns : 'month' |
|
32 | @columns = (columns && %w(year month week day).include?(columns)) ? columns : 'month' | |
33 | @from = from |
|
33 | @scope = time_entry_scope | |
34 | @to = to |
|
|||
35 |
|
34 | |||
36 | run |
|
35 | run | |
37 | end |
|
36 | end | |
@@ -44,15 +43,9 module Redmine | |||||
44 |
|
43 | |||
45 | def run |
|
44 | def run | |
46 | unless @criteria.empty? |
|
45 | unless @criteria.empty? | |
47 | scope = TimeEntry.visible.spent_between(@from, @to) |
|
|||
48 | if @issue |
|
|||
49 | scope = scope.on_issue(@issue) |
|
|||
50 | elsif @project |
|
|||
51 | scope = scope.on_project(@project, Setting.display_subprojects_issues?) |
|
|||
52 | end |
|
|||
53 | time_columns = %w(tyear tmonth tweek spent_on) |
|
46 | time_columns = %w(tyear tmonth tweek spent_on) | |
54 | @hours = [] |
|
47 | @hours = [] | |
55 | scope.sum(:hours, :include => :issue, :group => @criteria.collect{|criteria| @available_criteria[criteria][:sql]} + time_columns).each do |hash, hours| |
|
48 | @scope.sum(:hours, :include => :issue, :group => @criteria.collect{|criteria| @available_criteria[criteria][:sql]} + time_columns).each do |hash, hours| | |
56 | h = {'hours' => hours} |
|
49 | h = {'hours' => hours} | |
57 | (@criteria + time_columns).each_with_index do |name, i| |
|
50 | (@criteria + time_columns).each_with_index do |name, i| | |
58 | h[name] = hash[i] |
|
51 | h[name] = hash[i] | |
@@ -73,15 +66,11 module Redmine | |||||
73 | end |
|
66 | end | |
74 | end |
|
67 | end | |
75 |
|
68 | |||
76 | if @from.nil? |
|
69 | min = @hours.collect {|row| row['spent_on']}.min | |
77 | min = @hours.collect {|row| row['spent_on']}.min |
|
70 | @from = min ? min.to_date : Date.today | |
78 | @from = min ? min.to_date : Date.today |
|
|||
79 | end |
|
|||
80 |
|
71 | |||
81 | if @to.nil? |
|
72 | max = @hours.collect {|row| row['spent_on']}.max | |
82 | max = @hours.collect {|row| row['spent_on']}.max |
|
73 | @to = max ? max.to_date : Date.today | |
83 | @to = max ? max.to_date : Date.today |
|
|||
84 | end |
|
|||
85 |
|
74 | |||
86 | @total_hours = @hours.inject(0) {|s,k| s = s + k['hours'].to_f} |
|
75 | @total_hours = @hours.inject(0) {|s,k| s = s + k['hours'].to_f} | |
87 |
|
76 |
@@ -242,7 +242,13 function toggleOperator(field) { | |||||
242 | case "!*": |
|
242 | case "!*": | |
243 | case "*": |
|
243 | case "*": | |
244 | case "t": |
|
244 | case "t": | |
|
245 | case "ld": | |||
245 | case "w": |
|
246 | case "w": | |
|
247 | case "lw": | |||
|
248 | case "l2w": | |||
|
249 | case "m": | |||
|
250 | case "lm": | |||
|
251 | case "y": | |||
246 | case "o": |
|
252 | case "o": | |
247 | case "c": |
|
253 | case "c": | |
248 | enableValues(field, []); |
|
254 | enableValues(field, []); |
@@ -166,10 +166,9 class TimeEntryReportsControllerTest < ActionController::TestCase | |||||
166 | assert_equal 'text/csv; header=present', @response.content_type |
|
166 | assert_equal 'text/csv; header=present', @response.content_type | |
167 | lines = @response.body.chomp.split("\n") |
|
167 | lines = @response.body.chomp.split("\n") | |
168 | # Headers |
|
168 | # Headers | |
169 |
assert_equal 'Project,Member,Activity,2007- |
|
169 | assert_equal 'Project,Member,Activity,2007-3,2007-4,Total', lines.first | |
170 | lines.first |
|
|||
171 | # Total row |
|
170 | # Total row | |
172 |
assert_equal 'Total,"","", |
|
171 | assert_equal 'Total,"","",154.25,8.65,162.90', lines.last | |
173 | end |
|
172 | end | |
174 |
|
173 | |||
175 | def test_report_csv_export |
|
174 | def test_report_csv_export | |
@@ -180,10 +179,9 class TimeEntryReportsControllerTest < ActionController::TestCase | |||||
180 | assert_equal 'text/csv; header=present', @response.content_type |
|
179 | assert_equal 'text/csv; header=present', @response.content_type | |
181 | lines = @response.body.chomp.split("\n") |
|
180 | lines = @response.body.chomp.split("\n") | |
182 | # Headers |
|
181 | # Headers | |
183 |
assert_equal 'Project,Member,Activity,2007- |
|
182 | assert_equal 'Project,Member,Activity,2007-3,2007-4,Total', lines.first | |
184 | lines.first |
|
|||
185 | # Total row |
|
183 | # Total row | |
186 |
assert_equal 'Total,"","", |
|
184 | assert_equal 'Total,"","",154.25,8.65,162.90', lines.last | |
187 | end |
|
185 | end | |
188 |
|
186 | |||
189 | def test_csv_big_5 |
|
187 | def test_csv_big_5 |
@@ -430,131 +430,50 class TimelogControllerTest < ActionController::TestCase | |||||
430 | assert_equal [1, 3], assigns(:entries).collect(&:project_id).uniq.sort |
|
430 | assert_equal [1, 3], assigns(:entries).collect(&:project_id).uniq.sort | |
431 | assert_not_nil assigns(:total_hours) |
|
431 | assert_not_nil assigns(:total_hours) | |
432 | assert_equal "162.90", "%.2f" % assigns(:total_hours) |
|
432 | assert_equal "162.90", "%.2f" % assigns(:total_hours) | |
433 | # display all time by default |
|
|||
434 | assert_nil assigns(:from) |
|
|||
435 | assert_nil assigns(:to) |
|
|||
436 | assert_tag :form, |
|
433 | assert_tag :form, | |
437 | :attributes => {:action => "/projects/ecookbook/time_entries", :id => 'query_form'} |
|
434 | :attributes => {:action => "/projects/ecookbook/time_entries", :id => 'query_form'} | |
438 | end |
|
435 | end | |
439 |
|
436 | |||
440 | def test_index_at_project_level_with_date_range |
|
437 | def test_index_at_project_level_with_date_range | |
441 |
get :index, :project_id => 'ecookbook', |
|
438 | get :index, :project_id => 'ecookbook', | |
|
439 | :f => ['spent_on'], | |||
|
440 | :op => {'spent_on' => '><'}, | |||
|
441 | :v => {'spent_on' => ['2007-03-20', '2007-04-30']} | |||
442 | assert_response :success |
|
442 | assert_response :success | |
443 | assert_template 'index' |
|
443 | assert_template 'index' | |
444 | assert_not_nil assigns(:entries) |
|
444 | assert_not_nil assigns(:entries) | |
445 | assert_equal 3, assigns(:entries).size |
|
445 | assert_equal 3, assigns(:entries).size | |
446 | assert_not_nil assigns(:total_hours) |
|
446 | assert_not_nil assigns(:total_hours) | |
447 | assert_equal "12.90", "%.2f" % assigns(:total_hours) |
|
447 | assert_equal "12.90", "%.2f" % assigns(:total_hours) | |
448 | assert_equal '2007-03-20'.to_date, assigns(:from) |
|
|||
449 | assert_equal '2007-04-30'.to_date, assigns(:to) |
|
|||
450 | assert_tag :form, |
|
448 | assert_tag :form, | |
451 | :attributes => {:action => "/projects/ecookbook/time_entries", :id => 'query_form'} |
|
449 | :attributes => {:action => "/projects/ecookbook/time_entries", :id => 'query_form'} | |
452 | end |
|
450 | end | |
453 |
|
451 | |||
454 |
def test_index_at_project_level_with_ |
|
452 | def test_index_at_project_level_with_date_range_using_from_and_to_params | |
455 |
get :index, :project_id => 'ecookbook', : |
|
453 | get :index, :project_id => 'ecookbook', :from => '2007-03-20', :to => '2007-04-30' | |
456 | assert_response :success |
|
454 | assert_response :success | |
457 | assert_template 'index' |
|
455 | assert_template 'index' | |
458 | assert_not_nil assigns(:entries) |
|
456 | assert_not_nil assigns(:entries) | |
|
457 | assert_equal 3, assigns(:entries).size | |||
459 | assert_not_nil assigns(:total_hours) |
|
458 | assert_not_nil assigns(:total_hours) | |
460 |
assert_equal |
|
459 | assert_equal "12.90", "%.2f" % assigns(:total_hours) | |
461 | assert_equal Date.today, assigns(:to) |
|
|||
462 | assert_tag :form, |
|
460 | assert_tag :form, | |
463 | :attributes => {:action => "/projects/ecookbook/time_entries", :id => 'query_form'} |
|
461 | :attributes => {:action => "/projects/ecookbook/time_entries", :id => 'query_form'} | |
464 | end |
|
462 | end | |
465 |
|
463 | |||
466 |
def test_index_ |
|
464 | def test_index_at_project_level_with_period | |
467 |
get :index, :project_id => 'ecookbook', |
|
465 | get :index, :project_id => 'ecookbook', | |
|
466 | :f => ['spent_on'], | |||
|
467 | :op => {'spent_on' => '>t-'}, | |||
|
468 | :v => {'spent_on' => ['7']} | |||
468 | assert_response :success |
|
469 | assert_response :success | |
469 | assert_template 'index' |
|
470 | assert_template 'index' | |
|
471 | assert_not_nil assigns(:entries) | |||
470 | assert_not_nil assigns(:total_hours) |
|
472 | assert_not_nil assigns(:total_hours) | |
471 | assert_equal "4.25", "%.2f" % assigns(:total_hours) |
|
|||
472 | assert_tag :form, |
|
473 | assert_tag :form, | |
473 | :attributes => {:action => "/projects/ecookbook/time_entries", :id => 'query_form'} |
|
474 | :attributes => {:action => "/projects/ecookbook/time_entries", :id => 'query_form'} | |
474 | end |
|
475 | end | |
475 |
|
476 | |||
476 | def test_index_from_a_date |
|
|||
477 | get :index, :project_id => 'ecookbook', :from => "2007-03-23", :to => "" |
|
|||
478 | assert_equal '2007-03-23'.to_date, assigns(:from) |
|
|||
479 | assert_nil assigns(:to) |
|
|||
480 | end |
|
|||
481 |
|
||||
482 | def test_index_to_a_date |
|
|||
483 | get :index, :project_id => 'ecookbook', :from => "", :to => "2007-03-23" |
|
|||
484 | assert_nil assigns(:from) |
|
|||
485 | assert_equal '2007-03-23'.to_date, assigns(:to) |
|
|||
486 | end |
|
|||
487 |
|
||||
488 | def test_index_today |
|
|||
489 | Date.stubs(:today).returns('2011-12-15'.to_date) |
|
|||
490 | get :index, :period => 'today' |
|
|||
491 | assert_equal '2011-12-15'.to_date, assigns(:from) |
|
|||
492 | assert_equal '2011-12-15'.to_date, assigns(:to) |
|
|||
493 | end |
|
|||
494 |
|
||||
495 | def test_index_yesterday |
|
|||
496 | Date.stubs(:today).returns('2011-12-15'.to_date) |
|
|||
497 | get :index, :period => 'yesterday' |
|
|||
498 | assert_equal '2011-12-14'.to_date, assigns(:from) |
|
|||
499 | assert_equal '2011-12-14'.to_date, assigns(:to) |
|
|||
500 | end |
|
|||
501 |
|
||||
502 | def test_index_current_week |
|
|||
503 | Date.stubs(:today).returns('2011-12-15'.to_date) |
|
|||
504 | get :index, :period => 'current_week' |
|
|||
505 | assert_equal '2011-12-12'.to_date, assigns(:from) |
|
|||
506 | assert_equal '2011-12-18'.to_date, assigns(:to) |
|
|||
507 | end |
|
|||
508 |
|
||||
509 | def test_index_last_week |
|
|||
510 | Date.stubs(:today).returns('2011-12-15'.to_date) |
|
|||
511 | get :index, :period => 'last_week' |
|
|||
512 | assert_equal '2011-12-05'.to_date, assigns(:from) |
|
|||
513 | assert_equal '2011-12-11'.to_date, assigns(:to) |
|
|||
514 | end |
|
|||
515 |
|
||||
516 | def test_index_last_2_week |
|
|||
517 | Date.stubs(:today).returns('2011-12-15'.to_date) |
|
|||
518 | get :index, :period => 'last_2_weeks' |
|
|||
519 | assert_equal '2011-11-28'.to_date, assigns(:from) |
|
|||
520 | assert_equal '2011-12-11'.to_date, assigns(:to) |
|
|||
521 | end |
|
|||
522 |
|
||||
523 | def test_index_7_days |
|
|||
524 | Date.stubs(:today).returns('2011-12-15'.to_date) |
|
|||
525 | get :index, :period => '7_days' |
|
|||
526 | assert_equal '2011-12-08'.to_date, assigns(:from) |
|
|||
527 | assert_equal '2011-12-15'.to_date, assigns(:to) |
|
|||
528 | end |
|
|||
529 |
|
||||
530 | def test_index_current_month |
|
|||
531 | Date.stubs(:today).returns('2011-12-15'.to_date) |
|
|||
532 | get :index, :period => 'current_month' |
|
|||
533 | assert_equal '2011-12-01'.to_date, assigns(:from) |
|
|||
534 | assert_equal '2011-12-31'.to_date, assigns(:to) |
|
|||
535 | end |
|
|||
536 |
|
||||
537 | def test_index_last_month |
|
|||
538 | Date.stubs(:today).returns('2011-12-15'.to_date) |
|
|||
539 | get :index, :period => 'last_month' |
|
|||
540 | assert_equal '2011-11-01'.to_date, assigns(:from) |
|
|||
541 | assert_equal '2011-11-30'.to_date, assigns(:to) |
|
|||
542 | end |
|
|||
543 |
|
||||
544 | def test_index_30_days |
|
|||
545 | Date.stubs(:today).returns('2011-12-15'.to_date) |
|
|||
546 | get :index, :period => '30_days' |
|
|||
547 | assert_equal '2011-11-15'.to_date, assigns(:from) |
|
|||
548 | assert_equal '2011-12-15'.to_date, assigns(:to) |
|
|||
549 | end |
|
|||
550 |
|
||||
551 | def test_index_current_year |
|
|||
552 | Date.stubs(:today).returns('2011-12-15'.to_date) |
|
|||
553 | get :index, :period => 'current_year' |
|
|||
554 | assert_equal '2011-01-01'.to_date, assigns(:from) |
|
|||
555 | assert_equal '2011-12-31'.to_date, assigns(:to) |
|
|||
556 | end |
|
|||
557 |
|
||||
558 | def test_index_at_issue_level |
|
477 | def test_index_at_issue_level | |
559 | get :index, :issue_id => 1 |
|
478 | get :index, :issue_id => 1 | |
560 | assert_response :success |
|
479 | assert_response :success | |
@@ -577,11 +496,18 class TimelogControllerTest < ActionController::TestCase | |||||
577 | t2 = TimeEntry.create!(:user => User.find(1), :project => Project.find(1), :hours => 1, :spent_on => '2012-06-16', :created_on => '2012-06-16 20:05:00', :activity_id => 10) |
|
496 | t2 = TimeEntry.create!(:user => User.find(1), :project => Project.find(1), :hours => 1, :spent_on => '2012-06-16', :created_on => '2012-06-16 20:05:00', :activity_id => 10) | |
578 | t3 = TimeEntry.create!(:user => User.find(1), :project => Project.find(1), :hours => 1, :spent_on => '2012-06-15', :created_on => '2012-06-16 20:10:00', :activity_id => 10) |
|
497 | t3 = TimeEntry.create!(:user => User.find(1), :project => Project.find(1), :hours => 1, :spent_on => '2012-06-15', :created_on => '2012-06-16 20:10:00', :activity_id => 10) | |
579 |
|
498 | |||
580 |
get :index, :project_id => 1, |
|
499 | get :index, :project_id => 1, | |
|
500 | :f => ['spent_on'], | |||
|
501 | :op => {'spent_on' => '><'}, | |||
|
502 | :v => {'spent_on' => ['2012-06-15', '2012-06-16']} | |||
581 | assert_response :success |
|
503 | assert_response :success | |
582 | assert_equal [t2, t1, t3], assigns(:entries) |
|
504 | assert_equal [t2, t1, t3], assigns(:entries) | |
583 |
|
505 | |||
584 | get :index, :project_id => 1, :from => '2012-06-15', :to => '2012-06-16', :sort => 'spent_on' |
|
506 | get :index, :project_id => 1, | |
|
507 | :f => ['spent_on'], | |||
|
508 | :op => {'spent_on' => '><'}, | |||
|
509 | :v => {'spent_on' => ['2012-06-15', '2012-06-16']}, | |||
|
510 | :sort => 'spent_on' | |||
585 | assert_response :success |
|
511 | assert_response :success | |
586 | assert_equal [t3, t1, t2], assigns(:entries) |
|
512 | assert_equal [t3, t1, t2], assigns(:entries) | |
587 | end |
|
513 | end |
General Comments 0
You need to be logged in to leave comments.
Login now