diff --git a/app/controllers/admin/budget_investments_controller.rb b/app/controllers/admin/budget_investments_controller.rb
index 10342081c..17cc76923 100644
--- a/app/controllers/admin/budget_investments_controller.rb
+++ b/app/controllers/admin/budget_investments_controller.rb
@@ -1,6 +1,7 @@
class Admin::BudgetInvestmentsController < Admin::BaseController
- before_action :load_budget, only: [:index, :show]
+ before_action :load_budget
+ before_action :load_investment, only: [:show, :edit, :update]
has_filters %w{valuation_open without_admin managed valuating valuation_finished all}, only: :index
@@ -9,13 +10,49 @@ class Admin::BudgetInvestmentsController < Admin::BaseController
end
def show
- @investment = Budget::Investment.where(budget_id: @budget.id).find params[:id]
+ end
+
+ def edit
+ load_admins
+ load_valuators
+ load_tags
+ end
+
+ def update
+ if @investment.update(budget_investment_params)
+ redirect_to admin_budget_budget_investment_path(@budget, @investment, Budget::Investment.filter_params(params)),
+ notice: t("flash.actions.update.budget_investment")
+ else
+ load_admins
+ load_valuators
+ load_tags
+ render :edit
+ end
end
private
+ def budget_investment_params
+ params.require(:budget_investment).permit(:title, :description, :external_url, :heading_id, :administrator_id, :tag_list, valuator_ids: [])
+ end
+
def load_budget
@budget = Budget.includes(:groups).find params[:budget_id]
end
+ def load_investment
+ @investment = Budget::Investment.where(budget_id: @budget.id).find params[:id]
+ end
+
+ def load_admins
+ @admins = Administrator.includes(:user).all
+ end
+
+ def load_valuators
+ @valuators = Valuator.includes(:user).all.order("description ASC").order("users.email ASC")
+ end
+
+ def load_tags
+ @tags = ActsAsTaggableOn::Tag.budget_investment_tags
+ end
end
\ No newline at end of file
diff --git a/app/helpers/budget_headings_helper.rb b/app/helpers/budget_headings_helper.rb
index cb042f796..b9944be9b 100644
--- a/app/helpers/budget_headings_helper.rb
+++ b/app/helpers/budget_headings_helper.rb
@@ -4,4 +4,8 @@ module BudgetHeadingsHelper
budget.headings.map {|heading| [heading.name, heading.id]}
end
+ def budget_scoped_heading_select_options(budget)
+ budget.headings.includes(:group).order("group_id ASC, budget_headings.name ASC").map {|heading| [heading.group.name + ': ' + heading.name, heading.id]}
+ end
+
end
\ No newline at end of file
diff --git a/app/views/admin/budget_investments/edit.html.erb b/app/views/admin/budget_investments/edit.html.erb
new file mode 100644
index 000000000..db57c423b
--- /dev/null
+++ b/app/views/admin/budget_investments/edit.html.erb
@@ -0,0 +1,69 @@
+<%= link_to admin_budget_budget_investment_path(@budget, @investment, Budget::Investment.filter_params(params)), class: 'back' do %>
+ <%= t("shared.back") %>
+<% end %>
+
+<%= form_for @investment,
+ url: admin_budget_budget_investment_path(@budget, @investment) do |f| %>
+
+ <% Budget::Investment.filter_params(params).each do |filter_name, filter_value| %>
+ <%= hidden_field_tag filter_name, filter_value %>
+ <% end %>
+
+
+
+ <%= f.text_field :title, maxlength: Budget::Investment.title_max_length %>
+
+
+
+ <%= f.cktext_area :description, maxlength: Budget::Investment.description_max_length, ckeditor: { language: I18n.locale } %>
+
+
+
+ <%= f.text_field :external_url %>
+
+
+
+ <%= f.select :heading_id, budget_scoped_heading_select_options(@budget), include_blank: t("admin.budget_investments.edit.select_heading") %>
+
+
+
+ <%= t("admin.budget_investments.edit.classification") %>
+
+
+
+
+ <%= f.select(:administrator_id,
+ @admins.collect{ |a| [a.name_and_email, a.id ] },
+ { include_blank: t("admin.budget_investments.edit.undefined") }) %>
+
+
+
+
+ <%= f.label :tag_list, t("admin.budget_investments.edit.tags") %>
+
+ <%= f.text_field :tag_list, value: @investment.tag_list.to_s,
+ label: false,
+ placeholder: t("admin.budget_investments.edit.tags_placeholder"),
+ class: 'js-tag-list' %>
+
+
+
+ <%= f.label :valuator_ids, t("admin.budget_investments.edit.assigned_valuators") %>
+
+ <%= f.collection_check_boxes :valuator_ids, @valuators, :id, :email do |b| %>
+ <%= b.label(title: valuator_label(b.object)) { b.check_box + truncate(b.object.description_or_email, length: 60) } %>
+ <% end %>
+
+
+
+
+ <%= f.submit(class: "button", value: t("admin.budget_investments.edit.submit_button")) %>
+
+<% end %>
+
+
+<%# render 'valuation/budget_investments/written_by_valuators' %>
\ No newline at end of file
diff --git a/app/views/admin/budget_investments/show.html.erb b/app/views/admin/budget_investments/show.html.erb
index 47e66bc37..e7423b82d 100644
--- a/app/views/admin/budget_investments/show.html.erb
+++ b/app/views/admin/budget_investments/show.html.erb
@@ -5,7 +5,7 @@
<%= render 'written_by_author' %>
<%= link_to t("admin.budget_investments.show.edit"),
- admin_budget_budget_investment_path(@budget, @investment,
+ edit_admin_budget_budget_investment_path(@budget, @investment,
Budget::Investment.filter_params(params)) %>
@@ -33,7 +33,7 @@
<%= link_to t("admin.budget_investments.show.edit_classification"),
- edit_admin_spending_proposal_path(@investment,
+ edit_admin_budget_budget_investment_path(@budget, @investment,
{anchor: 'classification'}.merge(Budget::Investment.filter_params(params))) %>
@@ -41,7 +41,7 @@
<%= t("admin.budget_investments.show.dossier") %>
-<%# render 'valuation/budget_investments/written_by_valuators' %>
+<%= render 'valuation/budget_investments/written_by_valuators' %>
<%= link_to t("admin.budget_investments.show.edit_dossier"), edit_valuation_spending_proposal_path(@investment) %>
diff --git a/app/views/valuation/budget_investments/_written_by_valuators.html.erb b/app/views/valuation/budget_investments/_written_by_valuators.html.erb
new file mode 100644
index 000000000..9dc5a8e8c
--- /dev/null
+++ b/app/views/valuation/budget_investments/_written_by_valuators.html.erb
@@ -0,0 +1,53 @@
+
+
+ <%= t("valuation.budget_investments.show.price") %>
+ (<%= t("valuation.budget_investments.show.currency") %>):
+
+ <% if @investment.price.present? %>
+ <%= @investment.price %>
+ <% else %>
+ <%= t("valuation.budget_investments.show.undefined") %>
+ <% end %>
+
+
+
+
+ <%= t("valuation.budget_investments.show.price_first_year") %>
+ (<%= t("valuation.budget_investments.show.currency") %>):
+
+
+ <% if @investment.price_first_year.present? %>
+ <%= @investment.price_first_year %>
+ <% else %>
+ <%= t("valuation.budget_investments.show.undefined") %>
+ <% end %>
+
+
+<%= explanation_field @investment.price_explanation %>
+
+
+ <%= t("valuation.budget_investments.show.duration") %>:
+ <% if @investment.duration.present? %>
+ <%= @investment.duration %>
+ <% else %>
+ <%= t("valuation.budget_investments.show.undefined") %>
+ <% end %>
+
+
+
+ <%= t("valuation.budget_investments.show.feasibility") %>:
+ <%= t("valuation.budget_investments.show.#{@investment.feasibility}") %>
+
+
+<%= explanation_field @investment.unfeasibility_explanation %>
+
+<% if @investment.valuation_finished %>
+
+ <%= t("valuation.budget_investments.show.valuation_finished") %>
+
+<% end %>
+
+<% if @investment.internal_comments.present? %>
+ <%= t("valuation.budget_investments.show.internal_comments") %>
+ <%= explanation_field @investment.internal_comments %>
+<% end %>
diff --git a/config/initializers/acts_as_taggable_on.rb b/config/initializers/acts_as_taggable_on.rb
index 7b534897a..5cf75b8bb 100644
--- a/config/initializers/acts_as_taggable_on.rb
+++ b/config/initializers/acts_as_taggable_on.rb
@@ -42,6 +42,10 @@ module ActsAsTaggableOn
ActsAsTaggableOn::Tag.where('taggings.taggable_type' => 'SpendingProposal').includes(:taggings).order(:name).uniq
end
+ def self.budget_investment_tags
+ ActsAsTaggableOn::Tag.where('taggings.taggable_type' => 'Budget::Investment').includes(:taggings).order(:name).uniq
+ end
+
private
def custom_counter_field_name_for(taggable_type)
"#{taggable_type.underscore.pluralize}_count"
diff --git a/config/locales/activerecord.en.yml b/config/locales/activerecord.en.yml
index 5a7a591bd..8eb300289 100644
--- a/config/locales/activerecord.en.yml
+++ b/config/locales/activerecord.en.yml
@@ -7,6 +7,9 @@ en:
budget:
one: "Participatory budget"
other: "Participatory budgets"
+ budget/investment:
+ one: "Investment"
+ other: "Investments"
comment:
one: "Comment"
other: "Comments"
@@ -38,6 +41,12 @@ en:
one: "Spending proposal"
other: "Spending proposals"
attributes:
+ budget/investment:
+ administrator_id: "Administrator"
+ description: "Description"
+ external_url: "Link to additional documentation"
+ heading_id: "Heading"
+ title: "Title"
comment:
body: "Comment"
user: "User"
diff --git a/config/locales/activerecord.es.yml b/config/locales/activerecord.es.yml
index c7c811801..50ef09cf4 100644
--- a/config/locales/activerecord.es.yml
+++ b/config/locales/activerecord.es.yml
@@ -41,6 +41,12 @@ es:
one: "Propuesta de inversión"
other: "Propuestas de inversión"
attributes:
+ budget/investment:
+ administrator_id: "Administrador"
+ description: "Descripción"
+ external_url: "Enlace a documentación adicional"
+ heading_id: "Partida presupuestaria"
+ title: "Título"
comment:
body: "Comentario"
user: "Usuario"
diff --git a/config/locales/admin.en.yml b/config/locales/admin.en.yml
index 9b5e7c19c..c9bd21c18 100755
--- a/config/locales/admin.en.yml
+++ b/config/locales/admin.en.yml
@@ -129,6 +129,14 @@ en:
edit_dossier: Edit dossier
tags: Tags
undefined: Undefined
+ edit:
+ classification: Clasification
+ assigned_valuators: Valuators
+ select_heading: Select heading
+ submit_button: Update
+ tags: Tags
+ tags_placeholder: "Write the tags you want separated by commas (,)"
+ undefined: Undefined
comments:
index:
filter: Filter
diff --git a/config/locales/admin.es.yml b/config/locales/admin.es.yml
index 4f4536950..07b0c9991 100644
--- a/config/locales/admin.es.yml
+++ b/config/locales/admin.es.yml
@@ -129,6 +129,14 @@ es:
edit_dossier: Editar informe
tags: Etiquetas
undefined: Sin definir
+ edit:
+ classification: Clasificación
+ assigned_valuators: Evaluadores
+ select_heading: Seleccionar partida
+ submit_button: Actualizar
+ tags: Etiquetas
+ tags_placeholder: "Escribe las etiquetas que desees separadas por comas (,)"
+ undefined: Sin definir
comments:
index:
filter: Filtro
diff --git a/config/locales/responders.en.yml b/config/locales/responders.en.yml
index 825a9957b..9e8c8c4a7 100755
--- a/config/locales/responders.en.yml
+++ b/config/locales/responders.en.yml
@@ -17,7 +17,7 @@ en:
debate: "Debate updated successfully."
proposal: "Proposal updated successfully."
spending_proposal: "Investment project updated succesfully."
- budget_investment: "Budget Investment updated succesfully."
+ budget_investment: "Investment project updated succesfully."
destroy:
spending_proposal: "Spending proposal deleted succesfully."
- budget_investment: "Budget Investment deleted succesfully."
+ budget_investment: "Investment project deleted succesfully."
diff --git a/config/locales/valuation.en.yml b/config/locales/valuation.en.yml
index e136562f4..c3b6d8283 100644
--- a/config/locales/valuation.en.yml
+++ b/config/locales/valuation.en.yml
@@ -4,6 +4,29 @@ en:
menu:
title: Valuation
spending_proposals: Spending proposals
+ budget_investments:
+ show:
+ back: Back
+ heading: Investment project
+ info: Author info
+ by: Sent by
+ sent: Sent at
+ heading: Heading
+ dossier: Dossier
+ edit_dossier: Edit dossier
+ price: Price
+ price_first_year: Cost during the first year
+ currency: "€"
+ feasibility: Feasibility
+ feasible: Feasible
+ unfeasible: Unfeasible
+ undefined: Undefined
+ valuation_finished: Valuation finished
+ duration: Time scope
+ internal_comments: Internal comments
+ responsibles: Responsibles
+ assigned_admin: Assigned admin
+ assigned_valuators: Assigned valuators
spending_proposals:
index:
geozone_filter_all: All zones
diff --git a/config/locales/valuation.es.yml b/config/locales/valuation.es.yml
index 7d4ff5ed6..34771587d 100644
--- a/config/locales/valuation.es.yml
+++ b/config/locales/valuation.es.yml
@@ -4,6 +4,29 @@ es:
menu:
title: Evaluación
spending_proposals: Propuestas de inversión
+ budget_investments:
+ show:
+ back: Volver
+ heading: Propuesta de inversión
+ info: Datos de envío
+ by: Enviada por
+ sent: Fecha de creación
+ heading: Partida
+ dossier: Informe
+ edit_dossier: Editar informe
+ price: Coste
+ price_first_year: Coste en el primer año
+ currency: "€"
+ feasibility: Viabilidad
+ feasible: Viable
+ unfeasible: Inviable
+ undefined: Sin definir
+ valuation_finished: Informe finalizado
+ duration: Plazo de ejecución
+ internal_comments: Comentarios internos
+ responsibles: Responsables
+ assigned_admin: Administrador asignado
+ assigned_valuators: Evaluadores asignados
spending_proposals:
index:
geozone_filter_all: Todos los ámbitos de actuación
diff --git a/config/routes.rb b/config/routes.rb
index 278153a19..b22806dbd 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -162,7 +162,7 @@ Rails.application.routes.draw do
end
end
- resources :budget_investments, only: [:index, :show]
+ resources :budget_investments, only: [:index, :show, :edit, :update]
end
resources :banners, only: [:index, :new, :create, :edit, :update, :destroy] do
diff --git a/spec/features/admin/budget_investments_spec.rb b/spec/features/admin/budget_investments_spec.rb
index ad08ee634..c34354ede 100644
--- a/spec/features/admin/budget_investments_spec.rb
+++ b/spec/features/admin/budget_investments_spec.rb
@@ -98,15 +98,16 @@ feature 'Admin budget investments' do
expect(page).to have_link("Change name")
expect(page).to_not have_link("Plant trees")
- # click_link("Realocate visitors")
- # click_link("Edit classification")
- # expect(page).to have_button("Update")
- # click_link("Go back")
- # expect(page).to_not have_button("Update")
- # click_link("Go back")
+ click_link("Change name")
+ click_link("Edit classification")
+ expect(page).to have_button("Update")
+ click_link("Go back")
+ expect(page).to_not have_button("Update")
+ click_link("Go back")
- # expect(page).to_not have_link("Destroy the city")
- # expect(page).to have_link("Realocate visitors")
+ expect(page).to_not have_link("Realocate visitors")
+ expect(page).to have_link("Change name")
+ expect(page).to_not have_link("Plant trees")
end
scenario "Filtering by admin", :js do
@@ -142,16 +143,16 @@ feature 'Admin budget investments' do
expect(page).to_not have_link("Destroy the city")
expect(page).to have_link("Realocate visitors")
- # click_link("Realocate visitors")
- # click_link("Edit classification")
- # expect(page).to have_button("Update")
- # click_link("Go back")
- # expect(page).to_not have_button("Update")
- # click_link("Go back")
+ click_link("Realocate visitors")
+ click_link("Edit classification")
+ expect(page).to have_button("Update")
+ click_link("Go back")
+ expect(page).to_not have_button("Update")
+ click_link("Go back")
- # expect(page).to have_content('There is 1 investment')
- # expect(page).to_not have_link("Destroy the city")
- # expect(page).to have_link("Realocate visitors")
+ expect(page).to have_content('There is 1 investment')
+ expect(page).to_not have_link("Destroy the city")
+ expect(page).to have_link("Realocate visitors")
end
scenario "Filtering by valuator", :js do
@@ -188,16 +189,16 @@ feature 'Admin budget investments' do
expect(page).to_not have_link("Destroy the city")
expect(page).to have_link("Realocate visitors")
- # click_link("Realocate visitors")
- # click_link("Edit classification")
- # expect(page).to have_button("Update")
- # click_link("Go back")
- # expect(page).to_not have_button("Update")
- # click_link("Go back")
+ click_link("Realocate visitors")
+ click_link("Edit classification")
+ expect(page).to have_button("Update")
+ click_link("Go back")
+ expect(page).to_not have_button("Update")
+ click_link("Go back")
- # expect(page).to have_content('There is 1 investment')
- # expect(page).to_not have_link("Destroy the city")
- # expect(page).to have_link("Realocate visitors")
+ expect(page).to have_content('There is 1 investment')
+ expect(page).to_not have_link("Destroy the city")
+ expect(page).to have_link("Realocate visitors")
end
scenario "Current filter is properly highlighted" do
@@ -297,16 +298,159 @@ feature 'Admin budget investments' do
expect(page).to have_content("Educate the children")
expect(page).to have_content("More schools")
- # click_link("Educate the children")
- # click_link("Edit classification")
- # expect(page).to have_button("Update")
- # click_link("Go back")
- # expect(page).to_not have_button("Update")
- # click_link("Go back")
+ click_link("Educate the children")
+ click_link("Edit classification")
+ expect(page).to have_button("Update")
+ click_link("Go back")
+ expect(page).to_not have_button("Update")
+ click_link("Go back")
- # expect(page).to_not have_content("More hospitals")
- # expect(page).to have_content("Educate the children")
- # expect(page).to have_content("More schools")
+ expect(page).to_not have_content("More hospitals")
+ expect(page).to have_content("Educate the children")
+ expect(page).to have_content("More schools")
+ end
+
+ end
+
+ scenario 'Show' do
+ administrator = create(:administrator, user: create(:user, username: 'Ana', email: 'ana@admins.org'))
+ valuator = create(:valuator, user: create(:user, username: 'Rachel', email: 'rachel@valuators.org'))
+ budget_investment = create(:budget_investment,
+ price: 1234,
+ price_first_year: 1000,
+ feasibility: "unfeasible",
+ unfeasibility_explanation: 'It is impossible',
+ administrator: administrator)
+ budget_investment.valuators << valuator
+
+ visit admin_budget_budget_investments_path(budget_investment.budget)
+
+ click_link budget_investment.title
+
+ expect(page).to have_content(budget_investment.title)
+ expect(page).to have_content(budget_investment.description)
+ expect(page).to have_content(budget_investment.author.name)
+ expect(page).to have_content(budget_investment.heading.name)
+ expect(page).to have_content('1234')
+ expect(page).to have_content('1000')
+ expect(page).to have_content('Unfeasible')
+ expect(page).to have_content('It is impossible')
+ expect(page).to have_content('Ana (ana@admins.org)')
+
+ within('#assigned_valuators') do
+ expect(page).to have_content('Rachel (rachel@valuators.org)')
+ end
+ end
+
+ context "Edit" do
+
+ scenario "Change title, description or heading" do
+ budget_investment = create(:budget_investment)
+ create(:budget_heading, group: budget_investment.group, name: "Barbate")
+
+ visit admin_budget_budget_investment_path(budget_investment.budget, budget_investment)
+ click_link 'Edit'
+
+ fill_in 'budget_investment_title', with: 'Potatoes'
+ fill_in 'budget_investment_description', with: 'Carrots'
+ select "#{budget_investment.group.name}: Barbate", from: 'budget_investment[heading_id]'
+
+ click_button 'Update'
+
+ expect(page).to have_content 'Potatoes'
+ expect(page).to have_content 'Carrots'
+ expect(page).to have_content 'Barbate'
+ end
+
+ scenario "Add administrator" do
+ budget_investment = create(:budget_investment)
+ administrator = create(:administrator, user: create(:user, username: 'Marta', email: 'marta@admins.org'))
+
+ visit admin_budget_budget_investment_path(budget_investment.budget, budget_investment)
+ click_link 'Edit classification'
+
+ select 'Marta (marta@admins.org)', from: 'budget_investment[administrator_id]'
+ click_button 'Update'
+
+ expect(page).to have_content 'Investment project updated succesfully.'
+ expect(page).to have_content 'Assigned administrator: Marta'
+ end
+
+ scenario "Add valuators" do
+ budget_investment = create(:budget_investment)
+
+ valuator1 = create(:valuator, user: create(:user, username: 'Valentina', email: 'v1@valuators.org'))
+ valuator2 = create(:valuator, user: create(:user, username: 'Valerian', email: 'v2@valuators.org'))
+ valuator3 = create(:valuator, user: create(:user, username: 'Val', email: 'v3@valuators.org'))
+
+ visit admin_budget_budget_investment_path(budget_investment.budget, budget_investment)
+ click_link 'Edit classification'
+
+ check "budget_investment_valuator_ids_#{valuator1.id}"
+ check "budget_investment_valuator_ids_#{valuator3.id}"
+
+ click_button 'Update'
+
+ expect(page).to have_content 'Investment project updated succesfully.'
+
+ within('#assigned_valuators') do
+ expect(page).to have_content('Valentina (v1@valuators.org)')
+ expect(page).to have_content('Val (v3@valuators.org)')
+ expect(page).to_not have_content('Undefined')
+ expect(page).to_not have_content('Valerian (v2@valuators.org)')
+ end
+ end
+
+ scenario "Adds existing tags", :js do
+ create(:budget_investment, tag_list: 'Education, Health')
+
+ budget_investment = create(:budget_investment)
+
+ visit admin_budget_budget_investment_path(budget_investment.budget, budget_investment)
+ click_link 'Edit classification'
+
+ find('.js-add-tag-link', text: 'Education').click
+
+ fill_in 'budget_investment_title', with: 'Updated title'
+
+ click_button 'Update'
+
+ expect(page).to have_content 'Investment project updated succesfully.'
+
+ within "#tags" do
+ expect(page).to have_content 'Education'
+ expect(page).to_not have_content 'Health'
+ end
+ end
+
+ scenario "Adds non existent tags" do
+ budget_investment = create(:budget_investment)
+
+ visit admin_budget_budget_investment_path(budget_investment.budget, budget_investment)
+ click_link 'Edit classification'
+
+ fill_in 'budget_investment_tag_list', with: 'Refugees, Solidarity'
+ click_button 'Update'
+
+ expect(page).to have_content 'Investment project updated succesfully.'
+
+ within "#tags" do
+ expect(page).to have_content 'Refugees'
+ expect(page).to have_content 'Solidarity'
+ end
+ end
+
+ scenario "Errors on update" do
+ budget_investment = create(:budget_investment)
+
+ visit admin_budget_budget_investment_path(budget_investment.budget, budget_investment)
+ click_link 'Edit'
+
+ fill_in 'budget_investment_title', with: ''
+
+ click_button 'Update'
+
+ expect(page).to have_content "can't be blank"
end
end