decidim-budgets 0.19.0 → 0.22.0
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/images/decidim/budgets/icon.svg +1 -11
- data/app/assets/javascripts/decidim/budgets/projects.js.es6 +26 -4
- data/app/assets/stylesheets/decidim/budgets/budget/_budget-list.scss +147 -24
- data/app/cells/decidim/budgets/project_list_item/project_data.erb +5 -0
- data/app/cells/decidim/budgets/project_list_item/project_data_number.erb +3 -0
- data/app/cells/decidim/budgets/project_list_item/project_data_vote_button.erb +15 -0
- data/app/cells/decidim/budgets/project_list_item/project_data_votes.erb +7 -0
- data/app/cells/decidim/budgets/project_list_item/project_image.erb +5 -0
- data/app/cells/decidim/budgets/project_list_item/project_text.erb +17 -0
- data/app/cells/decidim/budgets/project_list_item/show.erb +5 -0
- data/app/cells/decidim/budgets/project_list_item_cell.rb +86 -0
- data/app/cells/decidim/budgets/project_m/data.erb +2 -2
- data/app/cells/decidim/budgets/project_m/footer.erb +1 -1
- data/app/commands/decidim/budgets/admin/create_project.rb +19 -9
- data/app/commands/decidim/budgets/admin/update_project.rb +12 -1
- data/app/commands/decidim/budgets/checkout.rb +2 -1
- data/app/controllers/concerns/decidim/budgets/needs_current_order.rb +5 -1
- data/app/controllers/concerns/decidim/budgets/orderable.rb +61 -0
- data/app/controllers/decidim/budgets/admin/projects_controller.rb +8 -5
- data/app/controllers/decidim/budgets/line_items_controller.rb +1 -1
- data/app/controllers/decidim/budgets/projects_controller.rb +23 -3
- data/app/forms/decidim/budgets/admin/component_form.rb +44 -0
- data/app/forms/decidim/budgets/admin/project_form.rb +14 -2
- data/app/helpers/decidim/budgets/application_helper.rb +1 -0
- data/app/helpers/decidim/budgets/projects_helper.rb +17 -0
- data/app/jobs/decidim/budgets/send_order_summary_job.rb +15 -0
- data/app/mailers/decidim/budgets/order_summary_mailer.rb +34 -0
- data/app/models/decidim/budgets/order.rb +28 -1
- data/app/models/decidim/budgets/project.rb +13 -0
- data/app/services/decidim/budgets/project_search.rb +8 -0
- data/app/types/decidim/budgets/budgets_type.rb +32 -0
- data/app/types/decidim/budgets/project_type.rb +25 -0
- data/app/views/decidim/budgets/admin/projects/_form.html.erb +3 -6
- data/app/views/decidim/budgets/admin/projects/proposals_picker.html.erb +1 -0
- data/app/views/decidim/budgets/order_summary_mailer/order_summary.html.erb +21 -0
- data/app/views/decidim/budgets/projects/_budget_confirm.html.erb +1 -1
- data/app/views/decidim/budgets/projects/_budget_summary.html.erb +8 -2
- data/app/views/decidim/budgets/projects/_filters.html.erb +10 -6
- data/app/views/decidim/budgets/projects/_linked_projects.html.erb +1 -1
- data/app/views/decidim/budgets/projects/_order_progress.html.erb +8 -16
- data/app/views/decidim/budgets/projects/_project.html.erb +1 -57
- data/app/views/decidim/budgets/projects/_project_budget_button.html.erb +3 -3
- data/app/views/decidim/budgets/projects/_projects.html.erb +8 -1
- data/app/views/decidim/budgets/projects/index.html.erb +3 -3
- data/app/views/decidim/budgets/projects/index.js.erb +8 -0
- data/app/views/decidim/budgets/projects/show.html.erb +1 -1
- data/config/locales/ar.yml +1 -6
- data/config/locales/bg-BG.yml +7 -0
- data/config/locales/ca.yml +27 -5
- data/config/locales/cs.yml +44 -22
- data/config/locales/da-DK.yml +1 -0
- data/config/locales/de.yml +27 -5
- data/config/locales/el-GR.yml +1 -0
- data/config/locales/el.yml +175 -0
- data/config/locales/en.yml +27 -5
- data/config/locales/es-MX.yml +27 -5
- data/config/locales/es-PY.yml +27 -5
- data/config/locales/es.yml +27 -5
- data/config/locales/et-EE.yml +1 -0
- data/config/locales/eu.yml +1 -6
- data/config/locales/fi-plain.yml +27 -5
- data/config/locales/fi.yml +40 -18
- data/config/locales/fr-CA.yml +175 -0
- data/config/locales/fr.yml +27 -5
- data/config/locales/ga-IE.yml +1 -0
- data/config/locales/gl.yml +1 -6
- data/config/locales/hr-HR.yml +1 -0
- data/config/locales/hu.yml +17 -6
- data/config/locales/id-ID.yml +1 -6
- data/config/locales/is-IS.yml +114 -0
- data/config/locales/it.yml +28 -6
- data/config/locales/ja-JP.yml +171 -0
- data/config/locales/lt-LT.yml +1 -0
- data/config/locales/lv-LV.yml +172 -0
- data/config/locales/mt-MT.yml +1 -0
- data/config/locales/nl.yml +32 -10
- data/config/locales/no.yml +160 -0
- data/config/locales/pl.yml +74 -52
- data/config/locales/pt-BR.yml +2 -7
- data/config/locales/pt.yml +64 -42
- data/config/locales/ro-RO.yml +179 -0
- data/config/locales/ru.yml +1 -6
- data/config/locales/sk-SK.yml +180 -0
- data/config/locales/sk.yml +175 -0
- data/config/locales/sl.yml +5 -0
- data/config/locales/sr-CS.yml +29 -0
- data/config/locales/sv.yml +27 -5
- data/config/locales/tr-TR.yml +1 -6
- data/config/locales/uk.yml +1 -6
- data/lib/decidim/budgets/admin_engine.rb +2 -0
- data/lib/decidim/budgets/component.rb +12 -0
- data/lib/decidim/budgets/seeds/city.jpeg +0 -0
- data/lib/decidim/budgets/test/factories.rb +33 -0
- data/lib/decidim/budgets/version.rb +1 -1
- metadata +55 -15
|
@@ -6,6 +6,9 @@ module Decidim
|
|
|
6
6
|
# This command is executed when the user changes a Project from the admin
|
|
7
7
|
# panel.
|
|
8
8
|
class UpdateProject < Rectify::Command
|
|
9
|
+
include ::Decidim::AttachmentMethods
|
|
10
|
+
include ::Decidim::GalleryMethods
|
|
11
|
+
|
|
9
12
|
# Initializes an UpdateProject Command.
|
|
10
13
|
#
|
|
11
14
|
# form - The form from which to get the data.
|
|
@@ -13,6 +16,7 @@ module Decidim
|
|
|
13
16
|
def initialize(form, project)
|
|
14
17
|
@form = form
|
|
15
18
|
@project = project
|
|
19
|
+
@attached_to = project
|
|
16
20
|
end
|
|
17
21
|
|
|
18
22
|
# Updates the project if valid.
|
|
@@ -21,9 +25,16 @@ module Decidim
|
|
|
21
25
|
def call
|
|
22
26
|
return broadcast(:invalid) if form.invalid?
|
|
23
27
|
|
|
28
|
+
if process_gallery?
|
|
29
|
+
build_gallery
|
|
30
|
+
return broadcast(:invalid) if gallery_invalid?
|
|
31
|
+
end
|
|
32
|
+
|
|
24
33
|
transaction do
|
|
25
34
|
update_project
|
|
26
35
|
link_proposals
|
|
36
|
+
create_gallery if process_gallery?
|
|
37
|
+
photo_cleanup!
|
|
27
38
|
end
|
|
28
39
|
|
|
29
40
|
broadcast(:ok)
|
|
@@ -31,7 +42,7 @@ module Decidim
|
|
|
31
42
|
|
|
32
43
|
private
|
|
33
44
|
|
|
34
|
-
attr_reader :project, :form
|
|
45
|
+
attr_reader :project, :form, :gallery
|
|
35
46
|
|
|
36
47
|
def update_project
|
|
37
48
|
Decidim.traceability.update!(
|
|
@@ -15,12 +15,16 @@ module Decidim
|
|
|
15
15
|
#
|
|
16
16
|
# Returns an Order.
|
|
17
17
|
def current_order
|
|
18
|
-
@current_order ||= Order.includes(:projects).
|
|
18
|
+
@current_order ||= Order.includes(:projects).find_or_initialize_by(user: current_user, component: current_component)
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
def current_order=(order)
|
|
22
22
|
@current_order = order
|
|
23
23
|
end
|
|
24
|
+
|
|
25
|
+
def persisted_current_order
|
|
26
|
+
current_order if current_order&.persisted?
|
|
27
|
+
end
|
|
24
28
|
end
|
|
25
29
|
end
|
|
26
30
|
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/concern"
|
|
4
|
+
|
|
5
|
+
module Decidim
|
|
6
|
+
module Budgets
|
|
7
|
+
# Common logic to sorting resources
|
|
8
|
+
module Orderable
|
|
9
|
+
extend ActiveSupport::Concern
|
|
10
|
+
|
|
11
|
+
included do
|
|
12
|
+
include Decidim::Orderable
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
# Available orders based on enabled settings
|
|
17
|
+
def available_orders
|
|
18
|
+
@available_orders ||= begin
|
|
19
|
+
available_orders = []
|
|
20
|
+
available_orders << "random" if voting_is_open? || !votes_are_visible?
|
|
21
|
+
available_orders << "most_voted" if votes_are_visible?
|
|
22
|
+
available_orders += %w(highest_cost lowest_cost)
|
|
23
|
+
available_orders
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def default_order
|
|
28
|
+
available_orders.first
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def voting_is_open?
|
|
32
|
+
current_settings.votes_enabled?
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def votes_are_visible?
|
|
36
|
+
current_settings.show_votes?
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def reorder(projects)
|
|
40
|
+
case order
|
|
41
|
+
when "highest_cost"
|
|
42
|
+
projects.order(budget: :desc)
|
|
43
|
+
when "lowest_cost"
|
|
44
|
+
projects.order(budget: :asc)
|
|
45
|
+
when "most_voted"
|
|
46
|
+
if votes_are_visible?
|
|
47
|
+
ids = projects.sort_by(&:confirmed_orders_count).map(&:id).reverse
|
|
48
|
+
projects.ordered_ids(ids)
|
|
49
|
+
else
|
|
50
|
+
projects
|
|
51
|
+
end
|
|
52
|
+
when "random"
|
|
53
|
+
projects.order_randomly(random_seed)
|
|
54
|
+
else
|
|
55
|
+
projects
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -5,12 +5,16 @@ module Decidim
|
|
|
5
5
|
module Admin
|
|
6
6
|
# This controller allows an admin to manage projects from a Participatory Process
|
|
7
7
|
class ProjectsController < Admin::ApplicationController
|
|
8
|
-
|
|
8
|
+
include Decidim::ApplicationHelper
|
|
9
|
+
include Decidim::Proposals::Admin::Picker
|
|
10
|
+
|
|
11
|
+
helper_method :projects, :finished_orders, :pending_orders, :present
|
|
9
12
|
|
|
10
13
|
def new
|
|
11
14
|
enforce_permission_to :create, :project
|
|
12
|
-
|
|
13
|
-
|
|
15
|
+
@form = form(ProjectForm).from_params(
|
|
16
|
+
attachment: form(AttachmentForm).instance
|
|
17
|
+
)
|
|
14
18
|
end
|
|
15
19
|
|
|
16
20
|
def create
|
|
@@ -33,13 +37,12 @@ module Decidim
|
|
|
33
37
|
|
|
34
38
|
def edit
|
|
35
39
|
enforce_permission_to :update, :project, project: project
|
|
36
|
-
|
|
37
40
|
@form = form(ProjectForm).from_model(project)
|
|
41
|
+
@form.attachment = form(AttachmentForm).instance
|
|
38
42
|
end
|
|
39
43
|
|
|
40
44
|
def update
|
|
41
45
|
enforce_permission_to :update, :project, project: project
|
|
42
|
-
|
|
43
46
|
@form = form(ProjectForm).from_params(params)
|
|
44
47
|
|
|
45
48
|
UpdateProject.call(@form, project) do
|
|
@@ -12,7 +12,7 @@ module Decidim
|
|
|
12
12
|
enforce_permission_to :vote, :project, project: project
|
|
13
13
|
|
|
14
14
|
respond_to do |format|
|
|
15
|
-
AddLineItem.call(
|
|
15
|
+
AddLineItem.call(persisted_current_order, project, current_user) do
|
|
16
16
|
on(:ok) do |order|
|
|
17
17
|
self.current_order = order
|
|
18
18
|
format.html { redirect_to :back }
|
|
@@ -7,13 +7,17 @@ module Decidim
|
|
|
7
7
|
include FilterResource
|
|
8
8
|
include NeedsCurrentOrder
|
|
9
9
|
include Orderable
|
|
10
|
+
include Decidim::Budgets::Orderable
|
|
10
11
|
|
|
11
12
|
helper_method :projects, :project
|
|
12
13
|
|
|
13
14
|
private
|
|
14
15
|
|
|
15
16
|
def projects
|
|
16
|
-
@projects
|
|
17
|
+
return @projects if @projects
|
|
18
|
+
|
|
19
|
+
@projects = search.results.page(params[:page]).per(current_component.settings.projects_per_page)
|
|
20
|
+
@projects = reorder(@projects)
|
|
17
21
|
end
|
|
18
22
|
|
|
19
23
|
def project
|
|
@@ -27,11 +31,27 @@ module Decidim
|
|
|
27
31
|
def default_filter_params
|
|
28
32
|
{
|
|
29
33
|
search_text: "",
|
|
30
|
-
scope_id:
|
|
31
|
-
category_id:
|
|
34
|
+
scope_id: default_filter_scope_params,
|
|
35
|
+
category_id: default_filter_category_params
|
|
32
36
|
}
|
|
33
37
|
end
|
|
34
38
|
|
|
39
|
+
def default_filter_category_params
|
|
40
|
+
return "all" unless current_component.participatory_space.categories.any?
|
|
41
|
+
|
|
42
|
+
["all"] + current_component.participatory_space.categories.map { |category| category.id.to_s }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def default_filter_scope_params
|
|
46
|
+
return "all" unless current_component.participatory_space.scopes.any?
|
|
47
|
+
|
|
48
|
+
if current_component.participatory_space.scope
|
|
49
|
+
["all", current_component.participatory_space.scope.id] + current_component.participatory_space.scope.children.map { |scope| scope.id.to_s }
|
|
50
|
+
else
|
|
51
|
+
%w(all global) + current_component.participatory_space.scopes.map { |scope| scope.id.to_s }
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
35
55
|
def context_params
|
|
36
56
|
{ component: current_component, organization: current_organization }
|
|
37
57
|
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module Budgets
|
|
5
|
+
module Admin
|
|
6
|
+
# A form object for the budgets component. Used to attach the component
|
|
7
|
+
# to a participatory process from the admin panel.
|
|
8
|
+
#
|
|
9
|
+
class ComponentForm < Decidim::Admin::ComponentForm
|
|
10
|
+
validate :budget_voting_rule_enabled_setting, :budget_voting_rule_value_setting
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
# Validations on budget settings:
|
|
15
|
+
# - a voting rule must be enabled.
|
|
16
|
+
def budget_voting_rule_enabled_setting
|
|
17
|
+
return unless manifest&.name == :budgets
|
|
18
|
+
|
|
19
|
+
i18n_error_scope = "decidim.components.budgets.settings.global.form.errors"
|
|
20
|
+
if settings.vote_rule_threshold_percent_enabled.blank? && settings.vote_rule_minimum_budget_projects_enabled.blank?
|
|
21
|
+
settings.errors.add(:vote_rule_threshold_percent_enabled, I18n.t(:budget_voting_rule_required, scope: i18n_error_scope))
|
|
22
|
+
settings.errors.add(:vote_rule_minimum_budget_projects_enabled, I18n.t(:budget_voting_rule_required, scope: i18n_error_scope))
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
if settings.vote_rule_threshold_percent_enabled && settings.vote_rule_minimum_budget_projects_enabled
|
|
26
|
+
settings.errors.add(:vote_rule_threshold_percent_enabled, I18n.t(:budget_voting_rule_only_one, scope: i18n_error_scope))
|
|
27
|
+
settings.errors.add(:vote_rule_minimum_budget_projects_enabled, I18n.t(:budget_voting_rule_only_one, scope: i18n_error_scope))
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# - the value must be a valid number
|
|
32
|
+
def budget_voting_rule_value_setting
|
|
33
|
+
return unless manifest&.name == :budgets
|
|
34
|
+
|
|
35
|
+
invalid_percent_number = settings.vote_threshold_percent.blank? || settings.vote_threshold_percent.to_i.negative?
|
|
36
|
+
settings.errors.add(:vote_threshold_percent) if settings.vote_rule_threshold_percent_enabled && invalid_percent_number
|
|
37
|
+
|
|
38
|
+
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 settings.vote_rule_minimum_budget_projects_enabled && invalid_minimum_number
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -16,6 +16,9 @@ module Decidim
|
|
|
16
16
|
attribute :decidim_scope_id, Integer
|
|
17
17
|
attribute :decidim_category_id, Integer
|
|
18
18
|
attribute :proposal_ids, Array[Integer]
|
|
19
|
+
attribute :attachment, AttachmentForm
|
|
20
|
+
attribute :photos, Array[String]
|
|
21
|
+
attribute :add_photos, Array
|
|
19
22
|
|
|
20
23
|
validates :title, translatable_presence: true
|
|
21
24
|
validates :description, translatable_presence: true
|
|
@@ -26,6 +29,8 @@ module Decidim
|
|
|
26
29
|
|
|
27
30
|
validate :scope_belongs_to_participatory_space_scope
|
|
28
31
|
|
|
32
|
+
validate :notify_missing_attachment_if_errored
|
|
33
|
+
|
|
29
34
|
delegate :categories, to: :current_component
|
|
30
35
|
|
|
31
36
|
def map_model(model)
|
|
@@ -38,9 +43,8 @@ module Decidim
|
|
|
38
43
|
|
|
39
44
|
def proposals
|
|
40
45
|
@proposals ||= Decidim.find_resource_manifest(:proposals).try(:resource_scope, current_component)
|
|
41
|
-
&.
|
|
46
|
+
&.where(id: proposal_ids)
|
|
42
47
|
&.order(title: :asc)
|
|
43
|
-
&.map { |proposal| [present(proposal).title, proposal.id] }
|
|
44
48
|
end
|
|
45
49
|
|
|
46
50
|
# Finds the Category from the decidim_category_id.
|
|
@@ -69,6 +73,14 @@ module Decidim
|
|
|
69
73
|
def scope_belongs_to_participatory_space_scope
|
|
70
74
|
errors.add(:decidim_scope_id, :invalid) if current_participatory_space.out_of_scope?(scope)
|
|
71
75
|
end
|
|
76
|
+
|
|
77
|
+
# This method will add an error to the `attachment` field only if there's
|
|
78
|
+
# any error in any other field. This is needed because when the form has
|
|
79
|
+
# an error, the attachment is lost, so we need a way to inform the user of
|
|
80
|
+
# this problem.
|
|
81
|
+
def notify_missing_attachment_if_errored
|
|
82
|
+
errors.add(:add_photos, :needs_to_be_reattached) if errors.any? && add_photos.present?
|
|
83
|
+
end
|
|
72
84
|
end
|
|
73
85
|
end
|
|
74
86
|
end
|
|
@@ -16,6 +16,19 @@ module Decidim
|
|
|
16
16
|
current_order&.budget_percent.to_f.floor
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
+
# Return the minimum percentage of the current order budget from the total budget
|
|
20
|
+
def current_order_budget_percent_minimum
|
|
21
|
+
return 0 if current_order.minimum_projects_rule?
|
|
22
|
+
|
|
23
|
+
component_settings.vote_threshold_percent
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def budget_confirm_disabled_attr
|
|
27
|
+
return if current_order_can_be_checked_out?
|
|
28
|
+
|
|
29
|
+
%( disabled="disabled" ).html_safe
|
|
30
|
+
end
|
|
31
|
+
|
|
19
32
|
# Return true if the current order is checked out
|
|
20
33
|
delegate :checked_out?, to: :current_order, prefix: true, allow_nil: true
|
|
21
34
|
|
|
@@ -23,6 +36,10 @@ module Decidim
|
|
|
23
36
|
def current_order_can_be_checked_out?
|
|
24
37
|
current_order&.can_checkout?
|
|
25
38
|
end
|
|
39
|
+
|
|
40
|
+
def projects_base_url
|
|
41
|
+
URI.parse(root_url).tap { |uri| uri.query = uri.fragment = nil } .to_s
|
|
42
|
+
end
|
|
26
43
|
end
|
|
27
44
|
end
|
|
28
45
|
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module Budgets
|
|
5
|
+
class SendOrderSummaryJob < ApplicationJob
|
|
6
|
+
queue_as :default
|
|
7
|
+
|
|
8
|
+
def perform(order)
|
|
9
|
+
return if order&.user&.email.blank?
|
|
10
|
+
|
|
11
|
+
OrderSummaryMailer.order_summary(order).deliver_now
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module Budgets
|
|
5
|
+
class OrderSummaryMailer < Decidim::ApplicationMailer
|
|
6
|
+
include Decidim::TranslationsHelper
|
|
7
|
+
include Decidim::SanitizeHelper
|
|
8
|
+
|
|
9
|
+
helper Decidim::TranslationsHelper
|
|
10
|
+
|
|
11
|
+
# Send an email to an user with the summary of the order.
|
|
12
|
+
#
|
|
13
|
+
# order - the order that was just created
|
|
14
|
+
def order_summary(order)
|
|
15
|
+
user = order.user
|
|
16
|
+
|
|
17
|
+
with_user(user) do
|
|
18
|
+
@user = user
|
|
19
|
+
@order = order
|
|
20
|
+
@space = order.participatory_space
|
|
21
|
+
@component = order.component
|
|
22
|
+
@organization = order.participatory_space.organization
|
|
23
|
+
|
|
24
|
+
subject = I18n.t(
|
|
25
|
+
"order_summary.subject",
|
|
26
|
+
scope: "decidim.budgets.order_summary_mailer",
|
|
27
|
+
space_name: translated_attribute(@space.title)
|
|
28
|
+
)
|
|
29
|
+
mail(to: user.email, subject: subject)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -27,6 +27,8 @@ module Decidim
|
|
|
27
27
|
less_than_or_equal_to: :maximum_budget
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
validate :reach_minimum_projects, if: :checked_out?
|
|
31
|
+
|
|
30
32
|
scope :finished, -> { where.not(checked_out_at: nil) }
|
|
31
33
|
scope :pending, -> { where(checked_out_at: nil) }
|
|
32
34
|
|
|
@@ -42,7 +44,11 @@ module Decidim
|
|
|
42
44
|
|
|
43
45
|
# Public: Check if the order total budget is enough to checkout
|
|
44
46
|
def can_checkout?
|
|
45
|
-
|
|
47
|
+
if minimum_projects_rule?
|
|
48
|
+
projects.count >= minimum_projects
|
|
49
|
+
else
|
|
50
|
+
total_budget.to_f >= minimum_budget
|
|
51
|
+
end
|
|
46
52
|
end
|
|
47
53
|
|
|
48
54
|
# Public: Returns the order budget percent from the settings total budget
|
|
@@ -53,6 +59,7 @@ module Decidim
|
|
|
53
59
|
# Public: Returns the required minimum budget to checkout
|
|
54
60
|
def minimum_budget
|
|
55
61
|
return 0 unless component
|
|
62
|
+
return 0 if minimum_projects_rule?
|
|
56
63
|
|
|
57
64
|
component.settings.total_budget.to_f * (component.settings.vote_threshold_percent.to_f / 100)
|
|
58
65
|
end
|
|
@@ -64,6 +71,20 @@ module Decidim
|
|
|
64
71
|
component.settings.total_budget.to_f
|
|
65
72
|
end
|
|
66
73
|
|
|
74
|
+
# Public: Returns if it is required a minimum projects limit to checkout
|
|
75
|
+
def minimum_projects_rule?
|
|
76
|
+
return unless component
|
|
77
|
+
|
|
78
|
+
component.settings.vote_rule_minimum_budget_projects_enabled
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Public: Returns the required minimum projects to checkout
|
|
82
|
+
def minimum_projects
|
|
83
|
+
return 0 unless component
|
|
84
|
+
|
|
85
|
+
component.settings.vote_minimum_budget_projects_number
|
|
86
|
+
end
|
|
87
|
+
|
|
67
88
|
def self.user_collection(user)
|
|
68
89
|
where(decidim_user_id: user.id)
|
|
69
90
|
end
|
|
@@ -87,6 +108,12 @@ module Decidim
|
|
|
87
108
|
|
|
88
109
|
errors.add(:user, :invalid) unless user.organization == organization
|
|
89
110
|
end
|
|
111
|
+
|
|
112
|
+
def reach_minimum_projects
|
|
113
|
+
return unless minimum_projects_rule?
|
|
114
|
+
|
|
115
|
+
errors.add(:projects, :invalid) if minimum_projects > projects.count
|
|
116
|
+
end
|
|
90
117
|
end
|
|
91
118
|
end
|
|
92
119
|
end
|