Merge pull request #2296 from consul/feature/2278#budget_price_show_phase
New Budget's phase to publish investment prices
This commit is contained in:
@@ -3,8 +3,11 @@ class Budget < ActiveRecord::Base
|
|||||||
include Measurable
|
include Measurable
|
||||||
include Sluggable
|
include Sluggable
|
||||||
|
|
||||||
PHASES = %w(drafting accepting reviewing selecting valuating balloting
|
PHASES = %w(drafting accepting reviewing selecting valuating publishing_prices
|
||||||
reviewing_ballots finished).freeze
|
balloting reviewing_ballots finished).freeze
|
||||||
|
ON_HOLD_PHASES = %w(reviewing valuating publishing_prices reviewing_ballots).freeze
|
||||||
|
PUBLISHED_PRICES_PHASES = %w(publishing_prices balloting reviewing_ballots finished).freeze
|
||||||
|
|
||||||
CURRENCY_SYMBOLS = %w(€ $ £ ¥).freeze
|
CURRENCY_SYMBOLS = %w(€ $ £ ¥).freeze
|
||||||
|
|
||||||
validates :name, presence: true, uniqueness: true
|
validates :name, presence: true, uniqueness: true
|
||||||
@@ -19,12 +22,13 @@ class Budget < ActiveRecord::Base
|
|||||||
|
|
||||||
before_validation :sanitize_descriptions
|
before_validation :sanitize_descriptions
|
||||||
|
|
||||||
scope :on_hold, -> { where(phase: %w(reviewing valuating reviewing_ballots")) }
|
scope :on_hold, -> { where(phase: ON_HOLD_PHASES) }
|
||||||
scope :drafting, -> { where(phase: "drafting") }
|
scope :drafting, -> { where(phase: "drafting") }
|
||||||
scope :accepting, -> { where(phase: "accepting") }
|
scope :accepting, -> { where(phase: "accepting") }
|
||||||
scope :reviewing, -> { where(phase: "reviewing") }
|
scope :reviewing, -> { where(phase: "reviewing") }
|
||||||
scope :selecting, -> { where(phase: "selecting") }
|
scope :selecting, -> { where(phase: "selecting") }
|
||||||
scope :valuating, -> { where(phase: "valuating") }
|
scope :valuating, -> { where(phase: "valuating") }
|
||||||
|
scope :publishing_prices, -> { where(phase: "publishing_prices") }
|
||||||
scope :balloting, -> { where(phase: "balloting") }
|
scope :balloting, -> { where(phase: "balloting") }
|
||||||
scope :reviewing_ballots, -> { where(phase: "reviewing_ballots") }
|
scope :reviewing_ballots, -> { where(phase: "reviewing_ballots") }
|
||||||
scope :finished, -> { where(phase: "finished") }
|
scope :finished, -> { where(phase: "finished") }
|
||||||
@@ -63,6 +67,10 @@ class Budget < ActiveRecord::Base
|
|||||||
phase == "valuating"
|
phase == "valuating"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def publishing_prices?
|
||||||
|
phase == "publishing_prices"
|
||||||
|
end
|
||||||
|
|
||||||
def balloting?
|
def balloting?
|
||||||
phase == "balloting"
|
phase == "balloting"
|
||||||
end
|
end
|
||||||
@@ -75,6 +83,10 @@ class Budget < ActiveRecord::Base
|
|||||||
phase == "finished"
|
phase == "finished"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def published_prices?
|
||||||
|
PUBLISHED_PRICES_PHASES.include?(phase)
|
||||||
|
end
|
||||||
|
|
||||||
def balloting_process?
|
def balloting_process?
|
||||||
balloting? || reviewing_ballots?
|
balloting? || reviewing_ballots?
|
||||||
end
|
end
|
||||||
@@ -84,7 +96,7 @@ class Budget < ActiveRecord::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
def on_hold?
|
def on_hold?
|
||||||
reviewing? || valuating? || reviewing_ballots?
|
ON_HOLD_PHASES.include?(phase)
|
||||||
end
|
end
|
||||||
|
|
||||||
def current?
|
def current?
|
||||||
@@ -118,7 +130,7 @@ class Budget < ActiveRecord::Base
|
|||||||
case phase
|
case phase
|
||||||
when 'accepting', 'reviewing'
|
when 'accepting', 'reviewing'
|
||||||
%w{random}
|
%w{random}
|
||||||
when 'balloting', 'reviewing_ballots'
|
when 'publishing_prices', 'balloting', 'reviewing_ballots'
|
||||||
%w{random price}
|
%w{random price}
|
||||||
else
|
else
|
||||||
%w{random confidence_score}
|
%w{random confidence_score}
|
||||||
|
|||||||
@@ -240,15 +240,11 @@ class Budget
|
|||||||
end
|
end
|
||||||
|
|
||||||
def should_show_price?
|
def should_show_price?
|
||||||
feasible? &&
|
selected? && price.present? && budget.published_prices?
|
||||||
selected? &&
|
|
||||||
(budget.reviewing_ballots? || budget.finished?)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def should_show_price_info?
|
def should_show_price_explanation?
|
||||||
feasible? &&
|
should_show_price? && price_explanation.present?
|
||||||
price_explanation.present? &&
|
|
||||||
(budget.balloting? || budget.reviewing_ballots? || budget.finished?)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def formatted_price
|
def formatted_price
|
||||||
|
|||||||
@@ -71,7 +71,7 @@
|
|||||||
<p><%= investment.unfeasibility_explanation %></p>
|
<p><%= investment.unfeasibility_explanation %></p>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<% if investment.should_show_price_info? %>
|
<% if investment.should_show_price_explanation? %>
|
||||||
<h2><%= t('budgets.investments.show.price_explanation') %></h2>
|
<h2><%= t('budgets.investments.show.price_explanation') %></h2>
|
||||||
<p><%= investment.price_explanation %></p>
|
<p><%= investment.price_explanation %></p>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ en:
|
|||||||
reviewing: Reviewing projects
|
reviewing: Reviewing projects
|
||||||
selecting: Selecting projects
|
selecting: Selecting projects
|
||||||
valuating: Valuating projects
|
valuating: Valuating projects
|
||||||
|
publishing_prices: Publishing projects prices
|
||||||
balloting: Balloting projects
|
balloting: Balloting projects
|
||||||
reviewing_ballots: Reviewing Ballots
|
reviewing_ballots: Reviewing Ballots
|
||||||
finished: Finished budget
|
finished: Finished budget
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ es:
|
|||||||
reviewing: Revisión interna de proyectos
|
reviewing: Revisión interna de proyectos
|
||||||
selecting: Fase de apoyos
|
selecting: Fase de apoyos
|
||||||
valuating: Evaluación de proyectos
|
valuating: Evaluación de proyectos
|
||||||
|
publishing_prices: Publicación de precios
|
||||||
balloting: Votación final
|
balloting: Votación final
|
||||||
reviewing_ballots: Votación finalizada
|
reviewing_ballots: Votación finalizada
|
||||||
finished: Resultados
|
finished: Resultados
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
class AddPublishingPricesPhaseToBudget < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_column :budgets, :description_publishing_prices, :text
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 20180108182839) do
|
ActiveRecord::Schema.define(version: 20180109175851) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
@@ -202,6 +202,7 @@ ActiveRecord::Schema.define(version: 20180108182839) do
|
|||||||
t.text "description_finished"
|
t.text "description_finished"
|
||||||
t.string "slug"
|
t.string "slug"
|
||||||
t.text "description_drafting"
|
t.text "description_drafting"
|
||||||
|
t.text "description_publishing_prices"
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table "campaigns", force: :cascade do |t|
|
create_table "campaigns", force: :cascade do |t|
|
||||||
|
|||||||
@@ -228,6 +228,7 @@ FactoryBot.define do
|
|||||||
description_reviewing "This budget is reviewing"
|
description_reviewing "This budget is reviewing"
|
||||||
description_selecting "This budget is selecting"
|
description_selecting "This budget is selecting"
|
||||||
description_valuating "This budget is valuating"
|
description_valuating "This budget is valuating"
|
||||||
|
description_publishing_prices "This budget is publishing prices"
|
||||||
description_balloting "This budget is balloting"
|
description_balloting "This budget is balloting"
|
||||||
description_reviewing_ballots "This budget is reviewing ballots"
|
description_reviewing_ballots "This budget is reviewing ballots"
|
||||||
description_finished "This budget is finished"
|
description_finished "This budget is finished"
|
||||||
@@ -252,6 +253,10 @@ FactoryBot.define do
|
|||||||
phase 'valuating'
|
phase 'valuating'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
trait :publishing_prices do
|
||||||
|
phase 'publishing_prices'
|
||||||
|
end
|
||||||
|
|
||||||
trait :balloting do
|
trait :balloting do
|
||||||
phase 'balloting'
|
phase 'balloting'
|
||||||
end
|
end
|
||||||
@@ -313,7 +318,6 @@ FactoryBot.define do
|
|||||||
selected true
|
selected true
|
||||||
feasibility "feasible"
|
feasibility "feasible"
|
||||||
valuation_finished true
|
valuation_finished true
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
trait :winner do
|
trait :winner do
|
||||||
@@ -326,6 +330,12 @@ FactoryBot.define do
|
|||||||
incompatible true
|
incompatible true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
trait :selected_with_price do
|
||||||
|
selected
|
||||||
|
price 1000
|
||||||
|
price_explanation 'Because of reasons'
|
||||||
|
end
|
||||||
|
|
||||||
trait :unselected do
|
trait :unselected do
|
||||||
selected false
|
selected false
|
||||||
feasibility "feasible"
|
feasibility "feasible"
|
||||||
|
|||||||
@@ -418,6 +418,64 @@ feature 'Budget Investments' do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "Show Investment's price & cost explanation" do
|
||||||
|
|
||||||
|
let(:investment) { create(:budget_investment, :selected_with_price, heading: heading) }
|
||||||
|
|
||||||
|
context "When investment with price is selected" do
|
||||||
|
|
||||||
|
scenario "Price & explanation is shown when Budget is on published prices phase" do
|
||||||
|
Budget::PUBLISHED_PRICES_PHASES.each do |phase|
|
||||||
|
budget.update(phase: phase)
|
||||||
|
visit budget_investment_path(budget_id: budget.id, id: investment.id)
|
||||||
|
|
||||||
|
expect(page).to have_content(investment.formatted_price)
|
||||||
|
expect(page).to have_content(investment.price_explanation)
|
||||||
|
|
||||||
|
visit budget_investments_path(budget)
|
||||||
|
|
||||||
|
expect(page).to have_content(investment.formatted_price)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario "Price & explanation isn't shown when Budget is not on published prices phase" do
|
||||||
|
(Budget::PHASES - Budget::PUBLISHED_PRICES_PHASES).each do |phase|
|
||||||
|
budget.update(phase: phase)
|
||||||
|
visit budget_investment_path(budget_id: budget.id, id: investment.id)
|
||||||
|
|
||||||
|
expect(page).not_to have_content(investment.formatted_price)
|
||||||
|
expect(page).not_to have_content(investment.price_explanation)
|
||||||
|
|
||||||
|
visit budget_investments_path(budget)
|
||||||
|
|
||||||
|
expect(page).not_to have_content(investment.formatted_price)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "When investment with price is unselected" do
|
||||||
|
|
||||||
|
background do
|
||||||
|
investment.update(selected: false)
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario "Price & explanation isn't shown for any Budget's phase" do
|
||||||
|
Budget::PHASES.each do |phase|
|
||||||
|
budget.update(phase: phase)
|
||||||
|
visit budget_investment_path(budget_id: budget.id, id: investment.id)
|
||||||
|
|
||||||
|
expect(page).not_to have_content(investment.formatted_price)
|
||||||
|
expect(page).not_to have_content(investment.price_explanation)
|
||||||
|
|
||||||
|
visit budget_investments_path(budget)
|
||||||
|
|
||||||
|
expect(page).not_to have_content(investment.formatted_price)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
scenario 'Can access the community' do
|
scenario 'Can access the community' do
|
||||||
Setting['feature.community'] = true
|
Setting['feature.community'] = true
|
||||||
|
|
||||||
@@ -477,13 +535,6 @@ feature 'Budget Investments' do
|
|||||||
expect(page).not_to have_content(investment.price_explanation)
|
expect(page).not_to have_content(investment.price_explanation)
|
||||||
end
|
end
|
||||||
|
|
||||||
scenario "Budget in balloting phase" do
|
|
||||||
budget.update(phase: "balloting")
|
|
||||||
visit budget_investment_path(budget_id: budget.id, id: investment.id)
|
|
||||||
|
|
||||||
expect(page).to have_content("Price explanation")
|
|
||||||
expect(page).to have_content(investment.price_explanation)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
scenario "Show (unfeasible budget investment)" do
|
scenario "Show (unfeasible budget investment)" do
|
||||||
|
|||||||
@@ -193,37 +193,73 @@ describe Budget::Investment do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#should_show_price_info?" do
|
describe "#should_show_price?" do
|
||||||
it "returns true for feasibles if phase is balloting or later and price_explanation is present" do
|
let(:budget) { create(:budget, :publishing_prices) }
|
||||||
["balloting", "reviewing_ballots", "finished"].each do |phase|
|
let(:investment) do
|
||||||
budget = create(:budget, phase: phase)
|
create(:budget_investment, :selected, budget: budget)
|
||||||
investment = create(:budget_investment, :feasible, budget: budget, price_explanation: "price explanation")
|
end
|
||||||
|
|
||||||
expect(investment.should_show_price_info?).to eq(true)
|
it "returns true for selected investments which budget's phase is publishing_prices or later" do
|
||||||
|
Budget::PUBLISHED_PRICES_PHASES.each do |phase|
|
||||||
|
budget.update(phase: phase)
|
||||||
|
|
||||||
|
expect(investment.should_show_price?).to eq(true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns false in any other phase" do
|
it "returns false in any other phase" do
|
||||||
(Budget::PHASES - ["balloting", "reviewing_ballots", "finished"]).each do |phase|
|
(Budget::PHASES - Budget::PUBLISHED_PRICES_PHASES).each do |phase|
|
||||||
budget = create(:budget, phase: phase)
|
budget.update(phase: phase)
|
||||||
investment = create(:budget_investment, :feasible, budget: budget, price_explanation: "price explanation")
|
|
||||||
|
|
||||||
expect(investment.should_show_price_info?).to eq(false)
|
expect(investment.should_show_price?).to eq(false)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns false if investment is unfeasible" do
|
it "returns false if investment is not selected" do
|
||||||
budget = create(:budget, phase: "balloting")
|
investment.selected = false
|
||||||
investment = create(:budget_investment, :unfeasible, budget: budget, price_explanation: "price explanation")
|
|
||||||
|
|
||||||
expect(investment.should_show_price_info?).to eq(false)
|
expect(investment.should_show_price?).to eq(false)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns false if price_explanation is blank" do
|
it "returns false if price is not present" do
|
||||||
budget = create(:budget, phase: "balloting")
|
investment.price = nil
|
||||||
investment = create(:budget_investment, :unfeasible, budget: budget, price_explanation: "")
|
|
||||||
|
|
||||||
expect(investment.should_show_price_info?).to eq(false)
|
expect(investment.should_show_price?).to eq(false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#should_show_price_explanation?" do
|
||||||
|
let(:budget) { create(:budget, :publishing_prices) }
|
||||||
|
let(:investment) do
|
||||||
|
create(:budget_investment, :selected, budget: budget, price_explanation: "because of reasons")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns true for selected with price_explanation & budget in publishing_prices or later" do
|
||||||
|
Budget::PUBLISHED_PRICES_PHASES.each do |phase|
|
||||||
|
budget.update(phase: phase)
|
||||||
|
|
||||||
|
expect(investment.should_show_price_explanation?).to eq(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns false in any other phase" do
|
||||||
|
(Budget::PHASES - Budget::PUBLISHED_PRICES_PHASES).each do |phase|
|
||||||
|
budget.update(phase: phase)
|
||||||
|
|
||||||
|
expect(investment.should_show_price_explanation?).to eq(false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns false if investment is not selected" do
|
||||||
|
investment.selected = false
|
||||||
|
|
||||||
|
expect(investment.should_show_price_explanation?).to eq(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns false if price_explanation is not present" do
|
||||||
|
investment.price_explanation = ""
|
||||||
|
|
||||||
|
expect(investment.should_show_price_explanation?).to eq(false)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,9 @@ describe Budget do
|
|||||||
budget.phase = "valuating"
|
budget.phase = "valuating"
|
||||||
expect(budget).to be_valuating
|
expect(budget).to be_valuating
|
||||||
|
|
||||||
|
budget.phase = "publishing_prices"
|
||||||
|
expect(budget).to be_publishing_prices
|
||||||
|
|
||||||
budget.phase = "balloting"
|
budget.phase = "balloting"
|
||||||
expect(budget).to be_balloting
|
expect(budget).to be_balloting
|
||||||
|
|
||||||
@@ -81,6 +84,9 @@ describe Budget do
|
|||||||
budget.phase = "valuating"
|
budget.phase = "valuating"
|
||||||
expect(budget).to be_on_hold
|
expect(budget).to be_on_hold
|
||||||
|
|
||||||
|
budget.phase = "publishing_prices"
|
||||||
|
expect(budget).to be_on_hold
|
||||||
|
|
||||||
budget.phase = "balloting"
|
budget.phase = "balloting"
|
||||||
expect(budget).not_to be_on_hold
|
expect(budget).not_to be_on_hold
|
||||||
|
|
||||||
@@ -107,6 +113,9 @@ describe Budget do
|
|||||||
budget.phase = "valuating"
|
budget.phase = "valuating"
|
||||||
expect(budget).not_to be_balloting_or_later
|
expect(budget).not_to be_balloting_or_later
|
||||||
|
|
||||||
|
budget.phase = "publishing_prices"
|
||||||
|
expect(budget).not_to be_balloting_or_later
|
||||||
|
|
||||||
budget.phase = "balloting"
|
budget.phase = "balloting"
|
||||||
expect(budget).to be_balloting_or_later
|
expect(budget).to be_balloting_or_later
|
||||||
|
|
||||||
@@ -142,6 +151,8 @@ describe Budget do
|
|||||||
expect(budget.investments_orders).to eq(['random'])
|
expect(budget.investments_orders).to eq(['random'])
|
||||||
end
|
end
|
||||||
it "is random and price when ballotting and reviewing ballots" do
|
it "is random and price when ballotting and reviewing ballots" do
|
||||||
|
budget.phase = 'publishing_prices'
|
||||||
|
expect(budget.investments_orders).to eq(['random', 'price'])
|
||||||
budget.phase = 'balloting'
|
budget.phase = 'balloting'
|
||||||
expect(budget.investments_orders).to eq(['random', 'price'])
|
expect(budget.investments_orders).to eq(['random', 'price'])
|
||||||
budget.phase = 'reviewing_ballots'
|
budget.phase = 'reviewing_ballots'
|
||||||
|
|||||||
Reference in New Issue
Block a user