Merge branch 'master' into proposal-dashboard

This commit is contained in:
decabeza
2019-04-04 14:08:30 +02:00
59 changed files with 1023 additions and 196 deletions

View File

@@ -22,10 +22,11 @@ env:
global:
- KNAPSACK_PRO_FIXED_QUEUE_SPLIT=true
- KNAPSACK_PRO_LOG_LEVEL=info
- KNAPSACK_PRO_CI_NODE_TOTAL=2
- KNAPSACK_PRO_CI_NODE_TOTAL=3
matrix:
- KNAPSACK_PRO_CI_NODE_INDEX=0
- KNAPSACK_PRO_CI_NODE_INDEX=1
- KNAPSACK_PRO_CI_NODE_INDEX=2
notifications:
slack:
secure: 18E9SU0SR/9knRvCMYwVqFCqVTBT6qJtZQ/gadpheqUPPlcLoQfnlIzJkLIYqkE0sn1nkBE5Bt2I90FU53p0NkrTEmSGlQXcN1vEXM8EXMaoVf3NBsIJeleMwt9VTojzo81EgIi6x7q3fDiFORJ4rqOGd9XkeLn5yrAtIkdaenVs0bhS5s24FP76hKqO37IFLG2v3EEqxg5k31oW6yhyP35Mxns+AGbfaZbxEy4XbCoU65KFuYhBsVZ/y1evOl/wcre2fCAoT2uKeqUWGEcDzH7oSCz7vfk7iO9BZnO++v7oj8mr/nrZL1KMFt77eqtdT51XQoJcchgJC/R9km5hRGkQqFCHhqPcBxo5c3p+jauL0kLaqTggeLDv2FQ2huJ8FSJ4ADac+n3g7wT7BX7HJlCvK0nbooY1JtBlk7+6/pw6ksSFIOo0FHg5gXN9IlG1tQQuENzzsXULNc6s4nPeT+n78uOp1b0N/Gn06moEBaKgXqqx1yV1XeJ02X8n3uDZxPuX3n2bJ4DMIrBjeWApxHAgyOraOzQHNQgJoj4tHlWutF33ApV2tcIMefIzvjM4tIYwIkpfGgohGaTf8eU5X9pqiMgwlDpJHVBsSvpk/Z/Nj7evYznjBiDYqOcXoztsqHrS0C91MaT+eExDfd9HDmThsE07RT7zcP9aElFZA/k=

View File

@@ -1,3 +1,9 @@
<!--
Title: CONSUL
Description: Citizen Participation and Open Government Application
Keywords: democracy, citizen participation, eparticipation, debates, proposals, voting, consultations, crowdlaw, participatory budgeting
-->
![CONSUL logo](https://raw.githubusercontent.com/consul/consul/master/public/consul_logo.png)
# CONSUL
@@ -19,13 +25,17 @@ Citizen Participation and Open Government Application
This is the opensource code repository of the eParticipation website CONSUL, originally developed for the Madrid City government eParticipation website
## Current state
## Documentation
Development started on [2015 July 15th](https://github.com/consul/consul/commit/8db36308379accd44b5de4f680a54c41a0cc6fc6). Code was deployed to production on 2015 september 7th to [decide.madrid.es](https://decide.madrid.es). Since then new features are added often. You can take a look at the current features at the [project's website](http://consulproject.org/) and future features at the [Roadmap](https://github.com/consul/consul/projects/6) and [open issues list](https://github.com/consul/consul/issues).
Check the ongoing documentation at [https://docs.consulproject.org](https://docs.consulproject.org) to learn more about how to start your own CONSUL fork, install it, customize it and learn to use it from an administrator/maintainer perspective.
## CONSUL Project main website
You can access the main website of the project at [http://consulproject.org](http://consulproject.org) where you can find documentation about the use of the platform, videos, and links to the community space.
## Configuration for development and test environments
**NOTE**: For more detailed instructions check the [docs](https://consul_docs.gitbooks.io/docs/)
**NOTE**: For more detailed instructions check the [docs](https://docs.consulproject.org)
Prerequisites: install git, Ruby 2.3.2, `bundler` gem, Node.js and PostgreSQL (>=9.4).
@@ -69,9 +79,9 @@ But for some actions like voting, you will need a verified user, the seeds file
See [installer](https://github.com/consul/installer)
## Documentation
## Current state
Check the ongoing documentation at [https://consul_docs.gitbooks.io/docs/content/](https://consul_docs.gitbooks.io/docs/content/) to learn more about how to start your own CONSUL fork, install it, customize it and learn to use it from an administrator/maintainer perspective. You can contribute to it at [https://github.com/consul/docs](https://github.com/consul/docs)
Development started on [2015 July 15th](https://github.com/consul/consul/commit/8db36308379accd44b5de4f680a54c41a0cc6fc6). Code was deployed to production on 2015 september 7th to [decide.madrid.es](https://decide.madrid.es). Since then new features are added often. You can take a look at the current features at the [project's website](http://consulproject.org/) and future features at the [Roadmap](https://github.com/consul/consul/projects/6) and [open issues list](https://github.com/consul/consul/issues).
## License

View File

@@ -1,3 +1,9 @@
<!--
Title: CONSUL
Description: Aplicación de Participación Ciudadana y Gobierno Abierto
Keywords: democracia, participación ciudadana, participación electrónica, debates, propuestas, votaciones, consultas, legislación colaborativa, presupuestos participativos
-->
![Logotipo de CONSUL](https://raw.githubusercontent.com/consul/consul/master/public/consul_logo.png)
# CONSUL
@@ -18,13 +24,17 @@ Aplicación de Participación Ciudadana y Gobierno Abierto
Este es el repositorio de código abierto de la Aplicación de Participación Ciudadana CONSUL, creada originariamente por el Ayuntamiento de Madrid.
## Estado del proyecto
## Documentación
El desarrollo de esta aplicación comenzó el [15 de Julio de 2015](https://github.com/consul/consul/commit/8db36308379accd44b5de4f680a54c41a0cc6fc6) y el código fue puesto en producción el día 7 de Septiembre de 2015 en [decide.madrid.es](https://decide.madrid.es). Desde entonces se le añaden mejoras y funcionalidades constantemente. Las funcionalidades actuales se pueden consultar en la [la página del projecto](http://consulproject.org/es) y las futuras funcionalidades en el [Roadmap](https://github.com/consul/consul/projects/6) y [el listado de issues](https://github.com/consul/consul/issues).
Por favor visita la documentación que está siendo completada en [https://docs.consulproject.org](https://docs.consulproject.org) para conocer más sobre este proyecto, cómo comenzar tu propio fork, instalarlo, personalizarlo y usarlo como administrador/mantenedor.
## Web CONSUL Project
Puedes acceder a la página principal del proyecto en [http://consulproject.org](http://consulproject.org) donde puedes encontrar documentación sobre el uso de la plataforma, videos y enlaces al espacio de la comunidad.
## Configuración para desarrollo y tests
**NOTA**: para unas instrucciones más detalladas consulta la [documentación](https://github.com/consul/docs/tree/master/es/getting_started/prerequisites)
**NOTA**: para unas instrucciones más detalladas consulta la [documentación](https://docs.consulproject.org)
Prerequisitos: tener instalado git, Ruby 2.3.2, la gema `bundler`, Node.js y PostgreSQL (9.4 o superior).
@@ -64,9 +74,9 @@ Pero para ciertas acciones, como apoyar, necesitarás un usuario verificado, el
**user:** verified@consul.dev
**pass:** 12345678
## Documentación
## Estado del proyecto
Por favor visita la documentación que está siendo completada en [https://consul_docs.gitbooks.io/docs/content/](https://consul_docs.gitbooks.io/docs/content/) para conocer más sobre este proyecto, como comenzar tu propio fork, instalarlo, customizarlo y usarlo como administrador/mantenedor. Puedes colaborar en ella en [https://github.com/consul/docs](https://github.com/consul/docs)
El desarrollo de esta aplicación comenzó el [15 de Julio de 2015](https://github.com/consul/consul/commit/8db36308379accd44b5de4f680a54c41a0cc6fc6) y el código fue puesto en producción el día 7 de Septiembre de 2015 en [decide.madrid.es](https://decide.madrid.es). Desde entonces se le añaden mejoras y funcionalidades constantemente. Las funcionalidades actuales se pueden consultar en la [la página del projecto](http://consulproject.org/es) y las futuras funcionalidades en el [Roadmap](https://github.com/consul/consul/projects/6) y [el listado de issues](https://github.com/consul/consul/issues).
## Licencia

View File

@@ -1205,6 +1205,11 @@ table {
.filter {
display: inline-block;
margin: 0 $line-height / 2;
label {
font-weight: normal;
margin: 0;
}
}
.button {

View File

@@ -1168,6 +1168,11 @@
text-decoration: none;
}
.confirmed {
font-size: rem-calc(24);
font-weight: bold;
}
.info {
background: #6a2a72;

View File

@@ -4,10 +4,8 @@ class Admin::BudgetInvestmentsController < Admin::BaseController
feature_flag :budgets
has_orders %w{oldest}, only: [:show, :edit]
has_filters(%w{all without_admin without_valuator under_valuation
valuation_finished winners},
only: [:index, :toggle_selection])
has_orders %w[oldest], only: [:show, :edit]
has_filters %w[all], only: [:index, :toggle_selection]
before_action :load_budget
before_action :load_investment, only: [:show, :edit, :update, :toggle_selection]

View File

@@ -23,7 +23,9 @@ class Admin::BudgetsController < Admin::BaseController
def calculate_winners
return unless @budget.balloting_process?
@budget.headings.each { |heading| Budget::Result.new(@budget, heading).delay.calculate_winners }
redirect_to admin_budget_budget_investments_path(budget_id: @budget.id, filter: "winners"),
redirect_to admin_budget_budget_investments_path(
budget_id: @budget.id,
advanced_filters: ["winners"]),
notice: I18n.t("admin.budgets.winners.calculated")
end

View File

@@ -1,12 +1,46 @@
class Officing::BaseController < ApplicationController
layout "admin"
helper_method :current_booth
before_action :authenticate_user!
before_action :verify_officer
skip_authorization_check
def verify_officer
raise CanCan::AccessDenied unless current_user.try(:poll_officer?)
end
private
def verify_officer
raise CanCan::AccessDenied unless current_user.try(:poll_officer?)
end
def load_officer_assignment
@officer_assignments ||= current_user.poll_officer.
officer_assignments.
voting_days.
where(date: Time.current.to_date)
end
def verify_officer_assignment
if @officer_assignments.blank?
redirect_to officing_root_path, notice: t("officing.residence.flash.not_allowed")
end
end
def verify_booth
return unless current_booth.blank?
booths = current_user.poll_officer.todays_booths
case booths.count
when 0
redirect_to officing_root_path
when 1
session[:booth_id] = booths.first.id
else
redirect_to new_officing_booth_path
end
end
def current_booth
Poll::Booth.where(id: session[:booth_id]).first
end
end

View File

@@ -0,0 +1,24 @@
class Officing::BoothController < Officing::BaseController
before_action :load_officer_assignment
before_action :verify_officer_assignment
def new
@booths = current_user.poll_officer.todays_booths
end
def create
set_booth(Poll::Booth.find(booth_params[:id]))
redirect_to officing_root_path
end
private
def booth_params
params.require(:booth).permit(:id)
end
def set_booth(booth)
session[:booth_id] = booth.id
end
end

View File

@@ -1,4 +1,5 @@
class Officing::PollsController < Officing::BaseController
before_action :verify_booth
def index
@polls = current_user.poll_officer? ? current_user.poll_officer.voting_days_assigned_polls : []

View File

@@ -1,7 +1,8 @@
class Officing::ResidenceController < Officing::BaseController
before_action :load_officer_assignment
before_action :validate_officer_assignment, only: :create
before_action :verify_officer_assignment
before_action :verify_booth
def new
@residence = Officing::Residence.new
@@ -22,16 +23,4 @@ class Officing::ResidenceController < Officing::BaseController
params.require(:residence).permit(:document_number, :document_type, :year_of_birth)
end
def load_officer_assignment
@officer_assignments = current_user.poll_officer.
officer_assignments.
voting_days.
where(date: Date.current)
end
def validate_officer_assignment
if @officer_assignments.blank?
redirect_to officing_root_path, notice: t("officing.residence.flash.not_allowed")
end
end
end

View File

@@ -7,6 +7,7 @@ class Officing::ResultsController < Officing::BaseController
before_action :load_officer_assignment, only: :create
before_action :check_officer_assignment, only: :create
before_action :build_results, only: :create
before_action :verify_booth
def new
end

View File

@@ -1,6 +1,10 @@
class Officing::VotersController < Officing::BaseController
respond_to :html, :js
before_action :load_officer_assignment
before_action :verify_officer_assignment
before_action :verify_booth
def new
@user = User.find(params[:id])
booths = current_user.poll_officer.shifts.current.vote_collection.pluck(:booth_id).uniq
@@ -15,7 +19,9 @@ class Officing::VotersController < Officing::BaseController
user: @user,
poll: @poll,
origin: "booth",
officer: current_user.poll_officer)
officer: current_user.poll_officer,
booth_assignment: Poll::BoothAssignment.where(poll: @poll, booth: current_booth).first,
officer_assignment: officer_assignment(@poll))
@voter.save!
end
@@ -25,4 +31,13 @@ class Officing::VotersController < Officing::BaseController
params.require(:voter).permit(:poll_id, :user_id)
end
def officer_assignment(poll)
Poll::OfficerAssignment.by_officer(current_user.poll_officer)
.by_poll(poll)
.by_booth(current_booth)
.by_date(Date.current)
.where(final: false)
.first
end
end

View File

@@ -3,7 +3,9 @@ class Users::SessionsController < Devise::SessionsController
private
def after_sign_in_path_for(resource)
if !verifying_via_email? && resource.show_welcome_screen?
if current_user.poll_officer?
new_officing_booth_path
elsif !verifying_via_email? && resource.show_welcome_screen?
welcome_path
else
super

View File

@@ -1,7 +1,13 @@
module AdminBudgetInvestmentsHelper
def advanced_menu_visibility
(params[:advanced_filters].empty? && params["min_total_supports"].blank?) ? "hide" : ""
if params[:advanced_filters].empty? &&
params["min_total_supports"].blank? &&
params["max_total_supports"].blank?
"hide"
else
""
end
end
def init_advanced_menu

View File

@@ -5,11 +5,15 @@ module OfficersHelper
end
def vote_collection_shift?
current_user.poll_officer.officer_assignments.where(date: Time.current.to_date).any?
current_user.poll_officer.officer_assignments.voting_days.where(date: Time.current.to_date).any?
end
def final_recount_shift?
current_user.poll_officer.officer_assignments.final.where(date: Time.current.to_date).any?
end
def no_shifts?
current_user.poll_officer.officer_assignments.where(date: Time.current.to_date).blank?
end
end

View File

@@ -117,7 +117,9 @@ class Budget
results = Investment.by_budget(budget)
results = results.where("cached_votes_up + physical_votes >= ?",
params[:min_total_supports]) if params[:min_total_supports].present?
params[:min_total_supports]) if params[:min_total_supports].present?
results = results.where("cached_votes_up + physical_votes <= ?",
params[:max_total_supports]) if params[:max_total_supports].present?
results = results.where(group_id: params[:group_id]) if params[:group_id].present?
results = results.by_tag(params[:tag_name]) if params[:tag_name].present?
results = results.by_heading(params[:heading_id]) if params[:heading_id].present?
@@ -132,12 +134,19 @@ class Budget
end
def self.advanced_filters(params, results)
results = results.without_admin if params[:advanced_filters].include?("without_admin")
results = results.without_valuator if params[:advanced_filters].include?("without_valuator")
results = results.under_valuation if params[:advanced_filters].include?("under_valuation")
results = results.valuation_finished if params[:advanced_filters].include?("valuation_finished")
results = results.winners if params[:advanced_filters].include?("winners")
ids = []
ids += results.valuation_finished_feasible.pluck(:id) if params[:advanced_filters].include?("feasible")
ids += results.where(selected: true).pluck(:id) if params[:advanced_filters].include?("selected")
ids += results.undecided.pluck(:id) if params[:advanced_filters].include?("undecided")
ids += results.unfeasible.pluck(:id) if params[:advanced_filters].include?("unfeasible")
results.where("budget_investments.id IN (?)", ids)
results = results.where("budget_investments.id IN (?)", ids) if ids.any?
results
end
def self.order_filter(params)

View File

@@ -58,6 +58,10 @@ class Budget::Investment::Exporter
def price(investment)
price_string = "admin.budget_investments.index.feasibility.#{investment.feasibility}"
I18n.t(price_string, price: investment.formatted_price)
if investment.feasible?
"#{I18n.t(price_string)} (#{investment.formatted_price})"
else
I18n.t(price_string)
end
end
end

View File

@@ -23,5 +23,9 @@ class Poll
sort {|x, y| y.ends_at <=> x.ends_at}
end
def todays_booths
officer_assignments.by_date(Date.current).map(&:booth).uniq
end
end
end

View File

@@ -17,11 +17,20 @@ class Poll
scope :by_officer_and_poll, ->(officer_id, poll_id) do
where("officer_id = ? AND poll_booth_assignments.poll_id = ?", officer_id, poll_id)
end
scope :by_officer, ->(officer){ where(officer_id: officer.id) }
scope :by_poll, ->(poll){ joins(:booth_assignment).where("poll_booth_assignments.poll_id" => poll.id) }
scope :by_booth, ->(booth){ joins(:booth_assignment).where("poll_booth_assignments.booth_id" => booth.id) }
scope :by_date, ->(date){ where(date: date) }
before_create :log_user_data
def log_user_data
self.user_data_log = "#{officer.user_id} - #{officer.user.name_and_email}"
end
def booth
booth_assignment.booth
end
end
end

View File

@@ -12,11 +12,13 @@ class Poll
validates :poll_id, presence: true
validates :user_id, presence: true
validates :booth_assignment_id, presence: true, if: ->(voter) { voter.origin == "booth" }
validates :officer_assignment_id, presence: true, if: ->(voter) { voter.origin == "booth" }
validates :document_number, presence: true, uniqueness: { scope: [:poll_id, :document_type], message: :has_voted }
validates :origin, inclusion: { in: VALID_ORIGINS }
before_validation :set_demographic_info, :set_document_info
before_validation :set_demographic_info, :set_document_info, :set_denormalized_booth_assignment_id
scope :web, -> { where(origin: "web") }
scope :booth, -> { where(origin: "booth") }
@@ -38,6 +40,10 @@ class Poll
private
def set_denormalized_booth_assignment_id
self.booth_assignment_id ||= officer_assignment.try(:booth_assignment_id)
end
def in_census?
census_api_response.valid?
end

View File

@@ -2,7 +2,7 @@
admin_budget_budget_investments_path(csv_params),
class: "float-right small clear" %>
<% if params[:filter] == "winners" %>
<% if params[:advanced_filters].include?("winners") %>
<% if display_calculate_winners_button?(@budget) %>
<%= link_to calculate_winner_button_text(@budget),
calculate_winners_admin_budget_path(@budget),
@@ -36,6 +36,7 @@
</th>
<th><%= t("admin.budget_investments.index.list.geozone") %></th>
<th><%= t("admin.budget_investments.index.list.feasibility") %></th>
<th><%= t("admin.budget_investments.index.list.price") %></th>
<th class="text-center"><%= t("admin.budget_investments.index.list.valuation_finished") %></th>
<th class="text-center"><%= t("admin.budget_investments.index.list.visible_to_valuators") %></th>
<th class="text-center"><%= t("admin.budget_investments.index.list.selected") %></th>

View File

@@ -11,14 +11,22 @@
<div id="advanced_filters" class="<%= advanced_menu_visibility %>" data-toggler=".hide">
<div class="small-12 column">
<div class="advanced-filters-content">
<% ["feasible", "selected", "undecided", "unfeasible"].each do |option| %>
<% %w[feasible selected undecided unfeasible without_admin without_valuator under_valuation
valuation_finished winners].each do |filter| %>
<div class="filter">
<%= check_box_tag "advanced_filters[]", option, params[:advanced_filters].index(option), id: "advanced_filters_#{option}" %>
<%= t("admin.budget_investments.index.filters.#{option}") %>
<%= check_box_tag "advanced_filters[]", filter, params[:advanced_filters].index(filter), id: "advanced_filters_#{filter}" %>
<%= label_tag "advanced_filters[#{filter}]", t("admin.budget_investments.index.filters.#{filter}") %>
</div>
<% end %>
<div class="filter">
<%= text_field_tag :min_total_supports, params["min_total_supports"], placeholder: t("admin.budget_investments.index.filters.min_total_supports") %>
<div>
<div class="filter">
<%= label_tag :min_total_supports, t("admin.budget_investments.index.filters.min_total_supports") %>
<%= text_field_tag :min_total_supports, params["min_total_supports"] %>
</div>
<div class="filter">
<%= label_tag :max_total_supports, t("admin.budget_investments.index.filters.max_total_supports") %>
<%= text_field_tag :max_total_supports, params["max_total_supports"] %>
</div>
</div>
</div>
</div>

View File

@@ -31,8 +31,10 @@
<%= investment.heading.name %>
</td>
<td class="small">
<%= t("admin.budget_investments.index.feasibility.#{investment.feasibility}",
price: investment.formatted_price) %>
<%= t("admin.budget_investments.index.feasibility.#{investment.feasibility}") %>
</td>
<td class="small">
<%= investment.formatted_price %>
</td>
<td class="small text-center">
<%= investment.valuation_finished? ? t("shared.yes"): t("shared.no") %>
@@ -54,6 +56,7 @@
filter: params[:filter],
sort_by: params[:sort_by],
min_total_supports: params[:min_total_supports],
max_total_supports: params[:max_total_supports],
advanced_filters: params[:advanced_filters],
page: params[:page]),
method: :patch,
@@ -67,6 +70,7 @@
filter: params[:filter],
sort_by: params[:sort_by],
min_total_supports: params[:min_total_supports],
max_total_supports: params[:max_total_supports],
advanced_filters: params[:advanced_filters],
page: params[:page]),
method: :patch,

View File

@@ -43,14 +43,14 @@
<%= link_to booth_assignment.booth.name, admin_poll_booth_assignment_path(@poll, booth_assignment, anchor: "tab-recounts") %>
</strong>
</td>
<td class="text-center <%= "count-error" if total_recounts.to_i != system_count %>">
<td class="text-center <%= "count-error" if total_recounts.to_i != system_count %>" id="<%= dom_id(booth_assignment) %>_recount">
<% if total_recounts.present? %>
<strong><%= total_recounts %></strong>
<% else %>
<span>-</span>
<% end %>
</td>
<td class="text-center">
<td class="text-center" id="<%= dom_id(booth_assignment) %>_system">
<% if system_count.present? %>
<strong><%= system_count %></strong>
<% else %>

View File

@@ -9,11 +9,10 @@
<%= t("budgets.ballots.show.voted_html",
count: @ballot.investments.count) %>
</h2>
<p class="confirmed">
<%= t("budgets.ballots.show.voted_info_html") %>
<p>
<small>
<%= t("budgets.ballots.show.voted_info_html") %>
</small>
</p>
<p><%= t("budgets.ballots.show.voted_info_2") %></p>
</div>
</div>
</div>

View File

@@ -71,4 +71,8 @@
<% end %>
<% end %>
</ul>
<%= link_to t("budgets.investments.header.check_ballot"),
budget_ballot_path(@budget),
class: "button hollow expanded" %>
<% end %>

View File

@@ -0,0 +1,5 @@
<% if current_user.poll_officer? %>
<div id="officing-booth" class="callout info">
<%= t("admin.officing_booth.title", booth: try(:current_booth).try(:location)) %>
</div>
<% end %>

View File

@@ -33,6 +33,7 @@
<div class="admin-content small-12 medium-9 column" data-equalizer-watch>
<%= render "layouts/flash" %>
<%= render "layouts/officing_booth" %>
<%= yield %>
</div>
</div>

View File

@@ -0,0 +1,25 @@
<div class="row margin-top">
<div class="small-12 medium-6 column small-centered">
<div class="panel margin-top">
<h1 class="text-center">
<%= t("officing.booth.new.title") %>
</h1>
<%= form_for Poll::Booth.new,
as: :booth,
url: officing_booth_path,
method: :post do |f| %>
<div class="row">
<div class="small-12 column">
<%= f.select :id,
@booths.collect { |booth| [booth.location, booth.id] },
selected: @booths.first,
label: false,
tabindex: "1" %>
<%= f.submit(t("devise_views.sessions.new.submit"), class: "button expanded") %>
</div>
</div>
<% end %>
</div>
</div>
</div>

View File

@@ -3,7 +3,7 @@
<p><%= t("officing.dashboard.index.info") %></p>
<% unless final_recount_shift? && vote_collection_shift? %>
<% if no_shifts? %>
<div class="callout warning">
<%= t("officing.dashboard.index.no_shifts") %>
</div>

View File

@@ -1,32 +1,25 @@
<h2><%= t("officing.residence.new.title") %></h2>
<% if @officer_assignments.present? %>
<div class="row verification account">
<div class="small-12 medium-8 column">
<%= form_for @residence, as: "residence", url: officing_residence_path do |f| %>
<%= render "errors" %>
<div class="row verification account">
<div class="small-12 medium-8 column">
<%= form_for @residence, as: "residence", url: officing_residence_path do |f| %>
<%= render "errors" %>
<div class="small-12 medium-6">
<%= f.select :document_type, document_types, prompt: "" %>
<div class="small-12 medium-6">
<%= f.select :document_type, document_types, prompt: "" %>
<%= f.text_field :document_number,
<%= f.text_field :document_number,
placeholder: t("officing.residence.new.document_number"),
autocomplete: "off" %>
</div>
</div>
<div class="date-of-birth small-12 medium-6">
<%= f.text_field :year_of_birth, type: "number", autocomplete: "off" %>
</div>
<div class="date-of-birth small-12 medium-6">
<%= f.text_field :year_of_birth, type: "number", autocomplete: "off" %>
</div>
<div class="small-12 medium-6">
<input type="submit" value="<%= t("officing.residence.new.submit") %>" class="button expanded">
</div>
<% end %>
</div>
<div class="small-12 medium-6">
<input type="submit" value="<%= t("officing.residence.new.submit") %>" class="button expanded">
</div>
<% end %>
</div>
<% else %>
<div class="callout primary">
<%= t("officing.residence.new.no_assignments") %>
</div>
<% end %>
</div>

View File

@@ -1,3 +1,4 @@
$("#<%= dom_id(@poll) %> #actions").html("<%= j render("voted") %>");
$("#<%= dom_id(@poll) %> #can_vote_callout").hide();
$("#not_voted").hide();
$(".js-vote-collection").removeClass("is-hidden");

View File

@@ -28,4 +28,8 @@
</table>
<% end %>
<%= link_to t("officing.voters.new.not_to_vote"), namespaced_root_path, class: "button" %>
<% if Poll.votable_by(@user).any? %>
<div id="not_voted">
<%= link_to t("officing.voters.new.not_to_vote"), namespaced_root_path, class: "button" %>
</div>
<% end %>

View File

@@ -14,6 +14,8 @@ en:
edit: Edit
configure: Configure
delete: Delete
officing_booth:
title: "You are officing the booth located at %{booth}. If this is not correct, do not continue and call the help phone number. Thank you."
banners:
index:
title: Banners
@@ -191,6 +193,7 @@ en:
undecided: Undecided
unfeasible: Unfeasible
min_total_supports: Minimum supports
max_total_supports: Maximum supports
winners: Winners
one_filter_html: "Current applied filters: <b><em>%{filter}</em></b>"
two_filters_html: "Current applied filters: <b><em>%{filter}, %{advanced_filters}</em></b>"
@@ -204,7 +207,7 @@ en:
no_valuators_assigned: No valuators assigned
no_valuation_groups: No valuation groups assigned
feasibility:
feasible: "Feasible (%{price})"
feasible: "Feasible"
unfeasible: "Unfeasible"
undecided: "Undecided"
selected: "Selected"
@@ -223,6 +226,7 @@ en:
visible_to_valuators: Show to valuators
author_username: Author username
incompatible: Incompatible
price: Price
cannot_calculate_winners: The budget has to stay on phase "Balloting projects", "Reviewing Ballots" or "Finished budget" in order to calculate winners projects
see_results: "See results"
show:

View File

@@ -10,7 +10,8 @@ en:
voted_html:
one: "You have voted <span>one</span> investment."
other: "You have voted <span>%{count}</span> investments."
voted_info_html: "You can change your vote at any time until the close of this phase.<br> No need to spend all the money available."
voted_info_html: "Your ballot is confirmed!"
voted_info_2: "But you can change your vote at any time until this phase is closed."
zero: You have not voted any investment project.
reasons_for_not_balloting:
not_logged_in: You must %{signin} or %{signup} to continue.
@@ -90,7 +91,7 @@ en:
voted_info_link: change your vote
different_heading_assigned_html: "You have active votes in another heading: %{heading_link}"
change_ballot: "If your change your mind you can remove your votes in %{check_ballot} and start again."
check_ballot_link: "check my ballot"
check_ballot_link: "check and confirm my ballot"
zero: You have not voted any investment project in this group.
verified_only: "To create a new budget investment %{verify}."
verify_account: "verify your account"
@@ -142,10 +143,10 @@ en:
zero: No supports
give_support: Support
header:
check_ballot: Check my ballot
check_ballot: Check and confirm my ballot
different_heading_assigned_html: "You have active votes in another heading: %{heading_link}"
change_ballot: "If your change your mind you can remove your votes in %{check_ballot} and start again."
check_ballot_link: "check my ballot"
check_ballot_link: "check and confirm my ballot"
price: "This heading has a budget of"
progress_bar:
assigned: "You have assigned: "

View File

@@ -16,6 +16,9 @@ en:
no_polls: You are not officing final recounts in any active poll
select_poll: Select poll
add_results: Add results
booth:
new:
title: "Choose your booth"
results:
flash:
create: "Results saved"
@@ -51,7 +54,6 @@ en:
submit: Validate document
error_verifying_census: "The Census was unable to verify this document."
form_errors: prevented the verification of this document
no_assignments: "You don't have officing shifts today"
voters:
new:
title: Polls

View File

@@ -14,6 +14,8 @@ es:
edit: Editar
configure: Configurar
delete: Borrar
officing_booth:
title: "Estás ahora mismo en la mesa ubicada en %{booth}. Si esto no es correcto no sigas adelante y llama al teléfono de incidencias. Gracias."
banners:
index:
title: Banners
@@ -191,6 +193,7 @@ es:
undecided: Sin decidir
unfeasible: Inviables
min_total_supports: Apoyos mínimos
max_total_supports: Apoyos máximos
winners: Ganadores
one_filter_html: "Filtros en uso: <b><em>%{filter}</em></b>"
two_filters_html: "Filtros en uso: <b><em>%{filter}, %{advanced_filters}</em></b>"
@@ -204,7 +207,7 @@ es:
no_valuators_assigned: Sin evaluador
no_valuation_groups: Sin grupos evaluadores
feasibility:
feasible: "Viable (%{price})"
feasible: "Viable"
unfeasible: "Inviable"
undecided: "Sin decidir"
selected: "Seleccionado"
@@ -223,6 +226,7 @@ es:
visible_to_valuators: Mostrar a evaluadores
author_username: Usuario autor
incompatible: Incompatible
price: Precio
cannot_calculate_winners: El presupuesto debe estar en las fases "Votación final", "Votación finalizada" o "Resultados" para poder calcular las propuestas ganadoras
see_results: "Ver resultados"
show:

View File

@@ -10,7 +10,8 @@ es:
voted_html:
one: "Has votado <span>un</span> proyecto."
other: "Has votado <span>%{count}</span> proyectos."
voted_info_html: "Puedes cambiar tus votos en cualquier momento hasta el cierre de esta fase.<br> No hace falta que gastes todo el dinero disponible."
voted_info_html: "¡Tus votos están confirmados!"
voted_info_2: "Pero puedes cambiarlos en cualquier momento hasta el cierre de esta fase."
zero: Todavía no has votado ningún proyecto de gasto.
reasons_for_not_balloting:
not_logged_in: Necesitas %{signin} o %{signup} para continuar.
@@ -90,7 +91,7 @@ es:
voted_info_link: cambiar tus votos
different_heading_assigned_html: "Ya apoyaste proyectos de otra sección del presupuesto: %{heading_link}"
change_ballot: "Si cambias de opinión puedes borrar tus votos en %{check_ballot} y volver a empezar."
check_ballot_link: "revisar mis votos"
check_ballot_link: "revisar y confirmar mis votos"
zero: Todavía no has votado ningún proyecto de gasto en este ámbito del presupuesto.
verified_only: "Para crear un nuevo proyecto de gasto %{verify}."
verify_account: "verifica tu cuenta"
@@ -142,10 +143,10 @@ es:
other: "%{count} apoyos"
give_support: Apoyar
header:
check_ballot: Revisar mis votos
check_ballot: Revisar y confirmar mis votos
different_heading_assigned_html: "Ya apoyaste proyectos de otra sección del presupuesto: %{heading_link}"
change_ballot: "Si cambias de opinión puedes borrar tus votos en %{check_ballot} y volver a empezar."
check_ballot_link: "revisar mis votos"
check_ballot_link: "revisar y confirmar mis votos"
price: "Esta partida tiene un presupuesto de"
progress_bar:
assigned: "Has asignado: "

View File

@@ -16,6 +16,9 @@ es:
no_polls: No tienes permiso para recuento final en ninguna votación reciente
select_poll: Selecciona votación
add_results: Añadir resultados
booth:
new:
title: "Escoge tu urna"
results:
flash:
create: "Datos guardados"
@@ -51,7 +54,6 @@ es:
submit: Validar documento
error_verifying_census: "El Padrón no pudo verificar este documento."
form_errors: evitaron verificar este documento
no_assignments: "Hoy no tienes turno de presidente de mesa"
voters:
new:
title: Votaciones

View File

@@ -4,6 +4,7 @@ namespace :officing do
resources :results, only: [:new, :create, :index]
end
resource :booth, controller: "booth", only: [:new, :create]
resource :residence, controller: "residence", only: [:new, :create]
resources :voters, only: [:new, :create]
root to: "dashboard#index"

View File

@@ -42,13 +42,13 @@ end
section "Creating Poll Questions & Answers" do
Poll.find_each do |poll|
(1..4).to_a.sample.times do
title = Faker::Lorem.sentence(3).truncate(60) + "?"
question_title = Faker::Lorem.sentence(3).truncate(60) + "?"
question = Poll::Question.new(author: User.all.sample,
title: title,
title: question_title,
poll: poll)
I18n.available_locales.map do |locale|
Globalize.with_locale(locale) do
question.title = "#{title} (#{locale})"
question.title = "#{question_title} (#{locale})"
end
end
question.save!
@@ -115,12 +115,16 @@ end
section "Creating Poll Voters" do
def vote_poll_on_booth(user, poll)
officer = Poll::Officer.all.sample
Poll::Voter.create!(document_type: user.document_type,
document_number: user.document_number,
user: user,
poll: poll,
origin: "booth",
officer: Poll::Officer.all.sample)
officer: officer,
officer_assignment: officer.officer_assignments.sample,
booth_assignment: poll.booth_assignments.sample)
end
def vote_poll_on_web(user, poll)
@@ -143,11 +147,11 @@ section "Creating Poll Voters" do
end
(Poll.expired + Poll.current + Poll.recounting).uniq.each do |poll|
level_two_verified_users = User.level_two_verified
verified_users = User.level_two_or_three_verified
if poll.geozone_restricted?
level_two_verified_users = level_two_verified_users.where(geozone_id: poll.geozone_ids)
verified_users = verified_users.where(geozone_id: poll.geozone_ids)
end
user_groups = level_two_verified_users.in_groups(2)
user_groups = verified_users.in_groups(2)
user_groups.first.each { |user| vote_poll_on_booth(user, poll) }
user_groups.second.compact.each { |user| vote_poll_on_web(user, poll) }
end
@@ -159,13 +163,23 @@ section "Creating Poll Recounts" do
officer_assignment = poll.officer_assignments.first
author = Poll::Officer.first.user
total_amount = white_amount = null_amount = 0
booth_assignment.voters.count.times do
case rand
when 0...0.1 then null_amount += 1
when 0.1...0.2 then white_amount += 1
else total_amount += 1
end
end
Poll::Recount.create!(officer_assignment: officer_assignment,
booth_assignment: booth_assignment,
author: author,
date: poll.ends_at,
white_amount: rand(0..10),
null_amount: rand(0..10),
total_amount: rand(100..9999),
white_amount: white_amount,
null_amount: null_amount,
total_amount: total_amount,
origin: "booth")
end
end

View File

@@ -8,7 +8,7 @@ section "Creating Users" do
password_confirmation: password,
confirmed_at: Time.current,
terms_of_service: "1",
gender: ["Male", "Female"].sample,
gender: %w[male female].sample,
date_of_birth: rand((Time.current - 80.years)..(Time.current - 16.years)),
public_activity: (rand(1..100) > 30)
)

View File

@@ -150,13 +150,17 @@ FactoryBot.define do
valuation_finished true
end
trait :hidden do
hidden_at { Time.current }
end
trait :hidden do
hidden_at { Time.current }
end
trait :with_ignored_flag do
ignored_flag_at { Time.current }
end
trait :with_ignored_flag do
ignored_flag_at { Time.current }
end
trait :with_administrator do
administrator
end
trait :flagged do
after :create do |investment|

View File

@@ -251,12 +251,161 @@ feature "Admin budget investments" do
expect(page).not_to have_link("Build a hospital")
end
scenario "Filtering by without assigned admin", :js do
create(:budget_investment,
title: "Investment without admin",
budget: budget)
create(:budget_investment,
:with_administrator,
title: "Investment with admin",
budget: budget)
visit admin_budget_budget_investments_path(budget_id: budget)
expect(page).to have_link("Investment without admin")
expect(page).to have_link("Investment with admin")
click_link "Advanced filters"
check("Without assigned admin")
click_button "Filter"
expect(page).to have_content("There is 1 investment")
expect(page).to have_link("Investment without admin")
expect(page).not_to have_link("Investment with admin")
uncheck("Without assigned admin")
click_button "Filter"
expect(page).to have_content("There are 2 investments")
expect(page).to have_link("Investment without admin")
expect(page).to have_link("Investment with admin")
end
scenario "Filtering by without assigned valuator", :js do
user = create(:user)
valuator = create(:valuator, user: user)
create(:budget_investment,
title: "Investment without valuator",
budget: budget)
create(:budget_investment,
title: "Investment with valuator",
budget: budget,
valuators: [valuator])
visit admin_budget_budget_investments_path(budget_id: budget)
expect(page).to have_link("Investment without valuator")
expect(page).to have_link("Investment with valuator")
click_link "Advanced filters"
check "Without assigned valuator"
click_button "Filter"
expect(page).to have_content("There is 1 investment")
expect(page).to have_link("Investment without valuator")
expect(page).not_to have_link("Investment with valuator")
uncheck "Without assigned valuator"
click_button "Filter"
expect(page).to have_content("There are 2 investments")
expect(page).to have_link("Investment without valuator")
expect(page).to have_link("Investment with valuator")
end
scenario "Filtering by under valuation", :js do
user = create(:user)
valuator = create(:valuator, user: user)
create(:budget_investment,
:with_administrator,
valuation_finished: false,
title: "Investment without valuation",
budget: budget,
valuators: [valuator])
create(:budget_investment,
:with_administrator,
title: "Investment with valuation",
budget: budget)
visit admin_budget_budget_investments_path(budget_id: budget)
expect(page).to have_link("Investment without valuation")
expect(page).to have_link("Investment with valuation")
click_link "Advanced filters"
check "Under valuation"
click_button "Filter"
expect(page).to have_content("There is 1 investment")
expect(page).to have_link("Investment without valuation")
expect(page).not_to have_link("Investment with valuation")
uncheck "Under valuation"
click_button "Filter"
expect(page).to have_content("There are 2 investments")
expect(page).to have_link("Investment without valuation")
expect(page).to have_link("Investment with valuation")
end
scenario "Filtering by valuation finished", :js do
create(:budget_investment,
title: "Investment valuation open",
budget: budget)
create(:budget_investment,
:finished,
title: "Investment valuation finished",
budget: budget)
visit admin_budget_budget_investments_path(budget_id: budget)
expect(page).to have_link("Investment valuation open")
expect(page).to have_link("Investment valuation finished")
click_link "Advanced filters"
check "Valuation finished"
click_button "Filter"
expect(page).to have_content("There is 1 investment")
expect(page).not_to have_link("Investment valuation open")
expect(page).to have_link("Investment valuation finished")
uncheck "Valuation finished"
click_button "Filter"
expect(page).to have_content("There are 2 investments")
expect(page).to have_link("Investment valuation open")
expect(page).to have_link("Investment valuation finished")
end
scenario "Filtering by winners", :js do
create(:budget_investment,
:winner,
valuation_finished: true,
title: "Investment winner",
budget: budget)
create(:budget_investment,
title: "Investment without winner",
budget: budget)
visit admin_budget_budget_investments_path(budget_id: budget)
expect(page).to have_link("Investment winner")
expect(page).to have_link("Investment without winner")
click_link "Advanced filters"
check "Winners"
click_button "Filter"
expect(page).to have_content("There is 1 investment")
expect(page).to have_link("Investment winner")
expect(page).not_to have_link("Investment without winner")
uncheck "Winners"
click_button "Filter"
expect(page).to have_content("There are 2 investments")
expect(page).to have_link("Investment winner")
expect(page).to have_link("Investment without winner")
end
scenario "Current filter is properly highlighted" do
filters_links = { "all" => "All",
"without_admin" => "Without assigned admin",
"without_valuator" => "Without assigned valuator",
"under_valuation" => "Under valuation",
"valuation_finished" => "Valuation finished" }
filters_links = { "all" => "All" }
visit admin_budget_budget_investments_path(budget_id: budget.id)
@@ -288,13 +437,15 @@ feature "Admin budget investments" do
expect(page).to have_content("Evaluating...")
expect(page).to have_content("With group")
visit admin_budget_budget_investments_path(budget_id: budget.id, filter: "without_admin")
visit admin_budget_budget_investments_path(budget_id: budget.id,
advanced_filters: ["without_admin"])
expect(page).to have_content("Evaluating...")
expect(page).to have_content("With group")
expect(page).not_to have_content("Assigned idea")
visit admin_budget_budget_investments_path(budget_id: budget.id, filter: "without_valuator")
visit admin_budget_budget_investments_path(budget_id: budget.id,
advanced_filters: ["without_valuator"])
expect(page).to have_content("Assigned idea")
expect(page).not_to have_content("Evaluating...")
@@ -309,17 +460,20 @@ feature "Admin budget investments" do
valuating.valuators.push(create(:valuator))
valuated.valuators.push(create(:valuator))
visit admin_budget_budget_investments_path(budget_id: budget.id, filter: "under_valuation")
query_params = {budget_id: budget.id, advanced_filters: ["under_valuation"]}
visit admin_budget_budget_investments_path(query_params)
expect(page).to have_content("Ongoing valuation")
expect(page).not_to have_content("Old idea")
visit admin_budget_budget_investments_path(budget_id: budget.id, filter: "valuation_finished")
visit admin_budget_budget_investments_path(budget_id: budget.id,
advanced_filters: ["valuation_finished"])
expect(page).not_to have_content("Ongoing valuation")
expect(page).to have_content("Old idea")
visit admin_budget_budget_investments_path(budget_id: budget.id, filter: "all")
visit admin_budget_budget_investments_path(budget_id: budget.id, advanced_filters: ["filter"])
expect(page).to have_content("Ongoing valuation")
expect(page).to have_content("Old idea")
end
@@ -380,7 +534,10 @@ feature "Admin budget investments" do
budget.update(phase: "reviewing_ballots")
visit admin_budget_budget_investments_path(budget)
click_link "Winners"
click_link "Advanced filters"
check "Winners"
click_button "Filter"
expect(page).to have_link "Calculate Winner Investments"
@@ -391,7 +548,9 @@ feature "Admin budget investments" do
budget.update(phase: "accepting")
visit admin_budget_budget_investments_path(budget)
click_link "Winners"
check "Winners"
click_button "Filter"
expect(page).not_to have_link "Calculate Winner Investments"
expect(page).to have_content 'The budget has to stay on phase "Balloting projects", '\
@@ -439,6 +598,42 @@ feature "Admin budget investments" do
expect(page).not_to have_link("Road 100 supports")
end
scenario "Filtering by maximum number of votes", :js do
group_1 = create(:budget_group, budget: budget)
group_2 = create(:budget_group, budget: budget)
parks = create(:budget_heading, group: group_1)
roads = create(:budget_heading, group: group_2)
streets = create(:budget_heading, group: group_2)
create(:budget_investment, heading: parks, cached_votes_up: 40, title: "Park 40 supports")
create(:budget_investment, heading: parks, cached_votes_up: 99, title: "Park 99 supports")
create(:budget_investment, heading: roads, cached_votes_up: 100, title: "Road 100 supports")
create(:budget_investment, heading: roads, cached_votes_up: 199, title: "Road 199 supports")
create(:budget_investment, heading: streets, cached_votes_up: 200, title: "St. 200 supports")
create(:budget_investment, heading: streets, cached_votes_up: 300, title: "St. 300 supports")
visit admin_budget_budget_investments_path(budget)
expect(page).to have_link("Park 40 supports")
expect(page).to have_link("Park 99 supports")
expect(page).to have_link("Road 100 supports")
expect(page).to have_link("Road 199 supports")
expect(page).to have_link("St. 200 supports")
expect(page).to have_link("St. 300 supports")
click_link "Advanced filters"
fill_in "max_total_supports", with: 180
click_button "Filter"
expect(page).to have_content("There are 3 investments")
expect(page).not_to have_link("Road 199 supports")
expect(page).not_to have_link("St. 200 supports")
expect(page).not_to have_link("St. 300 supports")
expect(page).to have_link("Park 40 supports")
expect(page).to have_link("Park 99 supports")
expect(page).to have_link("Road 100 supports")
end
scenario "Combination of checkbox with text search", :js do
user = create(:user, username: "Admin 1")
administrator = create(:administrator, user: user)
@@ -494,7 +689,7 @@ feature "Admin budget investments" do
click_link "Advanced filters"
page.check("advanced_filters_feasible")
check("Feasible")
click_button "Filter"
expect(page).to have_css(".budget_investment", count: 2)
@@ -549,7 +744,7 @@ feature "Admin budget investments" do
click_link "Advanced filters"
within("#advanced_filters") { check("advanced_filters_feasible") }
within("#advanced_filters") { check("Feasible") }
click_button("Filter")
expect(page).to have_css(".budget_investment", count: 2)
@@ -1120,16 +1315,17 @@ feature "Admin budget investments" do
scenario "Filtering by valuation and selection", :js do
visit admin_budget_budget_investments_path(budget)
within("#filter-subnav") { click_link "Valuation finished" }
click_link "Advanced filters"
check "Valuation finished"
click_button "Filter"
expect(page).not_to have_content(unfeasible_bi.title)
expect(page).not_to have_content(feasible_bi.title)
expect(page).to have_content(feasible_vf_bi.title)
expect(page).to have_content(selected_bi.title)
expect(page).to have_content(winner_bi.title)
click_link "Advanced filters"
within("#advanced_filters") { check("advanced_filters_feasible") }
within("#advanced_filters") { check("Feasible") }
click_button("Filter")
expect(page).not_to have_content(unfeasible_bi.title)
@@ -1139,8 +1335,8 @@ feature "Admin budget investments" do
expect(page).to have_content(winner_bi.title)
within("#advanced_filters") do
check("advanced_filters_selected")
uncheck("advanced_filters_feasible")
check("Selected")
uncheck("Feasible")
end
click_button("Filter")
@@ -1151,7 +1347,9 @@ feature "Admin budget investments" do
expect(page).to have_content(selected_bi.title)
expect(page).to have_content(winner_bi.title)
within("#filter-subnav") { click_link "Winners" }
check "Winners"
click_button "Filter"
expect(page).not_to have_content(unfeasible_bi.title)
expect(page).not_to have_content(feasible_bi.title)
expect(page).not_to have_content(feasible_vf_bi.title)
@@ -1164,7 +1362,7 @@ feature "Admin budget investments" do
click_link "Advanced filters"
within("#advanced_filters") { check("advanced_filters_undecided") }
within("#advanced_filters") { check("Undecided") }
click_button("Filter")
expect(page).to have_content(undecided_bi.title)
@@ -1174,7 +1372,7 @@ feature "Admin budget investments" do
expect(page).not_to have_content(unfeasible_bi.title)
expect(page).not_to have_content(feasible_vf_bi.title)
within("#advanced_filters") { check("advanced_filters_unfeasible") }
within("#advanced_filters") { check("Unfeasible") }
click_button("Filter")
expect(page).to have_content(undecided_bi.title)
@@ -1219,7 +1417,7 @@ feature "Admin budget investments" do
click_link "Advanced filters"
within("#advanced_filters") { check("advanced_filters_selected") }
within("#advanced_filters") { check("Selected") }
click_button("Filter")
within("#budget_investment_#{feasible_vf_bi.id}") do
@@ -1232,7 +1430,7 @@ feature "Admin budget investments" do
visit admin_budget_budget_investments_path(budget)
click_link "Advanced filters"
within("#advanced_filters") { check("advanced_filters_selected") }
within("#advanced_filters") { check("Selected") }
click_button("Filter")
expect(page).to have_content("There are 2 investments")
@@ -1289,15 +1487,18 @@ feature "Admin budget investments" do
investment2.update(administrator: admin)
visit admin_budget_budget_investments_path(budget)
within("#filter-subnav") { click_link "Under valuation" }
expect(page).not_to have_link("Under valuation")
click_link "Advanced filters"
check "Under valuation"
click_button "Filter"
within("#budget_investment_#{investment1.id}") do
check "budget_investment_visible_to_valuators"
end
visit admin_budget_budget_investments_path(budget)
within("#filter-subnav") { click_link "Under valuation" }
click_link "Advanced filters"
check "Under valuation"
click_button "Filter"
within("#budget_investment_#{investment1.id}") do
expect(find("#budget_investment_visible_to_valuators")).to be_checked
@@ -1335,15 +1536,20 @@ feature "Admin budget investments" do
investment2.update(administrator: admin, visible_to_valuators: true)
visit admin_budget_budget_investments_path(budget)
within("#filter-subnav") { click_link "Under valuation" }
expect(page).not_to have_link("Under valuation")
click_link "Advanced filters"
check "Under valuation"
click_button "Filter"
within("#budget_investment_#{investment1.id}") do
uncheck "budget_investment_visible_to_valuators"
end
visit admin_budget_budget_investments_path(budget)
within("#filter-subnav") { click_link "Under valuation" }
click_link "Advanced filters"
check "Under valuation"
click_button "Filter"
within("#budget_investment_#{investment1.id}") do
expect(find("#budget_investment_visible_to_valuators")).not_to be_checked
@@ -1364,7 +1570,9 @@ feature "Admin budget investments" do
expect(page).to have_css("#budget_investment_visible_to_valuators")
within("#filter-subnav") { click_link "Under valuation" }
click_link "Advanced filters"
check "Under valuation"
click_button "Filter"
within("#budget_investment_#{investment1.id}") do
valuating_checkbox = find("#budget_investment_visible_to_valuators")
@@ -1442,7 +1650,9 @@ feature "Admin budget investments" do
create(:budget_investment, :finished, budget: budget, title: "Finished Investment")
visit admin_budget_budget_investments_path(budget)
within("#filter-subnav") { click_link "Valuation finished" }
click_link "Advanced filters"
check "Valuation finished"
click_button "Filter"
click_link "Download current selection"

View File

@@ -281,7 +281,9 @@ feature "Admin budgets" do
expect(page).not_to have_content "Calculate Winner Investments"
visit admin_budget_budget_investments_path(budget)
click_link "Winners"
click_link "Advanced filters"
check "Winners"
click_button "Filter"
expect(page).to have_content "Recalculate Winner Investments"
expect(page).not_to have_content "Calculate Winner Investments"

View File

@@ -2,7 +2,7 @@ require "rails_helper"
feature "Budget Poll Officing" do
scenario "Show sidebar menu if officer has shifts assigned" do
scenario "Show sidebar menus if officer has shifts assigned" do
poll = create(:poll)
booth = create(:poll_booth)
booth_assignment = create(:poll_booth_assignment, poll: poll, booth: booth)
@@ -10,13 +10,21 @@ feature "Budget Poll Officing" do
user = create(:user)
officer = create(:poll_officer, user: user)
create(:poll_shift, officer: officer, booth: booth, date: Date.current, task: :vote_collection)
login_as user
visit officing_root_path
expect(page).not_to have_content("You don't have officing shifts today")
expect(page).to have_content("Validate document")
expect(page).not_to have_content("Total recounts and results")
create(:poll_shift, officer: officer, booth: booth, date: Date.current, task: :recount_scrutiny)
officer_assignment = create(:poll_officer_assignment,
booth_assignment: booth_assignment,
officer: officer)
login_as user
visit officing_root_path
expect(page).not_to have_content("You don't have officing shifts today")
@@ -24,7 +32,7 @@ feature "Budget Poll Officing" do
expect(page).to have_content("Total recounts and results")
end
scenario "Do not show sidebar menu if officer has no shifts assigned" do
scenario "Do not show sidebar menus if officer has no shifts assigned" do
user = create(:user)
officer = create(:poll_officer, user: user)

View File

@@ -117,6 +117,7 @@ feature "Ballots" do
within("#sidebar") do
expect(page).to have_content investment1.title
expect(page).to have_content "€10,000"
expect(page).to have_link("Check and confirm my ballot")
end
add_to_ballot(investment2)
@@ -127,6 +128,7 @@ feature "Ballots" do
within("#sidebar") do
expect(page).to have_content investment2.title
expect(page).to have_content "€20,000"
expect(page).to have_link("Check and confirm my ballot")
end
end
@@ -146,6 +148,7 @@ feature "Ballots" do
within("#sidebar") do
expect(page).to have_content investment.title
expect(page).to have_content "€10,000"
expect(page).to have_link("Check and confirm my ballot")
end
within("#budget_investment_#{investment.id}") do
@@ -158,6 +161,7 @@ feature "Ballots" do
within("#sidebar") do
expect(page).not_to have_content investment.title
expect(page).not_to have_content "€10,000"
expect(page).to have_link("Check and confirm my ballot")
end
end
@@ -454,7 +458,9 @@ feature "Ballots" do
visit budget_investments_path(budget, heading_id: new_york.id)
add_to_ballot(investment)
click_link "Check my ballot"
within(".budget-heading") do
click_link "Check and confirm my ballot"
end
expect(page).to have_content("You have voted one investment")

View File

@@ -583,43 +583,46 @@ feature "Budget Investments" do
context "Orders" do
before { budget.update(phase: "selecting") }
let(:per_page) { Budgets::InvestmentsController::PER_PAGE }
scenario "Default order is random" do
per_page = Kaminari.config.default_per_page
(per_page + 100).times { create(:budget_investment) }
visit budget_investments_path(budget, heading_id: heading.id)
order = all(".budget-investment h3").collect {|i| i.text }
visit budget_investments_path(budget, heading_id: heading.id)
new_order = eq(all(".budget-investment h3").collect {|i| i.text })
expect(order).not_to eq(new_order)
end
scenario "Random order after another order" do
per_page = Kaminari.config.default_per_page
(per_page + 2).times { create(:budget_investment) }
visit budget_investments_path(budget, heading_id: heading.id)
click_link "highest rated"
click_link "random"
order = all(".budget-investment h3").collect {|i| i.text }
visit budget_investments_path(budget, heading_id: heading.id)
new_order = eq(all(".budget-investment h3").collect {|i| i.text })
expect(order).not_to eq(new_order)
end
scenario "Random order maintained with pagination" do
per_page = Kaminari.config.default_per_page
(per_page + 2).times { create(:budget_investment, heading: heading) }
visit budget_investments_path(budget, heading_id: heading.id)
order = all(".budget-investment h3").collect {|i| i.text }
within(".submenu .is-active") { expect(page).to have_content "random" }
order = all(".budget-investment h3").collect { |i| i.text }
expect(order).not_to be_empty
visit budget_investments_path(budget, heading_id: heading.id)
new_order = all(".budget-investment h3").collect { |i| i.text }
expect(order).to eq(new_order)
end
scenario "Random order after another order" do
(per_page + 2).times { create(:budget_investment, heading: heading) }
visit budget_investments_path(budget, heading_id: heading.id)
order = all(".budget-investment h3").collect { |i| i.text }
expect(order).not_to be_empty
click_link "highest rated"
click_link "random"
visit budget_investments_path(budget, heading_id: heading.id)
new_order = all(".budget-investment h3").collect { |i| i.text }
expect(order).to eq(new_order)
end
scenario "Random order maintained with pagination" do
(per_page + 2).times { create(:budget_investment, heading: heading) }
visit budget_investments_path(budget, heading_id: heading.id)
order = all(".budget-investment h3").collect { |i| i.text }
expect(order).not_to be_empty
click_link "Next"
expect(page).to have_content "You're on page 2"
@@ -627,27 +630,27 @@ feature "Budget Investments" do
click_link "Previous"
expect(page).to have_content "You're on page 1"
new_order = all(".budget-investment h3").collect {|i| i.text }
new_order = all(".budget-investment h3").collect { |i| i.text }
expect(order).to eq(new_order)
end
scenario "Random order maintained when going back from show" do
10.times { |i| create(:budget_investment, heading: heading) }
per_page.times { |i| create(:budget_investment, heading: heading) }
visit budget_investments_path(budget, heading_id: heading.id)
order = all(".budget-investment h3").collect {|i| i.text }
order = all(".budget-investment h3").collect { |i| i.text }
expect(order).not_to be_empty
click_link Budget::Investment.first.title
click_link "Go back"
new_order = all(".budget-investment h3").collect {|i| i.text }
new_order = all(".budget-investment h3").collect { |i| i.text }
expect(order).to eq(new_order)
end
scenario "Investments are not repeated with random order" do
12.times { create(:budget_investment, heading: heading) }
# 12 instead of per_page + 2 because in each page there are 10 (in this case), not 25
(per_page + 2).times { create(:budget_investment, heading: heading) }
visit budget_investments_path(budget, order: "random")
@@ -661,7 +664,6 @@ feature "Budget Investments" do
common_values = first_page_investments & second_page_investments
expect(common_values.length).to eq(0)
end
scenario "Proposals are ordered by confidence_score" do
@@ -686,7 +688,7 @@ feature "Budget Investments" do
end
scenario "Each user has a different and consistent random budget investment order" do
(Kaminari.config.default_per_page * 1.3).to_i.times { create(:budget_investment, heading: heading) }
(per_page * 1.3).to_i.times { create(:budget_investment, heading: heading) }
in_browser(:one) do
visit budget_investments_path(budget, heading: heading)
@@ -722,7 +724,7 @@ feature "Budget Investments" do
end
scenario "Each user has a equal and consistent budget investment order when the random_seed is equal" do
(Kaminari.config.default_per_page * 1.3).to_i.times { create(:budget_investment, heading: heading) }
(per_page * 1.3).to_i.times { create(:budget_investment, heading: heading) }
in_browser(:one) do
visit budget_investments_path(budget, heading: heading, random_seed: "1")
@@ -741,10 +743,10 @@ feature "Budget Investments" do
voter = create(:user, :level_two)
login_as(voter)
10.times { create(:budget_investment, heading: heading) }
per_page.times { create(:budget_investment, heading: heading) }
voted_investments = []
10.times do
per_page.times do
investment = create(:budget_investment, heading: heading)
create(:vote, votable: investment, voter: voter)
voted_investments << investment
@@ -762,17 +764,18 @@ feature "Budget Investments" do
end
scenario "Order is random if budget is finished" do
10.times { create(:budget_investment) }
per_page.times { create(:budget_investment, :winner, heading: heading) }
budget.update(phase: "finished")
visit budget_investments_path(budget, heading_id: heading.id)
order = all(".budget-investment h3").collect {|i| i.text }
order = all(".budget-investment h3").collect { |i| i.text }
expect(order).not_to be_empty
visit budget_investments_path(budget, heading_id: heading.id)
new_order = eq(all(".budget-investment h3").collect {|i| i.text })
new_order = all(".budget-investment h3").collect { |i| i.text }
expect(order).not_to eq(new_order)
expect(order).to eq(new_order)
end
scenario "Order always is random for unfeasible and unselected investments" do
@@ -930,10 +933,12 @@ feature "Budget Investments" do
visit budget_investments_path(budget, heading_id: heading.id)
expect(page).not_to have_link("Check my ballot")
expect(page).not_to have_link("Check and confirm my ballot")
expect(page).not_to have_css("#progress_bar")
within("#sidebar") do
expect(page).not_to have_content("My ballot")
expect(page).not_to have_link("Check and confirm my ballot")
end
end
@@ -1564,7 +1569,8 @@ feature "Budget Investments" do
visit budget_ballot_path(budget)
expect(page).to have_content "You can change your vote at any time until the close of this phase"
expect(page).to have_content "But you can change your vote at any time "\
"until this phase is closed."
within("#budget_group_#{global_group.id}") do
expect(page).to have_content sp1.title
@@ -1627,10 +1633,12 @@ feature "Budget Investments" do
visit budget_investments_path(budget, heading_id: heading.id)
expect(page).to have_link("Check my ballot")
expect(page).to have_link("Check and confirm my ballot")
expect(page).to have_css("#progress_bar")
within("#sidebar") do
expect(page).to have_content("My ballot")
expect(page).to have_link("Check and confirm my ballot")
end
end

View File

@@ -0,0 +1,87 @@
require "rails_helper"
feature "Booth", :with_frozen_time do
scenario "Officer with no booth assignments today" do
officer = create(:poll_officer)
login_through_form_as_officer(officer.user)
expect(page).to have_content "You don't have officing shifts today"
end
scenario "Officer with booth assignments another day" do
officer = create(:poll_officer)
create(:poll_officer_assignment, officer: officer, date: Date.current + 1.day)
login_through_form_as_officer(officer.user)
expect(page).to have_content "You don't have officing shifts today"
end
scenario "Officer with single booth assignment today" do
officer = create(:poll_officer)
poll = create(:poll)
booth = create(:poll_booth)
booth_assignment = create(:poll_booth_assignment, poll: poll, booth: booth)
create(:poll_officer_assignment, officer: officer, booth_assignment: booth_assignment, date: Date.current)
login_through_form_as_officer(officer.user)
within("#officing-booth") do
expect(page).to have_content "You are officing the booth located at #{booth.location}."
end
end
scenario "Officer with multiple booth assignments today" do
officer = create(:poll_officer)
poll = create(:poll)
booth1 = create(:poll_booth)
booth2 = create(:poll_booth)
ba1 = create(:poll_booth_assignment, poll: poll, booth: booth1)
ba2 = create(:poll_booth_assignment, poll: poll, booth: booth2)
create(:poll_officer_assignment, officer: officer, booth_assignment: ba1, date: Date.current)
create(:poll_officer_assignment, officer: officer, booth_assignment: ba2, date: Date.current)
login_through_form_as_officer(officer.user)
expect(page).to have_content "Choose your booth"
select booth2.location, from: "booth_id"
click_button "Enter"
within("#officing-booth") do
expect(page).to have_content "You are officing the booth located at #{booth2.location}."
end
end
scenario "Display single booth for any number of polls" do
officer = create(:poll_officer)
booth1 = create(:poll_booth)
booth2 = create(:poll_booth)
poll1 = create(:poll)
poll2 = create(:poll)
ba1 = create(:poll_booth_assignment, poll: poll1, booth: booth1)
ba2 = create(:poll_booth_assignment, poll: poll2, booth: booth2)
ba3 = create(:poll_booth_assignment, poll: poll2, booth: booth2)
create(:poll_officer_assignment, officer: officer, booth_assignment: ba1, date: Date.current)
create(:poll_officer_assignment, officer: officer, booth_assignment: ba2, date: Date.current)
create(:poll_officer_assignment, officer: officer, booth_assignment: ba3, date: Date.current)
login_through_form_as_officer(officer.user)
expect(page).to have_content "Choose your booth"
expect(page).to have_select("booth_id", options: [booth1.location, booth2.location])
end
end

View File

@@ -25,7 +25,7 @@ feature "Residence", :with_frozen_time do
background do
create(:poll_officer_assignment, officer: officer)
login_as(officer.user)
login_through_form_as_officer(officer.user)
visit officing_root_path
end
@@ -93,4 +93,27 @@ feature "Residence", :with_frozen_time do
end
scenario "Verify booth", :js do
booth = create(:poll_booth)
poll = create(:poll)
ba = create(:poll_booth_assignment, poll: poll, booth: booth)
create(:poll_officer_assignment, officer: officer, booth_assignment: ba)
create(:poll_shift, officer: officer, booth: booth, date: Date.current)
login_as(officer.user)
visit new_officing_residence_path
within("#officing-booth") do
expect(page).to have_content "You are officing the booth located at #{booth.location}."
end
officing_verify_residence
expect(page).to have_content poll.name
click_button "Confirm vote"
expect(page).to have_content "Vote introduced!"
end
end

View File

@@ -5,6 +5,7 @@ feature "Officing Results", :with_frozen_time do
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)
@@ -15,6 +16,7 @@ feature "Officing Results", :with_frozen_time do
create(:poll_question_answer, title: "Tomorrow", question: @question_2, given_order: 2)
login_as(@poll_officer.user)
set_officing_booth(@officer_assignment.booth)
end
scenario "Only polls where user is officer for results are accessible" do
@@ -30,6 +32,7 @@ feature "Officing Results", :with_frozen_time do
click_link "Polling officers"
expect(page).to have_content("Poll officing")
within("#side_menu") do
click_link "Total recounts and results"
end

View File

@@ -12,9 +12,12 @@ feature "Voters" do
create(:poll_shift, officer: officer, booth: booth, date: Date.current, task: :vote_collection)
booth_assignment = create(:poll_booth_assignment, poll: poll, booth: booth)
create(:poll_officer_assignment, officer: officer, booth_assignment: booth_assignment)
set_officing_booth(booth)
end
scenario "Can vote", :js do
create(:poll_officer_assignment, officer: officer)
visit new_officing_residence_path
officing_verify_residence
@@ -57,6 +60,10 @@ feature "Voters" do
user = create(:user, residence_verified_at: Time.current, document_type: "1", document_number: "12345678Z")
expect(user).not_to be_level_two_verified
visit root_path
click_link "Sign out"
login_through_form_as_officer(officer.user)
visit new_officing_residence_path
officing_verify_residence
@@ -83,6 +90,7 @@ feature "Voters" do
booth_assignment = create(:poll_booth_assignment, poll: poll_geozone_restricted_out, booth: booth)
create(:poll_officer_assignment, officer: officer, booth_assignment: booth_assignment)
set_officing_booth(second_booth)
visit new_officing_residence_path
officing_verify_residence
@@ -93,4 +101,44 @@ feature "Voters" do
expect(page).to have_content poll_geozone_restricted_in.name
expect(page).not_to have_content poll_geozone_restricted_out.name
end
scenario "Store officer and booth information", :js do
create(:user, :in_census, id: rand(9999999))
poll1 = create(:poll, name: "¿Quieres que XYZ sea aprobado?")
poll2 = create(:poll, name: "Pregunta de votación de prueba")
second_booth = create(:poll_booth)
ba1 = create(:poll_booth_assignment, poll: poll1, booth: second_booth )
ba2 = create(:poll_booth_assignment, poll: poll2, booth: second_booth )
create(:poll_shift, officer: officer, booth: second_booth, date: Date.current, task: :vote_collection)
validate_officer
visit new_officing_residence_path
set_officing_booth(second_booth)
officing_verify_residence
within("#poll_#{poll1.id}") do
click_button "Confirm vote"
expect(page).to have_content "Vote introduced!"
end
within("#poll_#{poll2.id}") do
click_button "Confirm vote"
expect(page).to have_content "Vote introduced!"
end
expect(Poll::Voter.count).to eq(2)
voter1 = Poll::Voter.first
expect(voter1.booth_assignment).to eq(ba1)
expect(voter1.officer_assignment).to eq(ba1.officer_assignments.first)
voter2 = Poll::Voter.last
expect(voter2.booth_assignment).to eq(ba2)
expect(voter2.officer_assignment).to eq(ba2.officer_assignments.first)
end
end

View File

@@ -97,6 +97,7 @@ feature "Poll Officing" do
end
scenario "Poll officer access links" do
create(:poll)
create(:poll_officer, user: user)
login_as(user)
visit root_path

View File

@@ -8,6 +8,7 @@ feature "Voter" do
let(:question) { create(:poll_question, poll: poll) }
let(:booth) { create(:poll_booth) }
let(:officer) { create(:poll_officer) }
let(:admin) { create(:administrator) }
let!(:answer_yes) { create(:poll_question_answer, question: question, title: "Yes") }
let!(:answer_no) { create(:poll_question_answer, question: question, title: "No") }
@@ -71,6 +72,56 @@ feature "Voter" do
expect(Poll::Voter.count).to eq(1)
expect(Poll::Voter.first.origin).to eq("booth")
visit root_path
click_link "Sign out"
login_as(admin.user)
visit admin_poll_recounts_path(poll)
within("#total_system") do
expect(page).to have_content "1"
end
within("#poll_booth_assignment_#{Poll::BoothAssignment.where(poll: poll, booth: booth).first.id}_recounts") do
expect(page).to have_content "1"
end
end
context "The person has decided not to vote at this time" do
let!(:user) { create(:user, :in_census) }
scenario "Show not to vote at this time button" do
login_through_form_as_officer(officer.user)
visit new_officing_residence_path
officing_verify_residence
expect(page).to have_content poll.name
expect(page).to have_button "Confirm vote"
expect(page).to have_content "Can vote"
expect(page).to have_link "The person has decided not to vote at this time"
end
scenario "Hides not to vote at this time button if already voted", :js do
login_through_form_as_officer(officer.user)
visit new_officing_residence_path
officing_verify_residence
within("#poll_#{poll.id}") do
click_button("Confirm vote")
expect(page).not_to have_button("Confirm vote")
expect(page).to have_content "Vote introduced!"
expect(page).not_to have_content "The person has decided not to vote at this time"
end
visit new_officing_residence_path
officing_verify_residence
expect(page).to have_content "Has already participated in this poll"
expect(page).not_to have_content "The person has decided not to vote at this time"
end
end
context "Trying to vote the same poll in booth and web" do
@@ -107,6 +158,19 @@ feature "Voter" do
expect(page).not_to have_link(answer_yes.title)
expect(page).to have_content "You have already participated in a physical booth. You can not participate again."
expect(Poll::Voter.count).to eq(1)
visit root_path
click_link "Sign out"
login_as(admin.user)
visit admin_poll_recounts_path(poll)
within("#total_system") do
expect(page).to have_content "1"
end
within("#poll_booth_assignment_#{Poll::BoothAssignment.where(poll: poll, booth: booth).first.id}_recounts") do
expect(page).to have_content "1"
end
end
scenario "Trying to vote in web again", :js do
@@ -162,6 +226,19 @@ feature "Voter" do
expect(page).not_to have_link(answer_yes.title)
expect(page).to have_content "You have already participated in a physical booth. You can not participate again."
expect(Poll::Voter.count).to eq(1)
visit root_path
click_link "Sign out"
login_as(admin.user)
visit admin_poll_recounts_path(poll)
within("#total_system") do
expect(page).to have_content "1"
end
within("#poll_booth_assignment_#{Poll::BoothAssignment.where(poll: poll, booth: booth).first.id}_recounts") do
expect(page).to have_content "1"
end
end
context "Side menu" do

View File

@@ -1131,4 +1131,91 @@ describe Budget::Investment do
end
end
describe "scoped_filter" do
let(:budget) { create(:budget, phase: "balloting") }
let(:investment) { create(:budget_investment, budget: budget) }
describe "with without_admin filter" do
let(:params) { {advanced_filters: ["without_admin"], budget_id: budget.id} }
it "returns only investment without admin" do
create(:budget_investment,
:finished,
budget: budget)
create(:budget_investment,
:with_administrator,
budget: budget)
investment3 = create(:budget_investment, budget: budget)
expect(described_class.scoped_filter(params, "all")).to eq([investment3])
expect(described_class.scoped_filter(params, "all").count).to eq(1)
end
end
describe "with without_valuator filter" do
let(:params) { {advanced_filters: ["without_valuator"], budget_id: budget.id} }
it "returns only investment without valuator" do
create(:budget_investment,
:finished,
budget: budget)
investment2 = create(:budget_investment,
:with_administrator,
budget: budget)
investment3 = create(:budget_investment,
budget: budget)
expect(described_class.scoped_filter(params, "all"))
.to contain_exactly(investment2, investment3)
expect(described_class.scoped_filter(params, "all").count)
.to eq(2)
end
end
describe "with under_valuation filter" do
let(:params) { {advanced_filters: ["under_valuation"], budget_id: budget.id} }
it "returns only investment under valuation" do
valuator1 = create(:valuator)
investment1 = create(:budget_investment,
:with_administrator,
valuation_finished: false,
budget: budget)
investment1.valuators << valuator1
create(:budget_investment, :with_administrator, budget: budget)
create(:budget_investment, budget: budget)
expect(described_class.scoped_filter(params, "all")).to eq([investment1])
expect(described_class.scoped_filter(params, "all").count).to eq(1)
end
end
describe "with valuation_finished filter" do
let(:params) { {advanced_filters: ["valuation_finished"], budget_id: budget.id} }
it "returns only investment with valuation finished" do
investment1 = create(:budget_investment,
:selected,
budget: budget)
create(:budget_investment,
:with_administrator,
budget: budget)
create(:budget_investment,
budget: budget)
expect(described_class.scoped_filter(params, "all")).to eq([investment1])
expect(described_class.scoped_filter(params, "all").count).to eq(1)
end
end
describe "with winners filter" do
let(:params) { {advanced_filters: ["winners"], budget_id: budget.id} }
it "returns only investment winners" do
investment1 = create(:budget_investment,
:winner,
valuation_finished: true,
budget: budget)
create(:budget_investment,
:with_administrator,
budget: budget)
create(:budget_investment, budget: budget)
expect(described_class.scoped_filter(params, "all")).to eq([investment1])
expect(described_class.scoped_filter(params, "all").count).to eq(1)
end
end
end
end

View File

@@ -121,4 +121,21 @@ describe Poll::Officer do
expect(assigned_polls.last).to eq(poll_3)
end
end
describe "todays_booths" do
let(:officer) { create(:poll_officer) }
it "returns booths for the application's time zone date", :with_different_time_zone do
assignment_with_local_time_zone = create(:poll_officer_assignment,
date: Date.today,
officer: officer)
assignment_with_application_time_zone = create(:poll_officer_assignment,
date: Date.current,
officer: officer)
expect(officer.todays_booths).to include(assignment_with_application_time_zone.booth)
expect(officer.todays_booths).not_to include(assignment_with_local_time_zone.booth)
end
end
end

View File

@@ -6,6 +6,7 @@ describe Poll::Voter do
let(:booth) { create(:poll_booth) }
let(:booth_assignment) { create(:poll_booth_assignment, poll: poll, booth: booth) }
let(:voter) { create(:poll_voter) }
let(:officer_assignment) { create(:poll_officer_assignment) }
describe "validations" do
@@ -97,6 +98,7 @@ describe Poll::Voter do
it "is valid with a booth origin" do
voter.origin = "booth"
voter.officer_assignment = officer_assignment
expect(voter).to be_valid
end
@@ -104,7 +106,27 @@ describe Poll::Voter do
voter.origin = "web"
expect(voter).to be_valid
end
end
context "assignments" do
it "should not be valid without a booth_assignment_id when origin is booth" do
voter.origin = "booth"
voter.booth_assignment_id = nil
expect(voter).not_to be_valid
end
it "should not be valid without an officer_assignment_id when origin is booth" do
voter.origin = "booth"
voter.officer_assignment_id = nil
expect(voter).not_to be_valid
end
it "should be valid without assignments when origin is web" do
voter.origin = "web"
voter.booth_assignment_id = nil
voter.officer_assignment_id = nil
expect(voter).to be_valid
end
end
end

View File

@@ -21,4 +21,15 @@ module CommonActions
check "user_terms_of_service"
end
def validate_officer
allow_any_instance_of(Officing::BaseController).
to receive(:verify_officer_assignment).and_return(true)
end
def set_officing_booth(booth=nil)
booth = create(:poll_booth) if booth.blank?
allow_any_instance_of(Officing::BaseController).
to receive(:current_booth).and_return(booth)
end
end