diff --git a/.copier-answers.yml b/.copier-answers.yml index c05d0551..302c88f3 100644 --- a/.copier-answers.yml +++ b/.copier-answers.yml @@ -15,9 +15,10 @@ odoo_version: 14.0 org_name: Odoo Community Association (OCA) org_slug: OCA rebel_module_groups: [] -repo_description: 'TODO: add repo description.' -repo_name: account-budgeting +repo_description: You'll find modules that manage budgeting. +repo_name: Odoo Budgeting repo_slug: account-budgeting repo_website: https://github.com/OCA/account-budgeting travis_apt_packages: [] travis_apt_sources: [] + diff --git a/README.md b/README.md index 37ac89be..496e06ad 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,9 @@ -# account-budgeting +# Odoo Budgeting -TODO: add repo description. +You'll find modules that manage budgeting. diff --git a/account_budget_oca_analytic_tag/README.rst b/account_budget_oca_analytic_tag/README.rst new file mode 100644 index 00000000..68a40518 --- /dev/null +++ b/account_budget_oca_analytic_tag/README.rst @@ -0,0 +1,24 @@ +.. image:: https://img.shields.io/badge/licence-LGPL--3-blue.svg + :target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html + :alt: License: LGPL-3 + +=============================== +OSI Account Budget Analytic Tag +=============================== + +This module allows you to select an analytic tag on the budget line and report the consumed budget using that tag. + +Usage +===== + +No special usage instructions + +Credits +======= + +* Maxime Chambreuil + +Contributors +------------ + +* Open Source Integrators diff --git a/account_budget_oca_analytic_tag/__init__.py b/account_budget_oca_analytic_tag/__init__.py new file mode 100644 index 00000000..7d768b54 --- /dev/null +++ b/account_budget_oca_analytic_tag/__init__.py @@ -0,0 +1,3 @@ +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from . import models diff --git a/account_budget_oca_analytic_tag/__manifest__.py b/account_budget_oca_analytic_tag/__manifest__.py new file mode 100644 index 00000000..38c38a29 --- /dev/null +++ b/account_budget_oca_analytic_tag/__manifest__.py @@ -0,0 +1,20 @@ +# Copyright (c) 2021 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "OSI Account Budget OCA Analytic Tag", + "version": "14.0.1.0.0", + "license": "AGPL-3", + "summary": "This module allows you to select an analytic tag on the budget" + " line and report the consumed budget using that tag.", + "author": "Open Source Integrators, Odoo Community Association (OCA)", + "maintainer": "Open Source Integrators", + "website": "https://github.com/OCA/account-budgeting", + "category": "Accounting", + "depends": ["account_budget_oca"], + "data": [ + "views/account_budget_views.xml", + ], + "installable": True, + "maintainers": ["max3903"], +} diff --git a/account_budget_oca_analytic_tag/i18n/account_budget_analytic_tag.pot b/account_budget_oca_analytic_tag/i18n/account_budget_analytic_tag.pot new file mode 100644 index 00000000..e1a526ba --- /dev/null +++ b/account_budget_oca_analytic_tag/i18n/account_budget_analytic_tag.pot @@ -0,0 +1,49 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * account_budget_analytic_tag +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0+e-20211202\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-12-23 19:57+0000\n" +"PO-Revision-Date: 2021-12-23 19:57+0000\n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: account_budget_analytic_tag +#: model:ir.model.fields,field_description:account_budget_analytic_tag.field_crossovered_budget_lines__analytic_tag_id +msgid "Analytic Tag" +msgstr "" + +#. module: account_budget_analytic_tag +#: model:ir.model,name:account_budget_analytic_tag.model_crossovered_budget_lines +msgid "Budget Line" +msgstr "" + +#. module: account_budget_analytic_tag +#: model:ir.model.fields,field_description:account_budget_analytic_tag.field_crossovered_budget_lines__display_name +msgid "Display Name" +msgstr "" + +#. module: account_budget_analytic_tag +#: model:ir.model.fields,field_description:account_budget_analytic_tag.field_crossovered_budget_lines__id +msgid "ID" +msgstr "" + +#. module: account_budget_analytic_tag +#: model:ir.model.fields,field_description:account_budget_analytic_tag.field_crossovered_budget_lines____last_update +msgid "Last Modified on" +msgstr "" + +#. module: account_budget_analytic_tag +#: code:addons/account_budget_analytic_tag/models/account_budget.py:0 +#, python-format +msgid "" +"You have to enter at least a budgetary position or analytic account or " +"analytic tag on a budget line." +msgstr "" diff --git a/account_budget_oca_analytic_tag/i18n/es.po b/account_budget_oca_analytic_tag/i18n/es.po new file mode 100644 index 00000000..8d1c03a0 --- /dev/null +++ b/account_budget_oca_analytic_tag/i18n/es.po @@ -0,0 +1,51 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * account_budget_analytic_tag +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0+e-20211202\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-12-23 19:57+0000\n" +"PO-Revision-Date: 2021-12-23 19:57+0000\n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: account_budget_analytic_tag +#: model:ir.model.fields,field_description:account_budget_analytic_tag.field_crossovered_budget_lines__analytic_tag_id +msgid "Analytic Tag" +msgstr "Etiqueta analítica" + +#. module: account_budget_analytic_tag +#: model:ir.model,name:account_budget_analytic_tag.model_crossovered_budget_lines +msgid "Budget Line" +msgstr "Línea de presupuesto" + +#. module: account_budget_analytic_tag +#: model:ir.model.fields,field_description:account_budget_analytic_tag.field_crossovered_budget_lines__display_name +msgid "Display Name" +msgstr "Nombre" + +#. module: account_budget_analytic_tag +#: model:ir.model.fields,field_description:account_budget_analytic_tag.field_crossovered_budget_lines__id +msgid "ID" +msgstr "" + +#. module: account_budget_analytic_tag +#: model:ir.model.fields,field_description:account_budget_analytic_tag.field_crossovered_budget_lines____last_update +msgid "Last Modified on" +msgstr "Ultima modificación el" + +#. module: account_budget_analytic_tag +#: code:addons/account_budget_analytic_tag/models/account_budget.py:0 +#, python-format +msgid "" +"You have to enter at least a budgetary position or analytic account or " +"analytic tag on a budget line." +msgstr "" +"Deben entrar por lo menos una posicion presupuestarial, cuenta analítica o etiqueta " +"analítica en una línea de presupuesto." diff --git a/account_budget_oca_analytic_tag/models/__init__.py b/account_budget_oca_analytic_tag/models/__init__.py new file mode 100644 index 00000000..4eb3bdd9 --- /dev/null +++ b/account_budget_oca_analytic_tag/models/__init__.py @@ -0,0 +1,3 @@ +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from . import account_budget diff --git a/account_budget_oca_analytic_tag/models/account_budget.py b/account_budget_oca_analytic_tag/models/account_budget.py new file mode 100644 index 00000000..d5d85397 --- /dev/null +++ b/account_budget_oca_analytic_tag/models/account_budget.py @@ -0,0 +1,73 @@ +# Copyright (c) 2021 Open Source Integrators +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError + + +class CrossoveredBudgetLines(models.Model): + _inherit = "crossovered.budget.lines" + + analytic_tag_id = fields.Many2one("account.analytic.tag", string="Analytic Tag") + + def _compute_practical_amount(self): + """Overwrite this method for to count practical_amount based on + analytic_tag_id on move line.""" + for line in self: + acc_ids = line.general_budget_id.account_ids.ids + date_to = line.date_to + date_from = line.date_from + if line.analytic_account_id.id: + self.env.cr.execute( + """ + SELECT SUM(amount) + FROM account_analytic_line + WHERE account_id=%s + AND (date between %s + AND %s) + AND general_account_id=ANY(%s)""", + (line.analytic_account_id.id, date_from, date_to, acc_ids), + ) + result = self.env.cr.fetchone()[0] or 0.0 + + elif line.general_budget_id.account_ids: + self.env.cr.execute( + """ + SELECT SUM(credit) - SUM(debit) + FROM account_move_line aml + LEFT JOIN account_move am ON aml.move_id = am.id + LEFT JOIN + account_analytic_tag_account_move_line_rel aat + ON aat.account_move_line_id = aml.id + WHERE state=%s + AND account_id in %s + AND (aml.date between %s + AND %s) + AND aat.account_analytic_tag_id=%s""", + ( + "posted", + tuple(line.general_budget_id.account_ids.ids), + date_from, + date_to, + line.analytic_tag_id.id or 0.0, + ), + ) + result = self.env.cr.fetchone()[0] + else: + result = 0.0 + line.practical_amount = result + + @api.constrains("general_budget_id", "analytic_account_id", "analytic_tag_id") + def _must_have_analytical_or_budgetary_or_both(self): + for record in self: + if ( + not record.analytic_account_id + and not record.general_budget_id + and not record.analytic_tag_id + ): + raise ValidationError( + _( + "You have to enter at least a budgetary position or analytic account" + " or analytic tag on a budget line." + ) + ) diff --git a/account_budget_oca_analytic_tag/static/description/icon.png b/account_budget_oca_analytic_tag/static/description/icon.png new file mode 100644 index 00000000..3a0328b5 Binary files /dev/null and b/account_budget_oca_analytic_tag/static/description/icon.png differ diff --git a/account_budget_oca_analytic_tag/tests/__init__.py b/account_budget_oca_analytic_tag/tests/__init__.py new file mode 100644 index 00000000..847859fb --- /dev/null +++ b/account_budget_oca_analytic_tag/tests/__init__.py @@ -0,0 +1,3 @@ +# Copyright (C) 2022 Open Source Integrators (https://www.opensourceintegrators.com) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from . import test_account_budget_oca_analytic_tag diff --git a/account_budget_oca_analytic_tag/tests/test_account_budget_oca_analytic_tag.py b/account_budget_oca_analytic_tag/tests/test_account_budget_oca_analytic_tag.py new file mode 100644 index 00000000..d83bf2a3 --- /dev/null +++ b/account_budget_oca_analytic_tag/tests/test_account_budget_oca_analytic_tag.py @@ -0,0 +1,83 @@ +# Copyright (C) 2022 Open Source Integrators (https://www.opensourceintegrators.com) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo.tests import common + + +class TestBudgetAnalyticTag(common.TransactionCase): + def setUp(self): + super(TestBudgetAnalyticTag, self).setUp() + + self.budget_position_obj = self.env["account.budget.post"] + self.exp_account_type = self.env.ref("account.data_account_type_expenses") + self.company_id = self.env.ref("base.main_company") + self.analytic_account_id = self.env.ref("analytic.analytic_agrolait") + self.user_id = self.env.ref("base.user_admin") + self.partner_id = self.env.ref("base.res_partner_2") + self.product_id = self.env.ref("product.product_product_8") + self.budget_position_id = self.test_create_budget_position() + + def test_create_budget_position(self): + account_ids = ( + self.env["account.account"] + .search( + [ + ("company_id", "=", self.company_id.id), + ("user_type_id", "=", self.exp_account_type.id), + ] + ) + .ids + ) + self.account_budget_post_purchase0 = self.env["account.budget.post"].create( + {"name": "Purchases", "account_ids": [(6, None, account_ids)]} + ) + return self.budget_position_obj.create( + { + "name": "Budget Position", + "company_id": self.company_id.id, + "account_ids": [(6, 0, account_ids)], + } + ) + + def test_budget_creation(self): + budget_id = self.env["crossovered.budget"].create( + { + "name": "Budget 2022", + "creating_user_id": self.user_id.id, + "company_id": self.company_id.id, + "date_from": "2022-01-01", + "date_to": "2022-06-30", + "crossovered_budget_line_ids": [ + ( + 0, + 0, + { + "general_budget_id": self.budget_position_id.id, + "analytic_account_id": self.analytic_account_id.id, + "date_from": "2022-01-01", + "date_to": "2022-06-30", + "planned_amount": 10000.00, + }, + ) + ], + } + ) + # Add line to budget + line_id = self.env["crossovered.budget.lines"].create( + { + "crossovered_budget_id": budget_id.id, + "date_from": "2022-01-01", + "date_to": "2022-06-30", + "general_budget_id": self.budget_position_id.id, + "planned_amount": 30000.0, + } + ) + # Modify budget line + line_id.write( + { + "general_budget_id": self.account_budget_post_purchase0.id, + "planned_amount": 25000.0, + } + ) + budget_id.action_budget_confirm() + budget_id.action_budget_validate() diff --git a/account_budget_oca_analytic_tag/views/account_budget_views.xml b/account_budget_oca_analytic_tag/views/account_budget_views.xml new file mode 100644 index 00000000..1530789e --- /dev/null +++ b/account_budget_oca_analytic_tag/views/account_budget_views.xml @@ -0,0 +1,41 @@ + + + + crossovered.budget.view.form.inherit.analytic_tag + crossovered.budget + + + + 0 + + + 0 + + + + + + + + + + + diff --git a/setup/account_budget_oca_analytic_tag/odoo/addons/account_budget_oca_analytic_tag b/setup/account_budget_oca_analytic_tag/odoo/addons/account_budget_oca_analytic_tag new file mode 120000 index 00000000..014f2182 --- /dev/null +++ b/setup/account_budget_oca_analytic_tag/odoo/addons/account_budget_oca_analytic_tag @@ -0,0 +1 @@ +../../../../account_budget_oca_analytic_tag \ No newline at end of file diff --git a/setup/account_budget_oca_analytic_tag/setup.py b/setup/account_budget_oca_analytic_tag/setup.py new file mode 100644 index 00000000..28c57bb6 --- /dev/null +++ b/setup/account_budget_oca_analytic_tag/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)