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") %> +
+ <% @tags.each do |tag| %> + <%= tag.name %> + <% end %> +
+ <%= 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