- 3 anomaly types: behind_schedule, ahead_of_schedule, low_utilization - 3 severity levels: low, medium, high - expected / actual / variance_pct (mirrors anomaly_detection service output) - 4-state lifecycle: new -> acknowledged -> resolved (or dismissed) - action_acknowledge / action_dismiss / action_resolve transitions - ondelete='cascade' on asset_id (anomalies follow the asset) - 4 new tests (63 total) Made-with: Cursor
43 lines
1.4 KiB
Python
43 lines
1.4 KiB
Python
"""Persisted asset anomaly flags from the engine's variance detection."""
|
|
|
|
from odoo import fields, models
|
|
|
|
|
|
SEVERITY = [('low', 'Low'), ('medium', 'Medium'), ('high', 'High')]
|
|
ANOMALY_TYPES = [
|
|
('behind_schedule', 'Behind Schedule'),
|
|
('ahead_of_schedule', 'Ahead of Schedule'),
|
|
('low_utilization', 'Low Utilization'),
|
|
]
|
|
|
|
|
|
class FusionAssetAnomaly(models.Model):
|
|
_name = "fusion.asset.anomaly"
|
|
_description = "Flagged Asset Anomaly"
|
|
_order = "detected_at desc, severity desc"
|
|
|
|
asset_id = fields.Many2one('fusion.asset', required=True, ondelete='cascade')
|
|
company_id = fields.Many2one(related='asset_id.company_id', store=True)
|
|
anomaly_type = fields.Selection(ANOMALY_TYPES, required=True)
|
|
severity = fields.Selection(SEVERITY, required=True)
|
|
expected = fields.Float()
|
|
actual = fields.Float()
|
|
variance_pct = fields.Float()
|
|
detail = fields.Text()
|
|
detected_at = fields.Datetime(default=fields.Datetime.now, required=True)
|
|
state = fields.Selection([
|
|
('new', 'New'),
|
|
('acknowledged', 'Acknowledged'),
|
|
('resolved', 'Resolved'),
|
|
('dismissed', 'Dismissed'),
|
|
], default='new', required=True)
|
|
|
|
def action_acknowledge(self):
|
|
self.write({'state': 'acknowledged'})
|
|
|
|
def action_dismiss(self):
|
|
self.write({'state': 'dismissed'})
|
|
|
|
def action_resolve(self):
|
|
self.write({'state': 'resolved'})
|