From 1768a5f832085687cc964c4eed6274ba7bca6650 Mon Sep 17 00:00:00 2001 From: LauraCForgeFlow <laura.cazorla@forgeflow.com> Date: Thu, 14 Nov 2024 08:41:33 +0100 Subject: [PATCH] [IMP] hr_holidays_natural_period: exclude public holidays in natural days computation --- hr_holidays_natural_period/README.rst | 2 + hr_holidays_natural_period/__manifest__.py | 3 +- .../demo/hr_leave_type_data.xml | 1 + .../models/resource_calendar.py | 8 +- hr_holidays_natural_period/readme/USAGE.rst | 2 + .../static/description/index.html | 2 + .../tests/test_hr_leave.py | 113 ++++++++++++++++-- .../views/hr_leave_views.xml | 27 +++++ 8 files changed, 147 insertions(+), 11 deletions(-) create mode 100644 hr_holidays_natural_period/views/hr_leave_views.xml diff --git a/hr_holidays_natural_period/README.rst b/hr_holidays_natural_period/README.rst index 12a32afa..44787707 100644 --- a/hr_holidays_natural_period/README.rst +++ b/hr_holidays_natural_period/README.rst @@ -47,6 +47,8 @@ For using natural period on leaves: #. If no leave type is yet specified, then default configuration is to exclude public holidays. #. The number of days will be computed without employee calendar used. +#. The computation can exclude public holidays or not, depending on the configuration + of the leave type. Bug Tracker =========== diff --git a/hr_holidays_natural_period/__manifest__.py b/hr_holidays_natural_period/__manifest__.py index 08ff5304..5d87f6e4 100644 --- a/hr_holidays_natural_period/__manifest__.py +++ b/hr_holidays_natural_period/__manifest__.py @@ -10,7 +10,8 @@ "author": "Tecnativa, Odoo Community Association (OCA)", "license": "AGPL-3", "installable": True, - "depends": ["hr_holidays"], + "depends": ["hr_holidays_public"], "maintainers": ["victoralmau"], "demo": ["demo/hr_leave_type_data.xml"], + "data": ["views/hr_leave_views.xml"], } diff --git a/hr_holidays_natural_period/demo/hr_leave_type_data.xml b/hr_holidays_natural_period/demo/hr_leave_type_data.xml index a10abd02..7ee7e27b 100644 --- a/hr_holidays_natural_period/demo/hr_leave_type_data.xml +++ b/hr_holidays_natural_period/demo/hr_leave_type_data.xml @@ -5,5 +5,6 @@ <field name="request_unit">natural_day</field> <field name="responsible_id" ref="base.user_admin" /> <field name="employee_requests">yes</field> + <field name="exclude_public_holidays">False</field> </record> </odoo> diff --git a/hr_holidays_natural_period/models/resource_calendar.py b/hr_holidays_natural_period/models/resource_calendar.py index 9ae4784f..7fbbe2fb 100644 --- a/hr_holidays_natural_period/models/resource_calendar.py +++ b/hr_holidays_natural_period/models/resource_calendar.py @@ -47,7 +47,9 @@ def _attendance_intervals_batch( start_dt=start_dt, end_dt=end_dt, resources=resources, domain=domain, tz=tz ) if self.env.context.get("natural_period"): - return self._natural_period_intervals_batch( - start_dt, end_dt, res, resources - ) + res = self._natural_period_intervals_batch(start_dt, end_dt, res, resources) + if self.env.context.get("exclude_public_holidays") and resources: + return self._attendance_intervals_batch_exclude_public_holidays( + start_dt, end_dt, res, resources, tz + ) return res diff --git a/hr_holidays_natural_period/readme/USAGE.rst b/hr_holidays_natural_period/readme/USAGE.rst index a4425e87..7ef0e7c6 100644 --- a/hr_holidays_natural_period/readme/USAGE.rst +++ b/hr_holidays_natural_period/readme/USAGE.rst @@ -7,3 +7,5 @@ For using natural period on leaves: #. If no leave type is yet specified, then default configuration is to exclude public holidays. #. The number of days will be computed without employee calendar used. +#. The computation can exclude public holidays or not, depending on the configuration + of the leave type. diff --git a/hr_holidays_natural_period/static/description/index.html b/hr_holidays_natural_period/static/description/index.html index 8cf807aa..a443cd47 100644 --- a/hr_holidays_natural_period/static/description/index.html +++ b/hr_holidays_natural_period/static/description/index.html @@ -394,6 +394,8 @@ <h1><a class="toc-backref" href="#toc-entry-1">Usage</a></h1> <li>If no leave type is yet specified, then default configuration is to exclude public holidays.</li> <li>The number of days will be computed without employee calendar used.</li> +<li>The computation can exclude public holidays or not, depending on the configuration +of the leave type.</li> </ol> </div> <div class="section" id="bug-tracker"> diff --git a/hr_holidays_natural_period/tests/test_hr_leave.py b/hr_holidays_natural_period/tests/test_hr_leave.py index cd6be330..0e467cd8 100644 --- a/hr_holidays_natural_period/tests/test_hr_leave.py +++ b/hr_holidays_natural_period/tests/test_hr_leave.py @@ -56,6 +56,12 @@ def setUpClass(cls): "user_id": cls.user.id, } ) + cls.public_holiday = cls.env["hr.holidays.public"].create( + { + "year": 2023, + "country_id": False, + } + ) def _create_leave_allocation(self, leave_type, days): leave_allocation_form = Form( @@ -76,21 +82,114 @@ def _create_hr_leave(self, leave_type, date_from, date_to): leave_form.request_date_to = date_to return leave_form.save() + def _create_public_holiday_line(self, name, date, year): + public_holiday_line = Form(self.env["hr.holidays.public.line"].sudo()) + public_holiday_line.name = name + public_holiday_line.date = date + public_holiday_line.year_id = year + return public_holiday_line.save() + @users("test-user") def test_hr_leave_natural_day(self): - leave_allocation = self._create_leave_allocation(self.leave_type, 5) + leave_allocation = self._create_leave_allocation(self.leave_type, 10) leave_allocation.action_confirm() leave_allocation.sudo().action_validate() res_leave_type = self.env["hr.leave.type"].get_days_all_request()[0][1] - self.assertEqual(res_leave_type["remaining_leaves"], "5") - self.assertEqual(res_leave_type["virtual_remaining_leaves"], "5") - self.assertEqual(res_leave_type["max_leaves"], "5") + self.assertEqual(res_leave_type["remaining_leaves"], "10") + self.assertEqual(res_leave_type["virtual_remaining_leaves"], "10") + self.assertEqual(res_leave_type["max_leaves"], "10") + self.assertEqual(res_leave_type["leaves_taken"], "0") + self.assertEqual(res_leave_type["virtual_leaves_taken"], "0") + self.assertEqual(res_leave_type["request_unit"], "natural_day") + leave = self._create_hr_leave(self.leave_type, "2023-01-08", "2023-01-15") + self.assertEqual(leave.number_of_days, 8) + self.assertEqual(leave.number_of_days_display, 8) + + @users("test-user") + def test_hr_leave_natural_day_public_holiday_01(self): + leave_allocation = self._create_leave_allocation(self.leave_type, 10) + leave_allocation.action_confirm() + leave_allocation.sudo().action_validate() + self._create_public_holiday_line( + "Public holiday 1", "2023-01-09", self.public_holiday + ) + + res_leave_type = self.env["hr.leave.type"].get_days_all_request()[0][1] + self.assertEqual(res_leave_type["remaining_leaves"], "10") + self.assertEqual(res_leave_type["virtual_remaining_leaves"], "10") + self.assertEqual(res_leave_type["max_leaves"], "10") + self.assertEqual(res_leave_type["leaves_taken"], "0") + self.assertEqual(res_leave_type["virtual_leaves_taken"], "0") + self.assertEqual(res_leave_type["request_unit"], "natural_day") + self.assertEqual(self.leave_type.exclude_public_holidays, False) + leave = self._create_hr_leave(self.leave_type, "2023-01-08", "2023-01-15") + self.assertEqual(leave.number_of_days, 8) + self.assertEqual(leave.number_of_days_display, 8) + + @users("test-user") + def test_hr_leave_natural_day_public_holiday_02(self): + leave_allocation = self._create_leave_allocation(self.leave_type, 10) + leave_allocation.action_confirm() + leave_allocation.sudo().action_validate() + self._create_public_holiday_line( + "Public holiday 1", "2023-01-09", self.public_holiday + ) + self.leave_type.write({"exclude_public_holidays": True}) + + res_leave_type = self.env["hr.leave.type"].get_days_all_request()[0][1] + self.assertEqual(res_leave_type["remaining_leaves"], "10") + self.assertEqual(res_leave_type["virtual_remaining_leaves"], "10") + self.assertEqual(res_leave_type["max_leaves"], "10") + self.assertEqual(res_leave_type["leaves_taken"], "0") + self.assertEqual(res_leave_type["virtual_leaves_taken"], "0") + self.assertEqual(res_leave_type["request_unit"], "natural_day") + self.assertEqual(self.leave_type.exclude_public_holidays, True) + leave = self._create_hr_leave(self.leave_type, "2023-01-08", "2023-01-15") + self.assertEqual(leave.number_of_days, 7) + self.assertEqual(leave.number_of_days_display, 7) + + @users("test-user") + def test_hr_leave_natural_day_public_holiday_weekend_01(self): + leave_allocation = self._create_leave_allocation(self.leave_type, 10) + leave_allocation.action_confirm() + leave_allocation.sudo().action_validate() + self._create_public_holiday_line( + "Public holiday 1", "2023-01-14", self.public_holiday + ) + + res_leave_type = self.env["hr.leave.type"].get_days_all_request()[0][1] + self.assertEqual(res_leave_type["remaining_leaves"], "10") + self.assertEqual(res_leave_type["virtual_remaining_leaves"], "10") + self.assertEqual(res_leave_type["max_leaves"], "10") + self.assertEqual(res_leave_type["leaves_taken"], "0") + self.assertEqual(res_leave_type["virtual_leaves_taken"], "0") + self.assertEqual(res_leave_type["request_unit"], "natural_day") + self.assertEqual(self.leave_type.exclude_public_holidays, False) + leave = self._create_hr_leave(self.leave_type, "2023-01-08", "2023-01-15") + self.assertEqual(leave.number_of_days, 8) + self.assertEqual(leave.number_of_days_display, 8) + + @users("test-user") + def test_hr_leave_natural_day_public_holiday_weekend_02(self): + leave_allocation = self._create_leave_allocation(self.leave_type, 10) + leave_allocation.action_confirm() + leave_allocation.sudo().action_validate() + self._create_public_holiday_line( + "Public holiday 1", "2023-01-14", self.public_holiday + ) + self.leave_type.write({"exclude_public_holidays": True}) + + res_leave_type = self.env["hr.leave.type"].get_days_all_request()[0][1] + self.assertEqual(res_leave_type["remaining_leaves"], "10") + self.assertEqual(res_leave_type["virtual_remaining_leaves"], "10") + self.assertEqual(res_leave_type["max_leaves"], "10") self.assertEqual(res_leave_type["leaves_taken"], "0") self.assertEqual(res_leave_type["virtual_leaves_taken"], "0") self.assertEqual(res_leave_type["request_unit"], "natural_day") - leave = self._create_hr_leave(self.leave_type, "2023-01-02", "2023-01-05") - self.assertEqual(leave.number_of_days, 4.0) - self.assertEqual(leave.number_of_days_display, 4.0) + self.assertEqual(self.leave_type.exclude_public_holidays, True) + leave = self._create_hr_leave(self.leave_type, "2023-01-08", "2023-01-15") + self.assertEqual(leave.number_of_days, 7) + self.assertEqual(leave.number_of_days_display, 7) @users("test-user") def test_hr_leave_day(self): diff --git a/hr_holidays_natural_period/views/hr_leave_views.xml b/hr_holidays_natural_period/views/hr_leave_views.xml new file mode 100644 index 00000000..cc20860d --- /dev/null +++ b/hr_holidays_natural_period/views/hr_leave_views.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8" ?> +<odoo> + + <record id="hr_leave_view_form" model="ir.ui.view"> + <field name="name">hr.leave.view.form</field> + <field name="model">hr.leave</field> + <field name="inherit_id" ref="hr_holidays.hr_leave_view_form" /> + <field name="arch" type="xml"> + <xpath expr="//label[@for='request_unit_half']" position="attributes"> + <attribute + name="attrs" + >{'invisible': [('leave_type_request_unit', 'in', ['day', 'natural_day'])]}</attribute> + </xpath> + <xpath expr="//field[@name='request_unit_half']" position="attributes"> + <attribute + name="attrs" + >{'readonly': [('state', 'not in', ('draft', 'confirm'))], 'invisible': [('leave_type_request_unit', 'in', ['day', 'natural_day'])]}</attribute> + </xpath> + <xpath expr="//div[field[@name='request_unit_half']]" position="attributes"> + <attribute + name="attrs" + >{'invisible': [('leave_type_request_unit', 'in', ['day', 'natural_day'])]}</attribute> + </xpath> + </field> + </record> + +</odoo>