Files

68 lines
1.7 KiB
Python
Raw Permalink Normal View History

"""Audit trail helpers. Audit rows are append-only: the application exposes
no endpoint that updates or deletes them."""
from typing import Any
from sqlalchemy.ext.asyncio import AsyncSession
from app.models import AuditLog, Ncr
def _fmt(value: Any) -> str | None:
if value is None:
return None
if isinstance(value, bool):
return "true" if value else "false"
return str(value)
def audit_event(
db: AsyncSession,
*,
user_id: int,
action: str,
ncr_id: int | None = None,
field_name: str | None = None,
old_value: Any = None,
new_value: Any = None,
detail: str | None = None,
) -> None:
db.add(
AuditLog(
ncr_id=ncr_id,
user_id=user_id,
action=action,
field_name=field_name,
old_value=_fmt(old_value),
new_value=_fmt(new_value),
detail=detail,
)
)
def apply_field_updates(
db: AsyncSession,
ncr: Ncr,
user_id: int,
updates: dict[str, Any],
action: str = "update",
) -> dict[str, tuple[Any, Any]]:
"""Set attributes on the NCR, writing one audit row per actually-changed
field. Returns {field: (old, new)} for the fields that changed."""
changes: dict[str, tuple[Any, Any]] = {}
for field, new_value in updates.items():
old_value = getattr(ncr, field)
if old_value == new_value:
continue
setattr(ncr, field, new_value)
changes[field] = (old_value, new_value)
audit_event(
db,
ncr_id=ncr.id,
user_id=user_id,
action=action,
field_name=field,
old_value=old_value,
new_value=new_value,
)
return changes