We were calculating the age stats based on the age of the users who participated... at the moment where we were calculating the stats. That means that, if 20 years ago, 1000 people who were 16 years old participated, they would be shown as having 36 years in the stats. Instead, we want to show the stats at the time when the process took place, so we're implementing a `participation_date` method. Note that, for polls, we could actually use the `age` column in the `poll_voters` table. However, doing so would be harder, would only work for polls but not for budgets, and it wouldn't be statistically very relevant, since the stats are shown by age groups, and only a small percentage of people would change their age group (and only to the nearest one) between the time they participate and the time the process ends. We might use the `poll_voters` table in the future, though, since we have a similar issue with geozones and genders, and using the information in `poll_voters` would solve it as well (only for polls, though). Also note that we're using the `ends_at` dates because some people but be too young to vote when a process starts but old enough to vote when the process ends. Finally, note that we might need to change the way we calculate the participation date for a budget, since some budgets might not enabled every phase. Not sure how stats work in that scenario (even before these changes).
128 lines
3.1 KiB
Ruby
128 lines
3.1 KiB
Ruby
class Poll::Stats
|
|
include Statisticable
|
|
alias_method :poll, :resource
|
|
|
|
CHANNELS = Poll::Voter::VALID_ORIGINS
|
|
|
|
def self.stats_methods
|
|
super +
|
|
%i[total_valid_votes total_white_votes total_null_votes
|
|
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_participants_letter total_letter_valid total_letter_white total_letter_null
|
|
total_participants_web_percentage total_participants_booth_percentage
|
|
total_participants_letter_percentage
|
|
valid_percentage_web valid_percentage_booth valid_percentage_letter total_valid_percentage
|
|
white_percentage_web white_percentage_booth white_percentage_letter total_white_percentage
|
|
null_percentage_web null_percentage_booth null_percentage_letter total_null_percentage]
|
|
end
|
|
|
|
def total_participants
|
|
total_participants_web + total_participants_booth
|
|
end
|
|
|
|
def participation_date
|
|
poll.ends_at
|
|
end
|
|
|
|
def channels
|
|
CHANNELS.select { |channel| send(:"total_participants_#{channel}") > 0 }
|
|
end
|
|
|
|
CHANNELS.each do |channel|
|
|
define_method :"total_participants_#{channel}" do
|
|
send(:"total_#{channel}_valid") +
|
|
send(:"total_#{channel}_white") +
|
|
send(:"total_#{channel}_null")
|
|
end
|
|
|
|
define_method :"total_participants_#{channel}_percentage" do
|
|
calculate_percentage(send(:"total_participants_#{channel}"), total_participants)
|
|
end
|
|
end
|
|
|
|
def total_web_valid
|
|
voters.where(origin: "web").count - total_web_white
|
|
end
|
|
|
|
def total_web_white
|
|
0
|
|
end
|
|
|
|
def total_web_null
|
|
0
|
|
end
|
|
|
|
def total_booth_valid
|
|
recounts.sum(:total_amount)
|
|
end
|
|
|
|
def total_booth_white
|
|
recounts.sum(:white_amount)
|
|
end
|
|
|
|
def total_booth_null
|
|
recounts.sum(:null_amount)
|
|
end
|
|
|
|
def total_letter_valid
|
|
voters.where(origin: "letter").count # TODO: count only valid votes
|
|
end
|
|
|
|
def total_letter_white
|
|
0 # TODO
|
|
end
|
|
|
|
def total_letter_null
|
|
0 # TODO
|
|
end
|
|
|
|
%i[valid white null].each do |type|
|
|
CHANNELS.each do |channel|
|
|
define_method :"#{type}_percentage_#{channel}" do
|
|
calculate_percentage(send(:"total_#{channel}_#{type}"), send(:"total_#{type}_votes"))
|
|
end
|
|
end
|
|
|
|
define_method :"total_#{type}_votes" do
|
|
send(:"total_web_#{type}") + send(:"total_booth_#{type}")
|
|
end
|
|
|
|
define_method :"total_#{type}_percentage" do
|
|
calculate_percentage(send(:"total_#{type}_votes"), total_participants)
|
|
end
|
|
end
|
|
|
|
def total_no_demographic_data
|
|
super + total_unregistered_booth
|
|
end
|
|
|
|
def total_registered_booth
|
|
voters.where(origin: "booth").count
|
|
end
|
|
|
|
private
|
|
|
|
def participant_ids
|
|
voters
|
|
end
|
|
|
|
def voters
|
|
@voters ||= poll.voters.select(:user_id)
|
|
end
|
|
|
|
def recounts
|
|
@recounts ||= poll.recounts
|
|
end
|
|
|
|
def total_unregistered_booth
|
|
[total_participants_booth - total_registered_booth, 0].max
|
|
end
|
|
|
|
stats_cache(*stats_methods)
|
|
|
|
def stats_cache(key, &)
|
|
Rails.cache.fetch("polls_stats/#{poll.id}/#{key}/#{version}", &)
|
|
end
|
|
end
|