mirror of
https://github.com/bringout/oca-ocb-hr.git
synced 2026-04-26 20:12:05 +02:00
108 lines
4.2 KiB
Python
108 lines
4.2 KiB
Python
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from odoo import api, models, fields
|
|
|
|
|
|
class HrAttendanceOvertimeLine(models.Model):
|
|
_name = 'hr.attendance.overtime.line'
|
|
_description = "Attendance Overtime Line"
|
|
_rec_name = 'employee_id'
|
|
_order = 'time_start'
|
|
|
|
employee_id = fields.Many2one(
|
|
'hr.employee', string="Employee",
|
|
required=True, ondelete='cascade', index=True)
|
|
company_id = fields.Many2one(related='employee_id.company_id')
|
|
|
|
date = fields.Date(string='Day', index=True, required=True)
|
|
status = fields.Selection([
|
|
('to_approve', "To Approve"),
|
|
('approved', "Approved"),
|
|
('refused', "Refused")
|
|
],
|
|
compute='_compute_status',
|
|
required=True, store=True, readonly=False, precompute=True,
|
|
)
|
|
duration = fields.Float(string='Extra Hours', default=0.0, required=True)
|
|
manual_duration = fields.Float( # TODO -> real_duration for easier upgrade
|
|
string='Extra Hours (encoded)',
|
|
compute='_compute_manual_duration',
|
|
store=True, readonly=False,
|
|
)
|
|
|
|
time_start = fields.Datetime(string='Start') # time_start will be equal to attendance.check_in
|
|
time_stop = fields.Datetime(string='Stop') # time_stop will be equal to attendance.check_out
|
|
amount_rate = fields.Float("Overtime pay rate", required=True, default=1.0)
|
|
|
|
is_manager = fields.Boolean(compute="_compute_is_manager")
|
|
|
|
rule_ids = fields.Many2many("hr.attendance.overtime.rule", string="Applied Rules")
|
|
|
|
# in payroll: rate, work_entry_type
|
|
# in time_off: convertible_to_time_off
|
|
|
|
# Check no overlapping overtimes for the same employee.
|
|
# Technical explanation: Exclude constraints compares the given expression on rows 2 by 2 using the given operator; && on tsrange is the intersection.
|
|
# cf: https://www.postgresql.org/docs/current/ddl-constraints.html#DDL-CONSTRAINTS-EXCLUSION
|
|
# for employee_id we compare [employee_id -> employee_id] ranges bc raw integer is not supported (?)
|
|
# _overtime_no_overlap_same_employee = models.Constraint("""
|
|
# EXCLUDE USING GIST (
|
|
# tsrange(time_start, time_stop, '()') WITH &&,
|
|
# int4range(employee_id, employee_id, '[]') WITH =
|
|
# )
|
|
# """,
|
|
# "Employee cannot have overlapping overtimes",
|
|
# )
|
|
_overtime_start_before_end = models.Constraint(
|
|
'CHECK (time_stop > time_start)',
|
|
'Starting time should be before end time.',
|
|
)
|
|
|
|
@api.depends('employee_id')
|
|
def _compute_status(self):
|
|
for overtime in self:
|
|
if not overtime.status:
|
|
overtime.status = 'to_approve' if overtime.employee_id.company_id.attendance_overtime_validation == 'by_manager' else 'approved'
|
|
|
|
@api.depends('duration')
|
|
def _compute_manual_duration(self):
|
|
for overtime in self:
|
|
overtime.manual_duration = overtime.duration
|
|
|
|
@api.depends('employee_id')
|
|
def _compute_is_manager(self):
|
|
has_manager_right = self.env.user.has_group('hr_attendance.group_hr_attendance_manager')
|
|
has_officer_right = self.env.user.has_group('hr_attendance.group_hr_attendance_officer')
|
|
for overtime in self:
|
|
overtime.is_manager = (
|
|
has_manager_right or
|
|
(
|
|
has_officer_right
|
|
and overtime.employee_id.attendance_manager_id == self.env.user
|
|
)
|
|
)
|
|
|
|
def action_approve(self):
|
|
self.write({'status': 'approved'})
|
|
|
|
def action_refuse(self):
|
|
self.write({'status': 'refused'})
|
|
|
|
def _linked_attendances(self):
|
|
return self.env['hr.attendance'].search([
|
|
('check_in', 'in', self.mapped('time_start')),
|
|
('employee_id', 'in', self.employee_id.ids),
|
|
])
|
|
|
|
def write(self, vals):
|
|
if any(key in vals for key in ['status', 'manual_duration']):
|
|
attendances = self._linked_attendances()
|
|
self.env.add_to_compute(
|
|
attendances._fields['overtime_status'],
|
|
attendances
|
|
)
|
|
self.env.add_to_compute(
|
|
attendances._fields['validated_overtime_hours'],
|
|
attendances
|
|
)
|
|
return super().write(vals)
|