diff --git a/account_fiscal_year_auto_create/README.rst b/account_fiscal_year_auto_create/README.rst
new file mode 100644
index 00000000..bc7d401d
--- /dev/null
+++ b/account_fiscal_year_auto_create/README.rst
@@ -0,0 +1,8 @@
+=================================
+Fiscal Years - Automatic Creation
+=================================
+
+.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ !! This file is generated by oca-gen-addon-readme !!
+ !! changes will be overwritten. !!
+ !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
diff --git a/account_fiscal_year_auto_create/__init__.py b/account_fiscal_year_auto_create/__init__.py
new file mode 100644
index 00000000..0650744f
--- /dev/null
+++ b/account_fiscal_year_auto_create/__init__.py
@@ -0,0 +1 @@
+from . import models
diff --git a/account_fiscal_year_auto_create/__manifest__.py b/account_fiscal_year_auto_create/__manifest__.py
new file mode 100644
index 00000000..d5f217d9
--- /dev/null
+++ b/account_fiscal_year_auto_create/__manifest__.py
@@ -0,0 +1,21 @@
+# Copyright (C) 2021 - 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": "Fiscal Years - Automatic Creation",
+ "summary": "Automatically create new fiscal years, based on the datas"
+ " of the last fiscal years",
+ "version": "12.0.1.0.1",
+ "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": [
+ "data/ir_cron.xml",
+ ],
+}
diff --git a/account_fiscal_year_auto_create/data/ir_cron.xml b/account_fiscal_year_auto_create/data/ir_cron.xml
new file mode 100644
index 00000000..55e7f1ab
--- /dev/null
+++ b/account_fiscal_year_auto_create/data/ir_cron.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+ Auto Create Fiscal Years
+
+
+ code
+ model.cron_auto_create()
+ 1
+ days
+
+ -1
+
+
+
diff --git a/account_fiscal_year_auto_create/l18n/fr.po b/account_fiscal_year_auto_create/l18n/fr.po
new file mode 100644
index 00000000..094710bc
--- /dev/null
+++ b/account_fiscal_year_auto_create/l18n/fr.po
@@ -0,0 +1,35 @@
+# Translation of Odoo Server.
+# This file contains the translation of the following modules:
+# * account_fiscal_year_auto_create
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Odoo Server 12.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2021-03-31 08:41+0000\n"
+"PO-Revision-Date: 2021-03-31 08:41+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_fiscal_year_auto_create
+#: model:ir.actions.server,name:account_fiscal_year_auto_create.cron_fiscal_year_auto_create_ir_actions_server
+#: model:ir.cron,cron_name:account_fiscal_year_auto_create.cron_fiscal_year_auto_create
+#: model:ir.cron,name:account_fiscal_year_auto_create.cron_fiscal_year_auto_create
+msgid "Auto Create Fiscal Years"
+msgstr "Création automatique d'année fiscales"
+
+#. module: account_fiscal_year_auto_create
+#: code:addons/account_fiscal_year_auto_create/models/account_fiscal_year.py:45
+#, python-format
+msgid "FY %s - %s"
+msgstr "AF %s - %s"
+
+#. module: account_fiscal_year_auto_create
+#: model:ir.model,name:account_fiscal_year_auto_create.model_account_fiscal_year
+msgid "Fiscal Year"
+msgstr "Exercice fiscal"
+
diff --git a/account_fiscal_year_auto_create/models/__init__.py b/account_fiscal_year_auto_create/models/__init__.py
new file mode 100644
index 00000000..562a420f
--- /dev/null
+++ b/account_fiscal_year_auto_create/models/__init__.py
@@ -0,0 +1 @@
+from . import account_fiscal_year
diff --git a/account_fiscal_year_auto_create/models/account_fiscal_year.py b/account_fiscal_year_auto_create/models/account_fiscal_year.py
new file mode 100644
index 00000000..45c11651
--- /dev/null
+++ b/account_fiscal_year_auto_create/models/account_fiscal_year.py
@@ -0,0 +1,56 @@
+# Copyright (C) 2021 - 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 datetime import datetime
+from dateutil.relativedelta import relativedelta
+
+from odoo import _, api, models
+
+
+class AccountFiscalYear(models.Model):
+ _inherit = "account.fiscal.year"
+
+ @api.model
+ def cron_auto_create(self):
+ companies = self.env["res.company"].search([])
+ for company in companies:
+ last_fiscal_year = self.search(
+ [('company_id', '=', company.id)],
+ order="date_to desc", limit=1)
+
+ if last_fiscal_year and (
+ last_fiscal_year.date_to <
+ datetime.now().date() + relativedelta(days=1)
+ ):
+ self.create(last_fiscal_year._prepare_next_fiscal_year())
+
+ @api.multi
+ def _prepare_next_fiscal_year(self):
+ self.ensure_one()
+ # try to generate a new name, based on the previous
+ # name replacing YYYY pattern by YYYY+1 value
+ # - "FY 2018" will be replace by "FY 2019"
+ # - "FY 2018-2019" will be replace by "FY 2019-2020"
+ new_name = self.name.replace(
+ str((self.date_to.year)), str((self.date_to.year + 1))
+ ).replace(
+ str((self.date_from.year)), str((self.date_from.year + 1))
+ )
+ if self.search([
+ ("name", "=", new_name),
+ ("company_id", "=", self.company_id.id)
+ ]):
+ # the replace process fail to guess a correct unique name
+ new_name = _("FY %s - %s") % (
+ str(self.date_to), str(self.date_from)
+ )
+ # compute new dates, handling leap years
+ new_date_from = self.date_to + relativedelta(days=1)
+ new_date_to = new_date_from + relativedelta(years=1, days=-1)
+ return {
+ "name": new_name,
+ "company_id": self.company_id.id,
+ "date_from": new_date_from.strftime("%Y-%m-%d"),
+ "date_to": new_date_to.strftime("%Y-%m-%d"),
+ }
diff --git a/account_fiscal_year_auto_create/readme/CONTRIBUTORS.rst b/account_fiscal_year_auto_create/readme/CONTRIBUTORS.rst
new file mode 100644
index 00000000..9f76a75b
--- /dev/null
+++ b/account_fiscal_year_auto_create/readme/CONTRIBUTORS.rst
@@ -0,0 +1 @@
+* Sylvain LE GAL
diff --git a/account_fiscal_year_auto_create/readme/DESCRIPTION.rst b/account_fiscal_year_auto_create/readme/DESCRIPTION.rst
new file mode 100644
index 00000000..94e93455
--- /dev/null
+++ b/account_fiscal_year_auto_create/readme/DESCRIPTION.rst
@@ -0,0 +1,25 @@
+This module extends the functionality of Accounting Odoo module, to
+auto generate fiscal years.
+
+Once installed, a cron is running each day. It will create, for each company,
+a new fiscal year, if it is the last day of the current fiscal year.
+
+This module is interesting specially in multi company context, to avoid annoying setup every year.
+
+The fiscal year created has a classical "12 monthes" duration, but the accountant
+can modify it, once created.
+
+Exemple
+~~~~~~~
+
+If a company has it last fiscal year, defined as:
+
+- ``name``: FY 2021-2022
+- ``date_from``: 2021-06-01
+- ``date_to``: 2022-05-31
+
+When the cron will be executed on May 31, 2022, it will create the following fiscal year:
+
+- ``name``: FY 2022-2023
+- ``date_from``: 2022-06-01
+- ``date_to``: 2023-05-31
diff --git a/account_fiscal_year_auto_create/tests/__init__.py b/account_fiscal_year_auto_create/tests/__init__.py
new file mode 100644
index 00000000..d9b96c4f
--- /dev/null
+++ b/account_fiscal_year_auto_create/tests/__init__.py
@@ -0,0 +1 @@
+from . import test_module
diff --git a/account_fiscal_year_auto_create/tests/test_module.py b/account_fiscal_year_auto_create/tests/test_module.py
new file mode 100644
index 00000000..8c1658cc
--- /dev/null
+++ b/account_fiscal_year_auto_create/tests/test_module.py
@@ -0,0 +1,54 @@
+# Copyright (C) 2021 - 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.tests.common import TransactionCase
+
+from datetime import date, datetime
+
+
+class TestModule(TransactionCase):
+
+ def setUp(self):
+ super().setUp()
+ self.AccountFiscalYear = self.env["account.fiscal.year"]
+ self.company = self.env["res.company"].create({
+ "name": "Demo Company (account_fiscal_year_auto_create)",
+ })
+
+ # create a fiscal year
+ self.last_year = datetime.now().year - 1
+ self.last_fiscal_year = self.AccountFiscalYear.create({
+ "name": "FY %d" % (self.last_year),
+ "date_from": date(self.last_year, 1, 1).strftime("%Y-%m-%d"),
+ "date_to": date(self.last_year, 12, 31).strftime("%Y-%m-%d"),
+ "company_id": self.company.id,
+ })
+
+ def test_cron(self):
+ existing_fiscal_years = self.AccountFiscalYear.search([])
+ self.AccountFiscalYear.cron_auto_create()
+
+ # Run cron should create a new fiscal year
+ new_fiscal_year = self.AccountFiscalYear.search([
+ ("id", "not in", existing_fiscal_years.ids)
+ ])
+ self.assertTrue(new_fiscal_year)
+ self.assertEqual(
+ new_fiscal_year.name, "FY %d" % (self.last_year + 1))
+ self.assertEqual(
+ new_fiscal_year.date_from, date(self.last_year + 1, 1, 1))
+ self.assertEqual(
+ new_fiscal_year.date_from, date(self.last_year + 1, 1, 1))
+ self.assertEqual(
+ new_fiscal_year.name, "FY %d" % (self.last_year + 1))
+
+ # Rerun cron should not create a new fiscal year
+ existing_fiscal_years = self.AccountFiscalYear.search([])
+ self.AccountFiscalYear.cron_auto_create()
+
+ # Run cron should create a new fiscal year
+ new_fiscal_year = self.AccountFiscalYear.search([
+ ("id", "not in", existing_fiscal_years.ids)
+ ])
+ self.assertFalse(new_fiscal_year)