mirror of
https://github.com/bringout/oca-ocb-hr.git
synced 2026-04-26 07:32:04 +02:00
19.0 vanilla
This commit is contained in:
parent
e1d89e11e3
commit
a1f02d8cc7
225 changed files with 2335 additions and 775 deletions
|
|
@ -139,22 +139,23 @@ class HrEmployee(models.Model):
|
|||
('employee_id', 'in', self.ids),
|
||||
('date_from', '<=', fields.Datetime.now()),
|
||||
('date_to', '>=', fields.Datetime.now()),
|
||||
('holiday_status_id.time_type', '=', 'leave'),
|
||||
('state', '=', 'validate'),
|
||||
])
|
||||
leave_data = {}
|
||||
for holiday in holidays:
|
||||
leave_data[holiday.employee_id.id] = {}
|
||||
leave_data.setdefault(holiday.employee_id.id, {})
|
||||
leave_data[holiday.employee_id.id]['leave_date_from'] = holiday.date_from.date()
|
||||
back_on = holiday.employee_id._get_first_working_interval(holiday.date_to)
|
||||
leave_data[holiday.employee_id.id]['leave_date_to'] = back_on.date() if back_on else None
|
||||
leave_data[holiday.employee_id.id]['current_leave_state'] = holiday.state
|
||||
leave_data[holiday.employee_id.id]['is_absent'] = leave_data[holiday.employee_id.id].get('is_absent') or holiday.holiday_status_id.time_type == 'leave'
|
||||
|
||||
for employee in self:
|
||||
employee.leave_date_from = leave_data.get(employee.id, {}).get('leave_date_from')
|
||||
employee.leave_date_to = leave_data.get(employee.id, {}).get('leave_date_to')
|
||||
employee.current_leave_state = leave_data.get(employee.id, {}).get('current_leave_state')
|
||||
employee.is_absent = leave_data.get(employee.id) and leave_data.get(employee.id).get('current_leave_state') == 'validate'
|
||||
employee_leave_data = leave_data.get(employee.id, {})
|
||||
employee.leave_date_from = employee_leave_data.get('leave_date_from')
|
||||
employee.leave_date_to = employee_leave_data.get('leave_date_to')
|
||||
employee.current_leave_state = employee_leave_data.get('current_leave_state')
|
||||
employee.is_absent = employee_leave_data and employee_leave_data.get('is_absent') and employee_leave_data.get('current_leave_state') == 'validate'
|
||||
|
||||
@api.depends('parent_id')
|
||||
def _compute_leave_manager(self):
|
||||
|
|
@ -411,6 +412,11 @@ class HrEmployee(models.Model):
|
|||
return self.env.user.employee_id
|
||||
|
||||
def _get_consumed_leaves(self, leave_types, target_date=False, ignore_future=False):
|
||||
""" This method won't call `_get_future_leaves_on` for the allocations contained by this variable (it will only use the current value of
|
||||
the `number_of_days` of the allocation, alias `number_of_hours_display`)
|
||||
|
||||
`precomputed_allocations`: context variable (recordset) which can be used to pass allocation that are considered to be already computed
|
||||
"""
|
||||
employees = self or self._get_contextual_employee()
|
||||
leaves_domain = [
|
||||
('holiday_status_id', 'in', leave_types.ids),
|
||||
|
|
@ -486,10 +492,16 @@ class HrEmployee(models.Model):
|
|||
'to_recheck_leaves': self.env['hr.leave']
|
||||
})
|
||||
)
|
||||
precomputed_allocations = self.env.context.get('precomputed_allocations')
|
||||
for allocation in allocations:
|
||||
allocation_data = allocations_leaves_consumed[allocation.employee_id][allocation.holiday_status_id][allocation]
|
||||
precomputed = False
|
||||
if precomputed_allocations:
|
||||
if allocation.id in precomputed_allocations.ids:
|
||||
allocation = precomputed_allocations.filtered(lambda alloc: alloc._origin.id == allocation.id)[0]
|
||||
precomputed = True
|
||||
future_leaves = 0
|
||||
if allocation.allocation_type == 'accrual':
|
||||
if allocation.allocation_type == 'accrual' and not precomputed:
|
||||
future_leaves = allocation._get_future_leaves_on(target_date)
|
||||
max_leaves = allocation.number_of_hours_display\
|
||||
if allocation.holiday_status_id.request_unit in ['hour']\
|
||||
|
|
@ -513,7 +525,11 @@ class HrEmployee(models.Model):
|
|||
allocations_with_date_to |= leave_allocation
|
||||
else:
|
||||
allocations_without_date_to |= leave_allocation
|
||||
sorted_leave_allocations = allocations_with_date_to.sorted(key='date_to') + allocations_without_date_to
|
||||
# Defines the order in which allocation will be used to take the leaves in priority
|
||||
sorted_leave_allocations = (
|
||||
allocations_with_date_to.sorted(key='date_to') +
|
||||
allocations_without_date_to.filtered(lambda alloc: alloc.allocation_type == 'accrual') +
|
||||
allocations_without_date_to.filtered(lambda alloc: alloc.allocation_type == 'regular'))
|
||||
|
||||
if leave_type.request_unit in ['day', 'half_day']:
|
||||
leave_duration_field = 'number_of_days'
|
||||
|
|
|
|||
|
|
@ -910,9 +910,11 @@ Versions:
|
|||
if any(leave.state == 'cancel' for leave in self):
|
||||
raise UserError(_('Only a manager can modify a canceled leave.'))
|
||||
|
||||
# Unlink existing resource.calendar.leaves for validated time off
|
||||
if 'state' in values and values['state'] != 'validate':
|
||||
validated_leaves = self.filtered(lambda l: l.state == 'validate')
|
||||
# If a leave changes state from validated or if the dates of a validated leave change
|
||||
# unlink the corresponding resource calendar leave
|
||||
date_fields = {'date_from', 'date_to', 'request_date_from', 'request_date_to'}
|
||||
validated_leaves = self.filtered(lambda l: l.state == 'validate')
|
||||
if validated_leaves and (('state' in values and values['state'] != 'validate') or date_fields.intersection(values)):
|
||||
validated_leaves._remove_resource_leave()
|
||||
|
||||
employee_id = values.get('employee_id', False)
|
||||
|
|
|
|||
|
|
@ -203,8 +203,8 @@ class HrLeaveAllocation(models.Model):
|
|||
|
||||
@api.depends('employee_id', 'holiday_status_id')
|
||||
def _compute_leaves(self):
|
||||
date_from = fields.Date.from_string(self.env.context['default_date_from']) if 'default_date_from' in self.env.context else fields.Date.today()
|
||||
employee_days_per_allocation = self.employee_id._get_consumed_leaves(self.holiday_status_id, date_from)[0]
|
||||
date_from = fields.Date.today()
|
||||
employee_days_per_allocation = self.employee_id._get_consumed_leaves(self.holiday_status_id, date_from, ignore_future=True)[0]
|
||||
for allocation in self:
|
||||
origin = allocation._origin
|
||||
virtual_leave = employee_days_per_allocation[origin.employee_id][origin.holiday_status_id][origin]
|
||||
|
|
@ -436,6 +436,16 @@ class HrLeaveAllocation(models.Model):
|
|||
The goal of this method is to retroactively apply accrual plan levels and progress from nextcall to date_to or today.
|
||||
If force_period is set, the accrual will run until date_to in a prorated way (used for end of year accrual actions).
|
||||
"""
|
||||
def _get_leaves_taken(allocation):
|
||||
precomputed_allocations = allocation
|
||||
if context_precomputed := self.env.context.get('precomputed_allocations'):
|
||||
precomputed_allocations |= context_precomputed
|
||||
# By setting `precomputed_allocations`, avoid infinite loop (otherwise _get_consumed_leaves -> _get_future_leaves_on -> _process_accrual_plans -> ...)
|
||||
employee_days_per_allocation = allocation.employee_id.with_context(precomputed_allocations=precomputed_allocations)._get_consumed_leaves(
|
||||
allocation.holiday_status_id, allocation.nextcall, ignore_future=True)[0]
|
||||
origin = allocation._origin
|
||||
leaves_taken = employee_days_per_allocation[origin.employee_id][origin.holiday_status_id][origin]['leaves_taken']
|
||||
return leaves_taken
|
||||
|
||||
date_to = date_to or fields.Date.today()
|
||||
already_accrued = {allocation.id: allocation.already_accrued or (allocation.number_of_days != 0 and allocation.accrual_plan_id.accrued_gain_time == 'start') for allocation in self}
|
||||
|
|
@ -452,10 +462,6 @@ class HrLeaveAllocation(models.Model):
|
|||
# even if the value doesn't change. This is the best performance atm.
|
||||
first_level = level_ids[0]
|
||||
first_level_start_date = allocation.date_from + get_timedelta(first_level.start_count, first_level.start_type)
|
||||
if allocation.holiday_status_id.request_unit in ["day", "half_day"]:
|
||||
leaves_taken = allocation.leaves_taken
|
||||
else:
|
||||
leaves_taken = allocation.leaves_taken / allocation.employee_id._get_hours_per_day(allocation.date_from)
|
||||
allocation.already_accrued = already_accrued[allocation.id]
|
||||
# first time the plan is run, initialize nextcall and take carryover / level transition into account
|
||||
if not allocation.nextcall:
|
||||
|
|
@ -480,6 +486,10 @@ class HrLeaveAllocation(models.Model):
|
|||
# get current level and normal period boundaries, then set nextcall, adjusted for level transition and carryover
|
||||
# add days, trimmed if there is a maximum_leave
|
||||
while allocation.nextcall <= date_to:
|
||||
if allocation.holiday_status_id.request_unit in ["day", "half_day"]:
|
||||
leaves_taken = _get_leaves_taken(allocation)
|
||||
else:
|
||||
leaves_taken = _get_leaves_taken(allocation) / allocation.employee_id._get_hours_per_day(allocation.nextcall or allocation.date_from)
|
||||
(current_level, current_level_idx) = allocation._get_current_accrual_plan_level_id(allocation.nextcall)
|
||||
if not current_level:
|
||||
break
|
||||
|
|
@ -487,7 +497,7 @@ class HrLeaveAllocation(models.Model):
|
|||
if current_level.added_value_type == "day":
|
||||
current_level_maximum_leave = current_level.maximum_leave
|
||||
else:
|
||||
current_level_maximum_leave = current_level.maximum_leave / allocation.employee_id._get_hours_per_day(allocation.date_from)
|
||||
current_level_maximum_leave = current_level.maximum_leave / allocation.employee_id._get_hours_per_day(allocation.nextcall or allocation.date_from)
|
||||
nextcall = current_level._get_next_date(allocation.nextcall)
|
||||
# Since _get_previous_date returns the given date if it corresponds to a call date
|
||||
# this will always return lastcall except possibly on the first call
|
||||
|
|
@ -530,7 +540,7 @@ class HrLeaveAllocation(models.Model):
|
|||
# allocation.expiring_carryover_days - allocation.leaves_taken or 0 if all the expiring days were used
|
||||
# to take time off.
|
||||
# This ensures that only the days that weren't used to take time off will expire.
|
||||
expiring_days = max(0, allocation.expiring_carryover_days - allocation.leaves_taken)
|
||||
expiring_days = max(0, allocation.expiring_carryover_days - leaves_taken)
|
||||
allocation.number_of_days = max(0, allocation.number_of_days - expiring_days)
|
||||
allocation.expiring_carryover_days = 0
|
||||
|
||||
|
|
@ -571,6 +581,7 @@ class HrLeaveAllocation(models.Model):
|
|||
if allocation.accrual_plan_id.accrued_gain_time == 'start' and allocation.last_executed_carryover_date:
|
||||
last_carryover_date = allocation.last_executed_carryover_date
|
||||
carryover_level, carryover_level_idx = allocation._get_current_accrual_plan_level_id(last_carryover_date)
|
||||
carryover_period_start = carryover_level._get_previous_date(last_carryover_date)
|
||||
carryover_period_end = carryover_level._get_next_date(last_carryover_date)
|
||||
# Adjust carryover_period_end based on level_transition.
|
||||
if carryover_level_idx < (len(level_ids) - 1) and allocation.accrual_plan_id.transition_mode == 'immediately':
|
||||
|
|
@ -586,7 +597,8 @@ class HrLeaveAllocation(models.Model):
|
|||
# That is why (allocation.nextcall == period_end) is used instead of (is_accrual_date)
|
||||
accrued = not allocation.already_accrued and allocation.nextcall == period_end
|
||||
# If the days were accrued on the carryover period, then apply the carryover policy
|
||||
if accrued and last_carryover_date <= allocation.nextcall <= carryover_period_end:
|
||||
# If allocation.actual_lastcall == carryover_period_start, it means this loop has already been run once (skip to avoid applying the carryover twice)
|
||||
if accrued and last_carryover_date <= allocation.nextcall <= carryover_period_end and allocation.actual_lastcall != carryover_period_start:
|
||||
if carryover_level.action_with_unused_accruals == 'lost' or carryover_level.carryover_options == 'limited':
|
||||
allocation.last_executed_carryover_date = carryover_date
|
||||
allocated_days_left = allocation.number_of_days - leaves_taken
|
||||
|
|
@ -622,7 +634,8 @@ class HrLeaveAllocation(models.Model):
|
|||
current_level_maximum_leave = current_level.maximum_leave / allocation.employee_id._get_hours_per_day(allocation.date_from)
|
||||
if allocation.actual_lastcall in {period_start, allocation.date_from} | set(level_start.keys())\
|
||||
or (allocation.actual_lastcall - get_timedelta(current_level.accrual_validity_count, current_level.accrual_validity_type)
|
||||
in {period_start, allocation.date_from} | set(level_start.keys())):
|
||||
in {period_start, allocation.date_from} | set(level_start.keys())):
|
||||
leaves_taken = _get_leaves_taken(allocation)
|
||||
allocation._add_days_to_allocation(current_level, current_level_maximum_leave, leaves_taken, period_start, allocation.nextcall)
|
||||
allocation.already_accrued = True
|
||||
|
||||
|
|
@ -655,8 +668,8 @@ class HrLeaveAllocation(models.Model):
|
|||
and (not self.nextcall or self.nextcall <= accrual_date)):
|
||||
return 0
|
||||
|
||||
fake_allocation = self.env['hr.leave.allocation'].with_context(default_date_from=accrual_date).new(origin=self)
|
||||
fake_allocation.sudo().with_context(default_date_from=accrual_date)._process_accrual_plans(accrual_date, log=False)
|
||||
fake_allocation = self.env['hr.leave.allocation'].new(origin=self)
|
||||
fake_allocation.sudo()._process_accrual_plans(accrual_date, log=False)
|
||||
if self.holiday_status_id.request_unit in ['hour']:
|
||||
res = float_round(fake_allocation.number_of_hours_display - self.number_of_hours_display, precision_digits=2)
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -675,8 +675,8 @@ class HrLeaveType(models.Model):
|
|||
def _get_carried_over_days_expiration_data(self, allocations, target_date):
|
||||
fake_allocations = self.env['hr.leave.allocation']
|
||||
for allocation in allocations:
|
||||
fake_allocations |= self.env['hr.leave.allocation'].with_context(default_date_from=target_date).new(origin=allocation)
|
||||
fake_allocations.sudo().with_context(default_date_from=target_date)._process_accrual_plans(target_date, log=False)
|
||||
fake_allocations |= self.env['hr.leave.allocation'].new(origin=allocation)
|
||||
fake_allocations.sudo()._process_accrual_plans(target_date, log=False)
|
||||
carried_over_days_expiration_data = {
|
||||
fake_allocation._origin:
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue