diff --git a/app/assets/stylesheets/admin.scss b/app/assets/stylesheets/admin.scss index e864d9781..fd6ed0815 100644 --- a/app/assets/stylesheets/admin.scss +++ b/app/assets/stylesheets/admin.scss @@ -312,6 +312,11 @@ body.admin { } } +[class^="icon-"].delete { + border: 0; + font-size: $base-font-size; +} + .verified { color: $check; diff --git a/app/assets/stylesheets/layout.scss b/app/assets/stylesheets/layout.scss index 64684505c..fa0fd3455 100644 --- a/app/assets/stylesheets/layout.scss +++ b/app/assets/stylesheets/layout.scss @@ -234,6 +234,14 @@ a { color: $brand; } } + + &.no-margin-top { + margin-top: 0; + } + + &.no-padding-top { + padding-top: 0; + } } .small { @@ -1194,6 +1202,16 @@ table { } } +.table-for-mobile { + + @include breakpoint(medium down) { + th, td { + display: block; + text-align: left; + } + } +} + // 12. Social // ---------- diff --git a/app/controllers/budgets/results_controller.rb b/app/controllers/budgets/results_controller.rb new file mode 100644 index 000000000..aa94eb68b --- /dev/null +++ b/app/controllers/budgets/results_controller.rb @@ -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 \ No newline at end of file diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 0c23c0d22..6a040ec69 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -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 diff --git a/app/models/budget/investment.rb b/app/models/budget/investment.rb index 7d0aafb8a..56a50deec 100644 --- a/app/models/budget/investment.rb +++ b/app/models/budget/investment.rb @@ -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()") } diff --git a/app/models/budget/result.rb b/app/models/budget/result.rb new file mode 100644 index 000000000..f29bc72cc --- /dev/null +++ b/app/models/budget/result.rb @@ -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 \ No newline at end of file diff --git a/app/views/budgets/results/_results_table.html.erb b/app/views/budgets/results/_results_table.html.erb new file mode 100644 index 000000000..9024899b6 --- /dev/null +++ b/app/views/budgets/results/_results_table.html.erb @@ -0,0 +1,72 @@ +
| + <%= t("budgets.results.spending_proposal") %> + | ++ <%= t("budgets.results.ballot_lines_count") %> + | ++ <%= t("budgets.results.price") %> + | +
+ <%= format_price(heading.price) %> + <%= t("budgets.results.amount_available") %> + |
+
|---|---|---|---|
#{Faker::Lorem.paragraphs.join('
')}
", + created_at: rand((Time.now - 1.week) .. Time.now), + feasibility: "feasible", + valuation_finished: true, + selected: true, + price: rand(10000 .. heading.price), + terms_of_service: "1") +end +budget.headings.each do |heading| + Budget::Result.new(budget, heading).calculate_winners +end + puts " ✅" print "Creating Valuation Assignments" diff --git a/db/migrate/20170519084239_add_winner_to_budget_investments.rb b/db/migrate/20170519084239_add_winner_to_budget_investments.rb new file mode 100644 index 000000000..af6085468 --- /dev/null +++ b/db/migrate/20170519084239_add_winner_to_budget_investments.rb @@ -0,0 +1,5 @@ +class AddWinnerToBudgetInvestments < ActiveRecord::Migration + def change + add_column :budget_investments, :winner, :boolean, default: false + end +end diff --git a/db/schema.rb b/db/schema.rb index d3953f638..8a34df55d 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 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 diff --git a/spec/features/budgets/results_spec.rb b/spec/features/budgets/results_spec.rb new file mode 100644 index 000000000..961dd287e --- /dev/null +++ b/spec/features/budgets/results_spec.rb @@ -0,0 +1,48 @@ +require 'rails_helper' + +feature 'Results' do + + let(:budget) { create(:budget, phase: "finished") } + let(:group) { create(:budget_group, budget: budget) } + let(:heading) { create(:budget_heading, group: group, price: 1000) } + + let!(:investment1) { create(:budget_investment, :selected, heading: heading, price: 200, ballot_lines_count: 900) } + let!(:investment2) { create(:budget_investment, :selected, heading: heading, price: 300, ballot_lines_count: 800) } + let!(:investment3) { create(:budget_investment, :selected, heading: heading, price: 500, ballot_lines_count: 700) } + let!(:investment4) { create(:budget_investment, :selected, heading: heading, price: 100, ballot_lines_count: 600) } + + let!(:results) { Budget::Result.new(budget, heading).calculate_winners } + + scenario "Diplays winner investments" do + visit budget_path(budget) + click_link "See results" + + within("#budget-investments-results") do + expect(page).to have_content investment1.title + expect(page).to have_content investment2.title + expect(page).to have_content investment3.title + expect(page).to_not have_content investment4.title + + expect(investment1.title).to appear_before(investment2.title) + expect(investment2.title).to appear_before(investment3.title) + end + end + + scenario "Displays non winner investments", :js do + visit budget_path(budget) + click_link "See results" + click_link "Show all" + + within("#budget-investments-results") do + expect(page).to have_content investment1.title + expect(page).to have_content investment2.title + expect(page).to have_content investment3.title + expect(page).to have_content investment4.title + + expect(investment1.title).to appear_before(investment2.title) + expect(investment2.title).to appear_before(investment3.title) + expect(investment3.title).to appear_before(investment4.title) + end + end + +end \ No newline at end of file diff --git a/spec/models/budget/result_spec.rb b/spec/models/budget/result_spec.rb new file mode 100644 index 000000000..f96428221 --- /dev/null +++ b/spec/models/budget/result_spec.rb @@ -0,0 +1,35 @@ +require 'rails_helper' + +describe Budget::Result do + + describe "calculate_winners" do + let(:budget) { create(:budget) } + let(:group) { create(:budget_group, budget: budget) } + let(:heading) { create(:budget_heading, group: group, price: 1000) } + + it "calculates a budget's winner investments" do + investment1 = create(:budget_investment, :selected, heading: heading, price: 200, ballot_lines_count: 900) + investment2 = create(:budget_investment, :selected, heading: heading, price: 300, ballot_lines_count: 800) + investment3 = create(:budget_investment, :selected, heading: heading, price: 500, ballot_lines_count: 700) + investment4 = create(:budget_investment, :selected, heading: heading, price: 100, ballot_lines_count: 600) + + result = Budget::Result.new(budget, heading) + result.calculate_winners + + expect(result.winners).to eq([investment1, investment2, investment3]) + end + + it "resets winners before recalculating" do + investment1 = create(:budget_investment, :selected, heading: heading, price: 200, ballot_lines_count: 900, winner: true) + investment2 = create(:budget_investment, :selected, heading: heading, price: 300, ballot_lines_count: 800, winner: true) + investment3 = create(:budget_investment, :selected, heading: heading, price: 500, ballot_lines_count: 700, winner: true) + investment4 = create(:budget_investment, :selected, heading: heading, price: 100, ballot_lines_count: 600, winner: true) + + result = Budget::Result.new(budget, heading) + result.calculate_winners + + expect(result.winners).to eq([investment1, investment2, investment3]) + end + end + +end \ No newline at end of file