Skip to content

Commit

Permalink
added ability to show, filter and group target version
Browse files Browse the repository at this point in the history
* minor code cleanup in time_booking_query
  • Loading branch information
arBmind committed Jan 27, 2014
1 parent 39d9cc9 commit 94a402b
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 18 deletions.
9 changes: 9 additions & 0 deletions app/models/time_booking.rb
Expand Up @@ -9,6 +9,7 @@ class TimeBooking < ActiveRecord::Base
belongs_to :time_entry, :dependent => :delete
has_one :issue, :through => :time_entry
has_one :activity, :through => :time_entry
has_one :fixed_version, :through => :issue, :class_name => 'Version', :foreign_key => 'fixed_version_id'

validates_presence_of :time_log_id
validates :time_entry_id, :presence => true
Expand Down Expand Up @@ -135,6 +136,14 @@ def issue_id
end
end

def fixed_version
if self.time_entry.issue.nil? || self.time_entry.issue.fixed_version.nil?
l(:time_tracker_label_none)
else
self.time_entry.issue.fixed_version
end
end

def project=(project)
return if project == self.project # no validation or permission checks necessary if there are no changes!
raise StandardError, l(:tt_error_not_allowed_to_book_without_project) if project.nil?
Expand Down
49 changes: 35 additions & 14 deletions app/models/time_booking_query.rb
Expand Up @@ -6,7 +6,7 @@ class TimeBookingQuery < Query
@visible_permission = :index_tt_bookings_list

self.available_columns = [
QueryColumn.new(:project, :sortable => "#{Project.table_name}.name", :groupable => true),
QueryColumn.new(:project, :sortable => "#{Project.table_name}.name", :groupable => "#{Project.table_name}.name"),
QueryColumn.new(:activity, :caption => :field_tt_booking_activity, :sortable => "#{TimeEntryActivity.table_name}.name", :groupable => "#{TimeEntryActivity.table_name}.name"),
QueryColumn.new(:comments, :caption => :field_tt_comments),
QueryColumn.new(:user, :sortable => "#{User.table_name}.login", :caption => :field_tt_user),
Expand All @@ -15,21 +15,37 @@ class TimeBookingQuery < Query
QueryColumn.new(:get_formatted_stop_time, :caption => :field_tt_stop),
QueryColumn.new(:get_formatted_time, :caption => :field_tt_time),
QueryColumn.new(:issue, :sortable => "#{Issue.table_name}.subject", :caption => :field_tt_booking_issue, :groupable => "#{Issue.table_name}.subject"),
QueryColumn.new(:fixed_version, :sortable => lambda {Version.fields_for_order_statement}, :groupable => "#{Version.table_name}.name"),
]

def auth_values
add_available_filter 'tt_start_date', :type => :date, :order => 2
add_available_filter 'tt_booking_issue', :type => :list, :order => 4, :values => Issue.visible.all.collect { |s| [s.subject, s.id.to_s] }
add_available_filter 'tt_booking_activity', :type => :list, :order => 4, :values => help.get_activities('').map { |s| [s.name, s.name] }

project_values = []
if project.nil?
project_values = []
if User.current.logged? && User.current.memberships.any?
project_values << ["<< #{l(:label_my_projects).downcase} >>", "mine"]
end
project_values += all_projects_values
add_available_filter("tt_booking_project", :type => :list, :values => project_values) unless project_values.empty?
end

versions = []
if project
versions = project.shared_versions.all
else
# TODO: find a way to get shared_versions without killing the db
versions = Project.visible.includes(:versions).all.flat_map { |project| project.shared_versions.all }
versions.uniq!
end

if versions.any?
add_available_filter "tt_booking_fixed_version",
:type => :list_optional,
:values => versions.collect{|s| ["#{s.project.name} - #{s.name}", s.id.to_s] }.sort
end
end


Expand All @@ -42,7 +58,7 @@ def default_columns_names
def booking_count
# TODO refactor includes
TimeBooking.visible.
includes([:project, {:time_entry => :issue}, {:time_entry => :activity}, {:time_log => :user}]).
joins(:project, {:time_entry => [{:issue => :fixed_version}, :activity]}, {:time_log => :user}).
where(statement).
count(:id)
rescue ::ActiveRecord::StatementInvalid => e
Expand All @@ -58,12 +74,10 @@ def booking_count_by_group
# for some reason including the :project will result in an "ambiguous column" - error if we try to group by
# "project" and additionally filter by issue. so we have to use a small workaround
# todo figure out the 'rails-way' to avoid ambiguous columns
gbs = group_by_statement
gbs = "#{Project.table_name}.name" if gbs == "project"
r = TimeBooking.visible.
includes([:project, {:time_entry => :issue}, {:time_entry => :activity}, {:time_log => :user}]).
group(gbs).
joins(:project, {:time_entry => [{:issue => :fixed_version}, :activity]}, {:time_log => :user}).
where(statement).
group(group_by_statement).
count(:id)
rescue ActiveRecord::RecordNotFound
r = {nil => booking_count}
Expand All @@ -78,18 +92,17 @@ def booking_count_by_group
# Returns the bookings
# Valid options are :order, :offset, :limit, :include, :conditions
def bookings(options={})
group_by_order = (group_by_sort_order || '').strip
options[:order].unshift group_by_order unless options[:order].map { |opt| opt.gsub('asc', '').gsub('desc', '').strip }.include? group_by_order.gsub('asc', '').gsub('desc', '').strip
order_option = options[:order].reject { |s| s.blank? }.join(',')
order_option = nil if order_option.blank?
order_option = [group_by_sort_order, options[:order]].flatten.reject(&:blank?)

TimeBooking.visible.
includes([:project, {:time_entry => :issue}, {:time_entry => :activity}, {:time_log => :user}]).
scope = TimeBooking.visible.
includes([:project, {:time_entry => [{:issue => :fixed_version}, :activity]}, {:time_log => :user}]).
where(statement).
where(options[:conditions]).
order(order_option).
limit(options[:limit]).
offset(options[:offset])

scope.all
rescue ::ActiveRecord::StatementInvalid => e
raise Query::StatementInvalid.new(e.message)
end
Expand Down Expand Up @@ -120,4 +133,12 @@ def sql_for_tt_booking_issue_field(field, operator, value)
def sql_for_tt_booking_activity_field(field, operator, value)
"( #{TimeEntryActivity.table_name}.name #{operator == "=" ? 'IN' : 'NOT IN'} (" + value.collect { |val| "'#{connection.quote_string(val)}'" }.join(",") + ") )"
end
end

def sql_for_tt_booking_fixed_version_field(field, operator, value)
if operator == "="
"( #{Issue.table_name}.fixed_version_id IN (" + value.collect { |val| "'#{connection.quote_string(val)}'" }.join(",") + ") )"
else
"( #{Issue.table_name}.fixed_version_id NOT IN (" + value.collect { |val| "'#{connection.quote_string(val)}'" }.join(",") + ") OR #{Issue.table_name}.fixed_version_id IS NULL )"
end
end
end
6 changes: 3 additions & 3 deletions app/views/tt_bookings_list/_list.html.erb
Expand Up @@ -24,12 +24,12 @@
group = nil
else
group = case gb_col.name
when :project, :activity then
query.group_by_column.value(entry).to_s
when :tt_booking_date then
entry.send('started_on').send('localtime').to_date.to_s
when :issue then
entry.send('issue').send('subject') unless entry.send('issue') == l(:time_tracker_label_none)
else
query.group_by_column.value(entry).to_s
end
end %>
<% if group != previous_group %>
Expand All @@ -56,4 +56,4 @@
</table>
</div>
<% end -%>
</div>
</div>
3 changes: 2 additions & 1 deletion config/locales/de.yml
Expand Up @@ -16,6 +16,7 @@ de:
field_tt_stop: "Ende"
field_tt_time: "benötigte Zeit"
field_tt_user: "Benutzer"
field_tt_booking_fixed_version: "Zielversion"
force_auth_requires_rest_api: "Wenn die Einstellung 'Authentifizierung notwendig' aktiviert ist, muss auch die RESP-API aktiviert sein, damit das Plugin ordnungsgemäß funktioniert"
list_time_trackers: "Liste der Zeiterfassungen anzeigen"
no_time_tracker: "Keine Zeiterfassung vorhanden."
Expand Down Expand Up @@ -148,4 +149,4 @@ de:
time_tracker_settings_transition_title: "Statusänderungen"
time_tracker_settings_unknown_status: "Unbekannter Status"
time_tracker_settings_zombie_transition: "Zombie Statusänderung"
update_time_tracker_success: "Die Zeiterfassung wurde aktualisiert."
update_time_tracker_success: "Die Zeiterfassung wurde aktualisiert."
1 change: 1 addition & 0 deletions config/locales/en.yml
Expand Up @@ -16,6 +16,7 @@ en:
field_tt_stop: "Stop time"
field_tt_time: "Time spent"
field_tt_user: "User"
field_tt_booking_fixed_version: "Target version"
force_auth_requires_rest_api: "If 'Authentication required' was enabled in Redmine settings, the REST-API must be enabled also. Otherwise the TimeTracker plugin may not work properly!"
list_time_trackers: "list"
no_time_tracker: "No time tracker"
Expand Down

0 comments on commit 94a402b

Please sign in to comment.