decidim-lausanne-budgets 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (177) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +141 -0
  3. data/Rakefile +93 -0
  4. data/app/cells/decidim/lausanne/budgets/base_cell.rb +24 -0
  5. data/app/cells/decidim/lausanne/budgets/budget_cell.rb +23 -0
  6. data/app/cells/decidim/lausanne/budgets/budget_information_modal/show.erb +21 -0
  7. data/app/cells/decidim/lausanne/budgets/budget_information_modal_cell.rb +24 -0
  8. data/app/cells/decidim/lausanne/budgets/budget_list_item/show.erb +21 -0
  9. data/app/cells/decidim/lausanne/budgets/budget_list_item_cell.rb +43 -0
  10. data/app/cells/decidim/lausanne/budgets/budget_m/data.erb +12 -0
  11. data/app/cells/decidim/lausanne/budgets/budget_m/footer.erb +5 -0
  12. data/app/cells/decidim/lausanne/budgets/budget_m_cell.rb +18 -0
  13. data/app/cells/decidim/lausanne/budgets/budgets_header/show.erb +7 -0
  14. data/app/cells/decidim/lausanne/budgets/budgets_header_cell.rb +16 -0
  15. data/app/cells/decidim/lausanne/budgets/budgets_list/card_list.erb +7 -0
  16. data/app/cells/decidim/lausanne/budgets/budgets_list/highlighted.erb +11 -0
  17. data/app/cells/decidim/lausanne/budgets/budgets_list/show.erb +20 -0
  18. data/app/cells/decidim/lausanne/budgets/budgets_list/voted.erb +43 -0
  19. data/app/cells/decidim/lausanne/budgets/budgets_list_cell.rb +40 -0
  20. data/app/cells/decidim/lausanne/budgets/limit_announcement_cell.rb +47 -0
  21. data/app/cells/decidim/lausanne/budgets/project_cell.rb +23 -0
  22. data/app/cells/decidim/lausanne/budgets/project_list_item/project_data.erb +19 -0
  23. data/app/cells/decidim/lausanne/budgets/project_list_item/project_data_vote_button.erb +22 -0
  24. data/app/cells/decidim/lausanne/budgets/project_list_item/project_image.erb +5 -0
  25. data/app/cells/decidim/lausanne/budgets/project_list_item/project_text.erb +23 -0
  26. data/app/cells/decidim/lausanne/budgets/project_list_item/show.erb +5 -0
  27. data/app/cells/decidim/lausanne/budgets/project_list_item_cell.rb +75 -0
  28. data/app/cells/decidim/lausanne/budgets/project_m/data.erb +12 -0
  29. data/app/cells/decidim/lausanne/budgets/project_m/footer.erb +5 -0
  30. data/app/cells/decidim/lausanne/budgets/project_m_cell.rb +24 -0
  31. data/app/cells/decidim/lausanne/budgets/project_selected_status_cell.rb +30 -0
  32. data/app/cells/decidim/lausanne/budgets/project_tags/show.erb +4 -0
  33. data/app/cells/decidim/lausanne/budgets/project_tags_cell.rb +20 -0
  34. data/app/cells/decidim/lausanne/budgets/project_voted_hint_cell.rb +35 -0
  35. data/app/cells/decidim/lausanne/budgets/project_votes_count_cell.rb +46 -0
  36. data/app/commands/decidim/lausanne/budgets/add_line_item.rb +54 -0
  37. data/app/commands/decidim/lausanne/budgets/admin/create_budget.rb +50 -0
  38. data/app/commands/decidim/lausanne/budgets/admin/create_project.rb +71 -0
  39. data/app/commands/decidim/lausanne/budgets/admin/destroy_budget.rb +44 -0
  40. data/app/commands/decidim/lausanne/budgets/admin/destroy_project.rb +44 -0
  41. data/app/commands/decidim/lausanne/budgets/admin/import_proposals_to_budgets.rb +87 -0
  42. data/app/commands/decidim/lausanne/budgets/admin/update_budget.rb +50 -0
  43. data/app/commands/decidim/lausanne/budgets/admin/update_project.rb +79 -0
  44. data/app/commands/decidim/lausanne/budgets/cancel_order.rb +46 -0
  45. data/app/commands/decidim/lausanne/budgets/checkout.rb +43 -0
  46. data/app/commands/decidim/lausanne/budgets/command.rb +16 -0
  47. data/app/commands/decidim/lausanne/budgets/create_user_record.rb +39 -0
  48. data/app/commands/decidim/lausanne/budgets/remove_line_item.rb +40 -0
  49. data/app/commands/decidim/lausanne/budgets/update_user_record.rb +40 -0
  50. data/app/controllers/concerns/decidim/lausanne/budgets/needs_current_order.rb +52 -0
  51. data/app/controllers/concerns/decidim/lausanne/budgets/orderable.rb +54 -0
  52. data/app/controllers/decidim/lausanne/budgets/admin/application_controller.rb +34 -0
  53. data/app/controllers/decidim/lausanne/budgets/admin/attachment_collections_controller.rb +27 -0
  54. data/app/controllers/decidim/lausanne/budgets/admin/attachments_controller.rb +28 -0
  55. data/app/controllers/decidim/lausanne/budgets/admin/lausanne_budgets_controller.rb +105 -0
  56. data/app/controllers/decidim/lausanne/budgets/admin/projects_controller.rb +98 -0
  57. data/app/controllers/decidim/lausanne/budgets/admin/proposals_imports_controller.rb +43 -0
  58. data/app/controllers/decidim/lausanne/budgets/application_controller.rb +77 -0
  59. data/app/controllers/decidim/lausanne/budgets/lausanne_budgets_controller.rb +29 -0
  60. data/app/controllers/decidim/lausanne/budgets/line_items_controller.rb +63 -0
  61. data/app/controllers/decidim/lausanne/budgets/orders_controller.rb +59 -0
  62. data/app/controllers/decidim/lausanne/budgets/projects_controller.rb +103 -0
  63. data/app/controllers/decidim/lausanne/budgets/user_records_controller.rb +121 -0
  64. data/app/forms/decidim/lausanne/budgets/admin/component_form.rb +93 -0
  65. data/app/forms/decidim/lausanne/budgets/admin/lausanne_budget_form.rb +41 -0
  66. data/app/forms/decidim/lausanne/budgets/admin/project_form.rb +96 -0
  67. data/app/forms/decidim/lausanne/budgets/admin/project_import_proposals_form.rb +52 -0
  68. data/app/forms/decidim/lausanne/budgets/user_record_form.rb +61 -0
  69. data/app/helpers/decidim/lausanne/budgets/admin/application_helper.rb +15 -0
  70. data/app/helpers/decidim/lausanne/budgets/application_helper.rb +26 -0
  71. data/app/helpers/decidim/lausanne/budgets/projects_helper.rb +103 -0
  72. data/app/jobs/decidim/lausanne/budgets/send_order_summary_job.rb +17 -0
  73. data/app/mailers/decidim/lausanne/budgets/order_summary_mailer.rb +38 -0
  74. data/app/models/decidim/lausanne/budgets/application_record.rb +12 -0
  75. data/app/models/decidim/lausanne/budgets/lausanne_budget.rb +37 -0
  76. data/app/models/decidim/lausanne/budgets/line_item.rb +23 -0
  77. data/app/models/decidim/lausanne/budgets/order.rb +204 -0
  78. data/app/models/decidim/lausanne/budgets/project.rb +129 -0
  79. data/app/models/decidim/lausanne/budgets/user_record.rb +28 -0
  80. data/app/packs/entrypoints/decidim_lausanne_budgets.js +2 -0
  81. data/app/packs/images/decidim/lausanne/budgets/icon.svg +1 -0
  82. data/app/packs/images/decidim/lausanne/budgets/lausanneparticipe.gif +0 -0
  83. data/app/packs/src/decidim/lausanne/budgets/index.js +1 -0
  84. data/app/packs/src/decidim/lausanne/budgets/progressFixed.js.es6 +23 -0
  85. data/app/packs/src/decidim/lausanne/budgets/projects.js.es6 +66 -0
  86. data/app/packs/stylesheets/decidim/lausanne/budgets/_budgets.scss +13 -0
  87. data/app/packs/stylesheets/decidim/lausanne/budgets/budget/_budget-list.scss +195 -0
  88. data/app/packs/stylesheets/decidim/lausanne/budgets/budget/_budget-meter.scss +85 -0
  89. data/app/packs/stylesheets/decidim/lausanne/budgets/budget/_print.scss +73 -0
  90. data/app/packs/stylesheets/decidim/lausanne/budgets/budget/_progress.scss +25 -0
  91. data/app/packs/stylesheets/decidim/lausanne/budgets/budget/_proposal_link.scss +38 -0
  92. data/app/packs/stylesheets/decidim/lausanne/budgets/budget/_share_buttons.scss +15 -0
  93. data/app/packs/stylesheets/decidim/lausanne/budgets/budget/_user_record_form.scss +8 -0
  94. data/app/packs/stylesheets/decidim/lausanne/budgets/budget/_votation-progress.scss +100 -0
  95. data/app/packs/stylesheets/decidim/lausanne/budgets/budget/_voting-rules.scss +20 -0
  96. data/app/permissions/decidim/lausanne/budgets/admin/permissions.rb +49 -0
  97. data/app/permissions/decidim/lausanne/budgets/permissions.rb +63 -0
  98. data/app/presenters/decidim/lausanne/budgets/admin_log/budget_presenter.rb +44 -0
  99. data/app/presenters/decidim/lausanne/budgets/admin_log/project_presenter.rb +44 -0
  100. data/app/queries/decidim/lausanne/budgets/filtered_projects.rb +47 -0
  101. data/app/queries/decidim/lausanne/budgets/metrics/budget_followers_metric_measure.rb +34 -0
  102. data/app/queries/decidim/lausanne/budgets/metrics/budget_participants_metric_measure.rb +29 -0
  103. data/app/queries/decidim/lausanne/budgets/query.rb +16 -0
  104. data/app/serializers/decidim/lausanne/budgets/data_portability_budgets_order_serializer.rb +46 -0
  105. data/app/services/decidim/lausanne/budgets/project_search.rb +65 -0
  106. data/app/services/decidim/lausanne/budgets/project_search_rs.rb +13 -0
  107. data/app/views/decidim/lausanne/budgets/admin/lausanne_budgets/_form.html.erb +23 -0
  108. data/app/views/decidim/lausanne/budgets/admin/lausanne_budgets/edit.html.erb +7 -0
  109. data/app/views/decidim/lausanne/budgets/admin/lausanne_budgets/index.html.erb +75 -0
  110. data/app/views/decidim/lausanne/budgets/admin/lausanne_budgets/new.html.erb +7 -0
  111. data/app/views/decidim/lausanne/budgets/admin/projects/_form.html.erb +47 -0
  112. data/app/views/decidim/lausanne/budgets/admin/projects/edit.html.erb +7 -0
  113. data/app/views/decidim/lausanne/budgets/admin/projects/index.html.erb +82 -0
  114. data/app/views/decidim/lausanne/budgets/admin/projects/new.html.erb +7 -0
  115. data/app/views/decidim/lausanne/budgets/admin/projects/proposals_picker.html.erb +1 -0
  116. data/app/views/decidim/lausanne/budgets/admin/proposals_imports/new.html.erb +32 -0
  117. data/app/views/decidim/lausanne/budgets/lausanne_budgets/index.html.erb +5 -0
  118. data/app/views/decidim/lausanne/budgets/line_items/update_budget.js.erb +41 -0
  119. data/app/views/decidim/lausanne/budgets/order_summary_mailer/order_summary.html.erb +22 -0
  120. data/app/views/decidim/lausanne/budgets/orders/show.html.erb +71 -0
  121. data/app/views/decidim/lausanne/budgets/projects/_budget_confirm.html.erb +37 -0
  122. data/app/views/decidim/lausanne/budgets/projects/_budget_excess.html.erb +14 -0
  123. data/app/views/decidim/lausanne/budgets/projects/_budget_summary.html.erb +95 -0
  124. data/app/views/decidim/lausanne/budgets/projects/_count.html.erb +1 -0
  125. data/app/views/decidim/lausanne/budgets/projects/_filters.html.erb +34 -0
  126. data/app/views/decidim/lausanne/budgets/projects/_filters_small_view.html.erb +18 -0
  127. data/app/views/decidim/lausanne/budgets/projects/_linked_projects.html.erb +12 -0
  128. data/app/views/decidim/lausanne/budgets/projects/_order_progress.html.erb +32 -0
  129. data/app/views/decidim/lausanne/budgets/projects/_order_selected_projects.html.erb +27 -0
  130. data/app/views/decidim/lausanne/budgets/projects/_order_total_budget.html.erb +7 -0
  131. data/app/views/decidim/lausanne/budgets/projects/_project.html.erb +1 -0
  132. data/app/views/decidim/lausanne/budgets/projects/_project_budget_button.html.erb +46 -0
  133. data/app/views/decidim/lausanne/budgets/projects/_projects.html.erb +13 -0
  134. data/app/views/decidim/lausanne/budgets/projects/_user_record_form.html.erb +40 -0
  135. data/app/views/decidim/lausanne/budgets/projects/_votation_banner.html.erb +71 -0
  136. data/app/views/decidim/lausanne/budgets/projects/index.html.erb +36 -0
  137. data/app/views/decidim/lausanne/budgets/projects/index.js.erb +10 -0
  138. data/app/views/decidim/lausanne/budgets/projects/show.html.erb +81 -0
  139. data/app/views/decidim/lausanne/budgets/user_records/edit.html.erb +6 -0
  140. data/app/views/decidim/proposals/proposals/show.html.erb +172 -0
  141. data/app/views/layouts/lausanne_budgets/print.erb +12 -0
  142. data/config/assets.rb +11 -0
  143. data/config/initializers/social_share.rb +3 -0
  144. data/config/locales/fr.yml +381 -0
  145. data/config/routes.rb +7 -0
  146. data/db/migrate/20170127114122_create_lausanne_projects.rb +15 -0
  147. data/db/migrate/20170127114123_create_lausanne_user_records.rb +14 -0
  148. data/db/migrate/20170130095615_create_lausanne_orders.rb +16 -0
  149. data/db/migrate/20170130101825_create_lausanne_line_items.rb +12 -0
  150. data/db/migrate/20170215132708_add_lausanne_reference_to_projects.rb +13 -0
  151. data/db/migrate/20200617105120_create_decidim_lausanne_budgets.rb +15 -0
  152. data/db/migrate/20200629134013_add_lausanne_budget_reference_to_project.rb +7 -0
  153. data/db/migrate/20200706142609_add_lausanne_budget_reference_to_order.rb +7 -0
  154. data/db/migrate/20200714103519_move_lausanne_budgets_to_own_model.rb +109 -0
  155. data/db/migrate/20200717140012_add_lausanne_scope_to_budgets.rb +7 -0
  156. data/db/migrate/20200728075039_add_lausanne_selected_at_to_project.rb +7 -0
  157. data/db/migrate/20200804175222_lausanne_votes_enabled_to_votes_choices.rb +35 -0
  158. data/db/migrate/20200827154129_add_lausanne_commentable_counter_cache_to_projects.rb +9 -0
  159. data/db/migrate/20210310120613_add_lausanne_followable_counter_cache_to_budgets.rb +16 -0
  160. data/db/migrate/20210508180613_add_checkboxes_to_user_record.rb +9 -0
  161. data/db/migrate/20221001151237_add_excerpt_to_decidim_lausanne_budgets_project.rb +7 -0
  162. data/lib/decidim/lausanne/budgets/admin.rb +12 -0
  163. data/lib/decidim/lausanne/budgets/admin_engine.rb +40 -0
  164. data/lib/decidim/lausanne/budgets/component.rb +107 -0
  165. data/lib/decidim/lausanne/budgets/current_user_record_middleware.rb +17 -0
  166. data/lib/decidim/lausanne/budgets/engine.rb +57 -0
  167. data/lib/decidim/lausanne/budgets/project_serializer.rb +83 -0
  168. data/lib/decidim/lausanne/budgets/seeds/Exampledocument.pdf +0 -0
  169. data/lib/decidim/lausanne/budgets/seeds/city.jpeg +0 -0
  170. data/lib/decidim/lausanne/budgets/test/factories.rb +169 -0
  171. data/lib/decidim/lausanne/budgets/version.rb +15 -0
  172. data/lib/decidim/lausanne/budgets/workflows/all.rb +22 -0
  173. data/lib/decidim/lausanne/budgets/workflows/base.rb +140 -0
  174. data/lib/decidim/lausanne/budgets/workflows/one.rb +35 -0
  175. data/lib/decidim/lausanne/budgets/workflows.rb +19 -0
  176. data/lib/decidim/lausanne/budgets.rb +17 -0
  177. metadata +372 -0
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Lausanne
5
+ module Budgets
6
+ module Admin
7
+ # A command with all the business logic when an admin imports proposals from
8
+ # one component to projects of a budget.
9
+ class ImportProposalsToBudgets < Decidim::Lausanne::Budgets::Command
10
+ # Public: Initializes the command.
11
+ #
12
+ # form - A form object with the params.
13
+ def initialize(form)
14
+ @form = form
15
+ end
16
+
17
+ # Executes the command. Broadcasts these events:
18
+ #
19
+ # - :ok when everything is valid.
20
+ # - :invalid if the form wasn't valid and we couldn't proceed.
21
+ #
22
+ # Returns nothing.
23
+ def call
24
+ return broadcast(:invalid) unless @form.valid?
25
+
26
+ broadcast(:ok, create_projects_from_accepted_proposals)
27
+ end
28
+
29
+ private
30
+
31
+ attr_reader :form
32
+
33
+ def create_projects_from_accepted_proposals
34
+ transaction do
35
+ proposals.map do |original_proposal|
36
+ next if proposal_already_copied?(original_proposal)
37
+
38
+ new_project = create_project_from_proposal!(original_proposal)
39
+
40
+ new_project.link_resources([original_proposal], "included_proposals")
41
+ end.compact
42
+ end
43
+ end
44
+
45
+ def create_project_from_proposal!(original_proposal)
46
+ params = {
47
+ budget: form.budget,
48
+ title: original_proposal.title,
49
+ description: original_proposal.body,
50
+ budget_amount: form.default_budget,
51
+ category: original_proposal.category,
52
+ scope: original_proposal.scope
53
+ }
54
+
55
+ @project = Decidim.traceability.create!(
56
+ Project,
57
+ form.current_user,
58
+ params,
59
+ visibility: "all"
60
+ )
61
+ end
62
+
63
+ def proposals
64
+ return all_proposals if form.scope_id.blank?
65
+
66
+ all_proposals.where(decidim_scope_id: form.scope_id)
67
+ end
68
+
69
+ def all_proposals
70
+ Decidim::Proposals::Proposal.where(component: origin_component)
71
+ .where(state: :accepted)
72
+ end
73
+
74
+ def origin_component
75
+ form.origin_component
76
+ end
77
+
78
+ def proposal_already_copied?(original_proposal)
79
+ original_proposal.linked_resources(:projects, "included_proposals").any? do |project|
80
+ project.budget == form.budget
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Lausanne
5
+ module Budgets
6
+ module Admin
7
+ # This command is executed when the user updates a Budget
8
+ # from the admin panel.
9
+ class UpdateBudget < Decidim::Lausanne::Budgets::Command
10
+ def initialize(form, budget)
11
+ @form = form
12
+ @budget = budget
13
+ end
14
+
15
+ # Updates the budget if valid.
16
+ #
17
+ # Broadcasts :ok if successful, :invalid otherwise.
18
+ def call
19
+ return broadcast(:invalid) if form.invalid?
20
+
21
+ update_budget!
22
+
23
+ broadcast(:ok, budget)
24
+ end
25
+
26
+ private
27
+
28
+ attr_reader :form, :budget
29
+
30
+ def update_budget!
31
+ attributes = {
32
+ scope: form.scope,
33
+ title: form.title,
34
+ weight: form.weight,
35
+ description: form.description,
36
+ total_budget: form.total_budget
37
+ }
38
+
39
+ Decidim.traceability.update!(
40
+ budget,
41
+ form.current_user,
42
+ attributes,
43
+ visibility: "all"
44
+ )
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Lausanne
5
+ module Budgets
6
+ module Admin
7
+ # This command is executed when the user changes a Project from the admin
8
+ # panel.
9
+ class UpdateProject < Decidim::Lausanne::Budgets::Command
10
+ include ::Decidim::AttachmentMethods
11
+ include ::Decidim::GalleryMethods
12
+
13
+ # Initializes an UpdateProject Command.
14
+ #
15
+ # form - The form from which to get the data.
16
+ # project - The current instance of the project to be updated.
17
+ def initialize(form, project)
18
+ @form = form
19
+ @project = project
20
+ @attached_to = project
21
+ end
22
+
23
+ # Updates the project if valid.
24
+ #
25
+ # Broadcasts :ok if successful, :invalid otherwise.
26
+ def call
27
+ return broadcast(:invalid) if form.invalid?
28
+
29
+ if process_gallery?
30
+ build_gallery
31
+ return broadcast(:invalid) if gallery_invalid?
32
+ end
33
+
34
+ transaction do
35
+ update_project
36
+ link_proposals
37
+ create_gallery if process_gallery?
38
+ photo_cleanup!
39
+ end
40
+
41
+ broadcast(:ok)
42
+ end
43
+
44
+ private
45
+
46
+ attr_reader :project, :form, :gallery
47
+
48
+ def update_project
49
+ Decidim.traceability.update!(
50
+ project,
51
+ form.current_user,
52
+ scope: form.scope,
53
+ category: form.category,
54
+ title: form.title,
55
+ description: form.description,
56
+ excerpt: form.excerpt,
57
+ budget_amount: form.budget_amount,
58
+ selected_at: selected_at
59
+ )
60
+ end
61
+
62
+ def proposals
63
+ @proposals ||= project.sibling_scope(:proposals).where(id: form.proposal_ids)
64
+ end
65
+
66
+ def link_proposals
67
+ project.link_resources(proposals, "included_proposals")
68
+ end
69
+
70
+ def selected_at
71
+ return unless form.selected
72
+
73
+ Time.current
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Lausanne
5
+ module Budgets
6
+ # A command with all the business to cancel an order.
7
+ class CancelOrder < Decidim::Lausanne::Budgets::Command
8
+ # Public: Initializes the command.
9
+ #
10
+ # order - The current order for the user.
11
+ def initialize(order)
12
+ @order = order
13
+ end
14
+
15
+ # Executes the command. Broadcasts these events:
16
+ #
17
+ # - :ok when everything is valid.
18
+ #
19
+ # Returns nothing.
20
+ def call
21
+ transaction do
22
+ cancel_order!
23
+ end
24
+ broadcast(:ok, @order)
25
+ end
26
+
27
+ private
28
+ def user_record
29
+ @order.user_record
30
+ end
31
+ # If the order is not linked to a user,
32
+ # remove the user_record and the order.
33
+ # If the order is linked to a user, remove all the votes
34
+ def cancel_order!
35
+ @order.line_items.each do |line|
36
+ line.destroy!
37
+ end
38
+ unless user_record.user
39
+ @order.user_record.destroy!
40
+ end
41
+ @order.update(checked_out_at: nil)
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Lausanne
5
+ module Budgets
6
+ # A command with all the business to checkout.
7
+ class Checkout < Decidim::Lausanne::Budgets::Command
8
+ # Public: Initializes the command.
9
+ #
10
+ # order - The current order for the user.
11
+ def initialize(order)
12
+ @order = order
13
+ end
14
+
15
+ # Executes the command. Broadcasts these events:
16
+ #
17
+ # - :ok when everything is valid.
18
+ # - :invalid if the there is an error.
19
+ #
20
+ # Returns nothing.
21
+ def call
22
+ return broadcast(:invalid, order) unless checkout!
23
+
24
+ broadcast(:ok, order)
25
+ end
26
+
27
+ private
28
+
29
+ attr_reader :order
30
+
31
+ def checkout!
32
+ return unless order && order.valid?
33
+
34
+ @order.with_lock do
35
+ SendOrderSummaryJob.perform_later(@order)
36
+ @order.checked_out_at = Time.current
37
+ @order.save
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Lausanne
5
+ module Budgets
6
+ # maintains compatibility with v0.26 which uses Rectify
7
+ if defined? ::Decidim::Command
8
+ class Command < ::Decidim::Command
9
+ end
10
+ else
11
+ class Command < ::Rectify::Command
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Lausanne
5
+ module Budgets
6
+ class CreateUserRecord < Decidim::Lausanne::Budgets::Command
7
+ attr_reader :user_record, :budget, :current_user
8
+ def initialize(user_record, budget, current_user)
9
+ @user_record = user_record
10
+ @budget = budget
11
+ @current_user = current_user
12
+ end
13
+
14
+ def call
15
+ return broadcast(:invalid) unless budget
16
+ return broadcast(:invalid) if user_record.invalid?
17
+ new_user_record = nil
18
+ transaction do
19
+ new_user_record = UserRecord.create(
20
+ first_name: user_record.first_name,
21
+ last_name: user_record.last_name,
22
+ birthdate: user_record.birthdate,
23
+ iam_lausanne: user_record.iam_lausanne,
24
+ its_me: user_record.its_me,
25
+ allow_process_data: user_record.allow_process_data,
26
+ user: current_user || nil,
27
+ order: Order.create(
28
+ budget: budget
29
+ )
30
+ )
31
+ rescue e
32
+ broadcast(:invalid)
33
+ end
34
+ broadcast(:ok, new_user_record)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Lausanne
5
+ module Budgets
6
+ # A command with all the business to add remove line items from orders
7
+ class RemoveLineItem < Decidim::Lausanne::Budgets::Command
8
+ # Public: Initializes the command.
9
+ #
10
+ # order - The current order for the user
11
+ # project - The the project to remove from the order
12
+ def initialize(order, project)
13
+ @order = order
14
+ @project = project
15
+ end
16
+
17
+ # Executes the command. Broadcasts these events:
18
+ #
19
+ # - :ok when everything is valid.
20
+ # - :invalid if the there is an error.
21
+ #
22
+ # Returns nothing.
23
+ def call
24
+ return broadcast(:invalid) if @order.checked_out?
25
+
26
+ remove_line_item
27
+ broadcast(:ok, @order)
28
+ end
29
+
30
+ private
31
+
32
+ attr_reader :project
33
+
34
+ def remove_line_item
35
+ @order.projects.destroy(project)
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Lausanne
5
+ module Budgets
6
+ class UpdateUserRecord < Decidim::Lausanne::Budgets::Command
7
+ attr_reader :user_record, :budget, :current_user
8
+ def initialize(user_record, budget, current_user)
9
+ @user_record = user_record
10
+ @budget = budget
11
+ @current_user = current_user
12
+ end
13
+
14
+ def call
15
+ return broadcast(:invalid) unless budget
16
+ return broadcast(:invalid) if user_record.invalid?
17
+
18
+ new_user_record = nil
19
+ transaction do
20
+ new_user_record = UserRecord.create(
21
+ first_name: user_record.first_name,
22
+ last_name: user_record.last_name,
23
+ birthdate: user_record.birthdate,
24
+ iam_lausanne: user_record.iam_lausanne,
25
+ its_me: user_record.its_me,
26
+ allow_process_data: user_record.allow_process_data,
27
+ user: current_user || nil,
28
+ order: Order.create(
29
+ budget: budget
30
+ )
31
+ )
32
+ rescue e
33
+ broadcast(:invalid)
34
+ end
35
+ broadcast(:ok, new_user_record)
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/concern"
4
+
5
+ module Decidim
6
+ module Lausanne
7
+ module Budgets
8
+ # Shared behaviour for controllers that need the current order to be present.
9
+ module NeedsCurrentOrder
10
+ extend ActiveSupport::Concern
11
+
12
+ included do
13
+ helper_method :current_order, :can_have_order?, :voted_for?, :user_record_for_budget?,
14
+ :user_record_submitted?
15
+
16
+ def user_record_for_budget?
17
+ return true if current_user_record.new_record?
18
+ current_user_record.order.id == current_order.id
19
+ end
20
+ def user_record_submitted?
21
+ !current_user_record.new_record?
22
+ end
23
+
24
+ def current_order
25
+ @current_order ||= Order.includes(:projects).find_or_initialize_by(
26
+ user_record: current_user_record,
27
+ budget: budget
28
+ )
29
+ end
30
+
31
+ def current_order=(order)
32
+ @current_order = order
33
+ end
34
+
35
+ def persisted_current_order
36
+ current_order if current_order&.persisted?
37
+ end
38
+
39
+ def can_have_order?
40
+ voting_open? &&
41
+ allowed_to?(:create, :order, budget: budget, workflow: current_workflow)
42
+ end
43
+
44
+ # Return true if the user has voted the project
45
+ def voted_for?(project)
46
+ current_order && current_order.projects.include?(project)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/concern"
4
+
5
+ module Decidim
6
+ module Lausanne
7
+ module Budgets
8
+ # Common logic to sorting resources
9
+ module Orderable
10
+ extend ActiveSupport::Concern
11
+
12
+ included do
13
+ include Decidim::Orderable
14
+
15
+ private
16
+
17
+ # Available orders based on enabled settings
18
+ def available_orders
19
+ @available_orders ||= begin
20
+ available_orders = []
21
+ available_orders << "asc"
22
+ available_orders << "most_voted" if votes_are_visible?
23
+ available_orders += %w(highest_cost lowest_cost)
24
+ available_orders
25
+ end
26
+ end
27
+
28
+ def default_order
29
+ available_orders.first
30
+ end
31
+
32
+ def votes_are_visible?
33
+ current_settings.show_votes?
34
+ end
35
+
36
+ def reorder(projects)
37
+ case order
38
+ when "highest_cost"
39
+ projects.order(budget_amount: :desc)
40
+ when "lowest_cost"
41
+ projects.order(budget_amount: :asc)
42
+ when "asc"
43
+ projects.order(Arel.sql("title->>'#{I18n.locale}' ASC"))
44
+ when "random"
45
+ projects.order_randomly(random_seed)
46
+ else
47
+ projects
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Lausanne
5
+ module Budgets
6
+ module Admin
7
+ # This controller is the abstract class from which all other controllers of
8
+ # this engine inherit.
9
+ #
10
+ # Note that it inherits from `Decidim::Components::BaseController`, which
11
+ # override its layout and provide all kinds of useful methods.
12
+ class ApplicationController < Decidim::Admin::Components::BaseController
13
+ helper_method :budget, :projects, :project
14
+
15
+ def budget
16
+ @budget ||= LausanneBudget.where(component: current_component).includes(:projects).find_by(id: params[:lausanne_budget_id])
17
+ end
18
+
19
+ def projects
20
+ return unless budget
21
+
22
+ @projects ||= budget.projects
23
+ end
24
+
25
+ def project
26
+ return unless projects
27
+
28
+ @project ||= projects.find(params[:id])
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Lausanne
5
+ module Budgets
6
+ module Admin
7
+ # Controller that allows managing all the attachment collections for a budget.
8
+ #
9
+ class AttachmentCollectionsController < Admin::ApplicationController
10
+ include Decidim::Admin::Concerns::HasAttachmentCollections
11
+
12
+ def after_destroy_path
13
+ project_attachment_collections_path(project, project.component, current_participatory_space)
14
+ end
15
+
16
+ def collection_for
17
+ project
18
+ end
19
+
20
+ def project
21
+ @project ||= Decidim::Lausanne::Budgets::Project.find(params[:project_id])
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Lausanne
5
+ module Budgets
6
+ module Admin
7
+ # Controller that allows managing all the attachments for a participatory
8
+ # process.
9
+ #
10
+ class AttachmentsController < Admin::ApplicationController
11
+ include Decidim::Admin::Concerns::HasAttachments
12
+
13
+ def after_destroy_path
14
+ lausanne_budget_projects_path(project.budget)
15
+ end
16
+
17
+ def attached_to
18
+ project
19
+ end
20
+
21
+ def project
22
+ @project ||= Decidim::Lausanne::Budgets::Project.find(params[:project_id])
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end