/
time_booking_query.rb
144 lines (125 loc) · 6.36 KB
/
time_booking_query.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
class TimeBookingQuery < Query
include TtQueryOperators
include TtQueryConcern
self.queried_class = TimeBooking
@visible_permission = :index_tt_bookings_list
self.available_columns = [
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),
QueryColumn.new(:tt_booking_date, :sortable => "#{TimeBooking.table_name}.started_on", :default_order => 'desc', :caption => :field_tt_date, :groupable => "DATE(#{TimeBooking.table_name}.started_on)"),
QueryColumn.new(:get_formatted_start_time, :caption => :field_tt_start),
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?
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
def default_columns_names
[:project, :activity, :tt_booking_date, :get_formatted_start_time, :get_formatted_stop_time, :issue, :comments, :get_formatted_time]
end
# Returns the bookings count
def booking_count
# TODO refactor includes
TimeBooking.visible.
joins(:project, {:time_entry => [{:issue => :fixed_version}, :activity]}, {:time_log => :user}).
where(statement).
count(:id)
rescue ::ActiveRecord::StatementInvalid => e
raise StatementInvalid.new(e.message)
end
# Returns the bookings count by group or nil if query is not grouped
def booking_count_by_group
r = nil
if grouped?
begin
# Rails3 will raise an (unexpected) RecordNotFound if there's only a nil group value
# 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
r = TimeBooking.visible.
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}
end
custom_field_value()
end
r
rescue ::ActiveRecord::StatementInvalid => e
raise Query::StatementInvalid.new(e.message)
end
# Returns the bookings
# Valid options are :order, :offset, :limit, :include, :conditions
def bookings(options={})
order_option = [group_by_sort_order, options[:order]].flatten.reject(&:blank?)
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
# sql statements for where clauses have to be in an "sql_for_#{filed-name}_field" method
# so we have to implement some where-clauses for every new filter here
def sql_for_tt_booking_project_field(field, operator, value)
if value.delete('mine')
value += User.current.memberships.map(&:project_id).map(&:to_s)
end
if operator == "="
"( #{TimeBooking.table_name}.project_id IN (" + value.collect { |val| "'#{connection.quote_string(val)}'" }.join(",") + ") )"
else
"( #{TimeBooking.table_name}.project_id NOT IN (" + value.collect { |val| "'#{connection.quote_string(val)}'" }.join(",") + ") OR #{TimeBooking.table_name}.project_id IS NULL )"
end
end
def sql_for_tt_booking_issue_field(field, operator, value)
sql = "( #{Issue.table_name}.id #{operator == "=" ? 'IN' : 'NOT IN'} (" + value.collect { |val| "'#{connection.quote_string(val)}'" }.join(",") + ") "
if operator == "!"
sql << " OR #{Issue.table_name}.id IS NULL)"
else
sql << ")"
end
end
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
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