diff --git a/account_budget_distribution/.__manifest__.py.swp b/account_budget_distribution/.__manifest__.py.swp new file mode 100644 index 00000000..d4b3fb53 Binary files /dev/null and b/account_budget_distribution/.__manifest__.py.swp differ diff --git a/account_budget_distribution/README.rst b/account_budget_distribution/README.rst new file mode 100644 index 00000000..00bdd253 --- /dev/null +++ b/account_budget_distribution/README.rst @@ -0,0 +1,29 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + +=========================== +Account Budget Distribution +=========================== + +With this module you can distribute symetrically an amount from a budget to its +lines, taking into account its budget positions. + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues +`_. In case of trouble, +please check there if your issue has already been reported. If you spotted +it first, help us smash it by providing detailed and welcomed feedback. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Contributors +------------ + +* Oihane Crucelaegui +* Ana Juaristi diff --git a/account_budget_distribution/__init__.py b/account_budget_distribution/__init__.py new file mode 100644 index 00000000..31ca1a2f --- /dev/null +++ b/account_budget_distribution/__init__.py @@ -0,0 +1,6 @@ +# Copyright 2019 Oihane Crucelaegui - AvanzOSC +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +from . import models +from . import reports +from . import wizards diff --git a/account_budget_distribution/__manifest__.py b/account_budget_distribution/__manifest__.py new file mode 100644 index 00000000..0afadcf6 --- /dev/null +++ b/account_budget_distribution/__manifest__.py @@ -0,0 +1,21 @@ +# Copyright 2019 Oihane Crucelaegui - AvanzOSC +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +{ + "name": "Account Budget Distribution", + "version": "11.0.1.0.0", + "category": "Accounting", + "license": "AGPL-3", + "author": "AvanzOSC","OCA" + "website": "http://www.avanzosc.es", + "depends": [ + "account_budget", + ], + "data": [ + "security/ir.model.access.csv", + "reports/crossovered_budget_resume_view.xml", + "wizards/crossovered_budget_distribution_view.xml", + "views/crossovered_budget_view.xml", + ], + "installable": True, +} diff --git a/account_budget_distribution/i18n/es.po b/account_budget_distribution/i18n/es.po new file mode 100644 index 00000000..a31dbbc4 --- /dev/null +++ b/account_budget_distribution/i18n/es.po @@ -0,0 +1,142 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * account_budget_distribution +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 11.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2019-05-06 12:26+0000\n" +"PO-Revision-Date: 2019-05-06 12:26+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_distribution +#: model:ir.model,name:account_budget_distribution.model_crossovered_budget +#: model:ir.model.fields,field_description:account_budget_distribution.field_crossovered_budget_distribution_budget_id +#: model:ir.model.fields,field_description:account_budget_distribution.field_crossovered_budget_summary_crossovered_budget_id +#: model:ir.ui.view,arch_db:account_budget_distribution.crossovered_budget_summary_view_search +msgid "Budget" +msgstr "Presupuesto" + +#. module: account_budget_distribution +#: model:ir.model,name:account_budget_distribution.model_crossovered_budget_distribution_line +msgid "Budget Distribution Line" +msgstr "Línea de distribución" + +#. module: account_budget_distribution +#: model:ir.model,name:account_budget_distribution.model_crossovered_budget_distribution +msgid "Budget Distribution Wizard" +msgstr "Asistente de distribución" + +#. module: account_budget_distribution +#: model:ir.model.fields,field_description:account_budget_distribution.field_crossovered_budget_distribution_line_budget_post_id +#: model:ir.model.fields,field_description:account_budget_distribution.field_crossovered_budget_summary_general_budget_id +#: model:ir.ui.view,arch_db:account_budget_distribution.crossovered_budget_summary_view_search +msgid "Budget Position" +msgstr "Posición presupuestaria" + +#. module: account_budget_distribution +#: model:ir.ui.view,arch_db:account_budget_distribution.crossovered_budget_distribution_view_form +msgid "Cancel" +msgstr "Cancelar" + +#. module: account_budget_distribution +#: model:ir.model.fields,field_description:account_budget_distribution.field_crossovered_budget_distribution_create_uid +#: model:ir.model.fields,field_description:account_budget_distribution.field_crossovered_budget_distribution_line_create_uid +msgid "Created by" +msgstr "Creado por" + +#. module: account_budget_distribution +#: model:ir.model.fields,field_description:account_budget_distribution.field_crossovered_budget_distribution_create_date +#: model:ir.model.fields,field_description:account_budget_distribution.field_crossovered_budget_distribution_line_create_date +msgid "Created on" +msgstr "Creado en" + +#. module: account_budget_distribution +#: model:ir.actions.act_window,name:account_budget_distribution.action_crossovered_budget_summary_view +#: model:ir.model,name:account_budget_distribution.model_crossovered_budget_summary +#: model:ir.ui.menu,name:account_budget_distribution.crossovered_budget_summary_option_view +msgid "Crossovered Budget Summary Lines" +msgstr "Resumen de presupuestos" + +#. module: account_budget_distribution +#: model:ir.model.fields,field_description:account_budget_distribution.field_crossovered_budget_distribution_display_name +#: model:ir.model.fields,field_description:account_budget_distribution.field_crossovered_budget_distribution_line_display_name +#: model:ir.model.fields,field_description:account_budget_distribution.field_crossovered_budget_summary_display_name +msgid "Display Name" +msgstr "Nombre mostrado" + +#. module: account_budget_distribution +#: model:ir.ui.view,arch_db:account_budget_distribution.crossovered_budget_distribution_view_form +msgid "Distribute" +msgstr "Distribuir" + +#. module: account_budget_distribution +#: model:ir.actions.act_window,name:account_budget_distribution.action_crossovered_budget_distribution +#: model:ir.ui.view,arch_db:account_budget_distribution.crossovered_budget_view_form +msgid "Distribute Budget" +msgstr "Distribuir otros costes" + +#. module: account_budget_distribution +#: model:ir.model.fields,field_description:account_budget_distribution.field_crossovered_budget_distribution_id +#: model:ir.model.fields,field_description:account_budget_distribution.field_crossovered_budget_distribution_line_id +#: model:ir.model.fields,field_description:account_budget_distribution.field_crossovered_budget_summary_id +msgid "ID" +msgstr "ID" + +#. module: account_budget_distribution +#: model:ir.model.fields,field_description:account_budget_distribution.field_crossovered_budget_distribution___last_update +#: model:ir.model.fields,field_description:account_budget_distribution.field_crossovered_budget_distribution_line___last_update +#: model:ir.model.fields,field_description:account_budget_distribution.field_crossovered_budget_summary___last_update +msgid "Last Modified on" +msgstr "Última modificación en" + +#. module: account_budget_distribution +#: model:ir.model.fields,field_description:account_budget_distribution.field_crossovered_budget_distribution_line_write_uid +#: model:ir.model.fields,field_description:account_budget_distribution.field_crossovered_budget_distribution_write_uid +msgid "Last Updated by" +msgstr "Última actualización de" + +#. module: account_budget_distribution +#: model:ir.model.fields,field_description:account_budget_distribution.field_crossovered_budget_distribution_line_write_date +#: model:ir.model.fields,field_description:account_budget_distribution.field_crossovered_budget_distribution_write_date +msgid "Last Updated on" +msgstr "Última Actualización el" + +#. module: account_budget_distribution +#: model:ir.model.fields,field_description:account_budget_distribution.field_crossovered_budget_distribution_line_planned_amount +#: model:ir.model.fields,field_description:account_budget_distribution.field_crossovered_budget_summary_planned_amount +msgid "Planned Amount" +msgstr "Previsión" + +#. module: account_budget_distribution +#: model:ir.model.fields,field_description:account_budget_distribution.field_crossovered_budget_distribution_line_ids +#: model:ir.ui.view,arch_db:account_budget_distribution.crossovered_budget_view_form +msgid "Summary" +msgstr "Resumen" + +#. module: account_budget_distribution +#: model:ir.model.fields,field_description:account_budget_distribution.field_crossovered_budget_summary_ids +msgid "Summary Lines" +msgstr "Líneas de presupuesto" + +#. module: account_budget_distribution +#: model:ir.ui.view,arch_db:account_budget_distribution.crossovered_budget_summary_view_tree +msgid "Total Planned Amount" +msgstr "Total previsto" + +#. module: account_budget_distribution +#: model:ir.model.fields,field_description:account_budget_distribution.field_crossovered_budget_distribution_line_distribution_id +msgid "Wizard" +msgstr "Asistente" + +#. module: account_budget_distribution +#: model:ir.ui.view,arch_db:account_budget_distribution.crossovered_budget_distribution_view_form +msgid "or" +msgstr "o" + diff --git a/account_budget_distribution/models/__init__.py b/account_budget_distribution/models/__init__.py new file mode 100644 index 00000000..36cc21c2 --- /dev/null +++ b/account_budget_distribution/models/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2019 Oihane Crucelaegui - AvanzOSC +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +from . import crossovered_budget diff --git a/account_budget_distribution/models/crossovered_budget.py b/account_budget_distribution/models/crossovered_budget.py new file mode 100644 index 00000000..f36f43f5 --- /dev/null +++ b/account_budget_distribution/models/crossovered_budget.py @@ -0,0 +1,12 @@ +# Copyright 2019 Oihane Crucelaegui - AvanzOSC +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +from odoo import fields, models + + +class CrossoveredBudget(models.Model): + _inherit = 'crossovered.budget' + + summary_ids = fields.One2many( + comodel_name='crossovered.budget.summary', + inverse_name='crossovered_budget_id', string='Summary Lines') diff --git a/account_budget_distribution/reports/__init__.py b/account_budget_distribution/reports/__init__.py new file mode 100644 index 00000000..c7d20864 --- /dev/null +++ b/account_budget_distribution/reports/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2018 Oihane Crucelaegui - AvanzOSC +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +from . import crossovered_budget_resume diff --git a/account_budget_distribution/reports/crossovered_budget_resume.py b/account_budget_distribution/reports/crossovered_budget_resume.py new file mode 100644 index 00000000..4c43da28 --- /dev/null +++ b/account_budget_distribution/reports/crossovered_budget_resume.py @@ -0,0 +1,36 @@ +# Copyright 2019 Oihane Crucelaegui - AvanzOSC +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +from odoo import tools +from odoo import api, fields, models + + +class CrossoveredBudgetSummary(models.Model): + _name = 'crossovered.budget.summary' + _description = 'Crossovered Budget Summary Lines' + _auto = False + _rec_name = 'crossovered_budget_id' + + crossovered_budget_id = fields.Many2one( + comodel_name='crossovered.budget', string='Budget') + general_budget_id = fields.Many2one( + comodel_name='account.budget.post', string='Budget Position') + planned_amount = fields.Float(string='Planned Amount') + + @api.model_cr + def init(self): + tools.drop_view_if_exists(self.env.cr, self._table) + self.env.cr.execute(""" + CREATE or REPLACE VIEW %s as ( + SELECT + row_number() OVER () AS id, + crossovered_budget_id, + general_budget_id, + SUM(planned_amount) as planned_amount + FROM + crossovered_budget_lines + GROUP BY + crossovered_budget_id, + general_budget_id + )""" % ( + self._table)) diff --git a/account_budget_distribution/reports/crossovered_budget_resume_view.xml b/account_budget_distribution/reports/crossovered_budget_resume_view.xml new file mode 100644 index 00000000..f7e3b6d3 --- /dev/null +++ b/account_budget_distribution/reports/crossovered_budget_resume_view.xml @@ -0,0 +1,58 @@ + + + + crossovered.budget.summary + +
+ + + + + + + +
+
+
+ + + crossovered.budget.summary + + + + + + + + + + + crossovered.budget.summary + + + + + + + + + + + + + + Crossovered Budget Summary Lines + crossovered.budget.summary + form + tree,form + { + 'hide_budget_id': False, + } + + + +
diff --git a/account_budget_distribution/security/ir.model.access.csv b/account_budget_distribution/security/ir.model.access.csv new file mode 100755 index 00000000..0f869584 --- /dev/null +++ b/account_budget_distribution/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_crossovered_budget_summary,access_crossovered_budget_summary,model_crossovered_budget_summary,,1,0,0,0 diff --git a/account_budget_distribution/tests/__init__.py b/account_budget_distribution/tests/__init__.py new file mode 100644 index 00000000..5699e90c --- /dev/null +++ b/account_budget_distribution/tests/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2019 Oihane Crucelaegui - AvanzOSC +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +from . import test_account_budget_distribution diff --git a/account_budget_distribution/tests/test_account_budget_distribution.py b/account_budget_distribution/tests/test_account_budget_distribution.py new file mode 100644 index 00000000..9422973e --- /dev/null +++ b/account_budget_distribution/tests/test_account_budget_distribution.py @@ -0,0 +1,46 @@ +# Copyright 2019 Oihane Crucelaegui - AvanzOSC +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +from odoo.addons.account_budget.tests.common import TestAccountBudgetCommon + + +class TestAccountBudgetDistribution(TestAccountBudgetCommon): + + def test_account_budget_distribution(self): + pessimistic_budget = self.browse_ref( + 'account_budget.crossovered_budget_budgetpessimistic0') + self.assertTrue(pessimistic_budget.summary_ids) + pessimistic_summary = pessimistic_budget.summary_ids + wizard = self.env['crossovered.budget.distribution'].with_context( + active_model=pessimistic_budget._name, + active_id=pessimistic_budget.id).create({}) + self.assertEquals(len(wizard.line_ids), len(pessimistic_summary)) + planned_amounts = {} + for line in wizard.line_ids: + self.assertEquals( + line.planned_amount, pessimistic_summary.filtered( + lambda s: s.general_budget_id == line.budget_post_id + ).planned_amount) + budget_lines = pessimistic_budget.crossovered_budget_line.filtered( + lambda l: l.general_budget_id == line.budget_post_id) + try: + budget_lines = budget_lines.filtered( + lambda l: not l.general_budget_id.expenses) + except Exception: + pass + if budget_lines: + planned_amounts.update({ + line.budget_post_id.id: ( + line.planned_amount / len(budget_lines)), + }) + wizard.button_distribute_amount() + budget_lines = pessimistic_budget.crossovered_budget_line + try: + budget_lines = budget_lines.filtered( + lambda l: not l.general_budget_id.expenses) + except Exception: + pass + for budget_line in budget_lines: + self.assertEquals( + budget_line.planned_amount, + planned_amounts[budget_line.general_budget_id.id]) diff --git a/account_budget_distribution/views/crossovered_budget_view.xml b/account_budget_distribution/views/crossovered_budget_view.xml new file mode 100644 index 00000000..762b7f1b --- /dev/null +++ b/account_budget_distribution/views/crossovered_budget_view.xml @@ -0,0 +1,17 @@ + + + + crossovered.budget + + +
+
+ + + + + +
+
+
diff --git a/account_budget_distribution/wizards/__init__.py b/account_budget_distribution/wizards/__init__.py new file mode 100644 index 00000000..cda43365 --- /dev/null +++ b/account_budget_distribution/wizards/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2019 Oihane Crucelaegui - AvanzOSC +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +from . import crossovered_budget_distribution diff --git a/account_budget_distribution/wizards/crossovered_budget_distribution.py b/account_budget_distribution/wizards/crossovered_budget_distribution.py new file mode 100644 index 00000000..11a2f4a6 --- /dev/null +++ b/account_budget_distribution/wizards/crossovered_budget_distribution.py @@ -0,0 +1,65 @@ +# Copyright 2019 Oihane Crucelaegui - AvanzOSC +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +from odoo import api, fields, models + + +class CrossoveredBudgetDistribution(models.TransientModel): + _name = 'crossovered.budget.distribution' + _description = 'Budget Distribution Wizard' + + budget_id = fields.Many2one( + comodel_name='crossovered.budget', string='Budget') + line_ids = fields.One2many( + comodel_name='crossovered.budget.distribution.line', + inverse_name='distribution_id', string='Summary') + + @api.model + def default_get(self, fields): + context = self.env.context + res = super(CrossoveredBudgetDistribution, self).default_get(fields) + if context.get('active_model') == 'crossovered.budget': + budget = self.env[context.get('active_model')].browse( + context.get('active_id')) + summary = budget.summary_ids + try: + summary = summary.filtered( + lambda s: not s.general_budget_id.expenses) + except Exception: + pass + res.update({ + 'budget_id': budget.id, + 'line_ids': [ + (0, 0, {'budget_post_id': x.general_budget_id.id, + 'planned_amount': x.planned_amount}) + for x in summary], + }) + return res + + @api.multi + def button_distribute_amount(self): + for wiz in self: + for line in wiz.line_ids: + budget_lines = wiz.budget_id.crossovered_budget_line.filtered( + lambda l: l.general_budget_id == line.budget_post_id) + try: + budget_lines = budget_lines.filtered( + lambda l: not l.general_budget_id.expenses) + except Exception: + pass + if budget_lines: + budget_lines.write({ + 'planned_amount': ( + line.planned_amount / len(budget_lines)) + }) + + +class CrossoveredBudgetDistributionLine(models.TransientModel): + _name = 'crossovered.budget.distribution.line' + _description = 'Budget Distribution Line' + + distribution_id = fields.Many2one( + comodel_name='crossovered.budget.distribution', string='Wizard') + budget_post_id = fields.Many2one( + comodel_name='account.budget.post', string='Budget Position') + planned_amount = fields.Float(string='Planned Amount') diff --git a/account_budget_distribution/wizards/crossovered_budget_distribution_view.xml b/account_budget_distribution/wizards/crossovered_budget_distribution_view.xml new file mode 100644 index 00000000..48ba1bd0 --- /dev/null +++ b/account_budget_distribution/wizards/crossovered_budget_distribution_view.xml @@ -0,0 +1,35 @@ + + + + crossovered.budget.distribution + +
+ + + + + + + + + +
+
+
+
+
+ + + Distribute Budget + crossovered.budget.distribution + form + form + + new + +