117 lines
3.6 KiB
Python
117 lines
3.6 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Copyright 2024-2026 Nexa Systems Inc.
|
|
# License OPL-1 (Odoo Proprietary License v1.0)
|
|
|
|
"""
|
|
Fusion Technician Location
|
|
GPS location logging for field technicians.
|
|
"""
|
|
|
|
from odoo import models, fields, api, _
|
|
import logging
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
class FusionTechnicianLocation(models.Model):
|
|
_name = 'fusion.technician.location'
|
|
_description = 'Technician Location Log'
|
|
_order = 'logged_at desc'
|
|
|
|
user_id = fields.Many2one(
|
|
'res.users',
|
|
string='Technician',
|
|
required=True,
|
|
index=True,
|
|
ondelete='cascade',
|
|
)
|
|
latitude = fields.Float(
|
|
string='Latitude',
|
|
digits=(10, 7),
|
|
required=True,
|
|
)
|
|
longitude = fields.Float(
|
|
string='Longitude',
|
|
digits=(10, 7),
|
|
required=True,
|
|
)
|
|
accuracy = fields.Float(
|
|
string='Accuracy (m)',
|
|
help='GPS accuracy in meters',
|
|
)
|
|
logged_at = fields.Datetime(
|
|
string='Logged At',
|
|
default=fields.Datetime.now,
|
|
required=True,
|
|
index=True,
|
|
)
|
|
source = fields.Selection([
|
|
('portal', 'Portal'),
|
|
('app', 'Mobile App'),
|
|
], string='Source', default='portal')
|
|
|
|
@api.model
|
|
def log_location(self, latitude, longitude, accuracy=None):
|
|
"""Log the current user's location. Called from portal JS."""
|
|
return self.sudo().create({
|
|
'user_id': self.env.user.id,
|
|
'latitude': latitude,
|
|
'longitude': longitude,
|
|
'accuracy': accuracy or 0,
|
|
'source': 'portal',
|
|
})
|
|
|
|
@api.model
|
|
def get_latest_locations(self):
|
|
"""Get the most recent location for each technician (for map view)."""
|
|
self.env.cr.execute("""
|
|
SELECT DISTINCT ON (user_id)
|
|
user_id, latitude, longitude, accuracy, logged_at
|
|
FROM fusion_technician_location
|
|
WHERE logged_at > NOW() - INTERVAL '24 hours'
|
|
ORDER BY user_id, logged_at DESC
|
|
""")
|
|
rows = self.env.cr.dictfetchall()
|
|
result = []
|
|
for row in rows:
|
|
user = self.env['res.users'].sudo().browse(row['user_id'])
|
|
result.append({
|
|
'user_id': row['user_id'],
|
|
'name': user.name,
|
|
'latitude': row['latitude'],
|
|
'longitude': row['longitude'],
|
|
'accuracy': row['accuracy'],
|
|
'logged_at': str(row['logged_at']),
|
|
})
|
|
return result
|
|
|
|
@api.model
|
|
def _cron_cleanup_old_locations(self):
|
|
"""Remove location logs based on configurable retention setting.
|
|
|
|
Setting (fusion_claims.location_retention_days):
|
|
- Empty / not set => keep 30 days (default)
|
|
- "0" => delete at end of day (keep today only)
|
|
- "1" .. "N" => keep for N days
|
|
"""
|
|
ICP = self.env['ir.config_parameter'].sudo()
|
|
raw = (ICP.get_param('fusion_claims.location_retention_days') or '').strip()
|
|
|
|
if raw == '':
|
|
retention_days = 30 # default: 1 month
|
|
else:
|
|
try:
|
|
retention_days = max(int(raw), 0)
|
|
except (ValueError, TypeError):
|
|
retention_days = 30
|
|
|
|
cutoff = fields.Datetime.subtract(fields.Datetime.now(), days=retention_days)
|
|
old_records = self.search([('logged_at', '<', cutoff)])
|
|
count = len(old_records)
|
|
if count:
|
|
old_records.unlink()
|
|
_logger.info(
|
|
"Cleaned up %d technician location records (retention=%d days)",
|
|
count, retention_days,
|
|
)
|