diff --git a/app/controllers/timesheet_controller.rb b/app/controllers/timesheet_controller.rb index 0e94679..d2a9c8c 100644 --- a/app/controllers/timesheet_controller.rb +++ b/app/controllers/timesheet_controller.rb @@ -17,12 +17,11 @@ class TimesheetController < ApplicationController verify :method => :delete, :only => :reset, :render => {:nothing => true, :status => :method_not_allowed } def index - load_filters_from_session + #load_filters_from_session unless @timesheet @timesheet ||= Timesheet.new end @timesheet.allowed_projects = allowed_projects - if @timesheet.allowed_projects.empty? render :action => 'no_projects' return @@ -36,7 +35,7 @@ def report redirect_to :action => 'index' return end - + @timesheet.allowed_projects = allowed_projects if @timesheet.allowed_projects.empty? @@ -51,27 +50,31 @@ def report else @timesheet.projects = @timesheet.allowed_projects end - + call_hook(:plugin_timesheet_controller_report_pre_fetch_time_entries, { :timesheet => @timesheet, :params => params }) - save_filters_to_session(@timesheet) - - @timesheet.fetch_time_entries + #save_filters_to_session(@timesheet) + @timesheet.fetch_time_entries if @timesheet.detailed == "yes" + @timesheet.fetch_time_entries_summary unless @timesheet.detailed == "yes" # Sums @total = { } + @total_non_billable_hours = { } unless @timesheet.sort == :issue @timesheet.time_entries.each do |project,logs| @total[project] = 0 + @total_non_billable_hours[project] = 0 if logs[:logs] logs[:logs].each do |log| @total[project] += log.hours + @total_non_billable_hours[project] += log.non_billable_hours.to_f unless log.non_billable_hours.blank? end end end else @timesheet.time_entries.each do |project, project_data| @total[project] = 0 + @total_non_billable_hours[project] = 0 if project_data[:issues] project_data[:issues].each do |issue, issue_data| @total[project] += issue_data.collect(&:hours).sum @@ -79,12 +82,13 @@ def report end end end - @grand_total = @total.collect{|k,v| v}.inject{|sum,n| sum + n} - + @grand_total_non_billable_hours = @total_non_billable_hours.collect{|k,v| v}.inject{|sum,n| sum + n} + + respond_to do |format| format.html { render :action => 'details', :layout => false if request.xhr? } - format.csv { send_data @timesheet.to_csv, :filename => 'timesheet.csv', :type => "text/csv" } + format.csv { send_data @timesheet.to_csv, :filename => 'timesheet.csv', :type => "text/csv" } end end @@ -97,6 +101,44 @@ def reset clear_filters_from_session redirect_to :action => 'index' end + + def getprojects + custom_field_id = CustomField.find_by_name("Project Type").id + project_type = params[:project_type] + project_status = params[:project_status] + cond = ARCondition.new + cond << ["status =?",project_status] unless project_status == "Both" + if User.current.admin? + if project_type == "Both" + projects = Project.timesheet_order_by_name.find(:all,:conditions => cond.conditions,:order => "name ASC") + else + cond << ["custom_values.custom_field_id=? && custom_values.value=?",custom_field_id,project_type] + projects = Project.timesheet_order_by_name.find(:all,:joins => :custom_values,:conditions => cond.conditions,:order => "name ASC") + end + elsif Setting.plugin_timesheet_plugin['project_status'] == 'all' + if project_type == "Both" + projects = Project.timesheet_order_by_name.timesheet_with_membership(User.current).find(:all,:conditions => cond.conditions,:order => "name ASC") + else + cond << ["custom_values.custom_field_id=? && custom_values.value=?",custom_field_id,project_type] + projects = Project.timesheet_order_by_name.timesheet_with_membership(User.current).find(:all,:joins => :custom_values,:conditions => cond.conditions,:order => "name ASC") + end + else + cond << Project.visible_condition(User.current) + if project_type == "Both" + projects = Project.timesheet_order_by_name.find(:all,:conditions => cond.conditions,:order => "name ASC") + else + cond << ["custom_values.custom_field_id=? && custom_values.value=?",custom_field_id,project_type] + projects = Project.timesheet_order_by_name.find(:all,:joins => :custom_values,:conditions => cond.conditions,:order => "name ASC") + end + end + projStr ="" + projects.each do |project| + projStr << project.id.to_s() + ',' + project.name + "\n" + end + respond_to do |format| + format.text { render :text => projStr } + end + end private def get_list_size @@ -115,7 +157,7 @@ def get_precision end def get_activities - @activities = TimeEntryActivity.all(:conditions => 'parent_id IS NULL') + @activities = TimeEntryActivity.all(:conditions => 'parent_id IS NULL',:order => "name ASC") end def allowed_projects @@ -124,7 +166,7 @@ def allowed_projects elsif Setting.plugin_timesheet_plugin['project_status'] == 'all' Project.timesheet_order_by_name.timesheet_with_membership(User.current) else - Project.timesheet_order_by_name.all(:conditions => Project.visible_by(User.current)) + Project.timesheet_order_by_name.all(:conditions => Project.visible_condition(User.current)) end end diff --git a/app/helpers/timesheet_helper.rb b/app/helpers/timesheet_helper.rb index e108092..105a002 100644 --- a/app/helpers/timesheet_helper.rb +++ b/app/helpers/timesheet_helper.rb @@ -16,7 +16,7 @@ def link_to_csv_export(timesheet) :controller => 'timesheet', :action => 'report', :format => 'csv', - :timesheet => timesheet.to_param + :timesheet => timesheet.to_param, }, :method => 'post', :class => 'icon icon-timesheet') @@ -46,7 +46,8 @@ def displayed_time_entries_for_issue(time_entries) end def project_options(timesheet) - available_projects = timesheet.allowed_projects + #Onload of the page the project type is billable + available_projects = timesheet.filtered_projects(timesheet.project_type.blank? ? "Billable" : timesheet.project_type,timesheet.project_status.blank? ? Project::STATUS_ACTIVE : timesheet.project_status) selected_projects = timesheet.projects.collect(&:id) selected_projects = available_projects.collect(&:id) if selected_projects.blank? diff --git a/app/models/timesheet.rb b/app/models/timesheet.rb index 505cbc6..b53dc53 100644 --- a/app/models/timesheet.rb +++ b/app/models/timesheet.rb @@ -1,5 +1,5 @@ class Timesheet - attr_accessor :date_from, :date_to, :projects, :activities, :users, :allowed_projects, :period, :period_type + attr_accessor :date_from, :date_to, :projects, :activities, :users, :allowed_projects, :period, :period_type,:project_type,:detailed,:project_status # Time entries on the Timesheet in the form of: # project.name => {:logs => [time entries], :users => [users shown in logs] } @@ -12,10 +12,16 @@ class Timesheet # Sort time entries by this field attr_accessor :sort + ValidSortOptions = { :project => 'Project', - :user => 'User', - :issue => 'Issue' + :user => 'User'#, + #:issue => 'Issue' + } + ValidProjectTypes = { + :Billable => 'Billable', + :NonBillable => 'Non Billable', + :Both => 'Both' } ValidPeriodType = { @@ -23,6 +29,13 @@ class Timesheet :default => 1 } + ValidProjectStatuses = { + :Active => Project::STATUS_ACTIVE, + :Archived => Project::STATUS_ARCHIVED, + :Both => "Both" + } + CUSTOM_FIELD = CustomField.find_by_name("Non Billable Hours").id + def initialize(options = { }) self.projects = [ ] self.time_entries = options[:time_entries] || { } @@ -56,6 +69,12 @@ def initialize(options = { }) self.date_from = options[:date_from] || Date.today.to_s self.date_to = options[:date_to] || Date.today.to_s + + self.project_type = options[:project_type] || ValidProjectTypes[:Billable] + + self.detailed = options[:detailed] + + self.project_status = options[:project_status] unless options[:project_status].nil? if options[:period_type] && ValidPeriodType.values.include?(options[:period_type].to_i) self.period_type = options[:period_type].to_i @@ -79,6 +98,20 @@ def fetch_time_entries fetch_time_entries_by_project end end + + def fetch_time_entries_summary + self.time_entries = { } + case self.sort + when :project + fetch_time_entries_by_project_summary + when :user + fetch_time_entries_by_user_summary + when :issue + fetch_time_entries_by_issue + else + fetch_time_entries_by_project_summary + end + end def period=(period) return if self.period_type == Timesheet::ValidPeriodType[:free_period] @@ -122,7 +155,8 @@ def to_param :date_to => date_to, :activities => activities, :users => users, - :sort => sort + :sort => sort, + :detailed => detailed } end @@ -164,10 +198,42 @@ def self.viewable_users } end + def filtered_projects(project_type,project_status) + custom_field_id = CustomField.find_by_name("Project Type").id + cond = ARCondition.new + cond << ["status =?",project_status] unless project_status == "Both" + if User.current.admin? + if project_type == "Both" + projects = Project.timesheet_order_by_name.find(:all,:conditions => cond.conditions,:order => "name ASC") + else + cond << ["custom_values.custom_field_id=? && custom_values.value=?",custom_field_id,project_type] + projects = Project.timesheet_order_by_name.find(:all,:joins => :custom_values,:conditions => cond.conditions,:order => "name ASC") + end + elsif Setting.plugin_timesheet_plugin['project_status'] == 'all' + if project_type == "Both" + projects = Project.timesheet_order_by_name.timesheet_with_membership(User.current).find(:all,:conditions => cond.conditions,:order => "name ASC") + else + cond << ["custom_values.custom_field_id=? && custom_values.value=?",custom_field_id,project_type] + projects = Project.timesheet_order_by_name.timesheet_with_membership(User.current).find(:all,:joins => :custom_values,:conditions => cond.conditions,:order => "name ASC") + end + else + cond << Project.visible_condition(User.current) + if project_type == "Both" + projects = Project.timesheet_order_by_name.find(:all,:conditions => cond.conditions,:order => "name ASC") + else + cond << ["custom_values.custom_field_id=? && custom_values.value=?",custom_field_id,project_type] + projects = Project.timesheet_order_by_name.find(:all,:joins => :custom_values,:conditions => cond.conditions,:order => "name ASC") + end + end + + return projects + end + protected def csv_header - csv_data = [ + if self.detailed == "yes" + csv_data = [ '#', l(:label_date), l(:label_member), @@ -176,14 +242,24 @@ def csv_header l(:label_issue), "#{l(:label_issue)} #{l(:field_subject)}", l(:field_comments), - l(:field_hours) + l(:field_hours), + l(:field_non_billable_hours) ] + else + csv_data = [ + l(:label_member), + l(:label_project), + l(:field_hours), + l(:field_non_billable_hours) + ] + end Redmine::Hook.call_hook(:plugin_timesheet_model_timesheet_csv_header, { :timesheet => self, :csv_data => csv_data}) return csv_data end def time_entry_to_csv(time_entry) - csv_data = [ + if self.detailed == "yes" + csv_data = [ time_entry.id, time_entry.spent_on, time_entry.user.name, @@ -192,8 +268,17 @@ def time_entry_to_csv(time_entry) ("#{time_entry.issue.tracker.name} ##{time_entry.issue.id}" if time_entry.issue), (time_entry.issue.subject if time_entry.issue), time_entry.comments, - time_entry.hours + sprintf('%.2f', time_entry.hours), + time_entry.non_billable_hours.blank? ? nil : sprintf('%.2f', time_entry.non_billable_hours) ] + else + csv_data = [ + time_entry.first_name+" "+time_entry.last_name, + time_entry.project_name, + sprintf('%.2f', time_entry.hours), + time_entry.non_billable_hours.blank? ? nil : sprintf('%.2f', time_entry.non_billable_hours) + ] + end Redmine::Hook.call_hook(:plugin_timesheet_model_timesheet_time_entry_to_csv, { :timesheet => self, :time_entry => time_entry, :csv_data => csv_data}) return csv_data end @@ -240,25 +325,48 @@ def includes Redmine::Hook.call_hook(:plugin_timesheet_model_timesheet_includes, { :timesheet => self, :includes => includes}) return includes end - - private + + private def time_entries_for_all_users(project) return project.time_entries.find(:all, - :conditions => self.conditions(self.users), + :conditions => self.conditions(self.users,"custom_values.custom_field_id=#{CUSTOM_FIELD}"), :include => self.includes, + :joins => :custom_values, + :select => "time_entries.*,custom_values.value as non_billable_hours", :order => "spent_on ASC") end + def hours_summary_for_all_users(project) + return project.time_entries.find(:all, + :conditions => self.conditions(self.users,"custom_values.custom_field_id=#{CUSTOM_FIELD}"), + :joins => [:custom_values,:user,:project], + :select => "sum(time_entries.hours) as hours,time_entries.user_id,sum(custom_values.value) as non_billable_hours,users.firstname as first_name,projects.name as project_name,users.lastname as last_name", + :group => "user_id", + :order => "first_name ASC" + ) + end + def time_entries_for_current_user(project) return project.time_entries.find(:all, - :conditions => self.conditions(User.current.id), + :conditions => self.conditions(User.current.id,"custom_values.custom_field_id=#{CUSTOM_FIELD}"), :include => self.includes, :include => [:activity, :user, {:issue => [:tracker, :assigned_to, :priority]}], + :joins => :custom_values, + :select => "time_entries.*,custom_values.value as non_billable_hours", :order => "spent_on ASC") end + def hours_summary_for_current_user(project) + return project.time_entries.find(:all, + :conditions => self.conditions(User.current.id,"custom_values.custom_field_id=#{CUSTOM_FIELD}"), + :joins => [:custom_values,:user,:project], + :select => "sum(time_entries.hours) as hours,time_entries.user_id,sum(custom_values.value) as non_billable_hours,users.firstname as first_name,projects.name as project_name,users.lastname as last_name", + :group => "user_id", + :order => "first_name ASC") + end + def issue_time_entries_for_all_users(issue) return issue.time_entries.find(:all, :conditions => self.conditions(self.users), @@ -276,15 +384,29 @@ def issue_time_entries_for_current_user(issue) end def time_entries_for_user(user, options={}) - extra_conditions = options.delete(:conditions) + extra_conditions = "custom_values.custom_field_id=#{CUSTOM_FIELD}" return TimeEntry.find(:all, :conditions => self.conditions([user], extra_conditions), :include => self.includes, + :joins => :custom_values, + :select => "time_entries.*,custom_values.value as non_billable_hours", :order => "spent_on ASC" ) end + def hours_summary_for_user(user, options={}) + extra_conditions = "custom_values.custom_field_id=#{CUSTOM_FIELD}" + + return TimeEntry.find(:all, + :conditions => self.conditions([user], extra_conditions), + :joins => [:custom_values,:user,:project], + :select => "sum(time_entries.hours) as hours,time_entries.user_id,time_entries.project_id,sum(custom_values.value) as non_billable_hours,users.firstname as first_name,projects.name as project_name,users.lastname as last_name", + :group => "project_id", + :order => "project_name ASC" + ) + end + def fetch_time_entries_by_project self.projects.each do |project| logs = [] @@ -297,7 +419,7 @@ def fetch_time_entries_by_project # Users with the Role and correct permission can see all time entries logs = time_entries_for_all_users(project) users = logs.collect(&:user).uniq.sort - elsif User.current.allowed_to_on_single_potentially_archived_project?(:view_time_entries, project) + elsif User.current.allowed_to_on_single_potentially_archived_project?(:view_time_entries, project) && self.users.include?(User.current.id) # Users with permission to see their time entries logs = time_entries_for_current_user(project) users = logs.collect(&:user).uniq.sort @@ -305,15 +427,34 @@ def fetch_time_entries_by_project # Rest can see nothing end - # Append the parent project name - if project.parent.nil? - unless logs.empty? + unless logs.empty? self.time_entries[project.name] = { :logs => logs, :users => users } - end + end + end + end + + def fetch_time_entries_by_project_summary + self.projects.each do |project| + logs = [] + users = [] + if User.current.admin? + # Administrators can see all time entries + logs = hours_summary_for_all_users(project) + users = logs.collect(&:user).uniq.sort + elsif User.current.allowed_to_on_single_potentially_archived_project?(:see_project_timesheets, project) + # Users with the Role and correct permission can see all time entries + logs = hours_summary_for_all_users(project) + users = logs.collect(&:user).uniq.sort + elsif User.current.allowed_to_on_single_potentially_archived_project?(:view_time_entries, project) && self.users.include?(User.current.id) + # Users with permission to see their time entries + logs = hours_summary_for_current_user(project) + users = logs.collect(&:user).uniq.sort else - unless logs.empty? - self.time_entries[project.parent.name + ' / ' + project.name] = { :logs => logs, :users => users } - end + # Rest can see nothing + end + + unless logs.empty? + self.time_entries[project.name] = { :logs => logs, :users => users } end end end @@ -342,6 +483,30 @@ def fetch_time_entries_by_user end end + def fetch_time_entries_by_user_summary + self.users.each do |user_id| + logs = [] + if User.current.admin? + # Administrators can see all time entries + logs = hours_summary_for_user(user_id) + elsif User.current.id == user_id + # Users can see their own their time entries + logs = hours_summary_for_user(user_id) + elsif User.current.allowed_to_on_single_potentially_archived_project?(:see_project_timesheets, nil, :global => true) + # User can see project timesheets in at least once place, so + # fetch the user timelogs for those projects + logs = hours_summary_for_user(user_id, :conditions => Project.allowed_to_condition(User.current, :see_project_timesheets)) + else + # Rest can see nothing + end + + unless logs.empty? + user = User.find_by_id(user_id) + self.time_entries[user.name] = { :logs => logs } unless user.nil? + end + end + end + # project => { :users => [users shown in logs], # :issues => # { issue => {:logs => [time entries], diff --git a/app/views/timesheet/_form.rhtml b/app/views/timesheet/_form.rhtml index 923e458..bf42a8f 100644 --- a/app/views/timesheet/_form.rhtml +++ b/app/views/timesheet/_form.rhtml @@ -1,3 +1,33 @@ + +
<% form_for :timesheet, :url =>{:action => 'report'} do |f| %> @@ -11,20 +41,27 @@ <%= radio_button_tag 'timesheet[period_type]', '2', @timesheet.period_type == Timesheet::ValidPeriodType[:free_period] %> -
+ <%= f.text_field "date_from", :size => 10 %><%= calendar_for('timesheet_date_from') %>
-
<%= f.text_field "date_to", :size => 10 %><%= calendar_for('timesheet_date_to') %>

-

+


<%= select_tag("timesheet[sort]", options_for_select(Timesheet::ValidSortOptions.invert, @timesheet.sort)) %> -

+

+
+ <%= select_tag "timesheet[project_type]",options_for_select(Timesheet::ValidProjectTypes,@timesheet.project_type),:onChange => 'populate_projects_dropdown()' %> + +

+ +
+ <%= select_tag "timesheet[project_status]",options_for_select(Timesheet::ValidProjectStatuses,@timesheet.project_status.blank? ? Project::STATUS_ACTIVE : (@timesheet.project_status.to_i == 0 ? "Both" : @timesheet.project_status.to_i)),:onChange => 'populate_projects_dropdown()' %> +


<%= select_tag 'timesheet[projects][]', project_options(@timesheet), { :multiple => true, :size => @list_size} %> @@ -41,6 +78,11 @@ <%= select_tag 'timesheet[users][]', user_options(@timesheet), { :multiple => true, :size => @list_size} %>

+

+ <%= check_box_tag "timesheet[detailed]",'yes',@timesheet.detailed == "yes" %> + +

+ <%# TODO: Typo on hook %> <%= call_hook(:plugin_timesheet_view_timesheet_form, { :timesheet => @timesheet, :params => params, :list_size => @list_size }) %> <%= call_hook(:plugin_timesheet_views_timesheet_form, { :timesheet => @timesheet, :params => params, :list_size => @list_size }) %> diff --git a/app/views/timesheet/_time_entry.rhtml b/app/views/timesheet/_time_entry.rhtml index abebd40..4f774d1 100644 --- a/app/views/timesheet/_time_entry.rhtml +++ b/app/views/timesheet/_time_entry.rhtml @@ -16,7 +16,8 @@ <% end %> <%=h time_entry.comments %> - <%= number_with_precision(time_entry.hours, @precision) %> + <%= number_with_precision(time_entry.hours, @precision) %> + <%= number_with_precision(time_entry.non_billable_hours, @precision) %> <%= Redmine::Hook.call_hook(:plugin_timesheet_views_timesheet_time_entry, {:time_entry => time_entry, :precision => @precision }) %> <% if time_entry.editable_by?(User.current) -%> diff --git a/app/views/timesheet/_time_entry_summary.rhtml b/app/views/timesheet/_time_entry_summary.rhtml new file mode 100644 index 0000000..2354bd6 --- /dev/null +++ b/app/views/timesheet/_time_entry_summary.rhtml @@ -0,0 +1,10 @@ +<%# TODO: Typo on hook %> + hascontextmenu <%#= call_hook(:plugin_timesheet_view_timesheets_time_entry_row_class, {:time_entry => time_entry }) %> <%#= call_hook(:plugin_timesheet_views_timesheets_time_entry_row_class, {:time_entry => time_entry }) %>"> + + <%= time_entry_summary.first_name+" "+time_entry_summary.last_name %> + <%= time_entry_summary.project_name %> + <%= number_with_precision(time_entry_summary.hours, @precision) %> + <%= number_with_precision(time_entry_summary.non_billable_hours, @precision) %> + <%= Redmine::Hook.call_hook(:plugin_timesheet_views_timesheet_time_entry_summary, {:time_entry => time_entry_summary, :precision => @precision }) %> + + diff --git a/app/views/timesheet/_timesheet_group.rhtml b/app/views/timesheet/_timesheet_group.rhtml index 626e269..fb1de9c 100644 --- a/app/views/timesheet/_timesheet_group.rhtml +++ b/app/views/timesheet/_timesheet_group.rhtml @@ -6,16 +6,27 @@ <%= l(:label_date) %> <%= l(:label_member) %> - <%= l(:label_activity) %> - <%= l(:label_project) %> + <%= l(:label_activity) %> + <%= l(:label_project) %> <%= l(:label_issue) %> - <%= l(:field_comments) %> - <%= l(:field_hours) %> + <%= l(:field_comments) %> + <%= l(:field_hours) %> + <%= l(:field_non_billable_hours) %> <%= Redmine::Hook.call_hook(:plugin_timesheet_views_timesheet_group_header, { }) %> - +   <%= render :partial => "time_entry", :collection => entry[:logs] %> + <% if entry[:logs].count > 1 %> + +   + Sub Total + <%= h number_with_precision(@total[name], @precision)%> + <%= h number_with_precision(@total_non_billable_hours[name], @precision) %> +   +   + + <% end %>
diff --git a/app/views/timesheet/_timesheet_group_summary.rhtml b/app/views/timesheet/_timesheet_group_summary.rhtml new file mode 100644 index 0000000..2a3ddc7 --- /dev/null +++ b/app/views/timesheet/_timesheet_group_summary.rhtml @@ -0,0 +1,16 @@ + + + + + <%= render :partial => "time_entry_summary", :collection => entry[:logs] %> + <% if entry[:logs].count > 1 %> + + + + + + <% end %> + + +
Sub Total<%= h number_with_precision(@total[name], @precision)%><%= h number_with_precision(@total_non_billable_hours[name], @precision) %>
+
diff --git a/app/views/timesheet/_timesheet_summary_header.rhtml b/app/views/timesheet/_timesheet_summary_header.rhtml new file mode 100644 index 0000000..1c92794 --- /dev/null +++ b/app/views/timesheet/_timesheet_summary_header.rhtml @@ -0,0 +1,8 @@ + + + + + + + +
<%= l(:label_member) %><%= l(:label_project) %><%= l(:field_hours) %><%= l(:field_non_billable_hours) %>
diff --git a/app/views/timesheet/report.rhtml b/app/views/timesheet/report.rhtml index 8979145..568fdb0 100644 --- a/app/views/timesheet/report.rhtml +++ b/app/views/timesheet/report.rhtml @@ -8,30 +8,55 @@ <%= render :partial => 'form' %> <%= call_hook(:plugin_timesheet_views_timesheets_report_before_time_entries, { :timesheet => @timesheet }) %> - -<% form_tag({}, { :id => 'time_entries'}) do -%> <% if @timesheet.time_entries.length > 0 %> -

<%= l(:label_spent_time) %> (<%= h(number_with_precision(@grand_total, @precision)) -%> <%= h(l(:field_hours)) -%>)

- -<% @timesheet.time_entries.each do |entryname,entry| - case @timesheet.sort - when :user %> -

<%= h entryname -%> (<%= h number_with_precision(@total[entryname], @precision) %> <%= h(l(:field_hours)) -%>)

- <%= render :partial => 'timesheet_group', :locals => {:entry => entry, :name => entryname, :total => @total[entryname] } %> -<% when :issue %> -

<%= h entryname -%> (<%= h number_with_precision(@total[entryname], @precision) %> <%= h(l(:field_hours)) -%>)

- <%= render :partial => 'by_issue', :locals => {:entry => entry, :name => entryname, :total => 0 } %> -<% else %> -<%# Default to :project %> -

<%= h entryname -%> (<%= h number_with_precision(@total[entryname], @precision) %> <%= h(l(:field_hours)) -%>) <%= showing_users(entry[:users]) %>

- <%= render :partial => 'timesheet_group', :locals => {:entry => entry, :name => entryname, :total => @total[entryname] } %> - -<% end -end # each -end # length -end # form_tag --%> - + <% if @timesheet.detailed == "yes" %> + <% form_tag({}, { :id => 'time_entries'}) do -%> + <% @timesheet.time_entries.sort{ |a,b| a.to_s.downcase <=> b.to_s.downcase }.each do |entryname,entry| + case @timesheet.sort + when :user %> +

<%= h entryname -%>

+ <%= render :partial => 'timesheet_group', :locals => {:entry => entry, :name => entryname, :total => @total[entryname]} %> + <% when :issue %> + <%= render :partial => 'by_issue', :locals => {:entry => entry, :name => entryname, :total => 0 } %> + <% else %> + <%# Default to :project %> +

<%= h entryname -%> <%= showing_users(entry[:users]) %>

+ <%= render :partial => 'timesheet_group', :locals => {:entry => entry, :name => entryname, :total => @total[entryname]} %> + <% end %> + <% end %> + <% end %> + + + + + + + + +
 Grand Total<%= h(number_with_precision(@grand_total, @precision)) -%><%= h(number_with_precision(@grand_total_non_billable_hours, @precision)) -%> 
+ <% else %> + <%= render :partial => 'timesheet_summary_header' %> + <% @timesheet.time_entries.sort{ |a,b| a.to_s.downcase <=> b.to_s.downcase }.each do |entryname,entry| + case @timesheet.sort + when :user %> + <%= render :partial => 'timesheet_group_summary', :locals => {:entry => entry, :name => entryname } %> + <% when :issue %> +

<%= h entryname -%> (<%= h number_with_precision(@total[entryname], @precision) %> <%= h(l(:field_hours)) -%>)

+ <%= render :partial => 'by_issue', :locals => {:entry => entry, :name => entryname, :total => 0 } %> + <% else %> + <%# Default to :project %> + <%= render :partial => 'timesheet_group_summary', :locals => {:entry => entry,:name => entryname} %> + <% end %> + <% end %> + + + + + + +
Grand Total<%= h(number_with_precision(@grand_total, @precision)) -%><%= h(number_with_precision(@grand_total_non_billable_hours, @precision)) -%>
+ <% end %> +<% end %> <% content_for(:header_tags) do %> <%= javascript_include_tag 'context_menu' %> <%= stylesheet_link_tag 'context_menu' %> diff --git a/config/locales/cs.yml b/config/locales/cs.yml index 5c1d8da..3c58c0a 100644 --- a/config/locales/cs.yml +++ b/config/locales/cs.yml @@ -5,6 +5,3 @@ cs: timesheet_project_label: Projekt timesheet_activities_label: Aktivita timesheet_users_label: Uživatelé - timesheet_showing_users: 'zobrazuji časy pro: ' - timesheet_permalink: '(Permalink k tomuto přehledu práce)' - timesheet_group_by: Seskupit dle diff --git a/config/routes.rb b/config/routes.rb index 8e78a2c..fee41b3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,6 +1,4 @@ ActionController::Routing::Routes.draw do |map| - map.connect 'timesheet/index', :controller => 'timesheet', :action => 'index' - map.connect 'timesheet/context_menu', :controller => 'timesheet', :action => 'context_menu' map.connect 'timesheet/report.:format', :controller => 'timesheet', :action => 'report' map.connect 'timesheet/reset', :controller => 'timesheet', :action => 'reset', :conditions => { :method => :delete } end diff --git a/lang/cs.yml b/lang/cs.yml index d9b634b..ab3c9ea 100644 --- a/lang/cs.yml +++ b/lang/cs.yml @@ -4,6 +4,3 @@ timesheet_date_to_label: do timesheet_project_label: Projekt timesheet_activities_label: Aktivita timesheet_users_label: Uživatelé -timesheet_showing_users: 'zobrazuji časy pro: ' -timesheet_permalink: '(Permalink k tomuto přehledu práce)' -timesheet_group_by: Seskupit dle