from odoo.tests.common import TransactionCase from odoo.tests import tagged from odoo.addons.fusion_accounting_assets.services.anomaly_detection import ( detect_schedule_variance, detect_low_utilization, AssetAnomaly, ) @tagged('post_install', '-at_install') class TestAssetAnomalyDetection(TransactionCase): def test_schedule_variance_within_threshold_returns_none(self): # 5% variance < 10% threshold result = detect_schedule_variance( asset_id=1, asset_name='Truck', expected_accumulated=10000, actual_accumulated=10500, ) self.assertIsNone(result) def test_schedule_variance_behind_schedule_low_severity(self): # 15% behind: low severity, behind_schedule result = detect_schedule_variance( asset_id=1, asset_name='Truck', expected_accumulated=10000, actual_accumulated=8500, ) self.assertIsNotNone(result) self.assertEqual(result.anomaly_type, 'behind_schedule') self.assertEqual(result.severity, 'low') def test_schedule_variance_ahead_high_severity(self): # 60% ahead: high severity result = detect_schedule_variance( asset_id=2, asset_name='Server', expected_accumulated=10000, actual_accumulated=16000, ) self.assertIsNotNone(result) self.assertEqual(result.anomaly_type, 'ahead_of_schedule') self.assertEqual(result.severity, 'high') def test_schedule_variance_zero_expected_returns_none(self): result = detect_schedule_variance( asset_id=1, asset_name='Truck', expected_accumulated=0, actual_accumulated=500, ) self.assertIsNone(result) def test_low_utilization_flags_when_underused(self): # 60% deficit -> high severity result = detect_low_utilization( asset_id=3, asset_name='Mill', expected_units=1000, actual_units=400, ) self.assertIsNotNone(result) self.assertEqual(result.anomaly_type, 'low_utilization') self.assertEqual(result.severity, 'high') def test_low_utilization_within_tolerance_returns_none(self): # 95% used: within 10% tolerance result = detect_low_utilization( asset_id=3, asset_name='Mill', expected_units=1000, actual_units=950, ) self.assertIsNone(result) def test_anomaly_to_dict_round_trip(self): anomaly = AssetAnomaly( asset_id=1, asset_name='X', anomaly_type='behind_schedule', severity='medium', expected=100.0, actual=70.0, variance_pct=30.0, detail='example', ) d = anomaly.to_dict() self.assertEqual(d['asset_id'], 1) self.assertEqual(d['anomaly_type'], 'behind_schedule') self.assertEqual(d['severity'], 'medium')