Integrate formal decisions with cases
This commit is contained in:
@@ -32,6 +32,7 @@ from govoplan_cases.backend.manifest import (
|
||||
UPDATE_SCOPE,
|
||||
)
|
||||
from govoplan_cases.backend.schemas import (
|
||||
CaseDecisionRequest,
|
||||
CaseHistoryResponse,
|
||||
CaseListResponse,
|
||||
CaseStatusWriteRequest,
|
||||
@@ -40,6 +41,15 @@ from govoplan_cases.backend.schemas import (
|
||||
CaseUpdateRequest,
|
||||
CaseWriteRequest,
|
||||
)
|
||||
from govoplan_cases.backend.decision_path import (
|
||||
CaseDecisionCommand,
|
||||
CaseDecisionError,
|
||||
CaseDecisionPath,
|
||||
CaseDecisionUnavailable,
|
||||
DECISION_READ_SCOPE,
|
||||
DECISION_SENSITIVE_READ_SCOPE,
|
||||
DECISION_WRITE_SCOPE,
|
||||
)
|
||||
from govoplan_cases.backend.service import (
|
||||
CaseStoreError,
|
||||
can_access_case,
|
||||
@@ -66,7 +76,9 @@ def _require(principal: ApiPrincipal, scope: str) -> None:
|
||||
def _error(exc: Exception) -> HTTPException:
|
||||
message = str(exc)
|
||||
lowered = message.casefold()
|
||||
if isinstance(exc, LookupError):
|
||||
if isinstance(exc, CaseDecisionUnavailable):
|
||||
code = status.HTTP_424_FAILED_DEPENDENCY
|
||||
elif isinstance(exc, LookupError):
|
||||
code = 404
|
||||
elif isinstance(exc, PermissionError):
|
||||
code = 403
|
||||
@@ -206,6 +218,78 @@ def api_create_case(
|
||||
return item.to_dict()
|
||||
|
||||
|
||||
@router.get("/{case_id}/decisions", response_model=dict[str, list[dict[str, Any]]])
|
||||
def api_case_decisions(
|
||||
case_id: str,
|
||||
session: Session = Depends(get_session),
|
||||
principal: ApiPrincipal = Depends(get_api_principal),
|
||||
) -> dict[str, list[dict[str, Any]]]:
|
||||
_require(principal, READ_SCOPE)
|
||||
_require(principal, DECISION_READ_SCOPE)
|
||||
try:
|
||||
items = CaseDecisionPath(get_registry()).linked(
|
||||
session,
|
||||
principal,
|
||||
case_id=case_id,
|
||||
)
|
||||
except (
|
||||
CaseDecisionError,
|
||||
InstitutionalContextError,
|
||||
LookupError,
|
||||
PermissionError,
|
||||
) as exc:
|
||||
raise _error(exc) from exc
|
||||
disclose = has_scope(principal, DECISION_SENSITIVE_READ_SCOPE)
|
||||
return {
|
||||
"decisions": [
|
||||
item.to_dict(include_protected=disclose)
|
||||
for item in items
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@router.post(
|
||||
"/{case_id}/decisions",
|
||||
response_model=dict[str, Any],
|
||||
status_code=status.HTTP_201_CREATED,
|
||||
)
|
||||
def api_record_case_decision(
|
||||
case_id: str,
|
||||
payload: CaseDecisionRequest,
|
||||
session: Session = Depends(get_session),
|
||||
principal: ApiPrincipal = Depends(get_api_principal),
|
||||
) -> dict[str, Any]:
|
||||
_require(principal, UPDATE_SCOPE)
|
||||
_require(principal, DECISION_WRITE_SCOPE)
|
||||
try:
|
||||
result = CaseDecisionPath(get_registry()).record(
|
||||
session,
|
||||
principal,
|
||||
case_id=case_id,
|
||||
command=CaseDecisionCommand(
|
||||
expected_case_revision=payload.expected_case_revision,
|
||||
effective_at=payload.effective_at,
|
||||
decision_type=payload.decision_type,
|
||||
operative_result=payload.operative_result,
|
||||
reasoning=payload.reasoning,
|
||||
conditions=tuple(payload.conditions),
|
||||
change_reason=payload.change_reason,
|
||||
idempotency_key=payload.idempotency_key,
|
||||
),
|
||||
)
|
||||
session.commit()
|
||||
except (
|
||||
CaseDecisionError,
|
||||
InstitutionalContextError,
|
||||
LookupError,
|
||||
PermissionError,
|
||||
ValueError,
|
||||
) as exc:
|
||||
session.rollback()
|
||||
raise _error(exc) from exc
|
||||
return result.to_dict()
|
||||
|
||||
|
||||
@router.get("/{case_id}", response_model=dict[str, Any])
|
||||
def api_get_case(
|
||||
case_id: str,
|
||||
|
||||
Reference in New Issue
Block a user