-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ADD] budget_management: add budget management module
Add budget_management module to manage the budget in the analytic account. Users can create budgets and manage budget lines inside it. All the budget lines are related to analytic account and analytic account lines. The target budget for each account can be set and progress can be seen in the budget line views. Also, users can revise the budget and a new budget can be seen in chatter.
- Loading branch information
Showing
16 changed files
with
585 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
from . import models | ||
from . import wizard |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
{ | ||
"name": "Budget Management", | ||
"summary": "Module for managing budgets", | ||
"description": "Module for managing budgets", | ||
"category": "Account/ Budget Management", | ||
"version": "1.0", | ||
"application": True, | ||
"installable": True, | ||
"depends": ["base", "analytic"], | ||
"data": [ | ||
"security/ir.model.access.csv", | ||
"views/analytic_line_views.xml", | ||
"views/budget_budget_line_views.xml", | ||
"views/budget_budget_views.xml", | ||
"views/budget_budget_menu_views.xml", | ||
"wizard/budget_wizard_views.xml", | ||
], | ||
"license": "AGPL-3", | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from . import budget_line | ||
from . import budget_budget | ||
from . import analytic_line |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
from odoo import fields, models | ||
|
||
|
||
class AnalyticLine(models.Model): | ||
_inherit = "account.analytic.line" | ||
|
||
budget_line_id = fields.Many2one( | ||
"budget.budget.line", "Budget Line", ondelete="cascade" | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
from markupsafe import Markup | ||
|
||
from odoo import api, fields, models | ||
from odoo.exceptions import ValidationError | ||
|
||
|
||
class BudgetBudget(models.Model): | ||
_name = "budget.budget" | ||
_description = "Budget" | ||
_inherit = ["mail.thread", "mail.activity.mixin"] | ||
|
||
name = fields.Char(compute="_compute_name") | ||
date_from = fields.Date(required=True) | ||
date_to = fields.Date(required=True) | ||
color = fields.Integer(string="Color Index") | ||
active = fields.Boolean(default=True) | ||
show_warning = fields.Boolean(default=False, compute="_compute_show_warning") | ||
state = fields.Selection( | ||
[ | ||
("draft", "Draft"), | ||
("confirmed", "Confirmed"), | ||
("revised", "Revised"), | ||
("done", "Done"), | ||
], | ||
default="draft", | ||
) | ||
action_over_budget = fields.Selection( | ||
[("warning", "Warning"), ("restrict", "Restrict")], | ||
default="warning", | ||
) | ||
user_id = fields.Many2one("res.users", string="Responsible") | ||
company_id = fields.Many2one("res.company", string="Company") | ||
parent_id = fields.Many2one( | ||
string="Revision Of", | ||
comodel_name="budget.budget", | ||
ondelete="cascade", | ||
) | ||
budget_line_ids = fields.One2many( | ||
"budget.budget.line", "budget_id", string="Budget lines" | ||
) | ||
children_ids = fields.One2many( | ||
string="Revisions", | ||
comodel_name="budget.budget", | ||
inverse_name="parent_id", | ||
) | ||
|
||
@api.constrains("date_from", "date_to") | ||
def _check_dates(self): | ||
for budget in self: | ||
if ( | ||
budget.date_from | ||
and budget.date_to | ||
and budget.date_from > budget.date_to | ||
): | ||
raise ValidationError("The start date must be before the end date.") | ||
|
||
# period must be unique for all active budget | ||
@api.constrains("date_from", "date_to") | ||
def _check_date(self): | ||
for budget in self: | ||
if budget.date_from and budget.date_to: | ||
existing_budgets = self.search( | ||
[ | ||
("date_from", "=", budget.date_to), | ||
("date_to", "=", budget.date_from), | ||
("active", "=", True), | ||
("id", "!=", budget.id), | ||
] | ||
) | ||
if existing_budgets: | ||
raise ValidationError( | ||
"Budget period must be unique for all active budgets." | ||
) | ||
|
||
@api.depends("budget_line_ids.achieved_amount") | ||
def _compute_show_warning(self): | ||
for record in self: | ||
if record.action_over_budget == "warning" and any( | ||
ob.achieved_amount > ob.amount for ob in record.budget_line_ids | ||
): | ||
record.show_warning = True | ||
else: | ||
record.show_warning = False | ||
|
||
@api.depends("name", "date_from", "date_to") | ||
def _compute_name(self): | ||
for budget in self: | ||
if budget.date_from and budget.date_to: | ||
budget.name = "Budget: %s - %s " % ( | ||
budget.date_from.__format__("%d/%m/%Y"), | ||
budget.date_to.__format__("%d/%m/%Y"), | ||
) | ||
else: | ||
budget.name = "Budget: (from) - (to)" | ||
|
||
def action_budget_confirm(self): | ||
self.parent_id.filtered(lambda b: b.state == "confirmed").state = "revised" | ||
for budget in self: | ||
budget.state = "revised" if budget.children_ids else "confirmed" | ||
|
||
def action_budget_draft(self): | ||
self.state = "draft" | ||
|
||
def action_budget_done(self): | ||
self.state = "done" | ||
|
||
def create_revised_budget(self): | ||
revised = self.browse() | ||
for budget in self: | ||
budget.state = "revised" | ||
budget.active = False | ||
revised_budget = budget.copy( | ||
default={ | ||
"name": budget.name, | ||
"parent_id": budget.id, | ||
"active": True, | ||
} | ||
) | ||
|
||
revised += revised_budget | ||
budget.message_post( | ||
body=Markup( | ||
"%s: <a href='#' data-oe-model='budget.budget' data-oe-id='%s'>%s</a>" | ||
) | ||
% ( | ||
"New revision", | ||
revised_budget.id, | ||
revised_budget.name, | ||
) | ||
) | ||
return revised._get_records_action() | ||
|
||
def action_open_budget_lines(self): | ||
return { | ||
"name": "Budget Lines", | ||
"view_mode": "list,graph,pivot,gantt", | ||
"res_model": "budget.budget.line", | ||
"type": "ir.actions.act_window", | ||
"domain": [("budget_id", "=", self.id)], | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
from odoo import api, fields, models | ||
from odoo.exceptions import ValidationError | ||
|
||
|
||
class BudgetLine(models.Model): | ||
_name = "budget.budget.line" | ||
_description = "Budget Budget Line" | ||
|
||
name = fields.Char("Description", default="Budget Line") | ||
amount = fields.Float("Budget Amount", required=True) | ||
achieved_amount = fields.Float( | ||
"Achieved Amount", compute="_compute_achieved_amount", store=True | ||
) | ||
achieved_percent = fields.Float("Achieved %", compute="_compute_achieved_percent") | ||
date_from = fields.Date(related="budget_id.date_from") | ||
date_to = fields.Date(related="budget_id.date_to") | ||
sequence = fields.Integer("Sequence", default=1) | ||
budget_id = fields.Many2one("budget.budget", required=True) | ||
account_id = fields.Many2one("account.analytic.account", "Account") | ||
user_id = fields.Many2one(related="budget_id.user_id") | ||
analytic_line_ids = fields.One2many( | ||
"account.analytic.line", "budget_line_id", string="Analytic Lines" | ||
) | ||
|
||
@api.constrains("achieved_amount", "amount") | ||
def _check_restriction_on_creation(self): | ||
for record in self: | ||
if record.budget_id.action_over_budget == "restrict": | ||
if record.achieved_amount > record.amount: | ||
raise ValidationError( | ||
"Achieved amount cannot exceed amount when 'Restriction' is selected." | ||
) | ||
|
||
@api.depends("amount", "achieved_amount") | ||
def _compute_achieved_percent(self): | ||
for line in self: | ||
if line.account_id and line.amount: | ||
line.achieved_percent = (line.achieved_amount) / line.amount * 100 | ||
else: | ||
line.achieved_percent = 0 | ||
|
||
@api.depends( | ||
"analytic_line_ids.amount", | ||
) | ||
def _compute_achieved_amount(self): | ||
for record in self: | ||
total_achieved = abs( | ||
sum( | ||
record.analytic_line_ids.filtered(lambda l: l.amount < 0).mapped( | ||
"amount" | ||
) | ||
) | ||
) | ||
record.achieved_amount = total_achieved | ||
|
||
def action_open_analytic_lines(self): | ||
return { | ||
"type": "ir.actions.act_window", | ||
"name": "Analytic Lines", | ||
"res_model": "account.analytic.line", | ||
"view_mode": "list", | ||
"target": "new", | ||
"context": { | ||
"default_account_id": self.account_id.id, | ||
"default_date": self.budget_id.date_from, | ||
"default_budget_line_id": self.id, | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink | ||
budget_management.access_budget_budget_line,access_budget_budget_line,budget_management.model_budget_budget_line,base.group_user,1,1,1,1 | ||
budget_management.access_budget_budget,access_budget_budget,budget_management.model_budget_budget,base.group_user,1,1,1,1 | ||
budget_management.access_budget_wizard,access_budget_wizard,budget_management.model_budget_wizard,base.group_user,1,1,1,1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<comment version="3.0"> | ||
<caption/> | ||
<note>Piggy bank and dollar coin icon thin line for web and mobile, modern minimalistic flat design. Vector icon with dark grey outline and offset colour on light grey background.</note> | ||
<place/> | ||
<categories/> | ||
</comment> |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<odoo> | ||
|
||
<record id="view_account_analytic_line_tree_inherit_module_name" model="ir.ui.view"> | ||
<field name="name">account.analytic.line.view.list.inherit</field> | ||
<field name="model">account.analytic.line</field> | ||
<field name="inherit_id" ref="analytic.view_account_analytic_line_tree"/> | ||
<field name="arch" type="xml"> | ||
<xpath expr="//list" position="inside"> | ||
<field name="budget_line_id" optional="hide"></field> | ||
</xpath> | ||
|
||
<xpath expr="//list" position="attributes"> | ||
<attribute name="editable">bottom</attribute> | ||
</xpath> | ||
</field> | ||
</record> | ||
|
||
</odoo> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<odoo> | ||
|
||
<record id="budget_budget_line_action" model="ir.actions.act_window"> | ||
<field name="name">Budget Lines</field> | ||
<field name="res_model">budget.budget.line</field> | ||
<field name="view_mode">list,graph,gantt,pivot</field> | ||
<field name="context">[('budget_id','=',active_id)]</field> | ||
<field name="help" type="html"> | ||
<p class="o_view_nocontent_smiling_face"> | ||
Define new budget line | ||
</p> | ||
<p> | ||
Use options specified in form to list budget line | ||
</p> | ||
</field> | ||
</record> | ||
|
||
<record id="budget_budget_line_view_list" model="ir.ui.view"> | ||
<field name="name">budget.budget.line.view.list</field> | ||
<field name="model">budget.budget.line</field> | ||
<field name="arch" type="xml"> | ||
<list string="Budget Line"> | ||
<field name="sequence" widget="handle"/> | ||
<field name="name"/> | ||
<field name="account_id" optional="show"/> | ||
<field name="amount" /> | ||
<field name="achieved_amount" decoration-danger="(achieved_amount > amount)" /> | ||
</list> | ||
</field> | ||
</record> | ||
|
||
<record id="budget_budget_line_view_graph" model="ir.ui.view"> | ||
<field name="name">budget.line.graph</field> | ||
<field name="model">budget.budget.line</field> | ||
<field name="arch" type="xml"> | ||
<graph string="Budget Line" type="bar" stacked="true"> | ||
<field name="name" type="row"/> | ||
<field name="achieved_amount" /> | ||
<field name="amount" type="measure"/> | ||
</graph> | ||
</field> | ||
</record> | ||
|
||
<record id="budget_budget_line_view_gantt" model="ir.ui.view"> | ||
<field name="name">budget.line.gantt.view</field> | ||
<field name="model">budget.budget.line</field> | ||
<field name="arch" type="xml"> | ||
<gantt default_group_by="name" progress="achieved_percent" date_start="date_from" date_stop="date_to" string="Budget Lines" color="id"> | ||
<field name="name"/> | ||
</gantt> | ||
</field> | ||
</record> | ||
|
||
|
||
<record id="budget_budget_line_view_pivot" model="ir.ui.view"> | ||
<field name="name">budget.line.pivot</field> | ||
<field name="model">budget.budget.line</field> | ||
<field name="arch" type="xml"> | ||
<pivot string="Budget Lines"> | ||
<field name="name" type="row"/> | ||
</pivot> | ||
</field> | ||
</record> | ||
|
||
</odoo> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<odoo> | ||
|
||
<menuitem id="budget_management_menu" name="Budget Management" sequence="10" web_icon="budget_management,static/logo.png"/> | ||
<menuitem id="budget_budget_menu" name="Budgets" parent="budget_management_menu" action="budget_management.budget_budget_action" sequence="10"/> | ||
|
||
</odoo> |
Oops, something went wrong.