adds budget results
This commit is contained in:
21
app/controllers/budgets/results_controller.rb
Normal file
21
app/controllers/budgets/results_controller.rb
Normal file
@@ -0,0 +1,21 @@
|
||||
module Budgets
|
||||
class ResultsController < ApplicationController
|
||||
|
||||
load_and_authorize_resource :budget
|
||||
|
||||
def show
|
||||
@result = load_result
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def load_result
|
||||
Budget::Result.new(@budget, heading)
|
||||
end
|
||||
|
||||
def heading
|
||||
@budget.headings.find(params[:heading_id])
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
@@ -55,4 +55,8 @@ module ApplicationHelper
|
||||
def content_block(name, locale)
|
||||
SiteCustomization::ContentBlock.block_for(name, locale)
|
||||
end
|
||||
|
||||
def format_price(number)
|
||||
number_to_currency(number, precision: 0, locale: I18n.default_locale)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -33,6 +33,7 @@ class Budget
|
||||
validates :terms_of_service, acceptance: { allow_nil: false }, on: :create
|
||||
|
||||
scope :sort_by_confidence_score, -> { reorder(confidence_score: :desc, id: :desc) }
|
||||
scope :sort_by_ballots, -> { reorder(ballot_lines_count: :desc, id: :desc) }
|
||||
scope :sort_by_price, -> { reorder(price: :desc, confidence_score: :desc, id: :desc) }
|
||||
scope :sort_by_random, -> { reorder("RANDOM()") }
|
||||
|
||||
|
||||
55
app/models/budget/result.rb
Normal file
55
app/models/budget/result.rb
Normal file
@@ -0,0 +1,55 @@
|
||||
class Budget
|
||||
class Result
|
||||
|
||||
attr_accessor :budget, :heading, :money_spent, :current_investment
|
||||
|
||||
def initialize(budget, heading)
|
||||
@budget = budget
|
||||
@heading = heading
|
||||
end
|
||||
|
||||
def calculate_winners
|
||||
reset_winners
|
||||
investments.each do |investment|
|
||||
@current_investment = investment
|
||||
if inside_budget?
|
||||
set_winner
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def investments
|
||||
heading.investments.selected.sort_by_ballots
|
||||
end
|
||||
|
||||
def inside_budget?
|
||||
available_budget >= @current_investment.price
|
||||
end
|
||||
|
||||
def available_budget
|
||||
total_budget - money_spent
|
||||
end
|
||||
|
||||
def total_budget
|
||||
heading.price
|
||||
end
|
||||
|
||||
def money_spent
|
||||
@money_spent ||= 0
|
||||
end
|
||||
|
||||
def reset_winners
|
||||
investments.update_all(winner: false)
|
||||
end
|
||||
|
||||
def set_winner
|
||||
@money_spent += @current_investment.price
|
||||
@current_investment.update(winner: true)
|
||||
end
|
||||
|
||||
def winners
|
||||
investments.where(winner: true)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
76
app/views/budgets/results/_results_table.html.erb
Normal file
76
app/views/budgets/results/_results_table.html.erb
Normal file
@@ -0,0 +1,76 @@
|
||||
<div class="small-12 medium-10 column" id="results-container">
|
||||
<h2 class="inline-block">
|
||||
<%= heading.name %>
|
||||
</h2>
|
||||
|
||||
<span class="float-right">
|
||||
<%= link_to t("budgets.results.show_all_link"), "#",
|
||||
class: "js-toggle-link button hollow margin-bottom",
|
||||
data: {'toggle-selector' => '.js-discarded',
|
||||
'toggle-text' => t("budgets.results.hide_discarded_link")} %>
|
||||
</span>
|
||||
|
||||
<table id="budget-investments-results">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">
|
||||
<%= t("budgets.results.spending_proposal") %>
|
||||
</th>
|
||||
<th scope="col" class="text-right">
|
||||
<%= t("budgets.results.ballot_lines_count") %>
|
||||
</th>
|
||||
<th scope="col" class="text-right">
|
||||
<%= t("budgets.results.price") %>
|
||||
</th>
|
||||
<th scope="col" class="text-right"
|
||||
title="<%= t("budgets.results.amount_available") %>"
|
||||
style="width:120px">
|
||||
<%= format_price(heading.price) %>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<% amount_available = heading.price %>
|
||||
<% @result.investments.each do |investment| %>
|
||||
<% if investment.winner? %>
|
||||
<tr id="<%= dom_id(investment) %>"
|
||||
class="spending_proposal success">
|
||||
<% else %>
|
||||
<tr id="<%= dom_id(investment) %>"
|
||||
class="spending_proposal js-discarded" style="display:none">
|
||||
<% end %>
|
||||
<td>
|
||||
<% if investment.winner? %>
|
||||
<span class="icon-check">
|
||||
<span class="sr-only">
|
||||
<%= t("budgets.results.accepted") %>
|
||||
</span>
|
||||
</span>
|
||||
<% else %>
|
||||
<span class="icon-x">
|
||||
<span class="sr-only">
|
||||
<%= t("budgets.results.discarded") %>
|
||||
</span>
|
||||
</span>
|
||||
<% end %>
|
||||
<%= link_to investment.title,
|
||||
budget_investment_path(@budget, investment) %>
|
||||
</td>
|
||||
<td class="text-right">
|
||||
<%= investment.ballot_lines_count %>
|
||||
</td>
|
||||
<td class="text-right" style="width:100px">
|
||||
<%= format_price investment.price %>
|
||||
</td>
|
||||
<td class="small text-right"
|
||||
title="<%= format_price(amount_available) %> - <%= format_price(investment.price) %>">
|
||||
<%= format_price amount_available - investment.price %>
|
||||
<% amount_available -= investment.price if investment.winner? %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
50
app/views/budgets/results/show.html.erb
Normal file
50
app/views/budgets/results/show.html.erb
Normal file
@@ -0,0 +1,50 @@
|
||||
<% provide :title, t("budgets.results.page_title") %>
|
||||
|
||||
<div class="expanded spending-proposals results no-margin-top">
|
||||
<div class="row">
|
||||
<div class="small-12 column padding text-center">
|
||||
<%= link_to budgets_path, class: "left back" do %>
|
||||
<i class="icon-angle-left"></i>
|
||||
<%= t("shared.back") %>
|
||||
<% end %>
|
||||
|
||||
<h1 class="title">
|
||||
<%= t("budgets.results.heading") %>
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row margin-top">
|
||||
<div class="small-12 column">
|
||||
<ul class="tabs">
|
||||
<li class="tabs-title is-active">
|
||||
<span class="sr-only">
|
||||
<%= t("shared.you_are_in") %>
|
||||
</span>
|
||||
<%= link_to t("budgets.results.results_link"), "#", class: "is-active" %>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="small-12 medium-2 column">
|
||||
<ul class="menu vertical no-padding">
|
||||
<li>
|
||||
<strong>
|
||||
<%= t("budgets.results.geozone_selection_title") %>
|
||||
</strong>
|
||||
</li>
|
||||
|
||||
<% @budget.headings.each do |heading| %>
|
||||
<li>
|
||||
<%= link_to content_tag(:strong, heading.name),
|
||||
budget_results_path(@budget, heading_id: heading.id) %>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<%= render 'results_table', heading: @result.heading %>
|
||||
</div>
|
||||
@@ -115,3 +115,18 @@ en:
|
||||
unfeasible: See unfeasible investments
|
||||
unselected_title: Investments not selected for balloting phase
|
||||
unselected: See investments not selected for balloting phase
|
||||
results:
|
||||
page_title: "Participatory budget | Results"
|
||||
heading: "PARTICIPATORY BUDGET"
|
||||
results_link: Results
|
||||
stats_link: "Participation stats"
|
||||
geozone_selection_title: "By district"
|
||||
spending_proposal: Proposal title
|
||||
ballot_lines_count: Times selected
|
||||
hide_discarded_link: Hide discarded
|
||||
show_all_link: Show all
|
||||
price: Cost
|
||||
amount_available: Available budget
|
||||
incompatible: Incompatibles
|
||||
accepted: "Accepted spending proposal: "
|
||||
discarded: "Discarded spending proposal: "
|
||||
@@ -113,5 +113,25 @@ es:
|
||||
phase: Fase actual
|
||||
unfeasible_title: Propuestas inviables
|
||||
unfeasible: Ver las propuestas inviables
|
||||
<<<<<<< f0d7acd087346edce149efed36e057eb4b792a4c
|
||||
unselected_title: Propuestas no seleccionadas para la votación final
|
||||
unselected: Ver las propuestas no seleccionadas para la votación final
|
||||
=======
|
||||
unselected_title: Propuestas que no pasan a la votación final
|
||||
unselected: Ver las propuestas que no pasan a la votación final
|
||||
results:
|
||||
page_title: "Presupuestos participativos | Resultados"
|
||||
heading: "PRESUPUESTOS PARTICIPATIVOS"
|
||||
results_link: Resultados
|
||||
stats_link: "Estadísticas de participación"
|
||||
geozone_selection_title: "Ámbito de actuación"
|
||||
spending_proposal: Título
|
||||
ballot_lines_count: Votos
|
||||
hide_discarded_link: Ocultar descartadas
|
||||
show_all_link: Mostrar todas
|
||||
price: Coste
|
||||
amount_available: Presupuesto disponible
|
||||
incompatible: Incompatibles
|
||||
accepted: "Propuesta de inversión aceptada: "
|
||||
discarded: "Propuesta de inversión descartada: "
|
||||
>>>>>>> adds budget results
|
||||
|
||||
@@ -77,6 +77,7 @@ Rails.application.routes.draw do
|
||||
resource :ballot, only: :show, controller: "budgets/ballots" do
|
||||
resources :lines, controller: "budgets/ballot/lines", only: [:create, :destroy]
|
||||
end
|
||||
resource :results, only: :show, controller: "budgets/results"
|
||||
end
|
||||
|
||||
scope '/participatory_budget' do
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
class AddWinnerToBudgetInvestments < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :budget_investments, :winner, :boolean, default: false
|
||||
end
|
||||
end
|
||||
@@ -11,7 +11,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20170517123042) do
|
||||
ActiveRecord::Schema.define(version: 20170519084239) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
@@ -147,6 +147,7 @@ ActiveRecord::Schema.define(version: 20170517123042) do
|
||||
t.datetime "unfeasible_email_sent_at"
|
||||
t.integer "ballot_lines_count", default: 0
|
||||
t.integer "previous_heading_id"
|
||||
t.boolean "winner", default: false
|
||||
end
|
||||
|
||||
add_index "budget_investments", ["administrator_id"], name: "index_budget_investments_on_administrator_id", using: :btree
|
||||
|
||||
Reference in New Issue
Block a user