diff --git a/hr_payroll_period/__manifest__.py b/hr_payroll_period/__manifest__.py index d2e0d46e..7f82ccf2 100644 --- a/hr_payroll_period/__manifest__.py +++ b/hr_payroll_period/__manifest__.py @@ -19,6 +19,7 @@ "security/hr_period_security.xml", "data/ir_sequence_data.xml", "data/date_range_type.xml", + "data/ir_cron.xml", "views/menus.xml", "views/date_range_type_view.xml", "views/hr_period_view.xml", diff --git a/hr_payroll_period/data/ir_cron.xml b/hr_payroll_period/data/ir_cron.xml new file mode 100644 index 00000000..6eaf732a --- /dev/null +++ b/hr_payroll_period/data/ir_cron.xml @@ -0,0 +1,15 @@ + + + + Create Next Fiscal Year + 1 + months + -1 + + + model.cron_create_next_fiscal_year() + code + + + + diff --git a/hr_payroll_period/models/hr_fiscal_year.py b/hr_payroll_period/models/hr_fiscal_year.py index 8121485d..d74bdb96 100644 --- a/hr_payroll_period/models/hr_fiscal_year.py +++ b/hr_payroll_period/models/hr_fiscal_year.py @@ -302,3 +302,53 @@ def search_period(self, number): return next( (p for p in self.period_ids if p.number == number), self.env["hr.period"] ) + + @api.model + def cron_create_next_fiscal_year(self): + current_year = datetime.now().year + next_year = current_year + 1 + # Get the latest fiscal year that has not ended yet + latest_fiscal_year = self.search( + [("date_end", "<", datetime(next_year, 1, 1).strftime(DF))], + order="date_end desc", + limit=1, + ) + if not latest_fiscal_year: + return self + latest_period_end = max(latest_fiscal_year.period_ids.mapped("date_end")) + fiscal_year_start = latest_period_end + relativedelta(days=1) + fiscal_year_end = datetime(next_year, 12, 31).strftime(DF) + # Check if a fiscal year with the same start and end dates already exists + existing_fiscal_year = self.search( + [ + ("date_start", "=", fiscal_year_start), + ("date_end", "=", fiscal_year_end), + ], + limit=1, + ) + if existing_fiscal_year: + return existing_fiscal_year + + schedule_pay = latest_fiscal_year.schedule_pay + payment_weekday = latest_fiscal_year.payment_weekday + payment_week = latest_fiscal_year.payment_week + schedule_name = next( + (s[1] for s in get_schedules(self) if s[0] == schedule_pay), False + ) + + fiscal_year = self.create( + { + "name": "%(year)s - %(schedule)s" + % { + "year": next_year, + "schedule": schedule_name, + }, + "date_start": fiscal_year_start, + "date_end": fiscal_year_end, + "schedule_pay": schedule_pay, + "payment_weekday": payment_weekday, + "payment_week": payment_week, + } + ) + fiscal_year.create_periods() + return fiscal_year diff --git a/hr_payroll_period/static/description/index.html b/hr_payroll_period/static/description/index.html index dc2ebe98..5738bbca 100644 --- a/hr_payroll_period/static/description/index.html +++ b/hr_payroll_period/static/description/index.html @@ -1,4 +1,3 @@ - diff --git a/hr_payroll_period/tests/test_hr_fiscalyear.py b/hr_payroll_period/tests/test_hr_fiscalyear.py index 62cd261d..5c0f62bd 100644 --- a/hr_payroll_period/tests/test_hr_fiscalyear.py +++ b/hr_payroll_period/tests/test_hr_fiscalyear.py @@ -1,6 +1,8 @@ # Copyright 2015 Savoir-faire Linux. All Rights Reserved. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from datetime import date +from datetime import date, datetime + +from dateutil.relativedelta import relativedelta from odoo import fields from odoo.exceptions import UserError, ValidationError @@ -344,3 +346,48 @@ def test_create_periods_semi_monthly_payment_last_day(self): self.assertEqual(periods[2].date_payment, date(2015, 5, 4)) self.assertEqual(periods[22].date_payment, date(2016, 3, 5)) self.assertEqual(periods[23].date_payment, date(2016, 3, 19)) + + def test_cron_create_next_fiscal_year(self): + # if we are in 2024, it should create the periods for 2025 + current_year = datetime.now().year + current_fiscal_year = self.fy_model.search( + [ + ("date_start", "=", f"{current_year}-01-01"), + ("date_end", "=", f"{current_year}-12-31"), + ], + limit=1, + ) + + # If 2024 doesn't exist, create it + if not current_fiscal_year: + current_fiscal_year = self.create_fiscal_year( + { + "date_start": f"{current_year}-01-01", + "date_end": f"{current_year}-12-31", + } + ) + current_fiscal_year.create_periods() + next_fiscal_year = self.env["hr.fiscalyear"].cron_create_next_fiscal_year() + periods = self.get_periods(next_fiscal_year) + # Ensure the periods are continuous and within the fiscal year dates + for i, period in enumerate(periods): + if i == 0: + self.assertEqual(period.date_start, next_fiscal_year.date_start) + else: + self.assertEqual( + period.date_start, periods[i - 1].date_end + relativedelta(days=1) + ) + if i == len(periods) - 1: + self.assertEqual(period.date_end, next_fiscal_year.date_end) + # Check that the first period of next fiscal year starts 1 day after + current_year_periods = self.get_periods(current_fiscal_year) + last_period_current_year = current_year_periods[-1] + first_period_next_year = periods[0] + self.assertEqual( + first_period_next_year.date_start, + last_period_current_year.date_end + relativedelta(days=1), + ) + # Check that the first period end is on last of January + self.assertEqual( + first_period_next_year.date_end, datetime(current_year + 1, 1, 31).date() + )