[FIX]hr_employee_stats_sheet:fix identification of public holidays according to employee TZ
This commit is contained in:
@@ -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]
|
||||||
|
# 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 = (
|
||||||
|
|||||||
@@ -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,
|
||||||
|
'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")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user