decidim-budgets 0.23.2 → 0.24.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.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/decidim/budgets/projects.js.es6 +30 -13
  3. data/app/cells/decidim/budgets/limit_announcement_cell.rb +2 -9
  4. data/app/cells/decidim/budgets/project_list_item/project_data_vote_button.erb +1 -0
  5. data/app/cells/decidim/budgets/project_list_item_cell.rb +4 -0
  6. data/app/commands/decidim/budgets/admin/import_proposals_to_budgets.rb +8 -1
  7. data/app/controllers/decidim/budgets/admin/budgets_controller.rb +22 -1
  8. data/app/controllers/decidim/budgets/orders_controller.rb +1 -1
  9. data/app/forms/decidim/budgets/admin/component_form.rb +57 -10
  10. data/app/forms/decidim/budgets/admin/project_form.rb +3 -2
  11. data/app/forms/decidim/budgets/admin/project_import_proposals_form.rb +11 -0
  12. data/app/helpers/decidim/budgets/projects_helper.rb +45 -1
  13. data/app/models/decidim/budgets/order.rb +94 -18
  14. data/app/permissions/decidim/budgets/admin/permissions.rb +1 -1
  15. data/app/views/decidim/budgets/admin/budgets/index.html.erb +22 -5
  16. data/app/views/decidim/budgets/admin/projects/index.html.erb +13 -6
  17. data/app/views/decidim/budgets/admin/proposals_imports/new.html.erb +6 -1
  18. data/app/views/decidim/budgets/projects/_budget_excess.html.erb +2 -2
  19. data/app/views/decidim/budgets/projects/_budget_summary.html.erb +32 -12
  20. data/app/views/decidim/budgets/projects/_filters_small_view.html.erb +1 -1
  21. data/app/views/decidim/budgets/projects/_order_progress.html.erb +1 -1
  22. data/app/views/decidim/budgets/projects/_order_total_budget.html.erb +5 -1
  23. data/config/locales/ar.yml +2 -5
  24. data/config/locales/ca.yml +36 -8
  25. data/config/locales/cs.yml +34 -6
  26. data/config/locales/de.yml +34 -6
  27. data/config/locales/el.yml +2 -6
  28. data/config/locales/en.yml +35 -7
  29. data/config/locales/es-MX.yml +35 -7
  30. data/config/locales/es-PY.yml +35 -7
  31. data/config/locales/es.yml +35 -7
  32. data/config/locales/eu.yml +2 -5
  33. data/config/locales/fi-plain.yml +34 -6
  34. data/config/locales/fi.yml +34 -6
  35. data/config/locales/fr-CA.yml +35 -7
  36. data/config/locales/fr.yml +35 -7
  37. data/config/locales/gl.yml +23 -7
  38. data/config/locales/hu.yml +2 -5
  39. data/config/locales/id-ID.yml +2 -5
  40. data/config/locales/is-IS.yml +2 -4
  41. data/config/locales/it.yml +2 -6
  42. data/config/locales/ja.yml +3 -7
  43. data/config/locales/lv.yml +2 -6
  44. data/config/locales/nl.yml +49 -7
  45. data/config/locales/no.yml +2 -7
  46. data/config/locales/pl.yml +41 -13
  47. data/config/locales/pt-BR.yml +2 -5
  48. data/config/locales/pt.yml +2 -6
  49. data/config/locales/ro-RO.yml +69 -6
  50. data/config/locales/ru.yml +2 -5
  51. data/config/locales/sk.yml +2 -6
  52. data/config/locales/sr-CS.yml +0 -2
  53. data/config/locales/sv.yml +26 -7
  54. data/config/locales/tr-TR.yml +31 -7
  55. data/config/locales/uk.yml +2 -5
  56. data/config/locales/zh-CN.yml +2 -7
  57. data/db/migrate/20200804175222_votes_enabled_to_votes_choices.rb +4 -4
  58. data/db/migrate/20210310120613_add_followable_counter_cache_to_budgets.rb +16 -0
  59. data/lib/decidim/api/budget_type.rb +21 -0
  60. data/lib/decidim/api/budgets_type.rb +26 -0
  61. data/lib/decidim/api/project_type.rb +23 -0
  62. data/lib/decidim/budgets.rb +2 -0
  63. data/lib/decidim/budgets/api.rb +9 -0
  64. data/lib/decidim/budgets/component.rb +31 -14
  65. data/lib/decidim/budgets/project_serializer.rb +81 -0
  66. data/lib/decidim/budgets/test/factories.rb +35 -1
  67. data/lib/decidim/budgets/version.rb +1 -1
  68. data/lib/decidim/budgets/workflows/all.rb +1 -1
  69. data/lib/decidim/budgets/workflows/base.rb +3 -3
  70. data/lib/decidim/budgets/workflows/one.rb +1 -1
  71. metadata +20 -17
  72. data/app/types/decidim/budgets/budget_type.rb +0 -24
  73. data/app/types/decidim/budgets/budgets_type.rb +0 -32
  74. data/app/types/decidim/budgets/project_type.rb +0 -26
@@ -72,10 +72,10 @@ uk:
72
72
  description: Ось проекти, які ви обрали складовими бюджету.
73
73
  title: Підтвердьте голос
74
74
  budget_excess:
75
+ budget_excess:
76
+ title: Перевищено граничний бюджет
75
77
  close: Закрити
76
- description: Додавання цього проекту перевищить максимальний бюджет, і тому його не можна зараз додати. За бажанням ви можете видалити якийсь з тих проектів, що ви раніше вибрали для додавання, або проголосувати згідно ваших уподобань.
77
78
  ok: Гаразд
78
- title: Перевищено граничний бюджет
79
79
  budget_summary:
80
80
  are_you_sure: Ви дійсно бажаєте скасувати ваш голос?
81
81
  assigned: 'Надано:'
@@ -83,7 +83,6 @@ uk:
83
83
  checked_out:
84
84
  description: Ви вже проголосували за бюджет. Якщо ви змінили свою думку, ви можете %{cancel_link}.
85
85
  title: Голосування щодо бюджету завершено
86
- description: На які проекти, на вашу думку, ми маємо виділити кошти? Надавайте принаймні %{minimum_budget} бажаним для вас проектам та голосуйте згідно своїх уподобань, щоб визначити бюджет.
87
86
  title: Ви визначаєте бюджет
88
87
  count:
89
88
  projects_count:
@@ -125,7 +124,6 @@ uk:
125
124
  announcement: Оголошення
126
125
  comments_enabled: Коментарі увімкнено
127
126
  projects_per_page: Проектів на сторінку
128
- resources_permissions_enabled: Для кожної зустрічі можна встановити ті чи інші дозволи на дії
129
127
  total_budget: Загальний бюджет
130
128
  vote_threshold_percent: Мінімальний відсоток бюджету для голосування
131
129
  step:
@@ -146,4 +144,3 @@ uk:
146
144
  project_proposal: 'Пропозиції, включені до цього проекту:'
147
145
  index:
148
146
  confirmed_orders_count: Кількість голосів
149
- total_budget: Загальний бюджет
@@ -133,10 +133,10 @@ zh-CN:
133
133
  description: 这些是你选择作为预算一部分的项目。
134
134
  title: 确认投票
135
135
  budget_excess:
136
+ budget_excess:
137
+ title: 超出最大预算
136
138
  close: 关闭
137
- description: 此项目超出了最大预算,无法添加。 如果你想要,你可以删除一个你已经选择添加的项目,或者选择你的首选项投票。
138
139
  ok: 好的
139
- title: 超出最大预算
140
140
  budget_summary:
141
141
  are_you_sure: 您确定要取消您的投票吗?
142
142
  assigned: '已指派:'
@@ -144,8 +144,6 @@ zh-CN:
144
144
  checked_out:
145
145
  description: 您已经投票给了预算。如果您改变了主意,您可以 %{cancel_link}。
146
146
  title: 预算投票完成
147
- description: 你认为我们应该为哪些项目分配预算? 给您想要的项目分配至少 %{minimum_budget} ,并且以您的首选项投票来定义预算。
148
- description_minimum_projects_rule: 你认为我们应该为哪些项目分配预算? 选择至少 %{minimum_number} 个项目,您想要并以您的首选项投票来定义预算。
149
147
  title: 您决定预算
150
148
  count:
151
149
  projects_count:
@@ -185,7 +183,6 @@ zh-CN:
185
183
  view: 查看
186
184
  votes:
187
185
  other: 投票
188
- you_voted: 您投票了
189
186
  project_budget_button:
190
187
  add: 添加到您的投票
191
188
  add_descriptive: 将项目 %{resource_name} 添加到您的投票
@@ -212,7 +209,6 @@ zh-CN:
212
209
  landing_page_content: 预算登陆页
213
210
  more_information_modal: 更多信息模式
214
211
  projects_per_page: 每页项目数
215
- resources_permissions_enabled: 每次会议都可以设置动作权限
216
212
  scope_id: 范围
217
213
  scopes_enabled: 范围已启用
218
214
  title: 标题
@@ -257,4 +253,3 @@ zh-CN:
257
253
  project_proposal: '本项目中的建议:'
258
254
  index:
259
255
  confirmed_orders_count: 所得票数
260
- total_budget: 预算总额
@@ -7,12 +7,12 @@ class VotesEnabledToVotesChoices < ActiveRecord::Migration[5.2]
7
7
 
8
8
  def up
9
9
  budget_components.each do |component|
10
- steps = component["settings"] && component["settings"].dig("steps")
11
- default_step = component["settings"] && component["settings"].dig("default_step")
10
+ steps = component["settings"] && component["settings"]["steps"]
11
+ default_step = component["settings"] && component["settings"]["default_step"]
12
12
 
13
13
  if steps.present?
14
14
  new_steps_settings = component["settings"]["steps"].each_with_object({}) do |(step, config), new_config|
15
- votes_value = config.dig("votes_enabled") ? "enabled" : "disabled"
15
+ votes_value = config["votes_enabled"] ? "enabled" : "disabled"
16
16
 
17
17
  new_config[step] = config.merge("votes": votes_value).except("votes_enabled")
18
18
  new_config
@@ -20,7 +20,7 @@ class VotesEnabledToVotesChoices < ActiveRecord::Migration[5.2]
20
20
  component["settings"]["steps"] = new_steps_settings
21
21
  component.save!
22
22
  elsif default_step.present?
23
- votes_value = component["settings"]["default_step"].dig("votes_enabled") ? "enabled" : "disabled"
23
+ votes_value = component["settings"]["default_step"]["votes_enabled"] ? "enabled" : "disabled"
24
24
 
25
25
  new_default_step_settings = component["settings"]["default_step"].merge("votes": votes_value).except("votes_enabled")
26
26
  component["settings"]["default_step"] = new_default_step_settings
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AddFollowableCounterCacheToBudgets < ActiveRecord::Migration[5.2]
4
+ def change
5
+ add_column :decidim_budgets_projects, :follows_count, :integer, null: false, default: 0, index: true
6
+
7
+ reversible do |dir|
8
+ dir.up do
9
+ Decidim::Budgets::Project.reset_column_information
10
+ Decidim::Budgets::Project.find_each do |record|
11
+ record.class.reset_counters(record.id, :follows)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Budgets
5
+ class BudgetType < Decidim::Api::Types::BaseObject
6
+ implements Decidim::Core::ScopableInterface
7
+ implements Decidim::Core::TraceableInterface
8
+
9
+ description "A budget"
10
+
11
+ field :id, GraphQL::Types::ID, "The internal ID of this budget", null: false
12
+ field :title, Decidim::Core::TranslatedFieldType, "The title for this budget", null: false
13
+ field :description, Decidim::Core::TranslatedFieldType, "The description for this budget", null: false
14
+ field :total_budget, GraphQL::Types::Int, "The total budget", null: false, camelize: false
15
+ field :created_at, Decidim::Core::DateTimeType, "When this budget was created", null: true
16
+ field :updated_at, Decidim::Core::DateTimeType, "When this budget was updated", null: true
17
+
18
+ field :projects, [Decidim::Budgets::ProjectType, { null: true }], "The projects for this budget", null: false
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Budgets
5
+ class BudgetsType < Decidim::Api::Types::BaseObject
6
+ implements Decidim::Core::ComponentInterface
7
+
8
+ graphql_name "Budgets"
9
+ description "A budget component of a participatory space."
10
+
11
+ field :budgets, Decidim::Budgets::BudgetType.connection_type, null: true, connection: true
12
+
13
+ def budgets
14
+ Budget.where(component: object).includes(:component)
15
+ end
16
+
17
+ field :budget, Decidim::Budgets::BudgetType, null: true do
18
+ argument :id, GraphQL::Types::ID, required: true
19
+ end
20
+
21
+ def budget(**args)
22
+ Budget.where(component: object).find_by(id: args[:id])
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Budgets
5
+ class ProjectType < Decidim::Api::Types::BaseObject
6
+ implements Decidim::Core::ScopableInterface
7
+ implements Decidim::Core::AttachableInterface
8
+ implements Decidim::Comments::CommentableInterface
9
+ implements Decidim::Core::CategorizableInterface
10
+
11
+ description "A project"
12
+
13
+ field :id, GraphQL::Types::ID, "The internal ID for this project", null: false
14
+ field :title, Decidim::Core::TranslatedFieldType, "The title for this project", null: true
15
+ field :description, Decidim::Core::TranslatedFieldType, "The description for this project", null: true
16
+ field :budget_amount, GraphQL::Types::Int, "The budget amount for this project", null: true, camelize: false
17
+ field :selected, GraphQL::Types::Boolean, "Whether this proposal is selected or not", method: :selected?, null: true
18
+ field :created_at, Decidim::Core::DateTimeType, "When this project was created", null: true
19
+ field :updated_at, Decidim::Core::DateTimeType, "When this project was updated", null: true
20
+ field :reference, GraphQL::Types::String, "The reference for this project", null: true
21
+ end
22
+ end
23
+ end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "decidim/budgets/workflows"
4
4
  require "decidim/budgets/admin"
5
+ require "decidim/budgets/api"
5
6
  require "decidim/budgets/engine"
6
7
  require "decidim/budgets/admin_engine"
7
8
  require "decidim/budgets/component"
@@ -9,5 +10,6 @@ require "decidim/budgets/component"
9
10
  module Decidim
10
11
  # Base module for this engine.
11
12
  module Budgets
13
+ autoload :ProjectSerializer, "decidim/budgets/project_serializer"
12
14
  end
13
15
  end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Budgets
5
+ autoload :ProjectType, "decidim/api/project_type"
6
+ autoload :BudgetType, "decidim/api/budget_type"
7
+ autoload :BudgetsType, "decidim/api/budgets_type"
8
+ end
9
+ end
@@ -62,6 +62,19 @@ Decidim.register_component(:budgets) do |component|
62
62
  Decidim::Follow.where(decidim_followable_type: "Decidim::Budgets::Project", decidim_followable_id: projects_ids).count
63
63
  end
64
64
 
65
+ component.exports :projects do |exports|
66
+ exports.collection do |component_instance, _user, resource_id|
67
+ budgets = resource_id ? Decidim::Budgets::Budget.find(resource_id) : Decidim::Budgets::Budget.where(decidim_component_id: component_instance)
68
+ Decidim::Budgets::Project
69
+ .where(decidim_budgets_budget_id: budgets)
70
+ .includes(:category, :component)
71
+ end
72
+
73
+ exports.include_in_open_data = true
74
+
75
+ exports.serializer Decidim::Budgets::ProjectSerializer
76
+ end
77
+
65
78
  component.settings(:global) do |settings|
66
79
  settings.attribute :scopes_enabled, type: :boolean, default: false
67
80
  settings.attribute :scope_id, type: :scope
@@ -69,8 +82,12 @@ Decidim.register_component(:budgets) do |component|
69
82
  settings.attribute :projects_per_page, type: :integer, default: 12
70
83
  settings.attribute :vote_rule_threshold_percent_enabled, type: :boolean, default: true
71
84
  settings.attribute :vote_threshold_percent, type: :integer, default: 70
85
+ settings.attribute :vote_threshold_percent, type: :integer, default: 70
72
86
  settings.attribute :vote_rule_minimum_budget_projects_enabled, type: :boolean, default: false
73
87
  settings.attribute :vote_minimum_budget_projects_number, type: :integer, default: 1
88
+ settings.attribute :vote_rule_selected_projects_enabled, type: :boolean, default: false
89
+ settings.attribute :vote_selected_projects_minimum, type: :integer, default: 0
90
+ settings.attribute :vote_selected_projects_maximum, type: :integer, default: 1
74
91
  settings.attribute :comments_enabled, type: :boolean, default: true
75
92
  settings.attribute :comments_max_length, type: :integer, required: false
76
93
  settings.attribute :resources_permissions_enabled, type: :boolean, default: true
@@ -105,7 +122,7 @@ Decidim.register_component(:budgets) do |component|
105
122
  participatory_space: participatory_space,
106
123
  settings: {
107
124
  landing_page_content: landing_page_content,
108
- more_information_modal: Decidim::Faker::Localized.paragraph(4),
125
+ more_information_modal: Decidim::Faker::Localized.paragraph(sentence_count: 4),
109
126
  workflow: %w(one random all).sample
110
127
  }
111
128
  )
@@ -113,11 +130,11 @@ Decidim.register_component(:budgets) do |component|
113
130
  rand(1...3).times do
114
131
  Decidim::Budgets::Budget.create!(
115
132
  component: component,
116
- title: Decidim::Faker::Localized.sentence(2),
133
+ title: Decidim::Faker::Localized.sentence(word_count: 2),
117
134
  description: Decidim::Faker::Localized.wrapped("<p>", "</p>") do
118
- Decidim::Faker::Localized.paragraph(3)
135
+ Decidim::Faker::Localized.paragraph(sentence_count: 3)
119
136
  end,
120
- total_budget: Faker::Number.number(8)
137
+ total_budget: Faker::Number.number(digits: 8)
121
138
  )
122
139
  end
123
140
 
@@ -127,35 +144,35 @@ Decidim.register_component(:budgets) do |component|
127
144
  budget: budget,
128
145
  scope: participatory_space.organization.scopes.sample,
129
146
  category: participatory_space.categories.sample,
130
- title: Decidim::Faker::Localized.sentence(2),
147
+ title: Decidim::Faker::Localized.sentence(word_count: 2),
131
148
  description: Decidim::Faker::Localized.wrapped("<p>", "</p>") do
132
- Decidim::Faker::Localized.paragraph(3)
149
+ Decidim::Faker::Localized.paragraph(sentence_count: 3)
133
150
  end,
134
- budget_amount: Faker::Number.number(8)
151
+ budget_amount: Faker::Number.number(digits: 8)
135
152
  )
136
153
 
137
154
  attachment_collection = Decidim::AttachmentCollection.create!(
138
155
  name: Decidim::Faker::Localized.word,
139
- description: Decidim::Faker::Localized.sentence(5),
156
+ description: Decidim::Faker::Localized.sentence(word_count: 5),
140
157
  collection_for: project
141
158
  )
142
159
 
143
160
  Decidim::Attachment.create!(
144
- title: Decidim::Faker::Localized.sentence(2),
145
- description: Decidim::Faker::Localized.sentence(5),
161
+ title: Decidim::Faker::Localized.sentence(word_count: 2),
162
+ description: Decidim::Faker::Localized.sentence(word_count: 5),
146
163
  attachment_collection: attachment_collection,
147
164
  attached_to: project,
148
165
  file: File.new(File.join(__dir__, "seeds", "Exampledocument.pdf"))
149
166
  )
150
167
  Decidim::Attachment.create!(
151
- title: Decidim::Faker::Localized.sentence(2),
152
- description: Decidim::Faker::Localized.sentence(5),
168
+ title: Decidim::Faker::Localized.sentence(word_count: 2),
169
+ description: Decidim::Faker::Localized.sentence(word_count: 5),
153
170
  attached_to: project,
154
171
  file: File.new(File.join(__dir__, "seeds", "city.jpeg"))
155
172
  )
156
173
  Decidim::Attachment.create!(
157
- title: Decidim::Faker::Localized.sentence(2),
158
- description: Decidim::Faker::Localized.sentence(5),
174
+ title: Decidim::Faker::Localized.sentence(word_count: 2),
175
+ description: Decidim::Faker::Localized.sentence(word_count: 5),
159
176
  attached_to: project,
160
177
  file: File.new(File.join(__dir__, "seeds", "Exampledocument.pdf"))
161
178
  )
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Budgets
5
+ class ProjectSerializer < Decidim::Exporters::Serializer
6
+ include Decidim::ApplicationHelper
7
+ include Decidim::ResourceHelper
8
+ include Decidim::TranslationsHelper
9
+
10
+ # Public: Initializes the serializer with a project.
11
+ def initialize(project)
12
+ @project = project
13
+ end
14
+
15
+ # Public: Exports a hash with the serialized data for this project.
16
+ def serialize
17
+ {
18
+ id: project.id,
19
+ category: {
20
+ id: project.category.try(:id),
21
+ name: project.category.try(:name) || empty_translatable
22
+ },
23
+ scope: {
24
+ id: project.scope.try(:id),
25
+ name: project.scope.try(:name) || empty_translatable
26
+ },
27
+ participatory_space: {
28
+ id: project.participatory_space.id,
29
+ url: Decidim::ResourceLocatorPresenter.new(project.participatory_space).url
30
+ },
31
+ component: { id: component.id },
32
+ title: project.title,
33
+ description: project.description,
34
+ budget: { id: project.budget.id },
35
+ budget_amount: project.budget_amount,
36
+ confirmed_votes: project.confirmed_orders_count,
37
+ comments: project.comments.count,
38
+ created_at: project.created_at,
39
+ url: project.polymorphic_resource_url({}),
40
+ related_proposals: related_proposals,
41
+ related_proposal_titles: related_proposal_titles,
42
+ related_proposal_urls: related_proposal_urls
43
+ }
44
+ end
45
+
46
+ private
47
+
48
+ attr_reader :project
49
+
50
+ def component
51
+ project.component
52
+ end
53
+
54
+ def related_proposals
55
+ project.linked_resources(:proposals, "included_proposals").map(&:id)
56
+ end
57
+
58
+ def related_proposal_titles
59
+ project.linked_resources(:proposals, "included_proposals").map do |proposal|
60
+ Decidim::Proposals::ProposalPresenter.new(proposal).title
61
+ end
62
+ end
63
+
64
+ def related_proposal_urls
65
+ project.linked_resources(:proposals, "included_proposals").map do |proposal|
66
+ Decidim::ResourceLocatorPresenter.new(proposal).url
67
+ end
68
+ end
69
+
70
+ def url
71
+ Decidim::ResourceLocatorPresenter.new(project).url
72
+ end
73
+
74
+ def empty_translatable(locales = Decidim.available_locales)
75
+ locales.each_with_object({}) do |locale, result|
76
+ result[locale.to_s] = ""
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -16,6 +16,7 @@ FactoryBot.define do
16
16
  transient do
17
17
  vote_rule_threshold_percent_enabled { true }
18
18
  vote_rule_minimum_budget_projects_enabled { false }
19
+ vote_rule_projects_enabled { false }
19
20
  vote_threshold_percent { 70 }
20
21
  end
21
22
 
@@ -23,6 +24,7 @@ FactoryBot.define do
23
24
  {
24
25
  vote_rule_threshold_percent_enabled: vote_rule_threshold_percent_enabled,
25
26
  vote_rule_minimum_budget_projects_enabled: vote_rule_minimum_budget_projects_enabled,
27
+ vote_rule_selected_projects_enabled: vote_rule_projects_enabled,
26
28
  vote_threshold_percent: vote_threshold_percent
27
29
  }
28
30
  end
@@ -32,6 +34,7 @@ FactoryBot.define do
32
34
  transient do
33
35
  vote_rule_threshold_percent_enabled { false }
34
36
  vote_rule_minimum_budget_projects_enabled { true }
37
+ vote_rule_projects_enabled { false }
35
38
  vote_minimum_budget_projects_number { 3 }
36
39
  end
37
40
 
@@ -39,11 +42,32 @@ FactoryBot.define do
39
42
  {
40
43
  vote_rule_threshold_percent_enabled: vote_rule_threshold_percent_enabled,
41
44
  vote_rule_minimum_budget_projects_enabled: vote_rule_minimum_budget_projects_enabled,
45
+ vote_rule_selected_projects_enabled: vote_rule_projects_enabled,
42
46
  vote_minimum_budget_projects_number: vote_minimum_budget_projects_number
43
47
  }
44
48
  end
45
49
  end
46
50
 
51
+ trait :with_budget_projects_range do
52
+ transient do
53
+ vote_rule_threshold_percent_enabled { false }
54
+ vote_rule_minimum_budget_projects_enabled { false }
55
+ vote_rule_projects_enabled { true }
56
+ vote_minimum_budget_projects_number { 3 }
57
+ vote_maximum_budget_projects_number { 6 }
58
+ end
59
+
60
+ settings do
61
+ {
62
+ vote_rule_threshold_percent_enabled: vote_rule_threshold_percent_enabled,
63
+ vote_rule_minimum_budget_projects_enabled: vote_rule_minimum_budget_projects_enabled,
64
+ vote_rule_selected_projects_enabled: vote_rule_projects_enabled,
65
+ vote_selected_projects_minimum: vote_minimum_budget_projects_number,
66
+ vote_selected_projects_maximum: vote_maximum_budget_projects_number
67
+ }
68
+ end
69
+ end
70
+
47
71
  trait :with_votes_disabled do
48
72
  step_settings do
49
73
  {
@@ -96,12 +120,22 @@ FactoryBot.define do
96
120
  factory :project, class: "Decidim::Budgets::Project" do
97
121
  title { generate_localized_title }
98
122
  description { Decidim::Faker::Localized.wrapped("<p>", "</p>") { generate_localized_title } }
99
- budget_amount { Faker::Number.number(8) }
123
+ budget_amount { Faker::Number.number(digits: 8) }
100
124
  budget { create(:budget) }
101
125
 
102
126
  trait :selected do
103
127
  selected_at { Time.current }
104
128
  end
129
+
130
+ trait :with_photos do
131
+ transient do
132
+ photos_number { 2 }
133
+ end
134
+
135
+ after :create do |project, evaluator|
136
+ project.attachments = create_list(:attachment, evaluator.photos_number, :with_image, attached_to: project)
137
+ end
138
+ end
105
139
  end
106
140
 
107
141
  factory :order, class: "Decidim::Budgets::Order" do