diff --git a/app/assets/stylesheets/admin.scss b/app/assets/stylesheets/admin.scss
index cd8241fca..196d0be17 100644
--- a/app/assets/stylesheets/admin.scss
+++ b/app/assets/stylesheets/admin.scss
@@ -36,12 +36,21 @@ body.admin {
input[type="text"], textarea {
width: 100%;
}
+
+ .input-group input[type="text"] {
+ border-radius: 0;
+ margin-bottom: 0 !important;
+ }
}
table {
th {
text-align: left;
+
+ &.with-button {
+ line-height: $line-height*2;
+ }
}
tr {
diff --git a/app/controllers/admin/budget_groups_controller.rb b/app/controllers/admin/budget_groups_controller.rb
new file mode 100644
index 000000000..18f5a6b12
--- /dev/null
+++ b/app/controllers/admin/budget_groups_controller.rb
@@ -0,0 +1,15 @@
+class Admin::BudgetGroupsController < Admin::BaseController
+
+ def create
+ @budget = Budget.find params[:budget_id]
+ @budget.groups.create(budget_group_params)
+ @groups = @budget.groups.includes(:headings)
+ end
+
+ private
+
+ def budget_group_params
+ params.require(:budget_group).permit(:name)
+ end
+
+end
\ No newline at end of file
diff --git a/app/controllers/admin/budget_headings_controller.rb b/app/controllers/admin/budget_headings_controller.rb
new file mode 100644
index 000000000..3c8ccafa0
--- /dev/null
+++ b/app/controllers/admin/budget_headings_controller.rb
@@ -0,0 +1,16 @@
+class Admin::BudgetHeadingsController < Admin::BaseController
+
+ def create
+ @budget = Budget.find params[:budget_id]
+ @budget_group = @budget.groups.find params[:budget_group_id]
+ @budget_group.headings.create(budget_heading_params)
+ @headings = @budget_group.headings
+ end
+
+ private
+
+ def budget_heading_params
+ params.require(:budget_heading).permit(:name, :price, :geozone_id)
+ end
+
+end
\ No newline at end of file
diff --git a/app/controllers/admin/budgets_controller.rb b/app/controllers/admin/budgets_controller.rb
new file mode 100644
index 000000000..144b43a7f
--- /dev/null
+++ b/app/controllers/admin/budgets_controller.rb
@@ -0,0 +1,34 @@
+class Admin::BudgetsController < Admin::BaseController
+
+ has_filters %w{open finished}, only: :index
+
+ load_and_authorize_resource
+
+ def index
+ @budgets = Budget.send(@current_filter).order(created_at: :desc).page(params[:page])
+ end
+
+ def show
+ @budget = Budget.includes(groups: :headings).find(params[:id])
+ end
+
+ def new
+ @budget = Budget.new
+ end
+
+ def create
+ @budget = Budget.new(budget_params)
+ if @budget.save
+ redirect_to admin_budget_path(@budget), notice: t('admin.budgets.create.notice')
+ else
+ render :new
+ end
+ end
+
+ private
+
+ def budget_params
+ params.require(:budget).permit(:name, :description, :phase, :currency_symbol)
+ end
+
+end
diff --git a/app/helpers/budgets_helper.rb b/app/helpers/budgets_helper.rb
new file mode 100644
index 000000000..d281ef182
--- /dev/null
+++ b/app/helpers/budgets_helper.rb
@@ -0,0 +1,11 @@
+module BudgetsHelper
+
+ def budget_phases_select_options
+ Budget::VALID_PHASES.map { |ph| [ t("budget.phase.#{ph}"), ph ] }
+ end
+
+ def budget_currency_symbol_select_options
+ Budget::CURRENCY_SYMBOLS.map { |cs| [ cs, cs ] }
+ end
+
+end
\ No newline at end of file
diff --git a/app/helpers/geozones_helper.rb b/app/helpers/geozones_helper.rb
index bfc5f9105..ce03e0579 100644
--- a/app/helpers/geozones_helper.rb
+++ b/app/helpers/geozones_helper.rb
@@ -8,4 +8,9 @@ module GeozonesHelper
Geozone.all.order(name: :asc).collect { |g| [ g.name, g.id ] }
end
+ def geozone_name_from_id(g_id)
+ @all_geozones ||= Geozone.all.collect{ |g| [ g.id, g.name ] }.to_h
+ @all_geozones[g_id] || t("geozones.none")
+ end
+
end
diff --git a/app/models/abilities/administrator.rb b/app/models/abilities/administrator.rb
index 42e4ecbd3..f3f0b8f9b 100644
--- a/app/models/abilities/administrator.rb
+++ b/app/models/abilities/administrator.rb
@@ -42,7 +42,9 @@ module Abilities
can [:read, :update, :valuate, :destroy, :summary], SpendingProposal
- can [:create, :update], Budget
+ can [:index, :read, :new, :create, :update, :destroy], Budget
+ can [:read, :create, :update, :destroy], Budget::Group
+ can [:read, :create, :update, :destroy], Budget::Heading
can [:hide, :update], Budget::Investment
can :valuate, Budget::Investment, budget: { valuating: true }
can :create, Budget::ValuatorAssignment
diff --git a/app/models/budget.rb b/app/models/budget.rb
index ea22a4615..18f30ba7c 100644
--- a/app/models/budget.rb
+++ b/app/models/budget.rb
@@ -1,7 +1,9 @@
class Budget < ActiveRecord::Base
VALID_PHASES = %W{on_hold accepting selecting balloting finished}
+ CURRENCY_SYMBOLS = %W{€ $ £ ¥}
+ validates :name, presence: true
validates :phase, inclusion: { in: VALID_PHASES }
has_many :investments, dependent: :destroy
@@ -10,6 +12,9 @@ class Budget < ActiveRecord::Base
has_many :headings, through: :groups
has_many :investments, through: :headings
+ scope :open, -> { where.not(phase: "finished") }
+ scope :finished, -> { where(phase: "finished") }
+
def on_hold?
phase == "on_hold"
end
diff --git a/app/views/admin/_menu.html.erb b/app/views/admin/_menu.html.erb
index 7ea48b2c6..d1feaeb1e 100644
--- a/app/views/admin/_menu.html.erb
+++ b/app/views/admin/_menu.html.erb
@@ -35,6 +35,14 @@
<% end %>
+ <%# if feature?(:budgets) %>
+
>
+ <%= link_to admin_budgets_path do %>
+ <%= t("admin.menu.budgets") %>
+ <% end %>
+
+ <%# end %>
+
>
<%= link_to admin_banners_path do %>
<%= t("admin.menu.banner") %>
diff --git a/app/views/admin/budget_groups/create.js.erb b/app/views/admin/budget_groups/create.js.erb
new file mode 100644
index 000000000..cb926a7c6
--- /dev/null
+++ b/app/views/admin/budget_groups/create.js.erb
@@ -0,0 +1,2 @@
+$("#<%= dom_id(@budget) %>_groups").html('<%= j render("admin/budgets/groups", groups: @groups) %>');
+App.Forms.toggleLink();
\ No newline at end of file
diff --git a/app/views/admin/budget_headings/create.js.erb b/app/views/admin/budget_headings/create.js.erb
new file mode 100644
index 000000000..5d8eefb2d
--- /dev/null
+++ b/app/views/admin/budget_headings/create.js.erb
@@ -0,0 +1,2 @@
+$("#<%= dom_id(@budget_group) %>").html('<%= j render("admin/budgets/group", group: @budget_group, headings: @headings) %>');
+App.Forms.toggleLink();
\ No newline at end of file
diff --git a/app/views/admin/budgets/_group.html.erb b/app/views/admin/budgets/_group.html.erb
new file mode 100644
index 000000000..3660fa0c1
--- /dev/null
+++ b/app/views/admin/budgets/_group.html.erb
@@ -0,0 +1,76 @@
+
+
+
+
+
+ <%= group.name %>
+ <%= link_to t("admin.budgets.form.add_heading"), "#", class: "button float-right js-toggle-link", data: { "toggle-selector" => "#group-#{group.id}-new-heading-form" } %>
+
+
+
+ <% if headings.blank? %>
+
+
+
+
+ <%= t("admin.budgets.form.no_heading") %>
+
+
+
+ <% else %>
+
+ <%= t("admin.budgets.form.table_heading") %>
+ <%= t("admin.budgets.form.table_amount") %>
+ <%= t("admin.budgets.form.table_geozone") %>
+
+
+
+ <% end %>
+
+
+
+
+ <%= form_for [:admin, @budget, group, Budget::Heading.new], remote: true do |f| %>
+ <%= t("admin.budgets.form.heading") %>
+ <%= f.text_field :name,
+ label: false,
+ maxlength: 50,
+ placeholder: t("admin.budgets.form.heading") %>
+
+
+
+ <%= t("admin.budgets.form.amount") %>
+ <%= f.text_field :price,
+ label: false,
+ maxlength: 8,
+ placeholder: t("admin.budgets.form.amount") %>
+
+
+ <%= t("admin.budgets.form.geozone") %>
+ <%= f.select :geozone_id, geozone_select_options, {include_blank: t("geozones.none"), label: false} %>
+
+
+
+ <%= f.submit t("admin.budgets.form.save_heading"), class: "button success" %>
+ <% end %>
+
+
+
+
+ <% headings.each do |heading| %>
+
+
+ <%= heading.name %>
+
+
+ <%= heading.price %>
+
+
+ <%= geozone_name_from_id heading.geozone_id %>
+
+
+ <% end %>
+
+
+
+
\ No newline at end of file
diff --git a/app/views/admin/budgets/_groups.html.erb b/app/views/admin/budgets/_groups.html.erb
new file mode 100644
index 000000000..ba785ee0c
--- /dev/null
+++ b/app/views/admin/budgets/_groups.html.erb
@@ -0,0 +1,34 @@
+
+
<%= t('admin.budgets.show.groups') %>
+ <% if groups.blank? %>
+
+ <%= t("admin.budgets.form.no_groups") %>
+ <%= link_to t("admin.budgets.form.add_group"), "#",
+ class: "js-toggle-link",
+ data: { "toggle-selector" => "#new-group-form" } %>
+
+ <% else %>
+ <%= link_to t("admin.budgets.form.add_group"), "#", class: "button float-right js-toggle-link", data: { "toggle-selector" => "#new-group-form" } %>
+ <% end %>
+
+ <%= form_for [:admin, @budget, Budget::Group.new], html: {id: "new-group-form", style: "display:none"}, remote: true do |f| %>
+
+ <% end %>
+
+ <% groups.each do |group| %>
+
+ <%= render "admin/budgets/group", group: group, headings: group.headings %>
+
+ <% end %>
+
\ No newline at end of file
diff --git a/app/views/admin/budgets/index.html.erb b/app/views/admin/budgets/index.html.erb
new file mode 100644
index 000000000..193b6a7ef
--- /dev/null
+++ b/app/views/admin/budgets/index.html.erb
@@ -0,0 +1,25 @@
+<%= t("admin.budgets.index.title") %>
+
+<%= link_to t("admin.budgets.index.new_link"),
+ new_admin_budget_path,
+ class: "button float-right margin-right" %>
+
+<%= render 'shared/filter_subnav', i18n_namespace: "admin.budgets.index" %>
+
+
+<%= page_entries_info @budgets %>
+
+
+ <% @budgets.each do |budget| %>
+
+
+ <%= link_to budget.name, admin_budget_path(budget) %>
+
+
+ <%= t("budget.phase.#{budget.phase}") %>
+
+
+ <% end %>
+
+
+<%= paginate @budgets %>
\ No newline at end of file
diff --git a/app/views/admin/budgets/new.html.erb b/app/views/admin/budgets/new.html.erb
new file mode 100644
index 000000000..9ca0f34a5
--- /dev/null
+++ b/app/views/admin/budgets/new.html.erb
@@ -0,0 +1,29 @@
+
+
+
<%= t("admin.budgets.new.title") %>
+
+ <%= form_for [:admin, @budget] do |f| %>
+
+ <%= f.label :name, t("admin.budgets.new.name") %>
+ <%= f.text_field :name,
+ label: false,
+ maxlength: 30,
+ placeholder: t("admin.budgets.new.name") %>
+
+ <%= f.label :description, t("admin.budgets.new.description") %>
+ <%= f.text_area :description, rows: 3, maxlength: 6000, label: false, placeholder: t("admin.budgets.new.description") %>
+
+
+
+ <%= f.label :description, t("admin.budgets.new.phase") %>
+ <%= f.select :phase, budget_phases_select_options, {label: false} %>
+
+
+ <%= f.label :description, t("admin.budgets.new.currency") %>
+ <%= f.select :currency_symbol, budget_currency_symbol_select_options, {label: false} %>
+
+
+ <%= f.submit t("admin.budgets.new.create"), class: "button success" %>
+ <% end %>
+
+
\ No newline at end of file
diff --git a/app/views/admin/budgets/show.html.erb b/app/views/admin/budgets/show.html.erb
new file mode 100644
index 000000000..847aa2f60
--- /dev/null
+++ b/app/views/admin/budgets/show.html.erb
@@ -0,0 +1,16 @@
+
+
+
<%= @budget.name %>
+
+ <%= simple_format(text_with_links(@budget.description), {}, sanitize: false) %>
+
+
+ <%= t('admin.budgets.show.phase') %>: <%= t("budget.phase.#{@budget.phase}") %> |
+ <%= t('admin.budgets.show.currency') %>: <%= @budget.currency_symbol %>
+
+
+
+
+
+ <%= render "groups", groups: @budget.groups %>
+
\ No newline at end of file
diff --git a/app/views/shared/_admin_login_items.html.erb b/app/views/shared/_admin_login_items.html.erb
index 6ba10bbca..013320f38 100644
--- a/app/views/shared/_admin_login_items.html.erb
+++ b/app/views/shared/_admin_login_items.html.erb
@@ -5,13 +5,13 @@
<% end %>
- <% if current_user.moderator? || current_user.administrator? %>
+ <% if current_user.administrator? || current_user.moderator? %>
<%= link_to t("layouts.header.moderation"), moderation_root_path %>
<% end %>
- <% if feature?(:spending_proposals) && (current_user.valuator? || current_user.administrator?) %>
+ <% if feature?(:spending_proposals) && (current_user.administrator? || current_user.valuator?) %>
<%= link_to t("layouts.header.valuation"), valuation_root_path %>
diff --git a/config/i18n-tasks.yml b/config/i18n-tasks.yml
index 250ed18f9..e24d3af0c 100644
--- a/config/i18n-tasks.yml
+++ b/config/i18n-tasks.yml
@@ -112,6 +112,7 @@ ignore_unused:
- 'admin.banners.index.filters.*'
- 'admin.debates.index.filter*'
- 'admin.proposals.index.filter*'
+ - 'admin.budgets.index.filter*'
- 'admin.spending_proposals.index.filter*'
- 'admin.organizations.index.filter*'
- 'admin.users.index.filter*'
diff --git a/config/locales/activerecord.en.yml b/config/locales/activerecord.en.yml
index 07791e53c..5a7a591bd 100644
--- a/config/locales/activerecord.en.yml
+++ b/config/locales/activerecord.en.yml
@@ -4,6 +4,9 @@ en:
activity:
one: "activity"
other: "activities"
+ budget:
+ one: "Participatory budget"
+ other: "Participatory budgets"
comment:
one: "Comment"
other: "Comments"
diff --git a/config/locales/activerecord.es.yml b/config/locales/activerecord.es.yml
index d5b7f0005..ccd0240e8 100644
--- a/config/locales/activerecord.es.yml
+++ b/config/locales/activerecord.es.yml
@@ -4,6 +4,9 @@ es:
activity:
one: "actividad"
other: "actividades"
+ budget:
+ one: "Presupuesto participativo"
+ other: "Presupuestos participativos"
comment:
one: "Comentario"
other: "Comentarios"
diff --git a/config/locales/admin.en.yml b/config/locales/admin.en.yml
index 2f73f64d8..78a3a6d6c 100755
--- a/config/locales/admin.en.yml
+++ b/config/locales/admin.en.yml
@@ -32,8 +32,6 @@ en:
editing: Edit banner
form:
submit_button: Save changes
- errors:
- form:
errors:
form:
error:
@@ -60,6 +58,40 @@ en:
on_users: Users
title: Moderator activity
type: Type
+ budgets:
+ index:
+ title: Participatory budgets
+ new_link: Create new
+ filters:
+ open: Open
+ finished: Finished
+ create:
+ notice: New participatory budget created successfully!
+ new:
+ title: New participatory budget
+ create: Create budget
+ name: Budget's name
+ description: Description
+ phase: Phase
+ currency: Currency
+ show:
+ phase: Current phase
+ currency: Currency
+ groups: Groups of budget headings
+ form:
+ group: Group's name
+ no_groups: No groups created yet. Each user will be able to vote in only one heading per group.
+ add_group: Add new group
+ create_group: Create group
+ heading: Heading's name
+ add_heading: Add heading
+ amount: Amount
+ save_heading: Save heading
+ no_heading: This group has no assigned heading.
+ geozone: Scope of operation
+ table_heading: Heading
+ table_amount: Amount
+ table_geozone: Scope of operation
comments:
index:
filter: Filter
@@ -96,6 +128,7 @@ en:
activity: Moderator activity
admin: Admin menu
banner: Manage banners
+ budgets: Participatory budgets
debate_topics: Debate topics
hidden_comments: Hidden comments
hidden_debates: Hidden debates
diff --git a/config/locales/admin.es.yml b/config/locales/admin.es.yml
index 5aada1ce1..496a0208d 100644
--- a/config/locales/admin.es.yml
+++ b/config/locales/admin.es.yml
@@ -58,6 +58,40 @@ es:
on_users: Usuarios
title: Actividad de los Moderadores
type: Tipo
+ budgets:
+ index:
+ title: Presupuestos participativos
+ new_link: Crear nuevo
+ filters:
+ open: Abiertos
+ finished: Terminados
+ create:
+ notice: ¡Nueva campaña de presupuestos participativos creada con éxito!
+ new:
+ title: Nuevo presupuesto ciudadano
+ create: Crear presupuesto
+ name: Nombre del presupuesto
+ description: Descripción
+ phase: Fase
+ currency: Divisa
+ show:
+ phase: Fase actual
+ currency: Divisa
+ groups: Grupos de partidas presupuestarias
+ form:
+ group: Nombre del grupo
+ no_groups: No hay grupos creados todavía. Cada usuario podrá votar en una sola partida de cada grupo.
+ add_group: Añadir nuevo grupo
+ create_group: Crear grupo
+ heading: Nombre de la partida
+ add_heading: Añadir partida
+ amount: Cantidad
+ save_heading: Guardar partida
+ no_heading: Este grupo no tiene ninguna partida asignada.
+ geozone: Ámbito de actuación
+ table_heading: Partida
+ table_amount: Cantidad
+ table_geozone: Ámbito de actuación
comments:
index:
filter: Filtro
@@ -94,6 +128,7 @@ es:
activity: Actividad de moderadores
admin: Menú de administración
banner: Gestionar banners
+ budgets: Presupuestos participativos
debate_topics: Temas de debate
hidden_comments: Comentarios ocultos
hidden_debates: Debates ocultos
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 05153d714..fae75307f 100755
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -33,6 +33,13 @@ en:
application:
close: Close
menu: Menu
+ budget:
+ phase:
+ on_hold: On hold
+ accepting: Accepting proposals
+ selecting: Selecting
+ balloting: Balloting
+ finished: Finished
comments:
comment:
admin: Administrator
diff --git a/config/locales/es.yml b/config/locales/es.yml
index 9391da3bf..195a80766 100755
--- a/config/locales/es.yml
+++ b/config/locales/es.yml
@@ -33,6 +33,13 @@ es:
application:
close: Cerrar
menu: Menú
+ budget:
+ phase:
+ on_hold: En pausa
+ accepting: Aceptando propuestas
+ selecting: Fase de selección
+ balloting: Fase de Votación
+ finished: Terminado
comments:
comment:
admin: Administrador
diff --git a/config/routes.rb b/config/routes.rb
index 22518f8c8..8cf94ea23 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -153,6 +153,13 @@ Rails.application.routes.draw do
get :summary, on: :collection
end
+ resources :budgets do
+ resources :budget_groups do
+ resources :budget_headings do
+ end
+ end
+ end
+
resources :banners, only: [:index, :new, :create, :edit, :update, :destroy] do
collection { get :search}
end
diff --git a/db/schema.rb b/db/schema.rb
index ee5b3ab6f..df58b15cb 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -210,10 +210,10 @@ ActiveRecord::Schema.define(version: 20160617172616) do
t.string "visit_id"
t.datetime "hidden_at"
t.integer "flags_count", default: 0
- t.datetime "ignored_flag_at"
t.integer "cached_votes_total", default: 0
t.integer "cached_votes_up", default: 0
t.integer "cached_votes_down", default: 0
+ t.datetime "ignored_flag_at"
t.integer "comments_count", default: 0
t.datetime "confirmed_hide_at"
t.integer "cached_anonymous_votes_total", default: 0
diff --git a/spec/factories.rb b/spec/factories.rb
index 263900ecd..bca0c51e3 100644
--- a/spec/factories.rb
+++ b/spec/factories.rb
@@ -193,6 +193,10 @@ FactoryGirl.define do
currency_symbol "€"
phase 'on_hold'
+ trait :accepting do
+ phase 'accepting'
+ end
+
trait :selecting do
phase 'selecting'
end
diff --git a/spec/features/admin/budgets_spec.rb b/spec/features/admin/budgets_spec.rb
new file mode 100644
index 000000000..123ca43e8
--- /dev/null
+++ b/spec/features/admin/budgets_spec.rb
@@ -0,0 +1,158 @@
+require 'rails_helper'
+
+feature 'Admin budgets' do
+
+ background do
+ admin = create(:administrator)
+ login_as(admin.user)
+ end
+
+ context 'Feature flag' do
+
+ xscenario 'Disabled with a feature flag' do
+ Setting['feature.budgets'] = nil
+ expect{ visit admin_budgets_path }.to raise_exception(FeatureFlags::FeatureDisabled)
+ end
+
+ end
+
+ context 'Index' do
+
+ scenario 'Displaying budgets' do
+ budget = create(:budget)
+ visit admin_budgets_path
+
+ expect(page).to have_content(budget.name)
+ expect(page).to have_content(I18n.t("budget.phase.#{budget.phase}"))
+ end
+
+ scenario 'Filters by phase' do
+ budget1 = create(:budget)
+ budget2 = create(:budget, :accepting)
+ budget3 = create(:budget, :selecting)
+ budget4 = create(:budget, :balloting)
+ budget5 = create(:budget, :finished)
+
+ visit admin_budgets_path
+ expect(page).to have_content(budget1.name)
+ expect(page).to have_content(budget2.name)
+ expect(page).to have_content(budget3.name)
+ expect(page).to have_content(budget4.name)
+ expect(page).to_not have_content(budget5.name)
+
+ click_link 'Finished'
+ expect(page).to_not have_content(budget1.name)
+ expect(page).to_not have_content(budget2.name)
+ expect(page).to_not have_content(budget3.name)
+ expect(page).to_not have_content(budget4.name)
+ expect(page).to have_content(budget5.name)
+
+ click_link 'Open'
+ expect(page).to have_content(budget1.name)
+ expect(page).to have_content(budget2.name)
+ expect(page).to have_content(budget3.name)
+ expect(page).to have_content(budget4.name)
+ expect(page).to_not have_content(budget5.name)
+ end
+
+ scenario 'Current filter is properly highlighted' do
+ filters_links = {'open' => 'Open', 'finished' => 'Finished'}
+
+ visit admin_budgets_path
+
+ expect(page).to_not have_link(filters_links.values.first)
+ filters_links.keys.drop(1).each { |filter| expect(page).to have_link(filters_links[filter]) }
+
+ filters_links.each_pair do |current_filter, link|
+ visit admin_budgets_path(filter: current_filter)
+
+ expect(page).to_not have_link(link)
+
+ (filters_links.keys - [current_filter]).each do |filter|
+ expect(page).to have_link(filters_links[filter])
+ end
+ end
+ end
+
+ end
+
+ context 'New' do
+
+ scenario 'Create budget' do
+ visit admin_budgets_path
+ click_link 'Create new'
+
+ fill_in 'budget_name', with: 'M30 - Summer campaign'
+ fill_in 'budget_description', with: 'Budgeting for summer 2017 maintenance and improvements of the road M-30'
+ select 'Accepting proposals', from: 'budget[phase]'
+
+ click_button 'Create budget'
+
+ expect(page).to have_content 'New participatory budget created successfully!'
+ expect(page).to have_content 'M30 - Summer campaign'
+ end
+
+ scenario 'Name is mandatory' do
+ visit new_admin_budget_path
+ click_button 'Create budget'
+
+ expect(page).to_not have_content 'New participatory budget created successfully!'
+ expect(page).to have_css("label.error", text: "Budget's name")
+ end
+
+ end
+
+ context 'Manage groups and headings' do
+
+ scenario 'Create group', :js do
+ create(:budget, name: 'Yearly participatory budget')
+
+ visit admin_budgets_path
+ click_link 'Yearly participatory budget'
+
+ expect(page).to have_content 'No groups created yet.'
+
+ click_link 'Add new group'
+
+ fill_in 'budget_group_name', with: 'General improvments'
+ click_button 'Create group'
+
+ expect(page).to have_content 'Yearly participatory budget'
+ expect(page).to_not have_content 'No groups created yet.'
+
+ visit admin_budgets_path
+ click_link 'Yearly participatory budget'
+
+ expect(page).to have_content 'Yearly participatory budget'
+ expect(page).to_not have_content 'No groups created yet.'
+ end
+
+ scenario 'Create heading', :js do
+ budget = create(:budget, name: 'Yearly participatory budget')
+ group = create(:budget_group, budget: budget, name: 'Districts improvments')
+
+ visit admin_budget_path(budget)
+
+ within("#budget_group_#{group.id}") do
+ expect(page).to have_content 'This group has no assigned heading.'
+ click_link 'Add heading'
+
+ fill_in 'budget_heading_name', with: 'District 9 reconstruction'
+ fill_in 'budget_heading_price', with: '6785'
+ click_button 'Save heading'
+ end
+
+ expect(page).to_not have_content 'This group has no assigned heading.'
+
+ visit admin_budget_path(budget)
+ within("#budget_group_#{group.id}") do
+ expect(page).to_not have_content 'This group has no assigned heading.'
+
+ expect(page).to have_content 'District 9 reconstruction'
+ expect(page).to have_content '6785'
+ expect(page).to have_content 'All city'
+ end
+ end
+
+ end
+end
\ No newline at end of file
diff --git a/spec/helpers/geozones_helper_spec.rb b/spec/helpers/geozones_helper_spec.rb
index 605a774a6..0c0c13d70 100644
--- a/spec/helpers/geozones_helper_spec.rb
+++ b/spec/helpers/geozones_helper_spec.rb
@@ -31,4 +31,19 @@ describe GeozonesHelper do
end
end
+ describe "#geozone_name_from_id" do
+
+ it "returns geozone name if present" do
+ g1 = create(:geozone, name: "AAA")
+ g2 = create(:geozone, name: "BBB")
+
+ expect(geozone_name_from_id(g1.id)).to eq "AAA"
+ expect(geozone_name_from_id(g2.id)).to eq "BBB"
+ end
+
+ it "returns default string for no geozone if geozone is blank" do
+ expect(geozone_name_from_id(nil)).to eq "All city"
+ end
+ end
+
end