diff --git a/app/controllers/admin/poll/officer_assignments_controller.rb b/app/controllers/admin/poll/officer_assignments_controller.rb index e34e1a142..3a704b21a 100644 --- a/app/controllers/admin/poll/officer_assignments_controller.rb +++ b/app/controllers/admin/poll/officer_assignments_controller.rb @@ -17,6 +17,7 @@ class Admin::Poll::OfficerAssignmentsController < Admin::BaseController @officer_assignment = ::Poll::OfficerAssignment.new(booth_assignment: @booth_assignment, officer_id: create_params[:officer_id], date: create_params[:date]) + @officer_assignment.final = true if @officer_assignment.date > @booth_assignment.poll.ends_at if @officer_assignment.save notice = t("admin.poll_officer_assignments.flash.create") @@ -48,7 +49,7 @@ class Admin::Poll::OfficerAssignmentsController < Admin::BaseController end def load_booth_assignment - @booth_assignment = ::Poll::BoothAssignment.find_by(poll_id: create_params[:poll_id], booth_id: create_params[:booth_id]) + @booth_assignment = ::Poll::BoothAssignment.includes(:poll).find_by(poll_id: create_params[:poll_id], booth_id: create_params[:booth_id]) end def redirect_if_blank_required_params diff --git a/app/controllers/officing/final_recounts_controller.rb b/app/controllers/officing/final_recounts_controller.rb new file mode 100644 index 000000000..56b0c600e --- /dev/null +++ b/app/controllers/officing/final_recounts_controller.rb @@ -0,0 +1,47 @@ +class Officing::FinalRecountsController < Officing::BaseController + before_action :load_poll + before_action :load_officer_assignment, only: :create + + def new + @officer_assignments = ::Poll::OfficerAssignment. + includes(:final_recounts, booth_assignment: :booth). + joins(:booth_assignment). + final. + where(id: current_user.poll_officer.officer_assignment_ids). + where("poll_booth_assignments.poll_id = ?", @poll.id). + order(date: :asc) + + @final_recounts = @officer_assignments.select {|oa| oa.final_recounts.any?}.map(&:final_recounts).flatten + end + + def create + @final_recount = ::Poll::FinalRecount.find_or_initialize_by(booth_assignment_id: @officer_assignment.booth_assignment_id, date: final_recount_params[:date]) + @final_recount.officer_assignment_id = @officer_assignment.id + @final_recount.count = final_recount_params[:count] + + if @final_recount.save + notice = t("officing.final_recounts.flash.create") + else + notice = t("officing.final_recounts.flash.error_create") + end + redirect_to new_officing_poll_final_recount_path(@poll), notice: notice + end + + private + def load_poll + @poll = Poll.expired.find(params[:poll_id]) + end + + def load_officer_assignment + @officer_assignment = current_user.poll_officer. + officer_assignments.final.find_by(id: final_recount_params[:officer_assignment_id]) + if @officer_assignment.blank? + redirect_to new_officing_poll_final_recount_path(@poll), notice: t("officing.final_recounts.flash.error_create") + end + end + + def final_recount_params + params.permit(:officer_assignment_id, :count, :date) + end + +end \ No newline at end of file diff --git a/app/controllers/officing/polls_controller.rb b/app/controllers/officing/polls_controller.rb index 4841baa39..e122284ec 100644 --- a/app/controllers/officing/polls_controller.rb +++ b/app/controllers/officing/polls_controller.rb @@ -1,8 +1,15 @@ class Officing::PollsController < Officing::BaseController def index - @polls = current_user.poll_officer? ? current_user.poll_officer.assigned_polls : [] + @polls = current_user.poll_officer? ? current_user.poll_officer.voting_days_assigned_polls : [] @polls = @polls.select {|poll| poll.current?(Time.current) || poll.current?(1.day.ago)} end + def final + @polls = current_user.poll_officer? ? current_user.poll_officer.final_days_assigned_polls : [] + return unless current_user.poll_officer? + + @polls = @polls.select {|poll| poll.ends_at > 1.week.ago && poll.expired?} + end + end \ No newline at end of file diff --git a/app/controllers/officing/recounts_controller.rb b/app/controllers/officing/recounts_controller.rb index 0e0a79d69..62e955d5c 100644 --- a/app/controllers/officing/recounts_controller.rb +++ b/app/controllers/officing/recounts_controller.rb @@ -6,6 +6,7 @@ class Officing::RecountsController < Officing::BaseController @officer_assignments = ::Poll::OfficerAssignment. includes(:recount, booth_assignment: :booth). joins(:booth_assignment). + voting_days. where(id: current_user.poll_officer.officer_assignment_ids). where("poll_booth_assignments.poll_id = ?", @poll.id). order(date: :asc) @@ -27,7 +28,7 @@ class Officing::RecountsController < Officing::BaseController private def load_poll - @poll = Poll.current.find(params[:poll_id]) + @poll = Poll.find(params[:poll_id]) end def load_officer_assignment diff --git a/app/helpers/officing_helper.rb b/app/helpers/officing_helper.rb index d1436c515..5ace7ab5f 100644 --- a/app/helpers/officing_helper.rb +++ b/app/helpers/officing_helper.rb @@ -8,4 +8,12 @@ module OfficingHelper options_for_select(options) end + def booths_for_officer_select_options(officer_assignments) + options = [] + officer_assignments.each do |oa| + options << ["#{oa.booth_assignment.booth.name}", oa.id] + end + options_for_select(options) + end + end \ No newline at end of file diff --git a/app/helpers/polls_helper.rb b/app/helpers/polls_helper.rb index ed39f44e5..214234762 100644 --- a/app/helpers/polls_helper.rb +++ b/app/helpers/polls_helper.rb @@ -23,11 +23,16 @@ module PollsHelper def poll_dates_select_options(poll) options = [] (poll.starts_at.to_date..poll.ends_at.to_date).each do |date| - options << [l(date), l(date)] + options << [l(date, format: :long), l(date)] end options_for_select(options) end + def poll_final_recount_option(poll) + final_date = poll.ends_at.to_date + 1.day + options_for_select([[I18n.t("polls.final_date"), l(final_date)]]) + end + def poll_booths_select_options(poll) options = [] poll.booths.each do |booth| diff --git a/app/models/poll/booth_assignment.rb b/app/models/poll/booth_assignment.rb index 9460533fa..057a58d27 100644 --- a/app/models/poll/booth_assignment.rb +++ b/app/models/poll/booth_assignment.rb @@ -5,6 +5,7 @@ class Poll has_many :officer_assignments, class_name: "Poll::OfficerAssignment", dependent: :destroy has_many :recounts, class_name: "Poll::Recount", dependent: :destroy + has_many :final_recounts, class_name: "Poll::FinalRecount", dependent: :destroy has_many :officers, through: :officer_assignments has_many :voters end diff --git a/app/models/poll/final_recount.rb b/app/models/poll/final_recount.rb new file mode 100644 index 000000000..6ebf5eede --- /dev/null +++ b/app/models/poll/final_recount.rb @@ -0,0 +1,19 @@ +class Poll + class FinalRecount < ActiveRecord::Base + belongs_to :booth_assignment, class_name: "Poll::BoothAssignment" + belongs_to :officer_assignment, class_name: "Poll::OfficerAssignment" + + validates :booth_assignment_id, presence: true + validates :date, presence: true, uniqueness: {scope: :booth_assignment_id} + validates :count, presence: true, numericality: {only_integer: true} + + before_save :update_logs + + def update_logs + if self.count_changed? && self.count_was.present? + self.count_log += ":#{self.count_was.to_s}" + self.officer_assignment_id_log += ":#{self.officer_assignment_id_was.to_s}" + end + end + end +end \ No newline at end of file diff --git a/app/models/poll/officer.rb b/app/models/poll/officer.rb index 138a582fc..81a2afd5d 100644 --- a/app/models/poll/officer.rb +++ b/app/models/poll/officer.rb @@ -7,8 +7,15 @@ class Poll delegate :name, :email, to: :user - def assigned_polls - officer_assignments.includes(booth_assignment: :poll). + def voting_days_assigned_polls + officer_assignments.voting_days.includes(booth_assignment: :poll). + map(&:booth_assignment). + map(&:poll).uniq.compact. + sort {|x, y| y.ends_at <=> x.ends_at} + end + + def final_days_assigned_polls + officer_assignments.final.includes(booth_assignment: :poll). map(&:booth_assignment). map(&:poll).uniq.compact. sort {|x, y| y.ends_at <=> x.ends_at} diff --git a/app/models/poll/officer_assignment.rb b/app/models/poll/officer_assignment.rb index 398149977..736deb54b 100644 --- a/app/models/poll/officer_assignment.rb +++ b/app/models/poll/officer_assignment.rb @@ -3,6 +3,7 @@ class Poll belongs_to :officer belongs_to :booth_assignment has_one :recount + has_many :final_recounts has_many :voters validates :officer_id, presence: true @@ -10,5 +11,8 @@ class Poll validates :date, presence: true, uniqueness: { scope: [:officer_id, :booth_assignment_id] } delegate :poll_id, :booth_id, to: :booth_assignment + + scope :voting_days, -> { where(final: false) } + scope :final, -> { where(final: true) } end end diff --git a/app/views/admin/poll/officer_assignments/index.html.erb b/app/views/admin/poll/officer_assignments/index.html.erb index 81ac5aa61..8bac58295 100644 --- a/app/views/admin/poll/officer_assignments/index.html.erb +++ b/app/views/admin/poll/officer_assignments/index.html.erb @@ -11,7 +11,7 @@
<%= select_tag :date, - poll_dates_select_options(@poll), + poll_dates_select_options(@poll) + poll_final_recount_option(@poll), { prompt: t("admin.poll_officer_assignments.index.select_date"), label: false } %>
@@ -51,7 +51,7 @@ <% @officer_assignments.each do |officer_assignment| %> - <%= l officer_assignment.date.to_date %> + <%= officer_assignment.final? ? t('polls.final_date') : l(officer_assignment.date.to_date) %> <%= booth_name_with_location(officer_assignment.booth_assignment.booth) %> <%= link_to t("admin.poll_officer_assignments.index.remove_assignment"), diff --git a/app/views/officing/_menu.html.erb b/app/views/officing/_menu.html.erb index 40484a90a..d6773a426 100644 --- a/app/views/officing/_menu.html.erb +++ b/app/views/officing/_menu.html.erb @@ -8,11 +8,18 @@ <% end %> -
  • > +
  • > <%= link_to officing_polls_path do %> <%= t("officing.menu.recounts") %> <% end %>
  • + +
  • > + <%= link_to final_officing_polls_path do %> + + <%= t("officing.menu.final_recounts") %> + <% end %> +
  • diff --git a/app/views/officing/final_recounts/new.html.erb b/app/views/officing/final_recounts/new.html.erb new file mode 100644 index 000000000..42518cfd9 --- /dev/null +++ b/app/views/officing/final_recounts/new.html.erb @@ -0,0 +1,72 @@ +<% if @officer_assignments.any? %> +

    <%= t("officing.final_recounts.new.title", poll: @poll.name) %>

    + + <%= form_tag(officing_poll_final_recounts_path(@poll), {id: "officer_assignment_form"}) do %> +
    +
    + + <%= select_tag :officer_assignment_id, + booths_for_officer_select_options(@officer_assignments), + { prompt: t("officing.final_recounts.new.select_booth"), + label: false } %> +
    +
    + +
    +
    + + <%= select_tag :date, + poll_dates_select_options(@poll), + { prompt: t("officing.final_recounts.new.select_date"), + label: false } %> +
    +
    + +
    +
    + + <%= text_field_tag :count, nil, placeholder: t("officing.final_recounts.new.count_placeholder") %> +
    +
    + +
    +
    + <%= submit_tag t("officing.final_recounts.new.submit"), class: "button expanded" %> +
    +
    + <% end %> +<% else %> +

    <%= @poll.name %>

    +
    + <%= t("officing.final_recounts.new.not_allowed") %> +
    +<% end %> + + +<% if @final_recounts.any? %> +
    +

    <%= t("officing.final_recounts.new.final_recount_list") %>

    + + + + + + + + + <% @final_recounts.each do |final_recount| %> + + + + + + <% end %> + +
    <%= t("officing.final_recounts.new.date") %><%= t("officing.final_recounts.new.booth") %><%= t("officing.final_recounts.new.count") %>
    + <%= l(final_recount.date.to_date, format: :long) %> + + <%= final_recount.booth_assignment.booth.name %> + + <%= final_recount.count %> +
    +<% end %> \ No newline at end of file diff --git a/app/views/officing/polls/final.html.erb b/app/views/officing/polls/final.html.erb new file mode 100644 index 000000000..7159a3769 --- /dev/null +++ b/app/views/officing/polls/final.html.erb @@ -0,0 +1,30 @@ +

    <%= t("officing.polls.final.title") %>

    + +<% if @polls.any? %> + + + + + + + <% @polls.each do |poll| %> + + + + + <% end %> + +
    <%= t("officing.polls.final.select_poll") %> 
    + + <%= link_to poll.name, new_officing_poll_final_recount_path(poll) %> + + + <%= link_to t("officing.polls.final.add_recount"), + new_officing_poll_final_recount_path(poll), + class: "button hollow" %> +
    +<% else %> +
    + <%= t("officing.polls.final.no_polls") %> +
    +<% end %> \ No newline at end of file diff --git a/config/locales/en.yml b/config/locales/en.yml index a5b671809..edf96a210 100755 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -395,6 +395,7 @@ en: all: "All" no_dates: "no date assigned" dates: "From %{open_at} to %{closed_at}" + final_date: "Final recounts/Results" index: filters: current: "Open" diff --git a/config/locales/es.yml b/config/locales/es.yml index 388cbbbe7..ce5d328c5 100755 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -395,6 +395,7 @@ es: all: "Todas" no_dates: "sin fecha asignada" dates: "Desde el %{open_at} hasta el %{closed_at}" + final_date: "Recuento final/Resultados" index: filters: current: "Abiertas" diff --git a/config/locales/officing.en.yml b/config/locales/officing.en.yml index 4f320a125..c82d3f740 100644 --- a/config/locales/officing.en.yml +++ b/config/locales/officing.en.yml @@ -8,12 +8,18 @@ en: menu: voters: Validate document recounts: Store recount + final_recounts: Final recounts polls: index: title: Poll list no_polls: You are not officing in any active poll select_poll: Select poll add_recount: Add recount + final: + title: Polls ready for final recounting + no_polls: You are not officing final recounts in any active poll + select_poll: Select poll + add_recount: Add final recount recounts: flash: create: "Data added" @@ -29,6 +35,21 @@ en: recount_list: "Your recounts" booth: "Booth" date: "Date" + final_recounts: + flash: + create: "Data added" + error_create: "Final counts NOT added. Error in data." + new: + title: "%{poll} - Add final recount" + not_allowed: "You are allowed to add final recounts for this poll" + booth: "Booth" + date: "Date" + select_booth: "Select booth" + select_date: "Select date" + count: "Vote count" + count_placeholder: "Vote count" + submit: Save + final_recount_list: "Your final recounts" residence: flash: create: "Document verified with Census" diff --git a/config/locales/officing.es.yml b/config/locales/officing.es.yml index 28fc1595d..df91b79ed 100644 --- a/config/locales/officing.es.yml +++ b/config/locales/officing.es.yml @@ -8,12 +8,18 @@ es: menu: voters: "Validar documento" recounts: "Guardar recuento" + final_recounts: "Recuentos finales" polls: index: title: "Listado de votaciones" no_polls: "No eres presidente de mesa en ninguna votación activa" select_poll: "Selecciona votación" add_recount: "Añadir recuento" + final: + title: "Listado de votaciones finalizadas" + no_polls: "No tienes permiso para recuento final en ninguna votación reciente" + select_poll: "Selecciona votación" + add_recount: "Añadir recuentos finales" recounts: flash: create: "Datos añadidos" @@ -29,6 +35,21 @@ es: recount_list: "Tus recuentos" booth: "Urna" date: "Fecha" + final_recounts: + flash: + create: "Datos añadidos" + error_create: "Recuento final NO añadido. Error en los datos" + new: + title: "%{poll} - Añadir recuento final" + not_allowed: "No tienes permiso para introducir recountos finales" + booth: "Urna" + date: "Día" + select_booth: "Elige urna" + select_date: "Elige día" + count: "Número de votos" + count_placeholder: "Número de votos" + submit: "Guardar" + final_recount_list: "Tus recuentos finales" residence: flash: create: "Documento verificado con el Padrón" diff --git a/config/routes.rb b/config/routes.rb index 2a0a157c2..8be55feb5 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -332,7 +332,10 @@ Rails.application.routes.draw do namespace :officing do resources :polls, only: [:index] do + get :final, on: :collection + resources :recounts, only: [:new, :create] + resources :final_recounts, only: [:new, :create] end resource :residence, controller: "residence", only: [:new, :create] resources :voters, only: [:new, :create] diff --git a/db/migrate/20170130101121_create_poll_final_recount.rb b/db/migrate/20170130101121_create_poll_final_recount.rb new file mode 100644 index 000000000..07723b708 --- /dev/null +++ b/db/migrate/20170130101121_create_poll_final_recount.rb @@ -0,0 +1,15 @@ +class CreatePollFinalRecount < ActiveRecord::Migration + def change + create_table :poll_final_recounts do |t| + t.integer :booth_assignment_id + t.integer :officer_assignment_id + t.integer :count + t.text :count_log, default: "" + t.datetime :created_at, null: false + t.datetime :updated_at, null: false + t.text :officer_assignment_id_log, default: "" + end + + add_index :poll_final_recounts, :booth_assignment_id + end +end diff --git a/db/migrate/20170130103550_add_final_to_poll_officer_assignments.rb b/db/migrate/20170130103550_add_final_to_poll_officer_assignments.rb new file mode 100644 index 000000000..4cafb5ffb --- /dev/null +++ b/db/migrate/20170130103550_add_final_to_poll_officer_assignments.rb @@ -0,0 +1,5 @@ +class AddFinalToPollOfficerAssignments < ActiveRecord::Migration + def change + add_column :poll_officer_assignments, :final, :boolean, default: false + end +end diff --git a/db/migrate/20170130133736_add_date_to_final_recount.rb b/db/migrate/20170130133736_add_date_to_final_recount.rb new file mode 100644 index 000000000..14d0f564c --- /dev/null +++ b/db/migrate/20170130133736_add_date_to_final_recount.rb @@ -0,0 +1,5 @@ +class AddDateToFinalRecount < ActiveRecord::Migration + def change + add_column :poll_final_recounts, :date, :datetime, null: false + end +end diff --git a/db/migrate/20170130163030_change_datetimes_to_date_in_recounts_and_assignments.rb b/db/migrate/20170130163030_change_datetimes_to_date_in_recounts_and_assignments.rb new file mode 100644 index 000000000..2ef6d0d5a --- /dev/null +++ b/db/migrate/20170130163030_change_datetimes_to_date_in_recounts_and_assignments.rb @@ -0,0 +1,13 @@ +class ChangeDatetimesToDateInRecountsAndAssignments < ActiveRecord::Migration + def up + change_column :poll_recounts, :date, :date, null: false + change_column :poll_final_recounts, :date, :date, null: false + change_column :poll_officer_assignments, :date, :date, null: false + end + + def down + change_column :poll_recounts, :date, :datetime, null: false + change_column :poll_final_recounts, :date, :datetime, null: false + change_column :poll_officer_assignments, :date, :datetime, null: false + end +end diff --git a/db/schema.rb b/db/schema.rb index 020308da6..88a43f82f 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20170128214244) do +ActiveRecord::Schema.define(version: 20170130163030) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -398,12 +398,26 @@ ActiveRecord::Schema.define(version: 20170128214244) do t.string "location" end + create_table "poll_final_recounts", force: :cascade do |t| + t.integer "booth_assignment_id" + t.integer "officer_assignment_id" + t.integer "count" + t.text "count_log", default: "" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.text "officer_assignment_id_log", default: "" + t.date "date", null: false + end + + add_index "poll_final_recounts", ["booth_assignment_id"], name: "index_poll_final_recounts_on_booth_assignment_id", using: :btree + create_table "poll_officer_assignments", force: :cascade do |t| t.integer "booth_assignment_id" t.integer "officer_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.datetime "date" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.date "date", null: false + t.boolean "final", default: false end create_table "poll_officers", force: :cascade do |t| @@ -451,7 +465,7 @@ ActiveRecord::Schema.define(version: 20170128214244) do t.text "count_log", default: "" t.datetime "created_at", null: false t.datetime "updated_at", null: false - t.datetime "date" + t.date "date", null: false t.text "officer_assignment_id_log", default: "" end @@ -469,8 +483,8 @@ ActiveRecord::Schema.define(version: 20170128214244) do t.string "gender" t.integer "geozone_id" t.integer "answer_id" - t.integer "user_id" t.integer "officer_assignment_id" + t.integer "user_id" end add_index "poll_voters", ["document_number"], name: "index_poll_voters_on_document_number", using: :btree diff --git a/spec/factories.rb b/spec/factories.rb index dc3b4ff58..3ead9bf0e 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -415,6 +415,10 @@ FactoryGirl.define do association :officer, factory: :poll_officer association :booth_assignment, factory: :poll_booth_assignment date Time.current.to_date + + trait :final do + final true + end end factory :poll_recount, class: 'Poll::Recount' do @@ -424,6 +428,13 @@ FactoryGirl.define do date (1.month.ago.to_datetime..1.month.from_now.to_datetime).to_a.sample end + factory :poll_final_recount, class: 'Poll::FinalRecount' do + association :officer_assignment, factory: [:poll_officer_assignment, :final] + association :booth_assignment, factory: :poll_booth_assignment + count (1..100).to_a.sample + date (1.month.ago.to_datetime..1.month.from_now.to_datetime).to_a.sample + end + factory :poll_voter, class: 'Poll::Voter' do poll association :user, :level_two diff --git a/spec/features/admin/poll/officer_assignments_spec.rb b/spec/features/admin/poll/officer_assignments_spec.rb index 3cbf9fb13..53b174b9a 100644 --- a/spec/features/admin/poll/officer_assignments_spec.rb +++ b/spec/features/admin/poll/officer_assignments_spec.rb @@ -30,7 +30,7 @@ feature 'Admin officer assignments in poll' do expect(page).to have_content booth_assignment.poll.name within('#officer_assignment_form') do - select I18n.l(booth_assignment.poll.ends_at.to_date), from: 'date' + select I18n.l(booth_assignment.poll.ends_at.to_date, format: :long), from: 'date' select "#{booth_assignment.booth.name} (#{booth_assignment.booth.location})", from: 'booth_id' click_button 'Add shift' end diff --git a/spec/features/officing/final_recount_spec.rb b/spec/features/officing/final_recount_spec.rb new file mode 100644 index 000000000..770561bb7 --- /dev/null +++ b/spec/features/officing/final_recount_spec.rb @@ -0,0 +1,100 @@ +require 'rails_helper' + +feature 'Officing Final Recount' do + + background do + @poll_officer = create(:poll_officer) + @officer_assignment = create(:poll_officer_assignment, :final, officer: @poll_officer) + @poll = @officer_assignment.booth_assignment.poll + @poll.update(ends_at: 1.day.ago) + login_as(@poll_officer.user) + end + + scenario 'Only polls where user is officer for final recounts 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) + + not_allowed_poll_1 = create(:poll, :expired) + not_allowed_poll_2 = regular_officer_assignment_1.booth_assignment.poll + not_allowed_poll_2.update(ends_at: 1.day.ago) + not_allowed_poll_3 = regular_officer_assignment_2.booth_assignment.poll + + visit root_path + click_link 'Polling officers' + + expect(page).to have_content('Poll officing') + within('#side_menu') do + click_link 'Final recounts' + end + + expect(page).to_not have_content(not_allowed_poll_1.name) + expect(page).to_not have_content(not_allowed_poll_2.name) + expect(page).to_not have_content(not_allowed_poll_3.name) + expect(page).to have_content(@poll.name) + + visit new_officing_poll_final_recount_path(not_allowed_poll_1) + expect(page).to have_content('You are allowed to add final recounts for this poll') + end + + scenario 'Add final recount' do + visit officing_root_path + + within('#side_menu') do + click_link 'Final recounts' + end + + click_link @poll.name + + expect(page).to_not have_content('Your recounts') + + booth_name = @officer_assignment.booth_assignment.booth.name + date = I18n.l(@poll.starts_at.to_date, format: :long) + select booth_name, from: 'officer_assignment_id' + select date, from: 'date' + fill_in :count, with: '33' + click_button 'Save' + + expect(page).to have_content('Your final recounts') + + within("#poll_final_recount_#{@officer_assignment.booth_assignment.final_recounts.first.id}") do + expect(page).to have_content(date) + expect(page).to have_content(booth_name) + expect(page).to have_content('33') + end + end + + scenario 'Edit recount' do + final_recount = create(:poll_final_recount, + officer_assignment: @officer_assignment, + booth_assignment: @officer_assignment.booth_assignment, + date: @poll.starts_at, + count: 100) + + booth_name = @officer_assignment.booth_assignment.booth.name + date = I18n.l(final_recount.date.to_date, format: :long) + + visit new_officing_poll_final_recount_path(@poll) + + expect(page).to have_content('Your final recounts') + + within("#poll_final_recount_#{final_recount.id}") do + expect(page).to have_content(date) + expect(page).to have_content(booth_name) + expect(page).to have_content('100') + end + + select booth_name, from: 'officer_assignment_id' + select date, from: 'date' + fill_in :count, with: '42' + click_button 'Save' + + expect(page).to have_content "Data added" + + within("#poll_final_recount_#{final_recount.id}") do + expect(page).to have_content(date) + expect(page).to have_content(booth_name) + expect(page).to have_content('42') + end + expect(page).to_not have_content('100') + end +end \ No newline at end of file diff --git a/spec/models/poll/final_recount_spec.rb b/spec/models/poll/final_recount_spec.rb new file mode 100644 index 000000000..7239056a5 --- /dev/null +++ b/spec/models/poll/final_recount_spec.rb @@ -0,0 +1,40 @@ +require 'rails_helper' + +describe :final_recount do + + it "should update count_log if count changes" do + final_recount = create(:poll_final_recount, count: 33) + + expect(final_recount.count_log).to eq("") + + final_recount.count = 33 + final_recount.save + final_recount.count = 32 + final_recount.save + final_recount.count = 34 + final_recount.save + + expect(final_recount.count_log).to eq(":33:32") + end + + it "should update officer_assignment_id_log if count changes" do + final_recount = create(:poll_final_recount, count: 33) + + expect(final_recount.count_log).to eq("") + + final_recount.count = 33 + final_recount.officer_assignment_id = 1 + final_recount.save + + final_recount.count = 32 + final_recount.officer_assignment_id = 2 + final_recount.save + + final_recount.count = 34 + final_recount.officer_assignment_id = 3 + final_recount.save + + expect(final_recount.officer_assignment_id_log).to eq(":1:2") + end + +end \ No newline at end of file diff --git a/spec/models/poll/officer_spec.rb b/spec/models/poll/officer_spec.rb index cea0e8bae..83bdbecc2 100644 --- a/spec/models/poll/officer_spec.rb +++ b/spec/models/poll/officer_spec.rb @@ -2,8 +2,8 @@ require 'rails_helper' describe :officer do - describe "#assigned_polls" do - it "should return all polls with this officer assigned" do + describe "#voting_days_assigned_polls" do + it "should return all polls with this officer assigned during voting days" do officer = create(:poll_officer) poll_1 = create(:poll) @@ -18,13 +18,31 @@ describe :officer do create(:poll_officer_assignment, booth_assignment: booth_assignment_1b, officer: officer, date: poll_1.ends_at) create(:poll_officer_assignment, booth_assignment: booth_assignment_2, officer: officer) - assigned_polls = officer.assigned_polls + assigned_polls = officer.voting_days_assigned_polls expect(assigned_polls.size).to eq 2 expect(assigned_polls.include?(poll_1)).to eq(true) expect(assigned_polls.include?(poll_2)).to eq(true) expect(assigned_polls.include?(poll_3)).to eq(false) end + it "should not return polls with this officer assigned for final recount/results" do + officer = create(:poll_officer) + + poll_1 = create(:poll) + poll_2 = create(:poll) + + booth_assignment_1 = create(:poll_booth_assignment, poll: poll_1) + booth_assignment_2 = create(:poll_booth_assignment, poll: poll_2) + + create(:poll_officer_assignment, booth_assignment: booth_assignment_1, officer: officer, date: poll_1.starts_at) + create(:poll_officer_assignment, booth_assignment: booth_assignment_2, officer: officer, final: true) + + assigned_polls = officer.voting_days_assigned_polls + expect(assigned_polls.size).to eq 1 + expect(assigned_polls.include?(poll_1)).to eq(true) + expect(assigned_polls.include?(poll_2)).to eq(false) + end + it "should return polls ordered by end date (desc)" do officer = create(:poll_officer) @@ -36,7 +54,7 @@ describe :officer do create(:poll_officer_assignment, officer: officer, booth_assignment: create(:poll_booth_assignment, poll: p)) end - assigned_polls = officer.assigned_polls + assigned_polls = officer.voting_days_assigned_polls expect(assigned_polls.first).to eq(poll_2) expect(assigned_polls.second).to eq(poll_1) @@ -44,4 +62,63 @@ describe :officer do end end + describe "#final_days_assigned_polls" do + it "should return all polls with this officer assigned for final recount/results" do + officer = create(:poll_officer) + + poll_1 = create(:poll) + poll_2 = create(:poll) + poll_3 = create(:poll) + + booth_assignment_1a = create(:poll_booth_assignment, poll: poll_1) + booth_assignment_1b = create(:poll_booth_assignment, poll: poll_1) + booth_assignment_2 = create(:poll_booth_assignment, poll: poll_2) + + create(:poll_officer_assignment, booth_assignment: booth_assignment_1a, officer: officer, date: poll_1.starts_at, final: true) + create(:poll_officer_assignment, booth_assignment: booth_assignment_1b, officer: officer, date: poll_1.ends_at, final: true) + create(:poll_officer_assignment, booth_assignment: booth_assignment_2, officer: officer, final: true) + + assigned_polls = officer.final_days_assigned_polls + expect(assigned_polls.size).to eq 2 + expect(assigned_polls.include?(poll_1)).to eq(true) + expect(assigned_polls.include?(poll_2)).to eq(true) + expect(assigned_polls.include?(poll_3)).to eq(false) + end + + it "should not return polls with this officer assigned for voting days" do + officer = create(:poll_officer) + + poll_1 = create(:poll) + poll_2 = create(:poll) + + booth_assignment_1 = create(:poll_booth_assignment, poll: poll_1) + booth_assignment_2 = create(:poll_booth_assignment, poll: poll_2) + + create(:poll_officer_assignment, booth_assignment: booth_assignment_1, officer: officer, date: poll_1.starts_at) + create(:poll_officer_assignment, booth_assignment: booth_assignment_2, officer: officer, final: true) + + assigned_polls = officer.final_days_assigned_polls + expect(assigned_polls.size).to eq 1 + expect(assigned_polls.include?(poll_1)).to eq(false) + expect(assigned_polls.include?(poll_2)).to eq(true) + end + + it "should return polls ordered by end date (desc)" do + officer = create(:poll_officer) + + poll_1 = create(:poll, ends_at: 1.day.ago) + poll_2 = create(:poll, ends_at: 10.days.from_now) + poll_3 = create(:poll, ends_at: 10.day.ago) + + [poll_1, poll_2, poll_3].each do |p| + create(:poll_officer_assignment, officer: officer, booth_assignment: create(:poll_booth_assignment, poll: p), final: true) + end + + assigned_polls = officer.final_days_assigned_polls + + expect(assigned_polls.first).to eq(poll_2) + expect(assigned_polls.second).to eq(poll_1) + expect(assigned_polls.last).to eq(poll_3) + end + end end \ No newline at end of file