Verify poll ballots

This commit is contained in:
rgarcia
2018-07-04 15:29:51 +02:00
committed by Javi Martín
parent 1eaa5cc77b
commit aeb84108bc
10 changed files with 257 additions and 3 deletions

View File

@@ -2,6 +2,7 @@ class Budget
class Ballot < ActiveRecord::Base
belongs_to :user
belongs_to :budget
belongs_to :poll_ballot, class_name: "Poll::Ballot"
has_many :lines, dependent: :destroy
has_many :investments, through: :lines

View File

@@ -40,7 +40,7 @@ class Budget
end
def store_user_heading
ballot.user.update(balloted_heading_id: heading.id)
ballot.user.update(balloted_heading_id: heading.id) unless ballot.physical == true
end
end
end

36
app/models/poll/ballot.rb Normal file
View File

@@ -0,0 +1,36 @@
class Poll::Ballot < ActiveRecord::Base
belongs_to :ballot_sheet, class_name: Poll::BallotSheet
validates :ballot_sheet_id, presence: true
def verify
investments.each do |investment_id|
add_investment(investment_id)
end
end
def add_investment(investment_id)
investment = find_investment(investment_id)
if investment.present? && not_already_added?(investment)
ballot.add_investment(investment)
end
end
def investments
data.split(",")
end
def ballot
Budget::Ballot.where(poll_ballot: self).first
end
def find_investment(investment_id)
ballot.budget.investments.where(id: investment_id).first
end
def not_already_added?(investment)
ballot.lines.where(investment: investment).blank?
end
end

View File

@@ -1,6 +1,7 @@
class Poll::BallotSheet < ActiveRecord::Base
belongs_to :poll
belongs_to :officer_assignment
has_many :ballots, class_name: Poll::Ballot
validates :data, presence: true
validates :poll_id, presence: true
@@ -9,4 +10,33 @@ class Poll::BallotSheet < ActiveRecord::Base
def author
officer_assignment.officer.name
end
def verify_ballots
parsed_ballots.each_with_index do |investment_ids, index|
ballot = create_ballots(investment_ids, index)
ballot.verify
end
end
def parsed_ballots
data.split(/[;\n]/)
end
private
def create_ballots(investment_ids, index)
poll_ballot = Poll::Ballot.where(ballot_sheet: self,
data: investment_ids,
external_id: index).first_or_create
create_ballot(poll_ballot)
poll_ballot
end
def create_ballot(poll_ballot)
Budget::Ballot.where(physical: true,
user: nil,
poll_ballot: poll_ballot,
budget: poll.budget).first_or_create
end
end

View File

@@ -0,0 +1,10 @@
class CreatePollBallot < ActiveRecord::Migration
def change
create_table :poll_ballots do |t|
t.integer :ballot_sheet_id
t.text :data
t.integer :external_id
t.timestamps null: false
end
end
end

View File

@@ -0,0 +1,6 @@
class AddPhysicalToBudgetBallot < ActiveRecord::Migration
def change
add_column :budget_ballots, :physical, :boolean, default: false
add_column :budget_ballots, :poll_ballot_id, :integer
end
end

View File

@@ -142,6 +142,8 @@ ActiveRecord::Schema.define(version: 20190205131722) do
t.integer "budget_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "physical", default: false
t.integer "poll_ballot_id"
end
create_table "budget_content_blocks", force: :cascade do |t|
@@ -938,6 +940,14 @@ ActiveRecord::Schema.define(version: 20190205131722) do
add_index "poll_ballot_sheets", ["officer_assignment_id"], name: "index_poll_ballot_sheets_on_officer_assignment_id", using: :btree
add_index "poll_ballot_sheets", ["poll_id"], name: "index_poll_ballot_sheets_on_poll_id", using: :btree
create_table "poll_ballots", force: :cascade do |t|
t.integer "ballot_sheet_id"
t.text "data"
t.integer "external_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "poll_booth_assignments", force: :cascade do |t|
t.integer "booth_id"
t.integer "poll_id"

View File

@@ -153,6 +153,11 @@ FactoryBot.define do
data "1234;9876;5678\n1000;2000;3000;9999"
end
factory :poll_ballot, class: "Poll::Ballot" do
association :ballot_sheet, factory: :poll_ballot_sheet
data "1,2,3"
end
factory :officing_residence, class: "Officing::Residence" do
user
association :officer, factory: :poll_officer

View File

@@ -37,4 +37,24 @@ describe Poll::BallotSheet do
end
describe "#verify_ballots" do
it "creates ballots for each document number" do
budget = create(:budget)
poll = create(:poll, budget: budget)
poll_ballot = create(:poll_ballot_sheet, poll: poll, data: "1,2,3;4,5,6")
poll_ballot.verify_ballots
expect(Poll::Ballot.count).to eq(2)
expect(Budget::Ballot.count).to eq(2)
end
end
describe "#parsed_ballots" do
it "splits ballots by ';' or '\n'" do
data = "1,2,3;4,5,6\n7,8,9"
ballot_sheet.update(data: data)
expect(ballot_sheet.parsed_ballots).to eq(["1,2,3", "4,5,6", "7,8,9"])
end
end
end

View File

@@ -0,0 +1,136 @@
require "rails_helper"
describe Poll::Ballot do
let(:budget){ create(:budget) }
let(:group){ create(:budget_group, budget: budget) }
let(:heading){ create(:budget_heading, group: group, price: 10000000) }
let(:investment){ create(:budget_investment, :selected, price: 5000000, heading: heading) }
let(:poll) { create(:poll, budget: budget) }
let(:poll_ballot_sheet) { create(:poll_ballot_sheet, poll: poll) }
let(:poll_ballot) { create(:poll_ballot, ballot_sheet: poll_ballot_sheet, external_id: 1, data: investment.id) }
let!(:ballot) { create(:budget_ballot, budget: budget, physical: true, poll_ballot: poll_ballot) }
describe "#verify" do
it "adds ballot lines until there are sufficiente funds" do
investment2 = create(:budget_investment, :selected, price: 2000000, heading: heading)
investment3 = create(:budget_investment, :selected, price: 2000000, heading: heading)
investment4 = create(:budget_investment, :selected, price: 2000000, heading: heading)
poll_ballot.update(data: [investment.id, investment2.id, investment3.id, investment4.id].join(","))
poll_ballot.verify
expect(poll_ballot.ballot.lines.count).to eq(3)
expect(poll_ballot.ballot.lines.pluck(:investment_id).sort).to eq([investment.id, investment2.id, investment3.id].sort)
end
it "adds ballot lines if they are from valid headings" do
other_heading = create(:budget_heading, group: group, price: 10000000)
investment2 = create(:budget_investment, :selected, price: 2000000, heading: heading)
investment3 = create(:budget_investment, :selected, price: 2000000, heading: heading)
investment4 = create(:budget_investment, :selected, price: 2000000, heading: other_heading)
poll_ballot.update(data: [investment.id, investment2.id, investment3.id, investment4.id].join(","))
poll_ballot.verify
expect(poll_ballot.ballot.lines.count).to eq(3)
expect(poll_ballot.ballot.lines.pluck(:investment_id).sort).to eq([investment.id, investment2.id, investment3.id].sort)
end
it "adds ballot lines if they are from selectable" do
investment2 = create(:budget_investment, :selected, price: 2000000, heading: heading)
investment3 = create(:budget_investment, :selected, price: 2000000, heading: heading)
investment4 = create(:budget_investment, price: 2000000, heading: heading)
poll_ballot.update(data: [investment.id, investment2.id, investment3.id, investment4.id].join(","))
poll_ballot.verify
expect(poll_ballot.ballot.lines.count).to eq(3)
expect(poll_ballot.ballot.lines.pluck(:investment_id).sort).to eq([investment.id, investment2.id, investment3.id].sort)
end
end
describe "#add_investment" do
describe "Money" do
it "is not valid if insufficient funds" do
investment.update(price: heading.price + 1)
expect(poll_ballot.add_investment(investment.id)).to be(false)
end
it "is valid if sufficient funds" do
investment.update(price: heading.price - 1)
expect(poll_ballot.add_investment(investment.id)).to be(true)
end
end
describe "Heading" do
it "is not valid if investment heading is not valid" do
expect(poll_ballot.add_investment(investment.id)).to be(true)
other_heading = create(:budget_heading, group: group, price: 10000000)
other_investment = create(:budget_investment, :selected, price: 1000000, heading: other_heading)
expect(poll_ballot.add_investment(other_investment.id)).to be(false)
end
it "is valid if investment heading is valid" do
expect(poll_ballot.add_investment(investment.id)).to be(true)
other_investment = create(:budget_investment, :selected, price: 1000000, heading: heading)
expect(poll_ballot.add_investment(other_investment.id)).to be(true)
end
end
describe "Selectibility" do
it "is not valid if investment is unselected" do
investment.update(selected: false)
expect(poll_ballot.add_investment(investment.id)).to be(false)
end
it "is valid if investment is selected" do
investment.update(selected: true, price: 20000)
expect(poll_ballot.add_investment(investment.id)).to be(true)
end
end
describe "Budget" do
it "is not valid if investment belongs to a different budget" do
other_budget = create(:budget)
investment.update(budget: other_budget)
expect(poll_ballot.add_investment(investment.id)).to be(nil)
end
it "is valid if investment belongs to the poll's budget" do
expect(poll_ballot.add_investment(investment.id)).to be(true)
end
end
describe "Already added" do
it "is not valid if already exists" do
poll_ballot.add_investment(investment.id)
expect(poll_ballot.add_investment(investment.id)).to be(nil)
end
it "is valid if does not already exist" do
expect(poll_ballot.add_investment(investment.id)).to be(true)
end
end
end
describe "#find_investment" do
it "returns the investment if found" do
expect(poll_ballot.find_investment(investment.id)).to eq(investment)
end
it "finds investments with trailing zeros" do
expect(poll_ballot.find_investment("0#{investment.id}")).to eq(investment)
expect(poll_ballot.find_investment("00#{investment.id}")).to eq(investment)
end
end
end