From 1ef9c7ead84f35c9087c76533a510f008a41994b Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Sat, 30 May 2020 14:50:27 +0200 Subject: [PATCH] [ADD] new module account_subsequence_fiscal_year Co-authored-by: Saran @ Ecosoft --- account_subsequence_fiscal_year/README.rst | 8 + account_subsequence_fiscal_year/__init__.py | 1 + .../__manifest__.py | 27 ++++ .../demo/res_groups.xml | 14 ++ account_subsequence_fiscal_year/i18n/fr.po | 79 ++++++++++ .../models/__init__.py | 5 + .../models/account_bank_statement.py | 14 ++ .../models/account_move.py | 14 ++ .../models/ir_sequence.py | 59 ++++++++ .../models/res_company.py | 16 ++ .../models/res_config_settings.py | 13 ++ .../readme/CONFIGURE.rst | 27 ++++ .../readme/CONTRIBUTORS.rst | 1 + .../readme/DESCRIPTION.rst | 9 ++ .../static/description/res_config_setting.png | Bin 0 -> 18520 bytes .../tests/__init__.py | 1 + .../tests/test_module.py | 142 ++++++++++++++++++ .../views/view_res_config_settings.xml | 33 ++++ 18 files changed, 463 insertions(+) create mode 100644 account_subsequence_fiscal_year/README.rst create mode 100644 account_subsequence_fiscal_year/__init__.py create mode 100644 account_subsequence_fiscal_year/__manifest__.py create mode 100644 account_subsequence_fiscal_year/demo/res_groups.xml create mode 100644 account_subsequence_fiscal_year/i18n/fr.po create mode 100644 account_subsequence_fiscal_year/models/__init__.py create mode 100644 account_subsequence_fiscal_year/models/account_bank_statement.py create mode 100644 account_subsequence_fiscal_year/models/account_move.py create mode 100644 account_subsequence_fiscal_year/models/ir_sequence.py create mode 100644 account_subsequence_fiscal_year/models/res_company.py create mode 100644 account_subsequence_fiscal_year/models/res_config_settings.py create mode 100644 account_subsequence_fiscal_year/readme/CONFIGURE.rst create mode 100644 account_subsequence_fiscal_year/readme/CONTRIBUTORS.rst create mode 100644 account_subsequence_fiscal_year/readme/DESCRIPTION.rst create mode 100644 account_subsequence_fiscal_year/static/description/res_config_setting.png create mode 100644 account_subsequence_fiscal_year/tests/__init__.py create mode 100644 account_subsequence_fiscal_year/tests/test_module.py create mode 100644 account_subsequence_fiscal_year/views/view_res_config_settings.xml diff --git a/account_subsequence_fiscal_year/README.rst b/account_subsequence_fiscal_year/README.rst new file mode 100644 index 000000000..e83d36db2 --- /dev/null +++ b/account_subsequence_fiscal_year/README.rst @@ -0,0 +1,8 @@ +======================================== +Accounting Subsequences per Fiscal Years +======================================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! diff --git a/account_subsequence_fiscal_year/__init__.py b/account_subsequence_fiscal_year/__init__.py new file mode 100644 index 000000000..0650744f6 --- /dev/null +++ b/account_subsequence_fiscal_year/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/account_subsequence_fiscal_year/__manifest__.py b/account_subsequence_fiscal_year/__manifest__.py new file mode 100644 index 000000000..b1b13ae51 --- /dev/null +++ b/account_subsequence_fiscal_year/__manifest__.py @@ -0,0 +1,27 @@ +# Copyright (C) 2020 - Today: GRAP (http://www.grap.coop) +# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +{ + "name": "Accounting Subsequences per Fiscal Years", + "summary": "Allow to create sub sequences for account moves number, based" + " on the fiscal years settings", + "version": "12.0.1.0.0", + "category": "Accounting", + "author": "GRAP,Odoo Community Association (OCA)", + "maintainers": ["legalsylvain"], + "website": "http://www.github.com/OCA/account-financial-tools", + "license": "AGPL-3", + "depends": [ + "account", + ], + "data": [ + "views/view_res_config_settings.xml", + ], + "demo": [ + "demo/res_groups.xml", + ], + "images": [ + "static/description/res_config_setting.png", + ], +} diff --git a/account_subsequence_fiscal_year/demo/res_groups.xml b/account_subsequence_fiscal_year/demo/res_groups.xml new file mode 100644 index 000000000..12fb85d0a --- /dev/null +++ b/account_subsequence_fiscal_year/demo/res_groups.xml @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/account_subsequence_fiscal_year/i18n/fr.po b/account_subsequence_fiscal_year/i18n/fr.po new file mode 100644 index 000000000..0dcc21557 --- /dev/null +++ b/account_subsequence_fiscal_year/i18n/fr.po @@ -0,0 +1,79 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * account_subsequence_fiscal_year +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-05-30 17:11+0000\n" +"PO-Revision-Date: 2020-05-30 17:11+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_subsequence_fiscal_year +#: model_terms:ir.ui.view,arch_db:account_subsequence_fiscal_year.view_res_config_settings_form +msgid "Accounting Subsequences Method" +msgstr "Méthode pour les sous-séquences comptables" + +#. module: account_subsequence_fiscal_year +#: model:ir.model.fields,field_description:account_subsequence_fiscal_year.field_res_company__account_subsequence_method +#: model:ir.model.fields,field_description:account_subsequence_fiscal_year.field_res_config_settings__account_subsequence_method +msgid "Accounting Subsequences Method" +msgstr "Méthode pour les sous-séquences comptables" + +#. module: account_subsequence_fiscal_year +#: model:ir.model,name:account_subsequence_fiscal_year.model_account_bank_statement +msgid "Bank Statement" +msgstr "Relevé bancaire" + +#. module: account_subsequence_fiscal_year +#: selection:res.company,account_subsequence_method:0 +msgid "Based on Company Settings" +msgstr "Basé sur les paramètres de la société" + +#. module: account_subsequence_fiscal_year +#: selection:res.company,account_subsequence_method:0 +msgid "Based on Fiscal Years Settings" +msgstr "Basés sur les exercices comptables" + +#. module: account_subsequence_fiscal_year +#: model:ir.model,name:account_subsequence_fiscal_year.model_res_company +msgid "Companies" +msgstr "Sociétés" + +#. module: account_subsequence_fiscal_year +#: model:ir.model,name:account_subsequence_fiscal_year.model_res_config_settings +msgid "Config Settings" +msgstr "Paramètres de config" + +#. module: account_subsequence_fiscal_year +#: model_terms:ir.ui.view,arch_db:account_subsequence_fiscal_year.view_res_config_settings_form +msgid "Define how accounting subsequences are generated" +msgstr "Définit comment les sous-séquences comptables sont générées" + +#. module: account_subsequence_fiscal_year +#: model_terms:ir.ui.view,arch_db:account_subsequence_fiscal_year.view_res_config_settings_form +msgid "Generation Method" +msgstr "Méthode de génération" + +#. module: account_subsequence_fiscal_year +#: model:ir.model,name:account_subsequence_fiscal_year.model_account_move +msgid "Journal Entries" +msgstr "Pièces comptables" + +#. module: account_subsequence_fiscal_year +#: model:ir.model,name:account_subsequence_fiscal_year.model_ir_sequence +msgid "Sequence" +msgstr "Séquence" + +#. module: account_subsequence_fiscal_year +#: code:addons/account_subsequence_fiscal_year/models/ir_sequence.py:45 +#, python-format +msgid "You can not post an accounting entry for the date %s because there is no fiscal year defined at this date." +msgstr "Vous ne pouvez pas valider une pièce comptable pour la date du %s car aucun exercice comptable n'est défini à cette date." + diff --git a/account_subsequence_fiscal_year/models/__init__.py b/account_subsequence_fiscal_year/models/__init__.py new file mode 100644 index 000000000..5a544b6e6 --- /dev/null +++ b/account_subsequence_fiscal_year/models/__init__.py @@ -0,0 +1,5 @@ +from . import account_bank_statement +from . import account_move +from . import ir_sequence +from . import res_company +from . import res_config_settings diff --git a/account_subsequence_fiscal_year/models/account_bank_statement.py b/account_subsequence_fiscal_year/models/account_bank_statement.py new file mode 100644 index 000000000..8ad2e9034 --- /dev/null +++ b/account_subsequence_fiscal_year/models/account_bank_statement.py @@ -0,0 +1,14 @@ +# Copyright (C) 2020 - Today: GRAP (http://www.grap.coop) +# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from odoo import api, models + + +class AccountBankStatement(models.Model): + _inherit = "account.bank.statement" + + @api.multi + def button_open(self): + return super( + AccountBankStatement, self.with_context(account_sequence=True) + ).button_open() diff --git a/account_subsequence_fiscal_year/models/account_move.py b/account_subsequence_fiscal_year/models/account_move.py new file mode 100644 index 000000000..2f224a7a6 --- /dev/null +++ b/account_subsequence_fiscal_year/models/account_move.py @@ -0,0 +1,14 @@ +# Copyright (C) 2020 - Today: GRAP (http://www.grap.coop) +# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from odoo import api, models + + +class AccountMove(models.Model): + _inherit = "account.move" + + @api.multi + def post(self, invoice=False): + return super( + AccountMove, self.with_context(account_sequence=True) + ).post(invoice=invoice) diff --git a/account_subsequence_fiscal_year/models/ir_sequence.py b/account_subsequence_fiscal_year/models/ir_sequence.py new file mode 100644 index 000000000..3f7c21911 --- /dev/null +++ b/account_subsequence_fiscal_year/models/ir_sequence.py @@ -0,0 +1,59 @@ +# Copyright (C) 2020 - Today: GRAP (http://www.grap.coop) +# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +import datetime +from dateutil.relativedelta import relativedelta + +from odoo import _, fields, models +from odoo.exceptions import ValidationError + + +class IrSequence(models.Model): + _inherit = "ir.sequence" + + def _create_date_range_seq(self, date): + AccountFiscalYear = self.env["account.fiscal.year"] + IrSequenceDateRange = self.env["ir.sequence.date_range"] + if self._context.get("account_sequence", False)\ + and self.company_id\ + and self.company_id.account_subsequence_method: + + method = self.company_id.account_subsequence_method + object_date = fields.Date.from_string(date) + + if method == "company_setting": + base_date = datetime.date( + object_date.year, + int(self.company_id.fiscalyear_last_month), + int(self.company_id.fiscalyear_last_day), + ) + if object_date <= base_date: + date_from = base_date + relativedelta(years=-1, days=1) + date_to = base_date + else: + date_from = base_date + relativedelta(days=1) + date_to = base_date + relativedelta(years=1) + + elif method == "fiscal_year_setting": + fiscal_years = AccountFiscalYear.search( + [("date_to", ">=", object_date.strftime("%Y-%m-%d"))], + order="date_from desc", + limit=1 + ) + if not fiscal_years or fiscal_years[0].date_from > object_date: + raise ValidationError(_( + "You can not post an accounting entry for the" + " date %s because there is no fiscal year defined at" + " this date.") % (date)) + date_from = fiscal_years[0].date_from + date_to = fiscal_years[0].date_to + + # Create and return new sequence + return IrSequenceDateRange.sudo().create({ + 'sequence_id': self.id, + 'date_from': date_from, + 'date_to': date_to, + }) + + return super()._create_date_range_seq(date) diff --git a/account_subsequence_fiscal_year/models/res_company.py b/account_subsequence_fiscal_year/models/res_company.py new file mode 100644 index 000000000..9d45c1b4a --- /dev/null +++ b/account_subsequence_fiscal_year/models/res_company.py @@ -0,0 +1,16 @@ +# Copyright (C) 2020 - Today: GRAP (http://www.grap.coop) +# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + + +class ResCompany(models.Model): + _inherit = "res.company" + + account_subsequence_method = fields.Selection( + string="Accounting Subsequences Method", + selection=[ + ("company_setting", "Based on Company Settings"), + ("fiscal_year_setting", "Based on Fiscal Years Settings"), + ]) diff --git a/account_subsequence_fiscal_year/models/res_config_settings.py b/account_subsequence_fiscal_year/models/res_config_settings.py new file mode 100644 index 000000000..1ff9e9ba4 --- /dev/null +++ b/account_subsequence_fiscal_year/models/res_config_settings.py @@ -0,0 +1,13 @@ +# Copyright (C) 2020 - Today: GRAP (http://www.grap.coop) +# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from odoo import fields, models + + +class ResConfigSettings(models.TransientModel): + _inherit = "res.config.settings" + + account_subsequence_method = fields.Selection( + related="company_id.account_subsequence_method", + readonly=False, + ) diff --git a/account_subsequence_fiscal_year/readme/CONFIGURE.rst b/account_subsequence_fiscal_year/readme/CONFIGURE.rst new file mode 100644 index 000000000..990acc24a --- /dev/null +++ b/account_subsequence_fiscal_year/readme/CONFIGURE.rst @@ -0,0 +1,27 @@ +To configure this module, you need to: + +* Add your users to the group 'Technical Settings / Show Full Accounting Features' + +* Go to Invoicing > Configuration / Settings + +* configure your accounting settings + +.. figure:: ../static/description/res_config_setting.png + +Depending on what you want, 3 options are available. + +Given the following example: + +- an account move with a date set to 2030-06-01 +- a company set with ``fiscalyear_last_day = 1`` and ``fiscalyear_last_month = 10`` + +* 'empty' (default value): + the subsequence will be created "normaly", with ``date_from = 2030-01-01`` and ``date_to = 2030-12-31`` + +* 'Based on Company Settings': + the subsequence will be created depending on the values of ``fiscalyear_last_day`` + and ``fiscalyear_last_month``, so ``date_from = 2029-10-01`` and ``date_to = 2030-09-30`` + +* 'Based on Fiscal Years Settings': + the subsequence will be created with the values defined in the according fiscal year. + Note that if no fiscal year is found, the generation will fail. diff --git a/account_subsequence_fiscal_year/readme/CONTRIBUTORS.rst b/account_subsequence_fiscal_year/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..9f76a75bc --- /dev/null +++ b/account_subsequence_fiscal_year/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Sylvain LE GAL diff --git a/account_subsequence_fiscal_year/readme/DESCRIPTION.rst b/account_subsequence_fiscal_year/readme/DESCRIPTION.rst new file mode 100644 index 000000000..73340d02d --- /dev/null +++ b/account_subsequence_fiscal_year/readme/DESCRIPTION.rst @@ -0,0 +1,9 @@ +This module extends the functionality of Accounting Odoo module, to +generate custom sub sequences for accounting entries, if fiscal years are not "classic". +(ie: last day = 31 / last month = 12) + +without this module, in such cases (for example, for fiscal year from 01 April 2020 to 31 May 2021) +accounting moves of the same fiscal year will not have the same numbering: Some entries will +have ``BILL/2020/`` prefix and other will have ``BILL/2021/``, that is not allowed in many countries. + +That modules fixes this problem. diff --git a/account_subsequence_fiscal_year/static/description/res_config_setting.png b/account_subsequence_fiscal_year/static/description/res_config_setting.png new file mode 100644 index 0000000000000000000000000000000000000000..23ac1df7cf7847e3de37c5ed09560858343894f2 GIT binary patch literal 18520 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 literal 0 HcmV?d00001 diff --git a/account_subsequence_fiscal_year/tests/__init__.py b/account_subsequence_fiscal_year/tests/__init__.py new file mode 100644 index 000000000..d9b96c4fa --- /dev/null +++ b/account_subsequence_fiscal_year/tests/__init__.py @@ -0,0 +1 @@ +from . import test_module diff --git a/account_subsequence_fiscal_year/tests/test_module.py b/account_subsequence_fiscal_year/tests/test_module.py new file mode 100644 index 000000000..125366c76 --- /dev/null +++ b/account_subsequence_fiscal_year/tests/test_module.py @@ -0,0 +1,142 @@ +# Copyright 2020 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo.tests.common import TransactionCase +from odoo.exceptions import ValidationError + +from datetime import date + + +class TestModule(TransactionCase): + + def setUp(self): + super().setUp() + self.AccountFiscalYear = self.env["account.fiscal.year"] + self.company = self.env.ref("base.main_company") + self.account_type_receivable = self.env["account.account.type"].create( + {"name": "Test Receivable", "type": "receivable"} + ) + self.account_receivable = self.env["account.account"].create( + { + "name": "Test Receivable", + "code": "TEST_AR", + "user_type_id": self.account_type_receivable.id, + "reconcile": True, + } + ) + self.sale_journal = self.env["account.journal"].search( + [("type", "=", "sale"), ("company_id", "=", self.company.id)] + )[0] + self.sequence = self.sale_journal.sequence_id + self.sequence.use_date_range = True + + self.account_move = self.env["account.move"].create({ + "journal_id": self.sale_journal.id, + "company_id": self.company.id, + "line_ids": [(0, 0, { + "account_id": self.account_receivable.id, + "debit": 100, + }), (0, 0, { + "account_id": self.account_receivable.id, + "credit": 100, + })] + }) + + self.existing_subsequence_ids =\ + self.env["ir.sequence.date_range"].search([ + ("sequence_id", "=", self.sequence.id)]).ids + + def _get_new_subsequence(self): + return self.env["ir.sequence.date_range"].search([ + ("sequence_id", "=", self.sequence.id), + ("id", "not in", self.existing_subsequence_ids), + ]) + + def test_method_normal(self): + """Non Regression Test""" + self.company.account_subsequence_method = False + self.account_move.date = "2100-06-01" + self.account_move.post() + new_subsequences = self._get_new_subsequence() + self.assertEqual(len(new_subsequences), 1) + self.assertEqual( + new_subsequences[0].date_from, + date(2100, 1, 1) + ) + self.assertEqual( + new_subsequences[0].date_to, + date(2100, 12, 31) + ) + + def test_method_company_setting_before(self): + self.company.account_subsequence_method = 'company_setting' + self.company.fiscalyear_last_day = 31 + self.company.fiscalyear_last_month = 3 + self.account_move.date = "2100-03-15" + self.account_move.post() + + new_subsequences = self._get_new_subsequence() + self.assertEqual(len(new_subsequences), 1) + self.assertEqual( + new_subsequences[0].date_from, + date(2099, 4, 1) + ) + self.assertEqual( + new_subsequences[0].date_to, + date(2100, 3, 31) + ) + + def test_method_company_setting_after(self): + self.company.account_subsequence_method = 'company_setting' + self.company.fiscalyear_last_day = 31 + self.company.fiscalyear_last_month = 3 + self.account_move.date = "2100-05-15" + self.account_move.post() + + new_subsequences = self._get_new_subsequence() + self.assertEqual(len(new_subsequences), 1) + self.assertEqual( + new_subsequences[0].date_from, + date(2100, 4, 1) + ) + self.assertEqual( + new_subsequences[0].date_to, + date(2101, 3, 31) + ) + + def test_method_fiscal_year_setting(self): + self.company.account_subsequence_method = 'fiscal_year_setting' + with self.assertRaises(ValidationError): + self.account_move.date = "2100-06-01" + self.account_move.post() + + # create a Fiscal Year + self.AccountFiscalYear.create({ + "name": "2100 FY April to March", + "company_id": self.company.id, + "date_from": "2100-04-01", + "date_to": "2101-03-31", + }) + + # Try to post out the date range + with self.assertRaises(ValidationError): + self.account_move.date = "2100-03-31" + self.account_move.post() + + with self.assertRaises(ValidationError): + self.account_move.date = "2101-04-01" + self.account_move.post() + + # Post in the range should succeed + self.account_move.date = "2100-06-01" + self.account_move.post() + new_subsequences = self._get_new_subsequence() + self.assertEqual(len(new_subsequences), 1) + self.assertEqual( + new_subsequences[0].date_from, + date(2100, 4, 1) + ) + self.assertEqual( + new_subsequences[0].date_to, + date(2101, 3, 31) + ) diff --git a/account_subsequence_fiscal_year/views/view_res_config_settings.xml b/account_subsequence_fiscal_year/views/view_res_config_settings.xml new file mode 100644 index 000000000..b0ab90a5c --- /dev/null +++ b/account_subsequence_fiscal_year/views/view_res_config_settings.xml @@ -0,0 +1,33 @@ + + + + + + res.config.settings + + + +
+
+
+ Accounting Subsequences Method +
+ Define how accounting subsequences are generated +
+
+
+
+
+
+
+ + + + +