decidim-budgets 0.23.6 → 0.24.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/javascripts/decidim/budgets/projects.js.es6 +30 -13
- data/app/cells/decidim/budgets/limit_announcement_cell.rb +1 -1
- data/app/cells/decidim/budgets/project_list_item/project_data_vote_button.erb +1 -0
- data/app/cells/decidim/budgets/project_list_item_cell.rb +4 -0
- data/app/commands/decidim/budgets/admin/import_proposals_to_budgets.rb +8 -1
- data/app/controllers/decidim/budgets/admin/budgets_controller.rb +22 -1
- data/app/controllers/decidim/budgets/orders_controller.rb +1 -1
- data/app/forms/decidim/budgets/admin/component_form.rb +57 -10
- data/app/forms/decidim/budgets/admin/project_form.rb +3 -2
- data/app/forms/decidim/budgets/admin/project_import_proposals_form.rb +11 -0
- data/app/helpers/decidim/budgets/projects_helper.rb +45 -1
- data/app/models/decidim/budgets/order.rb +94 -18
- data/app/permissions/decidim/budgets/admin/permissions.rb +1 -1
- data/app/views/decidim/budgets/admin/budgets/index.html.erb +22 -5
- data/app/views/decidim/budgets/admin/projects/index.html.erb +13 -6
- data/app/views/decidim/budgets/admin/proposals_imports/new.html.erb +6 -1
- data/app/views/decidim/budgets/projects/_budget_excess.html.erb +2 -2
- data/app/views/decidim/budgets/projects/_budget_summary.html.erb +32 -12
- data/app/views/decidim/budgets/projects/_order_progress.html.erb +1 -1
- data/app/views/decidim/budgets/projects/_order_total_budget.html.erb +5 -1
- data/config/locales/ar.yml +2 -5
- data/config/locales/ca.yml +7 -9
- data/config/locales/cs.yml +34 -6
- data/config/locales/de.yml +34 -6
- data/config/locales/el.yml +2 -6
- data/config/locales/en.yml +35 -7
- data/config/locales/es-MX.yml +26 -8
- data/config/locales/es-PY.yml +26 -8
- data/config/locales/es.yml +26 -8
- data/config/locales/eu.yml +2 -5
- data/config/locales/fi-plain.yml +34 -6
- data/config/locales/fi.yml +36 -8
- data/config/locales/fr-CA.yml +35 -7
- data/config/locales/fr.yml +35 -7
- data/config/locales/gl.yml +7 -22
- data/config/locales/hu.yml +2 -5
- data/config/locales/id-ID.yml +2 -5
- data/config/locales/is-IS.yml +2 -4
- data/config/locales/it.yml +2 -6
- data/config/locales/ja.yml +3 -7
- data/config/locales/lv.yml +2 -6
- data/config/locales/nl.yml +35 -7
- data/config/locales/no.yml +2 -7
- data/config/locales/pl.yml +38 -10
- data/config/locales/pt-BR.yml +2 -5
- data/config/locales/pt.yml +2 -6
- data/config/locales/ro-RO.yml +2 -67
- data/config/locales/ru.yml +2 -5
- data/config/locales/sk.yml +2 -6
- data/config/locales/sr-CS.yml +0 -2
- data/config/locales/sv.yml +26 -7
- data/config/locales/tr-TR.yml +31 -7
- data/config/locales/uk.yml +2 -5
- data/config/locales/zh-CN.yml +2 -7
- data/db/migrate/20200804175222_votes_enabled_to_votes_choices.rb +4 -4
- data/lib/decidim/api/budget_type.rb +21 -0
- data/lib/decidim/api/budgets_type.rb +26 -0
- data/lib/decidim/api/project_type.rb +23 -0
- data/lib/decidim/budgets/api.rb +9 -0
- data/lib/decidim/budgets/component.rb +31 -14
- data/lib/decidim/budgets/project_serializer.rb +81 -0
- data/lib/decidim/budgets/test/factories.rb +35 -1
- data/lib/decidim/budgets/version.rb +1 -1
- data/lib/decidim/budgets/workflows/all.rb +1 -1
- data/lib/decidim/budgets/workflows/base.rb +3 -3
- data/lib/decidim/budgets/workflows/one.rb +1 -1
- data/lib/decidim/budgets.rb +2 -0
- metadata +21 -19
- data/app/types/decidim/budgets/budget_type.rb +0 -24
- data/app/types/decidim/budgets/budgets_type.rb +0 -32
- data/app/types/decidim/budgets/project_type.rb +0 -26
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 41710b06043e856a900ffaa5f04509ba3ac513e9e9bd0e3c95dfd6fa5cd6c9e3
|
4
|
+
data.tar.gz: d232449475a2e39087ce38fd9b265e7a689ef1e3b4c50860a304857df109b720
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 38699120554e836883325bb833b07bea0471d8793271342f88a5c09bd8335ced004bb6c8f1428cfafc8b14ff078d3659e1639f5fd1cb6193488c9f27c475eed9
|
7
|
+
data.tar.gz: 96404bf36a1032fcc72cdebfddc5f90520a495bf8023ad595c44c456a15f9f4f89e556b31ed891952c251afcc9fccca6f1623e83ad8e3c5821dfd811a0b1278c
|
@@ -6,22 +6,31 @@ $(() => {
|
|
6
6
|
const $budgetSummaryTotal = $(".budget-summary__total");
|
7
7
|
const $budgetExceedModal = $("#budget-excess");
|
8
8
|
const $budgetSummary = $(".budget-summary__progressbox");
|
9
|
-
const
|
9
|
+
const totalAllocation = parseInt($budgetSummaryTotal.attr("data-total-allocation"), 10);
|
10
10
|
|
11
11
|
const cancelEvent = (event) => {
|
12
12
|
event.stopPropagation();
|
13
13
|
event.preventDefault();
|
14
14
|
};
|
15
15
|
|
16
|
+
const allowExitFrom = ($el) => {
|
17
|
+
if ($el.parents("#loginModal").length > 0) {
|
18
|
+
return true;
|
19
|
+
} else if ($el.parents("#authorizationModal").length > 0) {
|
20
|
+
return true;
|
21
|
+
}
|
22
|
+
|
23
|
+
return false;
|
24
|
+
}
|
25
|
+
|
16
26
|
$projects.on("click", ".budget-list__action", (event) => {
|
17
|
-
const
|
27
|
+
const currentAllocation = parseInt($budgetSummary.attr("data-current-allocation"), 10);
|
18
28
|
const $currentTarget = $(event.currentTarget);
|
19
|
-
const
|
29
|
+
const projectAllocation = parseInt($currentTarget.attr("data-allocation"), 10);
|
20
30
|
|
21
31
|
if ($currentTarget.attr("disabled")) {
|
22
32
|
cancelEvent(event);
|
23
|
-
|
24
|
-
} else if (($currentTarget.attr("data-add") === "true") && ((currentBudget + projectBudget) > totalBudget)) {
|
33
|
+
} else if (($currentTarget.attr("data-add") === "true") && ((currentAllocation + projectAllocation) > totalAllocation)) {
|
25
34
|
$budgetExceedModal.foundation("toggle");
|
26
35
|
cancelEvent(event);
|
27
36
|
}
|
@@ -30,22 +39,30 @@ $(() => {
|
|
30
39
|
if ($("#order-progress [data-toggle=budget-confirm]").length > 0) {
|
31
40
|
const safeUrl = $(".budget-summary").attr("data-safe-url").split("?")[0];
|
32
41
|
$(document).on("click", "a", (event) => {
|
33
|
-
|
42
|
+
if (allowExitFrom($(event.currentTarget))) {
|
43
|
+
window.exitUrl = null;
|
44
|
+
} else {
|
45
|
+
window.exitUrl = event.currentTarget.href;
|
46
|
+
}
|
34
47
|
});
|
35
48
|
$(document).on("submit", "form", (event) => {
|
36
|
-
|
49
|
+
if (allowExitFrom($(event.currentTarget))) {
|
50
|
+
window.exitUrl = null;
|
51
|
+
} else {
|
52
|
+
window.exitUrl = event.currentTarget.action;
|
53
|
+
}
|
37
54
|
});
|
38
55
|
|
39
|
-
window.
|
40
|
-
const
|
56
|
+
window.addEventListener("beforeunload", (event) => {
|
57
|
+
const currentAllocation = parseInt($budgetSummary.attr("data-current-allocation"), 10);
|
41
58
|
const exitUrl = window.exitUrl;
|
42
59
|
window.exitUrl = null;
|
43
60
|
|
44
|
-
if (
|
45
|
-
return
|
61
|
+
if (currentAllocation === 0 || (exitUrl && exitUrl.startsWith(safeUrl))) {
|
62
|
+
return;
|
46
63
|
}
|
47
64
|
|
48
|
-
|
49
|
-
}
|
65
|
+
event.returnValue = true;
|
66
|
+
});
|
50
67
|
}
|
51
68
|
});
|
@@ -28,6 +28,10 @@ module Decidim
|
|
28
28
|
current_order && current_order.projects.include?(model)
|
29
29
|
end
|
30
30
|
|
31
|
+
def resource_allocation
|
32
|
+
current_order.allocation_for(model)
|
33
|
+
end
|
34
|
+
|
31
35
|
def data_class
|
32
36
|
[].tap do |list|
|
33
37
|
list << "budget-list__data--added" if can_have_order? && resource_added?
|
@@ -60,7 +60,14 @@ module Decidim
|
|
60
60
|
end
|
61
61
|
|
62
62
|
def proposals
|
63
|
-
|
63
|
+
return all_proposals if form.scope_id.blank?
|
64
|
+
|
65
|
+
all_proposals.where(decidim_scope_id: form.scope_id)
|
66
|
+
end
|
67
|
+
|
68
|
+
def all_proposals
|
69
|
+
Decidim::Proposals::Proposal.where(component: origin_component)
|
70
|
+
.where(state: :accepted)
|
64
71
|
end
|
65
72
|
|
66
73
|
def origin_component
|
@@ -5,7 +5,8 @@ module Decidim
|
|
5
5
|
module Admin
|
6
6
|
# This controller allows the create or update a budget.
|
7
7
|
class BudgetsController < Admin::ApplicationController
|
8
|
-
helper_method :budgets, :budget
|
8
|
+
helper_method :budgets, :budget, :finished_orders, :pending_orders,
|
9
|
+
:users_with_pending_orders, :users_with_finished_orders
|
9
10
|
|
10
11
|
def new
|
11
12
|
enforce_permission_to :create, :budget
|
@@ -76,6 +77,26 @@ module Decidim
|
|
76
77
|
def budget
|
77
78
|
@budget ||= budgets.find_by(id: params[:id])
|
78
79
|
end
|
80
|
+
|
81
|
+
def orders
|
82
|
+
@orders ||= Order.where(decidim_budgets_budget_id: budgets)
|
83
|
+
end
|
84
|
+
|
85
|
+
def pending_orders
|
86
|
+
orders.pending
|
87
|
+
end
|
88
|
+
|
89
|
+
def finished_orders
|
90
|
+
orders.finished
|
91
|
+
end
|
92
|
+
|
93
|
+
def users_with_pending_orders
|
94
|
+
orders.pending.pluck(:decidim_user_id).uniq
|
95
|
+
end
|
96
|
+
|
97
|
+
def users_with_finished_orders
|
98
|
+
orders.finished.pluck(:decidim_user_id).uniq
|
99
|
+
end
|
79
100
|
end
|
80
101
|
end
|
81
102
|
end
|
@@ -7,7 +7,10 @@ module Decidim
|
|
7
7
|
# to a participatory process from the admin panel.
|
8
8
|
#
|
9
9
|
class ComponentForm < Decidim::Admin::ComponentForm
|
10
|
-
validate :budget_voting_rule_enabled_setting,
|
10
|
+
validate :budget_voting_rule_enabled_setting,
|
11
|
+
:budget_voting_rule_threshold_value_setting,
|
12
|
+
:budget_voting_rule_minimum_value_setting,
|
13
|
+
:budget_voting_rule_projects_value_setting
|
11
14
|
|
12
15
|
private
|
13
16
|
|
@@ -16,27 +19,71 @@ module Decidim
|
|
16
19
|
def budget_voting_rule_enabled_setting
|
17
20
|
return unless manifest&.name == :budgets
|
18
21
|
|
22
|
+
rule_settings = [
|
23
|
+
:vote_rule_threshold_percent_enabled,
|
24
|
+
:vote_rule_minimum_budget_projects_enabled,
|
25
|
+
:vote_rule_selected_projects_enabled
|
26
|
+
]
|
27
|
+
active_rules = rule_settings.select { |key| settings.public_send(key) == true }
|
19
28
|
i18n_error_scope = "decidim.components.budgets.settings.global.form.errors"
|
20
|
-
if
|
21
|
-
|
22
|
-
|
29
|
+
if active_rules.blank?
|
30
|
+
rule_settings.each do |key|
|
31
|
+
settings.errors.add(key, I18n.t(:budget_voting_rule_required, scope: i18n_error_scope))
|
32
|
+
end
|
23
33
|
end
|
24
34
|
|
25
|
-
if
|
26
|
-
|
27
|
-
|
35
|
+
if active_rules.length > 1
|
36
|
+
rule_settings.each do |key|
|
37
|
+
settings.errors.add(key, I18n.t(:budget_voting_rule_only_one, scope: i18n_error_scope))
|
38
|
+
end
|
28
39
|
end
|
29
40
|
end
|
30
41
|
|
31
42
|
# - the value must be a valid number
|
32
|
-
def
|
43
|
+
def budget_voting_rule_threshold_value_setting
|
33
44
|
return unless manifest&.name == :budgets
|
45
|
+
return unless settings.vote_rule_threshold_percent_enabled
|
34
46
|
|
35
47
|
invalid_percent_number = settings.vote_threshold_percent.blank? || settings.vote_threshold_percent.to_i.negative?
|
36
|
-
settings.errors.add(:vote_threshold_percent) if
|
48
|
+
settings.errors.add(:vote_threshold_percent) if invalid_percent_number
|
49
|
+
end
|
50
|
+
|
51
|
+
def budget_voting_rule_minimum_value_setting
|
52
|
+
return unless manifest&.name == :budgets
|
53
|
+
return unless settings.vote_rule_minimum_budget_projects_enabled
|
37
54
|
|
38
55
|
invalid_minimum_number = settings.vote_minimum_budget_projects_number.blank? || (settings.vote_minimum_budget_projects_number.to_i < 1)
|
39
|
-
settings.errors.add(:vote_minimum_budget_projects_number) if
|
56
|
+
settings.errors.add(:vote_minimum_budget_projects_number) if invalid_minimum_number
|
57
|
+
end
|
58
|
+
|
59
|
+
def budget_voting_rule_projects_value_setting
|
60
|
+
return unless manifest&.name == :budgets
|
61
|
+
return unless settings.vote_rule_selected_projects_enabled
|
62
|
+
|
63
|
+
budget_voting_projects_value_setting_min
|
64
|
+
budget_voting_projects_value_setting_max
|
65
|
+
budget_voting_projects_value_setting_both
|
66
|
+
end
|
67
|
+
|
68
|
+
def budget_voting_projects_value_setting_min
|
69
|
+
return if settings.vote_selected_projects_minimum.present? && settings.vote_selected_projects_minimum.to_i >= 0
|
70
|
+
|
71
|
+
settings.errors.add(:vote_selected_projects_minimum)
|
72
|
+
end
|
73
|
+
|
74
|
+
def budget_voting_projects_value_setting_max
|
75
|
+
return if settings.vote_selected_projects_maximum.present? && settings.vote_selected_projects_maximum.to_i.positive?
|
76
|
+
|
77
|
+
settings.errors.add(:vote_selected_projects_maximum)
|
78
|
+
end
|
79
|
+
|
80
|
+
def budget_voting_projects_value_setting_both
|
81
|
+
return if settings.errors[:vote_selected_projects_minimum].present?
|
82
|
+
return if settings.errors[:vote_selected_projects_maximum].present?
|
83
|
+
return if settings.vote_selected_projects_maximum >= settings.vote_selected_projects_minimum
|
84
|
+
|
85
|
+
settings.errors.add(:vote_selected_projects_minimum)
|
86
|
+
settings.errors.add(:vote_selected_projects_maximum)
|
40
87
|
end
|
41
88
|
end
|
42
89
|
end
|
@@ -6,6 +6,7 @@ module Decidim
|
|
6
6
|
# This class holds a Form to create/update projects from Decidim's admin panel.
|
7
7
|
class ProjectForm < Decidim::Form
|
8
8
|
include TranslatableAttributes
|
9
|
+
include AttachmentAttributes
|
9
10
|
include TranslationsHelper
|
10
11
|
include Decidim::ApplicationHelper
|
11
12
|
|
@@ -17,10 +18,10 @@ module Decidim
|
|
17
18
|
attribute :decidim_category_id, Integer
|
18
19
|
attribute :proposal_ids, Array[Integer]
|
19
20
|
attribute :attachment, AttachmentForm
|
20
|
-
attribute :photos, Array[String]
|
21
|
-
attribute :add_photos, Array
|
22
21
|
attribute :selected, Boolean
|
23
22
|
|
23
|
+
attachments_attribute :photos
|
24
|
+
|
24
25
|
validates :title, translatable_presence: true
|
25
26
|
validates :description, translatable_presence: true
|
26
27
|
validates :budget_amount, presence: true, numericality: { greater_than: 0 }
|
@@ -9,12 +9,15 @@ module Decidim
|
|
9
9
|
mimic :proposals_import
|
10
10
|
|
11
11
|
attribute :origin_component_id, Integer
|
12
|
+
attribute :scope_id, Integer
|
12
13
|
attribute :default_budget, Integer
|
13
14
|
attribute :import_all_accepted_proposals, Boolean
|
14
15
|
|
15
16
|
validates :origin_component_id, :origin_component, :current_component, presence: true
|
16
17
|
validates :import_all_accepted_proposals, allow_nil: false, acceptance: true
|
17
18
|
validates :default_budget, presence: true, numericality: { greater_than: 0 }
|
19
|
+
validates :scope, presence: true, if: ->(form) { form.scope_id.present? }
|
20
|
+
validates :scope_id, scope_belongs_to_component: true, if: ->(form) { form.scope_id.present? }
|
18
21
|
|
19
22
|
def origin_component
|
20
23
|
@origin_component ||= origin_components.find_by(id: origin_component_id)
|
@@ -30,6 +33,14 @@ module Decidim
|
|
30
33
|
end
|
31
34
|
end
|
32
35
|
|
36
|
+
def scope
|
37
|
+
@scope ||= @scope_id ? current_component.scopes.find_by(id: @scope_id) : current_component.scope
|
38
|
+
end
|
39
|
+
|
40
|
+
def scope_id
|
41
|
+
@scope_id || scope&.id
|
42
|
+
end
|
43
|
+
|
33
44
|
def budget
|
34
45
|
@budget ||= context[:budget]
|
35
46
|
end
|
@@ -20,7 +20,11 @@ module Decidim
|
|
20
20
|
def current_order_budget_percent_minimum
|
21
21
|
return 0 if current_order.minimum_projects_rule?
|
22
22
|
|
23
|
-
|
23
|
+
if current_order.projects_rule?
|
24
|
+
(current_order.minimum_projects.to_f / current_order.maximum_projects)
|
25
|
+
else
|
26
|
+
component_settings.vote_threshold_percent
|
27
|
+
end
|
24
28
|
end
|
25
29
|
|
26
30
|
def budget_confirm_disabled_attr
|
@@ -36,6 +40,46 @@ module Decidim
|
|
36
40
|
def current_order_can_be_checked_out?
|
37
41
|
current_order&.can_checkout?
|
38
42
|
end
|
43
|
+
|
44
|
+
def current_rule_explanation
|
45
|
+
return unless current_order
|
46
|
+
|
47
|
+
if current_order.projects_rule?
|
48
|
+
if current_order.minimum_projects.positive? && current_order.minimum_projects < current_order.maximum_projects
|
49
|
+
t(
|
50
|
+
".projects_rule.instruction",
|
51
|
+
minimum_number: current_order.minimum_projects,
|
52
|
+
maximum_number: current_order.maximum_projects
|
53
|
+
)
|
54
|
+
else
|
55
|
+
t(".projects_rule_maximum_only.instruction", maximum_number: current_order.maximum_projects)
|
56
|
+
end
|
57
|
+
elsif current_order.minimum_projects_rule?
|
58
|
+
t(".minimum_projects_rule.instruction", minimum_number: current_order.minimum_projects)
|
59
|
+
else
|
60
|
+
t(".vote_threshold_percent_rule.instruction", minimum_budget: budget_to_currency(current_order.minimum_budget))
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def current_rule_description
|
65
|
+
return unless current_order
|
66
|
+
|
67
|
+
if current_order.projects_rule?
|
68
|
+
if current_order.minimum_projects.positive? && current_order.minimum_projects < current_order.maximum_projects
|
69
|
+
t(
|
70
|
+
".projects_rule.description",
|
71
|
+
minimum_number: current_order.minimum_projects,
|
72
|
+
maximum_number: current_order.maximum_projects
|
73
|
+
)
|
74
|
+
else
|
75
|
+
t(".projects_rule_maximum_only.description", maximum_number: current_order.maximum_projects)
|
76
|
+
end
|
77
|
+
elsif current_order.minimum_projects_rule?
|
78
|
+
t(".minimum_projects_rule.description", minimum_number: current_order.minimum_projects)
|
79
|
+
else
|
80
|
+
t(".vote_threshold_percent_rule.description", minimum_budget: budget_to_currency(current_order.minimum_budget))
|
81
|
+
end
|
82
|
+
end
|
39
83
|
end
|
40
84
|
end
|
41
85
|
end
|
@@ -18,24 +18,76 @@ module Decidim
|
|
18
18
|
validates :budget, presence: true
|
19
19
|
validate :user_belongs_to_organization
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
# Rules active for the budget threshold and minimum budgets rules.
|
22
|
+
with_options if: -> { !projects_rule? && checked_out? } do
|
23
|
+
validates :total_budget, numericality: {
|
24
|
+
greater_than_or_equal_to: :minimum_budget
|
25
|
+
}
|
26
|
+
end
|
27
|
+
with_options unless: :projects_rule? do
|
28
|
+
validates :total_budget, numericality: {
|
29
|
+
less_than_or_equal_to: :maximum_budget
|
30
|
+
}
|
31
|
+
end
|
24
32
|
|
25
|
-
|
26
|
-
|
27
|
-
|
33
|
+
# Rules active for the minimum projects rule.
|
34
|
+
with_options if: -> { minimum_projects_rule? && checked_out? } do
|
35
|
+
validates :total_projects, numericality: {
|
36
|
+
greater_than_or_equal_to: :minimum_projects
|
37
|
+
}
|
38
|
+
end
|
28
39
|
|
29
|
-
|
40
|
+
# Rules active for the projects rule.
|
41
|
+
with_options if: -> { projects_rule? && checked_out? } do
|
42
|
+
validates :total_projects, numericality: {
|
43
|
+
greater_than_or_equal_to: :minimum_projects
|
44
|
+
}
|
45
|
+
|
46
|
+
validates :total_projects, numericality: {
|
47
|
+
less_than_or_equal_to: :maximum_projects
|
48
|
+
}
|
49
|
+
end
|
30
50
|
|
31
51
|
scope :finished, -> { where.not(checked_out_at: nil) }
|
32
52
|
scope :pending, -> { where(checked_out_at: nil) }
|
33
53
|
|
54
|
+
# Public: Returns the available budget allocation the user is able to
|
55
|
+
# allocate to this order or the maximum amount of projects to be selected
|
56
|
+
# in case the project selection voting is enabled.
|
57
|
+
def available_allocation
|
58
|
+
return maximum_projects if projects_rule?
|
59
|
+
|
60
|
+
maximum_budget
|
61
|
+
end
|
62
|
+
|
63
|
+
# Public: Returns the numeric amount the given project should allocate
|
64
|
+
# from the total available allocation when it is added to the order. The
|
65
|
+
# allocation is normally the project's budget but for project selection
|
66
|
+
# voting, the allocation is one.
|
67
|
+
def allocation_for(project)
|
68
|
+
return 1 if projects_rule?
|
69
|
+
|
70
|
+
project.budget_amount
|
71
|
+
end
|
72
|
+
|
34
73
|
# Public: Returns the sum of project budgets
|
35
74
|
def total_budget
|
36
75
|
projects.to_a.sum(&:budget_amount)
|
37
76
|
end
|
38
77
|
|
78
|
+
# Public: Returns the count of projects
|
79
|
+
def total_projects
|
80
|
+
projects.count
|
81
|
+
end
|
82
|
+
|
83
|
+
# Public: For budget voting returns the total budget and for project
|
84
|
+
# selection voting, returns the amount of selected projects.
|
85
|
+
def total
|
86
|
+
return total_projects if projects_rule?
|
87
|
+
|
88
|
+
total_budget
|
89
|
+
end
|
90
|
+
|
39
91
|
# Public: Returns true if the order has been checked out
|
40
92
|
def checked_out?
|
41
93
|
checked_out_at.present?
|
@@ -43,22 +95,28 @@ module Decidim
|
|
43
95
|
|
44
96
|
# Public: Check if the order total budget is enough to checkout
|
45
97
|
def can_checkout?
|
46
|
-
if
|
47
|
-
|
98
|
+
if projects_rule?
|
99
|
+
total_projects >= minimum_projects && total_projects <= maximum_projects
|
100
|
+
elsif minimum_projects_rule?
|
101
|
+
total_projects >= minimum_projects
|
48
102
|
else
|
49
103
|
total_budget.to_f >= minimum_budget
|
50
104
|
end
|
51
105
|
end
|
52
106
|
|
53
107
|
# Public: Returns the order budget percent from the settings total budget
|
108
|
+
# or the progress for selected projects if the selected project rule is
|
109
|
+
# enabled
|
54
110
|
def budget_percent
|
55
|
-
(
|
111
|
+
return (total_projects.to_f / maximum_projects) * 100 if projects_rule?
|
112
|
+
|
113
|
+
(total_budget.to_f / budget.total_budget) * 100
|
56
114
|
end
|
57
115
|
|
58
116
|
# Public: Returns the required minimum budget to checkout
|
59
117
|
def minimum_budget
|
60
118
|
return 0 unless budget
|
61
|
-
return 0 if minimum_projects_rule?
|
119
|
+
return 0 if minimum_projects_rule? || projects_rule?
|
62
120
|
|
63
121
|
budget.total_budget.to_f * (budget.settings.vote_threshold_percent.to_f / 100)
|
64
122
|
end
|
@@ -77,11 +135,35 @@ module Decidim
|
|
77
135
|
budget.settings.vote_rule_minimum_budget_projects_enabled
|
78
136
|
end
|
79
137
|
|
138
|
+
# Public: Returns true if the project voting rule is enabled
|
139
|
+
def projects_rule?
|
140
|
+
return unless budget
|
141
|
+
|
142
|
+
budget.settings.vote_rule_selected_projects_enabled
|
143
|
+
end
|
144
|
+
|
80
145
|
# Public: Returns the required minimum projects to checkout
|
81
146
|
def minimum_projects
|
82
147
|
return 0 unless budget
|
83
148
|
|
84
|
-
|
149
|
+
if minimum_projects_rule?
|
150
|
+
budget.settings.vote_minimum_budget_projects_number
|
151
|
+
elsif projects_rule?
|
152
|
+
budget.settings.vote_selected_projects_minimum
|
153
|
+
else
|
154
|
+
0
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# Public: Returns the required maximum projects to checkout
|
159
|
+
def maximum_projects
|
160
|
+
return nil unless budget
|
161
|
+
|
162
|
+
if projects_rule?
|
163
|
+
budget.settings.vote_selected_projects_maximum
|
164
|
+
else
|
165
|
+
0
|
166
|
+
end
|
85
167
|
end
|
86
168
|
|
87
169
|
def self.user_collection(user)
|
@@ -112,12 +194,6 @@ module Decidim
|
|
112
194
|
|
113
195
|
errors.add(:user, :invalid) unless user.organization == organization
|
114
196
|
end
|
115
|
-
|
116
|
-
def reach_minimum_projects
|
117
|
-
return unless minimum_projects_rule?
|
118
|
-
|
119
|
-
errors.add(:projects, :invalid) if minimum_projects > projects.count
|
120
|
-
end
|
121
197
|
end
|
122
198
|
end
|
123
199
|
end
|
@@ -1,9 +1,17 @@
|
|
1
|
-
<div class="card">
|
1
|
+
<div class="card with-overflow">
|
2
2
|
<div class="card-divider">
|
3
|
-
<h2 class="card-title">
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
<h2 class="card-title flex--sbc">
|
4
|
+
<div>
|
5
|
+
<%= t(".title") %>
|
6
|
+
</div>
|
7
|
+
<div class="flex--cc flex-gap--1">
|
8
|
+
<% if allowed_to? :export, :budget %>
|
9
|
+
<%= export_dropdown %>
|
10
|
+
<% end %>
|
11
|
+
<div id="js-other-actions-wrapper">
|
12
|
+
<%= link_to t("actions.new", scope: "decidim.budgets", name: t("models.budget.name", scope: "decidim.budgets.admin")), new_budget_path, class: "button tiny button--title" if allowed_to? :create, :budget %>
|
13
|
+
</div>
|
14
|
+
</div>
|
7
15
|
</h2>
|
8
16
|
</div>
|
9
17
|
|
@@ -55,4 +63,13 @@
|
|
55
63
|
</table>
|
56
64
|
</div>
|
57
65
|
</div>
|
66
|
+
<div class="card-divider">
|
67
|
+
<strong><%= t ".finished_orders" %>: </strong><span><%= finished_orders.count %></span>
|
68
|
+
<span> | </span>
|
69
|
+
<strong><%= t ".pending_orders" %>: </strong><span><%= pending_orders.count %></span>
|
70
|
+
<span> | </span>
|
71
|
+
<strong><%= t ".users_with_finished_orders" %>: </strong><span><%= users_with_finished_orders.count %></span>
|
72
|
+
<span> | </span>
|
73
|
+
<strong><%= t ".users_with_pending_orders" %>: </strong><span><%= users_with_pending_orders.count %></span>
|
74
|
+
</div>
|
58
75
|
</div>
|
@@ -1,10 +1,17 @@
|
|
1
|
-
<div class="card">
|
1
|
+
<div class="card with-overflow">
|
2
2
|
<div class="card-divider">
|
3
|
-
<h2 class="card-title">
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
<h2 class="card-title flex--sbc">
|
4
|
+
<div>
|
5
|
+
<%= link_to translated_attribute(budget.title), budgets_path %> >
|
6
|
+
<%= t(".title") %>
|
7
|
+
</div>
|
8
|
+
<div class="flex--cc flex-gap--1">
|
9
|
+
<%= link_to t("actions.import", scope: "decidim.budgets", name: t("models.project.name", scope: "decidim.budgets.admin")), new_budget_proposals_import_path(budget), class: "button tiny button--title" if allowed_to? :import_proposals, :project %>
|
10
|
+
<% if allowed_to? :export, :budget %>
|
11
|
+
<%= export_dropdown(current_component, budget.id) %>
|
12
|
+
<% end %>
|
13
|
+
<%= link_to t("actions.new", scope: "decidim.budgets", name: t("models.project.name", scope: "decidim.budgets.admin")), new_budget_project_path, class: "button tiny button--title new" if allowed_to? :create, :project %>
|
14
|
+
</div>
|
8
15
|
</h2>
|
9
16
|
</div>
|
10
17
|
|
@@ -2,13 +2,18 @@
|
|
2
2
|
<% if @form.origin_components.any? %>
|
3
3
|
<div class="card">
|
4
4
|
<div class="card-divider">
|
5
|
-
<h2 class="card-title"><%= title %></h2>
|
5
|
+
<h2 class="card-title"><%= t(".title") %></h2>
|
6
6
|
</div>
|
7
7
|
|
8
8
|
<div class="card-section">
|
9
9
|
<div class="row column">
|
10
10
|
<%= f.select :origin_component_id, @form.origin_components_collection, prompt: t(".select_component") %>
|
11
11
|
</div>
|
12
|
+
<% if current_component.scopes_enabled? %>
|
13
|
+
<div class="row column">
|
14
|
+
<%= scopes_picker_field f, :scope_id, root: budget.scope %>
|
15
|
+
</div>
|
16
|
+
<% end %>
|
12
17
|
<div class="row column">
|
13
18
|
<%= f.number_field :default_budget %>
|
14
19
|
</div>
|
@@ -1,11 +1,11 @@
|
|
1
1
|
<div class="reveal" data-reveal id="budget-excess">
|
2
2
|
<div class="reveal__header">
|
3
|
-
<h3 class="reveal__title"><%= t(".title") %></h3>
|
3
|
+
<h3 class="reveal__title"><%= current_order.projects_rule? ? t(".projects_excess.title") : t(".budget_excess.title") %></h3>
|
4
4
|
<button class="close-button" data-close aria-label="<%= t(".close") %>" type="button">
|
5
5
|
<span aria-hidden="true">×</span>
|
6
6
|
</button>
|
7
7
|
</div>
|
8
|
-
<p><%= t(".description") %></p>
|
8
|
+
<p><%= current_order.projects_rule? ? t(".projects_excess.description") : t(".budget_excess.description") %></p>
|
9
9
|
<div class="row">
|
10
10
|
<div class="columns medium-8 medium-offset-2">
|
11
11
|
<button data-close class="button expanded"><%= t(".ok") %></button>
|