from backend.core.models import DocumentRiskControl from backend.core.utils import calculate_aggregate_likelihood, calculate_aggregate_weight, map_weight_to_impact_likelihood def risk_matrix_table(): impact_labels = [ "Insignificant (1)", "Significant (2)", "Severe (3)", "Material (4)", "Major (5)" ] header = ["Likelihood ↓ / Impact →"] + impact_labels matrix = [ ["Almost Certain (5)", (5, "bg-medium"), (10, "bg-high"), (15, "bg-critical"), (20, "bg-critical"), (25, "bg-critical") ], ["Likely (4)", (4, "bg-low"), (8, "bg-medium"), (12, "bg-high"), (16, "bg-high"), (20, "bg-critical") ], ["Probable (3)", (3, "bg-low"), (6, "bg-low"), (9, "bg-medium"), (12, "bg-high"), (15, "bg-high") ], ["Unlikely (2)", (2, "bg-very-low"), (4, "bg-low"), (6, "bg-medium"), (8, "bg-medium"), (10, "bg-medium") ], ["Rare (1)", (1, "bg-very-low"), (2, "bg-very-low"), (3, "bg-low"), (4, "bg-low"), (5, "bg-medium") ], ] table = [header] + matrix return table def get_risk_table(document): risks = ( DocumentRiskControl.objects .filter(document=document) .values('risk', 'risk__risk_name') .distinct() ) risks_with_controls = [] for risk_entry in risks: risk = { 'id': risk_entry['risk'], 'name': risk_entry['risk__risk_name'] } controls = ( DocumentRiskControl.objects .filter(document=document, risk_id=risk['id']) .values('control', 'control__name', 'weight', 'likelihood') .distinct() ) max_weight = 10*5 total_weight = calculate_aggregate_weight(controls) total_likelihood = calculate_aggregate_likelihood(controls) impact, likelihood = map_weight_to_impact_likelihood(total_weight, total_likelihood, max_weight) r_impact = round(impact) r_likelihood = round(likelihood) residua_impact = r_impact - 1 if r_impact > 2 else r_impact residual_likelihood = r_likelihood - 1 if r_likelihood > 2 else r_likelihood risks_with_controls.append({ 'risk': risk, 'controls': list(controls), 'total_weight': total_weight, 'impact': impact, 'likelihood': likelihood, 'r_impact': r_impact, 'r_likelihood': r_likelihood, 'risk_score': r_impact * r_likelihood, 'residual_impact': residua_impact, 'residual_likelihood': residual_likelihood, 'residual_risk_score': residua_impact * residual_likelihood, }) risks_with_controls.sort(key=lambda x: x['risk_score'], reverse=True) return risks_with_controls def get_safeguard_summary_table(risks_with_controls): from collections import Counter from backend.core.models import Control safeguard_counter = Counter() safeguard_names = {} for risk in risks_with_controls: for control in risk.get('controls', []): control_id = control.get('control') control_name = control.get('control__name') if control_id: safeguard_counter[control_id] += 1 safeguard_names[control_id] = control_name summary = [] controls = Control.objects.filter(id__in=safeguard_counter.keys()) controls_map = {c.id: c for c in controls} for control_id, count in safeguard_counter.items(): control = controls_map.get(control_id) summary.append({ 'id': control_id, 'safeguard_id': control.safeguard_id if control else '', 'name': safeguard_names.get(control_id, ''), 'description': control.description if control else '', 'count': count, }) summary.sort(key=lambda x: x['count'], reverse=True) return summary