diff --git a/app/models/budget/stats.rb b/app/models/budget/stats.rb index acbd93139..cbcde4703 100644 --- a/app/models/budget/stats.rb +++ b/app/models/budget/stats.rb @@ -2,7 +2,7 @@ class Budget::Stats include Statisticable alias_method :budget, :resource - def stats_methods + def self.stats_methods %i[total_participants total_participants_support_phase total_participants_vote_phase total_budget_investments total_votes total_selected_investments total_unfeasible_investments total_male_participants total_female_participants @@ -13,121 +13,111 @@ class Budget::Stats private def total_participants - stats_cache("total_participants") { participants.distinct.count } + participants.distinct.count end def total_participants_support_phase - stats_cache("total_participants_support_phase") { voters.uniq.count } + voters.uniq.count end def total_participants_web - stats_cache("total_participants_web") do - (balloters - poll_ballot_voters).uniq.compact.count - end + (balloters - poll_ballot_voters).uniq.compact.count end def total_participants_booths - stats_cache("total_participants_booths") { poll_ballot_voters.uniq.count } + poll_ballot_voters.uniq.count end def total_participants_vote_phase - stats_cache("total_participants_vote_phase") { balloters.uniq.count } + balloters.uniq.count end def total_budget_investments - stats_cache("total_budget_investments") { budget.investments.count } + budget.investments.count end def total_votes - stats_cache("total_votes") { budget.ballots.pluck(:ballot_lines_count).inject(0) { |sum, x| sum + x } } + budget.ballots.pluck(:ballot_lines_count).inject(0) { |sum, x| sum + x } end def total_selected_investments - stats_cache("total_selected_investments") { budget.investments.selected.count } + budget.investments.selected.count end def total_unfeasible_investments - stats_cache("total_unfeasible_investments") { budget.investments.unfeasible.count } + budget.investments.unfeasible.count end def total_male_participants - stats_cache("total_male_participants") { participants.where(gender: "male").count } + participants.where(gender: "male").count end def total_female_participants - stats_cache("total_female_participants") { participants.where(gender: "female").count } + participants.where(gender: "female").count end def total_supports - stats_cache("total_supports") { supports(budget).count } + supports(budget).count end def total_unknown_gender_or_age - stats_cache("total_unknown_gender_or_age") do - participants.where("gender IS NULL OR date_of_birth is NULL").uniq.count - end + participants.where("gender IS NULL OR date_of_birth is NULL").uniq.count end def age_groups - stats_cache("age_groups") do - groups = Hash.new(0) - ["16 - 19", - "20 - 24", - "25 - 29", - "30 - 34", - "35 - 39", - "40 - 44", - "45 - 49", - "50 - 54", - "55 - 59", - "60 - 64", - "65 - 69", - "70 - 140"].each do |group| - start, finish = group.split(" - ") - group_name = (group == "70 - 140" ? "+ 70" : group) - groups[group_name] = User.where(id: participants) - .where("date_of_birth > ? AND date_of_birth < ?", - finish.to_i.years.ago.beginning_of_year, - start.to_i.years.ago.end_of_year).count - end - groups + groups = Hash.new(0) + ["16 - 19", + "20 - 24", + "25 - 29", + "30 - 34", + "35 - 39", + "40 - 44", + "45 - 49", + "50 - 54", + "55 - 59", + "60 - 64", + "65 - 69", + "70 - 140"].each do |group| + start, finish = group.split(" - ") + group_name = (group == "70 - 140" ? "+ 70" : group) + groups[group_name] = User.where(id: participants) + .where("date_of_birth > ? AND date_of_birth < ?", + finish.to_i.years.ago.beginning_of_year, + start.to_i.years.ago.end_of_year).count end + groups end def male_percentage - stats_cache("male_percentage") { total_male_participants / total_participants_with_gender.to_f * 100 } + total_male_participants / total_participants_with_gender.to_f * 100 end def female_percentage - stats_cache("female_percentage") { total_female_participants / total_participants_with_gender.to_f * 100 } + total_female_participants / total_participants_with_gender.to_f * 100 end def participants - stats_cache("participants") do - User.where(id: (authors + voters + balloters + poll_ballot_voters).uniq.compact) - end + User.where(id: (authors + voters + balloters + poll_ballot_voters).uniq.compact) end def authors - stats_cache("authors") { budget.investments.pluck(:author_id) } + budget.investments.pluck(:author_id) end def voters - stats_cache("voters") { supports(budget).pluck(:voter_id) } + supports(budget).pluck(:voter_id) end def balloters - stats_cache("balloters") { budget.ballots.where("ballot_lines_count > ?", 0).pluck(:user_id) } + budget.ballots.where("ballot_lines_count > ?", 0).pluck(:user_id) end def poll_ballot_voters - stats_cache("poll_ballot_voters") do - budget&.poll ? budget.poll.voters.pluck(:user_id) : [] - end + budget&.poll ? budget.poll.voters.pluck(:user_id) : [] end def total_participants_with_gender - stats_cache("total_participants_with_gender") { participants.where.not(gender: nil).distinct.count } + participants.where.not(gender: nil).distinct.count end def balloters_by_heading(heading_id) @@ -143,28 +133,26 @@ class Budget::Stats end def headings - stats_cache("headings") do - groups = Hash.new(0) - budget.headings.order("id ASC").each do |heading| - groups[heading.id] = Hash.new(0).merge(calculate_heading_totals(heading)) - end - - groups[:total] = Hash.new(0) - groups[:total][:total_investments_count] = groups.collect {|_k, v| v[:total_investments_count]}.sum - groups[:total][:total_participants_support_phase] = groups.collect {|_k, v| v[:total_participants_support_phase]}.sum - groups[:total][:total_participants_vote_phase] = groups.collect {|_k, v| v[:total_participants_vote_phase]}.sum - groups[:total][:total_participants_all_phase] = groups.collect {|_k, v| v[:total_participants_all_phase]}.sum - - budget.headings.each do |heading| - groups[heading.id].merge!(calculate_heading_stats_with_totals(groups[heading.id], groups[:total], heading.population)) - end - - groups[:total][:percentage_participants_support_phase] = groups.collect {|_k, v| v[:percentage_participants_support_phase]}.sum - groups[:total][:percentage_participants_vote_phase] = groups.collect {|_k, v| v[:percentage_participants_vote_phase]}.sum - groups[:total][:percentage_participants_all_phase] = groups.collect {|_k, v| v[:percentage_participants_all_phase]}.sum - - groups + groups = Hash.new(0) + budget.headings.order("id ASC").each do |heading| + groups[heading.id] = Hash.new(0).merge(calculate_heading_totals(heading)) end + + groups[:total] = Hash.new(0) + groups[:total][:total_investments_count] = groups.collect {|_k, v| v[:total_investments_count]}.sum + groups[:total][:total_participants_support_phase] = groups.collect {|_k, v| v[:total_participants_support_phase]}.sum + groups[:total][:total_participants_vote_phase] = groups.collect {|_k, v| v[:total_participants_vote_phase]}.sum + groups[:total][:total_participants_all_phase] = groups.collect {|_k, v| v[:total_participants_all_phase]}.sum + + budget.headings.each do |heading| + groups[heading.id].merge!(calculate_heading_stats_with_totals(groups[heading.id], groups[:total], heading.population)) + end + + groups[:total][:percentage_participants_support_phase] = groups.collect {|_k, v| v[:percentage_participants_support_phase]}.sum + groups[:total][:percentage_participants_vote_phase] = groups.collect {|_k, v| v[:percentage_participants_vote_phase]}.sum + groups[:total][:percentage_participants_all_phase] = groups.collect {|_k, v| v[:percentage_participants_all_phase]}.sum + + groups end def calculate_heading_totals(heading) @@ -209,6 +197,10 @@ class Budget::Stats ActsAsVotable::Vote.where(votable_type: "Budget::Investment", votable_id: supportable.investments.pluck(:id)) end + stats_cache(*stats_methods) + stats_cache :total_participants_with_gender + stats_cache :voters, :participants, :authors, :balloters, :poll_ballot_voters + def stats_cache(key, &block) Rails.cache.fetch("budgets_stats/#{budget.id}/#{key}/v10", &block) end diff --git a/app/models/concerns/statisticable.rb b/app/models/concerns/statisticable.rb index 2751b7447..0a8032e3d 100644 --- a/app/models/concerns/statisticable.rb +++ b/app/models/concerns/statisticable.rb @@ -9,7 +9,19 @@ module Statisticable end def generate - stats_methods.map { |stat_name| [stat_name, send(stat_name)] }.to_h + self.class.stats_methods.map { |stat_name| [stat_name, send(stat_name)] }.to_h + end + end + + class_methods do + def stats_cache(*method_names) + method_names.each do |method_name| + alias_method :"raw_#{method_name}", method_name + + define_method method_name do + stats_cache(method_name) { send(:"raw_#{method_name}") } + end + end end end end diff --git a/app/models/poll/stats.rb b/app/models/poll/stats.rb index e855097ea..2b40f2daf 100644 --- a/app/models/poll/stats.rb +++ b/app/models/poll/stats.rb @@ -3,7 +3,7 @@ class Poll::Stats include StatsHelper alias_method :poll, :resource - def stats_methods + def self.stats_methods %i[total_participants total_participants_web total_web_valid total_web_white total_web_null total_participants_booth total_booth_valid total_booth_white total_booth_null total_valid_votes total_white_votes total_null_votes valid_percentage_web valid_percentage_booth @@ -15,105 +15,108 @@ class Poll::Stats private def total_participants - stats_cache("total_participants") { total_participants_web + total_participants_booth } + total_participants_web + total_participants_booth end def total_participants_web - stats_cache("total_participants_web") { total_web_valid + total_web_white + total_web_null } + total_web_valid + total_web_white + total_web_null end def total_participants_web_percentage - stats_cache("total_participants_web_percentage") { calculate_percentage(total_participants_web, total_participants) } + calculate_percentage(total_participants_web, total_participants) end def total_participants_booth - stats_cache("total_participants_booth") { total_booth_valid + total_booth_white + total_booth_null } + total_booth_valid + total_booth_white + total_booth_null end def total_participants_booth_percentage - stats_cache("total_participants_booth_percentage") { calculate_percentage(total_participants_booth, total_participants) } + calculate_percentage(total_participants_booth, total_participants) end def total_web_valid - stats_cache("total_web_valid") { voters.where(origin: "web").count - total_web_white } + voters.where(origin: "web").count - total_web_white end def valid_percentage_web - stats_cache("valid_percentage_web") { calculate_percentage(total_web_valid, total_valid_votes) } + calculate_percentage(total_web_valid, total_valid_votes) end def total_web_white - stats_cache("total_web_white") { 0 } + 0 end def white_percentage_web - stats_cache("white_percentage_web") { calculate_percentage(total_web_white, total_white_votes) } + calculate_percentage(total_web_white, total_white_votes) end def total_web_null - stats_cache("total_web_null") { 0 } + 0 end def null_percentage_web - stats_cache("null_percentage_web") { calculate_percentage(total_web_null, total_null_votes) } + calculate_percentage(total_web_null, total_null_votes) end def total_booth_valid - stats_cache("total_booth_valid") { recounts.sum(:total_amount) } + recounts.sum(:total_amount) end def valid_percentage_booth - stats_cache("valid_percentage_booth") { calculate_percentage(total_booth_valid, total_valid_votes) } + calculate_percentage(total_booth_valid, total_valid_votes) end def total_booth_white - stats_cache("total_booth_white") { recounts.sum(:white_amount) } + recounts.sum(:white_amount) end def white_percentage_booth - stats_cache("white_percentage_booth") { calculate_percentage(total_booth_white, total_white_votes) } + calculate_percentage(total_booth_white, total_white_votes) end def total_booth_null - stats_cache("total_booth_null") { recounts.sum(:null_amount) } + recounts.sum(:null_amount) end def null_percentage_booth - stats_cache("null_percentage_booth") { calculate_percentage(total_booth_null, total_null_votes) } + calculate_percentage(total_booth_null, total_null_votes) end def total_valid_votes - stats_cache("total_valid_votes") { total_web_valid + total_booth_valid } + total_web_valid + total_booth_valid end def total_valid_percentage - stats_cache("total_valid_percentage"){ calculate_percentage(total_valid_votes, total_participants) } + calculate_percentage(total_valid_votes, total_participants) end def total_white_votes - stats_cache("total_white_votes") { total_web_white + total_booth_white } + total_web_white + total_booth_white end def total_white_percentage - stats_cache("total_white_percentage") { calculate_percentage(total_white_votes, total_participants) } + calculate_percentage(total_white_votes, total_participants) end def total_null_votes - stats_cache("total_null_votes") { total_web_null + total_booth_null } + total_web_null + total_booth_null end def total_null_percentage - stats_cache("total_null_percentage") { calculate_percentage(total_null_votes, total_participants) } + calculate_percentage(total_null_votes, total_participants) end def voters - stats_cache("voters") { poll.voters } + poll.voters end def recounts - stats_cache("recounts") { poll.recounts } + poll.recounts end + stats_cache(*stats_methods) + stats_cache :voters, :recounts + def stats_cache(key, &block) Rails.cache.fetch("polls_stats/#{poll.id}/#{key}/v12", &block) end