stores reclassified votes

This commit is contained in:
rgarcia
2017-05-17 15:13:28 +02:00
parent 4787ee5716
commit 42f62e5c36
9 changed files with 179 additions and 23 deletions

View File

@@ -13,6 +13,8 @@ class Budget
validate :check_sufficient_funds validate :check_sufficient_funds
validate :check_valid_heading validate :check_valid_heading
scope :by_investment, -> (investment_id) { where(investment_id: investment_id) }
before_validation :set_denormalized_ids before_validation :set_denormalized_ids
def check_sufficient_funds def check_sufficient_funds

View File

@@ -244,22 +244,40 @@ class Budget
end end
def check_for_reclassification def check_for_reclassification
if reclassified? if heading_changed?
log_reclassification log_heading_change
store_reclassified_votes("heading_changed")
remove_reclassified_votes
elsif marked_as_unfeasible?
store_reclassified_votes("unfeasible")
remove_reclassified_votes remove_reclassified_votes
end end
end end
def reclassified? def heading_changed?
budget.balloting? && heading_id_changed? budget.balloting? && heading_id_changed?
end end
def log_reclassification def log_heading_change
update_column(:previous_heading_id, heading_id_was) update_column(:previous_heading_id, heading_id_was)
end end
def marked_as_unfeasible?
budget.balloting? && feasibility_changed? && unfeasible?
end
def store_reclassified_votes(reason)
ballot_lines_for_investment.each do |line|
Budget::ReclassifiedVote.create!(user: line.ballot.user, investment: self, reason: reason)
end
end
def remove_reclassified_votes def remove_reclassified_votes
Budget::Ballot::Line.where(investment: self).destroy_all ballot_lines_for_investment.destroy_all
end
def ballot_lines_for_investment
Budget::Ballot::Line.by_investment(self.id)
end end
private private

View File

@@ -0,0 +1,12 @@
class Budget
class ReclassifiedVote < ActiveRecord::Base
REASONS = %w(heading_changed unfeasible)
belongs_to :user
belongs_to :investment
validates :user, presence: true
validates :investment, presence: true
validates :reason, inclusion: {in: REASONS, allow_nil: false}
end
end

View File

@@ -0,0 +1,11 @@
class CreateBudgetReclassifiedVotes < ActiveRecord::Migration
def change
create_table :budget_reclassified_votes do |t|
t.integer :user_id
t.integer :investment_id
t.string :reason, default: nil
t.timestamps null: false
end
end
end

View File

@@ -11,7 +11,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20170513110025) do ActiveRecord::Schema.define(version: 20170517123042) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
@@ -63,6 +63,12 @@ ActiveRecord::Schema.define(version: 20170513110025) do
add_index "annotations", ["legislation_id"], name: "index_annotations_on_legislation_id", using: :btree add_index "annotations", ["legislation_id"], name: "index_annotations_on_legislation_id", using: :btree
add_index "annotations", ["user_id"], name: "index_annotations_on_user_id", using: :btree add_index "annotations", ["user_id"], name: "index_annotations_on_user_id", using: :btree
create_table "ar_internal_metadata", primary_key: "key", force: :cascade do |t|
t.string "value"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "banners", force: :cascade do |t| create_table "banners", force: :cascade do |t|
t.string "title", limit: 80 t.string "title", limit: 80
t.string "description" t.string "description"
@@ -154,6 +160,14 @@ ActiveRecord::Schema.define(version: 20170513110025) do
add_index "budget_investments", ["heading_id"], name: "index_budget_investments_on_heading_id", using: :btree add_index "budget_investments", ["heading_id"], name: "index_budget_investments_on_heading_id", using: :btree
add_index "budget_investments", ["tsv"], name: "index_budget_investments_on_tsv", using: :gin add_index "budget_investments", ["tsv"], name: "index_budget_investments_on_tsv", using: :gin
create_table "budget_reclassified_votes", force: :cascade do |t|
t.integer "user_id"
t.integer "investment_id"
t.string "reason"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "budget_valuator_assignments", force: :cascade do |t| create_table "budget_valuator_assignments", force: :cascade do |t|
t.integer "valuator_id" t.integer "valuator_id"
t.integer "investment_id" t.integer "investment_id"

View File

@@ -302,6 +302,12 @@ FactoryGirl.define do
association :investment, factory: :budget_investment association :investment, factory: :budget_investment
end end
factory :budget_reclassified_vote, class: 'Budget::ReclassifiedVote' do
user
association :investment, factory: :budget_investment
reason "unfeasible"
end
factory :vote do factory :vote do
association :votable, factory: :debate association :votable, factory: :debate
association :voter, factory: :user association :voter, factory: :user

View File

@@ -2,7 +2,6 @@ require 'rails_helper'
describe "Budget::Ballot::Line" do describe "Budget::Ballot::Line" do
describe 'Validations' do
let(:budget){ create(:budget) } let(:budget){ create(:budget) }
let(:group){ create(:budget_group, budget: budget) } let(:group){ create(:budget_group, budget: budget) }
let(:heading){ create(:budget_heading, group: group, price: 10000000) } let(:heading){ create(:budget_heading, group: group, price: 10000000) }
@@ -10,6 +9,8 @@ describe "Budget::Ballot::Line" do
let(:ballot) { create(:budget_ballot, budget: budget) } let(:ballot) { create(:budget_ballot, budget: budget) }
let(:ballot_line) { build(:budget_ballot_line, ballot: ballot, investment: investment) } let(:ballot_line) { build(:budget_ballot_line, ballot: ballot, investment: investment) }
describe 'Validations' do
it "should be valid and automatically denormallyze budget, group and heading when validated" do it "should be valid and automatically denormallyze budget, group and heading when validated" do
expect(ballot_line).to be_valid expect(ballot_line).to be_valid
expect(ballot_line.budget).to eq(budget) expect(ballot_line.budget).to eq(budget)
@@ -42,4 +43,30 @@ describe "Budget::Ballot::Line" do
end end
end end
describe "scopes" do
describe "by_investment" do
it "should return ballot lines for an investment" do
investment1 = create(:budget_investment, :selected, heading: heading)
investment2 = create(:budget_investment, :selected, heading: heading)
ballot1 = create(:budget_ballot, budget: budget)
ballot2 = create(:budget_ballot, budget: budget)
ballot3 = create(:budget_ballot, budget: budget)
ballot_line1 = create(:budget_ballot_line, ballot: ballot1, investment: investment1)
ballot_line2 = create(:budget_ballot_line, ballot: ballot2, investment: investment1)
ballot_line3 = create(:budget_ballot_line, ballot: ballot3, investment: investment2)
ballot_lines_by_investment = Budget::Ballot::Line.by_investment(investment1.id)
expect(ballot_lines_by_investment).to include ballot_line1
expect(ballot_lines_by_investment).to include ballot_line2
expect(ballot_lines_by_investment).to_not include ballot_line3
end
end
end
end end

View File

@@ -681,27 +681,27 @@ describe Budget::Investment do
end end
describe "Reclassification" do describe "Reclassification", :focus do
let(:budget) { create(:budget, phase: "balloting") } let(:budget) { create(:budget, phase: "balloting") }
let(:group) { create(:budget_group, budget: budget) } let(:group) { create(:budget_group, budget: budget) }
let(:heading1) { create(:budget_heading, group: group) } let(:heading1) { create(:budget_heading, group: group) }
let(:heading2) { create(:budget_heading, group: group) } let(:heading2) { create(:budget_heading, group: group) }
describe "reclassified?" do describe "heading_changed?" do
it "returns true if budget is in balloting phase and heading has changed" do it "returns true if budget is in balloting phase and heading has changed" do
investment = create(:budget_investment, heading: heading1) investment = create(:budget_investment, heading: heading1)
investment.heading = heading2 investment.heading = heading2
expect(investment.reclassified?).to eq(true) expect(investment.heading_changed?).to eq(true)
end end
it "returns false if heading has not changed" do it "returns false if heading has not changed" do
investment = create(:budget_investment) investment = create(:budget_investment)
investment.heading = investment.heading investment.heading = investment.heading
expect(investment.reclassified?).to eq(false) expect(investment.heading_changed?).to eq(false)
end end
it "returns false if budget is not balloting phase" do it "returns false if budget is not balloting phase" do
@@ -711,13 +711,13 @@ describe Budget::Investment do
investment.heading = heading2 investment.heading = heading2
expect(investment.reclassified?).to eq(false) expect(investment.heading_changed?).to eq(false)
end end
end end
end end
describe "log_reclassification" do describe "log_heading_change" do
it "stores the previous heading before being reclassified" do it "stores the previous heading before being reclassified" do
investment = create(:budget_investment, heading: heading1) investment = create(:budget_investment, heading: heading1)
@@ -735,6 +735,30 @@ describe Budget::Investment do
end end
describe "store_reclassified_votes" do
it "stores the votes for a reclassified investment", :focus do
investment = create(:budget_investment, :selected, heading: heading1)
3.times do
ballot = create(:budget_ballot, budget: budget)
ballot.investments << investment
end
expect(investment.ballot_lines_count).to eq(3)
investment.heading = heading2
investment.store_reclassified_votes("heading_changed")
reclassified_vote = Budget::ReclassifiedVote.first
expect(Budget::ReclassifiedVote.count).to eq(3)
expect(reclassified_vote.investment_id).to eq(investment.id)
expect(reclassified_vote.user_id).to eq(Budget::Ballot.first.user.id)
expect(reclassified_vote.reason).to eq("heading_changed")
end
end
describe "remove_reclassified_votes" do describe "remove_reclassified_votes" do
it "removes votes from invesment" do it "removes votes from invesment" do
@@ -756,9 +780,9 @@ describe Budget::Investment do
end end
describe "check_for_reclassification" do describe "check_for_reclassification", :focus do
it "removes votes if an investment has been reclassified" do it "stores reclassfied votes and removes actual votes if an investment has been reclassified" do
investment = create(:budget_investment, :selected, heading: heading1) investment = create(:budget_investment, :selected, heading: heading1)
3.times do 3.times do
@@ -773,9 +797,10 @@ describe Budget::Investment do
investment.reload investment.reload
expect(investment.ballot_lines_count).to eq(0) expect(investment.ballot_lines_count).to eq(0)
expect(Budget::ReclassifiedVote.count).to eq(3)
end end
it "does not remove votes if the investment has not been reclassifed" do it "does not store reclassified votes nor remove actual votes if the investment has not been reclassifed" do
investment = create(:budget_investment, :selected, heading: heading1) investment = create(:budget_investment, :selected, heading: heading1)
3.times do 3.times do
@@ -789,6 +814,7 @@ describe Budget::Investment do
investment.reload investment.reload
expect(investment.ballot_lines_count).to eq(3) expect(investment.ballot_lines_count).to eq(3)
expect(Budget::ReclassifiedVote.count).to eq(0)
end end
end end

View File

@@ -0,0 +1,40 @@
require 'rails_helper'
describe Budget::ReclassifiedVote do
describe "Validations", :focus do
let(:reclassified_vote) { build(:budget_reclassified_vote) }
it "should be valid" do
expect(reclassified_vote).to be_valid
end
it "should not be valid without a user" do
reclassified_vote.user_id = nil
expect(reclassified_vote).to_not be_valid
end
it "should not be valid without an investment" do
reclassified_vote.investment_id = nil
expect(reclassified_vote).to_not be_valid
end
it "should not be valid without a valid reason" do
reclassified_vote.reason = nil
expect(reclassified_vote).to_not be_valid
reclassified_vote.reason = ""
expect(reclassified_vote).to_not be_valid
reclassified_vote.reason = "random"
expect(reclassified_vote).to_not be_valid
reclassified_vote.reason = "heading_changed"
expect(reclassified_vote).to be_valid
reclassified_vote.reason = "unfeasible"
expect(reclassified_vote).to be_valid
end
end
end