# -*- coding: utf-8 -*- # Copyright 2026 Nexa Systems Inc. # License OPL-1 (Odoo Proprietary License v1.0) import logging from odoo import models, fields, api, _ from odoo.exceptions import UserError _logger = logging.getLogger(__name__) class FusionClockCorrection(models.Model): _name = 'fusion.clock.correction' _description = 'Timesheet Correction Request' _order = 'create_date desc, id desc' _rec_name = 'display_name' _inherit = ['mail.thread'] employee_id = fields.Many2one( 'hr.employee', string='Employee', required=True, index=True, ondelete='cascade', ) attendance_id = fields.Many2one( 'hr.attendance', string='Attendance Record', required=True, ondelete='cascade', ) original_check_in = fields.Datetime( string='Original Clock-In', related='attendance_id.check_in', ) original_check_out = fields.Datetime( string='Original Clock-Out', related='attendance_id.check_out', ) requested_check_in = fields.Datetime( string='Corrected Clock-In', ) requested_check_out = fields.Datetime( string='Corrected Clock-Out', ) reason = fields.Text( string='Reason for Correction', required=True, ) state = fields.Selection( [ ('pending', 'Pending'), ('approved', 'Approved'), ('rejected', 'Rejected'), ], string='Status', default='pending', tracking=True, index=True, ) reviewed_by = fields.Many2one( 'res.users', string='Reviewed By', ) reviewed_date = fields.Datetime(string='Reviewed Date') company_id = fields.Many2one( 'res.company', string='Company', related='employee_id.company_id', store=True, ) display_name = fields.Char( compute='_compute_display_name', store=True, ) @api.depends('employee_id', 'attendance_id', 'state') def _compute_display_name(self): for rec in self: emp = rec.employee_id.name or '' date_str = rec.attendance_id.check_in.strftime('%Y-%m-%d') if rec.attendance_id and rec.attendance_id.check_in else '' rec.display_name = f"{emp} - Correction ({date_str}) [{rec.state}]" @api.model_create_multi def create(self, vals_list): records = super().create(vals_list) for rec in records: rec._notify_office_user() rec._create_activity_log('pending') return records def action_approve(self): """Approve the correction and update the attendance record.""" self.ensure_one() if self.state != 'pending': raise UserError(_("Only pending corrections can be approved.")) vals = {} if self.requested_check_in: vals['check_in'] = self.requested_check_in if self.requested_check_out: vals['check_out'] = self.requested_check_out if vals: self.attendance_id.sudo().write(vals) self.write({ 'state': 'approved', 'reviewed_by': self.env.uid, 'reviewed_date': fields.Datetime.now(), }) self._create_activity_log('approved') def action_reject(self): """Reject the correction request.""" self.ensure_one() if self.state != 'pending': raise UserError(_("Only pending corrections can be rejected.")) self.write({ 'state': 'rejected', 'reviewed_by': self.env.uid, 'reviewed_date': fields.Datetime.now(), }) self._create_activity_log('rejected') def _notify_office_user(self): """Schedule a mail.activity for the office user.""" ICP = self.env['ir.config_parameter'].sudo() office_user_id = int(ICP.get_param('fusion_clock.office_user_id', '0')) if not office_user_id: return office_user = self.env['res.users'].sudo().browse(office_user_id) if not office_user.exists(): return try: date_str = self.attendance_id.check_in.strftime('%Y-%m-%d') if self.attendance_id.check_in else 'unknown' self.env['mail.activity'].sudo().create({ 'activity_type_id': self.env.ref('mail.mail_activity_data_todo').id, 'summary': f"Timesheet Correction: {self.employee_id.name} ({date_str})", 'note': f"Reason: {self.reason}", 'user_id': office_user.id, 'res_model_id': self.env['ir.model']._get_id('fusion.clock.correction'), 'res_id': self.id, 'date_deadline': fields.Date.today(), }) except Exception as e: _logger.error("Fusion Clock: Failed to create correction activity: %s", e) def _create_activity_log(self, action): """Log the correction event.""" try: desc = f"Correction {action} for attendance on " if self.attendance_id.check_in: desc += self.attendance_id.check_in.strftime('%Y-%m-%d') desc += f": {self.reason}" self.env['fusion.clock.activity.log'].sudo().create({ 'employee_id': self.employee_id.id, 'log_type': 'correction_request', 'description': desc, 'attendance_id': self.attendance_id.id, 'source': 'system', }) except Exception as e: _logger.error("Fusion Clock: Failed to create correction log: %s", e)