diff --git a/Gemfile.lock b/Gemfile.lock
index a6437663e..c33459f75 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -199,7 +199,7 @@ GEM
terminal-table (>= 1.5.1)
initialjs-rails (0.2.0.5)
railties (>= 3.1, < 6.0)
- invisible_captcha (0.9.2)
+ invisible_captcha (0.9.3)
rails (>= 3.2.0)
jquery-fileupload-rails (0.4.7)
actionpack (>= 3.1)
@@ -251,7 +251,7 @@ GEM
mime-types-data (3.2016.0521)
mimemagic (0.3.2)
mini_portile2 (2.2.0)
- minitest (5.10.2)
+ minitest (5.10.3)
mixlib-cli (1.7.0)
mixlib-config (2.2.4)
multi_json (1.12.1)
@@ -368,7 +368,7 @@ GEM
rspec-mocks (3.6.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.6.0)
- rspec-rails (3.6.0)
+ rspec-rails (3.6.1)
actionpack (>= 3.0)
activesupport (>= 3.0)
railties (>= 3.0)
@@ -398,7 +398,7 @@ GEM
sprockets (>= 2.8, < 4.0)
sprockets-rails (>= 2.0, < 4.0)
tilt (>= 1.1, < 3)
- savon (2.11.1)
+ savon (2.11.2)
akami (~> 1.2)
builder (>= 2.1.2)
gyoku (~> 1.2)
@@ -430,7 +430,7 @@ GEM
babel-source (>= 5.8.11)
babel-transpiler
sprockets (>= 3.0.0)
- sprockets-rails (3.2.0)
+ sprockets-rails (3.2.1)
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets (>= 3.0.0)
@@ -565,6 +565,5 @@ DEPENDENCIES
web-console (~> 3.3.0)
whenever (~> 0.9.7)
-
BUNDLED WITH
1.15.3
diff --git a/app/assets/images/help/help_icon_budgets.png b/app/assets/images/help/help_icon_budgets.png
index f8a909d7e..fc5e3022f 100644
Binary files a/app/assets/images/help/help_icon_budgets.png and b/app/assets/images/help/help_icon_budgets.png differ
diff --git a/app/assets/images/help/help_icon_debates.png b/app/assets/images/help/help_icon_debates.png
index c8d59e4c1..afc729671 100644
Binary files a/app/assets/images/help/help_icon_debates.png and b/app/assets/images/help/help_icon_debates.png differ
diff --git a/app/assets/images/help/help_icon_legislation_processes.png b/app/assets/images/help/help_icon_legislation_processes.png
index 9dd93ad8c..00872c247 100644
Binary files a/app/assets/images/help/help_icon_legislation_processes.png and b/app/assets/images/help/help_icon_legislation_processes.png differ
diff --git a/app/assets/images/help/help_icon_polls.png b/app/assets/images/help/help_icon_polls.png
index 503f8642d..b7f7cf479 100644
Binary files a/app/assets/images/help/help_icon_polls.png and b/app/assets/images/help/help_icon_polls.png differ
diff --git a/app/assets/images/help/help_icon_proposals.png b/app/assets/images/help/help_icon_proposals.png
index 05861d042..e41db1cf8 100644
Binary files a/app/assets/images/help/help_icon_proposals.png and b/app/assets/images/help/help_icon_proposals.png differ
diff --git a/app/assets/images/logo_header.png b/app/assets/images/logo_header.png
index 9bce3cef8..c178ec781 100644
Binary files a/app/assets/images/logo_header.png and b/app/assets/images/logo_header.png differ
diff --git a/app/assets/stylesheets/participation.scss b/app/assets/stylesheets/participation.scss
index 1683c2231..e10c0327f 100644
--- a/app/assets/stylesheets/participation.scss
+++ b/app/assets/stylesheets/participation.scss
@@ -894,17 +894,10 @@
}
}
-.help-link {
- margin-left: $line-height;
- position: relative;
+.help-header {
- &::before {
- color: $link;
- content: '\4e';
- font-family: 'icons';
- position: absolute;
- left: -24px;
- top: -2px;
+ h1 {
+ font-size: rem-calc(24);
}
}
diff --git a/app/controllers/admin/poll/officer_assignments_controller.rb b/app/controllers/admin/poll/officer_assignments_controller.rb
index 1f2a7ca2c..45c9a225a 100644
--- a/app/controllers/admin/poll/officer_assignments_controller.rb
+++ b/app/controllers/admin/poll/officer_assignments_controller.rb
@@ -32,35 +32,6 @@ class Admin::Poll::OfficerAssignmentsController < Admin::BaseController
end
end
- def create
- @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.to_date
-
- if @officer_assignment.save
- notice = t("admin.poll_officer_assignments.flash.create")
- else
- notice = t("admin.poll_officer_assignments.flash.error_create")
- end
-
- redirect_params = { poll_id: create_params[:poll_id], officer_id: create_params[:officer_id] }
- redirect_to by_officer_admin_poll_officer_assignments_path(redirect_params), notice: notice
- end
-
- def destroy
- @officer_assignment = ::Poll::OfficerAssignment.includes(:booth_assignment).find(params[:id])
-
- if @officer_assignment.destroy
- notice = t("admin.poll_officer_assignments.flash.destroy")
- else
- notice = t("admin.poll_officer_assignments.flash.error_destroy")
- end
-
- redirect_params = { poll_id: @officer_assignment.poll_id, officer_id: @officer_assignment.officer_id }
- redirect_to by_officer_admin_poll_officer_assignments_path(redirect_params), notice: notice
- end
-
private
def officer_assignment_params
diff --git a/app/controllers/admin/poll/shifts_controller.rb b/app/controllers/admin/poll/shifts_controller.rb
new file mode 100644
index 000000000..8a808a7a9
--- /dev/null
+++ b/app/controllers/admin/poll/shifts_controller.rb
@@ -0,0 +1,53 @@
+class Admin::Poll::ShiftsController < Admin::BaseController
+
+ before_action :load_booth
+ before_action :load_polls
+
+ def new
+ load_officers
+ load_shifts
+ @shift = ::Poll::Shift.new
+ end
+
+ def create
+ @shift = ::Poll::Shift.new(shift_params)
+ if @shift.save
+ notice = t("admin.poll_shifts.flash.create")
+ redirect_to new_admin_booth_shift_path(@shift.booth), notice: notice
+ else
+ load_officers
+ load_shifts
+ render :new
+ end
+ end
+
+ def destroy
+ @shift = Poll::Shift.find(params[:id])
+ @shift.destroy
+ notice = t("admin.poll_shifts.flash.destroy")
+ redirect_to new_admin_booth_shift_path(@booth), notice: notice
+ end
+
+ private
+
+ def load_booth
+ @booth = ::Poll::Booth.find(params[:booth_id])
+ end
+
+ def load_polls
+ @polls = ::Poll.current_or_incoming
+ end
+
+ def load_officers
+ @officers = ::Poll::Officer.all
+ end
+
+ def load_shifts
+ @shifts = @booth.shifts
+ end
+
+ def shift_params
+ params.require(:shift).permit(:booth_id, :officer_id, :date)
+ end
+
+end
\ No newline at end of file
diff --git a/app/helpers/shifts_helper.rb b/app/helpers/shifts_helper.rb
new file mode 100644
index 000000000..37f22a3e2
--- /dev/null
+++ b/app/helpers/shifts_helper.rb
@@ -0,0 +1,23 @@
+module ShiftsHelper
+
+ def shift_dates_select_options(polls)
+ options = []
+ (start_date(polls)..end_date(polls)).each do |date|
+ options << [l(date, format: :long), l(date)]
+ end
+ options_for_select(options, params[:date])
+ end
+
+ def start_date(polls)
+ polls.map(&:starts_at).min.to_date
+ end
+
+ def end_date(polls)
+ polls.map(&:ends_at).max.to_date
+ end
+
+ def officer_select_options(officers)
+ officers.collect { |officer| [officer.name, officer.id] }
+ end
+
+end
diff --git a/app/models/poll.rb b/app/models/poll.rb
index 6d033f514..4ba313963 100644
--- a/app/models/poll.rb
+++ b/app/models/poll.rb
@@ -35,6 +35,10 @@ class Poll < ActiveRecord::Base
ends_at < timestamp
end
+ def self.current_or_incoming
+ current + incoming
+ end
+
def answerable_by?(user)
user.present? &&
user.level_two_or_three_verified? &&
diff --git a/app/models/poll/booth.rb b/app/models/poll/booth.rb
index c7fb63efc..9edbcbaf0 100644
--- a/app/models/poll/booth.rb
+++ b/app/models/poll/booth.rb
@@ -2,6 +2,7 @@ class Poll
class Booth < ActiveRecord::Base
has_many :booth_assignments, class_name: "Poll::BoothAssignment"
has_many :polls, through: :booth_assignments
+ has_many :shifts
validates :name, presence: true, uniqueness: true
diff --git a/app/models/poll/shift.rb b/app/models/poll/shift.rb
new file mode 100644
index 000000000..8ee646ea4
--- /dev/null
+++ b/app/models/poll/shift.rb
@@ -0,0 +1,22 @@
+class Poll
+ class Shift < ActiveRecord::Base
+ belongs_to :booth
+ belongs_to :officer
+
+ validates :booth_id, presence: true
+ validates :officer_id, presence: true
+ validates :date, presence: true
+ validates :date, uniqueness: { scope: [:officer_id, :booth_id] }
+
+ after_create :create_officer_assignments
+
+ def create_officer_assignments
+ booth.booth_assignments.each do |booth_assignment|
+ attrs = { officer_id: officer_id,
+ date: date,
+ booth_assignment_id: booth_assignment.id }
+ Poll::OfficerAssignment.create!(attrs)
+ end
+ end
+ end
+ end
\ No newline at end of file
diff --git a/app/views/admin/_menu.html.erb b/app/views/admin/_menu.html.erb
index 62638f3b7..b42e717b4 100644
--- a/app/views/admin/_menu.html.erb
+++ b/app/views/admin/_menu.html.erb
@@ -73,9 +73,13 @@
<%= link_to t('admin.menu.poll_officers'), admin_officers_path %>
-
>
+ >
<%= link_to t('admin.menu.poll_booths'), admin_booths_path %>
+
+ >
+ <%= link_to t('admin.menu.poll_shifts'), admin_booths_path %>
+
<% end %>
diff --git a/app/views/admin/poll/booths/_booth.html.erb b/app/views/admin/poll/booths/_booth.html.erb
index 5732400a8..80b1ef38f 100644
--- a/app/views/admin/poll/booths/_booth.html.erb
+++ b/app/views/admin/poll/booths/_booth.html.erb
@@ -6,6 +6,9 @@
<%= booth.location %>
+ <%= link_to t("admin.booths.booth.shifts"),
+ new_admin_booth_shift_path(booth),
+ class: "button hollow" %>
<%= link_to t("admin.actions.edit"),
edit_admin_booth_path(booth),
class: "button hollow" %>
diff --git a/app/views/admin/poll/booths/index.html.erb b/app/views/admin/poll/booths/index.html.erb
index 9618aec59..0dbb62cdf 100644
--- a/app/views/admin/poll/booths/index.html.erb
+++ b/app/views/admin/poll/booths/index.html.erb
@@ -16,6 +16,7 @@
<%= t("admin.booths.index.name") %>
<%= t("admin.booths.index.location") %>
+
<% @booths.each do |booth| %>
diff --git a/app/views/admin/poll/officer_assignments/by_officer.html.erb b/app/views/admin/poll/officer_assignments/by_officer.html.erb
index 6e505040e..8cc6c0437 100644
--- a/app/views/admin/poll/officer_assignments/by_officer.html.erb
+++ b/app/views/admin/poll/officer_assignments/by_officer.html.erb
@@ -5,35 +5,6 @@
<%= @officer.name %> - <%= @officer.email %>
-<%= form_tag(admin_poll_officer_assignments_path(@poll), {id: "officer_assignment_form"}) do %>
-
- <%= t("admin.poll_officer_assignments.by_officer.new_assignment") %>
-
- <%= t("admin.poll_officer_assignments.by_officer.date") %>
- <%= select_tag :date,
- poll_dates_select_options(@poll) + poll_final_recount_option(@poll),
- { prompt: t("admin.poll_officer_assignments.by_officer.select_date"),
- label: false } %>
-
-
-
- <%= t("admin.poll_officer_assignments.by_officer.booth") %>
- <%= select_tag :booth_id,
- poll_booths_select_options(@poll),
- { prompt: t("admin.poll_officer_assignments.by_officer.select_booth"),
- label: false } %>
-
-
-
- <%= hidden_field_tag :officer_id, @officer.id %>
- <%= hidden_field_tag :poll_id, @poll.id %>
- <%= submit_tag t("admin.poll_officer_assignments.by_officer.add_assignment"),
- class: "button expanded hollow margin-top" %>
-
-
-<% end %>
-
-
<% if @officer_assignments.empty? %>
<%= t("admin.poll_officer_assignments.by_officer.no_assignments") %>
@@ -45,7 +16,6 @@
<%= t("admin.poll_officer_assignments.by_officer.date") %>
<%= t("admin.poll_officer_assignments.by_officer.booth") %>
- <%= t("admin.poll_officer_assignments.by_officer.assignment") %>
@@ -53,12 +23,6 @@
<%= 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.by_officer.remove_assignment"),
- admin_poll_officer_assignment_path(@poll, officer_assignment),
- method: :delete,
- class: "button hollow alert" %>
-
<% end %>
@@ -93,6 +57,3 @@
<% end %>
-
-
-
diff --git a/app/views/admin/poll/shifts/_shifts.html.erb b/app/views/admin/poll/shifts/_shifts.html.erb
new file mode 100644
index 000000000..800c6944b
--- /dev/null
+++ b/app/views/admin/poll/shifts/_shifts.html.erb
@@ -0,0 +1,24 @@
+<%= t("admin.poll_shifts.new.assignments") %>
+
+
+
+ <%= t("admin.poll_shifts.new.date") %>
+ <%= t("admin.poll_shifts.new.officer") %>
+ <%= t("admin.poll_shifts.new.assignment") %>
+
+
+
+ <% @shifts.each do |shift| %>
+
+ <%= l(shift.date.to_date, format: :long) %>
+ <%= shift.officer.name %>
+
+ <%= link_to t("admin.poll_shifts.new.remove_assignment"),
+ admin_booth_shift_path(@booth, shift),
+ method: :delete,
+ class: "button hollow alert" %>
+
+
+ <% end %>
+
+
diff --git a/app/views/admin/poll/shifts/new.html.erb b/app/views/admin/poll/shifts/new.html.erb
new file mode 100644
index 000000000..c997dc35f
--- /dev/null
+++ b/app/views/admin/poll/shifts/new.html.erb
@@ -0,0 +1,46 @@
+<%= back_link_to admin_booths_path %>
+
+<%= @booth.name %>
+
+<%= form_for @shift, as: :shift, url: admin_booth_shifts_path do |f| %>
+ <%= render "shared/errors", resource: @shift %>
+
+
+
+ <%= t("admin.poll_shifts.new.new_assignment") %>
+
+
+
+ <%= t("admin.poll_shifts.new.date") %>
+ <%= f.select :date,
+ shift_dates_select_options(@polls),
+ prompt: t("admin.poll_shifts.new.select_date"),
+ label: false %>
+
+
+
+ <%= t("admin.poll_shifts.new.officer") %>
+ <%= f.select :officer_id,
+ officer_select_options(@officers),
+ prompt: t("admin.poll_shifts.new.select_officer"),
+ label: false %>
+
+
+ <%= f.hidden_field :booth_id, value: @booth.id %>
+
+
+ <%= f.submit t("admin.poll_shifts.new.add_assignment"),
+ class: "button expanded hollow margin-top" %>
+
+
+<% end %>
+
+
+ <% if @shifts.empty? %>
+
+ <%= t("admin.poll_shifts.new.no_assignments") %>
+
+ <% else %>
+ <%= render "shifts" %>
+ <% end %>
+
\ No newline at end of file
diff --git a/app/views/shared/_section_header.html.erb b/app/views/shared/_section_header.html.erb
index 29688b487..ca0476bb9 100644
--- a/app/views/shared/_section_header.html.erb
+++ b/app/views/shared/_section_header.html.erb
@@ -1,10 +1,12 @@
-
+
diff --git a/config/locales/en/admin.yml b/config/locales/en/admin.yml
index 7b77ab8d0..c91719104 100644
--- a/config/locales/en/admin.yml
+++ b/config/locales/en/admin.yml
@@ -403,6 +403,7 @@ en:
poll_officers: Poll officers
polls: Polls
poll_booths: Booths location
+ poll_shifts: Manage shifts
officials: Officials
organizations: Organisations
settings: Configuration settings
@@ -481,11 +482,6 @@ en:
search: Search
user_not_found: User not found
poll_officer_assignments:
- flash:
- destroy: "Officing shift removed"
- create: "Officing shift added"
- error_destroy: "An error ocurred when removing officer assignment"
- error_create: "An error ocurred when adding officer assignment"
index:
officers_title: "List of officers"
no_officers: "There are no officers assigned to this poll."
@@ -494,18 +490,27 @@ en:
add_officer_assignments: "Add shifts as officer"
edit_officer_assignments: "Edit officing shifts"
by_officer:
- new_assignment: "New shift"
date: "Date"
booth: "Booth"
- assignment: "Assignment"
- select_date: "Select day"
- select_booth: "Select booth"
- add_assignment: "Add shift"
- remove_assignment: "Remove"
assignments: "Officing shifts in this poll"
no_assignments: "This user has no officing shifts in this poll."
final_recounts: "Final recounts"
final_recount: "Final recount (by officer)"
+ poll_shifts:
+ new:
+ new_assignment: "New shift"
+ date: "Date"
+ officer: "Officer"
+ assignment: "Assignment"
+ select_date: "Select day"
+ select_officer: "Select officer"
+ add_assignment: "Add shift"
+ remove_assignment: "Remove"
+ assignments: "Shifts in this booth"
+ no_assignments: "This booth has no shifts"
+ flash:
+ create: "Shift added"
+ destroy: "Shift removed"
poll_booth_assignments:
flash:
destroy: "Booth not assigned anymore"
@@ -618,6 +623,8 @@ en:
submit_button: "Update booth"
show:
location: "Location"
+ booth:
+ shifts: "Manage shifts"
officials:
edit:
destroy: Remove 'Official' status
diff --git a/config/locales/es/admin.yml b/config/locales/es/admin.yml
index 0e6ae8dfa..58fd31aa1 100644
--- a/config/locales/es/admin.yml
+++ b/config/locales/es/admin.yml
@@ -414,6 +414,7 @@ es:
poll_officers: Presidentes de mesa
polls: Votaciones
poll_booths: Ubicación de urnas
+ poll_shifts: Asignar turnos
officials: Cargos públicos
organizations: Organizaciones
settings: Configuración global
@@ -481,11 +482,6 @@ es:
search: Buscar
user_not_found: Usuario no encontrado
poll_officer_assignments:
- flash:
- destroy: "Eliminado turno de presidente de mesa"
- create: "Añadido turno de presidente de mesa"
- error_destroy: "Se ha producido un error al eliminar el turno"
- error_create: "Se ha producido un error al intentar crear el turno"
index:
officers_title: "Listado de presidentes de mesa asignados"
no_officers: "No hay presidentes de mesa asignados a esta votación."
@@ -494,18 +490,27 @@ es:
add_officer_assignments: "Añadir turnos como presidente de mesa"
edit_officer_assignments: "Editar turnos"
by_officer:
- new_assignment: "Nuevo turno"
date: "Fecha"
booth: "Urna"
- assignment: "Asignación"
- select_date: "Seleccionar día"
- select_booth: "Seleccionar urna"
- add_assignment: "Añadir turno"
- remove_assignment: "Eliminar turno"
assignments: "Turnos como presidente de mesa en esta votación"
no_assignments: "No tiene turnos como presidente de mesa en esta votación."
final_recounts: "Recuentos finales"
final_recount: "Recuento final (presidente de mesa)"
+ poll_shifts:
+ new:
+ new_assignment: "Nuevo turno"
+ date: "Fecha"
+ officer: "Presidente de mesa"
+ assignment: "Asignación"
+ select_date: "Seleccionar día"
+ select_officer: "Seleccionar presidente de mesa"
+ add_assignment: "Añadir turno"
+ remove_assignment: "Eliminar turno"
+ assignments: "Turnos en esta urna"
+ no_assignments: "Esta urna no tiene turnos asignados"
+ flash:
+ create: "Añadido turno de presidente de mesa"
+ destroy: "Eliminado turno de presidente de mesa"
poll_booth_assignments:
flash:
destroy: "Urna desasignada"
@@ -618,6 +623,8 @@ es:
submit_button: "Actualizar urna"
show:
location: "Ubicación"
+ booth:
+ shifts: "Asignar turnos"
officials:
edit:
destroy: Eliminar condición de 'Cargo Público'
diff --git a/config/routes.rb b/config/routes.rb
index 00985071a..eaf6b98f4 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -286,7 +286,10 @@ Rails.application.routes.draw do
get :search, on: :collection
end
- resources :booths
+ resources :booths do
+ resources :shifts
+ end
+
resources :questions
end
diff --git a/db/migrate/20170724190805_create_poll_shifts.rb b/db/migrate/20170724190805_create_poll_shifts.rb
new file mode 100644
index 000000000..8bb6eafd7
--- /dev/null
+++ b/db/migrate/20170724190805_create_poll_shifts.rb
@@ -0,0 +1,15 @@
+class CreatePollShifts < ActiveRecord::Migration
+ def change
+ create_table :poll_shifts do |t|
+ t.integer :booth_id
+ t.integer :officer_id
+ t.date :date
+
+ t.timestamps
+ end
+
+ add_index :poll_shifts, :booth_id
+ add_index :poll_shifts, :officer_id
+ add_index :poll_shifts, [:booth_id, :officer_id]
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 043e0db7e..b87332817 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -676,6 +676,18 @@ ActiveRecord::Schema.define(version: 20170822144743) do
add_index "poll_questions", ["proposal_id"], name: "index_poll_questions_on_proposal_id", using: :btree
add_index "poll_questions", ["tsv"], name: "index_poll_questions_on_tsv", using: :gin
+ create_table "poll_shifts", force: :cascade do |t|
+ t.integer "booth_id"
+ t.integer "officer_id"
+ t.date "date"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ end
+
+ add_index "poll_shifts", ["booth_id", "officer_id"], name: "index_poll_shifts_on_booth_id_and_officer_id", using: :btree
+ add_index "poll_shifts", ["booth_id"], name: "index_poll_shifts_on_booth_id", using: :btree
+ add_index "poll_shifts", ["officer_id"], name: "index_poll_shifts_on_officer_id", using: :btree
+
create_table "poll_voters", force: :cascade do |t|
t.string "document_number"
t.string "document_type"
diff --git a/spec/factories.rb b/spec/factories.rb
index 2817dfa2d..226723fe3 100644
--- a/spec/factories.rb
+++ b/spec/factories.rb
@@ -449,6 +449,11 @@ FactoryGirl.define do
starts_at { 1.month.ago }
ends_at { 1.month.from_now }
+ trait :current do
+ starts_at { 2.days.ago }
+ ends_at { 2.days.from_now }
+ end
+
trait :incoming do
starts_at { 2.days.from_now }
ends_at { 1.month.from_now }
@@ -492,6 +497,12 @@ FactoryGirl.define do
end
end
+ factory :poll_shift, class: 'Poll::Shift' do
+ association :booth, factory: :poll_booth
+ association :officer, factory: :poll_officer
+ date Date.current
+ end
+
factory :poll_final_recount, class: 'Poll::FinalRecount' do
association :officer_assignment, factory: [:poll_officer_assignment, :final]
association :booth_assignment, factory: :poll_booth_assignment
diff --git a/spec/features/admin/poll/officer_assignments_spec.rb b/spec/features/admin/poll/officer_assignments_spec.rb
deleted file mode 100644
index 08cbd3f99..000000000
--- a/spec/features/admin/poll/officer_assignments_spec.rb
+++ /dev/null
@@ -1,91 +0,0 @@
-require 'rails_helper'
-
-feature 'Admin officer assignments in poll' do
-
- background do
- admin = create(:administrator)
- login_as(admin.user)
- end
-
- scenario 'Assign officer to poll', :js do
- booth_assignment = create(:poll_booth_assignment)
- officer = create(:poll_officer)
-
- visit admin_poll_path(booth_assignment.poll)
- within('#poll-resources') do
- click_link 'Officers (0)'
- end
-
- expect(page).to have_content 'There are no officers assigned to this poll'
-
- fill_in 'search-officers', with: officer.name
- click_button 'Search'
-
- within('#search-officers-results') do
- click_link 'Add shifts as officer'
- end
-
- expect(page).to have_content 'This user has no officing shifts in this poll'
- expect(page).to have_content officer.name
- expect(page).to have_content booth_assignment.poll.name
-
- within('#officer_assignment_form') do
- 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
-
- expect(page).to have_content 'Officing shift added'
- expect(page).to_not have_content 'This user has no officing shifts in this poll'
-
- visit admin_poll_path(booth_assignment.poll)
- within('#poll-resources') do
- click_link 'Officers (1)'
- end
-
- expect(page).to_not have_content 'There are no officers in this poll'
- expect(page).to have_content officer.name
- expect(page).to have_content officer.email
- end
-
- scenario 'Remove officer assignment from poll' do
- officer_assignment = create(:poll_officer_assignment)
- poll = officer_assignment.booth_assignment.poll
- booth = officer_assignment.booth_assignment.booth
- officer = officer_assignment.officer
-
- visit by_officer_admin_poll_officer_assignments_path(poll, officer_id: officer.id)
-
- expect(page).to_not have_content 'This user has no officing shifts in this poll'
- within("#poll_officer_assignment_#{officer_assignment.id}") do
- expect(page).to have_content booth.name
- click_link 'Remove'
- end
-
- expect(page).to have_content 'Officing shift removed'
- expect(page).to have_content 'This user has no officing shifts in this poll'
- end
-
- scenario 'Index view shows recounts info for officer' do
- booth_assignment = create(:poll_booth_assignment)
- poll = booth_assignment.poll
- officer = create(:poll_officer)
- create(:poll_officer_assignment,
- booth_assignment: booth_assignment,
- officer: officer,
- date: poll.starts_at)
- final_officer_assignment = create(:poll_officer_assignment, :final,
- booth_assignment: booth_assignment,
- officer: officer,
- date: poll.ends_at + 1.day)
- create(:poll_final_recount,
- booth_assignment: booth_assignment,
- officer_assignment: final_officer_assignment,
- date: poll.ends_at,
- count: 9876)
-
- visit by_officer_admin_poll_officer_assignments_path(poll, officer_id: officer.id)
-
- within('#final_recount_list') { expect(page).to have_content('9876') }
- end
-end
diff --git a/spec/features/admin/poll/shifts_spec.rb b/spec/features/admin/poll/shifts_spec.rb
new file mode 100644
index 000000000..fd9b9f4ca
--- /dev/null
+++ b/spec/features/admin/poll/shifts_spec.rb
@@ -0,0 +1,88 @@
+require 'rails_helper'
+
+feature 'Admin shifts' do
+
+ background do
+ admin = create(:administrator)
+ login_as(admin.user)
+ end
+
+ scenario "Show" do
+ poll = create(:poll)
+ officer = create(:poll_officer)
+
+ booth1 = create(:poll_booth)
+ booth2 = create(:poll_booth)
+
+ shift1 = create(:poll_shift, officer: officer, booth: booth1, date: Date.today)
+ shift2 = create(:poll_shift, officer: officer, booth: booth2, date: Date.tomorrow)
+
+ visit new_admin_booth_shift_path(booth1)
+
+ expect(page).to have_css(".shift", count: 1)
+ expect(page).to have_content I18n.l(Date.today, format: :long)
+ expect(page).to have_content officer.name
+
+ visit new_admin_booth_shift_path(booth2)
+
+ expect(page).to have_css(".shift", count: 1)
+ expect(page).to have_content I18n.l(Date.tomorrow, format: :long)
+ expect(page).to have_content officer.name
+ end
+
+ scenario "Create" do
+ poll = create(:poll)
+ booth = create(:poll_booth)
+ officer = create(:poll_officer)
+
+ visit admin_booths_path
+
+ within("#booth_#{booth.id}") do
+ click_link "Manage shifts"
+ end
+
+ select I18n.l(poll.starts_at.to_date, format: :long), from: 'shift_date'
+ select officer.name, from: 'shift_officer_id'
+ click_button "Add shift"
+
+ expect(page).to have_content "Shift added"
+
+ within("#shifts") do
+ expect(page).to have_css(".shift", count: 1)
+ expect(page).to have_content(I18n.l(poll.starts_at.to_date, format: :long))
+ expect(page).to have_content(officer.name)
+ end
+ end
+
+ scenario "Destroy" do
+ poll = create(:poll)
+ booth = create(:poll_booth)
+ officer = create(:poll_officer)
+
+ shift = create(:poll_shift, officer: officer, booth: booth)
+
+ visit admin_booths_path
+
+ within("#booth_#{booth.id}") do
+ click_link "Manage shifts"
+ end
+
+ expect(page).to have_css(".shift", count: 1)
+ within("#shift_#{shift.id}") do
+ click_link "Remove"
+ end
+
+ expect(page).to have_content "Shift removed"
+ expect(page).to have_css(".shift", count: 0)
+ end
+
+ scenario "Empty" do
+ poll = create(:poll)
+ booth = create(:poll_booth)
+
+ visit new_admin_booth_shift_path(booth)
+
+ expect(page).to have_content "This booth has no shifts"
+ end
+
+end
diff --git a/spec/models/poll/poll_spec.rb b/spec/models/poll/poll_spec.rb
index 61f9fce52..2eb78841b 100644
--- a/spec/models/poll/poll_spec.rb
+++ b/spec/models/poll/poll_spec.rb
@@ -62,6 +62,20 @@ describe :poll do
end
end
+ describe "#current_or_incoming" do
+ it "returns current or incoming polls" do
+ current = create(:poll, :current)
+ incoming = create(:poll, :incoming)
+ expired = create(:poll, :expired)
+
+ current_or_incoming = Poll.current_or_incoming
+
+ expect(current_or_incoming).to include(current)
+ expect(current_or_incoming).to include(incoming)
+ expect(current_or_incoming).to_not include(expired)
+ end
+ end
+
describe "#document_has_voted?" do
it "returns true if Poll::Voter with document exists" do
poll = create(:poll)
diff --git a/spec/models/poll/shift_spec.rb b/spec/models/poll/shift_spec.rb
new file mode 100644
index 000000000..e70b5f9a0
--- /dev/null
+++ b/spec/models/poll/shift_spec.rb
@@ -0,0 +1,61 @@
+require 'rails_helper'
+
+describe :shift do
+ let(:shift) { build(:poll_shift) }
+
+ describe "validations" do
+
+ it "should be valid" do
+ expect(shift).to be_valid
+ end
+
+ it "should not be valid without a booth" do
+ shift.booth = nil
+ expect(shift).to_not be_valid
+ end
+
+ it "should not be valid without an officer" do
+ shift.officer = nil
+ expect(shift).to_not be_valid
+ end
+
+ it "should not be valid without a date" do
+ shift.date = nil
+ expect(shift).to_not be_valid
+ end
+
+ end
+
+ describe "officer_assignments" do
+
+ it "should create corresponding officer_assignments" do
+ poll1 = create(:poll)
+ poll2 = create(:poll)
+ poll3 = create(:poll)
+
+ booth = create(:poll_booth)
+ officer = create(:poll_officer)
+
+ booth_assignment1 = create(:poll_booth_assignment, poll: poll1, booth: booth)
+ booth_assignment2 = create(:poll_booth_assignment, poll: poll2, booth: booth)
+
+ shift = create(:poll_shift, booth: booth, officer: officer, date: Date.current)
+
+ officer_assignments = Poll::OfficerAssignment.all
+ expect(officer_assignments.count).to eq(2)
+
+ oa1 = officer_assignments.first
+ oa2 = officer_assignments.second
+
+ expect(oa1.officer).to eq(officer)
+ expect(oa1.date).to eq(Date.current)
+ expect(oa1.booth_assignment).to eq(booth_assignment1)
+
+ expect(oa2.officer).to eq(officer)
+ expect(oa2.date).to eq(Date.current)
+ expect(oa2.booth_assignment).to eq(booth_assignment2)
+ end
+
+ end
+
+end