class SpendingProposal < ActiveRecord::Base include Measurable include Sanitizable include Taggable include Searchable acts_as_votable belongs_to :author, -> { with_hidden }, class_name: 'User', foreign_key: 'author_id' belongs_to :geozone belongs_to :administrator has_many :valuation_assignments, dependent: :destroy has_many :valuators, through: :valuation_assignments validates :title, presence: true validates :author, presence: true validates :description, presence: true validates :feasible_explanation, presence: { if: :feasible_explanation_required? } validates :title, length: { in: 4..SpendingProposal.title_max_length } validates :description, length: { maximum: SpendingProposal.description_max_length } validates :terms_of_service, acceptance: { allow_nil: false }, on: :create scope :valuation_open, -> { where(valuation_finished: false) } scope :without_admin, -> { valuation_open.where(administrator_id: nil) } scope :managed, -> { valuation_open.where(valuation_assignments_count: 0).where("administrator_id IS NOT ?", nil) } scope :valuating, -> { valuation_open.where("valuation_assignments_count > 0 AND valuation_finished = ?", false) } scope :valuation_finished, -> { where(valuation_finished: true) } scope :feasible, -> { where(feasible: true) } scope :unfeasible, -> { where(feasible: false) } scope :not_unfeasible, -> { where("feasible IS ? OR feasible = ?", nil, true) } scope :with_supports, -> { where('cached_votes_up > 0') } scope :by_admin, ->(admin) { where(administrator_id: admin.presence) } scope :by_tag, ->(tag_name) { tagged_with(tag_name) } scope :by_valuator, ->(valuator) { where("valuation_assignments.valuator_id = ?", valuator.presence).joins(:valuation_assignments) } scope :for_render, -> { includes(:geozone) } before_validation :set_responsible_name def description super.try :html_safe end def self.filter_params(params) params.select{|x, _| %w{geozone_id administrator_id tag_name valuator_id}.include? x.to_s } end def self.scoped_filter(params, current_filter) results = self results = results.by_geozone(params[:geozone_id]) if params[:geozone_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) end def searchable_values { title => 'A', author.username => 'B', geozone.try(:name) => 'B', description => 'C' } end def self.search(terms) pg_search(terms) end def self.by_geozone(geozone) if geozone == 'all' where(geozone_id: nil) else where(geozone_id: geozone.presence) end end def feasibility case feasible when true "feasible" when false "not_feasible" else "undefined" end end def unfeasible_email_pending? unfeasible_email_sent_at.blank? && unfeasible? && valuation_finished? end def unfeasible? feasible == false end def valuation_finished? valuation_finished end def feasible_explanation_required? valuation_finished? && unfeasible? end def total_votes cached_votes_up + physical_votes end def code "#{created_at.strftime('%Y')}-#{id}" + (administrator.present? ? "-A#{administrator.id}" : "") end def send_unfeasible_email Mailer.unfeasible_spending_proposal(self).deliver_later update(unfeasible_email_sent_at: Time.current) end def reason_for_not_being_votable_by(user) return :not_voting_allowed if Setting["feature.spending_proposal_features.voting_allowed"].blank? return :not_logged_in unless user return :not_verified unless user.can?(:vote, SpendingProposal) return :unfeasible if unfeasible? return :organization if user.organization? end def votable_by?(user) reason_for_not_being_votable_by(user).blank? end def register_vote(user, vote_value) if votable_by?(user) vote_by(voter: user, vote: vote_value) end end def set_responsible_name self.responsible_name = author.try(:document_number) if author.try(:document_number).present? end def self.finished_and_feasible valuation_finished.feasible end def self.finished_and_unfeasible valuation_finished.unfeasible end end