Merge pull request #1123 from consul/budget-headings

Budget headings
This commit is contained in:
Juanjo Bazán
2016-05-23 11:51:44 +02:00
6 changed files with 70 additions and 29 deletions

View File

@@ -2,7 +2,7 @@ class Budget
class Ballot < ActiveRecord::Base
belongs_to :user
belongs_to :budget
belongs_to :geozone
belongs_to :heading
has_many :lines, dependent: :destroy
has_many :spending_proposals, through: :lines

View File

@@ -0,0 +1,10 @@
class Budget
class Heading < ActiveRecord::Base
belongs_to :budget
belongs_to :geozone
validates :budget_id, presence: true
validates :name, presence: true
validates :price, presence: true
end
end

View File

@@ -11,12 +11,13 @@ class Budget
include ActsAsParanoidAliases
belongs_to :author, -> { with_hidden }, class_name: 'User', foreign_key: 'author_id'
belongs_to :geozone
belongs_to :heading
belongs_to :administrator
has_many :valuation_assignments, dependent: :destroy
has_many :valuators, through: :valuation_assignments
has_many :comments, as: :commentable
has_many :headings, dependent: :destroy
validates :title, presence: true
validates :author, presence: true
@@ -46,53 +47,54 @@ class Budget
scope :by_tag, -> (tag_name) { tagged_with(tag_name) }
scope :by_valuator, -> (valuator_id) { where("valuation_assignments.valuator_id = ?", valuator_id).joins(:valuation_assignments) }
scope :for_render, -> { includes(:geozone) }
scope :for_render, -> { includes(heading: :geozone) }
scope :with_geozone, -> { where.not(geozone_id: nil) }
scope :no_geozone, -> { where(geozone_id: nil) }
scope :with_heading, -> { where.not(heading_id: nil) }
scope :no_heading, -> { where(heading_id: nil) }
before_save :calculate_confidence_score
before_validation :set_responsible_name
def self.filter_params(params)
params.select{|x,_| %w{geozone_id administrator_id tag_name valuator_id}.include? x.to_s }
params.select{|x,_| %w{heading_id administrator_id tag_name valuator_id}.include? x.to_s }
end
def self.scoped_filter(params, current_filter)
budget = Budget.find!(params[:budget_id])
results = self.by_budget(params[:budget_id])
if params[:max_for_no_geozone].present? || params[:max_per_geozone].present?
results = limit_results(results, params[:max_per_geozone].to_i, params[:max_for_no_geozone].to_i)
if params[:max_for_no_heading].present? || params[:max_per_heading].present?
results = limit_results(results, budget, params[:max_per_heading].to_i, params[:max_for_no_heading].to_i)
end
results = results.by_geozone(params[:geozone_id]) if params[:geozone_id].present?
results = results.by_heading(params[:heading_id]) if params[:heading_id].present?
results = results.by_admin(params[:administrator_id]) if params[:administrator_id].present?
results = results.by_tag(params[:tag_name]) if params[:tag_name].present?
results = results.by_valuator(params[:valuator_id]) if params[:valuator_id].present?
results = results.send(current_filter) if current_filter.present?
results.includes(:geozone, administrator: :user, valuators: :user)
results.includes(:heading, administrator: :user, valuators: :user)
end
def self.limit_results(results, max_per_geozone, max_for_no_geozone)
return results if max_per_geozone <= 0 && max_for_no_geozone <= 0
def self.limit_results(results, budget, max_per_heading, max_for_no_heading)
return results if max_per_heading <= 0 && max_for_no_heading <= 0
ids = []
if max_per_geozone > 0
Geozone.pluck(:id).each do |gid|
ids += Investment.where(geozone_id: gid).order(confidence_score: :desc).limit(max_per_geozone).pluck(:id)
if max_per_heading > 0
budget.headings.pluck(:id).each do |hid|
ids += Investment.where(heading_id: hid).order(confidence_score: :desc).limit(max_per_heading).pluck(:id)
end
end
if max_for_no_geozone > 0
ids += Investment.no_geozone.order(confidence_score: :desc).limit(max_for_no_geozone).pluck(:id)
if max_for_no_heading > 0
ids += Investment.no_heading.order(confidence_score: :desc).limit(max_for_no_heading).pluck(:id)
end
conditions = ["investments.id IN (?)"]
values = [ids]
if max_per_geozone == 0
conditions << "investments.geozone_id IS NOT ?"
if max_per_heading == 0
conditions << "investments.heading_id IS NOT ?"
values << nil
elsif max_for_no_geozone == 0
conditions << "investments.geozone_id IS ?"
elsif max_for_no_heading == 0
conditions << "investments.heading_id IS ?"
values << nil
end
@@ -102,7 +104,7 @@ class Budget
def searchable_values
{ title => 'A',
author.username => 'B',
geozone.try(:name) => 'B',
heading.try(:name) => 'B',
description => 'C'
}
end
@@ -111,8 +113,8 @@ class Budget
self.pg_search(terms)
end
def self.by_geozone(geozone)
where(geozone_id: geozone == 'all' ? nil : geozone.presence)
def self.by_heading(heading)
where(heading_id: heading == 'all' ? nil : heading.presence)
end
def undecided?
@@ -156,7 +158,7 @@ class Budget
def reason_for_not_being_ballotable_by(user, ballot)
return permission_problem(user) if permission_problem?(user)
return :no_ballots_allowed unless budget.balloting?
return :different_geozone_assigned unless geozone_id.blank? || ballot.blank? || geozone_id == ballot.geozone_id || ballot.geozone_id.nil?
return :different_heading_assigned unless heading_id.blank? || ballot.blank? || heading_id == ballot.heading_id || ballot.heading_id.nil?
return :not_enough_money unless enough_money?(ballot)
end
@@ -181,7 +183,7 @@ class Budget
def enough_money?(ballot)
return true if ballot.blank?
available_money = ballot.amount_available(geozone)
available_money = ballot.amount_available(heading)
price.to_i <= available_money
end

View File

@@ -0,0 +1,10 @@
class CreateBudgetHeading < ActiveRecord::Migration
def change
create_table :budget_headings do |t|
t.references :budget
t.references :geozone
t.string :name, limit: 50
t.integer :price, limit: 8
end
end
end

View File

@@ -0,0 +1,9 @@
class ReplaceGeozonesByHeadingsInBudgets < ActiveRecord::Migration
def change
remove_column :budget_investments, :geozone_id
remove_column :budget_ballots, :geozone_id
add_reference :budget_investments, :heading, index: true
add_reference :budget_ballots, :heading, index: true
end
end

View File

@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20160520100347) do
ActiveRecord::Schema.define(version: 20160520114820) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -74,15 +74,23 @@ ActiveRecord::Schema.define(version: 20160520100347) do
add_index "budget_ballot_lines", ["investment_id"], name: "index_budget_ballot_lines_on_investment_id", using: :btree
create_table "budget_ballots", force: :cascade do |t|
t.integer "geozone_id"
t.integer "user_id"
t.integer "budget_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "heading_id"
end
add_index "budget_ballots", ["heading_id"], name: "index_budget_ballots_on_heading_id", using: :btree
create_table "budget_headings", force: :cascade do |t|
t.integer "budget_id"
t.integer "geozone_id"
t.string "name", limit: 50
t.integer "price", limit: 8
end
create_table "budget_investments", force: :cascade do |t|
t.integer "geozone_id"
t.integer "author_id"
t.integer "administrator_id"
t.string "title"
@@ -105,10 +113,12 @@ ActiveRecord::Schema.define(version: 20160520100347) do
t.tsvector "tsv"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "heading_id"
end
add_index "budget_investments", ["administrator_id"], name: "index_budget_investments_on_administrator_id", using: :btree
add_index "budget_investments", ["author_id"], name: "index_budget_investments_on_author_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
create_table "budgets", force: :cascade do |t|