from typing import Any from sqlalchemy import select from app.core.constants import ActorValue from app.modules.audit.constants import ( AuditAction, AuditRiskLevel, AuditSource, AuditTargetType, ) from app.modules.audit.schemas import AuditLogCreate from app.modules.audit.service import AuditService from app.modules.business.constants import ( CLOSED_RISK_STATUSES, ) from app.modules.business.models import ( RiskEvent, ) from app.modules.business.service import serialize_model from app.modules.risk.constants import ( RiskGenerationAction, RiskGenerationResultKey, RiskEventPayloadKey, ) class RiskGenerationMixin: def generate_events(self, actor: str = ActorValue.API) -> dict[str, Any]: """Generate or refresh risk-event ledger entries from current signals.""" payloads = self._build_event_payloads() created = 0 updated = 0 skipped = 0 items: list[dict[str, Any]] = [] for payload in payloads: record = self.db.execute( select(RiskEvent).where(RiskEvent.code == payload[RiskEventPayloadKey.CODE]) ).scalar_one_or_none() if record is None: record = RiskEvent(**payload) self.db.add(record) self.db.flush() created += 1 action = RiskGenerationAction.CREATED elif record.status in CLOSED_RISK_STATUSES: skipped += 1 items.append( { RiskGenerationResultKey.ACTION: RiskGenerationAction.SKIPPED, RiskGenerationResultKey.RISK_EVENT: serialize_model(record), } ) continue else: for key, value in payload.items(): if key != RiskEventPayloadKey.CODE: setattr(record, key, value) updated += 1 action = RiskGenerationAction.UPDATED items.append( { RiskGenerationResultKey.ACTION: action, RiskGenerationResultKey.RISK_EVENT: serialize_model(record), } ) self.db.commit() AuditService(self.db).log( AuditLogCreate( actor=actor, source=AuditSource.RISK, action=AuditAction.GENERATE_EVENTS, target_type=AuditTargetType.RISK_EVENTS, risk_level=AuditRiskLevel.MEDIUM, response_payload={ RiskGenerationResultKey.CREATED: created, RiskGenerationResultKey.UPDATED: updated, RiskGenerationResultKey.SKIPPED: skipped, }, ) ) return { RiskGenerationResultKey.CREATED: created, RiskGenerationResultKey.UPDATED: updated, RiskGenerationResultKey.SKIPPED: skipped, RiskGenerationResultKey.ITEMS: items, }