hicknhack-software/redmine_hourglass

View on GitHub
app/models/hourglass/time_booking_query.rb

Summary

Maintainability
A
40 mins
Test Coverage
module Hourglass
  class TimeBookingQuery < Query
    include QueryBase

    set_available_columns(
        date: {sortable: "#{queried_class.table_name}.start", groupable: "DATE(#{queried_class.table_name}.start)"},
        start: {},
        stop: {},
        hours: {totalable: true},
        comments: {},
        user: {sortable: lambda { User.fields_for_order_statement }, groupable: "#{User.table_name}.id"},
        project: {sortable: "#{Project.table_name}.name", groupable: "#{Project.table_name}.id"},
        activity: {sortable: "#{TimeEntryActivity.table_name}.position", groupable: "#{TimeEntryActivity.table_name}.id"},
        issue: {sortable: "#{Issue.table_name}.subject", groupable: "#{Issue.table_name}.id"},
        fixed_version: {sortable: lambda { Version.fields_for_order_statement }, groupable: "#{Issue.table_name}.fixed_version_id"}
    )

    def initialize(attributes=nil, *args)
      super attributes
      self.filters ||= {'date' => {:operator => "m", :values => [""]}}
    end

    def initialize_available_filters
      add_user_filter
      add_date_filter
      add_issue_filter
      if project
        add_sub_project_filter unless project.leaf?
      else
        add_project_filter if all_projects.any?
      end
      add_activity_filter
      add_fixed_version_filter
      add_comments_filter
      add_associations_custom_fields_filters :user, :project, :activity, :fixed_version
      add_custom_fields_filters issue_custom_fields, :issue
      add_custom_fields_filters TimeEntryCustomField, :time_entry
      # we need fix the last added filters cause redmine fucks up the name
      available_filters.select { |k, _| k.start_with? 'time_entry' }.each do |_, v|
        v[:name] = v[:field].name
      end
    end

    def available_columns
      @available_columns ||= self.class.available_columns.dup.tap do |available_columns|
        {
            time_entry: TimeEntryCustomField,
            issue: issue_custom_fields,
            project: ProjectCustomField,
            user: UserCustomField,
            fixed_version: VersionCustomField

        }.each do |association, custom_field_scope|
          custom_field_scope.visible.each do |custom_field|
            available_columns << QueryAssociationCustomFieldColumn.new(association, custom_field)
          end
        end
      end
    end

    def default_columns_names
      @default_columns_names ||= [:date, :start, :stop, :hours, :project, :issue, :activity, :comments]
    end

    def base_scope
      super.visible.eager_load(:time_entry, :activity, :user, :project, issue: :fixed_version)
    end

    def sql_for_user_id_field(field, operator, value)
      sql_for_field(field, operator, value, User.table_name, 'id')
    end

    def sql_for_project_id_field(field, operator, value)
      sql_for_field(field, operator, value, Project.table_name, 'id')
    end

    def sql_for_issue_id_field(field, operator, value)
      sql_for_field(field, operator, value, Issue.table_name, 'id')
    end

    def sql_for_issue_subject_field(field, operator, value)
      sql_for_field(field, operator, value, Issue.table_name, 'subject')
    end

    def sql_for_fixed_version_id_field(field, operator, value)
      sql_for_field(field, operator, value, Issue.table_name, 'fixed_version_id')
    end

    def sql_for_comments_field(field, operator, value)
      sql_for_field(field, operator, value, TimeEntry.table_name, 'comments', true)
    end

    def sql_for_activity_id_field(field, operator, value)
      condition_on_id = sql_for_field(field, operator, value, Enumeration.table_name, 'id')
      condition_on_parent_id = sql_for_field(field, operator, value, Enumeration.table_name, 'parent_id')
      if operator == '='
        "(#{condition_on_id} OR #{condition_on_parent_id})"
      else
        "(#{condition_on_id} AND #{condition_on_parent_id})"
      end
    end

    def total_for_hours(scope)
      scope.group("#{TimeEntry.table_name}.project_id").sum("#{TimeEntry.table_name}.hours").each_with_object({}) do |((column, project_id), total), totals|
        totals[column] ||= {}
        if project_id
          totals[column][project_id] = total
        else
          totals[column] = total
        end
      end
    end

    def has_through_associations
      %i(user issue project activity fixed_version)
    end
  end
end