Coverage for backend/django/Economics/formulas/models.py: 93%
54 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 django.core.exceptions import ValidationError
2from django.db import models
4from core.managers import AccessControlManager
5from Economics.shared.model_base import FlowsheetScopedEconomicsModel
8class EconomicsMetricFormula(FlowsheetScopedEconomicsModel):
9 """Persist the formula envelope used to calculate one study financial metric."""
11 same_flowsheet_fields = ("study", "property_value")
13 flowsheet = models.ForeignKey(
14 "core_auxiliary.Flowsheet",
15 on_delete=models.CASCADE,
16 related_name="economics_metric_formulas",
17 )
18 study = models.ForeignKey(
19 "EconomicsStudy",
20 on_delete=models.CASCADE,
21 related_name="metric_formulas",
22 )
23 property_value = models.ForeignKey(
24 "core_auxiliary.PropertyValue",
25 on_delete=models.SET_NULL,
26 related_name="economics_metric_formulas",
27 null=True,
28 blank=True,
29 )
30 metric_key = models.CharField(max_length=96)
31 formula_key = models.CharField(max_length=128)
32 formula = models.TextField(blank=True)
33 property_formula = models.TextField(blank=True)
34 unit = models.CharField(max_length=64, blank=True)
35 value = models.CharField(max_length=128, null=True, blank=True)
36 status = models.CharField(max_length=32, default="calculated")
37 formula_audit = models.JSONField(default=dict, blank=True)
38 blocked_reason = models.TextField(blank=True)
39 created_at = models.DateTimeField(auto_now_add=True)
40 updated_at = models.DateTimeField(auto_now=True)
42 objects = AccessControlManager()
44 class Meta:
45 ordering = ["metric_key"]
46 constraints = [
47 models.UniqueConstraint(
48 fields=["study", "metric_key"],
49 name="unique_metric_formula_per_study",
50 ),
51 ]
53 def __str__(self):
54 return f"{self.study.name} {self.metric_key}"
56class EconomicsLineFormula(FlowsheetScopedEconomicsModel):
57 """Persist the formula envelope used to calculate one economics line property."""
59 same_flowsheet_fields = ("study", "property_value", "capital_line", "operating_line")
61 flowsheet = models.ForeignKey(
62 "core_auxiliary.Flowsheet",
63 on_delete=models.CASCADE,
64 related_name="economics_line_formulas",
65 )
66 study = models.ForeignKey(
67 "EconomicsStudy",
68 on_delete=models.CASCADE,
69 related_name="line_formulas",
70 )
71 property_value = models.ForeignKey(
72 "core_auxiliary.PropertyValue",
73 on_delete=models.SET_NULL,
74 related_name="economics_line_formulas",
75 null=True,
76 blank=True,
77 )
78 capital_line = models.ForeignKey(
79 "CapitalCostLine",
80 on_delete=models.CASCADE,
81 related_name="formula_records",
82 null=True,
83 blank=True,
84 )
85 operating_line = models.ForeignKey(
86 "OperatingCostLine",
87 on_delete=models.CASCADE,
88 related_name="formula_records",
89 null=True,
90 blank=True,
91 )
92 line_key = models.CharField(max_length=128)
93 formula_key = models.CharField(max_length=128)
94 formula = models.TextField(blank=True)
95 property_formula = models.TextField(blank=True)
96 unit = models.CharField(max_length=64, blank=True)
97 value = models.CharField(max_length=128, null=True, blank=True)
98 status = models.CharField(max_length=32, default="calculated")
99 formula_audit = models.JSONField(default=dict, blank=True)
100 blocked_reason = models.TextField(blank=True)
101 created_at = models.DateTimeField(auto_now_add=True)
102 updated_at = models.DateTimeField(auto_now=True)
104 objects = AccessControlManager()
106 class Meta:
107 ordering = ["line_key"]
108 constraints = [
109 models.UniqueConstraint(
110 fields=["study", "line_key"],
111 name="unique_line_formula_per_study",
112 ),
113 ]
115 def clean(self):
116 super().clean()
117 if bool(self.capital_line_id) == bool(self.operating_line_id): 117 ↛ 118line 117 didn't jump to line 118 because the condition on line 117 was never true
118 raise ValidationError({"line_key": "Line formula records must reference exactly one economics line."})
120 def __str__(self):
121 return f"{self.study.name} {self.line_key}"