diff --git a/hr_holidays_natural_period/README.rst b/hr_holidays_natural_period/README.rst new file mode 100644 index 00000000..a5e6135f --- /dev/null +++ b/hr_holidays_natural_period/README.rst @@ -0,0 +1,107 @@ +======================= +Holidays natural period +======================= + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:78da5aea18b0817984f207d9021d5623f8a1fe9d26a6160c4219a54b9f878df5 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/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%2Fhr--holidays-lightgray.png?logo=github + :target: https://github.com/OCA/hr-holidays/tree/17.0/hr_holidays_natural_period + :alt: OCA/hr-holidays +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/hr-holidays-17-0/hr-holidays-17-0-hr_holidays_natural_period + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/hr-holidays&target_branch=17.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module was written to define natural day option in request unit on +holidays type. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +For using natural period on leaves: + +1. Go to *Leaves > Dashboard*. +2. Select dragging on the calendar the days you want to be on leave, or + go to the form view for selecting start and end dates. +3. Select the proper "Leave Type" that has "Natural day" selected in + "Request unit". +4. If no leave type is yet specified, then default configuration is to + exclude public holidays. +5. The number of days will be computed without employee calendar used. + +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 +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* Tecnativa + +Contributors +------------ + +- Tecnativa + + - Víctor Martínez + - Pedro Baeza + - Carlos López + +- APSL-Nagarro + + - Antoni Marroig + +Maintainers +----------- + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +.. |maintainer-victoralmau| image:: https://github.com/victoralmau.png?size=40px + :target: https://github.com/victoralmau + :alt: victoralmau + +Current `maintainer `__: + +|maintainer-victoralmau| + +This module is part of the `OCA/hr-holidays `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/hr_holidays_natural_period/__init__.py b/hr_holidays_natural_period/__init__.py new file mode 100644 index 00000000..0650744f --- /dev/null +++ b/hr_holidays_natural_period/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/hr_holidays_natural_period/__manifest__.py b/hr_holidays_natural_period/__manifest__.py new file mode 100644 index 00000000..face965a --- /dev/null +++ b/hr_holidays_natural_period/__manifest__.py @@ -0,0 +1,16 @@ +# Copyright 2020 Tecnativa - Víctor Martínez +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +{ + "name": "Holidays natural period", + "summary": "Apply natural days in holidays", + "version": "17.0.1.0.0", + "category": "Human Resources", + "website": "https://github.com/OCA/hr-holidays", + "author": "Tecnativa, Odoo Community Association (OCA)", + "license": "AGPL-3", + "installable": True, + "depends": ["hr_holidays"], + "maintainers": ["victoralmau"], + "demo": ["demo/hr_leave_type_data.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 new file mode 100644 index 00000000..b0c82cb3 --- /dev/null +++ b/hr_holidays_natural_period/demo/hr_leave_type_data.xml @@ -0,0 +1,9 @@ + + + + Test Time Off (natural day) + natural_day + + yes + + diff --git a/hr_holidays_natural_period/i18n/ca.po b/hr_holidays_natural_period/i18n/ca.po new file mode 100644 index 00000000..e5bf1cb3 --- /dev/null +++ b/hr_holidays_natural_period/i18n/ca.po @@ -0,0 +1,47 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_holidays_natural_period +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2022-02-14 11:16+0000\n" +"Last-Translator: Noel estudillo \n" +"Language-Team: none\n" +"Language: ca\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.3.2\n" + +#. module: hr_holidays_natural_period +#: model:ir.model.fields.selection,name:hr_holidays_natural_period.selection__hr_leave_type__request_unit__natural_day +msgid "Natural day" +msgstr "Dia natural" + +#. module: hr_holidays_natural_period +#: model:ir.model,name:hr_holidays_natural_period.model_resource_calendar +msgid "Resource Working Time" +msgstr "Temps de treball dels recursos" + +#. module: hr_holidays_natural_period +#: model:ir.model.fields,field_description:hr_holidays_natural_period.field_hr_leave_type__request_unit +msgid "Take Time Off in" +msgstr "Preneu-vos un temps lliure" + +#. module: hr_holidays_natural_period +#: model:hr.leave.type,name:hr_holidays_natural_period.hr_leave_type_natural_day_test +msgid "Test Time Off (natural day)" +msgstr "" + +#. module: hr_holidays_natural_period +#: model:ir.model,name:hr_holidays_natural_period.model_hr_leave +msgid "Time Off" +msgstr "Temps lliure" + +#. module: hr_holidays_natural_period +#: model:ir.model,name:hr_holidays_natural_period.model_hr_leave_type +msgid "Time Off Type" +msgstr "Tipus de temps lliure" diff --git a/hr_holidays_natural_period/i18n/es.po b/hr_holidays_natural_period/i18n/es.po new file mode 100644 index 00000000..8e2ca740 --- /dev/null +++ b/hr_holidays_natural_period/i18n/es.po @@ -0,0 +1,47 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_holidays_natural_period +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 15.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-08-04 13:12+0000\n" +"Last-Translator: Ivorra78 \n" +"Language-Team: none\n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: hr_holidays_natural_period +#: model:ir.model.fields.selection,name:hr_holidays_natural_period.selection__hr_leave_type__request_unit__natural_day +msgid "Natural day" +msgstr "Día natural" + +#. module: hr_holidays_natural_period +#: model:ir.model,name:hr_holidays_natural_period.model_resource_calendar +msgid "Resource Working Time" +msgstr "Tiempo de Trabajo de Recursos" + +#. module: hr_holidays_natural_period +#: model:ir.model.fields,field_description:hr_holidays_natural_period.field_hr_leave_type__request_unit +msgid "Take Time Off in" +msgstr "Coger ausencia en" + +#. module: hr_holidays_natural_period +#: model:hr.leave.type,name:hr_holidays_natural_period.hr_leave_type_natural_day_test +msgid "Test Time Off (natural day)" +msgstr "Tiempo libre de prueba (día natural)" + +#. module: hr_holidays_natural_period +#: model:ir.model,name:hr_holidays_natural_period.model_hr_leave +msgid "Time Off" +msgstr "Ausencias" + +#. module: hr_holidays_natural_period +#: model:ir.model,name:hr_holidays_natural_period.model_hr_leave_type +msgid "Time Off Type" +msgstr "Tipo de ausencia" diff --git a/hr_holidays_natural_period/i18n/hr.po b/hr_holidays_natural_period/i18n/hr.po new file mode 100644 index 00000000..0135cdea --- /dev/null +++ b/hr_holidays_natural_period/i18n/hr.po @@ -0,0 +1,57 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_holidays_natural_period +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2022-08-23 12:07+0000\n" +"Last-Translator: Bole \n" +"Language-Team: none\n" +"Language: hr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Generator: Weblate 4.3.2\n" + +#. module: hr_holidays_natural_period +#: model:ir.model.fields.selection,name:hr_holidays_natural_period.selection__hr_leave_type__request_unit__natural_day +msgid "Natural day" +msgstr "Cijeli dan" + +#. module: hr_holidays_natural_period +#: model:ir.model,name:hr_holidays_natural_period.model_resource_calendar +msgid "Resource Working Time" +msgstr "Radno vrijeme resursa" + +#. module: hr_holidays_natural_period +#: model:ir.model.fields,field_description:hr_holidays_natural_period.field_hr_leave_type__request_unit +msgid "Take Time Off in" +msgstr "Uzmi slobodno kao" + +#. module: hr_holidays_natural_period +#: model:hr.leave.type,name:hr_holidays_natural_period.hr_leave_type_natural_day_test +msgid "Test Time Off (natural day)" +msgstr "" + +#. module: hr_holidays_natural_period +#: model:ir.model,name:hr_holidays_natural_period.model_hr_leave +msgid "Time Off" +msgstr "Slobodno vrijeme" + +#. module: hr_holidays_natural_period +#: model:ir.model,name:hr_holidays_natural_period.model_hr_leave_type +msgid "Time Off Type" +msgstr "Tip slobodnog vremena" + +#~ msgid "Display Name" +#~ msgstr "Prikazani naziv" + +#~ msgid "ID" +#~ msgstr "ID" + +#~ msgid "Last Modified on" +#~ msgstr "Zadnje modificirano" diff --git a/hr_holidays_natural_period/i18n/hr_holidays_natural_period.pot b/hr_holidays_natural_period/i18n/hr_holidays_natural_period.pot new file mode 100644 index 00000000..9b86f43b --- /dev/null +++ b/hr_holidays_natural_period/i18n/hr_holidays_natural_period.pot @@ -0,0 +1,44 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_holidays_natural_period +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \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: hr_holidays_natural_period +#: model:ir.model.fields.selection,name:hr_holidays_natural_period.selection__hr_leave_type__request_unit__natural_day +msgid "Natural day" +msgstr "" + +#. module: hr_holidays_natural_period +#: model:ir.model,name:hr_holidays_natural_period.model_resource_calendar +msgid "Resource Working Time" +msgstr "" + +#. module: hr_holidays_natural_period +#: model:ir.model.fields,field_description:hr_holidays_natural_period.field_hr_leave_type__request_unit +msgid "Take Time Off in" +msgstr "" + +#. module: hr_holidays_natural_period +#: model:hr.leave.type,name:hr_holidays_natural_period.hr_leave_type_natural_day_test +msgid "Test Time Off (natural day)" +msgstr "" + +#. module: hr_holidays_natural_period +#: model:ir.model,name:hr_holidays_natural_period.model_hr_leave +msgid "Time Off" +msgstr "" + +#. module: hr_holidays_natural_period +#: model:ir.model,name:hr_holidays_natural_period.model_hr_leave_type +msgid "Time Off Type" +msgstr "" diff --git a/hr_holidays_natural_period/i18n/it.po b/hr_holidays_natural_period/i18n/it.po new file mode 100644 index 00000000..dc16d884 --- /dev/null +++ b/hr_holidays_natural_period/i18n/it.po @@ -0,0 +1,47 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * hr_holidays_natural_period +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-07-10 09:10+0000\n" +"Last-Translator: mymage \n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: hr_holidays_natural_period +#: model:ir.model.fields.selection,name:hr_holidays_natural_period.selection__hr_leave_type__request_unit__natural_day +msgid "Natural day" +msgstr "Giorno solare" + +#. module: hr_holidays_natural_period +#: model:ir.model,name:hr_holidays_natural_period.model_resource_calendar +msgid "Resource Working Time" +msgstr "Orario lavoro risorsa" + +#. module: hr_holidays_natural_period +#: model:ir.model.fields,field_description:hr_holidays_natural_period.field_hr_leave_type__request_unit +msgid "Take Time Off in" +msgstr "Prendi ferie in" + +#. module: hr_holidays_natural_period +#: model:hr.leave.type,name:hr_holidays_natural_period.hr_leave_type_natural_day_test +msgid "Test Time Off (natural day)" +msgstr "Testa ferie (giorno solare)" + +#. module: hr_holidays_natural_period +#: model:ir.model,name:hr_holidays_natural_period.model_hr_leave +msgid "Time Off" +msgstr "Ferie" + +#. module: hr_holidays_natural_period +#: model:ir.model,name:hr_holidays_natural_period.model_hr_leave_type +msgid "Time Off Type" +msgstr "Tipo di ferie" diff --git a/hr_holidays_natural_period/models/__init__.py b/hr_holidays_natural_period/models/__init__.py new file mode 100644 index 00000000..3309c690 --- /dev/null +++ b/hr_holidays_natural_period/models/__init__.py @@ -0,0 +1,5 @@ +from . import hr_leave_type +from . import hr_leave +from . import resource_calendar +from . import hr_leave_allocation +from . import hr_employee diff --git a/hr_holidays_natural_period/models/hr_employee.py b/hr_holidays_natural_period/models/hr_employee.py new file mode 100644 index 00000000..12551b89 --- /dev/null +++ b/hr_holidays_natural_period/models/hr_employee.py @@ -0,0 +1,22 @@ +# Copyright 2024 APSL-Nagarro - Antoni Marroig Campomar +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import models + + +class HrEmployee(models.Model): + _inherit = "hr.employee" + + def _get_consumed_leaves(self, leave_types, target_date=False, ignore_future=False): + """We need to set request_unit as 'day' to avoid the calculations being done + as hours. + """ + old_request_unit_data = {} + for item in leave_types.filtered(lambda x: x.request_unit == "natural_day"): + old_request_unit_data[item.id] = item.request_unit + item.sudo().request_unit = "day" + res = super()._get_consumed_leaves(leave_types, target_date, ignore_future) + for item in leave_types: + if item.id in old_request_unit_data: + item.sudo().request_unit = old_request_unit_data[item.id] + return res diff --git a/hr_holidays_natural_period/models/hr_leave.py b/hr_holidays_natural_period/models/hr_leave.py new file mode 100644 index 00000000..6d441abf --- /dev/null +++ b/hr_holidays_natural_period/models/hr_leave.py @@ -0,0 +1,25 @@ +# Copyright 2020-2024 Tecnativa - Víctor Martínez +# Copyright 2024 Tecnativa - Carlos Lopez +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import models + + +class HrLeave(models.Model): + _inherit = "hr.leave" + + def _get_duration(self, check_leave_type=True, resource_calendar=None): + # We need to set request_unit as 'day' + # to avoid the calculations being done as hours. + is_request_unit_natural_day = ( + self.holiday_status_id.request_unit == "natural_day" + ) + instance = self.with_context(natural_period=is_request_unit_natural_day) + if is_request_unit_natural_day: + self.holiday_status_id.sudo().request_unit = "day" + res = super(HrLeave, instance)._get_duration( + check_leave_type=check_leave_type, resource_calendar=resource_calendar + ) + if is_request_unit_natural_day: + self.holiday_status_id.sudo().request_unit = "natural_day" + return res diff --git a/hr_holidays_natural_period/models/hr_leave_allocation.py b/hr_holidays_natural_period/models/hr_leave_allocation.py new file mode 100644 index 00000000..11ace727 --- /dev/null +++ b/hr_holidays_natural_period/models/hr_leave_allocation.py @@ -0,0 +1,13 @@ +# Copyright 2024 APSL-Nagarro - Antoni Marroig Campomar +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + + +class HrLeaveAllocation(models.Model): + _inherit = "hr.leave.allocation" + + # Added option to this field because it is now computed (was related before). + type_request_unit = fields.Selection( + selection_add=[("natural_day", "Natural day")], + ) diff --git a/hr_holidays_natural_period/models/hr_leave_type.py b/hr_holidays_natural_period/models/hr_leave_type.py new file mode 100644 index 00000000..e6e77ed0 --- /dev/null +++ b/hr_holidays_natural_period/models/hr_leave_type.py @@ -0,0 +1,13 @@ +# Copyright 2020-2023 Tecnativa - Víctor Martínez +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + + +class HrLeaveType(models.Model): + _inherit = "hr.leave.type" + + request_unit = fields.Selection( + selection_add=[("natural_day", "Natural day")], + ondelete={"natural_day": "set default"}, + ) diff --git a/hr_holidays_natural_period/models/resource_calendar.py b/hr_holidays_natural_period/models/resource_calendar.py new file mode 100644 index 00000000..42d68c13 --- /dev/null +++ b/hr_holidays_natural_period/models/resource_calendar.py @@ -0,0 +1,93 @@ +# Copyright 2020-2021 Tecnativa - Víctor Martínez +# Copyright 2024 Tecnativa - Carlos Lopez +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from collections import defaultdict +from datetime import datetime, time + +from dateutil import rrule +from pytz import timezone + +from odoo import models +from odoo.tools.float_utils import float_round + +from odoo.addons.resource.models.utils import Intervals + + +class ResourceCalendar(models.Model): + _inherit = "resource.calendar" + + def _get_attendance_intervals_days_data(self, attendance_intervals): + # replace function to avoid division by zero + # it occurs when the calendar has no attendance intervals + # i.e no working days(weekends) + # meta is a recordset of resource.calendar.attendance + # but in the function _natural_period_intervals_batch + # we are passing an empty recordset + if not self.env.context.get("natural_period"): + return super()._get_attendance_intervals_days_data(attendance_intervals) + day_hours = defaultdict(float) + day_days = defaultdict(float) + for start, stop, meta in attendance_intervals: + interval_hours = (stop - start).total_seconds() / 3600 + if meta: + interval_days = ( + sum(meta.mapped("duration_days")) + * interval_hours + / sum(meta.mapped("duration_hours")) + ) + else: + interval_days = interval_hours / 24 # hours on a day + day_hours[start.date()] += interval_hours + day_days[start.date()] += interval_days + + return { + # Round the number of days to the closest 16th of a day. + "days": float_round( + sum(day_days[day] for day in day_days), precision_rounding=0.001 + ), + "hours": sum(day_hours.values()), + } + + def _exist_interval_in_date(self, intervals, date): + for interval in intervals: + if interval[0].date() == date: + return True + return False + + def _natural_period_intervals_batch(self, start_dt, end_dt, intervals, resources): + for resource in resources or []: + interval_resource = intervals[resource.id] + tz = timezone(resource.tz) + attendances = [] + if len(interval_resource._items) > 0: + attendances = interval_resource._items + for day in rrule.rrule(rrule.DAILY, dtstart=start_dt, until=end_dt): + exist_interval = self._exist_interval_in_date(attendances, day.date()) + if not exist_interval: + attendances.append( + ( + datetime.combine(day.date(), time.min).replace(tzinfo=tz), + datetime.combine(day.date(), time.max).replace(tzinfo=tz), + self.env["resource.calendar.attendance"], + ) + ) + intervals[resource.id] = Intervals(attendances) + return intervals + + def _attendance_intervals_batch( + self, start_dt, end_dt, resources=None, domain=None, tz=None, lunch=False + ): + res = super()._attendance_intervals_batch( + start_dt=start_dt, + end_dt=end_dt, + resources=resources, + domain=domain, + tz=tz, + lunch=lunch, + ) + if self.env.context.get("natural_period"): + return self._natural_period_intervals_batch( + start_dt, end_dt, res, resources + ) + return res diff --git a/hr_holidays_natural_period/pyproject.toml b/hr_holidays_natural_period/pyproject.toml new file mode 100644 index 00000000..4231d0cc --- /dev/null +++ b/hr_holidays_natural_period/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/hr_holidays_natural_period/readme/CONTRIBUTORS.md b/hr_holidays_natural_period/readme/CONTRIBUTORS.md new file mode 100644 index 00000000..20fc22ff --- /dev/null +++ b/hr_holidays_natural_period/readme/CONTRIBUTORS.md @@ -0,0 +1,9 @@ +- Tecnativa \<\> + + > - Víctor Martínez + > - Pedro Baeza + > - Carlos López + +- APSL-Nagarro \<\> + + > - Antoni Marroig \<\> diff --git a/hr_holidays_natural_period/readme/DESCRIPTION.md b/hr_holidays_natural_period/readme/DESCRIPTION.md new file mode 100644 index 00000000..cb89dc01 --- /dev/null +++ b/hr_holidays_natural_period/readme/DESCRIPTION.md @@ -0,0 +1,2 @@ +This module was written to define natural day option in request unit on +holidays type. diff --git a/hr_holidays_natural_period/readme/USAGE.md b/hr_holidays_natural_period/readme/USAGE.md new file mode 100644 index 00000000..298cc0da --- /dev/null +++ b/hr_holidays_natural_period/readme/USAGE.md @@ -0,0 +1,10 @@ +For using natural period on leaves: + +1. Go to *Leaves \> Dashboard*. +2. Select dragging on the calendar the days you want to be on leave, or + go to the form view for selecting start and end dates. +3. Select the proper "Leave Type" that has "Natural day" selected in + "Request unit". +4. If no leave type is yet specified, then default configuration is to + exclude public holidays. +5. The number of days will be computed without employee calendar used. diff --git a/hr_holidays_natural_period/static/description/icon.png b/hr_holidays_natural_period/static/description/icon.png new file mode 100644 index 00000000..3a0328b5 Binary files /dev/null and b/hr_holidays_natural_period/static/description/icon.png differ diff --git a/hr_holidays_natural_period/static/description/index.html b/hr_holidays_natural_period/static/description/index.html new file mode 100644 index 00000000..61d0ed7d --- /dev/null +++ b/hr_holidays_natural_period/static/description/index.html @@ -0,0 +1,456 @@ + + + + + +Holidays natural period + + + +
+

Holidays natural period

+ + +

Beta License: AGPL-3 OCA/hr-holidays Translate me on Weblate Try me on Runboat

+

This module was written to define natural day option in request unit on +holidays type.

+

Table of contents

+ +
+

Usage

+

For using natural period on leaves:

+
    +
  1. Go to Leaves > Dashboard.
  2. +
  3. Select dragging on the calendar the days you want to be on leave, or +go to the form view for selecting start and end dates.
  4. +
  5. Select the proper “Leave Type” that has “Natural day” selected in +“Request unit”.
  6. +
  7. If no leave type is yet specified, then default configuration is to +exclude public holidays.
  8. +
  9. The number of days will be computed without employee calendar used.
  10. +
+
+
+

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 +feedback.

+

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

+
+
+

Credits

+
+

Authors

+
    +
  • Tecnativa
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+ +Odoo Community Association + +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

Current maintainer:

+

victoralmau

+

This module is part of the OCA/hr-holidays project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/hr_holidays_natural_period/tests/__init__.py b/hr_holidays_natural_period/tests/__init__.py new file mode 100644 index 00000000..4752aaf0 --- /dev/null +++ b/hr_holidays_natural_period/tests/__init__.py @@ -0,0 +1 @@ +from . import test_hr_leave diff --git a/hr_holidays_natural_period/tests/test_hr_leave.py b/hr_holidays_natural_period/tests/test_hr_leave.py new file mode 100644 index 00000000..e86ced64 --- /dev/null +++ b/hr_holidays_natural_period/tests/test_hr_leave.py @@ -0,0 +1,107 @@ +# Copyright 2020-2023 Tecnativa - Víctor Martínez +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from freezegun import freeze_time + +from odoo import fields +from odoo.tests import Form, new_test_user +from odoo.tests.common import users + +from odoo.addons.base.tests.common import BaseCommon + + +@freeze_time("2023-01-01", tick=True) +class TestHrLeave(BaseCommon): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.leave_type = cls.env.ref( + "hr_holidays_natural_period.hr_leave_type_natural_day_test" + ) + cls.leave_type_day = cls.env.ref("hr_holidays.holiday_status_cl") + cls.leave_type_day.employee_requests = "yes" + calendar = cls.env.ref("resource.resource_calendar_std") + calendar = calendar.copy({"name": "Test calendar"}) + calendar.switch_calendar_type() + calendar.attendance_ids.filtered( + lambda x: x.week_type == "0" + and not x.display_type + and x.day_period == "afternoon" + ).unlink() + calendar.attendance_ids.filtered( + lambda x: x.week_type == "1" + and not x.display_type + and x.day_period == "morning" + ).unlink() + partner = cls.env["res.partner"].create( + { + "name": "Test employee", + "type": "other", + "country_id": cls.env.ref("base.es").id, + } + ) + cls.user = new_test_user(cls.env, login="test-user") + cls.employee = cls.env["hr.employee"].create( + { + "name": "Test employee", + "address_id": partner.id, + "resource_calendar_id": calendar.id, + "user_id": cls.user.id, + } + ) + + def _create_leave_allocation(self, leave_type, days): + leave_allocation_form = Form( + self.env["hr.leave.allocation"].with_context( + default_date_from="2023-01-01", + default_date_to="%s-12-31" % (fields.Date.today().year), + ) + ) + + leave_allocation_form.holiday_status_id = leave_type + leave_allocation_form.number_of_days_display = days + return leave_allocation_form.save() + + def _create_hr_leave(self, leave_type, date_from, date_to): + leave_form = Form(self.env["hr.leave"]) + leave_form.holiday_status_id = leave_type + leave_form.request_date_from = date_from + leave_form.request_date_to = date_to + return leave_form.save() + + @users("test-user") + def test_hr_leave_natural_day(self): + leave_allocation = self._create_leave_allocation(self.leave_type, 5) + leave_allocation.sudo().action_validate() + res_leave_type = ( + self.env["hr.leave.type"] + .with_company(self.env.company) + .get_allocation_data_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["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) + + @users("test-user") + def test_hr_leave_day(self): + leave_allocation = self._create_leave_allocation(self.leave_type_day, 5) + leave_allocation.sudo().action_validate() + res_leave_type = ( + self.env["hr.leave.type"] + .with_company(self.env.company) + .get_allocation_data_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["leaves_taken"], 0) + self.assertEqual(res_leave_type["virtual_leaves_taken"], 0) + self.assertEqual(res_leave_type["request_unit"], "day") + leave = self._create_hr_leave(self.leave_type_day, "2023-01-08", "2023-01-15") + self.assertEqual(leave.number_of_days, 5) + self.assertEqual(leave.number_of_days_display, 5)