Files
timeoverflow/app/controllers/statistics_controller.rb

172 lines
5.7 KiB
Ruby

class StatisticsController < ApplicationController
AGE_GROUP_LABELS = {
0..17 => " -17",
18..24 => "18-24",
25..34 => "25-34",
35..44 => "35-44",
45..54 => "45-54",
55..64 => "55-64",
65..100 => "65+",
}
before_filter :authenticate_user!
def statistics_global_activity
@members = current_organization.members
@active_members = @members.active
@total_hours = num_movements = 0
@members.each do |m|
num_movements += m.account.movements.count
@total_hours += m.account.movements.map do
|a| (a.amount > 0) ? a.amount : 0
end.inject(0, :+)
end
# cada intercambio implica dos movimientos
@num_swaps = (num_movements +
current_organization.account.movements.count) / 2
# intercambios con el banco
@total_hours += current_organization.account.movements.
map { |a| (a.amount > 0) ? a.amount : 0 }.inject(0, :+)
# periodo a mostrar actividades globales, por defecto 6 meses
ini = params[:ini].presence.try(:to_date) || DateTime.now.to_date - 5.month
fin = params[:fin].presence.try(:to_date) || DateTime.now.to_date
if ini.present?
# calculo numero de meses
num_months = (fin.year * 12 + fin.month) - (ini.year * 12 + ini.month) + 1
date = ini
# vector para los meses de la gráfica ["Enero", "Febrero",...]
@months_names = []
# y vectores con los datos para la gráfica
@user_reg_months = []
@num_swaps_months = []
@hours_swaps_months = []
# valores por cada mes
num_months.times do
@months_names.push(l(date, format: "%B %Y"))
@user_reg_months.push(@members.by_month(date).count)
# movimientos de los miembros en dicho mes
swaps_members = @members.map { |a| a.account.movements.by_month(date) }
# movimimentos del banco
swaps_organization = current_organization.account.
movements.by_month(date)
# numero de movimientos totales
sum_swaps = (swaps_members.flatten.count + swaps_organization.count) / 2
@num_swaps_months.push(sum_swaps)
# horas intercambiadas
sum_hours = 0
swaps_members.flatten.each do |s|
sum_hours += (s.amount > 0) ? s.amount : 0
end
sum_hours += swaps_organization.map do
|a| (a.amount > 0) ? a.amount : 0
end.inject(0, :+)
sum_hours = sum_hours / 3600.0 if sum_hours > 0
@hours_swaps_months.push(sum_hours)
date = date.next_month
end
end
end
def statistics_inactive_users
@members = current_organization.members.active
end
def statistics_demographics
@members = current_organization.members
@age_counts = age_counts
end
def statistics_last_login
@members = current_organization.members.active.joins(:user).
order("users.current_sign_in_at ASC NULLS FIRST")
end
def statistics_without_offers
@members = current_organization.members.active
end
def statistics_type_swaps
offers = current_organization.posts.
where(type: "Offer").joins(:transfers, transfers: :movements).
select("posts.tags, posts.category_id, SUM(movements.amount) as
sum_of_transfers, COUNT(transfers.id) as
count_of_transfers").
where("movements.amount > 0").
group("posts.tags, posts.category_id, posts.updated_at")
@offers = count_offers_by_label(offers).to_a.each { |a| a.flatten!(1) }.
sort_by(&:last).reverse
end
def statistics_all_transfers
@transfers = current_organization.all_transfers.
includes(movements: {account: :accountable}).
order("transfers.created_at DESC").
uniq.
page(params[:page]).
per(20)
end
protected
def age(date_of_birth)
return unless date_of_birth
age_in_days = Date.today - date_of_birth
(age_in_days / 365.26).to_i
end
# returns a hash of
# {
# [ category_label, tag_label ] => [ sum, count, ratio ],
# ...
# }
def count_offers_by_label(offers)
# Cannot use Hash.new([0, 0]) because then
# counters[key][0] += n
# will modify directly the "global default" instead of
# first assigning a new array with the zeroed counters.
counters = Hash.new { |h, k| h[k] = [0, 0] }
offers.each do |offer|
labels_for_offer(offer).each do |labels|
# labels = [ category_label, tag_label ]
counters[labels][0] += offer.sum_of_transfers
counters[labels][1] += offer.count_of_transfers
end
end
add_ratios!(counters)
counters
end
def add_ratios!(counters)
# add the ratio at the end of each value
total_count = counters.values.map { |_, counts| counts }.sum
counters.each do |_, v|
v << v[1].to_f / total_count
end
end
# returns an array of
# [category_name, tag_name]
# one item per each tag. If the category or the tags are missing, they are
# replaced with a fallback "Unknown" label.
def labels_for_offer(offer)
tag_labels = offer.tags.presence ||
[t("statistics.statistics_type_swaps.without_tags")]
category_label = offer.category.try(:name) ||
t("statistics.statistics_type_swaps.without_category")
[category_label].product(tag_labels)
end
def age_counts
@members.each_with_object(Hash.new(0)) do |member, counts|
age = age(member.user_date_of_birth)
age_label = AGE_GROUP_LABELS.detect do |range, _|
range.include? age
end.try(:last) || t("statistics.statistics_demographics.unknown")
counts[age_label] += 1
end
end
end