@@ -22,7 +22,8 class TimelogController < ApplicationController | |||||
22 | before_filter :find_time_entries, :only => [:bulk_edit, :bulk_update, :destroy] |
|
22 | before_filter :find_time_entries, :only => [:bulk_edit, :bulk_update, :destroy] | |
23 | before_filter :authorize, :only => [:show, :edit, :update, :bulk_edit, :bulk_update, :destroy] |
|
23 | before_filter :authorize, :only => [:show, :edit, :update, :bulk_edit, :bulk_update, :destroy] | |
24 |
|
24 | |||
25 |
before_filter :find_optional_ |
|
25 | before_filter :find_optional_issue, :only => [:new, :create] | |
|
26 | before_filter :find_optional_project, :only => [:index, :report] | |||
26 | before_filter :authorize_global, :only => [:new, :create, :index, :report] |
|
27 | before_filter :authorize_global, :only => [:new, :create, :index, :report] | |
27 |
|
28 | |||
28 | accept_rss_auth :index |
|
29 | accept_rss_auth :index | |
@@ -251,11 +252,17 private | |||||
251 | end |
|
252 | end | |
252 | end |
|
253 | end | |
253 |
|
254 | |||
254 |
def find_optional_ |
|
255 | def find_optional_issue | |
255 | if params[:issue_id].present? |
|
256 | if params[:issue_id].present? | |
256 | @issue = Issue.find(params[:issue_id]) |
|
257 | @issue = Issue.find(params[:issue_id]) | |
257 | @project = @issue.project |
|
258 | @project = @issue.project | |
258 | elsif params[:project_id].present? |
|
259 | else | |
|
260 | find_optional_project | |||
|
261 | end | |||
|
262 | end | |||
|
263 | ||||
|
264 | def find_optional_project | |||
|
265 | if params[:project_id].present? | |||
259 | @project = Project.find(params[:project_id]) |
|
266 | @project = Project.find(params[:project_id]) | |
260 | end |
|
267 | end | |
261 | rescue ActiveRecord::RecordNotFound |
|
268 | rescue ActiveRecord::RecordNotFound | |
@@ -264,11 +271,7 private | |||||
264 |
|
271 | |||
265 | # Returns the TimeEntry scope for index and report actions |
|
272 | # Returns the TimeEntry scope for index and report actions | |
266 | def time_entry_scope(options={}) |
|
273 | def time_entry_scope(options={}) | |
267 |
|
|
274 | @query.results_scope(options) | |
268 | if @issue |
|
|||
269 | scope = scope.on_issue(@issue) |
|
|||
270 | end |
|
|||
271 | scope |
|
|||
272 | end |
|
275 | end | |
273 |
|
276 | |||
274 | def retrieve_time_entry_query |
|
277 | def retrieve_time_entry_query |
@@ -135,11 +135,13 module IssuesHelper | |||||
135 |
|
135 | |||
136 | def issue_spent_hours_details(issue) |
|
136 | def issue_spent_hours_details(issue) | |
137 | if issue.total_spent_hours > 0 |
|
137 | if issue.total_spent_hours > 0 | |
|
138 | path = project_time_entries_path(issue.project, :issue_id => "~#{issue.id}") | |||
|
139 | ||||
138 | if issue.total_spent_hours == issue.spent_hours |
|
140 | if issue.total_spent_hours == issue.spent_hours | |
139 |
link_to(l_hours_short(issue.spent_hours), |
|
141 | link_to(l_hours_short(issue.spent_hours), path) | |
140 | else |
|
142 | else | |
141 | s = issue.spent_hours > 0 ? l_hours_short(issue.spent_hours) : "" |
|
143 | s = issue.spent_hours > 0 ? l_hours_short(issue.spent_hours) : "" | |
142 |
s << " (#{l(:label_total)}: #{link_to l_hours_short(issue.total_spent_hours), |
|
144 | s << " (#{l(:label_total)}: #{link_to l_hours_short(issue.total_spent_hours), path})" | |
143 | s.html_safe |
|
145 | s.html_safe | |
144 | end |
|
146 | end | |
145 | end |
|
147 | end |
@@ -24,8 +24,10 module QueriesHelper | |||||
24 | ungrouped = [] |
|
24 | ungrouped = [] | |
25 | grouped = {} |
|
25 | grouped = {} | |
26 | query.available_filters.map do |field, field_options| |
|
26 | query.available_filters.map do |field, field_options| | |
27 | if [:tree, :relation].include?(field_options[:type]) |
|
27 | if field_options[:type] == :relation | |
28 | group = :label_relations |
|
28 | group = :label_relations | |
|
29 | elsif field_options[:type] == :tree | |||
|
30 | group = query.is_a?(IssueQuery) ? :label_relations : nil | |||
29 | elsif field =~ /^(.+)\./ |
|
31 | elsif field =~ /^(.+)\./ | |
30 | # association filters |
|
32 | # association filters | |
31 | group = "field_#{$1}" |
|
33 | group = "field_#{$1}" |
@@ -54,9 +54,7 module RoutesHelper | |||||
54 | end |
|
54 | end | |
55 |
|
55 | |||
56 | def _time_entries_path(project, issue, *args) |
|
56 | def _time_entries_path(project, issue, *args) | |
57 |
if |
|
57 | if project | |
58 | issue_time_entries_path(issue, *args) |
|
|||
59 | elsif project |
|
|||
60 | project_time_entries_path(project, *args) |
|
58 | project_time_entries_path(project, *args) | |
61 | else |
|
59 | else | |
62 | time_entries_path(*args) |
|
60 | time_entries_path(*args) | |
@@ -64,9 +62,7 module RoutesHelper | |||||
64 | end |
|
62 | end | |
65 |
|
63 | |||
66 | def _report_time_entries_path(project, issue, *args) |
|
64 | def _report_time_entries_path(project, issue, *args) | |
67 |
if |
|
65 | if project | |
68 | report_issue_time_entries_path(issue, *args) |
|
|||
69 | elsif project |
|
|||
70 | report_project_time_entries_path(project, *args) |
|
66 | report_project_time_entries_path(project, *args) | |
71 | else |
|
67 | else | |
72 | report_time_entries_path(*args) |
|
68 | report_time_entries_path(*args) |
@@ -20,20 +20,6 | |||||
20 | module TimelogHelper |
|
20 | module TimelogHelper | |
21 | include ApplicationHelper |
|
21 | include ApplicationHelper | |
22 |
|
22 | |||
23 | def render_timelog_breadcrumb |
|
|||
24 | links = [] |
|
|||
25 | links << link_to(l(:label_project_all), {:project_id => nil, :issue_id => nil}) |
|
|||
26 | links << link_to(h(@project), {:project_id => @project, :issue_id => nil}) if @project |
|
|||
27 | if @issue |
|
|||
28 | if @issue.visible? |
|
|||
29 | links << link_to_issue(@issue, :subject => false) |
|
|||
30 | else |
|
|||
31 | links << "##{@issue.id}" |
|
|||
32 | end |
|
|||
33 | end |
|
|||
34 | breadcrumb links |
|
|||
35 | end |
|
|||
36 |
|
||||
37 | # Returns a collection of activities for a select field. time_entry |
|
23 | # Returns a collection of activities for a select field. time_entry | |
38 | # is optional and will be used to check if the selected TimeEntryActivity |
|
24 | # is optional and will be used to check if the selected TimeEntryActivity | |
39 | # is active. |
|
25 | # is active. |
@@ -460,7 +460,7 class Query < ActiveRecord::Base | |||||
460 | next unless expression =~ /^#{Regexp.escape(operator)}(.*)$/ |
|
460 | next unless expression =~ /^#{Regexp.escape(operator)}(.*)$/ | |
461 | values = $1 |
|
461 | values = $1 | |
462 | add_filter field, operator, values.present? ? values.split('|') : [''] |
|
462 | add_filter field, operator, values.present? ? values.split('|') : [''] | |
463 | end || add_filter(field, '=', expression.split('|')) |
|
463 | end || add_filter(field, '=', expression.to_s.split('|')) | |
464 | end |
|
464 | end | |
465 |
|
465 | |||
466 | # Add multiple filters using +add_filter+ |
|
466 | # Add multiple filters using +add_filter+ |
@@ -67,6 +67,9 class TimeEntryQuery < Query | |||||
67 | ) unless project_values.empty? |
|
67 | ) unless project_values.empty? | |
68 | end |
|
68 | end | |
69 | end |
|
69 | end | |
|
70 | ||||
|
71 | add_available_filter("issue_id", :type => :tree, :label => :label_issue) | |||
|
72 | ||||
70 | principals.uniq! |
|
73 | principals.uniq! | |
71 | principals.sort! |
|
74 | principals.sort! | |
72 | users = principals.select {|p| p.is_a?(User)} |
|
75 | users = principals.select {|p| p.is_a?(User)} | |
@@ -114,6 +117,24 class TimeEntryQuery < Query | |||||
114 | includes(:activity). |
|
117 | includes(:activity). | |
115 | references(:activity) |
|
118 | references(:activity) | |
116 | end |
|
119 | end | |
|
120 | ||||
|
121 | def sql_for_issue_id_field(field, operator, value) | |||
|
122 | case operator | |||
|
123 | when "=" | |||
|
124 | "#{TimeEntry.table_name}.issue_id = #{value.first.to_i}" | |||
|
125 | when "~" | |||
|
126 | issue = Issue.where(:id => value.first.to_i).first | |||
|
127 | if issue && (issue_ids = issue.self_and_descendants.pluck(:id)).any? | |||
|
128 | "#{TimeEntry.table_name}.issue_id IN (#{issue_ids.join(',')})" | |||
|
129 | else | |||
|
130 | "1=0" | |||
|
131 | end | |||
|
132 | when "!*" | |||
|
133 | "#{TimeEntry.table_name}.issue_id IS NULL" | |||
|
134 | when "*" | |||
|
135 | "#{TimeEntry.table_name}.issue_id IS NOT NULL" | |||
|
136 | end | |||
|
137 | end | |||
117 |
|
138 | |||
118 | def sql_for_activity_id_field(field, operator, value) |
|
139 | def sql_for_activity_id_field(field, operator, value) | |
119 | condition_on_id = sql_for_field(field, operator, value, Enumeration.table_name, 'id') |
|
140 | condition_on_id = sql_for_field(field, operator, value, Enumeration.table_name, 'id') |
@@ -41,11 +41,11 | |||||
41 | </div> |
|
41 | </div> | |
42 |
|
42 | |||
43 | <div class="tabs hide-when-print"> |
|
43 | <div class="tabs hide-when-print"> | |
44 | <% query_params = params.slice(:f, :op, :v, :sort, :query_id) %> |
|
44 | <% query_params = request.query_parameters %> | |
45 | <ul> |
|
45 | <ul> | |
46 |
<li><%= link_to(l(:label_details), _time_entries_path(@project, |
|
46 | <li><%= link_to(l(:label_details), _time_entries_path(@project, nil, :params => query_params), | |
47 | :class => (action_name == 'index' ? 'selected' : nil)) %></li> |
|
47 | :class => (action_name == 'index' ? 'selected' : nil)) %></li> | |
48 |
<li><%= link_to(l(:label_report), _report_time_entries_path(@project, |
|
48 | <li><%= link_to(l(:label_report), _report_time_entries_path(@project, nil, :params => query_params), | |
49 | :class => (action_name == 'report' ? 'selected' : nil)) %></li> |
|
49 | :class => (action_name == 'report' ? 'selected' : nil)) %></li> | |
50 | </ul> |
|
50 | </ul> | |
51 | </div> |
|
51 | </div> |
@@ -4,11 +4,9 | |||||
4 | :class => 'icon icon-time-add' if User.current.allowed_to?(:log_time, @project, :global => true) %> |
|
4 | :class => 'icon icon-time-add' if User.current.allowed_to?(:log_time, @project, :global => true) %> | |
5 | </div> |
|
5 | </div> | |
6 |
|
6 | |||
7 | <%= render_timelog_breadcrumb %> |
|
|||
8 |
|
||||
9 | <h2><%= @query.new_record? ? l(:label_spent_time) : @query.name %></h2> |
|
7 | <h2><%= @query.new_record? ? l(:label_spent_time) : @query.name %></h2> | |
10 |
|
8 | |||
11 |
<%= form_tag( |
|
9 | <%= form_tag(_time_entries_path(@project, nil), :method => :get, :id => 'query_form') do %> | |
12 | <%= render :partial => 'date_range' %> |
|
10 | <%= render :partial => 'date_range' %> | |
13 | <% end %> |
|
11 | <% end %> | |
14 |
|
12 |
@@ -4,11 +4,9 | |||||
4 | :class => 'icon icon-time-add' if User.current.allowed_to?(:log_time, @project, :global => true) %> |
|
4 | :class => 'icon icon-time-add' if User.current.allowed_to?(:log_time, @project, :global => true) %> | |
5 | </div> |
|
5 | </div> | |
6 |
|
6 | |||
7 | <%= render_timelog_breadcrumb %> |
|
|||
8 |
|
||||
9 | <h2><%= @query.new_record? ? l(:label_spent_time) : @query.name %></h2> |
|
7 | <h2><%= @query.new_record? ? l(:label_spent_time) : @query.name %></h2> | |
10 |
|
8 | |||
11 |
<%= form_tag( |
|
9 | <%= form_tag(_report_time_entries_path(@project, nil), :method => :get, :id => 'query_form') do %> | |
12 | <% @report.criteria.each do |criterion| %> |
|
10 | <% @report.criteria.each do |criterion| %> | |
13 | <%= hidden_field_tag 'criteria[]', criterion, :id => nil %> |
|
11 | <%= hidden_field_tag 'criteria[]', criterion, :id => nil %> | |
14 | <% end %> |
|
12 | <% end %> |
@@ -188,11 +188,7 Rails.application.routes.draw do | |||||
188 | match 'bulk_edit', :via => [:get, :post] |
|
188 | match 'bulk_edit', :via => [:get, :post] | |
189 | post 'bulk_update' |
|
189 | post 'bulk_update' | |
190 | end |
|
190 | end | |
191 |
resources :time_entries, :controller => 'timelog', : |
|
191 | resources :time_entries, :controller => 'timelog', :only => [:new, :create] | |
192 | collection do |
|
|||
193 | get 'report' |
|
|||
194 | end |
|
|||
195 | end |
|
|||
196 | shallow do |
|
192 | shallow do | |
197 | resources :relations, :controller => 'issue_relations', :only => [:index, :show, :create, :destroy] |
|
193 | resources :relations, :controller => 'issue_relations', :only => [:index, :show, :create, :destroy] | |
198 | end |
|
194 | end |
@@ -128,15 +128,6 class TimeEntryReportsControllerTest < ActionController::TestCase | |||||
128 | assert_equal "4.25", "%.2f" % assigns(:report).total_hours |
|
128 | assert_equal "4.25", "%.2f" % assigns(:report).total_hours | |
129 | end |
|
129 | end | |
130 |
|
130 | |||
131 | def test_report_at_issue_level |
|
|||
132 | get :report, :issue_id => 1, :columns => 'month', :from => "2007-01-01", :to => "2007-12-31", :criteria => ["user", "activity"] |
|
|||
133 | assert_response :success |
|
|||
134 | assert_template 'report' |
|
|||
135 | assert_not_nil assigns(:report) |
|
|||
136 | assert_equal "154.25", "%.2f" % assigns(:report).total_hours |
|
|||
137 | assert_select 'form#query_form[action=?]', '/issues/1/time_entries/report' |
|
|||
138 | end |
|
|||
139 |
|
||||
140 | def test_report_by_week_should_use_commercial_year |
|
131 | def test_report_by_week_should_use_commercial_year | |
141 | TimeEntry.delete_all |
|
132 | TimeEntry.delete_all | |
142 | TimeEntry.generate!(:hours => '2', :spent_on => '2009-12-25') # 2009-52 |
|
133 | TimeEntry.generate!(:hours => '2', :spent_on => '2009-12-25') # 2009-52 |
@@ -676,20 +676,6 class TimelogControllerTest < ActionController::TestCase | |||||
676 | assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries' |
|
676 | assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries' | |
677 | end |
|
677 | end | |
678 |
|
678 | |||
679 | def test_index_at_issue_level |
|
|||
680 | get :index, :issue_id => 1 |
|
|||
681 | assert_response :success |
|
|||
682 | assert_template 'index' |
|
|||
683 | assert_not_nil assigns(:entries) |
|
|||
684 | assert_equal 2, assigns(:entries).size |
|
|||
685 | assert_not_nil assigns(:total_hours) |
|
|||
686 | assert_equal 154.25, assigns(:total_hours) |
|
|||
687 | # display all time |
|
|||
688 | assert_nil assigns(:from) |
|
|||
689 | assert_nil assigns(:to) |
|
|||
690 | assert_select 'form#query_form[action=?]', '/issues/1/time_entries' |
|
|||
691 | end |
|
|||
692 |
|
||||
693 | def test_index_should_sort_by_spent_on_and_created_on |
|
679 | def test_index_should_sort_by_spent_on_and_created_on | |
694 | t1 = TimeEntry.create!(:user => User.find(1), :project => Project.find(1), :hours => 1, :spent_on => '2012-06-16', :created_on => '2012-06-16 20:00:00', :activity_id => 10) |
|
680 | t1 = TimeEntry.create!(:user => User.find(1), :project => Project.find(1), :hours => 1, :spent_on => '2012-06-16', :created_on => '2012-06-16 20:00:00', :activity_id => 10) | |
695 | 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) |
|
681 | 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) | |
@@ -809,15 +795,6 class TimelogControllerTest < ActionController::TestCase | |||||
809 | end |
|
795 | end | |
810 | end |
|
796 | end | |
811 |
|
797 | |||
812 | def test_index_at_issue_level_should_include_csv_export_dialog |
|
|||
813 | get :index, :issue_id => 3 |
|
|||
814 | assert_response :success |
|
|||
815 |
|
||||
816 | assert_select '#csv-export-options' do |
|
|||
817 | assert_select 'form[action=?][method=get]', '/issues/3/time_entries.csv' |
|
|||
818 | end |
|
|||
819 | end |
|
|||
820 |
|
||||
821 | def test_index_csv_all_projects |
|
798 | def test_index_csv_all_projects | |
822 | with_settings :date_format => '%m/%d/%Y' do |
|
799 | with_settings :date_format => '%m/%d/%Y' do | |
823 | get :index, :format => 'csv' |
|
800 | get :index, :format => 'csv' |
@@ -40,10 +40,7 class RoutingTimelogsTest < Redmine::RoutingTest | |||||
40 | end |
|
40 | end | |
41 |
|
41 | |||
42 | def test_timelogs_scoped_under_issues |
|
42 | def test_timelogs_scoped_under_issues | |
43 |
should_route 'GET /issues/234/time_entries' => 'timelog# |
|
43 | should_route 'GET /issues/234/time_entries/new' => 'timelog#new', :issue_id => '234' | |
44 | should_route 'GET /issues/234/time_entries.csv' => 'timelog#index', :issue_id => '234', :format => 'csv' |
|
|||
45 | should_route 'GET /issues/234/time_entries.atom' => 'timelog#index', :issue_id => '234', :format => 'atom' |
|
|||
46 | should_route 'GET /issues/234/time_entries/new' => 'timelog#new', :issue_id => '234' |
|
|||
47 | should_route 'POST /issues/234/time_entries' => 'timelog#create', :issue_id => '234' |
|
44 | should_route 'POST /issues/234/time_entries' => 'timelog#create', :issue_id => '234' | |
48 | end |
|
45 | end | |
49 |
|
46 | |||
@@ -53,9 +50,6 class RoutingTimelogsTest < Redmine::RoutingTest | |||||
53 |
|
50 | |||
54 | should_route 'GET /projects/foo/time_entries/report' => 'timelog#report', :project_id => 'foo' |
|
51 | should_route 'GET /projects/foo/time_entries/report' => 'timelog#report', :project_id => 'foo' | |
55 | should_route 'GET /projects/foo/time_entries/report.csv' => 'timelog#report', :project_id => 'foo', :format => 'csv' |
|
52 | should_route 'GET /projects/foo/time_entries/report.csv' => 'timelog#report', :project_id => 'foo', :format => 'csv' | |
56 |
|
||||
57 | should_route 'GET /issues/234/time_entries/report' => 'timelog#report', :issue_id => '234' |
|
|||
58 | should_route 'GET /issues/234/time_entries/report.csv' => 'timelog#report', :issue_id => '234', :format => 'csv' |
|
|||
59 | end |
|
53 | end | |
60 |
|
54 | |||
61 | def test_timelogs_bulk_edit |
|
55 | def test_timelogs_bulk_edit |
@@ -26,15 +26,11 class RoutesHelperTest < ActionView::TestCase | |||||
26 |
|
26 | |||
27 | def test_time_entries_path |
|
27 | def test_time_entries_path | |
28 | assert_equal '/projects/ecookbook/time_entries', _time_entries_path(Project.find(1), nil) |
|
28 | assert_equal '/projects/ecookbook/time_entries', _time_entries_path(Project.find(1), nil) | |
29 | assert_equal '/issues/1/time_entries', _time_entries_path(Project.find(1), Issue.find(1)) |
|
|||
30 | assert_equal '/issues/1/time_entries', _time_entries_path(nil, Issue.find(1)) |
|
|||
31 | assert_equal '/time_entries', _time_entries_path(nil, nil) |
|
29 | assert_equal '/time_entries', _time_entries_path(nil, nil) | |
32 | end |
|
30 | end | |
33 |
|
31 | |||
34 | def test_report_time_entries_path |
|
32 | def test_report_time_entries_path | |
35 | assert_equal '/projects/ecookbook/time_entries/report', _report_time_entries_path(Project.find(1), nil) |
|
33 | assert_equal '/projects/ecookbook/time_entries/report', _report_time_entries_path(Project.find(1), nil) | |
36 | assert_equal '/issues/1/time_entries/report', _report_time_entries_path(Project.find(1), Issue.find(1)) |
|
|||
37 | assert_equal '/issues/1/time_entries/report', _report_time_entries_path(nil, Issue.find(1)) |
|
|||
38 | assert_equal '/time_entries/report', _report_time_entries_path(nil, nil) |
|
34 | assert_equal '/time_entries/report', _report_time_entries_path(nil, nil) | |
39 | end |
|
35 | end | |
40 |
|
36 |
General Comments 0
You need to be logged in to leave comments.
Login now