decidim-budgets 0.22.0 → 0.23.3

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.
Files changed (173) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +38 -3
  3. data/app/assets/stylesheets/decidim/budgets/budget/_budget-list.scss +5 -0
  4. data/app/cells/decidim/budgets/base_cell.rb +22 -0
  5. data/app/cells/decidim/budgets/budget_cell.rb +21 -0
  6. data/app/cells/decidim/budgets/budget_information_modal/show.erb +28 -0
  7. data/app/cells/decidim/budgets/budget_information_modal_cell.rb +22 -0
  8. data/app/cells/decidim/budgets/budget_list_item/show.erb +22 -0
  9. data/app/cells/decidim/budgets/budget_list_item_cell.rb +40 -0
  10. data/app/cells/decidim/budgets/budget_m/data.erb +12 -0
  11. data/app/cells/decidim/budgets/budget_m/footer.erb +5 -0
  12. data/app/cells/decidim/budgets/budget_m_cell.rb +16 -0
  13. data/app/cells/decidim/budgets/budgets_header/show.erb +7 -0
  14. data/app/cells/decidim/budgets/budgets_header_cell.rb +14 -0
  15. data/app/cells/decidim/budgets/budgets_list/card_list.erb +7 -0
  16. data/app/cells/decidim/budgets/budgets_list/highlighted.erb +11 -0
  17. data/app/cells/decidim/budgets/budgets_list/show.erb +20 -0
  18. data/app/cells/decidim/budgets/budgets_list/voted.erb +43 -0
  19. data/app/cells/decidim/budgets/budgets_list_cell.rb +39 -0
  20. data/app/cells/decidim/budgets/limit_announcement_cell.rb +52 -0
  21. data/app/cells/decidim/budgets/project_list_item/project_data.erb +17 -3
  22. data/app/cells/decidim/budgets/project_list_item/project_data_vote_button.erb +2 -2
  23. data/app/cells/decidim/budgets/project_list_item/project_text.erb +11 -5
  24. data/app/cells/decidim/budgets/project_list_item/show.erb +3 -3
  25. data/app/cells/decidim/budgets/project_list_item_cell.rb +8 -28
  26. data/app/cells/decidim/budgets/project_m/data.erb +1 -1
  27. data/app/cells/decidim/budgets/project_m_cell.rb +4 -0
  28. data/app/cells/decidim/budgets/project_selected_status_cell.rb +28 -0
  29. data/app/cells/decidim/budgets/project_tags/show.erb +5 -0
  30. data/app/cells/decidim/budgets/project_tags_cell.rb +18 -0
  31. data/app/cells/decidim/budgets/project_voted_hint_cell.rb +33 -0
  32. data/app/cells/decidim/budgets/project_votes_count_cell.rb +44 -0
  33. data/app/commands/decidim/budgets/add_line_item.rb +7 -10
  34. data/app/commands/decidim/budgets/admin/create_budget.rb +48 -0
  35. data/app/commands/decidim/budgets/admin/create_project.rb +12 -7
  36. data/app/commands/decidim/budgets/admin/destroy_budget.rb +42 -0
  37. data/app/commands/decidim/budgets/admin/import_proposals_to_budgets.rb +26 -25
  38. data/app/commands/decidim/budgets/admin/update_budget.rb +48 -0
  39. data/app/commands/decidim/budgets/admin/update_project.rb +8 -1
  40. data/app/commands/decidim/budgets/checkout.rb +6 -6
  41. data/app/commands/decidim/budgets/remove_line_item.rb +3 -2
  42. data/app/controllers/concerns/decidim/budgets/needs_current_order.rb +14 -2
  43. data/app/controllers/concerns/decidim/budgets/orderable.rb +3 -7
  44. data/app/controllers/decidim/budgets/admin/application_controller.rb +10 -2
  45. data/app/controllers/decidim/budgets/admin/attachment_collections_controller.rb +1 -1
  46. data/app/controllers/decidim/budgets/admin/attachments_controller.rb +2 -2
  47. data/app/controllers/decidim/budgets/admin/budgets_controller.rb +82 -0
  48. data/app/controllers/decidim/budgets/admin/projects_controller.rb +7 -7
  49. data/app/controllers/decidim/budgets/admin/proposals_imports_controller.rb +10 -2
  50. data/app/controllers/decidim/budgets/application_controller.rb +23 -0
  51. data/app/controllers/decidim/budgets/budgets_controller.rb +24 -0
  52. data/app/controllers/decidim/budgets/line_items_controller.rb +9 -5
  53. data/app/controllers/decidim/budgets/orders_controller.rb +20 -6
  54. data/app/controllers/decidim/budgets/projects_controller.rb +19 -18
  55. data/app/forms/decidim/budgets/admin/budget_form.rb +39 -0
  56. data/app/forms/decidim/budgets/admin/project_form.rb +14 -10
  57. data/app/forms/decidim/budgets/admin/project_import_proposals_form.rb +4 -0
  58. data/app/helpers/decidim/budgets/admin/application_helper.rb +13 -0
  59. data/app/helpers/decidim/budgets/application_helper.rb +10 -0
  60. data/app/helpers/decidim/budgets/projects_helper.rb +0 -4
  61. data/app/mailers/decidim/budgets/order_summary_mailer.rb +5 -3
  62. data/app/models/decidim/budgets/budget.rb +34 -0
  63. data/app/models/decidim/budgets/line_item.rb +4 -4
  64. data/app/models/decidim/budgets/order.rb +23 -19
  65. data/app/models/decidim/budgets/project.rb +34 -5
  66. data/app/permissions/decidim/budgets/admin/permissions.rb +23 -10
  67. data/app/permissions/decidim/budgets/permissions.rb +28 -6
  68. data/app/presenters/decidim/budgets/admin_log/budget_presenter.rb +42 -0
  69. data/app/queries/decidim/budgets/filtered_projects.rb +9 -1
  70. data/app/queries/decidim/budgets/metrics/budget_followers_metric_measure.rb +3 -2
  71. data/app/queries/decidim/budgets/metrics/budget_participants_metric_measure.rb +6 -5
  72. data/app/serializers/decidim/budgets/data_portability_budgets_order_serializer.rb +3 -2
  73. data/app/services/decidim/budgets/project_search.rb +12 -24
  74. data/app/types/decidim/budgets/budget_type.rb +24 -0
  75. data/app/types/decidim/budgets/budgets_type.rb +6 -6
  76. data/app/types/decidim/budgets/project_type.rb +2 -1
  77. data/app/views/decidim/budgets/admin/budgets/_form.html.erb +23 -0
  78. data/app/views/decidim/budgets/admin/budgets/edit.html.erb +7 -0
  79. data/app/views/decidim/budgets/admin/budgets/index.html.erb +58 -0
  80. data/app/views/decidim/budgets/admin/budgets/new.html.erb +7 -0
  81. data/app/views/decidim/budgets/admin/projects/_form.html.erb +12 -4
  82. data/app/views/decidim/budgets/admin/projects/edit.html.erb +2 -2
  83. data/app/views/decidim/budgets/admin/projects/index.html.erb +20 -7
  84. data/app/views/decidim/budgets/admin/projects/new.html.erb +2 -2
  85. data/app/views/decidim/budgets/admin/proposals_imports/new.html.erb +1 -1
  86. data/app/views/decidim/budgets/budgets/index.html.erb +5 -0
  87. data/app/views/decidim/budgets/order_summary_mailer/order_summary.html.erb +1 -0
  88. data/app/views/decidim/budgets/projects/_budget_confirm.html.erb +3 -3
  89. data/app/views/decidim/budgets/projects/_budget_summary.html.erb +19 -6
  90. data/app/views/decidim/budgets/projects/_filters.html.erb +6 -2
  91. data/app/views/decidim/budgets/projects/_linked_projects.html.erb +1 -1
  92. data/app/views/decidim/budgets/projects/_order_progress.html.erb +10 -6
  93. data/app/views/decidim/budgets/projects/_order_selected_projects.html.erb +3 -3
  94. data/app/views/decidim/budgets/projects/_project_budget_button.html.erb +36 -7
  95. data/app/views/decidim/budgets/projects/index.html.erb +12 -4
  96. data/app/views/decidim/budgets/projects/show.html.erb +22 -13
  97. data/config/locales/am-ET.yml +1 -0
  98. data/config/locales/ar.yml +2 -11
  99. data/config/locales/bg.yml +6 -0
  100. data/config/locales/ca.yml +102 -10
  101. data/config/locales/cs.yml +108 -16
  102. data/config/locales/da.yml +1 -0
  103. data/config/locales/de.yml +120 -28
  104. data/config/locales/el.yml +3 -9
  105. data/config/locales/en.yml +101 -9
  106. data/config/locales/eo.yml +1 -0
  107. data/config/locales/es-MX.yml +101 -9
  108. data/config/locales/es-PY.yml +101 -9
  109. data/config/locales/es.yml +102 -10
  110. data/config/locales/et.yml +1 -0
  111. data/config/locales/eu.yml +5 -8
  112. data/config/locales/fi-plain.yml +102 -10
  113. data/config/locales/fi.yml +103 -11
  114. data/config/locales/fr-CA.yml +101 -9
  115. data/config/locales/fr.yml +101 -9
  116. data/config/locales/gl.yml +70 -10
  117. data/config/locales/hr.yml +1 -0
  118. data/config/locales/hu.yml +2 -7
  119. data/config/locales/id-ID.yml +2 -6
  120. data/config/locales/is-IS.yml +0 -6
  121. data/config/locales/is.yml +114 -0
  122. data/config/locales/it.yml +71 -9
  123. data/config/locales/ja-JP.yml +1 -0
  124. data/config/locales/ja.yml +262 -0
  125. data/config/locales/ko-KR.yml +1 -0
  126. data/config/locales/ko.yml +1 -0
  127. data/config/locales/lt.yml +1 -0
  128. data/config/locales/{lv-LV.yml → lv.yml} +2 -10
  129. data/config/locales/mt.yml +1 -0
  130. data/config/locales/nl.yml +88 -10
  131. data/config/locales/no.yml +25 -9
  132. data/config/locales/om-ET.yml +1 -0
  133. data/config/locales/pl.yml +114 -22
  134. data/config/locales/pt-BR.yml +2 -7
  135. data/config/locales/pt.yml +3 -9
  136. data/config/locales/ro-RO.yml +3 -10
  137. data/config/locales/ru.yml +2 -9
  138. data/config/locales/si-LK.yml +1 -0
  139. data/config/locales/sk.yml +2 -11
  140. data/config/locales/sl.yml +0 -4
  141. data/config/locales/so-SO.yml +1 -0
  142. data/config/locales/sr-CS.yml +0 -2
  143. data/config/locales/sv.yml +101 -9
  144. data/config/locales/sw-KE.yml +1 -0
  145. data/config/locales/ti-ER.yml +1 -0
  146. data/config/locales/tr-TR.yml +153 -34
  147. data/config/locales/uk.yml +2 -9
  148. data/config/locales/vi-VN.yml +1 -0
  149. data/config/locales/vi.yml +1 -0
  150. data/config/locales/zh-CN.yml +260 -0
  151. data/config/locales/zh-TW.yml +1 -0
  152. data/db/migrate/20200617105120_create_decidim_budgets.rb +15 -0
  153. data/db/migrate/20200629072626_rename_budget_to_budget_ammount.rb +7 -0
  154. data/db/migrate/20200629134013_add_budget_reference_to_project.rb +7 -0
  155. data/db/migrate/20200706142609_add_budget_reference_to_order.rb +7 -0
  156. data/db/migrate/20200714103519_move_budgets_to_own_model.rb +109 -0
  157. data/db/migrate/20200717140012_add_scope_to_budgets.rb +7 -0
  158. data/db/migrate/20200728075039_add_selected_at_to_project.rb +7 -0
  159. data/db/migrate/20200804175222_votes_enabled_to_votes_choices.rb +35 -0
  160. data/db/migrate/20200827154129_add_commentable_counter_cache_to_projects.rb +9 -0
  161. data/lib/decidim/budgets.rb +1 -0
  162. data/lib/decidim/budgets/admin_engine.rb +10 -5
  163. data/lib/decidim/budgets/component.rb +83 -38
  164. data/lib/decidim/budgets/engine.rb +8 -6
  165. data/lib/decidim/budgets/test/factories.rb +42 -13
  166. data/lib/decidim/budgets/version.rb +1 -1
  167. data/lib/decidim/budgets/workflows.rb +17 -0
  168. data/lib/decidim/budgets/workflows/all.rb +20 -0
  169. data/lib/decidim/budgets/workflows/base.rb +132 -0
  170. data/lib/decidim/budgets/workflows/one.rb +33 -0
  171. metadata +89 -20
  172. data/app/cells/decidim/budgets/project_list_item/project_data_number.erb +0 -3
  173. data/app/cells/decidim/budgets/project_list_item/project_data_votes.erb +0 -7
@@ -9,6 +9,16 @@ module Decidim
9
9
  include Decidim::Comments::CommentsHelper
10
10
  include ProjectsHelper
11
11
  include Decidim::CheckBoxesTreeHelper
12
+
13
+ def filter_status_values
14
+ TreeNode.new(
15
+ TreePoint.new("", t("decidim.budgets.projects.filters.status_values.all")),
16
+ [
17
+ TreePoint.new("selected", t("decidim.budgets.projects.filters.status_values.selected")),
18
+ TreePoint.new("not_selected", t("decidim.budgets.projects.filters.status_values.not_selected"))
19
+ ]
20
+ )
21
+ end
12
22
  end
13
23
  end
14
24
  end
@@ -36,10 +36,6 @@ module Decidim
36
36
  def current_order_can_be_checked_out?
37
37
  current_order&.can_checkout?
38
38
  end
39
-
40
- def projects_base_url
41
- URI.parse(root_url).tap { |uri| uri.query = uri.fragment = nil } .to_s
42
- end
43
39
  end
44
40
  end
45
41
  end
@@ -17,13 +17,15 @@ module Decidim
17
17
  with_user(user) do
18
18
  @user = user
19
19
  @order = order
20
- @space = order.participatory_space
21
- @component = order.component
22
- @organization = order.participatory_space.organization
20
+ @budget = order.budget
21
+ @space = order.budget.participatory_space
22
+ @component = order.budget.component
23
+ @organization = order.budget.participatory_space.organization
23
24
 
24
25
  subject = I18n.t(
25
26
  "order_summary.subject",
26
27
  scope: "decidim.budgets.order_summary_mailer",
28
+ budget_name: translated_attribute(@budget.title),
27
29
  space_name: translated_attribute(@space.title)
28
30
  )
29
31
  mail(to: user.email, subject: subject)
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Budgets
5
+ # The data store for a budget in the Decidim::Budgets component.
6
+ class Budget < ApplicationRecord
7
+ include Decidim::Resourceable
8
+ include Decidim::ScopableResource
9
+ include Decidim::HasComponent
10
+ include Decidim::Searchable
11
+ include Traceable
12
+ include Loggable
13
+
14
+ component_manifest_name "budgets"
15
+
16
+ has_many :projects, foreign_key: "decidim_budgets_budget_id", class_name: "Decidim::Budgets::Project", inverse_of: :budget, dependent: :destroy
17
+ has_many :orders, foreign_key: "decidim_budgets_budget_id", class_name: "Decidim::Budgets::Order", inverse_of: :budget, dependent: :destroy
18
+
19
+ delegate :participatory_space, :manifest, :settings, to: :component
20
+
21
+ searchable_fields({
22
+ participatory_space: { component: :participatory_space },
23
+ A: :title,
24
+ D: [:description, :total_budget]
25
+ },
26
+ index_on_create: ->(budget) { budget.visible? },
27
+ index_on_update: ->(budget) { budget.visible? })
28
+
29
+ def self.log_presenter_class_for(_log)
30
+ Decidim::Budgets::AdminLog::BudgetPresenter
31
+ end
32
+ end
33
+ end
34
+ end
@@ -2,19 +2,19 @@
2
2
 
3
3
  module Decidim
4
4
  module Budgets
5
- # The data store for a LineItem in the Decidim::Budgets component. It describes an
5
+ # The data store for a LineItem in the Budget resource. It describes an
6
6
  # association between an order and a project.
7
7
  class LineItem < Budgets::ApplicationRecord
8
8
  belongs_to :order, class_name: "Decidim::Budgets::Order", foreign_key: "decidim_order_id"
9
9
  belongs_to :project, class_name: "Decidim::Budgets::Project", foreign_key: "decidim_project_id"
10
10
 
11
11
  validates :order, uniqueness: { scope: :project }
12
- validate :same_component
12
+ validate :same_budget
13
13
 
14
- def same_component
14
+ def same_budget
15
15
  return unless order && project
16
16
 
17
- errors.add(:order, :invalid) unless order.component == project.component
17
+ errors.add(:order, :invalid) unless order.budget == project.budget
18
18
  end
19
19
  end
20
20
  end
@@ -5,18 +5,17 @@ module Decidim
5
5
  # The data store for a Order in the Decidim::Budgets component. It is unique for each
6
6
  # user and component and contains a collection of projects
7
7
  class Order < Budgets::ApplicationRecord
8
- include Decidim::HasComponent
9
8
  include Decidim::DataPortability
10
9
  include Decidim::NewsletterParticipant
11
10
 
12
- component_manifest_name "budgets"
13
-
14
11
  belongs_to :user, class_name: "Decidim::User", foreign_key: "decidim_user_id"
15
-
12
+ belongs_to :budget, foreign_key: "decidim_budgets_budget_id", class_name: "Decidim::Budgets::Budget", inverse_of: :orders
13
+ has_one :component, through: :budget, foreign_key: "decidim_component_id", class_name: "Decidim::Component"
16
14
  has_many :line_items, class_name: "Decidim::Budgets::LineItem", foreign_key: "decidim_order_id", dependent: :destroy
17
15
  has_many :projects, through: :line_items, class_name: "Decidim::Budgets::Project", foreign_key: "decidim_project_id"
18
16
 
19
- validates :user, uniqueness: { scope: :component }
17
+ validates :user, uniqueness: { scope: :budget }
18
+ validates :budget, presence: true
20
19
  validate :user_belongs_to_organization
21
20
 
22
21
  validates :total_budget, numericality: {
@@ -34,7 +33,7 @@ module Decidim
34
33
 
35
34
  # Public: Returns the sum of project budgets
36
35
  def total_budget
37
- projects.to_a.sum(&:budget)
36
+ projects.to_a.sum(&:budget_amount)
38
37
  end
39
38
 
40
39
  # Public: Returns true if the order has been checked out
@@ -53,36 +52,36 @@ module Decidim
53
52
 
54
53
  # Public: Returns the order budget percent from the settings total budget
55
54
  def budget_percent
56
- (total_budget.to_f / component.settings.total_budget.to_f) * 100
55
+ (total_budget.to_f / budget.total_budget.to_f) * 100
57
56
  end
58
57
 
59
58
  # Public: Returns the required minimum budget to checkout
60
59
  def minimum_budget
61
- return 0 unless component
60
+ return 0 unless budget
62
61
  return 0 if minimum_projects_rule?
63
62
 
64
- component.settings.total_budget.to_f * (component.settings.vote_threshold_percent.to_f / 100)
63
+ budget.total_budget.to_f * (budget.settings.vote_threshold_percent.to_f / 100)
65
64
  end
66
65
 
67
66
  # Public: Returns the required maximum budget to checkout
68
67
  def maximum_budget
69
- return 0 unless component
68
+ return 0 unless budget
70
69
 
71
- component.settings.total_budget.to_f
70
+ budget.total_budget.to_f
72
71
  end
73
72
 
74
73
  # Public: Returns if it is required a minimum projects limit to checkout
75
74
  def minimum_projects_rule?
76
- return unless component
75
+ return unless budget
77
76
 
78
- component.settings.vote_rule_minimum_budget_projects_enabled
77
+ budget.settings.vote_rule_minimum_budget_projects_enabled
79
78
  end
80
79
 
81
80
  # Public: Returns the required minimum projects to checkout
82
81
  def minimum_projects
83
- return 0 unless component
82
+ return 0 unless budget
84
83
 
85
- component.settings.vote_minimum_budget_projects_number
84
+ budget.settings.vote_minimum_budget_projects_number
86
85
  end
87
86
 
88
87
  def self.user_collection(user)
@@ -94,15 +93,20 @@ module Decidim
94
93
  end
95
94
 
96
95
  def self.newsletter_participant_ids(component)
97
- Decidim::Budgets::Order.where(component: component).joins(:component)
98
- .finished
99
- .pluck(:decidim_user_id).flatten.compact.uniq
96
+ Decidim::Budgets::Order.finished
97
+ .joins(budget: [:component])
98
+ .where(budget: {
99
+ decidim_components: { id: component.id }
100
+ })
101
+ .group(:decidim_user_id)
102
+ .pluck(:decidim_user_id)
103
+ .flatten.compact
100
104
  end
101
105
 
102
106
  private
103
107
 
104
108
  def user_belongs_to_organization
105
- organization = component&.organization
109
+ organization = budget.try(:component).try(:organization)
106
110
 
107
111
  return if !user || !organization
108
112
 
@@ -6,8 +6,7 @@ module Decidim
6
6
  # title, description and any other useful information to render a custom project.
7
7
  class Project < Budgets::ApplicationRecord
8
8
  include Decidim::Resourceable
9
- include Decidim::HasComponent
10
- include Decidim::ScopableComponent
9
+ include Decidim::ScopableResource
11
10
  include Decidim::HasCategory
12
11
  include Decidim::HasAttachments
13
12
  include Decidim::HasAttachmentCollections
@@ -18,11 +17,17 @@ module Decidim
18
17
  include Decidim::Loggable
19
18
  include Decidim::Randomable
20
19
  include Decidim::Searchable
20
+ include Decidim::TranslatableResource
21
21
 
22
- component_manifest_name "budgets"
22
+ translatable_fields :title, :description
23
+
24
+ belongs_to :budget, foreign_key: "decidim_budgets_budget_id", class_name: "Decidim::Budgets::Budget", inverse_of: :projects
25
+ has_one :component, through: :budget, foreign_key: "decidim_component_id", class_name: "Decidim::Component"
23
26
  has_many :line_items, class_name: "Decidim::Budgets::LineItem", foreign_key: "decidim_project_id", dependent: :destroy
24
27
  has_many :orders, through: :line_items, foreign_key: "decidim_project_id", class_name: "Decidim::Budgets::Order"
25
28
 
29
+ delegate :organization, :participatory_space, to: :component
30
+
26
31
  searchable_fields(
27
32
  scope_id: :decidim_scope_id,
28
33
  participatory_space: { component: :participatory_space },
@@ -32,13 +37,25 @@ module Decidim
32
37
  )
33
38
 
34
39
  def self.ordered_ids(ids)
35
- order(Arel.sql("position(id::text in '#{ids.join(",")}')"))
40
+ # Make sure each ID in the matching text has a "," character as their
41
+ # delimiter. Otherwise e.g. ID 2 would match ID "26" in the original
42
+ # array. This is why we search for match ",2," instead to get the actual
43
+ # position for ID 2.
44
+ order(Arel.sql("position(concat(',', id::text, ',') in ',#{ids.join(",")},')"))
36
45
  end
37
46
 
38
47
  def self.log_presenter_class_for(_log)
39
48
  Decidim::Budgets::AdminLog::ProjectPresenter
40
49
  end
41
50
 
51
+ def polymorphic_resource_path(url_params)
52
+ ::Decidim::ResourceLocatorPresenter.new([budget, self]).path(url_params)
53
+ end
54
+
55
+ def polymorphic_resource_url(url_params)
56
+ ::Decidim::ResourceLocatorPresenter.new([budget, self]).url(url_params)
57
+ end
58
+
42
59
  # Public: Overrides the `commentable?` Commentable concern method.
43
60
  def commentable?
44
61
  component.settings.comments_enabled?
@@ -71,7 +88,19 @@ module Decidim
71
88
 
72
89
  # Public: Whether the object can have new comments or not.
73
90
  def user_allowed_to_comment?(user)
74
- can_participate_in_space?(user)
91
+ component.can_participate_in_space?(user)
92
+ end
93
+
94
+ # Public: Checks if the project has been selected or not.
95
+ #
96
+ # Returns Boolean.
97
+ def selected?
98
+ selected_at.present?
99
+ end
100
+
101
+ # Public: Returns the attachment context for this record.
102
+ def attachment_context
103
+ :admin
75
104
  end
76
105
  end
77
106
  end
@@ -5,18 +5,27 @@ module Decidim
5
5
  module Admin
6
6
  class Permissions < Decidim::DefaultPermissions
7
7
  def permissions
8
- # The public part needs to be implemented yet
9
8
  return permission_action if permission_action.scope != :admin
10
9
 
11
- return permission_action unless [:project, :projects].include?(permission_action.subject)
12
-
13
- case permission_action.action
14
- when :create
15
- permission_action.allow!
16
- when :import_proposals
17
- permission_action.allow!
18
- when :update, :destroy
19
- permission_action.allow! if project.present?
10
+ case permission_action.subject
11
+ when :budget
12
+ case permission_action.action
13
+ when :create, :read
14
+ allow!
15
+ when :update
16
+ toggle_allow(budget)
17
+ when :delete, :publish, :unpublish
18
+ toggle_allow(budget && budget.projects.empty?)
19
+ end
20
+ when :project, :projects
21
+ case permission_action.action
22
+ when :create
23
+ permission_action.allow!
24
+ when :import_proposals
25
+ permission_action.allow!
26
+ when :update, :destroy
27
+ permission_action.allow! if project.present?
28
+ end
20
29
  end
21
30
 
22
31
  permission_action
@@ -24,6 +33,10 @@ module Decidim
24
33
 
25
34
  private
26
35
 
36
+ def budget
37
+ @budget ||= context.fetch(:budget, nil)
38
+ end
39
+
27
40
  def project
28
41
  @project ||= context.fetch(:project, nil)
29
42
  end
@@ -10,15 +10,19 @@ module Decidim
10
10
  return Decidim::Budgets::Admin::Permissions.new(user, permission_action, context).permissions if permission_action.scope == :admin
11
11
  return permission_action if permission_action.scope != :public
12
12
 
13
- return permission_action if permission_action.subject != :project
13
+ return permission_action unless [:project, :order].include? permission_action.subject
14
14
 
15
- case permission_action.action
16
- when :vote
17
- can_vote_project?(project || order&.projects&.first)
18
- when :report
19
- permission_action.allow!
15
+ if permission_action.subject == :project
16
+ case permission_action.action
17
+ when :vote
18
+ can_vote?(false) if can_vote_project?(project || order&.projects&.first)
19
+ when :report
20
+ permission_action.allow!
21
+ end
20
22
  end
21
23
 
24
+ can_vote?(true) if permission_action.action == :create && permission_action.subject == :order
25
+
22
26
  permission_action
23
27
  end
24
28
 
@@ -32,6 +36,24 @@ module Decidim
32
36
  @order ||= context.fetch(:order, nil)
33
37
  end
34
38
 
39
+ def budget
40
+ @budget ||= context.fetch(:budget, nil)
41
+ end
42
+
43
+ def workflow
44
+ @workflow ||= context.fetch(:workflow, nil)
45
+ end
46
+
47
+ def can_vote?(active_allow)
48
+ is_allowed = workflow.vote_allowed?(budget)
49
+
50
+ if !is_allowed
51
+ disallow!
52
+ elsif active_allow
53
+ allow!
54
+ end
55
+ end
56
+
35
57
  def can_vote_project?(a_project)
36
58
  is_allowed = a_project && authorized?(:vote, resource: project)
37
59
 
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Budgets
5
+ module AdminLog
6
+ # This class holds the logic to present a `Decidim::Budgets::Budget`
7
+ # for the `AdminLog` log.
8
+ #
9
+ # Usage should be automatic and you shouldn't need to call this class
10
+ # directly, but here's an example:
11
+ #
12
+ # action_log = Decidim::ActionLog.last
13
+ # view_helpers # => this comes from the views
14
+ # BudgetPresenter.new(action_log, view_helpers).present
15
+ class BudgetPresenter < Decidim::Log::BasePresenter
16
+ private
17
+
18
+ def action_string
19
+ case action
20
+ when "create", "delete", "update"
21
+ "decidim.budgets.admin_log.budget.#{action}"
22
+ else
23
+ super
24
+ end
25
+ end
26
+
27
+ def diff_fields_mapping
28
+ {
29
+ title: :i18n,
30
+ weight: :integer,
31
+ description: :i18n,
32
+ total_budget: :currency
33
+ }
34
+ end
35
+
36
+ def i18n_labels_scope
37
+ "activemodel.attributes.budget"
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -27,11 +27,19 @@ module Decidim
27
27
  # Finds the Projects scoped to an array of components and filtered
28
28
  # by a range of dates.
29
29
  def query
30
- projects = Decidim::Budgets::Project.where(component: @components)
30
+ projects = Decidim::Budgets::Project.where(budget: budgets)
31
31
  projects = projects.where("created_at >= ?", @start_at) if @start_at.present?
32
32
  projects = projects.where("created_at <= ?", @end_at) if @end_at.present?
33
33
  projects
34
34
  end
35
+
36
+ private
37
+
38
+ attr_reader :components
39
+
40
+ def budgets
41
+ @budgets ||= Decidim::Budgets::Budget.where(component: components).order(weight: :asc)
42
+ end
35
43
  end
36
44
  end
37
45
  end