decidim-budgets 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|