decidim-budgets 0.0.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.
- checksums.yaml +7 -0
- data/README.md +23 -0
- data/Rakefile +2 -0
- data/app/assets/config/decidim_budgets_manifest.js +1 -0
- data/app/assets/images/decidim/budgets/icon.svg +4 -0
- data/app/assets/javascripts/decidim/budgets/projects.js.es6 +28 -0
- data/app/assets/stylesheets/decidim/budgets/_budgets.scss +1 -0
- data/app/assets/stylesheets/decidim/budgets/budget/_budget-list.scss +32 -0
- data/app/assets/stylesheets/decidim/budgets/budget/_budget-meter.scss +78 -0
- data/app/assets/stylesheets/decidim/budgets/budget/_progress.scss +17 -0
- data/app/commands/decidim/budgets/add_line_item.rb +43 -0
- data/app/commands/decidim/budgets/admin/create_project.rb +52 -0
- data/app/commands/decidim/budgets/admin/update_project.rb +56 -0
- data/app/commands/decidim/budgets/cancel_order.rb +36 -0
- data/app/commands/decidim/budgets/checkout.rb +34 -0
- data/app/commands/decidim/budgets/remove_line_item.rb +35 -0
- data/app/controllers/concerns/decidim/budgets/needs_current_order.rb +27 -0
- data/app/controllers/decidim/budgets/admin/application_controller.rb +14 -0
- data/app/controllers/decidim/budgets/admin/projects_controller.rb +69 -0
- data/app/controllers/decidim/budgets/application_controller.rb +13 -0
- data/app/controllers/decidim/budgets/line_items_controller.rb +43 -0
- data/app/controllers/decidim/budgets/orders_controller.rb +38 -0
- data/app/controllers/decidim/budgets/projects_controller.rb +44 -0
- data/app/forms/decidim/budgets/admin/project_form.rb +44 -0
- data/app/helpers/decidim/budgets/application_helper.rb +12 -0
- data/app/helpers/decidim/budgets/projects_helper.rb +29 -0
- data/app/models/decidim/budgets/application_record.rb +9 -0
- data/app/models/decidim/budgets/line_item.rb +20 -0
- data/app/models/decidim/budgets/order.rb +52 -0
- data/app/models/decidim/budgets/project.rb +15 -0
- data/app/services/decidim/budgets/project_search.rb +58 -0
- data/app/views/decidim/budgets/admin/projects/_form.html.erb +31 -0
- data/app/views/decidim/budgets/admin/projects/edit.html.erb +9 -0
- data/app/views/decidim/budgets/admin/projects/index.html.erb +27 -0
- data/app/views/decidim/budgets/admin/projects/new.html.erb +9 -0
- data/app/views/decidim/budgets/line_items/update_budget.js.erb +21 -0
- data/app/views/decidim/budgets/projects/_budget_confirm.html.erb +30 -0
- data/app/views/decidim/budgets/projects/_budget_excess.html.erb +14 -0
- data/app/views/decidim/budgets/projects/_budget_summary.html.erb +46 -0
- data/app/views/decidim/budgets/projects/_count.html.erb +1 -0
- data/app/views/decidim/budgets/projects/_filters.html.erb +24 -0
- data/app/views/decidim/budgets/projects/_linked_projects.html.erb +12 -0
- data/app/views/decidim/budgets/projects/_order_progress.html.erb +34 -0
- data/app/views/decidim/budgets/projects/_order_selected_projects.html.erb +25 -0
- data/app/views/decidim/budgets/projects/_order_total_budget.html.erb +1 -0
- data/app/views/decidim/budgets/projects/_project.html.erb +40 -0
- data/app/views/decidim/budgets/projects/_project_budget_button.html.erb +9 -0
- data/app/views/decidim/budgets/projects/_projects.html.erb +8 -0
- data/app/views/decidim/budgets/projects/_tags.html.erb +10 -0
- data/app/views/decidim/budgets/projects/index.html.erb +26 -0
- data/app/views/decidim/budgets/projects/index.js.erb +2 -0
- data/app/views/decidim/budgets/projects/show.html.erb +48 -0
- data/config/i18n-tasks.yml +4 -0
- data/config/locales/ca.yml +84 -0
- data/config/locales/en.yml +95 -0
- data/config/locales/es.yml +84 -0
- data/db/migrate/20170127114122_create_projects.rb +15 -0
- data/db/migrate/20170130095615_create_orders.rb +13 -0
- data/db/migrate/20170130101825_create_line_items.rb +10 -0
- data/lib/decidim/budgets/admin.rb +9 -0
- data/lib/decidim/budgets/admin_engine.rb +22 -0
- data/lib/decidim/budgets/feature.rb +59 -0
- data/lib/decidim/budgets/list_engine.rb +30 -0
- data/lib/decidim/budgets/test/factories.rb +43 -0
- data/lib/decidim/budgets.rb +11 -0
- metadata +210 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: aa8f0db3125a7ddb93f9076d6e4fff7256cb1934
|
4
|
+
data.tar.gz: 109c2f3e91977e116a7d5baccf9fa142a78e100f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 673eb952dde2972556bdcb286255d7a456f9f738764901f0c832adea7b8ea3d606b248cf4f6a33fc166ef4ed21b95f53c71d4f112745be53228e445acb7f04fd
|
7
|
+
data.tar.gz: 4e22d0bb6a0acc9a3c8820ef305eefb3a273521063908895e84f0b6a2c65c9a692e05986047949c5faaa54e396e2c9c522642be4e331d869552cfd7e215a8779
|
data/README.md
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# Decidim::Budgets
|
2
|
+
The Budgets module adds projects to any participatory process. It adds a CRUD engine to the admin and public views scoped inside the participatory process. Projects will link to related proposals and have a budget. The users should be able to distribute a budget between these projects.
|
3
|
+
|
4
|
+
## Usage
|
5
|
+
Budgets will be available as a Feature for a Participatory Process.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
gem 'decidim-budgets
|
12
|
+
```
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
```bash
|
16
|
+
$ bundle
|
17
|
+
```
|
18
|
+
|
19
|
+
## Contributing
|
20
|
+
See [Decidim](https://github.com/AjuntamentdeBarcelona/decidim).
|
21
|
+
|
22
|
+
## License
|
23
|
+
See [Decidim](https://github.com/AjuntamentdeBarcelona/decidim).
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
//= link decidim/budgets/projects.js
|
@@ -0,0 +1,4 @@
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="8" height="8" viewBox="0 0 8 8">
|
2
|
+
<path d="M2 0v1h-.75c-.68 0-1.25.57-1.25 1.25v.5c0 .68.44 1.24 1.09 1.41l2.56.66c.14.04.34.29.34.44v.5c0 .14-.11.25-.25.25h-2.5c-.12 0-.21-.04-.25-.06v-.94h-1v1c0 .34.2.63.44.78.23.16.52.22.81.22h.75v1h1v-1h.75c.69 0 1.25-.56 1.25-1.25v-.5c0-.68-.44-1.24-1.09-1.41l-2.56-.66c-.14-.04-.34-.29-.34-.44v-.5c0-.14.11-.25.25-.25h2.5c.11 0 .21.04.25.06v.94h1v-1c0-.34-.2-.63-.44-.78-.23-.16-.52-.22-.81-.22h-.75v-1h-1z"
|
3
|
+
transform="translate(1)" />
|
4
|
+
</svg>
|
@@ -0,0 +1,28 @@
|
|
1
|
+
// = require_self
|
2
|
+
|
3
|
+
$(() => {
|
4
|
+
const $projects = $('#projects, #project');
|
5
|
+
const $budgetSummaryTotal = $('.budget-summary__total');
|
6
|
+
const $budgetExceedModal = $('#budget-excess');
|
7
|
+
|
8
|
+
const totalBudget = $budgetSummaryTotal.data('total-budget');
|
9
|
+
|
10
|
+
const cancelEvent = (event) => {
|
11
|
+
event.stopPropagation();
|
12
|
+
event.preventDefault();
|
13
|
+
};
|
14
|
+
|
15
|
+
$projects.on('click', '.budget--list__action', (event) => {
|
16
|
+
const currentBudget = $('.budget-summary__progressbox').data('current-budget');
|
17
|
+
const $currentTarget = $(event.currentTarget);
|
18
|
+
const projectBudget = $currentTarget.data('budget');
|
19
|
+
|
20
|
+
if ($currentTarget.attr('disabled')) {
|
21
|
+
cancelEvent(event);
|
22
|
+
|
23
|
+
} else if ($currentTarget.data('add') && ((currentBudget + projectBudget) > totalBudget)) {
|
24
|
+
$budgetExceedModal.foundation('toggle');
|
25
|
+
cancelEvent(event);
|
26
|
+
}
|
27
|
+
});
|
28
|
+
});
|
@@ -0,0 +1 @@
|
|
1
|
+
@import "budget/*";
|
@@ -0,0 +1,32 @@
|
|
1
|
+
.budget-list__title{
|
2
|
+
@include breakpoint(smallmedium down){
|
3
|
+
font-size: $global-font-size;
|
4
|
+
}
|
5
|
+
}
|
6
|
+
.budget-list__data{
|
7
|
+
flex-basis: 9rem;
|
8
|
+
@include breakpoint(medium){
|
9
|
+
flex-direction: row;
|
10
|
+
flex-basis: 16rem;
|
11
|
+
}
|
12
|
+
}
|
13
|
+
.budget-list__data--added{
|
14
|
+
background-color: mix(white, $success, 80%);
|
15
|
+
}
|
16
|
+
|
17
|
+
.budget-list__number{
|
18
|
+
@include breakpoint(medium down){
|
19
|
+
font-size: 1rem;
|
20
|
+
}
|
21
|
+
@include breakpoint(medium){
|
22
|
+
flex-grow: 1;
|
23
|
+
font-size: 1.5rem;
|
24
|
+
margin-right: 1rem;
|
25
|
+
margin-bottom: 0;
|
26
|
+
text-align: right;
|
27
|
+
}
|
28
|
+
}
|
29
|
+
|
30
|
+
.budget--list__action{
|
31
|
+
margin-bottom: 0;
|
32
|
+
}
|
@@ -0,0 +1,78 @@
|
|
1
|
+
.budget-summary__total{
|
2
|
+
margin-bottom: .5rem;
|
3
|
+
}
|
4
|
+
|
5
|
+
.budget-summary__progressbox{
|
6
|
+
align-items: stretch;
|
7
|
+
margin-bottom: .5rem;
|
8
|
+
@include breakpoint(smallmedium down){
|
9
|
+
text-align: center;
|
10
|
+
}
|
11
|
+
@include breakpoint(medium){
|
12
|
+
display: flex;
|
13
|
+
}
|
14
|
+
.button{
|
15
|
+
margin-bottom: 0;
|
16
|
+
}
|
17
|
+
}
|
18
|
+
|
19
|
+
.progressbox-fixed-wrapper{
|
20
|
+
position: fixed;
|
21
|
+
top: 0;
|
22
|
+
left: 0;
|
23
|
+
right: 0;
|
24
|
+
z-index: 2;
|
25
|
+
background: $white;
|
26
|
+
box-shadow: 0 2px 7px rgba(black,.1);
|
27
|
+
display: none;
|
28
|
+
&.is-progressbox-visible{
|
29
|
+
display: block;
|
30
|
+
}
|
31
|
+
|
32
|
+
}
|
33
|
+
|
34
|
+
.budget-summary__progressbox--fixed{
|
35
|
+
margin: auto;
|
36
|
+
max-width: $global-width;
|
37
|
+
padding: 1rem 2rem;
|
38
|
+
@include breakpoint(mediumlarge){
|
39
|
+
padding: 1rem 4rem;
|
40
|
+
}
|
41
|
+
display: flex;
|
42
|
+
}
|
43
|
+
|
44
|
+
.budget-progress{
|
45
|
+
flex-grow: 1;
|
46
|
+
margin-bottom: .5rem;
|
47
|
+
min-height: 1.5rem;
|
48
|
+
@include breakpoint(medium){
|
49
|
+
min-height: 2rem;
|
50
|
+
margin-bottom: 0;
|
51
|
+
margin-right: 1rem;
|
52
|
+
}
|
53
|
+
}
|
54
|
+
|
55
|
+
.budget-progress--fixed{
|
56
|
+
min-height: 2rem;
|
57
|
+
margin-bottom: 0;
|
58
|
+
margin-right: 1rem;
|
59
|
+
}
|
60
|
+
|
61
|
+
|
62
|
+
.budget-progress__meter{
|
63
|
+
min-width: 0.1%;
|
64
|
+
}
|
65
|
+
|
66
|
+
.budget-summary__selected{
|
67
|
+
border-top: $border;
|
68
|
+
padding-top: .5rem;
|
69
|
+
padding-bottom: .5rem;
|
70
|
+
}
|
71
|
+
|
72
|
+
.budget-summary__selected-list{
|
73
|
+
margin-top: 2rem;
|
74
|
+
}
|
75
|
+
|
76
|
+
.budget-summary__selected-number{
|
77
|
+
margin: 0 .5rem;
|
78
|
+
}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
//Foundation progress extension
|
2
|
+
.progress{
|
3
|
+
position: relative;
|
4
|
+
}
|
5
|
+
.progress-meter--minimum{
|
6
|
+
background: repeating-linear-gradient(-55deg, rgba(white, 0.2), rgba(white, 0.2) 8px, rgba(black, 0.03) 8px, rgba(black, 0.03) 16px);
|
7
|
+
position: absolute;
|
8
|
+
}
|
9
|
+
|
10
|
+
.progress-meter-text--right{
|
11
|
+
left: auto;
|
12
|
+
min-width: 100%;
|
13
|
+
transform: translate(0, -50%);
|
14
|
+
text-align: right;
|
15
|
+
padding-left: 1rem;
|
16
|
+
padding-right: .5rem;
|
17
|
+
}
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Decidim
|
3
|
+
module Budgets
|
4
|
+
# A command with all the business to add new line items to orders
|
5
|
+
class AddLineItem < Rectify::Command
|
6
|
+
# Public: Initializes the command.
|
7
|
+
#
|
8
|
+
# order - The current order for the user or nil if it is not created yet.
|
9
|
+
# project - The the project to include in the order
|
10
|
+
# current_user - The current user logged in
|
11
|
+
def initialize(current_order, project, current_user)
|
12
|
+
@order = current_order
|
13
|
+
@project = project
|
14
|
+
@current_user = current_user
|
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
|
+
transaction do
|
25
|
+
return broadcast(:invalid) if order.checked_out?
|
26
|
+
add_line_item
|
27
|
+
broadcast(:ok, order)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def order
|
34
|
+
@order ||= Order.create!(user: @current_user, feature: @project.feature)
|
35
|
+
end
|
36
|
+
|
37
|
+
def add_line_item
|
38
|
+
order.projects << @project
|
39
|
+
order.save!
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Decidim
|
3
|
+
module Budgets
|
4
|
+
module Admin
|
5
|
+
# This command is executed when the user creates a Project from the admin
|
6
|
+
# panel.
|
7
|
+
class CreateProject < Rectify::Command
|
8
|
+
def initialize(form)
|
9
|
+
@form = form
|
10
|
+
end
|
11
|
+
|
12
|
+
# Creates the project if valid.
|
13
|
+
#
|
14
|
+
# Broadcasts :ok if successful, :invalid otherwise.
|
15
|
+
def call
|
16
|
+
return broadcast(:invalid) if @form.invalid?
|
17
|
+
|
18
|
+
transaction do
|
19
|
+
create_project
|
20
|
+
link_proposals
|
21
|
+
end
|
22
|
+
|
23
|
+
broadcast(:ok)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
attr_reader :project
|
29
|
+
|
30
|
+
def create_project
|
31
|
+
@project = Project.create!(
|
32
|
+
scope: @form.scope,
|
33
|
+
category: @form.category,
|
34
|
+
feature: @form.current_feature,
|
35
|
+
title: @form.title,
|
36
|
+
short_description: @form.short_description,
|
37
|
+
description: @form.description,
|
38
|
+
budget: @form.budget
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
def proposals
|
43
|
+
@proposals ||= project.sibling_scope(:proposals).where(id: @form.proposal_ids)
|
44
|
+
end
|
45
|
+
|
46
|
+
def link_proposals
|
47
|
+
project.link_resources(proposals, "included_proposals")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Decidim
|
3
|
+
module Budgets
|
4
|
+
module Admin
|
5
|
+
# This command is executed when the user changes a Project from the admin
|
6
|
+
# panel.
|
7
|
+
class UpdateProject < Rectify::Command
|
8
|
+
# Initializes an UpdateProject Command.
|
9
|
+
#
|
10
|
+
# form - The form from which to get the data.
|
11
|
+
# project - The current instance of the project to be updated.
|
12
|
+
def initialize(form, project)
|
13
|
+
@form = form
|
14
|
+
@project = project
|
15
|
+
end
|
16
|
+
|
17
|
+
# Updates the project if valid.
|
18
|
+
#
|
19
|
+
# Broadcasts :ok if successful, :invalid otherwise.
|
20
|
+
def call
|
21
|
+
return broadcast(:invalid) if form.invalid?
|
22
|
+
|
23
|
+
transaction do
|
24
|
+
update_project
|
25
|
+
link_proposals
|
26
|
+
end
|
27
|
+
|
28
|
+
broadcast(:ok)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
attr_reader :project, :form
|
34
|
+
|
35
|
+
def update_project
|
36
|
+
project.update_attributes!(
|
37
|
+
scope: form.scope,
|
38
|
+
category: form.category,
|
39
|
+
title: form.title,
|
40
|
+
short_description: form.short_description,
|
41
|
+
description: form.description,
|
42
|
+
budget: form.budget
|
43
|
+
)
|
44
|
+
end
|
45
|
+
|
46
|
+
def proposals
|
47
|
+
@proposals ||= project.sibling_scope(:proposals).where(id: form.proposal_ids)
|
48
|
+
end
|
49
|
+
|
50
|
+
def link_proposals
|
51
|
+
project.link_resources(proposals, "included_proposals")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Decidim
|
3
|
+
module Budgets
|
4
|
+
# A command with all the business to cancel an order.
|
5
|
+
class CancelOrder < Rectify::Command
|
6
|
+
# Public: Initializes the command.
|
7
|
+
#
|
8
|
+
# order - The current order for the user.
|
9
|
+
def initialize(order)
|
10
|
+
@order = order
|
11
|
+
end
|
12
|
+
|
13
|
+
# Executes the command. Broadcasts these events:
|
14
|
+
#
|
15
|
+
# - :ok when everything is valid.
|
16
|
+
# - :invalid if the there is an error.
|
17
|
+
#
|
18
|
+
# Returns nothing.
|
19
|
+
def call
|
20
|
+
return broadcast(:invalid) if invalid_order?
|
21
|
+
cancel_order!
|
22
|
+
broadcast(:ok, @order)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def invalid_order?
|
28
|
+
!@order&.checked_out?
|
29
|
+
end
|
30
|
+
|
31
|
+
def cancel_order!
|
32
|
+
@order.destroy!
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Decidim
|
3
|
+
module Budgets
|
4
|
+
# A command with all the business to checkout.
|
5
|
+
class Checkout < Rectify::Command
|
6
|
+
# Public: Initializes the command.
|
7
|
+
#
|
8
|
+
# order - The current order for the user.
|
9
|
+
# feature - The current feature.
|
10
|
+
def initialize(order, feature)
|
11
|
+
@order = order
|
12
|
+
@feature = feature
|
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) unless @order&.can_checkout?
|
23
|
+
checkout!
|
24
|
+
broadcast(:ok, @order)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def checkout!
|
30
|
+
@order.update_attributes!(checked_out_at: Time.current)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Decidim
|
3
|
+
module Budgets
|
4
|
+
# A command with all the business to add remove line items from orders
|
5
|
+
class RemoveLineItem < Rectify::Command
|
6
|
+
# Public: Initializes the command.
|
7
|
+
#
|
8
|
+
# order - The current order for the user
|
9
|
+
# project - The the project to remove from the order
|
10
|
+
def initialize(order, project)
|
11
|
+
@order = order
|
12
|
+
@project = project
|
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) if @order.checked_out?
|
23
|
+
remove_line_item
|
24
|
+
broadcast(:ok, @order)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def remove_line_item
|
30
|
+
@order.projects.destroy(@project)
|
31
|
+
@order.save!
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/concern"
|
4
|
+
|
5
|
+
module Decidim
|
6
|
+
module Budgets
|
7
|
+
# Shared behaviour for controllers that need the current order to be present.
|
8
|
+
module NeedsCurrentOrder
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
included do
|
12
|
+
helper_method :current_order
|
13
|
+
|
14
|
+
# The current order created by the user.
|
15
|
+
#
|
16
|
+
# Returns an Order.
|
17
|
+
def current_order
|
18
|
+
@current_order ||= Order.includes(:projects).find_by(user: current_user, feature: current_feature)
|
19
|
+
end
|
20
|
+
|
21
|
+
def current_order=(order)
|
22
|
+
@current_order = order
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Decidim
|
3
|
+
module Budgets
|
4
|
+
module Admin
|
5
|
+
# This controller is the abstract class from which all other controllers of
|
6
|
+
# this engine inherit.
|
7
|
+
#
|
8
|
+
# Note that it inherits from `Decidim::Features::BaseController`, which
|
9
|
+
# override its layout and provide all kinds of useful methods.
|
10
|
+
class ApplicationController < Decidim::Admin::Features::BaseController
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Decidim
|
3
|
+
module Budgets
|
4
|
+
module Admin
|
5
|
+
# This controller allows an admin to manage projects from a Participatory Process
|
6
|
+
class ProjectsController < Admin::ApplicationController
|
7
|
+
helper_method :projects
|
8
|
+
|
9
|
+
def new
|
10
|
+
@form = form(ProjectForm).instance
|
11
|
+
end
|
12
|
+
|
13
|
+
def create
|
14
|
+
@form = form(ProjectForm).from_params(params)
|
15
|
+
|
16
|
+
CreateProject.call(@form) do
|
17
|
+
on(:ok) do
|
18
|
+
flash[:notice] = I18n.t("projects.create.success", scope: "decidim.budgets.admin")
|
19
|
+
redirect_to projects_path
|
20
|
+
end
|
21
|
+
|
22
|
+
on(:invalid) do
|
23
|
+
flash.now[:alert] = I18n.t("projects.create.invalid", scope: "decidim.budgets.admin")
|
24
|
+
render action: "new"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def edit
|
30
|
+
@form = form(ProjectForm).from_model(project)
|
31
|
+
end
|
32
|
+
|
33
|
+
def update
|
34
|
+
@form = form(ProjectForm).from_params(params)
|
35
|
+
|
36
|
+
UpdateProject.call(@form, project) do
|
37
|
+
on(:ok) do
|
38
|
+
flash[:notice] = I18n.t("projects.update.success", scope: "decidim.budgets.admin")
|
39
|
+
redirect_to projects_path
|
40
|
+
end
|
41
|
+
|
42
|
+
on(:invalid) do
|
43
|
+
flash.now[:alert] = I18n.t("projects.update.invalid", scope: "decidim.budgets.admin")
|
44
|
+
render action: "edit"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def destroy
|
50
|
+
project.destroy!
|
51
|
+
|
52
|
+
flash[:notice] = I18n.t("projects.destroy.success", scope: "decidim.budgets.admin")
|
53
|
+
|
54
|
+
redirect_to projects_path
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def projects
|
60
|
+
@projects ||= Project.where(feature: current_feature)
|
61
|
+
end
|
62
|
+
|
63
|
+
def project
|
64
|
+
@project ||= projects.find(params[:id])
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Budgets
|
5
|
+
# This controller is the abstract class from which all other controllers of
|
6
|
+
# this engine inherit.
|
7
|
+
#
|
8
|
+
# Note that it inherits from `Decidim::Components::BaseController`, which
|
9
|
+
# override its layout and provide all kinds of useful methods.
|
10
|
+
class ApplicationController < Decidim::Features::BaseController
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Budgets
|
5
|
+
# Exposes the line items resource so users can create and remove from orders.
|
6
|
+
class LineItemsController < Decidim::Budgets::ApplicationController
|
7
|
+
include NeedsCurrentOrder
|
8
|
+
|
9
|
+
helper_method :project
|
10
|
+
|
11
|
+
def create
|
12
|
+
AddLineItem.call(current_order, project, current_user) do
|
13
|
+
on(:ok) do |order|
|
14
|
+
self.current_order = order
|
15
|
+
render "update_budget"
|
16
|
+
end
|
17
|
+
|
18
|
+
on(:invalid) do
|
19
|
+
render nothing: true, status: 422
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def destroy
|
25
|
+
RemoveLineItem.call(current_order, project) do
|
26
|
+
on(:ok) do |_order|
|
27
|
+
render "update_budget"
|
28
|
+
end
|
29
|
+
|
30
|
+
on(:invalid) do
|
31
|
+
render nothing: true, status: 422
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def project
|
39
|
+
@project ||= Project.where(id: params[:project_id], feature: current_feature).first
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Budgets
|
5
|
+
# Exposes the order resource so users can checkout it.
|
6
|
+
class OrdersController < Decidim::Budgets::ApplicationController
|
7
|
+
include NeedsCurrentOrder
|
8
|
+
|
9
|
+
def checkout
|
10
|
+
Checkout.call(current_order, current_feature) do
|
11
|
+
on(:ok) do
|
12
|
+
flash[:notice] = I18n.t("orders.checkout.success", scope: "decidim")
|
13
|
+
redirect_to projects_path
|
14
|
+
end
|
15
|
+
|
16
|
+
on(:invalid) do
|
17
|
+
flash.now[:alert] = I18n.t("orders.checkout.error", scope: "decidim")
|
18
|
+
redirect_to projects_path
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def destroy
|
24
|
+
CancelOrder.call(current_order) do
|
25
|
+
on(:ok) do
|
26
|
+
flash[:notice] = I18n.t("orders.destroy.success", scope: "decidim")
|
27
|
+
redirect_to projects_path
|
28
|
+
end
|
29
|
+
|
30
|
+
on(:invalid) do
|
31
|
+
flash.now[:alert] = I18n.t("orders.destroy.error", scope: "decidim")
|
32
|
+
redirect_to projects_path
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|