From d461492b7a12f83dbc1f0bdeb262448aa79a95a5 Mon Sep 17 00:00:00 2001 From: Abraham Anes Date: Sun, 16 Aug 2026 23:34:53 +0200 Subject: [PATCH] [18.0][IMP] hr_shift_holidays_public: assign templates on public holiday --- hr_shift_holidays_public/README.rst | 12 ++++--- hr_shift_holidays_public/__manifest__.py | 2 +- hr_shift_holidays_public/models/__init__.py | 2 ++ .../models/res_company.py | 13 ++++++++ .../models/res_config_settings.py | 12 +++++++ .../models/shift_planning_line.py | 17 +++++++++- hr_shift_holidays_public/readme/USAGE.md | 6 ++++ .../static/description/index.html | 31 +++++++++---------- .../tests/test_hr_shift_holidays_public.py | 22 +++++++++++++ .../views/res_config_settings_views.xml | 18 +++++++++++ 10 files changed, 112 insertions(+), 23 deletions(-) create mode 100644 hr_shift_holidays_public/models/res_company.py create mode 100644 hr_shift_holidays_public/models/res_config_settings.py create mode 100644 hr_shift_holidays_public/views/res_config_settings_views.xml diff --git a/hr_shift_holidays_public/README.rst b/hr_shift_holidays_public/README.rst index 7c625dc..72f2dd3 100644 --- a/hr_shift_holidays_public/README.rst +++ b/hr_shift_holidays_public/README.rst @@ -1,7 +1,3 @@ -.. image:: https://odoo-community.org/readme-banner-image - :target: https://odoo-community.org/get-involved?utm_source=readme - :alt: Odoo Community Association - ==================================== Employees Shifts and public holidays ==================================== @@ -17,7 +13,7 @@ Employees Shifts and public holidays .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png :target: https://odoo-community.org/page/development-status :alt: Beta -.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fshift--planning-lightgray.png?logo=github @@ -48,6 +44,12 @@ assingment card. |Public holidays in shift cards| +By default it is not possible to assign a shift template on a public +holiday. If your company does work on some public holidays, enable +*Shift assignment overrides public holidays* in the Employees settings: +lines keep being flagged as holidays, but explicitly assigning a +template to them turns them into regular working shifts. + .. |Public holidays in shift cards| image:: https://raw.githubusercontent.com/OCA/shift-planning/18.0/hr_shift_holidays_public/static/description/public_holidays.png Bug Tracker diff --git a/hr_shift_holidays_public/__manifest__.py b/hr_shift_holidays_public/__manifest__.py index 06524ff..92533fe 100644 --- a/hr_shift_holidays_public/__manifest__.py +++ b/hr_shift_holidays_public/__manifest__.py @@ -9,5 +9,5 @@ "website": "https://github.com/OCA/shift-planning", "category": "Marketing", "depends": ["calendar_public_holiday", "hr_shift"], - "data": [], + "data": ["views/res_config_settings_views.xml"], } diff --git a/hr_shift_holidays_public/models/__init__.py b/hr_shift_holidays_public/models/__init__.py index 5374e2e..9820f44 100644 --- a/hr_shift_holidays_public/models/__init__.py +++ b/hr_shift_holidays_public/models/__init__.py @@ -1 +1,3 @@ +from . import res_company +from . import res_config_settings from . import shift_planning_line diff --git a/hr_shift_holidays_public/models/res_company.py b/hr_shift_holidays_public/models/res_company.py new file mode 100644 index 0000000..a95abf7 --- /dev/null +++ b/hr_shift_holidays_public/models/res_company.py @@ -0,0 +1,13 @@ +# Copyright 2026 Tesseratech - Abraham Anes +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from odoo import fields, models + + +class ResCompany(models.Model): + _inherit = "res.company" + + shift_template_overrides_public_holiday = fields.Boolean( + string="Shift assignment overrides public holidays", + help="When enabled, a shift line with a template explicitly assigned " + "is considered a working shift even if it falls on a public holiday.", + ) diff --git a/hr_shift_holidays_public/models/res_config_settings.py b/hr_shift_holidays_public/models/res_config_settings.py new file mode 100644 index 0000000..b5110fd --- /dev/null +++ b/hr_shift_holidays_public/models/res_config_settings.py @@ -0,0 +1,12 @@ +# Copyright 2026 Tesseratech - Abraham Anes +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from odoo import fields, models + + +class ResConfigSettings(models.TransientModel): + _inherit = "res.config.settings" + + shift_template_overrides_public_holiday = fields.Boolean( + related="company_id.shift_template_overrides_public_holiday", + readonly=False, + ) diff --git a/hr_shift_holidays_public/models/shift_planning_line.py b/hr_shift_holidays_public/models/shift_planning_line.py index 49c1f01..8382fa2 100644 --- a/hr_shift_holidays_public/models/shift_planning_line.py +++ b/hr_shift_holidays_public/models/shift_planning_line.py @@ -1,14 +1,29 @@ # Copyright 2024 Tecnativa - David Vidal # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). -from odoo import models +from odoo import api, models class ShiftPlanningLine(models.Model): _inherit = "hr.shift.planning.line" + def _template_overrides_public_holiday(self): + company = self.employee_id.company_id or self.env.company + return company.shift_template_overrides_public_holiday + def _is_public_holiday(self): if not (self.start_date and self.employee_id): return False + if self.template_id and self._template_overrides_public_holiday(): + return False return self.env["calendar.public.holiday"].is_public_holiday( self.start_date, self.employee_id.address_id.id ) + + @api.constrains("template_id") + def _constrain_template_id(self): + lines = self.filtered( + lambda line: not ( + line.state == "holiday" and line._template_overrides_public_holiday() + ) + ) + return super(ShiftPlanningLine, lines)._constrain_template_id() diff --git a/hr_shift_holidays_public/readme/USAGE.md b/hr_shift_holidays_public/readme/USAGE.md index 9f793d8..d75263b 100644 --- a/hr_shift_holidays_public/readme/USAGE.md +++ b/hr_shift_holidays_public/readme/USAGE.md @@ -2,3 +2,9 @@ When there's a public holiday for an employees work address no shift will be ass for that day. Those days will be marked as black in the assingment card. ![Public holidays in shift cards](../static/description/public_holidays.png) + +By default it is not possible to assign a shift template on a public holiday. +If your company does work on some public holidays, enable *Shift assignment +overrides public holidays* in the Employees settings: lines keep being flagged +as holidays, but explicitly assigning a template to them turns them into +regular working shifts. diff --git a/hr_shift_holidays_public/static/description/index.html b/hr_shift_holidays_public/static/description/index.html index cae7719..abc4060 100644 --- a/hr_shift_holidays_public/static/description/index.html +++ b/hr_shift_holidays_public/static/description/index.html @@ -3,7 +3,7 @@ -README.rst +Employees Shifts and public holidays -
+
+

Employees Shifts and public holidays

- - -Odoo Community Association - -
-

Employees Shifts and public holidays

-

Beta License: AGPL-3 OCA/shift-planning Translate me on Weblate Try me on Runboat

+

Beta License: AGPL-3 OCA/shift-planning Translate me on Weblate Try me on Runboat

Avoid assigning shifts on public holidays.

Table of contents

@@ -390,14 +385,19 @@

Employees Shifts and public holidays

-

Usage

+

Usage

When there’s a public holiday for an employees work address no shift will be assigned for that day. Those days will be marked as black in the assingment card.

Public holidays in shift cards

+

By default it is not possible to assign a shift template on a public +holiday. If your company does work on some public holidays, enable +Shift assignment overrides public holidays in the Employees settings: +lines keep being flagged as holidays, but explicitly assigning a +template to them turns them into regular working shifts.

-

Bug Tracker

+

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 to smash it by providing a detailed and welcomed @@ -405,15 +405,15 @@

Bug Tracker

Do not contact contributors directly about support or help with technical issues.

-

Credits

+

Credits

-

Authors

+

Authors

  • Tecnativa
-

Contributors

+

Contributors

-

Maintainers

+

Maintainers

This module is maintained by the OCA.

Odoo Community Association @@ -440,6 +440,5 @@

Maintainers

-
diff --git a/hr_shift_holidays_public/tests/test_hr_shift_holidays_public.py b/hr_shift_holidays_public/tests/test_hr_shift_holidays_public.py index 0dc2edf..f78e7b1 100644 --- a/hr_shift_holidays_public/tests/test_hr_shift_holidays_public.py +++ b/hr_shift_holidays_public/tests/test_hr_shift_holidays_public.py @@ -1,6 +1,7 @@ # Copyright 2025 Tecnativa - Víctor Martínez # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from odoo import Command +from odoo.exceptions import UserError from odoo.addons.hr_shift.tests.common import TestHrShiftBase @@ -35,3 +36,24 @@ def test_hr_shift_planning_holiday_public(self): self.assertEqual(shift_a_line_0.state, "unassigned") shift_a_line_1 = shift_a.line_ids.filtered(lambda x: x.day_number == "1") self.assertEqual(shift_a_line_1.state, "holiday") + + def test_template_on_public_holiday_forbidden(self): + self.planning.generate_shifts() + shift_a = self.planning.shift_ids.filtered( + lambda x: x.employee_id == self.employee_a + ) + line_1 = shift_a.line_ids.filtered(lambda x: x.day_number == "1") + self.assertEqual(line_1.state, "holiday") + with self.assertRaises(UserError): + line_1.template_id = self.env.ref("hr_shift.template_morning") + + def test_template_overrides_public_holiday(self): + self.company.shift_template_overrides_public_holiday = True + self.planning.generate_shifts() + shift_a = self.planning.shift_ids.filtered( + lambda x: x.employee_id == self.employee_a + ) + line_1 = shift_a.line_ids.filtered(lambda x: x.day_number == "1") + self.assertEqual(line_1.state, "holiday") + line_1.template_id = self.env.ref("hr_shift.template_morning") + self.assertEqual(line_1.state, "assigned") diff --git a/hr_shift_holidays_public/views/res_config_settings_views.xml b/hr_shift_holidays_public/views/res_config_settings_views.xml new file mode 100644 index 0000000..ec87f50 --- /dev/null +++ b/hr_shift_holidays_public/views/res_config_settings_views.xml @@ -0,0 +1,18 @@ + + + + res.config.settings + + + + + + + + + +