Files
enterprise-addons/l10n_be_hr_payroll/models/hr_leave.py
T

145 lines
6.9 KiB
Python

from datetime import timezone
from dateutil.relativedelta import relativedelta
from odoo import api, fields, models, _
from odoo.exceptions import UserError
class HrLeave(models.Model):
_inherit = 'hr.leave'
l10n_be_sickness_relapse = fields.Boolean(default=True, string="Sickness Relapse")
l10n_be_sickness_can_relapse = fields.Boolean(compute="_compute_can_relapse")
@api.depends("date_from", "validation_type", "employee_id", "holiday_status_id.work_entry_type_id.code")
def _compute_can_relapse(self):
l10n_be_leaves = self.filtered(
lambda leave:
leave.company_id.country_code == "BE"
and leave.validation_type == "hr"
and leave.employee_id
and leave.date_from
)
sick_work_entry_type = self.env.ref("hr_work_entry.work_entry_type_sick_leave")
partial_sick_work_entry_type = self.env.ref("hr_work_entry.l10n_be_work_entry_type_part_sick")
long_sick_work_entry_type = self.env.ref("hr_work_entry.l10n_be_work_entry_type_long_sick")
sick_work_entry_types = (
sick_work_entry_type
+ partial_sick_work_entry_type
+ long_sick_work_entry_type
)
if l10n_be_leaves:
recent_leaves = dict(
self
.env["hr.leave"]
._read_group(
domain=[
("employee_id.id", "in", l10n_be_leaves.employee_id.ids),
("date_to", "<=", max(l10n_be_leaves.mapped("date_from"))),
("date_to", ">=", min(l10n_be_leaves.mapped(
lambda l: l.date_from + relativedelta(days=-56)
if l.date_from.year >= 2026
else l.date_from + relativedelta(days=-14)
))),
("holiday_status_id.work_entry_type_id", "in", sick_work_entry_types.ids),
("state", "=", "validate"),
],
groupby=["employee_id"],
aggregates=["request_date_to:max"],
)
)
for employee, leaves in l10n_be_leaves.grouped('employee_id').items():
for leave in leaves:
leave.l10n_be_sickness_can_relapse = bool(recent_leaves.get(employee))
for leave in (self - l10n_be_leaves):
leave.l10n_be_sickness_can_relapse = False
def _action_validate(self, check_state=True):
res = super()._action_validate(check_state=check_state)
activity_type_id = self.env.ref('mail.mail_activity_data_todo').id
res_model_id = self.env.ref('hr_holidays.model_hr_leave').id
for leave in self:
leave._check_consecutive_leaves()
if leave.employee_id.company_id.country_id.code == "BE" and \
leave.sudo().holiday_status_id.work_entry_type_id.code in self._get_drs_work_entry_type_codes():
drs_link = "https://www.socialsecurity.be/site_fr/employer/applics/drs/index.htm"
drs_link = '<a href="%s" target="_blank">%s</a>' % (drs_link, drs_link)
user_ids = leave.holiday_status_id.responsible_ids.ids
note = _('%(employee)s is in %(holiday_status)s. Fill in the appropriate eDRS here: %(link)s',
employee=leave.employee_id.name,
holiday_status=leave.holiday_status_id.name,
link=drs_link)
activity_vals = []
for user_id in user_ids:
activity_vals.append({
'activity_type_id': activity_type_id,
'automated': True,
'note': note,
'user_id': user_id,
'res_id': leave.id,
'res_model_id': res_model_id,
})
# TDE TODO: batch schedule with record-based note
self.env['mail.activity'].create(activity_vals)
return res
def _get_drs_work_entry_type_codes(self):
drs_work_entry_types = [
'LEAVE290', # Breast Feeding
'LEAVE280', # Long Term Sick
'LEAVE210', # Maternity
'LEAVE230', # Paternity Time Off (Legal)
'YOUNG01', # Youth Time Off
'LEAVE115', # Work Accident
]
return drs_work_entry_types
def _check_work_interval_between_dates(self, date_from, date_to, employee):
'''
Check if there is a work interval between two dates for an employee
Returns true if there is a period where the employee worked
or had a leave borne by the employee (e.g. not a public holiday)
between date_from and date_to
'''
calendar = employee._get_calendars()[employee.id]
dt_from = date_from.replace(tzinfo=timezone.utc)
dt_to = date_to.replace(tzinfo=timezone.utc)
attendance_intervals = calendar._attendance_intervals_batch(dt_from, dt_to, employee.resource_id)
leave_intervals = calendar._leave_intervals_batch(dt_from, dt_to, employee.resource_id)
employee_leave_intervals = leave_intervals[employee.resource_id.id]
# remove holidays taken by the user from employee_leave_intervals
employee_leave_intervals -= [
(start, end, leave)
for start, end, leave in employee_leave_intervals
if leave.holiday_id
]
attendance_intervals = attendance_intervals[employee.resource_id.id] - employee_leave_intervals
return bool(attendance_intervals)
def _check_consecutive_leaves(self):
self.ensure_one()
if not self.holiday_status_id.l10n_be_no_consecutive_leaves_allowed:
return
employee = self.employee_id
last_leave_taken = self.env['hr.leave'].search([
('employee_id', '=', employee.id),
('date_to', '<', self.date_from),
('holiday_status_id', '=', self.holiday_status_id.id),
('state', '=', 'validate'),
], order='date_to desc', limit=1)
next_leave_taken = self.env['hr.leave'].search([
('employee_id', '=', employee.id),
('date_from', '>', self.date_to),
('holiday_status_id', '=', self.holiday_status_id.id),
('state', '=', 'validate'),
], order='date_from asc', limit=1)
if last_leave_taken:
if not self._check_work_interval_between_dates(last_leave_taken.date_to, self.date_from, employee):
raise UserError(_("You can't take two consecutive leaves of the same type."))
if next_leave_taken:
if not self._check_work_interval_between_dates(self.date_to, next_leave_taken.date_from, employee):
raise UserError(_("You can't take two consecutive leaves of the same type."))