diff --git a/app/assets/stylesheets/participation.scss b/app/assets/stylesheets/participation.scss
index ff7a212ee..923d3f69c 100644
--- a/app/assets/stylesheets/participation.scss
+++ b/app/assets/stylesheets/participation.scss
@@ -627,6 +627,15 @@
}
}
+.milestone-status {
+ background: $budget;
+ border-radius: rem-calc(4);
+ color: #fff;
+ display: inline-block;
+ margin-top: $line-height / 6;
+ padding: $line-height / 4 $line-height / 2;
+}
+
.show-actions-menu {
[class^="icon-"] {
diff --git a/app/controllers/admin/budget_investment_milestones_controller.rb b/app/controllers/admin/budget_investment_milestones_controller.rb
index d2fdf5700..d54dc0174 100644
--- a/app/controllers/admin/budget_investment_milestones_controller.rb
+++ b/app/controllers/admin/budget_investment_milestones_controller.rb
@@ -3,6 +3,7 @@ class Admin::BudgetInvestmentMilestonesController < Admin::BaseController
before_action :load_budget_investment, only: [:index, :new, :create, :edit, :update, :destroy]
before_action :load_budget_investment_milestone, only: [:edit, :update, :destroy]
+ before_action :load_statuses, only: [:index, :new, :create, :edit, :update]
def index
end
@@ -45,7 +46,7 @@ class Admin::BudgetInvestmentMilestonesController < Admin::BaseController
def milestone_params
image_attributes = [:id, :title, :attachment, :cached_attachment, :user_id, :_destroy]
documents_attributes = [:id, :title, :attachment, :cached_attachment, :user_id, :_destroy]
- attributes = [:title, :description, :publication_date, :budget_investment_id,
+ attributes = [:title, :description, :publication_date, :budget_investment_id, :status_id,
image_attributes: image_attributes, documents_attributes: documents_attributes]
params.require(:budget_investment_milestone).permit(*attributes, translation_params(params[:budget_investment_milestone]))
@@ -71,4 +72,8 @@ class Admin::BudgetInvestmentMilestonesController < Admin::BaseController
get_milestone
end
+ def load_statuses
+ @statuses = Budget::Investment::Status.all
+ end
+
end
diff --git a/app/models/budget/investment/milestone.rb b/app/models/budget/investment/milestone.rb
index 3f8ba4f3a..b00744138 100644
--- a/app/models/budget/investment/milestone.rb
+++ b/app/models/budget/investment/milestone.rb
@@ -11,11 +11,12 @@ class Budget
globalize_accessors locales: [:en, :es, :fr, :nl, :val, :pt_br]
belongs_to :investment
+ belongs_to :status, class_name: 'Budget::Investment::Status'
validates :title, presence: true
- validates :description, presence: true
validates :investment, presence: true
validates :publication_date, presence: true
+ validate :description_or_status_present?
scope :order_by_publication_date, -> { order(publication_date: :asc) }
@@ -23,6 +24,11 @@ class Budget
80
end
+ def description_or_status_present?
+ unless description.present? || status_id.present?
+ errors.add(:description)
+ end
+ end
end
end
end
diff --git a/app/views/admin/budget_investment_milestones/_form.html.erb b/app/views/admin/budget_investment_milestones/_form.html.erb
index 6643c7317..4e7017d75 100644
--- a/app/views/admin/budget_investment_milestones/_form.html.erb
+++ b/app/views/admin/budget_investment_milestones/_form.html.erb
@@ -5,6 +5,15 @@
<%= f.hidden_field :title, value: l(Time.current, format: :datetime),
maxlength: Budget::Investment::Milestone.title_max_length %>
+
+ <%= f.select :status_id,
+ @statuses.collect { |s| [s.name, s.id] },
+ { include_blank: @statuses.any? ? '' : t('admin.milestones.form.no_statuses_defined') },
+ { disabled: @statuses.blank? } %>
+ <%= link_to t('admin.milestones.form.admin_statuses'),
+ admin_budget_investment_statuses_path %>
+
+
<%= f.label :description, t("admin.milestones.new.description") %>
<% @milestone.globalize_locales.each do |locale| %>
<%= hidden_field_tag "delete_translations[#{locale}]", 0 %>
diff --git a/app/views/admin/budget_investments/_milestones.html.erb b/app/views/admin/budget_investments/_milestones.html.erb
index 75d4c65a1..757fb97e4 100644
--- a/app/views/admin/budget_investments/_milestones.html.erb
+++ b/app/views/admin/budget_investments/_milestones.html.erb
@@ -6,6 +6,7 @@
<%= t("admin.milestones.index.table_title") %> |
<%= t("admin.milestones.index.table_description") %> |
<%= t("admin.milestones.index.table_publication_date") %> |
+ <%= t("admin.milestones.index.table_status") %> |
<%= t("admin.milestones.index.image") %> |
<%= t("admin.milestones.index.documents") %> |
<%= t("admin.milestones.index.table_actions") %> |
@@ -25,6 +26,9 @@
<%= l(milestone.publication_date.to_date) if milestone.publication_date.present? %>
|
+
+ <%= milestone.status.present? ? milestone.status.name : '' %>
+ |
<%= link_to t("admin.milestones.index.show_image"),
milestone.image_url(:large),
diff --git a/app/views/budgets/investments/milestones/_milestone.html.erb b/app/views/budgets/investments/milestones/_milestone.html.erb
index 774819d0c..79c8c05a0 100644
--- a/app/views/budgets/investments/milestones/_milestone.html.erb
+++ b/app/views/budgets/investments/milestones/_milestone.html.erb
@@ -10,6 +10,18 @@
<% end %>
+ <% if milestone.status.present? %>
+
+
+ <%= t("budgets.investments.show.milestone_status_changed") %>
+
+
+
+ <%= milestone.status.name %>
+
+
+ <% end %>
+
<%= image_tag(milestone.image_url(:large), { id: "image_#{milestone.id}", alt: milestone.image.title, class: "margin" }) if milestone.image.present? %>
<% globalize(neutral_locale(locale)) do %>
diff --git a/config/locales/en/activerecord.yml b/config/locales/en/activerecord.yml
index c7a69a8aa..7ea038a92 100644
--- a/config/locales/en/activerecord.yml
+++ b/config/locales/en/activerecord.yml
@@ -126,8 +126,9 @@ en:
image: "Proposal descriptive image"
image_title: "Image title"
budget/investment/milestone:
+ status_id: "Current investment status (optional)"
title: "Title"
- description: "Description"
+ description: "Description (optional if there's an status assigned)"
publication_date: "Publication date"
budget/investment/status:
name: "Name"
diff --git a/config/locales/en/admin.yml b/config/locales/en/admin.yml
index 2a21a1621..965278bb9 100644
--- a/config/locales/en/admin.yml
+++ b/config/locales/en/admin.yml
@@ -251,6 +251,7 @@ en:
table_title: "Title"
table_description: "Description"
table_publication_date: "Publication date"
+ table_status: Status
table_actions: "Actions"
delete: "Delete milestone"
no_milestones: "Don't have defined milestones"
@@ -260,6 +261,8 @@ en:
form:
add_language: Add language
remove_language: Remove language
+ admin_statuses: Admin investment statuses
+ no_statuses_defined: There are no defined investment statuses yet
new:
creating: Create milestone
date: Date
diff --git a/config/locales/en/budgets.yml b/config/locales/en/budgets.yml
index f43042052..ffd2a50cd 100644
--- a/config/locales/en/budgets.yml
+++ b/config/locales/en/budgets.yml
@@ -124,6 +124,7 @@ en:
milestones_tab: Milestones
no_milestones: Don't have defined milestones
milestone_publication_date: "Published %{publication_date}"
+ milestone_status_changed: Investment status changed to
author: Author
project_unfeasible_html: 'This investment project has been marked as not feasible and will not go to balloting phase.'
project_not_selected_html: 'This investment project has not been selected for balloting phase.'
diff --git a/config/locales/es/activerecord.yml b/config/locales/es/activerecord.yml
index db6d7a42c..3b137d67b 100644
--- a/config/locales/es/activerecord.yml
+++ b/config/locales/es/activerecord.yml
@@ -126,8 +126,9 @@ es:
image: "Imagen descriptiva del proyecto de gasto"
image_title: "Título de la imagen"
budget/investment/milestone:
+ status_id: "Estado actual del proyecto (opcional)"
title: "Título"
- description: "Descripción"
+ description: "Descripción (opcional si se ha asignado un estado de proyecto)"
publication_date: "Fecha de publicación"
budget/investment/status:
name: "Nombre"
diff --git a/config/locales/es/admin.yml b/config/locales/es/admin.yml
index 57c1a6f90..141360e98 100644
--- a/config/locales/es/admin.yml
+++ b/config/locales/es/admin.yml
@@ -251,6 +251,7 @@ es:
table_title: "Título"
table_description: "Descripción"
table_publication_date: "Fecha de publicación"
+ table_status: Estado
table_actions: "Acciones"
delete: "Eliminar hito"
no_milestones: "No hay hitos definidos"
@@ -260,6 +261,8 @@ es:
form:
add_language: Añadir idioma
remove_language: Eliminar idioma
+ admin_statuses: Gestionar estados de proyectos
+ no_statuses_defined: No hay estados definidos
new:
creating: Crear hito
date: Fecha
diff --git a/config/locales/es/budgets.yml b/config/locales/es/budgets.yml
index 974d9b09e..9ca162cf1 100644
--- a/config/locales/es/budgets.yml
+++ b/config/locales/es/budgets.yml
@@ -124,6 +124,7 @@ es:
milestones_tab: Seguimiento
no_milestones: No hay hitos definidos
milestone_publication_date: "Publicado el %{publication_date}"
+ milestone_status_changed: El proyecto ha cambiado al estado
author: Autor
project_unfeasible_html: 'Este proyecto de inversión ha sido marcado como inviable y no pasará a la fase de votación.'
project_not_selected_html: 'Este proyecto de inversión no ha sido seleccionado para la fase de votación.'
diff --git a/db/migrate/20180321180149_add_status_to_milestones.rb b/db/migrate/20180321180149_add_status_to_milestones.rb
new file mode 100644
index 000000000..527d87181
--- /dev/null
+++ b/db/migrate/20180321180149_add_status_to_milestones.rb
@@ -0,0 +1,8 @@
+class AddStatusToMilestones < ActiveRecord::Migration
+ disable_ddl_transaction!
+
+ def change
+ add_column :budget_investment_milestones, :status_id, :integer
+ add_index :budget_investment_milestones, :status_id, algorithm: :concurrently
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index e0a25c219..d1408273d 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -137,8 +137,11 @@ ActiveRecord::Schema.define(version: 20180519132610) do
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.datetime "publication_date"
+ t.integer "status_id"
end
+ add_index "budget_investment_milestones", ["status_id"], name: "index_budget_investment_milestones_on_status_id", using: :btree
+
create_table "budget_investment_statuses", force: :cascade do |t|
t.string "name"
t.text "description"
diff --git a/spec/factories.rb b/spec/factories.rb
index 32670b63f..3aeaef9e2 100644
--- a/spec/factories.rb
+++ b/spec/factories.rb
@@ -411,6 +411,7 @@ FactoryBot.define do
factory :budget_investment_milestone, class: 'Budget::Investment::Milestone' do
association :investment, factory: :budget_investment
+ association :status, factory: :budget_investment_status
sequence(:title) { |n| "Budget investment milestone #{n} title" }
description 'Milestone description'
publication_date Date.current
diff --git a/spec/features/admin/budget_investment_milestones_spec.rb b/spec/features/admin/budget_investment_milestones_spec.rb
index 81b9be430..a4272432d 100644
--- a/spec/features/admin/budget_investment_milestones_spec.rb
+++ b/spec/features/admin/budget_investment_milestones_spec.rb
@@ -21,6 +21,7 @@ feature 'Admin budget investment milestones' do
expect(page).to have_content(milestone.title)
expect(page).to have_content(milestone.id)
expect(page).to have_content(milestone.publication_date.to_date)
+ expect(page).to have_content(milestone.status.name)
expect(page).to have_link 'Show image'
expect(page).to have_link document.title
end
@@ -35,10 +36,12 @@ feature 'Admin budget investment milestones' do
context "New" do
scenario "Add milestone" do
+ status = create(:budget_investment_status)
visit admin_budget_budget_investment_path(@investment.budget, @investment)
click_link 'Create new milestone'
+ select status.name, from: 'budget_investment_milestone_status_id'
fill_in 'budget_investment_milestone_description_en', with: 'New description milestone'
fill_in 'budget_investment_milestone_publication_date', with: Date.current
@@ -46,6 +49,14 @@ feature 'Admin budget investment milestones' do
expect(page).to have_content 'New description milestone'
expect(page).to have_content Date.current
+ expect(page).to have_content status.name
+ end
+
+ scenario "Status select is disabled if there are no statuses available" do
+ visit admin_budget_budget_investment_path(@investment.budget, @investment)
+
+ click_link 'Create new milestone'
+ expect(find("#budget_investment_milestone_status_id").disabled?).to be true
end
scenario "Show validation errors on milestone form" do
diff --git a/spec/features/budgets/investments_spec.rb b/spec/features/budgets/investments_spec.rb
index 1ad7a82e9..51445bccc 100644
--- a/spec/features/budgets/investments_spec.rb
+++ b/spec/features/budgets/investments_spec.rb
@@ -1017,6 +1017,7 @@ feature 'Budget Investments' do
expect(page.find("#image_#{first_milestone.id}")['alt']).to have_content(image.title)
expect(page).to have_link(document.title)
expect(page).to have_link("https://consul.dev")
+ expect(page).to have_content(first_milestone.status.name)
end
select('Español', from: 'locale-switcher')
diff --git a/spec/models/budget/investment/milestone_spec.rb b/spec/models/budget/investment/milestone_spec.rb
index b019e8a40..ad844865d 100644
--- a/spec/models/budget/investment/milestone_spec.rb
+++ b/spec/models/budget/investment/milestone_spec.rb
@@ -14,15 +14,59 @@ describe Budget::Investment::Milestone do
expect(milestone).not_to be_valid
end
- it "is not valid without a description" do
+ it "is not valid without a description if status is empty" do
+ milestone.status = nil
milestone.description = nil
expect(milestone).not_to be_valid
end
+ it "is valid without a description if status is present" do
+ milestone.description = nil
+ expect(milestone).to be_valid
+ end
+
it "is not valid without an investment" do
milestone.investment_id = nil
expect(milestone).not_to be_valid
end
+
+ it "is not valid if description and status are not present" do
+ milestone.description = nil
+ milestone.status_id = nil
+ expect(milestone).not_to be_valid
+ end
+
+ it "is valid without status if description is present" do
+ milestone.status_id = nil
+ expect(milestone).to be_valid
+ end
+
+ it "is valid without description if status is present" do
+ milestone.description = nil
+ expect(milestone).to be_valid
+ end
+ end
+
+ describe "#description_or_status_present?" do
+ let(:milestone) { build(:budget_investment_milestone) }
+
+ it "is not valid when status is removed and there's no description" do
+ milestone.update(description: nil)
+ expect(milestone.update(status_id: nil)).to be false
+ end
+
+ it "is not valid when description is removed and there's no status" do
+ milestone.update(status_id: nil)
+ expect(milestone.update(description: nil)).to be false
+ end
+
+ it "is valid when description is removed and there is a status" do
+ expect(milestone.update(description: nil)).to be true
+ end
+
+ it "is valid when status is removed and there is a description" do
+ expect(milestone.update(status_id: nil)).to be true
+ end
end
end
|