From b483ca7f7e8d2cac38df4401ad50bb0a3d9b8eba Mon Sep 17 00:00:00 2001 From: Angel Perez Date: Wed, 27 Jun 2018 09:28:47 -0400 Subject: [PATCH 01/32] Add 'Execution' tab to a finished Budget This new tab will show all winner investments projects with milestones --- app/views/budgets/results/show.html.erb | 4 ++-- config/locales/en/budgets.yml | 2 ++ config/locales/es/budgets.yml | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/views/budgets/results/show.html.erb b/app/views/budgets/results/show.html.erb index 63308eaca..81c5e0904 100644 --- a/app/views/budgets/results/show.html.erb +++ b/app/views/budgets/results/show.html.erb @@ -29,10 +29,10 @@ diff --git a/config/locales/en/budgets.yml b/config/locales/en/budgets.yml index 094fcbe9e..6147af785 100644 --- a/config/locales/en/budgets.yml +++ b/config/locales/en/budgets.yml @@ -174,6 +174,8 @@ en: investment_proyects: List of all investment projects unfeasible_investment_proyects: List of all unfeasible investment projects not_selected_investment_proyects: List of all investment projects not selected for balloting + executions: + link: "Execution" phases: errors: dates_range_invalid: "Start date can't be equal or later than End date" diff --git a/config/locales/es/budgets.yml b/config/locales/es/budgets.yml index 11592e9c8..1674dce06 100644 --- a/config/locales/es/budgets.yml +++ b/config/locales/es/budgets.yml @@ -174,6 +174,8 @@ es: investment_proyects: Ver lista completa de proyectos de gasto unfeasible_investment_proyects: Ver lista de proyectos de gasto inviables not_selected_investment_proyects: Ver lista de proyectos de gasto no seleccionados para la votación final + executions: + link: "Ejecución" phases: errors: dates_range_invalid: "La fecha de comienzo no puede ser igual o superior a la de finalización" From 3e6cbc95058c7a5f12420dbc416b5b959d6c361a Mon Sep 17 00:00:00 2001 From: Angel Perez Date: Thu, 28 Jun 2018 09:26:50 -0400 Subject: [PATCH 02/32] Add basic frontend for budget executions list --- .../budgets/executions_controller.rb | 39 +++++++++++ app/models/abilities/everyone.rb | 2 +- app/views/budgets/executions/show.html.erb | 64 +++++++++++++++++++ config/locales/en/budgets.yml | 3 + config/locales/es/budgets.yml | 3 + config/routes/budget.rb | 1 + 6 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 app/controllers/budgets/executions_controller.rb create mode 100644 app/views/budgets/executions/show.html.erb diff --git a/app/controllers/budgets/executions_controller.rb b/app/controllers/budgets/executions_controller.rb new file mode 100644 index 000000000..d513c3924 --- /dev/null +++ b/app/controllers/budgets/executions_controller.rb @@ -0,0 +1,39 @@ +module Budgets + class ExecutionsController < ApplicationController + before_action :load_budget + before_action :load_heading + before_action :load_investments + + load_and_authorize_resource :budget + + def show + authorize! :read_executions, @budget + @statuses = ::Budget::Investment::Status.all + end + + private + + def load_budget + @budget = Budget.find_by(slug: params[:id]) || Budget.find_by(id: params[:id]) + end + + def load_heading + @heading = if params[:heading_id].present? + @budget.headings.find_by(slug: params[:heading_id]) + else + @heading = @budget.headings.first + end + end + + def load_investments + @investments = Budget::Result.new(@budget, @heading).investments.joins(:milestones) + + if params[:status].present? + @investments.where('budget_investment_milestones.status_id = ?', params[:status]) + else + @investments + end + end + + end +end diff --git a/app/models/abilities/everyone.rb b/app/models/abilities/everyone.rb index 23cfdc971..18927cc80 100644 --- a/app/models/abilities/everyone.rb +++ b/app/models/abilities/everyone.rb @@ -22,7 +22,7 @@ module Abilities can [:read], Budget can [:read], Budget::Group can [:read, :print, :json_data], Budget::Investment - can :read_results, Budget, phase: "finished" + can [:read_results, :read_executions], Budget, phase: "finished" can :new, DirectMessage can [:read, :debate, :draft_publication, :allegations, :result_publication, :proposals], Legislation::Process, published: true can [:read, :changes, :go_to_version], Legislation::DraftVersion diff --git a/app/views/budgets/executions/show.html.erb b/app/views/budgets/executions/show.html.erb new file mode 100644 index 000000000..8cab9ba10 --- /dev/null +++ b/app/views/budgets/executions/show.html.erb @@ -0,0 +1,64 @@ +<% provide :title, t('budgets.executions.page_title', budget: @budget.name) %> +<% content_for :meta_description do %><%= @budget.description_for_phase('finished') %><% end %> +<% provide :social_media_meta_tags do %> +<%= render 'shared/social_media_meta_tags', + social_url: budget_executions_url(@budget), + social_title: @budget.name, + social_description: @budget.description_for_phase('finished') %> +<% end %> + +<% content_for :canonical do %> + <%= render 'shared/canonical', href: budget_executions_url(@budget) %> +<% end %> + +
+
+
+
+ <%= back_link_to budgets_path %> +

+ <%= t('budgets.executions.heading') %>
+ <%= @budget.name %> +

+
+
+
+
+ +
+
+
    +
  • + <%= link_to t('budgets.results.link'), budget_results_path(@budget) %> +
  • +
  • + <%= link_to t('budgets.executions.link'), budget_executions_path(@budget), class: 'is-active' %> +
  • +
+
+
+ +
+
+

+ <%= t('budgets.executions.heading_selection_title') %> +

+ +
+ +
+ <%= form_tag(budget_executions_path(budget: @budget), method: :get) do %> +
+ <%= select_tag 'status', options_from_collection_for_select(@statuses, 'id', 'name') %> +
+ <% end %> +
+
diff --git a/config/locales/en/budgets.yml b/config/locales/en/budgets.yml index 6147af785..59cf697be 100644 --- a/config/locales/en/budgets.yml +++ b/config/locales/en/budgets.yml @@ -176,6 +176,9 @@ en: not_selected_investment_proyects: List of all investment projects not selected for balloting executions: link: "Execution" + page_title: "%{budget} - Executions" + heading: "Participatory budget executions" + heading_selection_title: "By district" phases: errors: dates_range_invalid: "Start date can't be equal or later than End date" diff --git a/config/locales/es/budgets.yml b/config/locales/es/budgets.yml index 1674dce06..90aed7ed8 100644 --- a/config/locales/es/budgets.yml +++ b/config/locales/es/budgets.yml @@ -176,6 +176,9 @@ es: not_selected_investment_proyects: Ver lista de proyectos de gasto no seleccionados para la votación final executions: link: "Ejecución" + page_title: "%{budget} - Ejecuciones" + heading: "Ejecuciones presupuestos participativos" + heading_selection_title: "Ámbito de actuación" phases: errors: dates_range_invalid: "La fecha de comienzo no puede ser igual o superior a la de finalización" diff --git a/config/routes/budget.rb b/config/routes/budget.rb index b3422744f..475d5496a 100644 --- a/config/routes/budget.rb +++ b/config/routes/budget.rb @@ -15,6 +15,7 @@ resources :budgets, only: [:show, :index] do end resource :results, only: :show, controller: "budgets/results" + resource :executions, only: :show, controller: 'budgets/executions' end scope '/participatory_budget' do From 3574bf867c274a48af5a2cff2fa97ee16019700a Mon Sep 17 00:00:00 2001 From: Angel Perez Date: Thu, 28 Jun 2018 17:03:50 -0400 Subject: [PATCH 03/32] Add default image for investments without picture --- app/models/site_customization/image.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/models/site_customization/image.rb b/app/models/site_customization/image.rb index b10f3799f..f551d206f 100644 --- a/app/models/site_customization/image.rb +++ b/app/models/site_customization/image.rb @@ -4,7 +4,8 @@ class SiteCustomization::Image < ActiveRecord::Base "logo_header" => [260, 80], "social_media_icon" => [470, 246], "social_media_icon_twitter" => [246, 246], - "apple-touch-icon-200" => [200, 200] + "apple-touch-icon-200" => [200, 200], + "budget_execution_no_image" => [800, 600] } has_attached_file :image From 97809db1b7ba647258e0d9b8b2648ebc564113d0 Mon Sep 17 00:00:00 2001 From: Angel Perez Date: Thu, 28 Jun 2018 22:37:25 -0400 Subject: [PATCH 04/32] Enable filtering of investments by their milestones statuses --- app/views/budgets/executions/show.html.erb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/views/budgets/executions/show.html.erb b/app/views/budgets/executions/show.html.erb index 8cab9ba10..03fce026e 100644 --- a/app/views/budgets/executions/show.html.erb +++ b/app/views/budgets/executions/show.html.erb @@ -57,7 +57,9 @@
<%= form_tag(budget_executions_path(budget: @budget), method: :get) do %>
- <%= select_tag 'status', options_from_collection_for_select(@statuses, 'id', 'name') %> + <%= select_tag :status, options_from_collection_for_select( + @statuses, "id", "name", params[:status] + ), class: "js-submit-on-change", include_blank: true %>
<% end %>
From 4f878180e5b9e77545d13532902ea6a157953ac6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20Mart=C3=ADn?= Date: Tue, 6 Nov 2018 13:02:30 +0100 Subject: [PATCH 05/32] Move creation of milestone statuses seeds So it's in the same lines as in Madrid's repository. --- db/dev_seeds/budgets.rb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/db/dev_seeds/budgets.rb b/db/dev_seeds/budgets.rb index 04b5272ff..6a44b977c 100644 --- a/db/dev_seeds/budgets.rb +++ b/db/dev_seeds/budgets.rb @@ -139,6 +139,13 @@ section "Creating Valuation Assignments" do end end +section "Creating default Investment Milestone Statuses" do + Budget::Investment::Status.create(name: I18n.t('seeds.budgets.statuses.studying_project')) + Budget::Investment::Status.create(name: I18n.t('seeds.budgets.statuses.bidding')) + Budget::Investment::Status.create(name: I18n.t('seeds.budgets.statuses.executing_project')) + Budget::Investment::Status.create(name: I18n.t('seeds.budgets.statuses.executed')) +end + section "Creating investment milestones" do Budget::Investment.find_each do |investment| milestone = Budget::Investment::Milestone.new(investment_id: investment.id, publication_date: Date.tomorrow) @@ -151,10 +158,3 @@ section "Creating investment milestones" do end end end - -section "Creating default Investment Milestone Statuses" do - Budget::Investment::Status.create(name: I18n.t('seeds.budgets.statuses.studying_project')) - Budget::Investment::Status.create(name: I18n.t('seeds.budgets.statuses.bidding')) - Budget::Investment::Status.create(name: I18n.t('seeds.budgets.statuses.executing_project')) - Budget::Investment::Status.create(name: I18n.t('seeds.budgets.statuses.executed')) -end From 6559c7212b3fff74689350145854413c3ecb0b7e Mon Sep 17 00:00:00 2001 From: Angel Perez Date: Mon, 2 Jul 2018 18:15:19 -0400 Subject: [PATCH 06/32] Add prompt & label for milestones filters under budgets/executions#show --- app/views/budgets/executions/show.html.erb | 15 ++++++++------- config/locales/en/budgets.yml | 3 +++ config/locales/es/budgets.yml | 3 +++ 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/app/views/budgets/executions/show.html.erb b/app/views/budgets/executions/show.html.erb index 03fce026e..ed0175463 100644 --- a/app/views/budgets/executions/show.html.erb +++ b/app/views/budgets/executions/show.html.erb @@ -1,4 +1,4 @@ -<% provide :title, t('budgets.executions.page_title', budget: @budget.name) %> +<% provide :title, t("budgets.executions.page_title", budget: @budget.name) %> <% content_for :meta_description do %><%= @budget.description_for_phase('finished') %><% end %> <% provide :social_media_meta_tags do %> <%= render 'shared/social_media_meta_tags', @@ -17,7 +17,7 @@
<%= back_link_to budgets_path %>

- <%= t('budgets.executions.heading') %>
+ <%= t("budgets.executions.heading") %>
<%= @budget.name %>

@@ -29,10 +29,10 @@
  • - <%= link_to t('budgets.results.link'), budget_results_path(@budget) %> + <%= link_to t("budgets.results.link"), budget_results_path(@budget) %>
  • - <%= link_to t('budgets.executions.link'), budget_executions_path(@budget), class: 'is-active' %> + <%= link_to t("budgets.executions.link"), budget_executions_path(@budget), class: 'is-active' %>
@@ -41,7 +41,7 @@

- <%= t('budgets.executions.heading_selection_title') %> + <%= t("budgets.executions.heading_selection_title") %>

- <%= form_tag(budget_executions_path(budget: @budget), method: :get) do %> + <%= form_tag(budget_executions_path(@budget), method: :get) do %>
<%= label_tag t("budgets.executions.filters.label") %> <%= select_tag :status, options_from_collection_for_select( From 5de74ea6f1d14dd8377d801be4b794af5027a2f8 Mon Sep 17 00:00:00 2001 From: Angel Perez Date: Mon, 2 Jul 2018 22:22:07 -0400 Subject: [PATCH 08/32] Load budget headings on budgets/executions#show action --- .../budgets/executions_controller.rb | 21 +------------------ app/views/budgets/executions/show.html.erb | 2 +- 2 files changed, 2 insertions(+), 21 deletions(-) diff --git a/app/controllers/budgets/executions_controller.rb b/app/controllers/budgets/executions_controller.rb index d513c3924..3d5373391 100644 --- a/app/controllers/budgets/executions_controller.rb +++ b/app/controllers/budgets/executions_controller.rb @@ -1,14 +1,13 @@ module Budgets class ExecutionsController < ApplicationController before_action :load_budget - before_action :load_heading - before_action :load_investments load_and_authorize_resource :budget def show authorize! :read_executions, @budget @statuses = ::Budget::Investment::Status.all + @headings = @budget.headings.order(id: :asc) end private @@ -17,23 +16,5 @@ module Budgets @budget = Budget.find_by(slug: params[:id]) || Budget.find_by(id: params[:id]) end - def load_heading - @heading = if params[:heading_id].present? - @budget.headings.find_by(slug: params[:heading_id]) - else - @heading = @budget.headings.first - end - end - - def load_investments - @investments = Budget::Result.new(@budget, @heading).investments.joins(:milestones) - - if params[:status].present? - @investments.where('budget_investment_milestones.status_id = ?', params[:status]) - else - @investments - end - end - end end diff --git a/app/views/budgets/executions/show.html.erb b/app/views/budgets/executions/show.html.erb index 558e95127..2788a6379 100644 --- a/app/views/budgets/executions/show.html.erb +++ b/app/views/budgets/executions/show.html.erb @@ -44,7 +44,7 @@ <%= t("budgets.executions.heading_selection_title") %>
<% end %> + + <%= render 'budgets/executions/investments' %>
From c7936bacae788f384f545a9b2e72086f6717389f Mon Sep 17 00:00:00 2001 From: decabeza Date: Tue, 3 Jul 2018 17:22:48 +0200 Subject: [PATCH 10/32] Adds styles to budgets execution --- app/assets/stylesheets/participation.scss | 52 +++++++++++++++++++ .../budgets/executions/_investments.html.erb | 40 +++++++++----- 2 files changed, 78 insertions(+), 14 deletions(-) diff --git a/app/assets/stylesheets/participation.scss b/app/assets/stylesheets/participation.scss index 112afe7d4..b4ee47a83 100644 --- a/app/assets/stylesheets/participation.scss +++ b/app/assets/stylesheets/participation.scss @@ -1680,6 +1680,58 @@ } } +.budget-execution { + border: 1px solid $border; + overflow: hidden; + position: relative; + + a { + color: $text; + display: block; + + img { + max-height: $line-height * 13; + transition-duration: 0.3s; + transition-property: transform; + } + + &:hover { + text-decoration: none; + + img { + transform: scale(1.05); + } + } + } + + h5 { + font-size: $base-font-size; + margin-bottom: 0; + } + + .budget-execution-info { + padding: $line-height / 2; + } + + .author { + color: $text-medium; + font-size: $small-font-size; + } + + .budget-execution-content { + min-height: $line-height * 3; + } + + .price { + color: $budget; + font-size: rem-calc(24); + } + + &:hover { + box-shadow: 0 0 12px 0 rgba(0, 0, 0, 0.2); + } +} + // 07. Proposals successful // ------------------------- diff --git a/app/views/budgets/executions/_investments.html.erb b/app/views/budgets/executions/_investments.html.erb index fb7df6170..c07ae9fdb 100644 --- a/app/views/budgets/executions/_investments.html.erb +++ b/app/views/budgets/executions/_investments.html.erb @@ -1,17 +1,29 @@ -
- <% @headings.each do |heading| %> - <%= heading.name %> +<% @headings.each do |heading| %> +

+ <%= heading.name %> +

+
<% heading.investments.selected.sort_by_ballots.joins(:milestones).each do |investment| %> -
- <% if investment.image.present? %> - <%= image_tag investment.image_url(:thumb), alt: investment.image.title %> - <% else %> - <%= image_tag Rails.root.join('/budget_execution_no_image.jpg'), alt: investment.title %> - <% end %> - <%= investment.title %> - <%= investment.author.name %> - <%= investment.formatted_price %> +
+
+ <%= link_to investment.url, data: { 'equalizer-watch': true} do %> + <% if investment.image.present? %> + <%= image_tag investment.image_url(:thumb), alt: investment.image.title %> + <% else %> + <%= image_tag Rails.root.join('/budget_execution_no_image.jpg'), alt: investment.title %> + <% end %> +
+
+
<%= investment.title %>
+ <%= investment.author.name %> +
+

+ <%= investment.formatted_price %> +

+
+ <% end %> +
<% end %> - <% end %> -
+
+<% end %> From eb76f644b796d87fb8a559e8868db83e9ea5490b Mon Sep 17 00:00:00 2001 From: decabeza Date: Tue, 3 Jul 2018 17:23:10 +0200 Subject: [PATCH 11/32] Adds link to heading name on sidebar --- app/views/budgets/executions/show.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/budgets/executions/show.html.erb b/app/views/budgets/executions/show.html.erb index 423714d92..1d793ea80 100644 --- a/app/views/budgets/executions/show.html.erb +++ b/app/views/budgets/executions/show.html.erb @@ -46,7 +46,7 @@ From a03c13aa22ca38ecb05e42daa5537eb9277ce2bc Mon Sep 17 00:00:00 2001 From: decabeza Date: Wed, 4 Jul 2018 12:54:46 +0200 Subject: [PATCH 12/32] Updates executions texts --- config/locales/en/budgets.yml | 6 +++--- config/locales/es/budgets.yml | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/config/locales/en/budgets.yml b/config/locales/en/budgets.yml index 091a9fab3..37d364305 100644 --- a/config/locales/en/budgets.yml +++ b/config/locales/en/budgets.yml @@ -175,9 +175,9 @@ en: unfeasible_investment_proyects: List of all unfeasible investment projects not_selected_investment_proyects: List of all investment projects not selected for balloting executions: - link: "Execution" - page_title: "%{budget} - Executions" - heading: "Participatory budget executions" + link: "Milestones" + page_title: "%{budget} - Milestones" + heading: "Participatory budget Milestones" heading_selection_title: "By district" filters: label: "Project's current state" diff --git a/config/locales/es/budgets.yml b/config/locales/es/budgets.yml index e2b1596e8..9547c235a 100644 --- a/config/locales/es/budgets.yml +++ b/config/locales/es/budgets.yml @@ -175,9 +175,9 @@ es: unfeasible_investment_proyects: Ver lista de proyectos de gasto inviables not_selected_investment_proyects: Ver lista de proyectos de gasto no seleccionados para la votación final executions: - link: "Ejecución" - page_title: "%{budget} - Ejecuciones" - heading: "Ejecuciones presupuestos participativos" + link: "Seguimiento" + page_title: "%{budget} - Seguimiento de proyectos" + heading: "Seguimiento de proyectos" heading_selection_title: "Ámbito de actuación" filters: label: "Estado actual del proyecto" From 689b25c97785f1585dca22667d451b10f810b482 Mon Sep 17 00:00:00 2001 From: decabeza Date: Wed, 4 Jul 2018 12:55:20 +0200 Subject: [PATCH 13/32] Adds tab-milestones anchor to link and milestone image --- app/views/budgets/executions/_investments.html.erb | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/app/views/budgets/executions/_investments.html.erb b/app/views/budgets/executions/_investments.html.erb index c07ae9fdb..d8d74d593 100644 --- a/app/views/budgets/executions/_investments.html.erb +++ b/app/views/budgets/executions/_investments.html.erb @@ -6,11 +6,15 @@ <% heading.investments.selected.sort_by_ballots.joins(:milestones).each do |investment| %>
- <%= link_to investment.url, data: { 'equalizer-watch': true} do %> - <% if investment.image.present? %> - <%= image_tag investment.image_url(:thumb), alt: investment.image.title %> - <% else %> - <%= image_tag Rails.root.join('/budget_execution_no_image.jpg'), alt: investment.title %> + <%= link_to budget_investment_path(@budget, investment, anchor: "tab-milestones"), data: { 'equalizer-watch': true } do %> + <% investment.milestones.each do |milestone| %> + <% if milestone.image.present? %> + <%= image_tag milestone.image_url(:large), alt: milestone.image.title %> + <% elsif investment.image.present? %> + <%= image_tag investment.image_url(:thumb), alt: investment.image.title %> + <% else %> + <%= image_tag Rails.root.join('/budget_execution_no_image.jpg'), alt: investment.title %> + <% end %> <% end %>
From a07a100828f5f6d8d988c199077974ab4acabe2b Mon Sep 17 00:00:00 2001 From: decabeza Date: Wed, 4 Jul 2018 12:55:31 +0200 Subject: [PATCH 14/32] Fixes image sizes --- app/assets/stylesheets/participation.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/participation.scss b/app/assets/stylesheets/participation.scss index b4ee47a83..4bc64f9a5 100644 --- a/app/assets/stylesheets/participation.scss +++ b/app/assets/stylesheets/participation.scss @@ -1690,9 +1690,10 @@ display: block; img { - max-height: $line-height * 13; + height: $line-height * 9; transition-duration: 0.3s; transition-property: transform; + width: 100%; } &:hover { From 448ac7a1584bfadb2bad0ffc8ea37b29b9ef1a19 Mon Sep 17 00:00:00 2001 From: Angel Perez Date: Wed, 4 Jul 2018 13:33:50 -0400 Subject: [PATCH 15/32] Restore filtering investments by milestone status query This commit makes 3 changes: 1. Extracts a query into a helper for clarity and DRYness 2. Adds a `.where` clause to filter investments based on their (current) milestone status 3. Fixes a bug where investments would be rendered as many times as milestones associated to an investment --- app/helpers/budget_executions_helper.rb | 20 +++++++++++++++++++ .../budgets/executions/_investments.html.erb | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 app/helpers/budget_executions_helper.rb diff --git a/app/helpers/budget_executions_helper.rb b/app/helpers/budget_executions_helper.rb new file mode 100644 index 000000000..1681da6f4 --- /dev/null +++ b/app/helpers/budget_executions_helper.rb @@ -0,0 +1,20 @@ +module BudgetExecutionsHelper + + def winner_investments(heading) + if params[:status].present? + heading.investments + .selected + .sort_by_ballots + .joins(:milestones) + .distinct + .where('budget_investment_milestones.status_id = ?', params[:status]) + else + heading.investments + .selected + .sort_by_ballots + .joins(:milestones) + .distinct + end + end + +end diff --git a/app/views/budgets/executions/_investments.html.erb b/app/views/budgets/executions/_investments.html.erb index d8d74d593..bbcd50409 100644 --- a/app/views/budgets/executions/_investments.html.erb +++ b/app/views/budgets/executions/_investments.html.erb @@ -3,7 +3,7 @@ <%= heading.name %>
- <% heading.investments.selected.sort_by_ballots.joins(:milestones).each do |investment| %> + <% winner_investments(heading).each do |investment| %>
<%= link_to budget_investment_path(@budget, investment, anchor: "tab-milestones"), data: { 'equalizer-watch': true } do %> From 99e4e7ef8a3b382650e34f6294fa38d1bde38599 Mon Sep 17 00:00:00 2001 From: Angel Perez Date: Thu, 5 Jul 2018 18:30:10 -0400 Subject: [PATCH 16/32] Limit milestones to 1 per investment and sort them by publication date --- app/views/budgets/executions/_investments.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/budgets/executions/_investments.html.erb b/app/views/budgets/executions/_investments.html.erb index bbcd50409..0c96a58e7 100644 --- a/app/views/budgets/executions/_investments.html.erb +++ b/app/views/budgets/executions/_investments.html.erb @@ -7,7 +7,7 @@
<%= link_to budget_investment_path(@budget, investment, anchor: "tab-milestones"), data: { 'equalizer-watch': true } do %> - <% investment.milestones.each do |milestone| %> + <% investment.milestones.order(publication_date: :desc).limit(1).each do |milestone| %> <% if milestone.image.present? %> <%= image_tag milestone.image_url(:large), alt: milestone.image.title %> <% elsif investment.image.present? %> From 51147929415437d366cb9208535e411be6b674cb Mon Sep 17 00:00:00 2001 From: Angel Perez Date: Fri, 6 Jul 2018 00:56:23 -0400 Subject: [PATCH 17/32] Add specs for budgets/executions feature --- spec/features/budgets/executions_spec.rb | 150 +++++++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 spec/features/budgets/executions_spec.rb diff --git a/spec/features/budgets/executions_spec.rb b/spec/features/budgets/executions_spec.rb new file mode 100644 index 000000000..2dd9b5954 --- /dev/null +++ b/spec/features/budgets/executions_spec.rb @@ -0,0 +1,150 @@ +require 'rails_helper' + +feature 'Executions' do + + let(:budget) { create(:budget, phase: 'finished') } + let(:group) { create(:budget_group, budget: budget) } + let(:heading) { create(:budget_heading, group: group, price: 1000) } + + let!(:investment1) { create(:budget_investment, :selected, heading: heading, price: 200, ballot_lines_count: 900) } + let!(:investment2) { create(:budget_investment, :selected, heading: heading, price: 300, ballot_lines_count: 800) } + let!(:investment3) { create(:budget_investment, :incompatible, heading: heading, price: 500, ballot_lines_count: 700) } + let!(:investment4) { create(:budget_investment, :selected, heading: heading, price: 600, ballot_lines_count: 600) } + + scenario 'only displays investments with milestones' do + create(:budget_investment_milestone, investment: investment1) + + visit budget_path(budget) + click_link 'See results' + + expect(page).to have_link('Milestones') + + click_link 'Milestones' + + expect(page).to have_content(investment1.title) + expect(page).not_to have_content(investment2.title) + expect(page).not_to have_content(investment3.title) + expect(page).not_to have_content(investment4.title) + end + + context 'Images' do + scenario 'renders milestone image if available' do + milestone1 = create(:budget_investment_milestone, investment: investment1) + create(:image, imageable: milestone1) + + visit budget_path(budget) + + click_link 'See results' + click_link 'Milestones' + + expect(page).to have_content(investment1.title) + expect(page).to have_css("img[alt='#{milestone1.image.title}']") + end + + scenario 'renders investment image if no milestone image is available' do + create(:budget_investment_milestone, investment: investment2) + create(:image, imageable: investment2) + + visit budget_path(budget) + + click_link 'See results' + click_link 'Milestones' + + expect(page).to have_content(investment2.title) + expect(page).to have_css("img[alt='#{investment2.image.title}']") + end + + scenario 'renders default image if no milestone nor investment images are available' do + create(:budget_investment_milestone, investment: investment4) + + visit budget_path(budget) + + click_link 'See results' + click_link 'Milestones' + + expect(page).to have_content(investment4.title) + expect(page).to have_css("img[alt='#{investment4.title}']") + end + + scenario "renders last milestone's image if investment has multiple milestones with images associated" do + milestone1 = create(:budget_investment_milestone, investment: investment1, + publication_date: Date.yesterday) + + milestone2 = create(:budget_investment_milestone, investment: investment1, + publication_date: Date.tomorrow) + + create(:image, imageable: milestone1, title: 'First milestone image') + create(:image, imageable: milestone2, title: 'Second milestone image') + + visit budget_path(budget) + + click_link 'See results' + click_link 'Milestones' + + expect(page).to have_content(investment1.title) + expect(page).to have_css("img[alt='#{milestone2.image.title}']") + expect(page).not_to have_css("img[alt='#{milestone1.image.title}']") + end + end + + context 'Filters' do + + let!(:status1) { create(:budget_investment_status, name: I18n.t('seeds.budgets.statuses.studying_project')) } + let!(:status2) { create(:budget_investment_status, name: I18n.t('seeds.budgets.statuses.bidding')) } + + scenario 'by milestone status', :js do + create(:budget_investment_milestone, investment: investment1, status: status1) + create(:budget_investment_milestone, investment: investment2, status: status2) + create(:budget_investment_status, name: I18n.t('seeds.budgets.statuses.executing_project')) + + visit budget_path(budget) + + click_link 'See results' + click_link 'Milestones' + + expect(page).to have_content(investment1.title) + expect(page).to have_content(investment2.title) + + select 'Studying the project', from: 'status' + + expect(page).to have_content(investment1.title) + expect(page).not_to have_content(investment2.title) + + select 'Bidding', from: 'status' + + expect(page).to have_content(investment2.title) + expect(page).not_to have_content(investment1.title) + + select 'Executing the project', from: 'status' + + expect(page).not_to have_content(investment1.title) + expect(page).not_to have_content(investment2.title) + end + + xscenario 'are based on latest milestone status', :js do + create(:budget_investment_milestone, investment: investment1, + publication_date: Date.yesterday, + status: status1) + + create(:budget_investment_milestone, investment: investment1, + publication_date: Date.tomorrow, + status: status2) + + visit budget_path(budget) + + click_link 'See results' + click_link 'Milestones' + + expect(page).to have_content(investment1.title) + + select 'Studying the project', from: 'status' + + expect(page).not_to have_content(investment1.title) + + select 'Bidding', from: 'status' + + expect(page).to have_content(investment1.title) + end + end + +end From 62b99f01bc0a364d031d22e14870d020f5a47069 Mon Sep 17 00:00:00 2001 From: Angel Perez Date: Wed, 11 Jul 2018 12:39:34 -0400 Subject: [PATCH 18/32] Show message for headings without winner investments --- .../budgets/executions/_investments.html.erb | 56 ++++++++++--------- config/locales/en/budgets.yml | 1 + config/locales/es/budgets.yml | 1 + spec/features/budgets/executions_spec.rb | 17 ++++++ 4 files changed, 50 insertions(+), 25 deletions(-) diff --git a/app/views/budgets/executions/_investments.html.erb b/app/views/budgets/executions/_investments.html.erb index 0c96a58e7..b04639a50 100644 --- a/app/views/budgets/executions/_investments.html.erb +++ b/app/views/budgets/executions/_investments.html.erb @@ -2,32 +2,38 @@

<%= heading.name %>

-
- <% winner_investments(heading).each do |investment| %> -
-
- <%= link_to budget_investment_path(@budget, investment, anchor: "tab-milestones"), data: { 'equalizer-watch': true } do %> - <% investment.milestones.order(publication_date: :desc).limit(1).each do |milestone| %> - <% if milestone.image.present? %> - <%= image_tag milestone.image_url(:large), alt: milestone.image.title %> - <% elsif investment.image.present? %> - <%= image_tag investment.image_url(:thumb), alt: investment.image.title %> - <% else %> - <%= image_tag Rails.root.join('/budget_execution_no_image.jpg'), alt: investment.title %> + <% if winner_investments(heading).any? %> +
+ <% winner_investments(heading).each do |investment| %> +
+
+ <%= link_to budget_investment_path(@budget, investment, anchor: "tab-milestones"), data: { 'equalizer-watch': true } do %> + <% investment.milestones.order(publication_date: :desc).limit(1).each do |milestone| %> + <% if milestone.image.present? %> + <%= image_tag milestone.image_url(:large), alt: milestone.image.title %> + <% elsif investment.image.present? %> + <%= image_tag investment.image_url(:thumb), alt: investment.image.title %> + <% else %> + <%= image_tag Rails.root.join('/budget_execution_no_image.jpg'), alt: investment.title %> + <% end %> <% end %> - <% end %> -
-
-
<%= investment.title %>
- <%= investment.author.name %> +
+
+
<%= investment.title %>
+ <%= investment.author.name %> +
+

+ <%= investment.formatted_price %> +

-

- <%= investment.formatted_price %> -

-
- <% end %> + <% end %> +
-
- <% end %> -
+ <% end %> +
+ <% else %> +
+ <%= t("budgets.executions.no_winner_investments") %> +
+ <% end %> <% end %> diff --git a/config/locales/en/budgets.yml b/config/locales/en/budgets.yml index 37d364305..b342aaf86 100644 --- a/config/locales/en/budgets.yml +++ b/config/locales/en/budgets.yml @@ -179,6 +179,7 @@ en: page_title: "%{budget} - Milestones" heading: "Participatory budget Milestones" heading_selection_title: "By district" + no_winner_investments: "No winner investments for this heading" filters: label: "Project's current state" all: "All" diff --git a/config/locales/es/budgets.yml b/config/locales/es/budgets.yml index 9547c235a..7f1e03914 100644 --- a/config/locales/es/budgets.yml +++ b/config/locales/es/budgets.yml @@ -179,6 +179,7 @@ es: page_title: "%{budget} - Seguimiento de proyectos" heading: "Seguimiento de proyectos" heading_selection_title: "Ámbito de actuación" + no_winner_investments: "No hay proyectos de gasto ganadores para esta partida" filters: label: "Estado actual del proyecto" all: "Todos" diff --git a/spec/features/budgets/executions_spec.rb b/spec/features/budgets/executions_spec.rb index 2dd9b5954..6c3b6b6b1 100644 --- a/spec/features/budgets/executions_spec.rb +++ b/spec/features/budgets/executions_spec.rb @@ -27,6 +27,23 @@ feature 'Executions' do expect(page).not_to have_content(investment4.title) end + scenario 'render a message for headings without winner investments' do + empty_group = create(:budget_group, budget: budget) + empty_heading = create(:budget_heading, group: empty_group, price: 1000) + + visit budget_path(budget) + click_link 'See results' + + expect(page).to have_content(heading.name) + expect(page).to have_content(empty_heading.name) + + click_link 'Milestones' + click_link "#{empty_heading.name}" + + expect(page).to have_content('No winner investments for this heading') + end + + context 'Images' do scenario 'renders milestone image if available' do milestone1 = create(:budget_investment_milestone, investment: investment1) From 749954267de78e6d37f587fd21fdd8366fc61cbc Mon Sep 17 00:00:00 2001 From: Angel Perez Date: Wed, 11 Jul 2018 12:41:48 -0400 Subject: [PATCH 19/32] Use Budget::Investment#winners scope to fetch only winner investments --- app/helpers/budget_executions_helper.rb | 6 ++---- spec/features/budgets/executions_spec.rb | 6 +++--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/app/helpers/budget_executions_helper.rb b/app/helpers/budget_executions_helper.rb index 1681da6f4..ec448c675 100644 --- a/app/helpers/budget_executions_helper.rb +++ b/app/helpers/budget_executions_helper.rb @@ -3,15 +3,13 @@ module BudgetExecutionsHelper def winner_investments(heading) if params[:status].present? heading.investments - .selected - .sort_by_ballots + .winners .joins(:milestones) .distinct .where('budget_investment_milestones.status_id = ?', params[:status]) else heading.investments - .selected - .sort_by_ballots + .winners .joins(:milestones) .distinct end diff --git a/spec/features/budgets/executions_spec.rb b/spec/features/budgets/executions_spec.rb index 6c3b6b6b1..03bdc21ab 100644 --- a/spec/features/budgets/executions_spec.rb +++ b/spec/features/budgets/executions_spec.rb @@ -6,10 +6,10 @@ feature 'Executions' do let(:group) { create(:budget_group, budget: budget) } let(:heading) { create(:budget_heading, group: group, price: 1000) } - let!(:investment1) { create(:budget_investment, :selected, heading: heading, price: 200, ballot_lines_count: 900) } - let!(:investment2) { create(:budget_investment, :selected, heading: heading, price: 300, ballot_lines_count: 800) } + let!(:investment1) { create(:budget_investment, :winner, heading: heading, price: 200, ballot_lines_count: 900) } + let!(:investment2) { create(:budget_investment, :winner, heading: heading, price: 300, ballot_lines_count: 800) } let!(:investment3) { create(:budget_investment, :incompatible, heading: heading, price: 500, ballot_lines_count: 700) } - let!(:investment4) { create(:budget_investment, :selected, heading: heading, price: 600, ballot_lines_count: 600) } + let!(:investment4) { create(:budget_investment, :winner, heading: heading, price: 600, ballot_lines_count: 600) } scenario 'only displays investments with milestones' do create(:budget_investment_milestone, investment: investment1) From a3ef662509f945c1c26e3aba3545390e888ee254 Mon Sep 17 00:00:00 2001 From: Angel Perez Date: Thu, 12 Jul 2018 22:01:26 -0400 Subject: [PATCH 20/32] Filtering investments are based on the latest milestone status --- app/helpers/budget_executions_helper.rb | 9 ++++++++- spec/features/budgets/executions_spec.rb | 4 +++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/app/helpers/budget_executions_helper.rb b/app/helpers/budget_executions_helper.rb index ec448c675..64caa0c18 100644 --- a/app/helpers/budget_executions_helper.rb +++ b/app/helpers/budget_executions_helper.rb @@ -6,7 +6,7 @@ module BudgetExecutionsHelper .winners .joins(:milestones) .distinct - .where('budget_investment_milestones.status_id = ?', params[:status]) + .where(filter_investment_by_latest_milestone, params[:status]) else heading.investments .winners @@ -15,4 +15,11 @@ module BudgetExecutionsHelper end end + def filter_investment_by_latest_milestone + <<-SQL + (SELECT status_id FROM budget_investment_milestones + WHERE investment_id = budget_investments.id ORDER BY publication_date DESC LIMIT 1) = ? + SQL + end + end diff --git a/spec/features/budgets/executions_spec.rb b/spec/features/budgets/executions_spec.rb index 03bdc21ab..0f8a31a8d 100644 --- a/spec/features/budgets/executions_spec.rb +++ b/spec/features/budgets/executions_spec.rb @@ -138,7 +138,7 @@ feature 'Executions' do expect(page).not_to have_content(investment2.title) end - xscenario 'are based on latest milestone status', :js do + scenario 'are based on latest milestone status', :js do create(:budget_investment_milestone, investment: investment1, publication_date: Date.yesterday, status: status1) @@ -157,10 +157,12 @@ feature 'Executions' do select 'Studying the project', from: 'status' expect(page).not_to have_content(investment1.title) + expect(page).to have_content('No winner investments for this heading') select 'Bidding', from: 'status' expect(page).to have_content(investment1.title) + expect(page).not_to have_content('No winner investments for this heading') end end From 8376efce3f2c4466b58938754354e70d79fa42f3 Mon Sep 17 00:00:00 2001 From: Marko Lovic Date: Fri, 20 Jul 2018 12:43:36 +0200 Subject: [PATCH 21/32] Hide headings with no investments The page should not show any headings which don't have any winning investments. The "no content" message should only be shown when there are no headings with investments to avoid an otherwise blank page. __Note:__ in the main @headings query, _both_ #includes and #joins are needed to: 1. eager load all necessary data (#includes) and 2. to perform an INNER JOIN on milestones to filter out investments with no milestones (#joins). --- .../budgets/executions_controller.rb | 17 ++++++++++++- app/helpers/budget_executions_helper.rb | 25 ------------------- .../budgets/executions/_investments.html.erb | 14 +++-------- app/views/budgets/executions/show.html.erb | 8 +++++- config/locales/en/budgets.yml | 2 +- config/locales/es/budgets.yml | 2 +- spec/features/budgets/executions_spec.rb | 23 ++++++++++++++--- 7 files changed, 48 insertions(+), 43 deletions(-) delete mode 100644 app/helpers/budget_executions_helper.rb diff --git a/app/controllers/budgets/executions_controller.rb b/app/controllers/budgets/executions_controller.rb index 3d5373391..dc899c3a7 100644 --- a/app/controllers/budgets/executions_controller.rb +++ b/app/controllers/budgets/executions_controller.rb @@ -7,7 +7,16 @@ module Budgets def show authorize! :read_executions, @budget @statuses = ::Budget::Investment::Status.all - @headings = @budget.headings.order(id: :asc) + @headings = @budget.headings + .includes(investments: :milestones) + .joins(investments: :milestones) + .where(budget_investments: {winner: true}) + .distinct + .order(id: :asc) + + if params[:status].present? + @headings = @headings.where(filter_investment_by_latest_milestone, params[:status]) + end end private @@ -16,5 +25,11 @@ module Budgets @budget = Budget.find_by(slug: params[:id]) || Budget.find_by(id: params[:id]) end + def filter_investment_by_latest_milestone + <<-SQL + (SELECT status_id FROM budget_investment_milestones + WHERE investment_id = budget_investments.id ORDER BY publication_date DESC LIMIT 1) = ? + SQL + end end end diff --git a/app/helpers/budget_executions_helper.rb b/app/helpers/budget_executions_helper.rb deleted file mode 100644 index 64caa0c18..000000000 --- a/app/helpers/budget_executions_helper.rb +++ /dev/null @@ -1,25 +0,0 @@ -module BudgetExecutionsHelper - - def winner_investments(heading) - if params[:status].present? - heading.investments - .winners - .joins(:milestones) - .distinct - .where(filter_investment_by_latest_milestone, params[:status]) - else - heading.investments - .winners - .joins(:milestones) - .distinct - end - end - - def filter_investment_by_latest_milestone - <<-SQL - (SELECT status_id FROM budget_investment_milestones - WHERE investment_id = budget_investments.id ORDER BY publication_date DESC LIMIT 1) = ? - SQL - end - -end diff --git a/app/views/budgets/executions/_investments.html.erb b/app/views/budgets/executions/_investments.html.erb index b04639a50..0808b354a 100644 --- a/app/views/budgets/executions/_investments.html.erb +++ b/app/views/budgets/executions/_investments.html.erb @@ -1,10 +1,9 @@ <% @headings.each do |heading| %> -

- <%= heading.name %> -

- <% if winner_investments(heading).any? %> +

+ <%= heading.name %> +

- <% winner_investments(heading).each do |investment| %> + <% heading.investments.each do |investment| %>
<%= link_to budget_investment_path(@budget, investment, anchor: "tab-milestones"), data: { 'equalizer-watch': true } do %> @@ -31,9 +30,4 @@
<% end %>
- <% else %> -
- <%= t("budgets.executions.no_winner_investments") %> -
- <% end %> <% end %> diff --git a/app/views/budgets/executions/show.html.erb b/app/views/budgets/executions/show.html.erb index 1d793ea80..dc18d2d08 100644 --- a/app/views/budgets/executions/show.html.erb +++ b/app/views/budgets/executions/show.html.erb @@ -62,6 +62,12 @@
<% end %> - <%= render 'budgets/executions/investments' %> + <% if @headings.any? %> + <%= render 'budgets/executions/investments' %> + <% else %> +
+ <%= t("budgets.executions.no_winner_investments") %> +
+ <% end %>
diff --git a/config/locales/en/budgets.yml b/config/locales/en/budgets.yml index b342aaf86..658ac429d 100644 --- a/config/locales/en/budgets.yml +++ b/config/locales/en/budgets.yml @@ -179,7 +179,7 @@ en: page_title: "%{budget} - Milestones" heading: "Participatory budget Milestones" heading_selection_title: "By district" - no_winner_investments: "No winner investments for this heading" + no_winner_investments: "No winner investments in this state" filters: label: "Project's current state" all: "All" diff --git a/config/locales/es/budgets.yml b/config/locales/es/budgets.yml index 7f1e03914..60a02a6eb 100644 --- a/config/locales/es/budgets.yml +++ b/config/locales/es/budgets.yml @@ -179,7 +179,7 @@ es: page_title: "%{budget} - Seguimiento de proyectos" heading: "Seguimiento de proyectos" heading_selection_title: "Ámbito de actuación" - no_winner_investments: "No hay proyectos de gasto ganadores para esta partida" + no_winner_investments: "No hay proyectos de gasto ganadores en este estado" filters: label: "Estado actual del proyecto" all: "Todos" diff --git a/spec/features/budgets/executions_spec.rb b/spec/features/budgets/executions_spec.rb index 0f8a31a8d..78b8ab4d0 100644 --- a/spec/features/budgets/executions_spec.rb +++ b/spec/features/budgets/executions_spec.rb @@ -27,7 +27,9 @@ feature 'Executions' do expect(page).not_to have_content(investment4.title) end - scenario 'render a message for headings without winner investments' do + scenario "Do not display headings with no winning investments for selected status" do + create(:budget_investment_milestone, investment: investment1) + empty_group = create(:budget_group, budget: budget) empty_heading = create(:budget_heading, group: empty_group, price: 1000) @@ -38,11 +40,25 @@ feature 'Executions' do expect(page).to have_content(empty_heading.name) click_link 'Milestones' - click_link "#{empty_heading.name}" - expect(page).to have_content('No winner investments for this heading') + expect(page).to have_content(heading.name) + expect(page).not_to have_content(empty_heading.name) end + scenario "Show message when there are no winning investments with the selected status", :js do + create(:budget_investment_status, name: I18n.t('seeds.budgets.statuses.executed')) + + visit budget_path(budget) + + click_link 'See results' + click_link 'Milestones' + + expect(page).not_to have_content('No winner investments in this state') + + select 'Executed', from: 'status' + + expect(page).to have_content('No winner investments in this state') + end context 'Images' do scenario 'renders milestone image if available' do @@ -157,7 +173,6 @@ feature 'Executions' do select 'Studying the project', from: 'status' expect(page).not_to have_content(investment1.title) - expect(page).to have_content('No winner investments for this heading') select 'Bidding', from: 'status' From 685927116c863c4022b87498828e199f0d09d9e4 Mon Sep 17 00:00:00 2001 From: rgarcia Date: Fri, 20 Jul 2018 21:40:50 +0200 Subject: [PATCH 22/32] Query for all investments, not only winner investment Spending proposals did not have a winner attribute, instead winners where calculated dynamically looking at votes Removing this condition, so that we can see investment for the 2016 participatory budget which used spending proposals --- app/controllers/budgets/executions_controller.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/controllers/budgets/executions_controller.rb b/app/controllers/budgets/executions_controller.rb index dc899c3a7..d0ff488b9 100644 --- a/app/controllers/budgets/executions_controller.rb +++ b/app/controllers/budgets/executions_controller.rb @@ -10,7 +10,6 @@ module Budgets @headings = @budget.headings .includes(investments: :milestones) .joins(investments: :milestones) - .where(budget_investments: {winner: true}) .distinct .order(id: :asc) From 4758c1b91a6678a91fc83b6c5062c72d720d64d2 Mon Sep 17 00:00:00 2001 From: Marko Lovic Date: Mon, 23 Jul 2018 20:07:50 +0200 Subject: [PATCH 23/32] Show city heading in first position on executions list --- .../budgets/executions_controller.rb | 16 +++++++++++ spec/features/budgets/executions_spec.rb | 27 +++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/app/controllers/budgets/executions_controller.rb b/app/controllers/budgets/executions_controller.rb index d0ff488b9..7828ca8ec 100644 --- a/app/controllers/budgets/executions_controller.rb +++ b/app/controllers/budgets/executions_controller.rb @@ -16,6 +16,8 @@ module Budgets if params[:status].present? @headings = @headings.where(filter_investment_by_latest_milestone, params[:status]) end + + @headings = reorder_with_city_heading_first(@headings) end private @@ -30,5 +32,19 @@ module Budgets WHERE investment_id = budget_investments.id ORDER BY publication_date DESC LIMIT 1) = ? SQL end + + def reorder_with_city_heading_first(original_headings) + headings = original_headings.to_a.dup + + city_heading_index = headings.find_index do |heading| + heading.name == "Toda la ciudad" + end + + if city_heading_index + headings.insert(0, headings.delete_at(city_heading_index)) + else + headings + end + end end end diff --git a/spec/features/budgets/executions_spec.rb b/spec/features/budgets/executions_spec.rb index 78b8ab4d0..5ac7f9cfd 100644 --- a/spec/features/budgets/executions_spec.rb +++ b/spec/features/budgets/executions_spec.rb @@ -181,4 +181,31 @@ feature 'Executions' do end end + context 'Heading Order' do + + def create_heading_with_investment_with_milestone(group:, name:) + heading = create(:budget_heading, group: group, name: name) + investment = create(:budget_investment, :winner, heading: heading) + milestone = create(:budget_investment_milestone, investment: investment) + heading + end + + scenario 'City heading is displayed first' do + heading.destroy! + other_heading1 = create_heading_with_investment_with_milestone(group: group, name: 'Other 1') + city_heading = create_heading_with_investment_with_milestone(group: group, name: 'Toda la ciudad') + other_heading2 = create_heading_with_investment_with_milestone(group: group, name: 'Other 2') + + visit budget_path(budget) + click_link 'See results' + + expect(page).to have_link('Milestones') + + click_link 'Milestones' + + expect(page).to have_css('.budget-execution', count: 3) + expect(city_heading.name).to appear_before(other_heading1.name) + expect(city_heading.name).to appear_before(other_heading2.name) + end + end end From 375fbf775f30881a6bf2fb373802e9d96f94818b Mon Sep 17 00:00:00 2001 From: Marko Lovic Date: Mon, 23 Jul 2018 20:09:01 +0200 Subject: [PATCH 24/32] Order non-city headings by alphabetical order --- .../budgets/executions_controller.rb | 2 +- spec/features/budgets/executions_spec.rb | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/app/controllers/budgets/executions_controller.rb b/app/controllers/budgets/executions_controller.rb index 7828ca8ec..f0b3f5d57 100644 --- a/app/controllers/budgets/executions_controller.rb +++ b/app/controllers/budgets/executions_controller.rb @@ -11,7 +11,7 @@ module Budgets .includes(investments: :milestones) .joins(investments: :milestones) .distinct - .order(id: :asc) + .order(name: :asc) if params[:status].present? @headings = @headings.where(filter_investment_by_latest_milestone, params[:status]) diff --git a/spec/features/budgets/executions_spec.rb b/spec/features/budgets/executions_spec.rb index 5ac7f9cfd..e2e4d8061 100644 --- a/spec/features/budgets/executions_spec.rb +++ b/spec/features/budgets/executions_spec.rb @@ -207,5 +207,23 @@ feature 'Executions' do expect(city_heading.name).to appear_before(other_heading1.name) expect(city_heading.name).to appear_before(other_heading2.name) end + + scenario 'Non-city headings are displayed in alphabetical order' do + heading.destroy! + z_heading = create_heading_with_investment_with_milestone(group: group, name: 'Zzz') + a_heading = create_heading_with_investment_with_milestone(group: group, name: 'Aaa') + m_heading = create_heading_with_investment_with_milestone(group: group, name: 'Mmm') + + visit budget_path(budget) + click_link 'See results' + + expect(page).to have_link('Milestones') + + click_link 'Milestones' + + expect(page).to have_css('.budget-execution', count: 3) + expect(a_heading.name).to appear_before(m_heading.name) + expect(m_heading.name).to appear_before(z_heading.name) + end end end From 997db6710401c03a3560c6e3046504adc26366f3 Mon Sep 17 00:00:00 2001 From: Marko Lovic Date: Mon, 23 Jul 2018 20:31:41 +0200 Subject: [PATCH 25/32] Refactor how headings are ordered --- .../budgets/executions_controller.rb | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/app/controllers/budgets/executions_controller.rb b/app/controllers/budgets/executions_controller.rb index f0b3f5d57..5bc7705e0 100644 --- a/app/controllers/budgets/executions_controller.rb +++ b/app/controllers/budgets/executions_controller.rb @@ -17,7 +17,7 @@ module Budgets @headings = @headings.where(filter_investment_by_latest_milestone, params[:status]) end - @headings = reorder_with_city_heading_first(@headings) + @headings = reorder_alphabetically_with_city_heading_first(@headings) end private @@ -33,17 +33,15 @@ module Budgets SQL end - def reorder_with_city_heading_first(original_headings) - headings = original_headings.to_a.dup - - city_heading_index = headings.find_index do |heading| - heading.name == "Toda la ciudad" - end - - if city_heading_index - headings.insert(0, headings.delete_at(city_heading_index)) - else - headings + def reorder_alphabetically_with_city_heading_first(headings) + headings.sort do |a, b| + if a.name == 'Toda la ciudad' + -1 + elsif b.name == 'Toda la ciudad' + 1 + else + a.name <=> b.name + end end end end From 406bbb4cdbeb795195d22529a97e9e4aa2efd6b4 Mon Sep 17 00:00:00 2001 From: Marko Lovic Date: Mon, 23 Jul 2018 20:40:05 +0200 Subject: [PATCH 26/32] Avoid unnecessary navigation for faster specs --- spec/features/budgets/executions_spec.rb | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/spec/features/budgets/executions_spec.rb b/spec/features/budgets/executions_spec.rb index e2e4d8061..4a5ec8694 100644 --- a/spec/features/budgets/executions_spec.rb +++ b/spec/features/budgets/executions_spec.rb @@ -196,12 +196,7 @@ feature 'Executions' do city_heading = create_heading_with_investment_with_milestone(group: group, name: 'Toda la ciudad') other_heading2 = create_heading_with_investment_with_milestone(group: group, name: 'Other 2') - visit budget_path(budget) - click_link 'See results' - - expect(page).to have_link('Milestones') - - click_link 'Milestones' + visit budget_executions_path(budget) expect(page).to have_css('.budget-execution', count: 3) expect(city_heading.name).to appear_before(other_heading1.name) @@ -214,12 +209,7 @@ feature 'Executions' do a_heading = create_heading_with_investment_with_milestone(group: group, name: 'Aaa') m_heading = create_heading_with_investment_with_milestone(group: group, name: 'Mmm') - visit budget_path(budget) - click_link 'See results' - - expect(page).to have_link('Milestones') - - click_link 'Milestones' + visit budget_executions_path(budget) expect(page).to have_css('.budget-execution', count: 3) expect(a_heading.name).to appear_before(m_heading.name) From d089cc14a5a6ef2230612b794204f03b51147c33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mar=C3=ADa=20Checa?= Date: Tue, 24 Jul 2018 17:53:08 +0200 Subject: [PATCH 27/32] Add logic to handle budget investments with an execution process --- .../budgets/executions_controller.rb | 36 +++++---------- app/models/budget/investment/milestone.rb | 2 + .../budgets/executions/_investments.html.erb | 6 +-- app/views/budgets/executions/show.html.erb | 11 ++--- spec/features/budgets/executions_spec.rb | 44 ++++++++++++------- 5 files changed, 51 insertions(+), 48 deletions(-) diff --git a/app/controllers/budgets/executions_controller.rb b/app/controllers/budgets/executions_controller.rb index 5bc7705e0..9db722de4 100644 --- a/app/controllers/budgets/executions_controller.rb +++ b/app/controllers/budgets/executions_controller.rb @@ -7,14 +7,19 @@ module Budgets def show authorize! :read_executions, @budget @statuses = ::Budget::Investment::Status.all - @headings = @budget.headings - .includes(investments: :milestones) - .joins(investments: :milestones) - .distinct - .order(name: :asc) if params[:status].present? - @headings = @headings.where(filter_investment_by_latest_milestone, params[:status]) + @investments_by_heading = @budget.investments.winners + .joins(:milestones).includes(:milestones) + .select { |i| i.milestones.published.with_status + .order_by_publication_date.last + .status_id == params[:status].to_i } + .uniq + .group_by(&:heading) + else + @investments_by_heading = @budget.investments.winners + .joins(:milestones).includes(:milestones) + .distinct.group_by(&:heading) end @headings = reorder_alphabetically_with_city_heading_first(@headings) @@ -25,24 +30,5 @@ module Budgets def load_budget @budget = Budget.find_by(slug: params[:id]) || Budget.find_by(id: params[:id]) end - - def filter_investment_by_latest_milestone - <<-SQL - (SELECT status_id FROM budget_investment_milestones - WHERE investment_id = budget_investments.id ORDER BY publication_date DESC LIMIT 1) = ? - SQL - end - - def reorder_alphabetically_with_city_heading_first(headings) - headings.sort do |a, b| - if a.name == 'Toda la ciudad' - -1 - elsif b.name == 'Toda la ciudad' - 1 - else - a.name <=> b.name - end - end - end end end diff --git a/app/models/budget/investment/milestone.rb b/app/models/budget/investment/milestone.rb index c71516446..2421974da 100644 --- a/app/models/budget/investment/milestone.rb +++ b/app/models/budget/investment/milestone.rb @@ -18,6 +18,8 @@ class Budget validate :description_or_status_present? scope :order_by_publication_date, -> { order(publication_date: :asc) } + scope :published, -> { where("publication_date <= ?", Date.today) } + scope :with_status, -> { where("status_id IS NOT NULL") } def self.title_max_length 80 diff --git a/app/views/budgets/executions/_investments.html.erb b/app/views/budgets/executions/_investments.html.erb index 0808b354a..9a03dacb8 100644 --- a/app/views/budgets/executions/_investments.html.erb +++ b/app/views/budgets/executions/_investments.html.erb @@ -1,9 +1,9 @@ -<% @headings.each do |heading| %> +<% @investments_by_heading.each do |heading, investments| %>

- <%= heading.name %> + <%= heading.name %> (<%= investments.count %>)

- <% heading.investments.each do |investment| %> + <% investments.each do |investment| %>
<%= link_to budget_investment_path(@budget, investment, anchor: "tab-milestones"), data: { 'equalizer-watch': true } do %> diff --git a/app/views/budgets/executions/show.html.erb b/app/views/budgets/executions/show.html.erb index dc18d2d08..941e0d2d2 100644 --- a/app/views/budgets/executions/show.html.erb +++ b/app/views/budgets/executions/show.html.erb @@ -44,7 +44,7 @@ <%= t("budgets.executions.heading_selection_title") %>