101 lines
3.7 KiB
Python
101 lines
3.7 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Copyright 2026 Nexa Systems Inc.
|
|
# License OPL-1 (Odoo Proprietary License v1.0)
|
|
|
|
from datetime import datetime, timedelta
|
|
from odoo import models, fields, api
|
|
|
|
|
|
class HrEmployee(models.Model):
|
|
_inherit = 'hr.employee'
|
|
|
|
x_fclk_default_location_id = fields.Many2one(
|
|
'fusion.clock.location',
|
|
string='Default Clock Location',
|
|
help="The default location shown on this employee's clock page.",
|
|
)
|
|
x_fclk_enable_clock = fields.Boolean(
|
|
string='Enable Fusion Clock',
|
|
default=True,
|
|
help="If unchecked, this employee cannot use the Fusion Clock portal/systray.",
|
|
)
|
|
x_fclk_break_minutes = fields.Float(
|
|
string='Custom Break (min)',
|
|
default=0.0,
|
|
help="Override default break duration for this employee. 0 = use company default.",
|
|
)
|
|
x_fclk_period_hours = fields.Float(
|
|
string='Period Hours',
|
|
compute='_compute_fclk_period_hours',
|
|
help="Net hours worked in the current pay period.",
|
|
)
|
|
x_fclk_period_label = fields.Char(
|
|
string='Current Period',
|
|
compute='_compute_fclk_period_hours',
|
|
help="Label for the current pay period.",
|
|
)
|
|
|
|
def _get_fclk_break_minutes(self):
|
|
"""Return effective break minutes for this employee."""
|
|
self.ensure_one()
|
|
if self.x_fclk_break_minutes > 0:
|
|
return self.x_fclk_break_minutes
|
|
return float(
|
|
self.env['ir.config_parameter'].sudo().get_param(
|
|
'fusion_clock.default_break_minutes', '30'
|
|
)
|
|
)
|
|
|
|
def action_fclk_open_attendance(self):
|
|
"""Open attendance list for this employee, grouped by pay period."""
|
|
self.ensure_one()
|
|
list_view = self.env.ref('fusion_clock.view_hr_attendance_list_by_period')
|
|
search_view = self.env.ref('fusion_clock.view_hr_attendance_search_by_period')
|
|
return {
|
|
'type': 'ir.actions.act_window',
|
|
'name': f'{self.name} - Attendance',
|
|
'res_model': 'hr.attendance',
|
|
'view_mode': 'list,form',
|
|
'views': [(list_view.id, 'list'), (False, 'form')],
|
|
'search_view_id': (search_view.id, search_view.name),
|
|
'domain': [('employee_id', '=', self.id)],
|
|
'context': {
|
|
'search_default_group_pay_period': 1,
|
|
'default_employee_id': self.id,
|
|
},
|
|
}
|
|
|
|
def _compute_fclk_period_hours(self):
|
|
ICP = self.env['ir.config_parameter'].sudo()
|
|
schedule_type = ICP.get_param('fusion_clock.pay_period_type', 'biweekly')
|
|
anchor_str = ICP.get_param('fusion_clock.pay_period_start', '')
|
|
anchor = None
|
|
if anchor_str:
|
|
try:
|
|
anchor = fields.Date.from_string(anchor_str)
|
|
except Exception:
|
|
pass
|
|
|
|
today = fields.Date.today()
|
|
Attendance = self.env['hr.attendance']
|
|
period_start, period_end = Attendance._calc_period(schedule_type, anchor, today)
|
|
|
|
period_label = (
|
|
f"{period_start.strftime('%b %d')} - "
|
|
f"{period_end.strftime('%b %d, %Y')}"
|
|
)
|
|
start_dt = datetime.combine(period_start, datetime.min.time())
|
|
end_dt = datetime.combine(period_end + timedelta(days=1), datetime.min.time())
|
|
|
|
for emp in self:
|
|
atts = Attendance.sudo().search([
|
|
('employee_id', '=', emp.id),
|
|
('check_in', '>=', start_dt),
|
|
('check_in', '<', end_dt),
|
|
('check_out', '!=', False),
|
|
])
|
|
emp.x_fclk_period_hours = round(
|
|
sum(a.x_fclk_net_hours or 0 for a in atts), 1
|
|
)
|
|
emp.x_fclk_period_label = period_label
|