hicknhack-software/redmine_hourglass

View on GitHub
app/helpers/hourglass/chart_helper.rb

Summary

Maintainability
A
1 hr
Test Coverage
module Hourglass
  module ChartHelper

    # works only for time bookings for now
    def chart_data(chart_query)
      data = Hash.new([].freeze)
      ticks = []
      tooltips = Hash.new([].freeze)

      if chart_query.valid?
        hours_per_date_without_column = hours_per_date chart_query
        dates = hours_per_date_without_column.keys.sort
        if dates.present?
          group_key_is_string = dates.first.is_a?(String)
          date_range = group_key_is_string ? (Date.parse(dates.first)..Date.parse(dates.last)) : (dates.first..dates.last)
          hours_per_column_per_date(hours_per_date_without_column).each do |column, hours_per_date|
            date_range.each do |date|
              hours = hours_per_date[group_key_is_string ? date.to_s : date]
              data[column] += [hours || 0.0]
              tooltips[column] += ["#{format_date date.to_time}, #{localized_hours_in_units hours}"]
            end
          end
          ticks = calculate_ticks date_range
        end
      end
      [data.values, ticks, tooltips.values]
    end

    private
    # to get readable labels, we have to blank out some of them if there are to many
    def calculate_ticks(date_range)
      gap = [(date_range.count / 8.to_f).ceil, 1].max
      date_range.each_with_index.map { |date, i| i % gap == 0 ? format_date(date.to_time) : '' }
    end

    def hours_per_date(query)
      query.total_by_group_for(:hours).transform_values do |totals_by_column|
        totals_by_column = {default: totals_by_column} unless query.main_query.group_by_statement
        totals_by_column.transform_keys! { |_| :default } if query.main_query.group_by == 'date'
        Hash[totals_by_column.map { |column, total| [column, unrounded_total(total)] }]
      end
    end

    def unrounded_total(total)
      total.reduce(0.0) do |sum, total_by_project|
        sum + total_by_project[1].to_f.round(2)
      end
    end

    def hours_per_column_per_date(hours_per_date)
      hours_per_date.each_with_object({}) do |(date, hours_per_column), hours_per_column_per_date|
        hours_per_column.each do |project_id, hours|
          hours_per_column_per_date[project_id] ||= {}
          hours_per_column_per_date[project_id][date] = hours
        end
      end
    end
  end
end