diff --git a/mis_builder_cash_flow/README.rst b/mis_builder_cash_flow/README.rst new file mode 100644 index 00000000..21cd7854 --- /dev/null +++ b/mis_builder_cash_flow/README.rst @@ -0,0 +1,21 @@ +**This file is going to be generated by oca-gen-addon-readme.** + +*Manual changes will be overwritten.* + +Please provide content in the ``readme`` directory: + +* **DESCRIPTION.rst** (required) +* INSTALL.rst (optional) +* CONFIGURE.rst (optional) +* **USAGE.rst** (optional, highly recommended) +* DEVELOP.rst (optional) +* ROADMAP.rst (optional) +* HISTORY.rst (optional, recommended) +* **CONTRIBUTORS.rst** (optional, highly recommended) +* CREDITS.rst (optional) + +Content of this README will also be drawn from the addon manifest, +from keys such as name, authors, maintainers, development_status, +and license. + +A good, one sentence summary in the manifest is also highly recommended. diff --git a/mis_builder_cash_flow/__init__.py b/mis_builder_cash_flow/__init__.py new file mode 100644 index 00000000..8e455ad1 --- /dev/null +++ b/mis_builder_cash_flow/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2019 ADHOC SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from . import models +from . import report diff --git a/mis_builder_cash_flow/__manifest__.py b/mis_builder_cash_flow/__manifest__.py new file mode 100644 index 00000000..dc7b39e5 --- /dev/null +++ b/mis_builder_cash_flow/__manifest__.py @@ -0,0 +1,26 @@ +# Copyright 2019 ADHOC SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + 'name': 'MIS Builder Cash Flow', + 'version': '12.0.1.1.0', + 'license': 'LGPL-3', + 'author': 'ADHOC SA, ' + 'Odoo Community Association (OCA)', + 'website': 'https://github.com/OCA/mis-builder', + 'depends': [ + 'mis_builder', + ], + 'data': [ + 'security/mis_cash_flow_security.xml', + 'report/mis_cash_flow_views.xml', + 'views/mis_cash_flow_forecast_line_views.xml', + 'views/account_account_views.xml', + 'data/mis_report_style.xml', + 'data/mis_report.xml', + 'data/mis_report_instance.xml', + ], + 'installable': True, + 'maintainers': ['jjscarafia'], + 'development_status': 'Beta', +} diff --git a/mis_builder_cash_flow/data/mis_report.xml b/mis_builder_cash_flow/data/mis_report.xml new file mode 100644 index 00000000..c818ef14 --- /dev/null +++ b/mis_builder_cash_flow/data/mis_report.xml @@ -0,0 +1,105 @@ + + + + + + + Cash Flow + + + + + + liquidity + LIQUIDITY + + + + 20 + bal[][('account_id.internal_type', '=', 'liquidity'), ('line_type', '=', 'move_line'), ('account_id.hide_in_cash_flow', '=', False)] + + + + + in_total + IN TOTAL + + 30 + in_receivable + in_forecast + + + + + in_receivable + In receivable + + + + 50 + bal[][('account_id.internal_type', '=', 'receivable'), ('full_reconcile_id', '=', False), ('line_type', '=', 'move_line'), ('account_id.hide_in_cash_flow', '=', False)] + + + + + in_forecast + In forecast + + + + 70 + bal[][('line_type', '=', 'forecast_line'), ('debit', '!=', 0.0), ('account_id.hide_in_cash_flow', '=', False)] + + + + + out_total + OUT TOTAL + + 80 + out_payable + out_forecast + + + + + out_payable + Out payable + + + + 100 + bal[][('account_id.internal_type', '=', 'payable'), ('full_reconcile_id', '=', False), ('line_type', '=', 'move_line'), ('account_id.hide_in_cash_flow', '=', False)] + + + + + out_forecast + Out forecast + + + + 120 + bal[][('line_type', '=', 'forecast_line'), ('credit', '!=', 0.0), ('account_id.hide_in_cash_flow', '=', False)] + + + + + period_balance + PERIOD BALANCE + + 130 + in_total + out_total + 'Cash Flow - Good' if period_balance >= 0.0 else 'Cash Flow - Bad' + + + + + balance + BALANCE + + 150 + bale[][('account_id.hide_in_cash_flow', '=', False), '|', ('line_type', '=', 'forecast_line'), ('line_type', '=', 'move_line'), '|', ('account_id.internal_type', '=', 'liquidity'), ('account_id.internal_type', 'in', ('receivable', 'payable')), ('full_reconcile_id', '=', False)] + 'Cash Flow - Good' if balance >= 0.0 else 'Cash Flow - Bad' + + + diff --git a/mis_builder_cash_flow/data/mis_report_instance.xml b/mis_builder_cash_flow/data/mis_report_instance.xml new file mode 100644 index 00000000..2089bb82 --- /dev/null +++ b/mis_builder_cash_flow/data/mis_report_instance.xml @@ -0,0 +1,146 @@ + + + + + + + Cash Flow + + + + + + + Current + + actuals_alt + + relative + w + -4000 + 4001 + 4 + + + + +1w + + actuals_alt + + relative + w + 1 + 1 + 10 + + + + +2w + + actuals_alt + + relative + w + 2 + 1 + 20 + + + + +3w + + actuals_alt + + relative + w + 3 + 1 + 30 + + + + +4w + + actuals_alt + + relative + w + 4 + 1 + 40 + + + + +5w + + actuals_alt + + relative + w + 5 + 1 + 50 + + + + +6w + + actuals_alt + + relative + w + 6 + 1 + 60 + + + + +7w + + actuals_alt + + relative + w + 7 + 1 + 70 + + + + +8w + + actuals_alt + + relative + w + 8 + 1 + 80 + + + + third month + + actuals_alt + + relative + w + 9 + 4 + 90 + + + + fourth month + + actuals_alt + + relative + w + 13 + 4 + 90 + + + diff --git a/mis_builder_cash_flow/data/mis_report_style.xml b/mis_builder_cash_flow/data/mis_report_style.xml new file mode 100644 index 00000000..ff7564b1 --- /dev/null +++ b/mis_builder_cash_flow/data/mis_report_style.xml @@ -0,0 +1,71 @@ + + + + + + + Cash Flow + + + + + + Cash flow style account detail + + italic + + 2 + + x-small + + + + Cash flow line + + #FFFFFF + + #D4AFC4 + + 1 + + + + Cash flow style sub-total + + #FFFFFF + + #967C8B + + bold + + + + Cash flow style total + + #FFFFFF + + #7A6571 + + bold + + + + Cash Flow - hidden + + + + + + Cash Flow - Good + + #005700 + + + + Cash Flow - Bad + + #7A0000 + + + diff --git a/mis_builder_cash_flow/models/__init__.py b/mis_builder_cash_flow/models/__init__.py new file mode 100644 index 00000000..63bc6fd4 --- /dev/null +++ b/mis_builder_cash_flow/models/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2019 ADHOC SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from . import mis_cash_flow_forecast_line +from . import account_account diff --git a/mis_builder_cash_flow/models/account_account.py b/mis_builder_cash_flow/models/account_account.py new file mode 100644 index 00000000..828f1585 --- /dev/null +++ b/mis_builder_cash_flow/models/account_account.py @@ -0,0 +1,12 @@ +# Copyright 2019 ADHOC SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from odoo import fields, models + + +class AccountAccount(models.Model): + + _inherit = 'account.account' + + hide_in_cash_flow = fields.Boolean( + string='Hide in Cash Flow?', + ) diff --git a/mis_builder_cash_flow/models/mis_cash_flow_forecast_line.py b/mis_builder_cash_flow/models/mis_cash_flow_forecast_line.py new file mode 100644 index 00000000..23e5297f --- /dev/null +++ b/mis_builder_cash_flow/models/mis_cash_flow_forecast_line.py @@ -0,0 +1,44 @@ +# Copyright 2019 ADHOC SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from odoo import fields, models, api, _ +from odoo.exceptions import ValidationError + + +class MisCashFlowForecastLine(models.Model): + + _name = 'mis.cash_flow.forecast_line' + _description = 'MIS Cash Flow Forecast Line' + + date = fields.Date( + required=True, + index=True, + ) + account_id = fields.Many2one( + comodel_name='account.account', + string='Account', + required=True, + help='The account of the forecast line is only for informative ' + 'purpose', + ) + name = fields.Char( + required=True, + default='/', + ) + balance = fields.Float( + required=True, + ) + company_id = fields.Many2one( + 'res.company', + string='Company', + required=True, + default=lambda self: self.env.user.company_id.id, + index=True, + ) + + @api.multi + @api.constrains('company_id', 'account_id') + def _check_company_id_account_id(self): + if self.filtered(lambda x: x.company_id != x.account_id.company_id): + raise ValidationError(_( + 'The Company and the Company of the Account must be the ' + 'same.')) diff --git a/mis_builder_cash_flow/readme/CONTRIBUTORS.rst b/mis_builder_cash_flow/readme/CONTRIBUTORS.rst new file mode 100644 index 00000000..2fe7ced3 --- /dev/null +++ b/mis_builder_cash_flow/readme/CONTRIBUTORS.rst @@ -0,0 +1,2 @@ +* Juan José Scarafía +* Gonzalo Ruzafa diff --git a/mis_builder_cash_flow/readme/DESCRIPTION.rst b/mis_builder_cash_flow/readme/DESCRIPTION.rst new file mode 100644 index 00000000..4ffe5d7a --- /dev/null +++ b/mis_builder_cash_flow/readme/DESCRIPTION.rst @@ -0,0 +1,5 @@ +This module allows you to have a cash flow forecast. +The forecast is based on two types of date: + +* Accounting entries: Due date field instead of Date +* Forecast lines: manual lines created that forecast in/out cashflow moves. diff --git a/mis_builder_cash_flow/readme/ROADMAP.rst b/mis_builder_cash_flow/readme/ROADMAP.rst new file mode 100644 index 00000000..b11c6391 --- /dev/null +++ b/mis_builder_cash_flow/readme/ROADMAP.rst @@ -0,0 +1,3 @@ +The mis_builder `roadmap `_ +and `known issues `_ can +be found on GitHub. diff --git a/mis_builder_cash_flow/readme/USAGE.rst b/mis_builder_cash_flow/readme/USAGE.rst new file mode 100644 index 00000000..44f6253a --- /dev/null +++ b/mis_builder_cash_flow/readme/USAGE.rst @@ -0,0 +1,4 @@ +To use this module, you need to: + +#. Go to Accounting > Reports > MIS Reporting > MIS Reports and choose "Cash Flow" report +#. You can add forecast lines on Accounting > Reports > MIS Reporting > Cash Flow Forecast Line diff --git a/mis_builder_cash_flow/report/__init__.py b/mis_builder_cash_flow/report/__init__.py new file mode 100644 index 00000000..579023b2 --- /dev/null +++ b/mis_builder_cash_flow/report/__init__.py @@ -0,0 +1,3 @@ +# Copyright 2019 ADHOC SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from . import mis_cash_flow diff --git a/mis_builder_cash_flow/report/mis_cash_flow.py b/mis_builder_cash_flow/report/mis_cash_flow.py new file mode 100644 index 00000000..02e4b9f6 --- /dev/null +++ b/mis_builder_cash_flow/report/mis_cash_flow.py @@ -0,0 +1,132 @@ +# Copyright 2019 ADHOC SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from odoo import api, fields, models, tools +from psycopg2.extensions import AsIs + + +class MisCashFlow(models.Model): + + _name = 'mis.cash_flow' + _description = 'MIS Cash Flow' + _auto = False + + line_type = fields.Selection( + [('forecast_line', 'Forecast Line'), ('move_line', 'Journal Item')], + index=True, + readonly=True, + ) + name = fields.Char( + readonly=True, + ) + account_id = fields.Many2one( + comodel_name='account.account', + string='Account', + auto_join=True, + index=True, + readonly=True, + ) + move_line_id = fields.Many2one( + comodel_name='account.move.line', + string='Journal Item', + auto_join=True, + readonly=True, + ) + company_id = fields.Many2one( + comodel_name='res.company', + string='Company', + auto_join=True, + readonly=True, + index=True, + ) + credit = fields.Float( + readonly=True, + ) + debit = fields.Float( + readonly=True, + ) + date = fields.Date( + readonly=True, + index=True, + ) + reconciled = fields.Boolean( + readonly=True, + ) + full_reconcile_id = fields.Many2one( + 'account.full.reconcile', + string="Matching Number", + readonly=True, + index=True, + ) + user_type_id = fields.Many2one( + 'account.account.type', + auto_join=True, + readonly=True, + index=True, + ) + + @api.model_cr + def init(self): + query = """ + SELECT + -- we use negative id to avoid duplicates and we don't use + -- ROW_NUMBER() because the performance was very poor + -aml.id as id, + CAST('move_line' AS varchar) as line_type, + aml.id as move_line_id, + aml.account_id as account_id, + CASE + WHEN aml.amount_residual > 0 + THEN aml.amount_residual + ELSE 0.0 + END AS debit, + CASE + WHEN aml.amount_residual < 0 + THEN -aml.amount_residual + ELSE 0.0 + END AS credit, + aml.reconciled as reconciled, + aml.full_reconcile_id as full_reconcile_id, + aml.company_id as company_id, + aml.user_type_id as user_type_id, + aml.name as name, + aml.date_maturity as date + FROM account_move_line as aml + UNION ALL + SELECT + fl.id as id, + CAST('forecast_line' AS varchar) as line_type, + Null as move_line_id, + fl.account_id as account_id, + CASE + WHEN fl.balance > 0 + THEN fl.balance + ELSE 0.0 + END AS debit, + CASE + WHEN fl.balance < 0 + THEN -fl.balance + ELSE 0.0 + END AS credit, + Null as reconciled, + Null as full_reconcile_id, + fl.company_id as company_id, + -- we dont need this field on forecast lines + Null as user_type_id, + fl.name as name, + fl.date as date + FROM mis_cash_flow_forecast_line as fl + """ + tools.drop_view_if_exists(self.env.cr, self._table) + self._cr.execute( + 'CREATE OR REPLACE VIEW %s AS %s', + (AsIs(self._table), AsIs(query)) + ) + + @api.multi + def action_open_related_line(self): + self.ensure_one() + if self.line_type == 'move_line': + return self.move_line_id.get_formview_action() + else: + return self.env['mis.cash_flow.forecast_line'].browse( + self.id).get_formview_action() diff --git a/mis_builder_cash_flow/report/mis_cash_flow_views.xml b/mis_builder_cash_flow/report/mis_cash_flow_views.xml new file mode 100644 index 00000000..9b313717 --- /dev/null +++ b/mis_builder_cash_flow/report/mis_cash_flow_views.xml @@ -0,0 +1,92 @@ + + + + + + + mis.cash_flow.tree + mis.cash_flow + + + + + + + + + +