diff --git a/app/assets/stylesheets/admin.scss b/app/assets/stylesheets/admin.scss index 17ea18b9d..9c95f400f 100644 --- a/app/assets/stylesheets/admin.scss +++ b/app/assets/stylesheets/admin.scss @@ -1205,6 +1205,11 @@ table { .filter { display: inline-block; margin: 0 $line-height / 2; + + label { + font-weight: normal; + margin: 0; + } } .button { diff --git a/app/controllers/admin/budget_investments_controller.rb b/app/controllers/admin/budget_investments_controller.rb index 1a213c2f2..a451d67a5 100644 --- a/app/controllers/admin/budget_investments_controller.rb +++ b/app/controllers/admin/budget_investments_controller.rb @@ -4,10 +4,8 @@ class Admin::BudgetInvestmentsController < Admin::BaseController feature_flag :budgets - has_orders %w{oldest}, only: [:show, :edit] - has_filters(%w{all without_admin without_valuator under_valuation - valuation_finished winners}, - only: [:index, :toggle_selection]) + has_orders %w[oldest], only: [:show, :edit] + has_filters %w[all], only: [:index, :toggle_selection] before_action :load_budget before_action :load_investment, only: [:show, :edit, :update, :toggle_selection] diff --git a/app/controllers/admin/budgets_controller.rb b/app/controllers/admin/budgets_controller.rb index 252e48134..955da3f1d 100644 --- a/app/controllers/admin/budgets_controller.rb +++ b/app/controllers/admin/budgets_controller.rb @@ -23,7 +23,9 @@ class Admin::BudgetsController < Admin::BaseController def calculate_winners return unless @budget.balloting_process? @budget.headings.each { |heading| Budget::Result.new(@budget, heading).delay.calculate_winners } - redirect_to admin_budget_budget_investments_path(budget_id: @budget.id, filter: "winners"), + redirect_to admin_budget_budget_investments_path( + budget_id: @budget.id, + advanced_filters: ["winners"]), notice: I18n.t("admin.budgets.winners.calculated") end diff --git a/app/models/budget/investment.rb b/app/models/budget/investment.rb index 4dae6c3ac..b033d7404 100644 --- a/app/models/budget/investment.rb +++ b/app/models/budget/investment.rb @@ -117,7 +117,7 @@ class Budget results = Investment.by_budget(budget) results = results.where("cached_votes_up + physical_votes >= ?", - params[:min_total_supports]) if params[:min_total_supports].present? + params[:min_total_supports]) if params[:min_total_supports].present? results = results.where("cached_votes_up + physical_votes <= ?", params[:max_total_supports]) if params[:max_total_supports].present? results = results.where(group_id: params[:group_id]) if params[:group_id].present? @@ -134,12 +134,19 @@ class Budget end def self.advanced_filters(params, results) + results = results.without_admin if params[:advanced_filters].include?("without_admin") + results = results.without_valuator if params[:advanced_filters].include?("without_valuator") + results = results.under_valuation if params[:advanced_filters].include?("under_valuation") + results = results.valuation_finished if params[:advanced_filters].include?("valuation_finished") + results = results.winners if params[:advanced_filters].include?("winners") + ids = [] ids += results.valuation_finished_feasible.pluck(:id) if params[:advanced_filters].include?("feasible") ids += results.where(selected: true).pluck(:id) if params[:advanced_filters].include?("selected") ids += results.undecided.pluck(:id) if params[:advanced_filters].include?("undecided") ids += results.unfeasible.pluck(:id) if params[:advanced_filters].include?("unfeasible") - results.where("budget_investments.id IN (?)", ids) + results = results.where("budget_investments.id IN (?)", ids) if ids.any? + results end def self.order_filter(params) diff --git a/app/views/admin/budget_investments/_investments.html.erb b/app/views/admin/budget_investments/_investments.html.erb index 2c697f53b..55603bbcd 100644 --- a/app/views/admin/budget_investments/_investments.html.erb +++ b/app/views/admin/budget_investments/_investments.html.erb @@ -2,7 +2,7 @@ admin_budget_budget_investments_path(csv_params), class: "float-right small clear" %> -<% if params[:filter] == "winners" %> +<% if params[:advanced_filters].include?("winners") %> <% if display_calculate_winners_button?(@budget) %> <%= link_to calculate_winner_button_text(@budget), calculate_winners_admin_budget_path(@budget), diff --git a/app/views/admin/budget_investments/_search_form.html.erb b/app/views/admin/budget_investments/_search_form.html.erb index 77e177b71..301845a8b 100644 --- a/app/views/admin/budget_investments/_search_form.html.erb +++ b/app/views/admin/budget_investments/_search_form.html.erb @@ -11,10 +11,11 @@
- <% ["feasible", "selected", "undecided", "unfeasible"].each do |option| %> + <% %w[feasible selected undecided unfeasible without_admin without_valuator under_valuation + valuation_finished winners].each do |filter| %>
- <%= check_box_tag "advanced_filters[]", option, params[:advanced_filters].index(option), id: "advanced_filters_#{option}" %> - <%= t("admin.budget_investments.index.filters.#{option}") %> + <%= check_box_tag "advanced_filters[]", filter, params[:advanced_filters].index(filter), id: "advanced_filters_#{filter}" %> + <%= label_tag "advanced_filters[#{filter}]", t("admin.budget_investments.index.filters.#{filter}") %>
<% end %>
diff --git a/spec/factories/budgets.rb b/spec/factories/budgets.rb index 0b9130825..b53bd8b56 100644 --- a/spec/factories/budgets.rb +++ b/spec/factories/budgets.rb @@ -150,13 +150,17 @@ FactoryBot.define do valuation_finished true end - trait :hidden do - hidden_at { Time.current } - end + trait :hidden do + hidden_at { Time.current } + end - trait :with_ignored_flag do - ignored_flag_at { Time.current } - end + trait :with_ignored_flag do + ignored_flag_at { Time.current } + end + + trait :with_administrator do + administrator + end trait :flagged do after :create do |investment| diff --git a/spec/features/admin/budget_investments_spec.rb b/spec/features/admin/budget_investments_spec.rb index 48451e14f..bfc8e7881 100644 --- a/spec/features/admin/budget_investments_spec.rb +++ b/spec/features/admin/budget_investments_spec.rb @@ -251,12 +251,161 @@ feature "Admin budget investments" do expect(page).not_to have_link("Build a hospital") end + scenario "Filtering by without assigned admin", :js do + create(:budget_investment, + title: "Investment without admin", + budget: budget) + create(:budget_investment, + :with_administrator, + title: "Investment with admin", + budget: budget) + + visit admin_budget_budget_investments_path(budget_id: budget) + expect(page).to have_link("Investment without admin") + expect(page).to have_link("Investment with admin") + + click_link "Advanced filters" + check("Without assigned admin") + click_button "Filter" + + expect(page).to have_content("There is 1 investment") + expect(page).to have_link("Investment without admin") + expect(page).not_to have_link("Investment with admin") + + uncheck("Without assigned admin") + click_button "Filter" + + expect(page).to have_content("There are 2 investments") + expect(page).to have_link("Investment without admin") + expect(page).to have_link("Investment with admin") + end + + scenario "Filtering by without assigned valuator", :js do + user = create(:user) + valuator = create(:valuator, user: user) + create(:budget_investment, + title: "Investment without valuator", + budget: budget) + create(:budget_investment, + title: "Investment with valuator", + budget: budget, + valuators: [valuator]) + + visit admin_budget_budget_investments_path(budget_id: budget) + expect(page).to have_link("Investment without valuator") + expect(page).to have_link("Investment with valuator") + + click_link "Advanced filters" + check "Without assigned valuator" + click_button "Filter" + + expect(page).to have_content("There is 1 investment") + expect(page).to have_link("Investment without valuator") + expect(page).not_to have_link("Investment with valuator") + + uncheck "Without assigned valuator" + click_button "Filter" + + expect(page).to have_content("There are 2 investments") + expect(page).to have_link("Investment without valuator") + expect(page).to have_link("Investment with valuator") + end + + scenario "Filtering by under valuation", :js do + user = create(:user) + valuator = create(:valuator, user: user) + create(:budget_investment, + :with_administrator, + valuation_finished: false, + title: "Investment without valuation", + budget: budget, + valuators: [valuator]) + create(:budget_investment, + :with_administrator, + title: "Investment with valuation", + budget: budget) + + visit admin_budget_budget_investments_path(budget_id: budget) + expect(page).to have_link("Investment without valuation") + expect(page).to have_link("Investment with valuation") + + click_link "Advanced filters" + check "Under valuation" + click_button "Filter" + + expect(page).to have_content("There is 1 investment") + expect(page).to have_link("Investment without valuation") + expect(page).not_to have_link("Investment with valuation") + + uncheck "Under valuation" + click_button "Filter" + + expect(page).to have_content("There are 2 investments") + expect(page).to have_link("Investment without valuation") + expect(page).to have_link("Investment with valuation") + end + + scenario "Filtering by valuation finished", :js do + create(:budget_investment, + title: "Investment valuation open", + budget: budget) + create(:budget_investment, + :finished, + title: "Investment valuation finished", + budget: budget) + + visit admin_budget_budget_investments_path(budget_id: budget) + expect(page).to have_link("Investment valuation open") + expect(page).to have_link("Investment valuation finished") + + click_link "Advanced filters" + check "Valuation finished" + click_button "Filter" + + expect(page).to have_content("There is 1 investment") + expect(page).not_to have_link("Investment valuation open") + expect(page).to have_link("Investment valuation finished") + + uncheck "Valuation finished" + click_button "Filter" + + expect(page).to have_content("There are 2 investments") + expect(page).to have_link("Investment valuation open") + expect(page).to have_link("Investment valuation finished") + end + + scenario "Filtering by winners", :js do + create(:budget_investment, + :winner, + valuation_finished: true, + title: "Investment winner", + budget: budget) + create(:budget_investment, + title: "Investment without winner", + budget: budget) + + visit admin_budget_budget_investments_path(budget_id: budget) + expect(page).to have_link("Investment winner") + expect(page).to have_link("Investment without winner") + + click_link "Advanced filters" + check "Winners" + click_button "Filter" + + expect(page).to have_content("There is 1 investment") + expect(page).to have_link("Investment winner") + expect(page).not_to have_link("Investment without winner") + + uncheck "Winners" + click_button "Filter" + + expect(page).to have_content("There are 2 investments") + expect(page).to have_link("Investment winner") + expect(page).to have_link("Investment without winner") + end + scenario "Current filter is properly highlighted" do - filters_links = { "all" => "All", - "without_admin" => "Without assigned admin", - "without_valuator" => "Without assigned valuator", - "under_valuation" => "Under valuation", - "valuation_finished" => "Valuation finished" } + filters_links = { "all" => "All" } visit admin_budget_budget_investments_path(budget_id: budget.id) @@ -288,13 +437,15 @@ feature "Admin budget investments" do expect(page).to have_content("Evaluating...") expect(page).to have_content("With group") - visit admin_budget_budget_investments_path(budget_id: budget.id, filter: "without_admin") + visit admin_budget_budget_investments_path(budget_id: budget.id, + advanced_filters: ["without_admin"]) expect(page).to have_content("Evaluating...") expect(page).to have_content("With group") expect(page).not_to have_content("Assigned idea") - visit admin_budget_budget_investments_path(budget_id: budget.id, filter: "without_valuator") + visit admin_budget_budget_investments_path(budget_id: budget.id, + advanced_filters: ["without_valuator"]) expect(page).to have_content("Assigned idea") expect(page).not_to have_content("Evaluating...") @@ -309,17 +460,20 @@ feature "Admin budget investments" do valuating.valuators.push(create(:valuator)) valuated.valuators.push(create(:valuator)) - visit admin_budget_budget_investments_path(budget_id: budget.id, filter: "under_valuation") + query_params = {budget_id: budget.id, advanced_filters: ["under_valuation"]} + + visit admin_budget_budget_investments_path(query_params) expect(page).to have_content("Ongoing valuation") expect(page).not_to have_content("Old idea") - visit admin_budget_budget_investments_path(budget_id: budget.id, filter: "valuation_finished") + visit admin_budget_budget_investments_path(budget_id: budget.id, + advanced_filters: ["valuation_finished"]) expect(page).not_to have_content("Ongoing valuation") expect(page).to have_content("Old idea") - visit admin_budget_budget_investments_path(budget_id: budget.id, filter: "all") + visit admin_budget_budget_investments_path(budget_id: budget.id, advanced_filters: ["filter"]) expect(page).to have_content("Ongoing valuation") expect(page).to have_content("Old idea") end @@ -380,7 +534,10 @@ feature "Admin budget investments" do budget.update(phase: "reviewing_ballots") visit admin_budget_budget_investments_path(budget) - click_link "Winners" + + click_link "Advanced filters" + check "Winners" + click_button "Filter" expect(page).to have_link "Calculate Winner Investments" @@ -391,7 +548,9 @@ feature "Admin budget investments" do budget.update(phase: "accepting") visit admin_budget_budget_investments_path(budget) - click_link "Winners" + + check "Winners" + click_button "Filter" expect(page).not_to have_link "Calculate Winner Investments" expect(page).to have_content 'The budget has to stay on phase "Balloting projects", '\ @@ -530,7 +689,7 @@ feature "Admin budget investments" do click_link "Advanced filters" - page.check("advanced_filters_feasible") + check("Feasible") click_button "Filter" expect(page).to have_css(".budget_investment", count: 2) @@ -585,7 +744,7 @@ feature "Admin budget investments" do click_link "Advanced filters" - within("#advanced_filters") { check("advanced_filters_feasible") } + within("#advanced_filters") { check("Feasible") } click_button("Filter") expect(page).to have_css(".budget_investment", count: 2) @@ -1156,16 +1315,17 @@ feature "Admin budget investments" do scenario "Filtering by valuation and selection", :js do visit admin_budget_budget_investments_path(budget) - within("#filter-subnav") { click_link "Valuation finished" } + click_link "Advanced filters" + check "Valuation finished" + click_button "Filter" + expect(page).not_to have_content(unfeasible_bi.title) expect(page).not_to have_content(feasible_bi.title) expect(page).to have_content(feasible_vf_bi.title) expect(page).to have_content(selected_bi.title) expect(page).to have_content(winner_bi.title) - click_link "Advanced filters" - - within("#advanced_filters") { check("advanced_filters_feasible") } + within("#advanced_filters") { check("Feasible") } click_button("Filter") expect(page).not_to have_content(unfeasible_bi.title) @@ -1175,8 +1335,8 @@ feature "Admin budget investments" do expect(page).to have_content(winner_bi.title) within("#advanced_filters") do - check("advanced_filters_selected") - uncheck("advanced_filters_feasible") + check("Selected") + uncheck("Feasible") end click_button("Filter") @@ -1187,7 +1347,9 @@ feature "Admin budget investments" do expect(page).to have_content(selected_bi.title) expect(page).to have_content(winner_bi.title) - within("#filter-subnav") { click_link "Winners" } + check "Winners" + click_button "Filter" + expect(page).not_to have_content(unfeasible_bi.title) expect(page).not_to have_content(feasible_bi.title) expect(page).not_to have_content(feasible_vf_bi.title) @@ -1200,7 +1362,7 @@ feature "Admin budget investments" do click_link "Advanced filters" - within("#advanced_filters") { check("advanced_filters_undecided") } + within("#advanced_filters") { check("Undecided") } click_button("Filter") expect(page).to have_content(undecided_bi.title) @@ -1210,7 +1372,7 @@ feature "Admin budget investments" do expect(page).not_to have_content(unfeasible_bi.title) expect(page).not_to have_content(feasible_vf_bi.title) - within("#advanced_filters") { check("advanced_filters_unfeasible") } + within("#advanced_filters") { check("Unfeasible") } click_button("Filter") expect(page).to have_content(undecided_bi.title) @@ -1255,7 +1417,7 @@ feature "Admin budget investments" do click_link "Advanced filters" - within("#advanced_filters") { check("advanced_filters_selected") } + within("#advanced_filters") { check("Selected") } click_button("Filter") within("#budget_investment_#{feasible_vf_bi.id}") do @@ -1268,7 +1430,7 @@ feature "Admin budget investments" do visit admin_budget_budget_investments_path(budget) click_link "Advanced filters" - within("#advanced_filters") { check("advanced_filters_selected") } + within("#advanced_filters") { check("Selected") } click_button("Filter") expect(page).to have_content("There are 2 investments") @@ -1325,15 +1487,18 @@ feature "Admin budget investments" do investment2.update(administrator: admin) visit admin_budget_budget_investments_path(budget) - within("#filter-subnav") { click_link "Under valuation" } - expect(page).not_to have_link("Under valuation") + click_link "Advanced filters" + check "Under valuation" + click_button "Filter" within("#budget_investment_#{investment1.id}") do check "budget_investment_visible_to_valuators" end visit admin_budget_budget_investments_path(budget) - within("#filter-subnav") { click_link "Under valuation" } + click_link "Advanced filters" + check "Under valuation" + click_button "Filter" within("#budget_investment_#{investment1.id}") do expect(find("#budget_investment_visible_to_valuators")).to be_checked @@ -1371,15 +1536,20 @@ feature "Admin budget investments" do investment2.update(administrator: admin, visible_to_valuators: true) visit admin_budget_budget_investments_path(budget) - within("#filter-subnav") { click_link "Under valuation" } - expect(page).not_to have_link("Under valuation") + + click_link "Advanced filters" + check "Under valuation" + click_button "Filter" within("#budget_investment_#{investment1.id}") do uncheck "budget_investment_visible_to_valuators" end visit admin_budget_budget_investments_path(budget) - within("#filter-subnav") { click_link "Under valuation" } + + click_link "Advanced filters" + check "Under valuation" + click_button "Filter" within("#budget_investment_#{investment1.id}") do expect(find("#budget_investment_visible_to_valuators")).not_to be_checked @@ -1400,7 +1570,9 @@ feature "Admin budget investments" do expect(page).to have_css("#budget_investment_visible_to_valuators") - within("#filter-subnav") { click_link "Under valuation" } + click_link "Advanced filters" + check "Under valuation" + click_button "Filter" within("#budget_investment_#{investment1.id}") do valuating_checkbox = find("#budget_investment_visible_to_valuators") @@ -1478,7 +1650,9 @@ feature "Admin budget investments" do create(:budget_investment, :finished, budget: budget, title: "Finished Investment") visit admin_budget_budget_investments_path(budget) - within("#filter-subnav") { click_link "Valuation finished" } + click_link "Advanced filters" + check "Valuation finished" + click_button "Filter" click_link "Download current selection" diff --git a/spec/features/admin/budgets_spec.rb b/spec/features/admin/budgets_spec.rb index e24c344b2..38347b56e 100644 --- a/spec/features/admin/budgets_spec.rb +++ b/spec/features/admin/budgets_spec.rb @@ -281,7 +281,9 @@ feature "Admin budgets" do expect(page).not_to have_content "Calculate Winner Investments" visit admin_budget_budget_investments_path(budget) - click_link "Winners" + click_link "Advanced filters" + check "Winners" + click_button "Filter" expect(page).to have_content "Recalculate Winner Investments" expect(page).not_to have_content "Calculate Winner Investments" diff --git a/spec/models/budget/investment_spec.rb b/spec/models/budget/investment_spec.rb index 7c2b0a980..044dead99 100644 --- a/spec/models/budget/investment_spec.rb +++ b/spec/models/budget/investment_spec.rb @@ -1131,4 +1131,91 @@ describe Budget::Investment do end end + + describe "scoped_filter" do + let(:budget) { create(:budget, phase: "balloting") } + let(:investment) { create(:budget_investment, budget: budget) } + + describe "with without_admin filter" do + let(:params) { {advanced_filters: ["without_admin"], budget_id: budget.id} } + it "returns only investment without admin" do + create(:budget_investment, + :finished, + budget: budget) + create(:budget_investment, + :with_administrator, + budget: budget) + investment3 = create(:budget_investment, budget: budget) + expect(described_class.scoped_filter(params, "all")).to eq([investment3]) + expect(described_class.scoped_filter(params, "all").count).to eq(1) + end + end + + describe "with without_valuator filter" do + let(:params) { {advanced_filters: ["without_valuator"], budget_id: budget.id} } + it "returns only investment without valuator" do + create(:budget_investment, + :finished, + budget: budget) + investment2 = create(:budget_investment, + :with_administrator, + budget: budget) + investment3 = create(:budget_investment, + budget: budget) + expect(described_class.scoped_filter(params, "all")) + .to contain_exactly(investment2, investment3) + expect(described_class.scoped_filter(params, "all").count) + .to eq(2) + end + end + + describe "with under_valuation filter" do + let(:params) { {advanced_filters: ["under_valuation"], budget_id: budget.id} } + it "returns only investment under valuation" do + valuator1 = create(:valuator) + investment1 = create(:budget_investment, + :with_administrator, + valuation_finished: false, + budget: budget) + investment1.valuators << valuator1 + create(:budget_investment, :with_administrator, budget: budget) + create(:budget_investment, budget: budget) + + expect(described_class.scoped_filter(params, "all")).to eq([investment1]) + expect(described_class.scoped_filter(params, "all").count).to eq(1) + end + end + + describe "with valuation_finished filter" do + let(:params) { {advanced_filters: ["valuation_finished"], budget_id: budget.id} } + it "returns only investment with valuation finished" do + investment1 = create(:budget_investment, + :selected, + budget: budget) + create(:budget_investment, + :with_administrator, + budget: budget) + create(:budget_investment, + budget: budget) + expect(described_class.scoped_filter(params, "all")).to eq([investment1]) + expect(described_class.scoped_filter(params, "all").count).to eq(1) + end + end + + describe "with winners filter" do + let(:params) { {advanced_filters: ["winners"], budget_id: budget.id} } + it "returns only investment winners" do + investment1 = create(:budget_investment, + :winner, + valuation_finished: true, + budget: budget) + create(:budget_investment, + :with_administrator, + budget: budget) + create(:budget_investment, budget: budget) + expect(described_class.scoped_filter(params, "all")).to eq([investment1]) + expect(described_class.scoped_filter(params, "all").count).to eq(1) + end + end + end end