diff --git a/app/controllers/officing/base_controller.rb b/app/controllers/officing/base_controller.rb index e73f2b696..96f185d24 100644 --- a/app/controllers/officing/base_controller.rb +++ b/app/controllers/officing/base_controller.rb @@ -20,10 +20,7 @@ class Officing::BaseController < ApplicationController end def load_officer_assignment - @officer_assignments ||= current_user.poll_officer. - officer_assignments. - voting_days. - where(date: Time.current.to_date) + @officer_assignments ||= current_user.poll_officer.officer_assignments.where(date: Time.current.to_date) end def verify_officer_assignment diff --git a/app/controllers/polls/questions_controller.rb b/app/controllers/polls/questions_controller.rb index 6773282ef..eb054dd1e 100644 --- a/app/controllers/polls/questions_controller.rb +++ b/app/controllers/polls/questions_controller.rb @@ -13,9 +13,6 @@ class Polls::QuestionsController < ApplicationController answer.touch if answer.persisted? answer.save! answer.record_voter_participation(token) - @question.question_answers.where(question_id: @question).each do |question_answer| - question_answer.set_most_voted - end @answers_by_question_id = { @question.id => params[:answer] } end diff --git a/app/helpers/stats_helper.rb b/app/helpers/stats_helper.rb index 57db7166a..5dabd3f82 100644 --- a/app/helpers/stats_helper.rb +++ b/app/helpers/stats_helper.rb @@ -31,4 +31,8 @@ module StatsHelper content_tag :div, "", opt end + def calculate_percentage(fraction, total) + percent = fraction / total.to_f + percent.nan? ? 0.0 : (percent * 100).round(3) + end end diff --git a/app/models/poll/question.rb b/app/models/poll/question.rb index a63e4ec4a..bcdfe68a4 100644 --- a/app/models/poll/question.rb +++ b/app/models/poll/question.rb @@ -59,7 +59,10 @@ class Poll::Question < ApplicationRecord end def answers_total_votes - question_answers.map { |a| Poll::Answer.where(question_id: self, answer: a.title).count }.sum + question_answers.inject(0) { |total, question_answer| total + question_answer.total_votes } end + def most_voted_answer_id + question_answers.max_by { |answer| answer.total_votes }.id + end end diff --git a/app/models/poll/question/answer.rb b/app/models/poll/question/answer.rb index b2434aa3b..cde5e00d1 100644 --- a/app/models/poll/question/answer.rb +++ b/app/models/poll/question/answer.rb @@ -32,22 +32,11 @@ class Poll::Question::Answer < ApplicationRecord end def total_votes - Poll::Answer.where(question_id: question, answer: title).count - end - - def most_voted? - most_voted + Poll::Answer.where(question_id: question, answer: title).count + + ::Poll::PartialResult.where(question: question).where(answer: title).sum(:amount) end def total_votes_percentage question.answers_total_votes.zero? ? 0 : (total_votes * 100.0) / question.answers_total_votes end - - def set_most_voted - answers = question.question_answers - .map { |a| Poll::Answer.where(question_id: a.question, answer: a.title).count } - is_most_voted = answers.none?{ |a| a > total_votes } - - update(most_voted: is_most_voted) - end end diff --git a/app/models/poll/stats.rb b/app/models/poll/stats.rb index 7f12e2a56..fe9560c34 100644 --- a/app/models/poll/stats.rb +++ b/app/models/poll/stats.rb @@ -1,5 +1,6 @@ class Poll class Stats + include StatsHelper def initialize(poll) @poll = poll @@ -26,29 +27,23 @@ class Poll end def total_participants_web_percentage - stats_cache("total_participants_web_percentage") do - total_participants.zero? ? 0 : total_participants_web * 100 / total_participants - end + stats_cache("total_participants_web_percentage") { calculate_percentage(total_participants_web, total_participants) } end def total_participants_booth - stats_cache("total_participants_booth") { voters.where(origin: "booth").count } + stats_cache("total_participants_booth") { total_booth_valid + total_booth_white + total_booth_null } end def total_participants_booth_percentage - stats_cache("total_participants_booth_percentage") do - total_participants.zero? ? 0 : total_participants_booth * 100 / total_participants.to_f - end + stats_cache("total_participants_booth_percentage") { calculate_percentage(total_participants_booth, total_participants) } end def total_web_valid - stats_cache("total_web_valid") { voters.where(origin: "web").count } + stats_cache("total_web_valid") { voters.where(origin: "web").count - total_web_white } end def valid_percentage_web - stats_cache("valid_percentage_web") do - total_valid_votes.zero? ? 0 : total_web_valid * 100 / total_valid_votes.to_f - end + stats_cache("valid_percentage_web") { calculate_percentage(total_web_valid, total_valid_votes) } end def total_web_white @@ -56,7 +51,7 @@ class Poll end def white_percentage_web - stats_cache("white_percentage_web") { 0 } + stats_cache("white_percentage_web") { calculate_percentage(total_web_white, total_white_votes) } end def total_web_null @@ -64,7 +59,7 @@ class Poll end def null_percentage_web - stats_cache("null_percentage_web") { 0 } + stats_cache("null_percentage_web") { calculate_percentage(total_web_null, total_null_votes) } end def total_booth_valid @@ -72,9 +67,7 @@ class Poll end def valid_percentage_booth - stats_cache("valid_percentage_booth") do - total_valid_votes.zero? ? 0 : total_booth_valid * 100 / total_valid_votes.to_f - end + stats_cache("valid_percentage_booth") { calculate_percentage(total_booth_valid, total_valid_votes) } end def total_booth_white @@ -82,9 +75,7 @@ class Poll end def white_percentage_booth - stats_cache("white_percentage_booth") do - total_white_votes.zero? ? 0 : total_booth_white * 100 / total_white_votes.to_f - end + stats_cache("white_percentage_booth") { calculate_percentage(total_booth_white, total_white_votes) } end def total_booth_null @@ -92,9 +83,7 @@ class Poll end def null_percentage_booth - stats_cache("null_percentage_booth") do - total_null_votes.zero? ? 0 : total_booth_null * 100 / total_null_votes.to_f - end + stats_cache("null_percentage_booth") { calculate_percentage(total_booth_null, total_null_votes) } end def total_valid_votes @@ -102,9 +91,7 @@ class Poll end def total_valid_percentage - stats_cache("total_valid_percentage") do - total_participants.zero? ? 0 : total_valid_votes * 100 / total_participants.to_f - end + stats_cache("total_valid_percentage"){ calculate_percentage(total_valid_votes, total_participants) } end def total_white_votes @@ -112,9 +99,7 @@ class Poll end def total_white_percentage - stats_cache("total_white_percentage") do - total_participants.zero? ? 0 : total_white_votes * 100 / total_participants.to_f - end + stats_cache("total_white_percentage") { calculate_percentage(total_white_votes, total_participants) } end def total_null_votes @@ -122,9 +107,7 @@ class Poll end def total_null_percentage - stats_cache("total_null_percentage") do - total_participants.zero? ? 0 : total_null_votes * 100 / total_participants.to_f - end + stats_cache("total_null_percentage") { calculate_percentage(total_null_votes, total_participants) } end def voters diff --git a/app/models/poll/voter.rb b/app/models/poll/voter.rb index 522c28de2..c899cabc9 100644 --- a/app/models/poll/voter.rb +++ b/app/models/poll/voter.rb @@ -1,7 +1,7 @@ class Poll class Voter < ApplicationRecord - VALID_ORIGINS = %w{web booth}.freeze + VALID_ORIGINS = %w[web booth letter].freeze belongs_to :poll belongs_to :user @@ -20,8 +20,9 @@ class Poll before_validation :set_demographic_info, :set_document_info, :set_denormalized_booth_assignment_id - scope :web, -> { where(origin: "web") } - scope :booth, -> { where(origin: "booth") } + scope :web, -> { where(origin: "web") } + scope :booth, -> { where(origin: "booth") } + scope :letter, -> { where(origin: "letter") } def set_demographic_info return if user.blank? diff --git a/app/views/polls/results.html.erb b/app/views/polls/results.html.erb index cafb1c9a9..7627fe018 100644 --- a/app/views/polls/results.html.erb +++ b/app/views/polls/results.html.erb @@ -17,13 +17,14 @@
<%- @poll.questions.each do |question| %> + <% most_voted_answer_id = question.most_voted_answer_id %>

<%= question.title %>

<%- question.question_answers.each do |answer| %> - <%- question.question_answers.each do |answer| %> - diff --git a/app/views/polls/show.html.erb b/app/views/polls/show.html.erb index 2984e16d9..4c33f6b97 100644 --- a/app/views/polls/show.html.erb +++ b/app/views/polls/show.html.erb @@ -59,7 +59,7 @@ -
+
<% @poll_questions_answers.each do |answer| %> diff --git a/spec/features/officing/results_spec.rb b/spec/features/officing/results_spec.rb index d4f9f3621..7ce642e8d 100644 --- a/spec/features/officing/results_spec.rb +++ b/spec/features/officing/results_spec.rb @@ -1,27 +1,27 @@ require "rails_helper" feature "Officing Results", :with_frozen_time do + let(:poll) { create(:poll, ends_at: 1.day.ago) } + let(:booth) { create(:poll_booth) } + let(:poll_officer) { create(:poll_officer) } background do - @poll_officer = create(:poll_officer) - @officer_assignment = create(:poll_officer_assignment, :final, officer: @poll_officer) - create(:poll_shift, officer: @poll_officer, booth: @officer_assignment.booth, date: Date.current) - @poll = @officer_assignment.booth_assignment.poll - @poll.update(ends_at: 1.day.ago) - @question_1 = create(:poll_question, poll: @poll) + create(:poll_booth_assignment, poll: poll, booth: booth) + create(:poll_shift, :recount_scrutiny_task, officer: poll_officer, booth: booth, date: Date.current) + @question_1 = create(:poll_question, poll: poll) create(:poll_question_answer, title: "Yes", question: @question_1, given_order: 1) create(:poll_question_answer, title: "No", question: @question_1, given_order: 2) - @question_2 = create(:poll_question, poll: @poll) + @question_2 = create(:poll_question, poll: poll) create(:poll_question_answer, title: "Today", question: @question_2, given_order: 1) create(:poll_question_answer, title: "Tomorrow", question: @question_2, given_order: 2) - login_as(@poll_officer.user) - set_officing_booth(@officer_assignment.booth) + login_as(poll_officer.user) + set_officing_booth(booth) end scenario "Only polls where user is officer for results are accessible" do - regular_officer_assignment_1 = create(:poll_officer_assignment, officer: @poll_officer) - regular_officer_assignment_2 = create(:poll_officer_assignment, officer: @poll_officer) + regular_officer_assignment_1 = create(:poll_officer_assignment, officer: poll_officer) + regular_officer_assignment_2 = create(:poll_officer_assignment, officer: poll_officer) not_allowed_poll_1 = create(:poll, :expired) not_allowed_poll_2 = regular_officer_assignment_1.booth_assignment.poll @@ -40,7 +40,7 @@ feature "Officing Results", :with_frozen_time do expect(page).not_to have_content(not_allowed_poll_1.name) expect(page).not_to have_content(not_allowed_poll_2.name) expect(page).not_to have_content(not_allowed_poll_3.name) - expect(page).to have_content(@poll.name) + expect(page).to have_content(poll.name) visit new_officing_poll_result_path(not_allowed_poll_1) expect(page).to have_content("You are not allowed to add results for this poll") @@ -53,15 +53,14 @@ feature "Officing Results", :with_frozen_time do click_link "Total recounts and results" end - within("#poll_#{@poll.id}") do - expect(page).to have_content(@poll.name) + within("#poll_#{poll.id}") do + expect(page).to have_content(poll.name) click_link "Add results" end expect(page).not_to have_content("Your results") - booth_name = @officer_assignment.booth_assignment.booth.name - select booth_name, from: "officer_assignment_id" + select booth.name, from: "officer_assignment_id" fill_in "questions[#{@question_1.id}][0]", with: "100" fill_in "questions[#{@question_1.id}][1]", with: "200" @@ -77,27 +76,27 @@ feature "Officing Results", :with_frozen_time do expect(page).to have_content("Your results") - within("#results_#{@officer_assignment.booth_assignment_id}_#{Date.current.strftime("%Y%m%d")}") do + within("#results_#{poll_officer.officer_assignments.first.booth_assignment_id}_#{Date.current.strftime("%Y%m%d")}") do expect(page).to have_content(I18n.l(Date.current, format: :long)) - expect(page).to have_content(booth_name) + expect(page).to have_content(booth.name) end end scenario "Edit result" do partial_result = create(:poll_partial_result, - officer_assignment: @officer_assignment, - booth_assignment: @officer_assignment.booth_assignment, + officer_assignment: poll_officer.officer_assignments.first, + booth_assignment: poll_officer.officer_assignments.first.booth_assignment, date: Date.current, question: @question_1, answer: @question_1.question_answers.first.title, - author: @poll_officer.user, + author: poll_officer.user, amount: 7777) - visit officing_poll_results_path(@poll, date: I18n.l(partial_result.date), booth_assignment_id: partial_result.booth_assignment_id) + visit officing_poll_results_path(poll, date: I18n.l(partial_result.date), booth_assignment_id: partial_result.booth_assignment_id) within("#question_#{@question_1.id}_0_result") { expect(page).to have_content("7777") } - visit new_officing_poll_result_path(@poll) + visit new_officing_poll_result_path(poll) booth_name = partial_result.booth_assignment.booth.name select booth_name, from: "officer_assignment_id" @@ -126,25 +125,25 @@ feature "Officing Results", :with_frozen_time do scenario "Index lists all questions and answers" do partial_result = create(:poll_partial_result, - officer_assignment: @officer_assignment, - booth_assignment: @officer_assignment.booth_assignment, - date: @poll.ends_at, + officer_assignment: poll_officer.officer_assignments.first, + booth_assignment: poll_officer.officer_assignments.first.booth_assignment, + date: poll.ends_at, question: @question_1, amount: 33) poll_recount = create(:poll_recount, - officer_assignment: @officer_assignment, - booth_assignment: @officer_assignment.booth_assignment, - date: @poll.ends_at, + officer_assignment: poll_officer.officer_assignments.first, + booth_assignment: poll_officer.officer_assignments.first.booth_assignment, + date: poll.ends_at, white_amount: 21, null_amount: 44, total_amount: 66) - visit officing_poll_results_path(@poll, - date: I18n.l(@poll.ends_at.to_date), - booth_assignment_id: @officer_assignment.booth_assignment_id) + visit officing_poll_results_path(poll, + date: I18n.l(poll.ends_at.to_date), + booth_assignment_id: poll_officer.officer_assignments.first.booth_assignment_id) - expect(page).to have_content(I18n.l(@poll.ends_at.to_date, format: :long)) - expect(page).to have_content(@officer_assignment.booth_assignment.booth.name) + expect(page).to have_content(I18n.l(poll.ends_at.to_date, format: :long)) + expect(page).to have_content(poll_officer.officer_assignments.first.booth_assignment.booth.name) expect(page).to have_content(@question_1.title) @question_1.question_answers.each_with_index do |answer, i|
> - <% if answer.most_voted %> + > + <% if answer.id == most_voted_answer_id %> <%= t("polls.show.results.most_voted_answer") %> <% end %> <%= answer.title %> @@ -34,7 +35,7 @@
> + > <%= answer.total_votes %> (<%= answer.total_votes_percentage.round(2) %>%)