Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add custom fields support #1

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 12 additions & 10 deletions app/controllers/timesheet_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ class TimesheetController < ApplicationController
helper :issues
include ApplicationHelper
helper :timelog
helper :custom_fields
include CustomFieldsHelper

SessionKey = 'timesheet_filter'

Expand All @@ -36,19 +38,19 @@ def report
redirect_to :action => 'index'
return
end

@timesheet.allowed_projects = allowed_projects

if @timesheet.allowed_projects.empty?
render :action => 'no_projects'
return
end

if !params[:timesheet][:projects].blank?
@timesheet.projects = @timesheet.allowed_projects.find_all { |project|
@timesheet.projects = @timesheet.allowed_projects.find_all { |project|
params[:timesheet][:projects].include?(project.id.to_s)
}
else
else
@timesheet.projects = @timesheet.allowed_projects
end

Expand Down Expand Up @@ -79,15 +81,15 @@ def report
end
end
end

@grand_total = @total.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" }
end
end

def context_menu
@time_entries = TimeEntry.find(:all, :conditions => ['id IN (?)', params[:ids]])
render :layout => false
Expand All @@ -105,7 +107,7 @@ def get_list_size

def get_precision
precision = Setting.plugin_timesheet_plugin['precision']

if precision.blank?
# Set precision to a high number
@precision = 10
Expand All @@ -117,9 +119,9 @@ def get_precision
def get_activities
@activities = TimeEntryActivity.all
end

def allowed_projects
if User.current.admin?
if User.current.admin? && Setting.plugin_timesheet_plugin['project_status'] == 'all'
Project.timesheet_order_by_name
elsif Setting.plugin_timesheet_plugin['project_status'] == 'all'
Project.timesheet_order_by_name.timesheet_with_membership(User.current)
Expand All @@ -140,7 +142,7 @@ def load_filters_from_session
end

if session[SessionKey] && session[SessionKey]['projects']
@timesheet.projects = allowed_projects.find_all { |project|
@timesheet.projects = allowed_projects.find_all { |project|
session[SessionKey]['projects'].include?(project.id.to_s)
}
end
Expand Down
91 changes: 56 additions & 35 deletions app/models/timesheet.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
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, :custom_field_values

# Time entries on the Timesheet in the form of:
# project.name => {:logs => [time entries], :users => [users shown in logs] }
# project.name => {:logs => [time entries], :users => [users shown in logs] }
# project.name could be the parent project name also
attr_accessor :time_entries

# Array of TimeEntry ids to fetch
attr_accessor :potential_time_entry_ids

Expand All @@ -22,19 +22,20 @@ class Timesheet
:free_period => 0,
:default => 1
}

def initialize(options = { })
self.projects = [ ]
self.time_entries = options[:time_entries] || { }
self.potential_time_entry_ids = options[:potential_time_entry_ids] || [ ]
self.allowed_projects = options[:allowed_projects] || [ ]
self.custom_field_values = options[:custom_field_values] || [ ]

unless options[:activities].nil?
self.activities = options[:activities].collect { |a| a.to_i }
else
self.activities = TimeEntryActivity.all.collect { |a| a.id.to_i }
end

unless options[:users].nil?
self.users = options[:users].collect { |u| u.to_i }
else
Expand All @@ -46,7 +47,7 @@ def initialize(options = { })
else
self.sort = :project
end

self.date_from = options[:date_from] || Date.today.to_s
self.date_to = options[:date_to] || Date.today.to_s

Expand Down Expand Up @@ -115,6 +116,7 @@ def to_param
:date_to => date_to,
:activities => activities,
:users => users,
:custom_field_values => custom_field_values,
:sort => sort
}
end
Expand Down Expand Up @@ -150,7 +152,7 @@ def self.viewable_users
user.allowed_to?(:log_time, nil, :global => true)
}
end

protected

def csv_header
Expand All @@ -162,9 +164,15 @@ def csv_header
l(:label_project),
l(:label_issue),
"#{l(:label_issue)} #{l(:field_subject)}",
l(:field_comments),
l(:field_hours)
l(:field_comments)
]
time_entry_header = TimeEntry.new
time_entry_header.custom_field_values.each do |value|
csv_data << value.custom_field.name
end

csv_data << l(:field_hours)

Redmine::Hook.call_hook(:plugin_timesheet_model_timesheet_csv_header, { :timesheet => self, :csv_data => csv_data})
return csv_data
end
Expand All @@ -178,9 +186,15 @@ def time_entry_to_csv(time_entry)
time_entry.project.name,
("#{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
time_entry.comments
]

custom_fields_helper = Object.new.extend(CustomFieldsHelper)
time_entry.custom_field_values.each do |value|
csv_data << custom_fields_helper.show_value(value)
end

csv_data << time_entry.hours
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
Expand All @@ -189,8 +203,15 @@ def time_entry_to_csv(time_entry)
# String of extra conditions to add onto the query (AND)
def conditions(users, extra_conditions=nil)
if self.potential_time_entry_ids.empty?

# @todo: Add multiple custom fields selection
custom_field_conditions = ""
self.custom_field_values.each do |value|
custom_field_conditions << " AND #{CustomValue.table_name}.custom_field_id = #{value[0]} AND #{CustomValue.table_name}.value = '#{value[1]}'" unless value[1].empty?
end

if self.date_from.present? && self.date_to.present?
conditions = ["spent_on >= (:from) AND spent_on <= (:to) AND #{TimeEntry.table_name}.project_id IN (:projects) AND user_id IN (:users) AND (activity_id IN (:activities) OR (#{::Enumeration.table_name}.parent_id IN (:activities) AND #{::Enumeration.table_name}.project_id IN (:projects)))",
conditions = ["spent_on >= (:from) AND spent_on <= (:to) AND #{TimeEntry.table_name}.project_id IN (:projects) AND user_id IN (:users) AND (activity_id IN (:activities) OR (#{::Enumeration.table_name}.parent_id IN (:activities) AND #{::Enumeration.table_name}.project_id IN (:projects))) #{custom_field_conditions}",
{
:from => self.date_from,
:to => self.date_to,
Expand All @@ -199,7 +220,7 @@ def conditions(users, extra_conditions=nil)
:users => users
}]
else # All time
conditions = ["#{TimeEntry.table_name}.project_id IN (:projects) AND user_id IN (:users) AND (activity_id IN (:activities) OR (#{::Enumeration.table_name}.parent_id IN (:activities) AND #{::Enumeration.table_name}.project_id IN (:projects)))",
conditions = ["#{TimeEntry.table_name}.project_id IN (:projects) AND user_id IN (:users) AND (activity_id IN (:activities) OR (#{::Enumeration.table_name}.parent_id IN (:activities) AND #{::Enumeration.table_name}.project_id IN (:projects))) #{custom_field_conditions}",
{
:projects => self.projects,
:activities => self.activities,
Expand All @@ -217,61 +238,61 @@ def conditions(users, extra_conditions=nil)
if extra_conditions
conditions[0] = conditions.first + ' AND ' + extra_conditions
end

Redmine::Hook.call_hook(:plugin_timesheet_model_timesheet_conditions, { :timesheet => self, :conditions => conditions})
return conditions
end

def includes
includes = [:activity, :user, :project, {:issue => [:tracker, :assigned_to, :priority]}]
includes = [:activity, :user, :project, {:issue => [:tracker, :assigned_to, :priority]}, :custom_values]
Redmine::Hook.call_hook(:plugin_timesheet_model_timesheet_includes, { :timesheet => self, :includes => includes})
return includes
end

private


def time_entries_for_all_users(project)
return project.time_entries.find(:all,
:conditions => self.conditions(self.users),
:include => self.includes,
:order => "spent_on ASC")
end

def time_entries_for_current_user(project)
return project.time_entries.find(:all,
:conditions => self.conditions(User.current.id),
:include => self.includes,
:include => [:activity, :user, {:issue => [:tracker, :assigned_to, :priority]}],
:include => [:activity, :user, {:issue => [:tracker, :assigned_to, :priority]}, :custom_values],
:order => "spent_on ASC")
end

def issue_time_entries_for_all_users(issue)
return issue.time_entries.find(:all,
:conditions => self.conditions(self.users),
:include => self.includes,
:include => [:activity, :user],
:include => [:activity, :user, :custom_values],
:order => "spent_on ASC")
end

def issue_time_entries_for_current_user(issue)
return issue.time_entries.find(:all,
:conditions => self.conditions(User.current.id),
:include => self.includes,
:include => [:activity, :user],
:include => [:activity, :user, :custom_values],
:order => "spent_on ASC")
end

def time_entries_for_user(user, options={})
extra_conditions = options.delete(:conditions)

return TimeEntry.find(:all,
:conditions => self.conditions([user], extra_conditions),
:include => self.includes,
:order => "spent_on ASC"
)
end

def fetch_time_entries_by_project
self.projects.each do |project|
logs = []
Expand All @@ -291,11 +312,11 @@ def fetch_time_entries_by_project
else
# Rest can see nothing
end

# Append the parent project name
if project.parent.nil?
unless logs.empty?
self.time_entries[project.name] = { :logs => logs, :users => users }
self.time_entries[project.name] = { :logs => logs, :users => users }
end
else
unless logs.empty?
Expand All @@ -304,7 +325,7 @@ def fetch_time_entries_by_project
end
end
end

def fetch_time_entries_by_user
self.users.each do |user_id|
logs = []
Expand All @@ -321,20 +342,20 @@ def fetch_time_entries_by_user
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 =>
# :issues =>
# { issue => {:logs => [time entries],
# issue => {:logs => [time entries],
# issue => {:logs => [time entries]}
#
#
def fetch_time_entries_by_issue
self.projects.each do |project|
logs = []
Expand All @@ -356,19 +377,19 @@ def fetch_time_entries_by_issue

logs.flatten! if logs.respond_to?(:flatten!)
logs.uniq! if logs.respond_to?(:uniq!)

unless logs.empty?
users << logs.collect(&:user).uniq.sort


issues = logs.collect(&:issue).uniq
issue_logs = { }
issues.each do |issue|
issue_logs[issue] = logs.find_all {|time_log| time_log.issue == issue } # TimeEntry is for this issue
end

# TODO: TE without an issue

self.time_entries[project] = { :issues => issue_logs, :users => users}
end
end
Expand Down
6 changes: 5 additions & 1 deletion app/views/timesheet/_by_issue.rhtml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@
<th width="8%"><%= l(:label_date) %></th>
<th width="10%"><%= l(:label_member) %></th>
<th width="45%"><%= l(:label_issue) %> / <%= l(:field_comments) %></th>
<% time_entry = TimeEntry.new
time_entry.custom_field_values.each do |value| %>
<th width="10%"><%= value.custom_field.name %></th>
<% end %>
<th width="10%"><%= l(:field_hours) %>
<%= Redmine::Hook.call_hook(:plugin_timesheet_views_timesheet_group_header, { }) %>
<th align="center"></td>
<th align="center"></th>
</thead>
<tbody>
<%= render :partial => "issue_time_entries", :collection => entry[:issues] %>
Expand Down
12 changes: 12 additions & 0 deletions app/views/timesheet/_form.rhtml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,18 @@
<%= select_tag 'timesheet[users][]', user_options(@timesheet), { :multiple => true, :size => @list_size} %>
</p>


<% time_entry = TimeEntry.new
time_entry.custom_field_values = @timesheet.custom_field_values unless @timesheet.custom_field_values.empty?
time_entry.custom_field_values.each do |value|
# Remove required attribute for the search
value.custom_field.is_required = false
value.custom_field.default_value = ""
value.value = "" if @timesheet.custom_field_values.empty?
%>
<p><%= custom_field_tag_with_label :timesheet, value %></p>
<% end %>

<%# 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 }) %>
Expand Down
Loading