Merge pull request #971 from consul/valuation

Valuation interface
This commit is contained in:
Raimond Garcia
2016-03-08 14:16:08 +01:00
33 changed files with 1031 additions and 32 deletions

View File

@@ -168,7 +168,7 @@ body.admin {
clear: both;
.checkbox {
font-size: rem-calc(12);
font-size: $small-font-size;
}
}

View File

@@ -641,6 +641,10 @@ form {
line-height: $line-height;
}
fieldset legend {
font-weight: bold;
}
input, textarea {
height: 48px\9;
line-height: 48px\9;
@@ -648,13 +652,28 @@ form {
width: 100%\9;
}
input[type="checkbox"] {
input[type="checkbox"],
input[type="radio"] {
height: auto\9;
line-height: inherit\9;
width: auto\9;
}
input[type]:not([type=submit]):not([type=file]):not([type=checkbox]) {
input[type="radio"] {
height: $line-height !important;
vertical-align: top;
width: 18px\9;
+ label {
font-weight: normal;
}
&:checked + label {
font-weight: bold;
}
}
input[type]:not([type=submit]):not([type=file]):not([type=checkbox]):not([type=radio]) {
background: $input-bg;
height: $line-height*2;
margin-bottom: rem-calc(16);

View File

@@ -0,0 +1,15 @@
class Valuation::BaseController < ApplicationController
layout 'admin'
before_action :authenticate_user!
before_action :verify_valuator
skip_authorization_check
private
def verify_valuator
raise CanCan::AccessDenied unless current_user.try(:valuator?) || current_user.try(:administrator?)
end
end

View File

@@ -0,0 +1,38 @@
class Valuation::SpendingProposalsController < Valuation::BaseController
include FeatureFlags
feature_flag :spending_proposals
before_action :restrict_access_to_assigned_items, only: [:show, :edit, :valuate]
has_filters %w{valuating valuation_finished}, only: :index
load_and_authorize_resource
def index
if current_user.valuator?
@spending_proposals = SpendingProposal.search(params_for_current_valuator, @current_filter).order(created_at: :desc).page(params[:page])
else
@spending_proposals = SpendingProposal.none.page(params[:page])
end
end
def valuate
@spending_proposal.update_attributes(valuation_params)
redirect_to valuation_spending_proposal_path(@spending_proposal), notice: t('valuation.spending_proposals.notice.valuate')
end
private
def valuation_params
params.require(:spending_proposal).permit(:price, :price_first_year, :price_explanation, :feasible, :feasible_explanation, :time_scope, :valuation_finished, :internal_comments)
end
def params_for_current_valuator
params.merge({valuator_id: current_user.valuator.id})
end
def restrict_access_to_assigned_items
raise ActionController::RoutingError.new('Not Found') unless current_user.administrator? || ValuationAssignment.exists?(spending_proposal_id: params[:id], valuator_id: current_user.valuator.id)
end
end

View File

@@ -11,4 +11,8 @@ module TextWithLinksHelper
Rinku.auto_link(html, :all, 'target="_blank" rel="nofollow"').html_safe
end
def simple_format_no_tags_no_sanitize(html)
simple_format(html, {}, sanitize: false)
end
end

View File

@@ -0,0 +1,30 @@
module ValuationHelper
def valuator_select_options(valuator=nil)
if valuator.present?
Valuator.where.not(id: valuator.id).order('users.username asc').includes(:user).collect { |v| [ v.name, v.id ] }.prepend([valuator.name, valuator.id])
else
Valuator.all.order('users.username asc').includes(:user).collect { |v| [ v.name, v.id ] }
end
end
def assigned_valuators_info(valuators)
case valuators.size
when 0
t("valuation.spending_proposals.index.no_valuators_assigned")
when 1
"<span title=\"#{t('valuation.spending_proposals.index.valuators_assigned', count: 1)}\">".html_safe +
valuators.first.name +
"</span>".html_safe
else
"<span title=\"".html_safe + valuators.map(&:name).join(', ') + "\">".html_safe +
t('valuation.spending_proposals.index.valuators_assigned', count: valuators.size) +
"</span>".html_safe
end
end
def explanation_field(field)
simple_format_no_tags_no_sanitize(safe_html_with_links(field.html_safe)) if field.present?
end
end

View File

@@ -4,6 +4,7 @@ module Abilities
def initialize(user)
self.merge Abilities::Moderation.new(user)
self.merge Abilities::Valuator.new(user)
can :restore, Comment
cannot :restore, Comment, hidden_at: nil

View File

@@ -34,6 +34,7 @@ class SpendingProposal < ActiveRecord::Base
results = self
results = results.by_geozone(params[:geozone_id]) if params[:geozone_id].present?
results = results.by_administrator(params[:administrator_id]) if params[:administrator_id].present?
results = results.by_valuator(params[:valuator_id]) if params[:valuator_id].present?
results = results.send(current_filter) if current_filter.present?
results.for_render
end
@@ -50,6 +51,10 @@ class SpendingProposal < ActiveRecord::Base
where(administrator_id: administrator.presence)
end
def self.by_valuator(valuator)
joins(:valuation_assignments).includes(:valuators).where("valuation_assignments.valuator_id = ?", valuator.presence)
end
def feasibility
case feasible
when true

View File

@@ -62,6 +62,10 @@
<p><strong><%= t("admin.spending_proposals.show.price") %> (<%= t("admin.spending_proposals.show.currency") %>):</strong>
<%= @spending_proposal.price.present? ? @spending_proposal.price : t("admin.spending_proposals.show.undefined") %>
</p>
<p><strong><%= t("admin.spending_proposals.show.price_first_year") %> (<%= t("admin.spending_proposals.show.currency") %>):</strong>
<%= @spending_proposal.price_first_year.present? ? @spending_proposal.price_first_year : t("admin.spending_proposals.show.undefined") %>
</p>
<%= simple_format(safe_html_with_links(@spending_proposal.price_explanation.html_safe), {}, sanitize: false) if @spending_proposal.price_explanation.present? %>
<p><strong><%= t("admin.spending_proposals.show.feasibility") %>:</strong>

View File

@@ -10,4 +10,10 @@
<%= link_to t("layouts.header.moderation"), moderation_root_path %>
</li>
<% end %>
<% if current_user.valuator? || current_user.administrator? %>
<li>
<%= link_to t("layouts.header.valuation"), valuation_root_path %>
</li>
<% end %>
<% end %>

View File

@@ -0,0 +1,17 @@
<nav class="admin-sidebar">
<ul id="valuation_menu">
<li>
<%= link_to t("valuation.menu.title"), valuation_root_path %>
</li>
<% if feature?(:spending_proposals) %>
<li <%= "class=active" if controller_name == "spending_proposals" %>>
<%= link_to valuation_spending_proposals_path do %>
<i class="icon-budget"></i>
<%= t("valuation.menu.spending_proposals") %>
<% end %>
</li>
<% end %>
</ul>
</nav>

View File

@@ -0,0 +1,132 @@
<%= link_to "#{t('valuation.spending_proposals.show.heading')} #{@spending_proposal.id}", valuation_spending_proposal_path(@spending_proposal), class: 'back' %>
<h2><%= t("valuation.spending_proposals.edit.dossier") %></h2>
<%= form_for(@spending_proposal, url: valuate_valuation_spending_proposal_path(@spending_proposal)) do |f| %>
<%= render 'shared/errors', resource: @spending_proposal %>
<div class="row">
<div class="small-12 medium-4 column">
<%= f.label :price, "#{t('valuation.spending_proposals.edit.price')} (#{t('valuation.spending_proposals.edit.currency')})" %>
<%= f.number_field :price, label: false %>
</div>
<div class="small-12 medium-4 column end">
<%= f.label :price_first_year, "#{t('valuation.spending_proposals.edit.price_first_year')} ( #{t('valuation.spending_proposals.edit.currency')})" %>
<%= f.number_field :price_first_year, label: false %>
</div>
</div>
<div class="row">
<div class="small-12 medium-8 column">
<%= f.label :price_explanation, t("valuation.spending_proposals.edit.price_explanation") %>
<%= f.text_area :price_explanation, label: false, rows: 3 %>
</div>
</div>
<div class="row">
<div class="small-12 medium-8 column">
<fieldset class="fieldset">
<legend><%= t('valuation.spending_proposals.edit.feasibility') %></legend>
<div class="small-6 column">
<span class="checkbox">
<%= f.radio_button :feasible, true, value: true, label: false %>
<%= f.label :feasible_true, t('valuation.spending_proposals.edit.feasible') %>
</span>
</div>
<div class="small-6 column">
<span class="checkbox">
<%= f.radio_button :feasible, false, value: false, label: false %>
<%= f.label :feasible_false, t('valuation.spending_proposals.edit.not_feasible') %>
</span>
</div>
</fieldset>
</div>
</div>
<div class="row">
<div class="small-12 medium-8 column">
<%= f.label :feasible_explanation, t("valuation.spending_proposals.edit.feasible_explanation") %>
<%= f.text_area :feasible_explanation, label: false, rows: 3 %>
</div>
</div>
<div class="row">
<div class="small-12 medium-8 column">
<%= f.label :time_scope, t("valuation.spending_proposals.edit.time_scope") %>
<%= f.text_field :time_scope, label: false %>
</div>
</div>
<div class="row">
<div class="small-12 medium-8 column">
<%= f.label :valuation_finished do %>
<%= f.check_box :valuation_finished, label: false %>
<span class="checkbox"><%= t("valuation.spending_proposals.edit.valuation_finished") %></span>
<% end %>
</div>
</div>
<div class="row">
<div class="small-12 medium-8 column">
<%= f.label :internal_comments, t("valuation.spending_proposals.edit.internal_comments") %>
<%= f.text_area :internal_comments, label: false, rows: 3 %>
</div>
</div>
<div class="row">
<div class="actions small-12 medium-4 column">
<%= f.submit(class: "button expanded large", value: t("valuation.spending_proposals.edit.save")) %>
</div>
</div>
<% end %>
<h1><%= @spending_proposal.title %></h1>
<%= safe_html_with_links @spending_proposal.description %>
<% if @spending_proposal.external_url.present? %>
<p><%= text_with_links @spending_proposal.external_url %></p>
<% end %>
<h2><%= t("valuation.spending_proposals.show.info") %></h2>
<p><strong><%= t("valuation.spending_proposals.show.by") %>:</strong>
<%= link_to @spending_proposal.author.name, user_path(@spending_proposal.author) %>
</p>
<% if @spending_proposal.association_name.present? %>
<p><strong><%= t("valuation.spending_proposals.show.association_name") %>:</strong>
<%= @spending_proposal.association_name %>
</p>
<% end %>
<p><strong><%= t("valuation.spending_proposals.show.geozone") %>:</strong>
<%= geozone_name(@spending_proposal) %>
</p>
<p><strong><%= t("valuation.spending_proposals.show.sent") %>:</strong>
<%= l @spending_proposal.created_at, format: :datetime %>
</p>
<h2><%= t("valuation.spending_proposals.show.responsibles") %></h2>
<p><strong><%= t("valuation.spending_proposals.show.assigned_admin") %>:</strong>
<% if @spending_proposal.administrator.present? %>
<%= @spending_proposal.administrator.name %> (<%= @spending_proposal.administrator.email %>)
<% else %>
<%= t("valuation.spending_proposals.show.undefined") %></li>
<% end %>
</p>
<p><strong><%= t("valuation.spending_proposals.show.assigned_valuators") %>:</strong></p>
<div id="assigned_valuators">
<ul>
<% @spending_proposal.valuators.each do |valuator| %>
<li><%= valuator.name %> (<%= valuator.email %>)</li>
<% end %>
<% if @spending_proposal.valuators.empty? %>
<li><%= t("valuation.spending_proposals.show.undefined") %></li>
<% end %>
</ul>
</div>

View File

@@ -0,0 +1,41 @@
<h2><%= t("valuation.spending_proposals.index.title") %></h2>
<div>
<%= form_tag valuation_spending_proposals_path, method: :get, enforce_utf8: false do %>
<div class="small-12 medium-4 column float-right">
<%= select_tag :geozone_id,
options_for_select(geozone_select_options.unshift([t("geozones.none"), "all"]), params[:geozone_id]),
{ prompt: t("valuation.spending_proposals.index.geozone_filter_all"),
label: false,
class: "js-submit-on-change" } %>
</div>
<% end %>
</div>
<%= render 'shared/filter_subnav', i18n_namespace: "valuation.spending_proposals.index" %>
<h3><%= page_entries_info @spending_proposals %></h3>
<table>
<% @spending_proposals.each do |spending_proposal| %>
<tr id="<%= dom_id(spending_proposal) %>">
<td>
<strong><%= spending_proposal.id %></strong>
</td>
<td>
<%= link_to spending_proposal.title, valuation_spending_proposal_path(spending_proposal) %>
</td>
<td class="small">
<%= link_to t("valuation.spending_proposals.index.edit"), edit_valuation_spending_proposal_path(spending_proposal) %>
</td>
<td class="small">
<%= assigned_valuators_info(spending_proposal.valuators) %>
</td>
<td class="small">
<%= geozone_name(spending_proposal) %>
</td>
</tr>
<% end %>
</table>
<%= paginate @spending_proposals %>

View File

@@ -0,0 +1,92 @@
<%= link_to t("valuation.spending_proposals.show.back"), :back, class: 'back' %>
<h2><%= t("valuation.spending_proposals.show.heading") %> <%= @spending_proposal.id %> </h2>
<h1><%= @spending_proposal.title %></h1>
<%= safe_html_with_links @spending_proposal.description %>
<% if @spending_proposal.external_url.present? %>
<p><%= text_with_links @spending_proposal.external_url %></p>
<% end %>
<h2><%= t("valuation.spending_proposals.show.info") %></h2>
<p><strong><%= t("valuation.spending_proposals.show.by") %>:</strong>
<%= link_to @spending_proposal.author.name, user_path(@spending_proposal.author) %>
</p>
<% if @spending_proposal.association_name.present? %>
<p><strong><%= t("valuation.spending_proposals.show.association_name") %>:</strong>
<%= @spending_proposal.association_name %>
</p>
<% end %>
<p><strong><%= t("valuation.spending_proposals.show.geozone") %>:</strong>
<%= geozone_name(@spending_proposal) %>
</p>
<p><strong><%= t("valuation.spending_proposals.show.sent") %>:</strong>
<%= l @spending_proposal.created_at, format: :datetime %>
</p>
<h2><%= t("valuation.spending_proposals.show.responsibles") %></h2>
<p><strong><%= t("valuation.spending_proposals.show.assigned_admin") %>:</strong>
<% if @spending_proposal.administrator.present? %>
<%= @spending_proposal.administrator.name %> (<%= @spending_proposal.administrator.email %>)
<% else %>
<%= t("valuation.spending_proposals.show.undefined") %></li>
<% end %>
</p>
<p><strong><%= t("valuation.spending_proposals.show.assigned_valuators") %>:</strong></p>
<div id="assigned_valuators">
<ul>
<% @spending_proposal.valuators.each do |valuator| %>
<li><%= valuator.name %> (<%= valuator.email %>)</li>
<% end %>
<% if @spending_proposal.valuators.empty? %>
<li><%= t("valuation.spending_proposals.show.undefined") %></li>
<% end %>
</ul>
</div>
<h2><%= t("valuation.spending_proposals.show.dossier") %></h2>
<p>
<%= link_to t("valuation.spending_proposals.show.edit_dossier"), edit_valuation_spending_proposal_path(@spending_proposal) %>
</p>
<p id="price">
<strong><%= t("valuation.spending_proposals.show.price") %> (<%= t("valuation.spending_proposals.show.currency") %>):</strong>
<%= @spending_proposal.price.presence or t("valuation.spending_proposals.show.undefined") %>
</p>
<p id="price_first_year">
<strong><%= t("valuation.spending_proposals.show.price_first_year") %> (<%= t("valuation.spending_proposals.show.currency") %>):</strong>
<%= @spending_proposal.price_first_year.presence or t("valuation.spending_proposals.show.undefined") %>
</p>
<%= explanation_field @spending_proposal.price_explanation %>
<p id="time_scope">
<strong><%= t("valuation.spending_proposals.show.time_scope") %>:</strong>
<%= @spending_proposal.time_scope.presence or t("valuation.spending_proposals.show.undefined") %>
</p>
<p id="feasibility">
<strong><%= t("valuation.spending_proposals.show.feasibility") %>:</strong>
<%= t("valuation.spending_proposals.show.#{@spending_proposal.feasibility}") %>
</p>
<%= explanation_field @spending_proposal.feasible_explanation %>
<% if @spending_proposal.valuation_finished %>
<p>
<strong><%= t("valuation.spending_proposals.show.valuation_finished") %></strong>
</p>
<% end %>
<% if @spending_proposal.internal_comments.present? %>
<h2><%= t("valuation.spending_proposals.show.internal_comments") %></h2>
<%= simple_format_no_tags_no_sanitize(safe_html_with_links(@spending_proposal.internal_comments.html_safe)) %>
<% end %>