[FIX] hr_work_entry_contract: Correctly compute work entries for edge timezones
closes odoo/odoo#124222 Related: odoo/upgrade#4699 Related: odoo/enterprise#41253 Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
This commit is contained in:
@@ -124,7 +124,6 @@ class HrContract(models.Model):
|
||||
def _get_contract_work_entries_values(self, date_start, date_stop):
|
||||
start_dt = pytz.utc.localize(date_start) if not date_start.tzinfo else date_start
|
||||
end_dt = pytz.utc.localize(date_stop) if not date_stop.tzinfo else date_stop
|
||||
|
||||
contract_vals = []
|
||||
bypassing_work_entry_type_codes = self._get_bypassing_work_entry_type_codes()
|
||||
|
||||
@@ -253,7 +252,18 @@ class HrContract(models.Model):
|
||||
Generate a work_entries list between date_start and date_stop for one contract.
|
||||
:return: list of dictionnary.
|
||||
"""
|
||||
contract_vals = self._get_contract_work_entries_values(date_start, date_stop)
|
||||
if isinstance(date_start, datetime):
|
||||
contract_vals = self._get_contract_work_entries_values(date_start, date_stop)
|
||||
else:
|
||||
contract_vals = []
|
||||
contracts_by_tz = defaultdict(lambda: self.env['hr.contract'])
|
||||
for contract in self:
|
||||
contracts_by_tz[contract.resource_calendar_id.tz] += contract
|
||||
for contract_tz, contracts in contracts_by_tz.items():
|
||||
tz = pytz.timezone(contract_tz) if contract_tz else pytz.utc
|
||||
contract_vals += contracts._get_contract_work_entries_values(
|
||||
tz.localize(date_start),
|
||||
tz.localize(date_stop))
|
||||
|
||||
# {contract_id: ([dates_start], [dates_stop])}
|
||||
mapped_contract_dates = defaultdict(lambda: ([], []))
|
||||
|
||||
@@ -114,7 +114,6 @@ class TestWorkEntryLeave(TestWorkEntryHolidaysBase):
|
||||
def test_refuse_approved_leave(self):
|
||||
start = datetime(2019, 10, 10, 6, 0)
|
||||
end = datetime(2019, 10, 10, 18, 0)
|
||||
|
||||
# Setup contract generation state
|
||||
contract = self.richard_emp.contract_ids[:1]
|
||||
contract.state = 'open'
|
||||
|
||||
@@ -272,7 +272,6 @@ class ResourceCalendar(models.Model):
|
||||
def _attendance_intervals_batch(self, start_dt, end_dt, resources=None, domain=None, tz=None, lunch=False):
|
||||
assert start_dt.tzinfo and end_dt.tzinfo
|
||||
self.ensure_one()
|
||||
|
||||
if not resources:
|
||||
resources = self.env['resource.resource']
|
||||
resources_list = [resources]
|
||||
@@ -340,6 +339,7 @@ class ResourceCalendar(models.Model):
|
||||
else:
|
||||
base_result.append((day_from, day_to, attendance))
|
||||
|
||||
|
||||
# Copy the result localized once per necessary timezone
|
||||
# Strictly speaking comparing start_dt < time or start_dt.astimezone(tz) < time
|
||||
# should always yield the same result. however while working with dates it is easier
|
||||
|
||||
@@ -532,6 +532,26 @@ class TestCalendar(TestResourceCommon):
|
||||
calendar_dt = self.calendar_john._get_closest_work_time(dt, resource=self.john.resource_id)
|
||||
self.assertEqual(calendar_dt, start, "It should have found the attendance on the 3rd April")
|
||||
|
||||
def test_attendance_interval_edge_tz(self):
|
||||
# When genereting the attendance intervals in an edge timezone, the last interval shouldn't
|
||||
# be truncated if the timezone is correctly set
|
||||
self.env.user.tz = "America/Los_Angeles"
|
||||
self.calendar_jean.tz = "America/Los_Angeles"
|
||||
attendances = self.calendar_jean._attendance_intervals_batch(
|
||||
datetime.combine(date(2023, 1, 1), datetime.min.time(), tzinfo=timezone("UTC")),
|
||||
datetime.combine(date(2023, 1, 31), datetime.max.time(), tzinfo=timezone("UTC")))
|
||||
last_attendance = list(attendances[False])[-1]
|
||||
self.assertEqual(last_attendance[0].replace(tzinfo=None), datetime(2023, 1, 31, 8))
|
||||
self.assertEqual(last_attendance[1].replace(tzinfo=None), datetime(2023, 1, 31, 15, 59, 59, 999999))
|
||||
|
||||
attendances = self.calendar_jean._attendance_intervals_batch(
|
||||
datetime.combine(date(2023, 1, 1), datetime.min.time(), tzinfo=timezone("America/Los_Angeles")),
|
||||
datetime.combine(date(2023, 1, 31), datetime.max.time(), tzinfo=timezone("America/Los_Angeles")))
|
||||
last_attendance = list(attendances[False])[-1]
|
||||
self.assertEqual(last_attendance[0].replace(tzinfo=None), datetime(2023, 1, 31, 8))
|
||||
self.assertEqual(last_attendance[1].replace(tzinfo=None), datetime(2023, 1, 31, 16))
|
||||
|
||||
|
||||
class TestResMixin(TestResourceCommon):
|
||||
|
||||
def test_adjust_calendar(self):
|
||||
|
||||
Reference in New Issue
Block a user