Coverage for backend/django/Economics/costing/capital/lang_factors.py: 88%
52 statements
« prev ^ index » next coverage.py v7.10.7, created at 2026-06-23 21:51 +0000
« prev ^ index » next coverage.py v7.10.7, created at 2026-06-23 21:51 +0000
1from __future__ import annotations
3from dataclasses import dataclass
4from decimal import Decimal
6from Economics.shared.choices import CostBasis, LangFactorDefaultScope
8from Economics.reference_data.models import EconomicsLangFactorDefault
10from Economics.costing.models import EquipmentMapping
11from Economics.settings_profiles.services.settings_profiles import get_settings_profile
14GLOBAL_LANG_FACTOR_DEFAULT = Decimal("3.000000")
17@dataclass(frozen=True)
18class LangFactorResolution:
19 label: str
20 effective_value: Decimal | None
21 active_default_value: Decimal | None
22 source: str
23 is_custom: bool
24 default_key: str
27def resolve_lang_factor(mapping: EquipmentMapping | None) -> LangFactorResolution:
28 """Resolve effective Lang factor using study defaults before per-item overrides."""
29 if mapping is None: 29 ↛ 30line 29 didn't jump to line 30 because the condition on line 29 was never true
30 default = _global_default()
31 return _resolution_from_default(default, source="global_default")
33 if mapping.cost_curve_id and mapping.cost_curve.cost_basis == CostBasis.INSTALLED:
34 return LangFactorResolution(
35 label="Lang factor",
36 effective_value=None,
37 active_default_value=None,
38 source="installed_cost_curve",
39 is_custom=False,
40 default_key="installed_cost_no_factor",
41 )
43 if mapping.use_study_lang_factor:
44 settings_profile = get_settings_profile(mapping.costable_item.study)
45 if settings_profile is None:
46 value = GLOBAL_LANG_FACTOR_DEFAULT
47 else:
48 value = settings_profile.default_lang_factor
49 return LangFactorResolution(
50 label="Lang factor",
51 effective_value=value,
52 active_default_value=value,
53 source="study_default",
54 is_custom=False,
55 default_key="study_default_lang_factor",
56 )
58 default = _default_for_mapping(mapping)
59 if mapping.install_factor is None:
60 return _resolution_from_default(default, source=_default_source(default))
62 return LangFactorResolution(
63 label="Lang factor",
64 effective_value=mapping.install_factor,
65 active_default_value=default.value,
66 source="per_item_override" if mapping.install_factor != default.value else _default_source(default),
67 is_custom=mapping.install_factor != default.value,
68 default_key=default.key,
69 )
72def _default_for_mapping(mapping: EquipmentMapping) -> EconomicsLangFactorDefault:
73 object_type = ""
74 if mapping.costable_item_id and mapping.costable_item.simulation_object_id: 74 ↛ 76line 74 didn't jump to line 76 because the condition on line 74 was always true
75 object_type = mapping.costable_item.simulation_object.objectType
76 if object_type: 76 ↛ 87line 76 didn't jump to line 87 because the condition on line 76 was always true
77 default = (
78 EconomicsLangFactorDefault.objects.filter(
79 scope=LangFactorDefaultScope.UNIT_OPERATION_TYPE,
80 unit_operation_type=object_type,
81 )
82 .order_by("pk")
83 .first()
84 )
85 if default is not None:
86 return default
87 return _global_default()
90def _global_default() -> EconomicsLangFactorDefault:
91 default = (
92 EconomicsLangFactorDefault.objects.filter(scope=LangFactorDefaultScope.GLOBAL)
93 .order_by("pk")
94 .first()
95 )
96 if default is not None: 96 ↛ 98line 96 didn't jump to line 98 because the condition on line 96 was always true
97 return default
98 return EconomicsLangFactorDefault(
99 key="global_lang_factor_3x",
100 scope=LangFactorDefaultScope.GLOBAL,
101 value=GLOBAL_LANG_FACTOR_DEFAULT,
102 label="Global Lang factor default",
103 source_label="Ahuora v1 economics default",
104 )
107def _resolution_from_default(default: EconomicsLangFactorDefault, *, source: str) -> LangFactorResolution:
108 return LangFactorResolution(
109 label="Lang factor",
110 effective_value=default.value,
111 active_default_value=default.value,
112 source=source,
113 is_custom=False,
114 default_key=default.key,
115 )
118def _default_source(default: EconomicsLangFactorDefault) -> str:
119 if default.scope == LangFactorDefaultScope.UNIT_OPERATION_TYPE: 119 ↛ 121line 119 didn't jump to line 121 because the condition on line 119 was always true
120 return "unit_operation_type_default"
121 return "global_default"