Skip to content

Commit

Permalink
[ADD] hr_attendance_sheet_compensatory - Refactor of hr_attendance_va…
Browse files Browse the repository at this point in the history
…lidation to make it works with hr_attendance_sheet
  • Loading branch information
FrancoMaxime committed Aug 30, 2023
1 parent 097b5d4 commit 1e3e132
Show file tree
Hide file tree
Showing 41 changed files with 2,561 additions and 438 deletions.
2 changes: 2 additions & 0 deletions hr_attendance_sheet/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@
"data": [
"security/ir.model.access.csv",
"security/security_groups.xml",
"security/hr_attendance_sheet_config_acl.xml",
"data/cron.xml",
"data/mail_data.xml",
"report/hr_attendance_sheet_report.xml",
"views/hr_attendance_sheet.xml",
"views/hr_attendance_sheet_config.xml",
"views/hr_attendance_view.xml",
"views/hr_department.xml",
"views/hr_employee.xml",
Expand Down
2 changes: 2 additions & 0 deletions hr_attendance_sheet/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
# Copyright 2020 Pavlov Media
# Copyright 2023 ACSONE SA/NV
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html

from . import hr_attendance
from . import hr_attendance_sheet
from . import hr_attendance_sheet_config
from . import hr_department
from . import hr_employee
from . import res_company
Expand Down
61 changes: 43 additions & 18 deletions hr_attendance_sheet/models/hr_attendance.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,13 @@ class HrAttendance(models.Model):
auto_lunch = fields.Boolean(
string="Auto Lunch Applied",
help="If Auto Lunch is enabled and applied on this attendance.",
compute="_compute_duration",
)
company_id = fields.Many2one(
"res.company", string="Company", related="attendance_sheet_id.company_id"
)
auto_lunch_enabled = fields.Boolean(
string="Auto Lunch Enabled", related="company_id.auto_lunch"
string="Auto Lunch Enabled", related="attendance_sheet_config_id.auto_lunch"
)
override_auto_lunch = fields.Boolean(
string="Override Auto Lunch",
Expand All @@ -49,6 +50,31 @@ class HrAttendance(models.Model):
is set on the department.""",
related="department_id.attendance_admin",
)
attendance_sheet_config_id = fields.Many2one(
comodel_name="hr.attendance.sheet.config",
compute="_compute_attendance_sheet_config_id",
)

@api.depends(
"check_in",
"check_out",
"employee_id.company_id",
)
def _compute_attendance_sheet_config_id(self):
for attendance in self:
if attendance.attendance_sheet_id:
config = attendance.attendance_sheet_id.attendance_sheet_config_id
else:
config = self.env["hr.attendance.sheet.config"].search(
[
("start_date", "<=", attendance.check_in),
"|",
("end_date", ">=", attendance.check_out),
("end_date", "=", False),
("company_id", "=", attendance.employee_id.company_id.id),
]
)
attendance.attendance_sheet_config_id = config

# Get Methods
def _get_attendance_employee_tz(self, date=None):
Expand Down Expand Up @@ -88,16 +114,22 @@ def _compute_attendance_sheet_id(self):
domain = [("employee_id", "=", attendance.employee_id.id)]
if check_in:
domain += [
("date_start", "<=", check_in),
("date_end", ">=", check_in),
("start_date", "<=", check_in),
("end_date", ">=", check_in),
]
attendance_sheet_ids = sheet_obj.search(domain, limit=1)
if attendance_sheet_ids.state not in ("locked", "done"):
attendance.attendance_sheet_id = attendance_sheet_ids or False

@api.depends(
"check_in",
"check_out",
"employee_id.company_id",
)
def _compute_duration(self):
for rec in self:
rec.duration = 0.0
rec.auto_lunch = False
if rec.check_in and rec.check_out:
delta = rec.check_out - rec.check_in
duration = delta.total_seconds() / 3600
Expand All @@ -121,38 +153,31 @@ def _compute_duration(self):
# If auto lunch is enabled for the company and time between
# other attendances < lunch period, then adjust the duration
# calculation for the first attendance.
config = rec.attendance_sheet_config_id
if (
rec.company_id.auto_lunch
and total_duration > rec.company_id.auto_lunch_duration != 0.0
config.auto_lunch
and total_duration > config.auto_lunch_duration != 0.0
and not rec.override_auto_lunch
):
first_attendance = self.get_first_attendances(today_attendances)
if first_attendance and first_attendance.id == rec.id:
if len(today_attendances) > 1:
rec.write({"auto_lunch": False})
time_between_attendances = (

Check warning on line 165 in hr_attendance_sheet/models/hr_attendance.py

View check run for this annotation

Codecov / codecov/patch

hr_attendance_sheet/models/hr_attendance.py#L165

Added line #L165 was not covered by tests
self.compute_time_between_attendances(today_attendances)
)
total_time_between_attendances = sum(

Check warning on line 168 in hr_attendance_sheet/models/hr_attendance.py

View check run for this annotation

Codecov / codecov/patch

hr_attendance_sheet/models/hr_attendance.py#L168

Added line #L168 was not covered by tests
time_between_attendances
)
if (
total_time_between_attendances
< rec.company_id.auto_lunch_hours
):
if total_time_between_attendances < config.auto_lunch_hours:
rec.duration = self.compute_rest_of_autolunch(

Check warning on line 172 in hr_attendance_sheet/models/hr_attendance.py

View check run for this annotation

Codecov / codecov/patch

hr_attendance_sheet/models/hr_attendance.py#L172

Added line #L172 was not covered by tests
duration,
time_between_attendances,
rec.company_id.auto_lunch_hours,
config.auto_lunch_hours,
)
rec.write({"auto_lunch": True})
rec.auto_lunch = True

Check warning on line 177 in hr_attendance_sheet/models/hr_attendance.py

View check run for this annotation

Codecov / codecov/patch

hr_attendance_sheet/models/hr_attendance.py#L177

Added line #L177 was not covered by tests
else:
rec.duration = duration - rec.company_id.auto_lunch_hours
rec.write({"auto_lunch": True})
else:
rec.write({"auto_lunch": False})
elif rec.company_id.auto_lunch and rec.auto_lunch:
rec.write({"auto_lunch": False})
rec.duration = duration - config.auto_lunch_hours
rec.auto_lunch = True

def compute_time_between_attendances(self, attendances):
previous_attendance = attendances[0]
Expand Down
137 changes: 77 additions & 60 deletions hr_attendance_sheet/models/hr_attendance_sheet.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ class HrAttendanceSheet(models.Model):
user_id = fields.Many2one(
"res.users", related="employee_id.user_id", string="User", store=True
)
date_start = fields.Date(string="Date From", required=True, index=True)
date_end = fields.Date(string="Date To", required=True, index=True)
start_date = fields.Date(string="Date From", required=True, index=True)
end_date = fields.Date(string="Date To", required=True, index=True)
attendance_ids = fields.One2many(
"hr.attendance", "attendance_sheet_id", string="Attendances"
)
Expand Down Expand Up @@ -80,6 +80,23 @@ class HrAttendanceSheet(models.Model):
is set on the department.""",
related="department_id.attendance_admin",
)
attendance_sheet_config_id = fields.Many2one(
comodel_name="hr.attendance.sheet.config",
compute="_compute_attendance_sheet_config_id",
)

def _compute_attendance_sheet_config_id(self):
for sheet in self:
config = self.env["hr.attendance.sheet.config"].search(
[
("start_date", "<=", sheet.start_date),
"|",
("end_date", ">=", sheet.end_date),
("end_date", "=", False),
("company_id", "=", sheet.company_id.id),
]
)
sheet.attendance_sheet_config_id = config if config else None

def _valid_field_parameter(self, field, name):
# I can't even
Expand All @@ -90,6 +107,7 @@ def activity_update(self):
"""Activity processing that shows in chatter for approval activity."""
to_clean = self.env["hr.attendance.sheet"]
to_do = self.env["hr.attendance.sheet"]
external_id = "hr_attendance_sheet.mail_act_attendance_sheet_approval"
for sheet in self:
if sheet.state == "draft":
to_clean |= sheet
Expand All @@ -99,87 +117,86 @@ def activity_update(self):
):
if sheet.sudo().employee_id.parent_id.user_id.id:
sheet.activity_schedule(
"hr_attendance_sheet." "mail_act_attendance_sheet_approval",
external_id,
user_id=sheet.sudo().employee_id.parent_id.user_id.id,
)

elif sheet.state == "done":
to_do |= sheet
if to_clean:
to_clean.activity_unlink(
["hr_attendance_sheet.mail_act_attendance_sheet_approval"]
)
to_clean.activity_unlink([external_id])
if to_do:
to_do.activity_feedback(
["hr_attendance_sheet.mail_act_attendance_sheet_approval"]
)
to_do.activity_feedback([external_id])

# Scheduled Action Methods
def _create_sheet_id(self):
"""Method used by the scheduling action to auto create sheets."""
companies = (
self.env["res.company"].search([("use_attendance_sheets", "=", True)]).ids
)
employees = self.env["hr.employee"].search(
[
("use_attendance_sheets", "=", True),
("company_id", "in", companies),
("active", "=", True),
]
companies = self.env["res.company"].search(
[("use_attendance_sheets", "=", True)]
)
for employee in employees:
if not employee.company_id.date_start or not employee.company_id.date_end:
raise UserError(
_(
"Date From and Date To for Attendance \
must be set on the Company %s"
)
% employee.company_id.name
)
sheet = self.env["hr.attendance.sheet"].search(
sheets = self.env["hr.attendance.sheet"]
for company in companies:
employees = self.env["hr.employee"].search(
[
("employee_id", "=", employee.id),
("date_start", ">=", employee.company_id.date_start),
("date_end", "<=", employee.company_id.date_end),
("use_attendance_sheets", "=", True),
("company_id", "=", company.id),
("active", "=", True),
]
)
if not sheet:
self.env["hr.attendance.sheet"].create(
{
"employee_id": employee.id,
"date_start": employee.company_id.date_start,
"date_end": employee.company_id.date_end,
}
last_sheet = sheets.search(
[("company_id", "=", company.id)], limit=1, order="end_date DESC"
)
next_sheet_date = None
if last_sheet:
next_sheet_date = last_sheet.end_date + relativedelta(days=1)
config = self.env["hr.attendance.sheet.config"].search(

Check warning on line 152 in hr_attendance_sheet/models/hr_attendance_sheet.py

View check run for this annotation

Codecov / codecov/patch

hr_attendance_sheet/models/hr_attendance_sheet.py#L151-L152

Added lines #L151 - L152 were not covered by tests
[
("start_date", "<=", next_sheet_date),
("company_id", "=", company.id),
]
)
self.check_pay_period_dates()

def check_pay_period_dates(self):
companies = self.env["res.company"].search(
[("use_attendance_sheets", "!=", False)]
)
for company_id in companies:
if company_id.date_end and datetime.today().date() > company_id.date_end:
company_id.date_start = company_id.date_end + relativedelta(days=1)
company_id.set_date_end(company_id.id)
else:
config = self.env["hr.attendance.sheet.config"].search(
[
("company_id", "=", company.id),
],
limit=1,
order="end_date DESC",
)
if not config:
continue
if not next_sheet_date:
next_sheet_date = config.start_date
if next_sheet_date <= fields.Date.today():
for employee in employees:
sheet = self.env["hr.attendance.sheet"].create(
{
"employee_id": employee.id,
"start_date": next_sheet_date,
"end_date": config.compute_end_date(next_sheet_date),
}
)
sheets += sheet
return sheets

# Compute Methods
@api.depends("employee_id", "date_start", "date_end")
@api.depends("employee_id", "start_date", "end_date")
def _compute_name(self):
for sheet in self:
sheet.name = False
if sheet.employee_id and sheet.date_start and sheet.date_end:
if sheet.employee_id and sheet.start_date and sheet.end_date:
sheet.name = (
sheet.employee_id.name
+ " ("
+ str(
datetime.strptime(
str(sheet.date_start), DEFAULT_SERVER_DATE_FORMAT
str(sheet.start_date), DEFAULT_SERVER_DATE_FORMAT
).strftime("%m/%d/%y")
)
+ " - "
+ str(
datetime.strptime(
str(sheet.date_end), DEFAULT_SERVER_DATE_FORMAT
str(sheet.end_date), DEFAULT_SERVER_DATE_FORMAT
).strftime("%m/%d/%y")
)
+ ")"
Expand Down Expand Up @@ -274,13 +291,13 @@ def create(self, vals):
[
("employee_id", "=", res.employee_id.id),
("attendance_sheet_id", "=", False),
("check_in", ">=", res.date_start),
("check_in", "<=", res.date_end),
("check_in", ">=", res.start_date),
("check_in", "<=", res.end_date),
"|",
("check_out", "=", False),
"&",
("check_out", ">=", res.date_start),
("check_out", "<=", res.date_end),
("check_out", ">=", res.start_date),
("check_out", "<=", res.end_date),
]
)
attendances._compute_attendance_sheet_id()
Expand All @@ -292,8 +309,8 @@ def write(self, values):
"employee_id",
"name",
"attendance_ids",
"date_start",
"date_end",
"start_date",
"end_date",
]
for record in self:
if record.state == "locked" and any(
Expand Down Expand Up @@ -321,8 +338,8 @@ def action_attendance_sheet_confirm(self):
lambda att: att.check_in and not att.check_out
)
if not ids_not_checkout:
self.write({"state": "confirm"})
self.activity_update()
sheet.write({"state": "confirm"})
sheet.activity_update()
else:
raise UserError(
_(
Expand Down
Loading

0 comments on commit 1e3e132

Please sign in to comment.