Skip to content

Commit 3393dca

Browse files
committed
fix(spp_simulation): fix metric rendering, CEL profile context, and fallback logic
- Load CEL profile in _get_ideal_population_ids so the executor runs with the correct base domain and model context (matches _execute_targeting) - Fix _compute_metric_results_html to read "rate" and "ratio" keys for coverage and ratio metrics instead of always reading "value" - Fix distribution stats to use explicit None check so zero values render as numbers instead of dashes - Add "scenario_id.target_type" to @api.depends for _compute_summary_html - Set amount_mode = "fixed" in the multiplier-to-fixed fallback branch so the wizard item is created with an explicit mode - Fix aggregate metric to use metric.aggregation as the result key so that sum/avg/min/max aggregations read the correct value from the CEL result
1 parent a923947 commit 3393dca

3 files changed

Lines changed: 29 additions & 6 deletions

File tree

spp_simulation/models/simulation_run.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ def _compute_display_name(self):
225225
"equity_score",
226226
"scenario_id.name",
227227
"scenario_id.budget_amount",
228+
"scenario_id.target_type",
228229
)
229230
def _compute_summary_html(self):
230231
for record in self:
@@ -312,7 +313,7 @@ def _compute_distribution_details_html(self):
312313
("Std Dev", dist.get("standard_deviation", 0), "{:,.2f}"),
313314
]
314315
for label, value, fmt in stats:
315-
formatted = fmt.format(value) if value else "-"
316+
formatted = fmt.format(value) if value is not None else "-"
316317
html_parts.append(f"<tr><td><strong>{label}</strong></td><td>{formatted}</td></tr>")
317318
html_parts.append("</tbody></table></div>")
318319

@@ -392,7 +393,13 @@ def _compute_metric_results_html(self):
392393
Markup("</tr></thead><tbody>"),
393394
]
394395
for metric_name, metric_data in metrics.items():
395-
value = metric_data.get("value", 0)
396+
# coverage stores result under "rate", ratio under "ratio";
397+
# fall back through all three keys using explicit None checks
398+
value = metric_data.get("value")
399+
if value is None:
400+
value = metric_data.get("rate")
401+
if value is None:
402+
value = metric_data.get("ratio", 0)
396403
metric_type = metric_data.get("type", "unknown")
397404
# Format value based on type
398405
if metric_type == "coverage":

spp_simulation/services/simulation_service.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -360,11 +360,15 @@ def _compute_custom_metrics(self, scenario, beneficiary_ids):
360360
base_domain=[("id", "in", beneficiary_ids)],
361361
limit=0,
362362
)
363-
count = result.get("count", 0)
363+
# Use the aggregation type as the result key so that
364+
# sum/avg/min/max metrics read the correct key rather
365+
# than always reading "count".
366+
agg_key = metric.aggregation or "count"
367+
value = result.get(agg_key, 0)
364368
results[metric.name] = {
365369
"type": "aggregate",
366370
"aggregation": metric.aggregation,
367-
"value": count,
371+
"value": value,
368372
}
369373

370374
elif metric.metric_type == "coverage":
@@ -587,6 +591,7 @@ def _create_wizard_entitlement_items(self, wizard, scenario, warnings):
587591
# Multiplier mode cannot be directly mapped because
588592
# simulation rules use a Char field name while wizard items
589593
# use a Many2one to ir.model.fields. Fall back to fixed.
594+
item_vals["amount_mode"] = "fixed"
590595
warnings.append(
591596
_(
592597
"Entitlement rule '%s' uses multiplier mode with field '%s'. "

spp_simulation/services/targeting_efficiency_service.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,19 @@ def compute_targeting_efficiency(self, scenario, simulated_ids):
5656

5757
@api.model
5858
def _get_ideal_population_ids(self, scenario):
59-
"""Get the ideal population IDs from the ideal population expression."""
60-
executor = self.env["spp.cel.executor"]
59+
"""Get the ideal population IDs from the ideal population expression.
60+
61+
Loads the CEL profile matching the scenario target type so that the
62+
executor evaluates the expression in the correct model context (same
63+
pattern used by _execute_targeting in simulation_service.py).
64+
"""
65+
# Load the CEL profile so the executor has the correct base domain
66+
# and model context, matching _execute_targeting in simulation_service.py
67+
profile = "registry_groups" if scenario.target_type == "group" else "registry_individuals"
68+
registry = self.env["spp.cel.registry"]
69+
cfg = registry.load_profile(profile)
70+
71+
executor = self.env["spp.cel.executor"].with_context(cel_cfg=cfg)
6172
all_ids = []
6273
try:
6374
for batch_ids in executor.compile_for_batch(

0 commit comments

Comments
 (0)