Skip to content

Commit

Permalink
[IMP] hr_attendance_missing_days: Rework to use dates instead of date…
Browse files Browse the repository at this point in the history
…times
  • Loading branch information
fkantelberg committed Aug 15, 2023
1 parent b417368 commit 8fb2b1e
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 36 deletions.
2 changes: 1 addition & 1 deletion hr_attendance_missing_days/data/ir_cron.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<field name="active" eval="False" />
<field name="state">code</field>
<field name="code">
model.create_missing_attendances(datetime.datetime.now() - datetime.timedelta(days=31))
model.create_missing_attendances(datetime.date.today() - datetime.timedelta(days=31))
</field>
</record>
</odoo>
55 changes: 30 additions & 25 deletions hr_attendance_missing_days/models/hr_employee.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

import logging
from datetime import datetime, time
from datetime import date, datetime, time, timedelta

import pytz

Expand All @@ -20,6 +20,15 @@ def ensure_tz(dt, tz=None):
class Employee(models.Model):
_inherit = "hr.employee"

def _prepare_missing_attendance_values(self, dt, reasons):
self.ensure_one()
return {
"employee_id": self.id,
"check_in": dt,
"check_out": dt,
"attendance_reason_ids": [(6, 0, reasons.ids)],
}

def create_missing_attendances(self, date_from=None, date_to=None):
for emp in self.search([]):
emp._create_missing_attendances(date_from, date_to)
Expand All @@ -32,36 +41,37 @@ def _create_missing_attendances(self, date_from=None, date_to=None):
return

if not date_from:
date_from = datetime.combine(
self.env.company.sudo().overtime_start_date, time.min
)
date_from = self.env.company.sudo().overtime_start_date

if not date_to:
date_to = datetime.now()
date_to = date.today()

# Determine the start and end of the day and convert to UTC
dt_from = datetime.combine(date_from, time.min)
dt_to = datetime.combine(date_to, time.max)

date_from, date_to = map(ensure_tz, (date_from, date_to))
tz = pytz.timezone(self.tz or "UTC")
dt_from, dt_to = map(tz.localize, (dt_from, dt_to))
dt_from, dt_to = ensure_tz(dt_from, pytz.utc), ensure_tz(dt_to, pytz.utc)

intervals = self.resource_calendar_id._work_intervals_batch(date_from, date_to)
# Skip the active day
if dt_to.replace(tzinfo=None) > datetime.now():
dt_to -= timedelta(days=1)

if dt_from > dt_to:
return

intervals = self.resource_calendar_id._work_intervals_batch(dt_from, dt_to)
work_dates = {}
for start, _stop, _attendance in sorted(intervals[False]):
start_date = start.date()

# Check that the end of the day for the employee is before date_to to
# avoid a run mid working day
tz = pytz.timezone(self.tz or "UTC")
end_of_day = datetime.combine(start_date, time.max)
end_of_day = tz.localize(end_of_day).astimezone(pytz.utc)
if end_of_day >= date_to:
continue

if start_date not in work_dates:
work_dates[start_date] = ensure_tz(start, pytz.utc).replace(tzinfo=None)

domain = [
("check_in", ">=", date_from.replace(tzinfo=None)),
("check_in", "<=", date_to.replace(tzinfo=None)),
("check_in", ">=", dt_from.replace(tzinfo=None)),
("check_in", "<=", dt_to.replace(tzinfo=None)),
]
tz = pytz.timezone(self.tz)
attendances = {
ensure_tz(attendance.check_in, tz).date()
for attendance in self.attendance_ids.filtered_domain(domain)
Expand All @@ -70,12 +80,7 @@ def _create_missing_attendances(self, date_from=None, date_to=None):
vals = []
for missing in set(work_dates) - attendances:
vals.append(
{
"employee_id": self.id,
"check_in": work_dates[missing],
"check_out": work_dates[missing],
"attendance_reason_ids": [(4, reason.id)],
}
self._prepare_missing_attendance_values(work_dates[missing], reason)
)

self.env["hr.attendance"].create(vals)
15 changes: 5 additions & 10 deletions hr_attendance_missing_days/tests/test_attendance.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,7 @@ def test_attendance_creation(self):
)

# Cover a huge time span
employee._create_missing_attendances(
datetime(2023, 6, 1, 0, 0), datetime(2023, 8, 1, 0, 0)
)
employee._create_missing_attendances(date(2023, 6, 1), date(2023, 8, 1))

domain = [
("employee_id", "=", employee.id),
Expand All @@ -96,20 +94,17 @@ def test_attendance_creation(self):
def test_attendance_creation_during_day(self):
self.env.company.attendance_missing_days_reason = self.reason

start = datetime(2023, 7, 3, 12, 30)
now = datetime.now()
self.env["hr.attendance"].create(
{
"employee_id": self.employee.id,
"check_in": start,
"check_out": start + timedelta(minutes=30),
"check_in": now - timedelta(minutes=30),
"check_out": now + timedelta(minutes=30),
}
)

attendances_before = self.employee.attendance_ids
self.employee._create_missing_attendances(
start - timedelta(hours=12),
start - timedelta(minutes=30),
)
self.employee._create_missing_attendances(now, now)
attendances_after = self.employee.attendance_ids

attendances_new = attendances_after - attendances_before
Expand Down

0 comments on commit 8fb2b1e

Please sign in to comment.