decidim-budgets 0.23.3 → 0.24.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/assets/javascripts/decidim/budgets/projects.js.es6 +30 -13
- data/app/cells/decidim/budgets/limit_announcement_cell.rb +2 -9
- 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/_filters_small_view.html.erb +1 -1
- 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 +36 -8
- 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 +35 -7
- data/config/locales/es-PY.yml +35 -7
- data/config/locales/es.yml +35 -7
- 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 +23 -7
- 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 +49 -7
- data/config/locales/no.yml +2 -7
- data/config/locales/pl.yml +41 -13
- data/config/locales/pt-BR.yml +2 -5
- data/config/locales/pt.yml +2 -6
- data/config/locales/ro-RO.yml +69 -6
- 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 +35 -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/db/migrate/20210310120613_add_followable_counter_cache_to_budgets.rb +16 -0
- 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.rb +2 -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
- metadata +20 -17
- 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: 4d91881aea249a69386309da0bbf83a61b74543236fd59d962b09e218d67bae5
|
4
|
+
data.tar.gz: cd1379113a70f33668e8814ae51c92e3d8c805893793dddc8caf4f8c0ac95789
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b53ea096b8718ddbe6630ee5702cc30623850dc24357c3014db58755d40a296daa4518060de3c8d555b5f6fd90053a2af4f7e6f5615b5265cf42b7edc5528398
|
7
|
+
data.tar.gz: 18dc70348221c5fd6fe95bc08827eb0edfa7c49e527d992e3bb26a27564bfc703cdad90f495a0a7d8dadb44a159cf2717ec71bf12bb7aadcc751689e241f0956
|
@@ -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
|
});
|
@@ -9,7 +9,7 @@ module Decidim
|
|
9
9
|
delegate :voting_open?, to: :controller
|
10
10
|
|
11
11
|
def show
|
12
|
-
cell("decidim/announcement",
|
12
|
+
cell("decidim/announcement", announcement_message, callout_class: "warning") if announce?
|
13
13
|
end
|
14
14
|
|
15
15
|
private
|
@@ -20,14 +20,7 @@ module Decidim
|
|
20
20
|
return if vote_allowed?(budget)
|
21
21
|
return if voted?(budget)
|
22
22
|
|
23
|
-
discardable.any? || !vote_allowed?(budget, false)
|
24
|
-
end
|
25
|
-
|
26
|
-
def announcement_args
|
27
|
-
{
|
28
|
-
callout_class: "warning",
|
29
|
-
announcement: announcement_message
|
30
|
-
}
|
23
|
+
discardable.any? || !vote_allowed?(budget, consider_progress: false)
|
31
24
|
end
|
32
25
|
|
33
26
|
def announcement_message
|
@@ -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
|