@@ -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 | 36 | include TimelogHelper |
|
37 | 37 | helper :custom_fields |
|
38 | 38 | include CustomFieldsHelper |
|
39 | helper :queries | |
|
39 | 40 | |
|
40 | 41 | def index |
|
41 | sort_init 'spent_on', 'desc' | |
|
42 | sort_update 'spent_on' => ['spent_on', "#{TimeEntry.table_name}.created_on"], | |
|
43 | 'user' => 'user_id', | |
|
44 | 'activity' => 'activity_id', | |
|
45 | 'project' => "#{Project.table_name}.name", | |
|
46 | 'issue' => 'issue_id', | |
|
47 | 'hours' => 'hours' | |
|
42 | @query = TimeEntryQuery.build_from_params(params, :name => '_') | |
|
43 | scope = time_entry_scope | |
|
48 | 44 | |
|
49 | retrieve_date_range | |
|
50 | ||
|
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 | |
|
45 | sort_init(@query.sort_criteria.empty? ? [['spent_on', 'desc']] : @query.sort_criteria) | |
|
46 | sort_update(@query.sortable_columns) | |
|
57 | 47 | |
|
58 | 48 | respond_to do |format| |
|
59 | 49 | format.html { |
@@ -100,8 +90,10 class TimelogController < ApplicationController | |||
|
100 | 90 | end |
|
101 | 91 | |
|
102 | 92 | def report |
|
103 | retrieve_date_range | |
|
104 | @report = Redmine::Helpers::TimeReport.new(@project, @issue, params[:criteria], params[:columns], @from, @to) | |
|
93 | @query = TimeEntryQuery.build_from_params(params, :name => '_') | |
|
94 | scope = time_entry_scope | |
|
95 | ||
|
96 | @report = Redmine::Helpers::TimeReport.new(@project, @issue, params[:criteria], params[:columns], scope) | |
|
105 | 97 | |
|
106 | 98 | respond_to do |format| |
|
107 | 99 | format.html { render :layout => !request.xhr? } |
@@ -291,6 +283,17 private | |||
|
291 | 283 | end |
|
292 | 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 | 297 | # Retrieves the date range based on predefined ranges or specific from/to param dates |
|
295 | 298 | def retrieve_date_range |
|
296 | 299 | @free_period = false |
@@ -117,7 +117,13 class Query < ActiveRecord::Base | |||
|
117 | 117 | "><t+"=> :label_in_the_next_days, |
|
118 | 118 | "t+" => :label_in, |
|
119 | 119 | "t" => :label_today, |
|
120 | "ld" => :label_yesterday, | |
|
120 | 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 | 127 | ">t-" => :label_less_than_ago, |
|
122 | 128 | "<t-" => :label_more_than_ago, |
|
123 | 129 | "><t-"=> :label_in_the_past_days, |
@@ -135,8 +141,8 class Query < ActiveRecord::Base | |||
|
135 | 141 | :list_status => [ "o", "=", "!", "c", "*" ], |
|
136 | 142 | :list_optional => [ "=", "!", "!*", "*" ], |
|
137 | 143 | :list_subprojects => [ "*", "!*", "=" ], |
|
138 | :date => [ "=", ">=", "<=", "><", "<t+", ">t+", "><t+", "t+", "t", "w", ">t-", "<t-", "><t-", "t-", "!*", "*" ], | |
|
139 | :date_past => [ "=", ">=", "<=", "><", ">t-", "<t-", "><t-", "t-", "t", "w", "!*", "*" ], | |
|
144 | :date => [ "=", ">=", "<=", "><", "<t+", ">t+", "><t+", "t+", "t", "ld", "w", "lw", "l2w", "m", "lm", "y", ">t-", "<t-", "><t-", "t-", "!*", "*" ], | |
|
145 | :date_past => [ "=", ">=", "<=", "><", ">t-", "<t-", "><t-", "t-", "t", "ld", "w", "lw", "l2w", "m", "lm", "y", "!*", "*" ], | |
|
140 | 146 | :string => [ "=", "~", "!", "!~", "!*", "*" ], |
|
141 | 147 | :text => [ "~", "!~", "!*", "*" ], |
|
142 | 148 | :integer => [ "=", ">=", "<=", "><", "!*", "*" ], |
@@ -173,6 +179,11 class Query < ActiveRecord::Base | |||
|
173 | 179 | self |
|
174 | 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 | 187 | def validate_query_filters |
|
177 | 188 | filters.each_key do |field| |
|
178 | 189 | if values_for(field) |
@@ -195,7 +206,7 class Query < ActiveRecord::Base | |||
|
195 | 206 | # filter requires one or more values |
|
196 | 207 | (values_for(field) and !values_for(field).first.blank?) or |
|
197 | 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 | 210 | end if filters |
|
200 | 211 | end |
|
201 | 212 | |
@@ -218,7 +229,7 class Query < ActiveRecord::Base | |||
|
218 | 229 | |
|
219 | 230 | # Returns a hash of localized labels for all filter operators |
|
220 | 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 | 233 | end |
|
223 | 234 | |
|
224 | 235 | # Returns a representation of the available filters for JSON serialization |
@@ -245,7 +256,7 class Query < ActiveRecord::Base | |||
|
245 | 256 | @all_projects_values = values |
|
246 | 257 | end |
|
247 | 258 | |
|
248 | def add_filter(field, operator, values) | |
|
259 | def add_filter(field, operator, values=nil) | |
|
249 | 260 | # values must be an array |
|
250 | 261 | return unless values.nil? || values.is_a?(Array) |
|
251 | 262 | # check if field is defined as an available filter |
@@ -612,12 +623,39 class Query < ActiveRecord::Base | |||
|
612 | 623 | when "t" |
|
613 | 624 | # = today |
|
614 | 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 | 629 | when "w" |
|
616 | 630 | # = this week |
|
617 | 631 | first_day_of_week = l(:general_first_day_of_week).to_i |
|
618 | 632 | day_of_week = Date.today.cwday |
|
619 | 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 | 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 | 659 | when "~" |
|
622 | 660 | sql = "LOWER(#{db_table}.#{db_field}) LIKE '%#{connection.quote_string(value.first.to_s.downcase)}%'" |
|
623 | 661 | when "!~" |
@@ -1,42 +1,23 | |||
|
1 | <fieldset id="date-range" class="collapsible"> | |
|
2 | <legend onclick="toggleFieldset(this);"><%= l(:label_date_range) %></legend> | |
|
3 | <div> | |
|
4 | <p> | |
|
5 | <%= label_tag "period_type_list", l(:description_date_range_list), :class => "hidden-for-sighted" %> | |
|
6 | <%= radio_button_tag 'period_type', '1', !@free_period, :onclick => '$("#from,#to").attr("disabled", true);$("#period").removeAttr("disabled");', :id => "period_type_list"%> | |
|
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> | |
|
1 | <div id="query_form_content" class="hide-when-print"> | |
|
2 | <fieldset id="filters" class="collapsible <%= @query.new_record? ? "" : "collapsed" %>"> | |
|
3 | <legend onclick="toggleFieldset(this);"><%= l(:label_filter_plural) %></legend> | |
|
4 | <div style="<%= @query.new_record? ? "" : "display: none;" %>"> | |
|
5 | <%= render :partial => 'queries/filters', :locals => {:query => @query} %> | |
|
6 | </div> | |
|
22 | 7 | </fieldset> |
|
23 | <p class="buttons"> | |
|
8 | </div> | |
|
9 | ||
|
10 | <p class="buttons hide-when-print"> | |
|
24 | 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 | 13 | </p> |
|
27 | 14 | |
|
28 | 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 | 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 | 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 | 21 | :class => (action_name == 'report' ? 'selected' : nil)) %></li> |
|
35 | 22 | </ul> |
|
36 | 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 | 18 | module Redmine |
|
19 | 19 | module Helpers |
|
20 | 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 | 24 | @project = project |
|
25 | 25 | @issue = issue |
|
26 | 26 | |
@@ -30,8 +30,7 module Redmine | |||
|
30 | 30 | @criteria = @criteria[0,3] |
|
31 | 31 | |
|
32 | 32 | @columns = (columns && %w(year month week day).include?(columns)) ? columns : 'month' |
|
33 | @from = from | |
|
34 | @to = to | |
|
33 | @scope = time_entry_scope | |
|
35 | 34 | |
|
36 | 35 | run |
|
37 | 36 | end |
@@ -44,15 +43,9 module Redmine | |||
|
44 | 43 | |
|
45 | 44 | def run |
|
46 | 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 | 46 | time_columns = %w(tyear tmonth tweek spent_on) |
|
54 | 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 | 49 | h = {'hours' => hours} |
|
57 | 50 | (@criteria + time_columns).each_with_index do |name, i| |
|
58 | 51 | h[name] = hash[i] |
@@ -73,15 +66,11 module Redmine | |||
|
73 | 66 | end |
|
74 | 67 | end |
|
75 | 68 | |
|
76 | if @from.nil? | |
|
77 | min = @hours.collect {|row| row['spent_on']}.min | |
|
78 | @from = min ? min.to_date : Date.today | |
|
79 | end | |
|
69 | min = @hours.collect {|row| row['spent_on']}.min | |
|
70 | @from = min ? min.to_date : Date.today | |
|
80 | 71 | |
|
81 | if @to.nil? | |
|
82 | max = @hours.collect {|row| row['spent_on']}.max | |
|
83 | @to = max ? max.to_date : Date.today | |
|
84 | end | |
|
72 | max = @hours.collect {|row| row['spent_on']}.max | |
|
73 | @to = max ? max.to_date : Date.today | |
|
85 | 74 | |
|
86 | 75 | @total_hours = @hours.inject(0) {|s,k| s = s + k['hours'].to_f} |
|
87 | 76 |
@@ -242,7 +242,13 function toggleOperator(field) { | |||
|
242 | 242 | case "!*": |
|
243 | 243 | case "*": |
|
244 | 244 | case "t": |
|
245 | case "ld": | |
|
245 | 246 | case "w": |
|
247 | case "lw": | |
|
248 | case "l2w": | |
|
249 | case "m": | |
|
250 | case "lm": | |
|
251 | case "y": | |
|
246 | 252 | case "o": |
|
247 | 253 | case "c": |
|
248 | 254 | enableValues(field, []); |
@@ -166,10 +166,9 class TimeEntryReportsControllerTest < ActionController::TestCase | |||
|
166 | 166 | assert_equal 'text/csv; header=present', @response.content_type |
|
167 | 167 | lines = @response.body.chomp.split("\n") |
|
168 | 168 | # Headers |
|
169 |
assert_equal 'Project,Member,Activity,2007- |
|
|
170 | lines.first | |
|
169 | assert_equal 'Project,Member,Activity,2007-3,2007-4,Total', lines.first | |
|
171 | 170 | # Total row |
|
172 |
assert_equal 'Total,"","", |
|
|
171 | assert_equal 'Total,"","",154.25,8.65,162.90', lines.last | |
|
173 | 172 | end |
|
174 | 173 | |
|
175 | 174 | def test_report_csv_export |
@@ -180,10 +179,9 class TimeEntryReportsControllerTest < ActionController::TestCase | |||
|
180 | 179 | assert_equal 'text/csv; header=present', @response.content_type |
|
181 | 180 | lines = @response.body.chomp.split("\n") |
|
182 | 181 | # Headers |
|
183 |
assert_equal 'Project,Member,Activity,2007- |
|
|
184 | lines.first | |
|
182 | assert_equal 'Project,Member,Activity,2007-3,2007-4,Total', lines.first | |
|
185 | 183 | # Total row |
|
186 |
assert_equal 'Total,"","", |
|
|
184 | assert_equal 'Total,"","",154.25,8.65,162.90', lines.last | |
|
187 | 185 | end |
|
188 | 186 | |
|
189 | 187 | def test_csv_big_5 |
@@ -430,131 +430,50 class TimelogControllerTest < ActionController::TestCase | |||
|
430 | 430 | assert_equal [1, 3], assigns(:entries).collect(&:project_id).uniq.sort |
|
431 | 431 | assert_not_nil assigns(:total_hours) |
|
432 | 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 | 433 | assert_tag :form, |
|
437 | 434 | :attributes => {:action => "/projects/ecookbook/time_entries", :id => 'query_form'} |
|
438 | 435 | end |
|
439 | 436 | |
|
440 | 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 | 442 | assert_response :success |
|
443 | 443 | assert_template 'index' |
|
444 | 444 | assert_not_nil assigns(:entries) |
|
445 | 445 | assert_equal 3, assigns(:entries).size |
|
446 | 446 | assert_not_nil assigns(:total_hours) |
|
447 | 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 | 448 | assert_tag :form, |
|
451 | 449 | :attributes => {:action => "/projects/ecookbook/time_entries", :id => 'query_form'} |
|
452 | 450 | end |
|
453 | 451 | |
|
454 |
def test_index_at_project_level_with_ |
|
|
455 |
get :index, :project_id => 'ecookbook', : |
|
|
452 | def test_index_at_project_level_with_date_range_using_from_and_to_params | |
|
453 | get :index, :project_id => 'ecookbook', :from => '2007-03-20', :to => '2007-04-30' | |
|
456 | 454 | assert_response :success |
|
457 | 455 | assert_template 'index' |
|
458 | 456 | assert_not_nil assigns(:entries) |
|
457 | assert_equal 3, assigns(:entries).size | |
|
459 | 458 | assert_not_nil assigns(:total_hours) |
|
460 |
assert_equal |
|
|
461 | assert_equal Date.today, assigns(:to) | |
|
459 | assert_equal "12.90", "%.2f" % assigns(:total_hours) | |
|
462 | 460 | assert_tag :form, |
|
463 | 461 | :attributes => {:action => "/projects/ecookbook/time_entries", :id => 'query_form'} |
|
464 | 462 | end |
|
465 | 463 | |
|
466 |
def test_index_ |
|
|
467 |
get :index, :project_id => 'ecookbook', |
|
|
464 | def test_index_at_project_level_with_period | |
|
465 | get :index, :project_id => 'ecookbook', | |
|
466 | :f => ['spent_on'], | |
|
467 | :op => {'spent_on' => '>t-'}, | |
|
468 | :v => {'spent_on' => ['7']} | |
|
468 | 469 | assert_response :success |
|
469 | 470 | assert_template 'index' |
|
471 | assert_not_nil assigns(:entries) | |
|
470 | 472 | assert_not_nil assigns(:total_hours) |
|
471 | assert_equal "4.25", "%.2f" % assigns(:total_hours) | |
|
472 | 473 | assert_tag :form, |
|
473 | 474 | :attributes => {:action => "/projects/ecookbook/time_entries", :id => 'query_form'} |
|
474 | 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 | 477 | def test_index_at_issue_level |
|
559 | 478 | get :index, :issue_id => 1 |
|
560 | 479 | assert_response :success |
@@ -577,11 +496,18 class TimelogControllerTest < ActionController::TestCase | |||
|
577 | 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 | 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 | 503 | assert_response :success |
|
582 | 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 | 511 | assert_response :success |
|
586 | 512 | assert_equal [t3, t1, t2], assigns(:entries) |
|
587 | 513 | end |
General Comments 0
You need to be logged in to leave comments.
Login now