Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[16.0][MIG] budget_control_expense #440

Merged
merged 4 commits into from
Aug 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions budget_control/models/budget_period.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,8 @@ def check_budget_precommit(self, doclines, doc_type="account"):
budget_move = line.with_context(force_commit=True).commit_budget()
if budget_move:
budget_moves.append(budget_move)
# Update database, so we can check budget with query
budget_move.flush_model()
# Check Budget
self.env["budget.period"].check_budget(doclines, doc_type=doc_type)
# Remove commits
Expand Down
6 changes: 6 additions & 0 deletions budget_control/views/account_move_views.xml
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,16 @@
expr="//field[@name='invoice_line_ids']/tree/field[@name='analytic_distribution']"
position="after"
>
<!-- Add new field no permission -->
<field name="analytic_distribution" invisible="1" />
<field
name="json_budget_popover"
optional="show"
nolabel="1"
string="Budget Figure"
width="10px"
widget="popover_widget"
attrs="{'invisible': [('analytic_distribution', '=', False)]}"
groups="budget_control.group_budget_control_user"
/>
</xpath>
Expand All @@ -77,13 +80,16 @@
expr="//page[@id='aml_tab']/field[@name='line_ids']/tree/field[@name='analytic_distribution']"
position="after"
>
<!-- Add new field no permission -->
<field name="analytic_distribution" invisible="1" />
<field
name="json_budget_popover"
optional="show"
nolabel="1"
string="Budget Figure"
width="10px"
widget="popover_widget"
attrs="{'invisible': [('analytic_distribution', '=', False)]}"
groups="budget_control.group_budget_control_user"
/>
</xpath>
Expand Down
82 changes: 82 additions & 0 deletions budget_control_expense/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
=========================
Budget Control on Expense
=========================

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:706da40b770c239865c0e98f26db39077822f0f37c7c3c33a5c580b3df043c93
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |badge1| image:: https://img.shields.io/badge/maturity-Alpha-red.png
:target: https://odoo-community.org/page/development-status
:alt: Alpha
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-ecosoft--odoo%2Fbudgeting-lightgray.png?logo=github
:target: https://github.com/ecosoft-odoo/budgeting/tree/16.0/budget_control_expense
:alt: ecosoft-odoo/budgeting

|badge1| |badge2| |badge3|

This module will create budget commitment for expense (to be used as alternate actual source in mis_builder)

When expense report is approved, hr_expense.budget.commit is created, and when
journal entry is posted, reversed hr_expense.budget.commit is created.

A new tab "Budget Commitment" is created on expense report for budget user to keep track of the committed budget.

.. IMPORTANT::
This is an alpha version, the data model and design can change at any time without warning.
Only for development or testing purpose, do not use in production.
`More details on development status <https://odoo-community.org/page/development-status>`_

**Table of contents**

.. contents::
:local:

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/ecosoft-odoo/budgeting/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/ecosoft-odoo/budgeting/issues/new?body=module:%20budget_control_expense%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

Do not contact contributors directly about support or help with technical issues.

Credits
=======

Authors
~~~~~~~

* Ecosoft

Contributors
~~~~~~~~~~~~

* Kitti Upariphutthiphong <kittiu@ecosoft.co.th>
* Saran Lim. <saranl@ecosoft.co.th>

Maintainers
~~~~~~~~~~~

.. |maintainer-kittiu| image:: https://github.com/kittiu.png?size=40px
:target: https://github.com/kittiu
:alt: kittiu
.. |maintainer-ru3ix-bbb| image:: https://github.com/ru3ix-bbb.png?size=40px
:target: https://github.com/ru3ix-bbb
:alt: ru3ix-bbb

Current maintainers:

|maintainer-kittiu| |maintainer-ru3ix-bbb|

This module is part of the `ecosoft-odoo/budgeting <https://github.com/ecosoft-odoo/budgeting/tree/16.0/budget_control_expense>`_ project on GitHub.

You are welcome to contribute.
5 changes: 5 additions & 0 deletions budget_control_expense/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from . import models
from . import report
from . import wizard
22 changes: 22 additions & 0 deletions budget_control_expense/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Copyright 2021 Ecosoft Co., Ltd. (http://ecosoft.co.th)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

{
"name": "Budget Control on Expense",
"version": "16.0.1.0.0",
"license": "AGPL-3",
"author": "Ecosoft, Odoo Community Association (OCA)",
"website": "https://github.com/ecosoft-odoo/budgeting",
"depends": ["budget_control", "hr_expense"],
"data": [
"security/ir.model.access.csv",
"views/expense_budget_move.xml",
"views/budget_period_view.xml",
"views/hr_expense_view.xml",
"views/budget_control_view.xml",
"views/budget_commit_forward_view.xml",
],
"installable": True,
"maintainers": ["kittiu", "ru3ix-bbb"],
"development_status": "Alpha",
}
10 changes: 10 additions & 0 deletions budget_control_expense/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from . import account_budget_move
from . import expense_budget_move
from . import budget_period
from . import account_move
from . import account_move_line
from . import hr_expense
from . import budget_control
from . import budget_commit_forward
19 changes: 19 additions & 0 deletions budget_control_expense/models/account_budget_move.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Copyright 2020 Ecosoft Co., Ltd. (http://ecosoft.co.th)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import api, models


class AccountBudgetMove(models.Model):
_inherit = "account.budget.move"

@api.depends("move_id")
def _compute_source_document(self):
res = super()._compute_source_document()
for rec in self.filtered("move_line_id.expense_id.sheet_id"):
if hasattr(rec.move_line_id.expense_id.sheet_id, "number"):
display_name = rec.move_line_id.expense_id.sheet_id.number
else:
display_name = rec.move_line_id.expense_id.sheet_id.display_name
rec.source_document = rec.source_document or display_name
return res
15 changes: 15 additions & 0 deletions budget_control_expense/models/account_move.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright 2020 Ecosoft Co., Ltd. (http://ecosoft.co.th)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import models


class AccountMove(models.Model):
_inherit = "account.move"

def write(self, vals):
"""Uncommit budget for source expense document."""
res = super().write(vals)
if vals.get("state") in ("draft", "posted", "cancel"):
self.mapped("line_ids.expense_id").recompute_budget_move()
return res
46 changes: 46 additions & 0 deletions budget_control_expense/models/account_move_line.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Copyright 2020 Ecosoft Co., Ltd. (http://ecosoft.co.th)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import models


class AccountMoveLine(models.Model):
_inherit = "account.move.line"

def _init_docline_budget_vals(self, budget_vals, analytic_id):
self.ensure_one()
res = super()._init_docline_budget_vals(budget_vals, analytic_id)
expense = self.expense_id
if expense: # case expense (support with include tax)
budget_vals["amount_currency"] = (
(expense.quantity * expense.unit_amount)
if expense.product_has_cost
else expense.total_amount
)
return res

def uncommit_expense_budget(self):
"""Uncommit the budget for related expenses when the vendor bill is in a valid state."""
Expense = self.env["hr.expense"]
for ml in self:
inv_state = ml.move_id.state
if not ml.move_id.expense_sheet_id:
continue
if inv_state == "posted":
expense = ml.expense_id.filtered("amount_commit")
# Because this is not invoice, we need to compare account
if not expense:
continue
# Also test for future advance extension, never uncommit for advance
if hasattr(expense, "advance") and expense["advance"]:
continue
expense.commit_budget(
reverse=True,
move_line_id=ml.id,
date=ml.date_commit,
analytic_distribution=expense.fwd_analytic_distribution or False,
)
else: # Cancel or draft, not commitment line
self.env[Expense._budget_model()].search(
[("move_line_id", "=", ml.id)]
).unlink()
53 changes: 53 additions & 0 deletions budget_control_expense/models/budget_commit_forward.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Copyright 2020 Ecosoft Co., Ltd. (http://ecosoft.co.th)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import fields, models


class BudgetCommitForward(models.Model):
_inherit = "budget.commit.forward"

expense = fields.Boolean(
default=True,
help="If checked, click review budget commitment will pull expense commitment",
)
forward_expense_ids = fields.One2many(
comodel_name="budget.commit.forward.line",
inverse_name="forward_id",
string="Expenses",
domain=[("res_model", "=", "hr.expense")],
)

def _get_budget_docline_model(self):
res = super()._get_budget_docline_model()
if self.expense:
res.append("hr.expense")
return res

def _get_document_number(self, doc):
if doc._name == "hr.expense":
return f"{doc.sheet_id._name},{doc.sheet_id.id}"
return super()._get_document_number(doc)

def _get_base_domain_extension(self, res_model):
"""For module extension"""
if res_model == "hr.expense":
return " AND a.state != 'cancel'"
return super()._get_base_domain_extension(res_model)


class BudgetCommitForwardLine(models.Model):
_inherit = "budget.commit.forward.line"

res_model = fields.Selection(
selection_add=[("hr.expense", "Expense")],
ondelete={"hr.expense": "cascade"},
)
document_id = fields.Reference(
selection_add=[("hr.expense", "Expense")],
ondelete={"hr.expense": "cascade"},
)
document_number = fields.Reference(
selection_add=[("hr.expense.sheet", "Expense Sheet")],
ondelete={"hr.expense.sheet": "cascade"},
)
14 changes: 14 additions & 0 deletions budget_control_expense/models/budget_control.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Copyright 2021 Ecosoft Co., Ltd. (http://ecosoft.co.th)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import fields, models


class BudgetControl(models.Model):
_inherit = "budget.control"

amount_expense = fields.Monetary(
string="Expense",
compute="_compute_budget_info",
help="Sum of expense amount",
)
38 changes: 38 additions & 0 deletions budget_control_expense/models/budget_period.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Copyright 2020 Ecosoft Co., Ltd. (http://ecosoft.co.th)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import api, fields, models


class BudgetPeriod(models.Model):
_inherit = "budget.period"

expense = fields.Boolean(
string="On Expense",
compute="_compute_control_expense",
store=True,
readonly=False,
help="Control budget on expense approved",
)

def _budget_info_query(self):
query = super()._budget_info_query()
query["info_cols"]["amount_expense"] = ("5_ex_commit", True)
return query

@api.depends("control_budget")
def _compute_control_expense(self):
for rec in self:
rec.expense = rec.control_budget

@api.model
def _get_eligible_budget_period(self, date=False, doc_type=False):
budget_period = super()._get_eligible_budget_period(date, doc_type)
# Get period control budget.
# if doctype is expense, check special control too.
if doc_type == "expense":
return budget_period.filtered(
lambda l: (l.control_budget and l.expense)
or (not l.control_budget and l.expense)
)
return budget_period
42 changes: 42 additions & 0 deletions budget_control_expense/models/expense_budget_move.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Copyright 2020 Ecosoft Co., Ltd. (http://ecosoft.co.th)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import api, fields, models


class ExpenseBudgetMove(models.Model):
_name = "expense.budget.move"
_inherit = ["base.budget.move"]
_description = "Expense Budget Moves"

expense_id = fields.Many2one(
comodel_name="hr.expense",
readonly=True,
index=True,
help="Commit budget for this expense_id",
)
sheet_id = fields.Many2one(
comodel_name="hr.expense.sheet",
related="expense_id.sheet_id",
readonly=True,
store=True,
index=True,
)
move_id = fields.Many2one(
comodel_name="account.move",
related="move_line_id.move_id",
store=True,
)
move_line_id = fields.Many2one(
comodel_name="account.move.line",
readonly=True,
index=True,
help="Uncommit budget from this move_line_id",
)

@api.depends("sheet_id")
def _compute_reference(self):
for rec in self:
rec.reference = (
rec.reference if rec.reference else rec.sheet_id.display_name
)
Loading
Loading