# -*- coding: utf-8 -*- # Copyright 2026 Nexa Systems Inc. # License OPL-1 (Odoo Proprietary License v1.0) from odoo import models, fields, api class FusionClockActivityLog(models.Model): _name = 'fusion.clock.activity.log' _description = 'Clock Activity Log' _order = 'log_date desc, id desc' _rec_name = 'display_name' employee_id = fields.Many2one( 'hr.employee', string='Employee', required=True, index=True, ondelete='cascade', ) log_type = fields.Selection( [ ('clock_in', 'Clock In'), ('clock_out', 'Clock Out'), ('late_clock_in', 'Late Clock-In'), ('early_clock_out', 'Early Clock-Out'), ('outside_geofence', 'Outside Geofence'), ('auto_clock_out', 'Auto Clock-Out'), ('missed_clock_out', 'Missed Clock-Out'), ('absent', 'Absent'), ('leave_request', 'Leave Request'), ('reason_provided', 'Reason Provided'), ('overtime', 'Overtime'), ('correction_request', 'Correction Request'), ('ip_fallback', 'IP Fallback Used'), ('streak_milestone', 'Streak Milestone'), ('card_enrollment', 'Card Enrollment'), ('unknown_card_tap', 'Unknown Card Tap'), ], string='Log Type', required=True, index=True, ) log_date = fields.Datetime( string='Date/Time', required=True, default=fields.Datetime.now, index=True, ) description = fields.Text(string='Description') attendance_id = fields.Many2one( 'hr.attendance', string='Attendance', ondelete='set null', index=True, ) location_id = fields.Many2one( 'fusion.clock.location', string='Location', ondelete='set null', ) latitude = fields.Float(string='Latitude', digits=(10, 7)) longitude = fields.Float(string='Longitude', digits=(10, 7)) distance = fields.Float( string='Distance (m)', digits=(10, 2), help="Distance from location center in meters.", ) source = fields.Selection( [ ('portal', 'Portal'), ('portal_fab', 'Portal FAB'), ('systray', 'Systray'), ('backend_fab', 'Backend FAB'), ('kiosk', 'Kiosk'), ('nfc_kiosk', 'NFC Kiosk'), ('system', 'System (Cron)'), ], string='Source', ) company_id = fields.Many2one( 'res.company', string='Company', related='employee_id.company_id', store=True, ) attempt_map_url = fields.Char( string='Map Preview', compute='_compute_attempt_map_url', ) display_name = fields.Char( compute='_compute_display_name', store=True, ) LOG_TYPE_LABELS = { 'clock_in': 'Clock In', 'clock_out': 'Clock Out', 'late_clock_in': 'Late Clock-In', 'early_clock_out': 'Early Clock-Out', 'outside_geofence': 'Outside Geofence', 'auto_clock_out': 'Auto Clock-Out', 'missed_clock_out': 'Missed Clock-Out', 'absent': 'Absent', 'leave_request': 'Leave Request', 'reason_provided': 'Reason Provided', 'overtime': 'Overtime', 'correction_request': 'Correction Request', 'ip_fallback': 'IP Fallback Used', 'streak_milestone': 'Streak Milestone', } @api.depends('latitude', 'longitude') def _compute_attempt_map_url(self): api_key = self.env['ir.config_parameter'].sudo().get_param( 'fusion_clock.google_maps_api_key', '' ) for rec in self: if rec.latitude and rec.longitude and api_key: lat, lng = rec.latitude, rec.longitude rec.attempt_map_url = ( f"https://maps.googleapis.com/maps/api/staticmap?" f"center={lat},{lng}&zoom=16&size=600x250&maptype=roadmap" f"&markers=color:red%7C{lat},{lng}" f"&key={api_key}" ) else: rec.attempt_map_url = False @api.depends('employee_id', 'log_type', 'log_date') def _compute_display_name(self): for rec in self: emp = rec.employee_id.name or '' ltype = self.LOG_TYPE_LABELS.get(rec.log_type, rec.log_type or '') date_str = rec.log_date.strftime('%Y-%m-%d %H:%M') if rec.log_date else '' rec.display_name = f"{emp} - {ltype} ({date_str})"