72 lines
2.8 KiB
Python
72 lines
2.8 KiB
Python
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')
|