16.0-planning_and_public_holidays #15

Merged
laetitiadacosta merged 4 commits from 16.0-planning_and_public_holidays into 16.0 2025-12-15 11:20:12 +00:00
2 changed files with 65 additions and 2 deletions
Showing only changes of commit 5b103056d6 - Show all commits

View File

@@ -1,7 +1,9 @@
import logging import logging
import pytz
from odoo import api, fields, models from odoo import api, fields, models
from datetime import timedelta from datetime import timedelta
from pytz import utc
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
@@ -169,8 +171,40 @@ class HrEmployeeStats(models.Model):
stat.is_public_holiday = False stat.is_public_holiday = False
continue continue
stat.dayofweek = int(stat.date.strftime("%u")) - 1 stat.dayofweek = int(stat.date.strftime("%u")) - 1
stat.is_public_holiday = bool(stat.sheet_id.employee_id._get_public_holidays(stat.date, stat.date - timedelta(days=1))) stat.is_public_holiday = stat._is_public_holiday_accordig_to_employe_tz()
def _convert_to_employee_tz(self, date):
"""Convert a UTC datetime to the employee's timezone datetime."""
self.ensure_one()
if not date:
return None
employee_tz = pytz.timezone(self.employee_id.tz or "UTC")
if date.tzinfo is None:
dt = pytz.utc.localize(date)
return dt.astimezone(employee_tz)
def _is_public_holiday_accordig_to_employe_tz(self):
self.ensure_one()
if not self.date or not self.employee_id:
return False
#get public holidays for the employee
public_holidays = self.employee_id._get_public_holidays(
self.date, self.date
)
if not public_holidays:
return False
ph = public_holidays[0]
mondot marked this conversation as resolved Outdated

if len(public_holidays) > 1:
raise UserError("un msg bien clair pour que le client nous contacte et qu'on corrige le soucis")

if len(public_holidays) > 1: raise UserError("un msg bien clair pour que le client nous contacte et qu'on corrige le soucis")

après vérification _get_public_holidays, on n'a effectivement pas censé avoir plusieurs jours fériés pour un meme calendrier, mais par sécurité j'ai ajouté

if len(public_holidays) > 1: raise UserError( _("Several holidays have been found ont he date '%s'. Please correct the anomaly before continuing.") % self.date )

après vérification _get_public_holidays, on n'a effectivement pas censé avoir plusieurs jours fériés pour un meme calendrier, mais par sécurité j'ai ajouté ` if len(public_holidays) > 1: raise UserError( _("Several holidays have been found ont he date '%s'. Please correct the anomaly before continuing.") % self.date ) `
# Convert public holiday to the employee timezone
ph_datetime_from_tz = self._convert_to_employee_tz(ph.date_from)
ph_datetime_to_tz = self._convert_to_employee_tz(ph.date_to)
# Convert datetime to date
ph_date_from = ph_datetime_from_tz.date()
ph_date_to = ph_datetime_to_tz.date()
# Check if the stat date falls within the public holiday range after conversion in employee tz
if ph_date_from <= self.date <= ph_date_to:
return True
else:
return False
def _get_gap_hours(self, total_hours, total_recovery_hours, total_leave_hours, total_planned_hours): def _get_gap_hours(self, total_hours, total_recovery_hours, total_leave_hours, total_planned_hours):
self.ensure_one() self.ensure_one()
balance = ( balance = (

View File

@@ -1,7 +1,8 @@
from odoo.tests.common import TransactionCase from odoo.tests.common import TransactionCase
from odoo.tests import tagged from odoo.tests import tagged
from datetime import date, timedelta from datetime import date, timedelta, datetime
from odoo.exceptions import UserError from odoo.exceptions import UserError
from odoo.fields import Date
@tagged("post_install", "-at_install") @tagged("post_install", "-at_install")
class TestHrEmployeeStatsRecovery(TransactionCase): class TestHrEmployeeStatsRecovery(TransactionCase):
@@ -19,6 +20,7 @@ class TestHrEmployeeStatsRecovery(TransactionCase):
self.employee = self.env['hr.employee'].create({ self.employee = self.env['hr.employee'].create({
'name': 'Camille', 'name': 'Camille',
'user_id': self.user.id, 'user_id': self.user.id,
'tz': 'Europe/Paris',
}) })
self.base_calendar = self.env['resource.calendar'].create({ self.base_calendar = self.env['resource.calendar'].create({
'name': 'Default Calendar', 'name': 'Default Calendar',
@@ -242,6 +244,33 @@ class TestHrEmployeeStatsRecovery(TransactionCase):
recovery_allocation = self.env["hr.leave.allocation"].search([("timesheet_sheet_id","=",timesheet_sheet_2.id)]) recovery_allocation = self.env["hr.leave.allocation"].search([("timesheet_sheet_id","=",timesheet_sheet_2.id)])
self.assertEqual(len(recovery_allocation), 1, "There should be one recovery") self.assertEqual(len(recovery_allocation), 1, "There should be one recovery")
def test_public_holiday(self):
# create a public holiday
self.env["resource.calendar.leaves"].create(
{
"name": "1 mai 2025",
"date_from": datetime(2025,4,30,22,0,0),
"date_to": datetime(2025,5,1,21,0,0),
}
)
#create 5 stats of 7h each including the public holiday on 1st may
stats = self._create_stats(Date.to_date("2025-04-28"), 5, 7)
for stat in stats:
stat._compute_dayofweek()
stat._compute_hours()
#create 1 timesheet sheet from monday to friday including the public holiday on 1st may
timesheet_sheet = self.env['hr_timesheet.sheet'].create({
'employee_id': self.employee.id,
mondot marked this conversation as resolved Outdated

Dans l'idéal il faudrait reproduire la situation où on ajoute le 1er mai de minuit à minuit et avec le jeu des timezones ça crée un resource.calendar.leaves de 22h à 22h.

Si trop compliqué, on ajoute seulement un commentaire

Dans l'idéal il faudrait reproduire la situation où on ajoute le 1er mai de minuit à minuit et avec le jeu des timezones ça crée un resource.calendar.leaves de 22h à 22h. Si trop compliqué, on ajoute seulement un commentaire

j'ai ajouté des commentaires

j'ai ajouté des commentaires
'date_start': "2025-04-28",
'date_end': "2025-05-04",
})
self.assertEqual(timesheet_sheet.timesheet_sheet_gap_hours, 7, "timesheet_sheet_gap_hours should be 7",)
self.assertEqual(timesheet_sheet.timesheet_sheet_recovery_hours, 8.75, "timesheet_sheet_recovery_hours should be 8,75",)
timesheet_sheet.action_generate_recovery_allocation()
recovery_allocation = self.env["hr.leave.allocation"].search([("timesheet_sheet_id","=",timesheet_sheet.id)])
self.assertEqual(len(recovery_allocation), 1, "Il doit y avoir une allocation de récupération générée")
self.assertEqual(recovery_allocation.number_of_days,1.25, "The recovery allocation should be 1,25 days")