diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 7fb92b5e3..b9a3ec9dc 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -42,6 +42,7 @@ //= require suggest //= require forms //= require tracks +//= require valuation_budget_investment_form //= require valuation_spending_proposal_form //= require embed_video //= require banners @@ -63,6 +64,7 @@ var initialize_modules = function() { App.Suggest.initialize(); App.Forms.initialize(); App.Tracks.initialize(); + App.ValuationBudgetInvestmentForm.initialize(); App.ValuationSpendingProposalForm.initialize(); App.EmbedVideo.initialize(); App.Banners.initialize(); diff --git a/app/assets/javascripts/valuation_budget_investment_form.js.coffee b/app/assets/javascripts/valuation_budget_investment_form.js.coffee new file mode 100644 index 000000000..d79ff600e --- /dev/null +++ b/app/assets/javascripts/valuation_budget_investment_form.js.coffee @@ -0,0 +1,32 @@ +App.ValuationBudgetInvestmentForm = + + showFeasibleFields: -> + $('#valuation_budget_investment_edit_form #unfeasible_fields').hide('down') + $('#valuation_budget_investment_edit_form #feasible_fields').show() + + showNotFeasibleFields: -> + $('#valuation_budget_investment_edit_form #feasible_fields').hide('down') + $('#valuation_budget_investment_edit_form #unfeasible_fields').show() + + showAllFields: -> + $('#valuation_budget_investment_edit_form #feasible_fields').show('down') + $('#valuation_budget_investment_edit_form #unfeasible_fields').show('down') + + showFeasibilityFields: -> + feasibility = $("#valuation_budget_investment_edit_form input[type=radio][name='budget_investment[feasibility]']:checked").val() + if feasibility == 'feasible' + App.ValuationBudgetInvestmentForm.showFeasibleFields() + else if feasibility == 'unfeasible' + App.ValuationBudgetInvestmentForm.showNotFeasibleFields() + + + showFeasibilityFieldsOnChange: -> + $("#valuation_budget_investment_edit_form input[type=radio][name='budget_investment[feasibility]']").change -> + App.ValuationBudgetInvestmentForm.showAllFields() + App.ValuationBudgetInvestmentForm.showFeasibilityFields() + + + initialize: -> + App.ValuationBudgetInvestmentForm.showFeasibilityFields() + App.ValuationBudgetInvestmentForm.showFeasibilityFieldsOnChange() + false \ No newline at end of file diff --git a/app/controllers/valuation/budget_investments_controller.rb b/app/controllers/valuation/budget_investments_controller.rb index 348f275da..69269f6bd 100644 --- a/app/controllers/valuation/budget_investments_controller.rb +++ b/app/controllers/valuation/budget_investments_controller.rb @@ -4,6 +4,7 @@ class Valuation::BudgetInvestmentsController < Valuation::BaseController before_action :restrict_access_to_assigned_items, only: [:show, :edit, :valuate] before_action :load_budget + before_action :load_investment, only: [:show, :edit, :valuate] has_filters %w{valuating valuation_finished}, only: :index @@ -20,12 +21,7 @@ class Valuation::BudgetInvestmentsController < Valuation::BaseController def valuate if valid_price_params? && @investment.update(valuation_params) - - if @investment.unfeasible_email_pending? - @investment.send_unfeasible_email - end - - redirect_to valuation_budget_investment_path(@investment), notice: t('valuation.budget_investments.notice.valuate') + redirect_to valuation_budget_budget_investment_path(@budget, @investment), notice: t('valuation.budget_investments.notice.valuate') else render action: :edit end @@ -37,6 +33,10 @@ class Valuation::BudgetInvestmentsController < Valuation::BaseController @budget = Budget.find(params[:budget_id]) end + def load_investment + @investment = @budget.investments.find params[:id] + end + def heading_filters investments = @budget.investments.by_valuator(current_user.valuator.try(:id)).valuation_open.select(:heading_id).all.to_a @@ -57,13 +57,11 @@ class Valuation::BudgetInvestmentsController < Valuation::BaseController end def valuation_params - params[:budget_investment][:feasible] = nil if params[:budget_investment][:feasible] == 'nil' - - params.require(:budget_investment).permit(:price, :price_first_year, :price_explanation, :feasible, :feasible_explanation, :duration, :valuation_finished, :internal_comments) + params.require(:budget_investment).permit(:price, :price_first_year, :price_explanation, :feasibility, :unfeasibility_explanation, :duration, :valuation_finished, :internal_comments) end def restrict_access_to_assigned_items - raise ActionController::RoutingError.new('Not Found') unless current_user.administrator? || ValuatorAssignment.exists?(investment_id: params[:id], valuator_id: current_user.valuator.id) + raise ActionController::RoutingError.new('Not Found') unless current_user.administrator? || Budget::ValuatorAssignment.exists?(investment_id: params[:id], valuator_id: current_user.valuator.id) end def valid_price_params? diff --git a/app/views/admin/budget_investments/show.html.erb b/app/views/admin/budget_investments/show.html.erb index e7423b82d..3ebfd4940 100644 --- a/app/views/admin/budget_investments/show.html.erb +++ b/app/views/admin/budget_investments/show.html.erb @@ -44,6 +44,6 @@ <%= render 'valuation/budget_investments/written_by_valuators' %>

- <%= link_to t("admin.budget_investments.show.edit_dossier"), edit_valuation_spending_proposal_path(@investment) %> + <%= link_to t("admin.budget_investments.show.edit_dossier"), edit_valuation_budget_budget_investment_path(@budget, @investment) %>

diff --git a/app/views/valuation/budget_investments/edit.html.erb b/app/views/valuation/budget_investments/edit.html.erb new file mode 100644 index 000000000..e03d850a4 --- /dev/null +++ b/app/views/valuation/budget_investments/edit.html.erb @@ -0,0 +1,141 @@ +<%= link_to "#{t('valuation.budget_investments.show.title')} #{@investment.id}", valuation_budget_budget_investment_path(@budget, @investment), class: 'back' %> +

<%= t("valuation.budget_investments.edit.dossier") %>

+ +<%= form_for(@investment, url: valuate_valuation_budget_budget_investment_path(@budget, @investment), html: {id: "valuation_budget_investment_edit_form"}) do |f| %> + <%= render 'shared/errors', resource: @investment %> +
+
+
+ <%= t('valuation.budget_investments.edit.feasibility') %> +
+ + <%= f.radio_button :feasibility, 'undecided', label: false %> + <%= f.label :feasibility_undecided, t('valuation.budget_investments.edit.undefined_feasible') %> + +
+ +
+ + <%= f.radio_button :feasibility, 'feasible', label: false %> + <%= f.label :feasibility_feasible, t('valuation.budget_investments.edit.feasible') %> + +
+ +
+ + <%= f.radio_button :feasibility, 'unfeasible', label: false %> + <%= f.label :feasibility_unfeasible, t('valuation.budget_investments.edit.unfeasible') %> + +
+
+
+
+ +
+ +
+
+ <%= f.label :unfeasibility_explanation, t("valuation.budget_investments.edit.feasible_explanation_html") %> + <%= f.text_area :unfeasibility_explanation, label: false, rows: 3 %> +
+
+ +
+ +
+ +
+
+ <%= f.label :price, "#{t('valuation.budget_investments.edit.price_html', currency: @budget.currency_symbol)}" %> + <%= f.number_field :price, label: false, max: 1000000000000000 %> +
+ +
+ <%= f.label :price_first_year, "#{t('valuation.budget_investments.edit.price_first_year_html', currency: @budget.currency_symbol)}" %> + <%= f.number_field :price_first_year, label: false, max: 1000000000000000 %> +
+
+ +
+
+ <%= f.label :price_explanation, t("valuation.budget_investments.edit.price_explanation_html") %> + <%= f.text_area :price_explanation, label: false, rows: 3 %> +
+
+ +
+
+ <%= f.label :duration, t("valuation.budget_investments.edit.duration_html") %> + <%= f.text_field :duration, label: false %> +
+
+ +
+ +
+
+ <%= f.label :valuation_finished do %> + <%= f.check_box :valuation_finished, title: t('valuation.budget_investments.edit.valuation_finished'), label: false %> + <%= t("valuation.budget_investments.edit.valuation_finished") %> + <% end %> +
+
+ +
+
+ <%= f.label :internal_comments, t("valuation.budget_investments.edit.internal_comments_html") %> + <%= f.text_area :internal_comments, label: false, rows: 3 %> +
+
+ +
+
+ <%= f.submit(class: "button expanded large", value: t("valuation.budget_investments.edit.save")) %> +
+
+<% end %> + +

<%= @investment.title %>

+ +<%= safe_html_with_links @investment.description %> + +<% if @investment.external_url.present? %> +

<%= text_with_links @investment.external_url %>

+<% end %> + +

<%= t("valuation.budget_investments.show.info") %>

+ +

<%= t("valuation.budget_investments.show.by") %>: + <%= link_to @investment.author.name, user_path(@investment.author) %> +

+ +

<%= t("valuation.budget_investments.show.heading") %>: + <%= @investment.heading.name %> +

+ +

<%= t("valuation.budget_investments.show.sent") %>: + <%= l @investment.created_at, format: :datetime %> +

+ +

<%= t("valuation.budget_investments.show.responsibles") %>

+ +

<%= t("valuation.budget_investments.show.assigned_admin") %>: + <% if @investment.administrator.present? %> + <%= @investment.administrator.name %> (<%= @investment.administrator.email %>) + <% else %> + <%= t("valuation.budget_investments.show.undefined") %> + <% end %> +

+ +

<%= t("valuation.budget_investments.show.assigned_valuators") %>:

+
+ +
\ No newline at end of file diff --git a/app/views/valuation/budget_investments/show.html.erb b/app/views/valuation/budget_investments/show.html.erb new file mode 100644 index 000000000..602c53dda --- /dev/null +++ b/app/views/valuation/budget_investments/show.html.erb @@ -0,0 +1,55 @@ +<%= render "shared/back_link" %> + +

<%= t("valuation.budget_investments.show.title") %> <%= @investment.id %>

+

<%= @investment.title %>

+ +<%= safe_html_with_links @investment.description %> + +<% if @investment.external_url.present? %> +

<%= text_with_links @investment.external_url %>

+<% end %> + +

<%= t("valuation.budget_investments.show.info") %>

+ +

<%= t("valuation.budget_investments.show.by") %>: + <%= link_to @investment.author.name, user_path(@investment.author) %> +

+ +

<%= t("valuation.budget_investments.show.heading") %>: + <%= @investment.heading.name %> +

+ +

<%= t("valuation.budget_investments.show.sent") %>: + <%= l @investment.created_at, format: :datetime %> +

+ +

<%= t("valuation.budget_investments.show.responsibles") %>

+ +

<%= t("valuation.budget_investments.show.assigned_admin") %>: + <% if @investment.administrator.present? %> + <%= @investment.administrator.name_and_email %> + <% else %> + <%= t("valuation.budget_investments.show.undefined") %> + <% end %> +

+ +

<%= t("valuation.budget_investments.show.assigned_valuators") %>:

+
+ +
+ +

<%= t("valuation.budget_investments.show.dossier") %>

+ +

+ <%= link_to t("valuation.budget_investments.show.edit_dossier"), edit_valuation_budget_budget_investment_path(@budget, @investment) %> +

+ +<%= render 'written_by_valuators' %> \ No newline at end of file diff --git a/config/locales/valuation.en.yml b/config/locales/valuation.en.yml index b1cf1ff81..a5195deca 100644 --- a/config/locales/valuation.en.yml +++ b/config/locales/valuation.en.yml @@ -26,7 +26,7 @@ en: no_valuators_assigned: No valuators assigned show: back: Back - heading: Investment project + title: Investment project info: Author info by: Sent by sent: Sent at @@ -46,6 +46,20 @@ en: responsibles: Responsibles assigned_admin: Assigned admin assigned_valuators: Assigned valuators + edit: + dossier: Dossier + price_html: "Price (%{currency})" + price_first_year_html: "Cost during the first year (%{currency})" + price_explanation_html: Price explanation + feasibility: Feasibility + feasible: Feasible + unfeasible: Not feasible + undefined_feasible: Pending + feasible_explanation_html: Feasibility explanation + valuation_finished: Valuation finished + duration_html: Time scope + internal_comments_html: Internal comments + save: Save changes notice: valuate: "Dossier updated" spending_proposals: diff --git a/config/locales/valuation.es.yml b/config/locales/valuation.es.yml index 163ee658d..67302437b 100644 --- a/config/locales/valuation.es.yml +++ b/config/locales/valuation.es.yml @@ -26,7 +26,7 @@ es: no_valuators_assigned: Sin evaluador show: back: Volver - heading: Propuesta de inversión + title: Propuesta de inversión info: Datos de envío by: Enviada por sent: Fecha de creación @@ -46,6 +46,20 @@ es: responsibles: Responsables assigned_admin: Administrador asignado assigned_valuators: Evaluadores asignados + edit: + dossier: Informe + price_html: "Coste (%{currency}) (dato público)" + price_first_year_html: "Coste en el primer año (%{currency}) (opcional, privado)" + price_explanation_html: "Informe de coste (opcional, dato público)" + feasibility: Viabilidad + feasible: Viable + unfeasible: Inviable + undefined_feasible: Sin decidir + feasible_explanation_html: "Informe de inviabilidad (en caso de que lo sea, dato público)" + valuation_finished: Informe finalizado + duration_html: "Plazo de ejecución (opcional, dato no público)" + internal_comments_html: "Comentarios y observaciones (para responsables internos, dato no público)" + save: Guardar cambios notice: valuate: "Dossier actualizado" spending_proposals: diff --git a/spec/features/valuation/budget_investments_spec.rb b/spec/features/valuation/budget_investments_spec.rb index 53f60e416..56a20f2c6 100644 --- a/spec/features/valuation/budget_investments_spec.rb +++ b/spec/features/valuation/budget_investments_spec.rb @@ -158,4 +158,238 @@ feature 'Valuation budget investments' do expect(page).to have_content("Old idea") end + feature 'Show' do + scenario 'visible for assigned valuators' do + administrator = create(:administrator, user: create(:user, username: 'Ana', email: 'ana@admins.org')) + valuator2 = create(:valuator, user: create(:user, username: 'Rick', email: 'rick@valuators.org')) + investment = create(:budget_investment, + budget: @budget, + price: 1234, + feasibility: 'unfeasible', + unfeasibility_explanation: 'It is impossible', + administrator: administrator) + investment.valuators << [@valuator, valuator2] + + visit valuation_budget_budget_investments_path(@budget) + + click_link investment.title + + expect(page).to have_content(investment.title) + expect(page).to have_content(investment.description) + expect(page).to have_content(investment.author.name) + expect(page).to have_content(investment.heading.name) + expect(page).to have_content('1234') + 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)') + expect(page).to have_content('Rick (rick@valuators.org)') + end + end + + scenario 'visible for admins' do + logout + login_as create(:administrator).user + + administrator = create(:administrator, user: create(:user, username: 'Ana', email: 'ana@admins.org')) + valuator2 = create(:valuator, user: create(:user, username: 'Rick', email: 'rick@valuators.org')) + investment = create(:budget_investment, + budget: @budget, + price: 1234, + feasibility: 'unfeasible', + unfeasibility_explanation: 'It is impossible', + administrator: administrator) + investment.valuators << [@valuator, valuator2] + + visit valuation_budget_budget_investment_path(@budget, investment) + + expect(page).to have_content(investment.title) + expect(page).to have_content(investment.description) + expect(page).to have_content(investment.author.name) + expect(page).to have_content(investment.heading.name) + expect(page).to have_content('1234') + 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)') + expect(page).to have_content('Rick (rick@valuators.org)') + end + end + + scenario 'not visible for not assigned valuators' do + logout + login_as create(:valuator).user + + valuator2 = create(:valuator, user: create(:user, username: 'Rick', email: 'rick@valuators.org')) + investment = create(:budget_investment, + budget: @budget, + price: 1234, + feasibility: 'unfeasible', + unfeasibility_explanation: 'It is impossible', + administrator: create(:administrator)) + investment.valuators << [@valuator, valuator2] + + expect { visit valuation_budget_budget_investment_path(@budget, investment) }.to raise_error "Not Found" + end + + end + + feature 'Valuate' do + background do + @investment = create(:budget_investment, + budget: @budget, + price: nil, + administrator: create(:administrator)) + @investment.valuators << @valuator + end + + scenario 'Dossier empty by default' do + visit valuation_budget_budget_investments_path(@budget) + click_link @investment.title + + within('#price') { expect(page).to have_content('Undefined') } + within('#price_first_year') { expect(page).to have_content('Undefined') } + within('#duration') { expect(page).to have_content('Undefined') } + within('#feasibility') { expect(page).to have_content('Undecided') } + expect(page).to_not have_content('Valuation finished') + expect(page).to_not have_content('Internal comments') + end + + scenario 'Edit dossier' do + visit valuation_budget_budget_investments_path(@budget) + within("#budget_investment_#{@investment.id}") do + click_link "Edit" + end + + fill_in 'budget_investment_price', with: '12345' + fill_in 'budget_investment_price_first_year', with: '9876' + fill_in 'budget_investment_price_explanation', with: 'Very cheap idea' + choose 'budget_investment_feasibility_feasible' + fill_in 'budget_investment_duration', with: '19 months' + fill_in 'budget_investment_internal_comments', with: 'Should be double checked by the urbanism area' + click_button 'Save changes' + + expect(page).to have_content "Dossier updated" + + visit valuation_budget_budget_investments_path(@budget) + click_link @investment.title + + within('#price') { expect(page).to have_content('12345') } + within('#price_first_year') { expect(page).to have_content('9876') } + expect(page).to have_content('Very cheap idea') + within('#duration') { expect(page).to have_content('19 months') } + within('#feasibility') { expect(page).to have_content('Feasible') } + expect(page).to_not have_content('Valuation finished') + expect(page).to have_content('Internal comments') + expect(page).to have_content('Should be double checked by the urbanism area') + end + + scenario 'Feasibility can be marked as pending' do + visit valuation_budget_budget_investment_path(@budget, @investment) + click_link 'Edit dossier' + + expect(find "#budget_investment_feasibility_undecided").to be_checked + choose 'budget_investment_feasibility_feasible' + click_button 'Save changes' + + visit edit_valuation_budget_budget_investment_path(@budget, @investment) + + expect(find "#budget_investment_feasibility_undecided").to_not be_checked + expect(find "#budget_investment_feasibility_feasible").to be_checked + + choose 'budget_investment_feasibility_undecided' + click_button 'Save changes' + + visit edit_valuation_budget_budget_investment_path(@budget, @investment) + expect(find "#budget_investment_feasibility_undecided").to be_checked + end + + scenario 'Feasibility selection makes proper fields visible', :js do + feasible_fields = ['Price (€)','Cost during the first year (€)','Price explanation','Time scope'] + unfeasible_fields = ['Feasibility explanation'] + any_feasibility_fields = ['Valuation finished','Internal comments'] + undecided_fields = feasible_fields + unfeasible_fields + any_feasibility_fields + + visit edit_valuation_budget_budget_investment_path(@budget, @investment) + + expect(find "#budget_investment_feasibility_undecided").to be_checked + + undecided_fields.each do |field| + expect(page).to have_content(field) + end + + choose 'budget_investment_feasibility_feasible' + + unfeasible_fields.each do |field| + expect(page).to_not have_content(field) + end + + (feasible_fields + any_feasibility_fields).each do |field| + expect(page).to have_content(field) + end + + choose 'budget_investment_feasibility_unfeasible' + + feasible_fields.each do |field| + expect(page).to_not have_content(field) + end + + (unfeasible_fields + any_feasibility_fields).each do |field| + expect(page).to have_content(field) + end + + click_button 'Save changes' + + visit edit_valuation_budget_budget_investment_path(@budget, @investment) + + expect(find "#budget_investment_feasibility_unfeasible").to be_checked + feasible_fields.each do |field| + expect(page).to_not have_content(field) + end + + (unfeasible_fields + any_feasibility_fields).each do |field| + expect(page).to have_content(field) + end + + choose 'budget_investment_feasibility_undecided' + + undecided_fields.each do |field| + expect(page).to have_content(field) + end + end + + scenario 'Finish valuation' do + visit valuation_budget_budget_investment_path(@budget, @investment) + click_link 'Edit dossier' + + check 'budget_investment_valuation_finished' + click_button 'Save changes' + + visit valuation_budget_budget_investments_path(@budget) + expect(page).to_not have_content @investment.title + click_link 'Valuation finished' + + expect(page).to have_content @investment.title + click_link @investment.title + expect(page).to have_content('Valuation finished') + end + + scenario 'Validates price formats' do + visit valuation_budget_budget_investments_path(@budget) + within("#budget_investment_#{@investment.id}") do + click_link "Edit" + end + + fill_in 'budget_investment_price', with: '12345,98' + fill_in 'budget_investment_price_first_year', with: '9876.6' + click_button 'Save changes' + + expect(page).to have_content('2 errors') + expect(page).to have_content('Only integer numbers', count: 2) + end + end end \ No newline at end of file