Files
ai-contract-platform/backend/app/api/contract_approvals.py
T

158 lines
5.8 KiB
Python

from typing import Optional
from fastapi import APIRouter, Depends, Header, Request
from pydantic import BaseModel, Field
from sqlalchemy.orm import Session
from app.core.response import success_response
from app.db import get_db_session
from app.services.audit_log_service import AuditLogService
from app.services.auth_service import AuthService
from app.services.contract_approval_service import ContractApprovalService
router = APIRouter(prefix="/contract-approvals", tags=["contract-approvals"])
class ContractApprovalSubmitRequest(BaseModel):
contract_id: str = Field(..., min_length=1, max_length=64)
title: Optional[str] = Field(default=None, max_length=200)
comment: Optional[str] = Field(default=None, max_length=2000)
assignee_id: Optional[str] = Field(default=None, max_length=64)
assignee_name: Optional[str] = Field(default=None, max_length=100)
step_type: str = Field(default="legal_review", max_length=64)
class ContractApprovalDecisionRequest(BaseModel):
decision: str = Field(..., min_length=1, max_length=32)
comment: Optional[str] = Field(default=None, max_length=2000)
def get_contract_approval_service(db: Session = Depends(get_db_session)) -> ContractApprovalService:
return ContractApprovalService(db)
def get_audit_log_service(db: Session = Depends(get_db_session)) -> AuditLogService:
return AuditLogService(db)
def require_current_user(
authorization: Optional[str] = Header(default=None),
db: Session = Depends(get_db_session),
):
return AuthService(db).require_current_user(authorization)
@router.get("")
def list_contract_approvals(
page: int = 1,
page_size: int = 20,
status_value: Optional[str] = None,
scope: str = "assigned_to_me",
contract_approval_service: ContractApprovalService = Depends(get_contract_approval_service),
current_user: dict = Depends(require_current_user),
):
return success_response(
contract_approval_service.list_approvals(
current_user=current_user,
page=page,
page_size=page_size,
status_value=status_value,
scope=scope,
)
)
@router.get("/assignees")
def list_contract_approval_assignees(
contract_approval_service: ContractApprovalService = Depends(get_contract_approval_service),
current_user: dict = Depends(require_current_user),
):
return success_response(contract_approval_service.list_assignees(current_user))
@router.get("/contracts/{contract_id}")
def list_contract_approval_history(
contract_id: str,
contract_approval_service: ContractApprovalService = Depends(get_contract_approval_service),
current_user: dict = Depends(require_current_user),
):
return success_response(contract_approval_service.list_contract_approvals(current_user, contract_id))
@router.post("")
def submit_contract_approval(
payload: ContractApprovalSubmitRequest,
request: Request,
contract_approval_service: ContractApprovalService = Depends(get_contract_approval_service),
audit_log_service: AuditLogService = Depends(get_audit_log_service),
current_user: dict = Depends(require_current_user),
):
result = contract_approval_service.submit_approval(
current_user=current_user,
contract_id=payload.contract_id,
title=payload.title,
comment=payload.comment,
assignee_id=payload.assignee_id,
assignee_name=payload.assignee_name,
step_type=payload.step_type,
)
audit_log_service.record_event(
tenant_id=current_user.get("tenant_id"),
user_id=current_user.get("id"),
action="contract_approval_submit",
resource_type="contract_approval",
resource_id=result.get("id"),
detail_json={
"contract_id": result.get("contract_id"),
"approval_id": result.get("id"),
"title": result.get("title"),
"step_type": result.get("step_type"),
"submitter_id": result.get("submitter_id"),
"assignee_id": result.get("assignee_id"),
"assignee_name": result.get("assignee_name"),
"status": result.get("status"),
"audit_key": result.get("audit_key"),
},
ip_address=request.client.host if request.client else None,
user_agent=request.headers.get("user-agent"),
)
return success_response(result)
@router.post("/{approval_id}/decision")
def decide_contract_approval(
approval_id: str,
payload: ContractApprovalDecisionRequest,
request: Request,
contract_approval_service: ContractApprovalService = Depends(get_contract_approval_service),
audit_log_service: AuditLogService = Depends(get_audit_log_service),
current_user: dict = Depends(require_current_user),
):
result = contract_approval_service.decide_approval(
current_user=current_user,
approval_id=approval_id,
decision=payload.decision,
comment=payload.comment,
)
audit_log_service.record_event(
tenant_id=current_user.get("tenant_id"),
user_id=current_user.get("id"),
action=f"contract_approval_{result.get('status')}",
resource_type="contract_approval",
resource_id=result.get("id"),
detail_json={
"contract_id": result.get("contract_id"),
"approval_id": result.get("id"),
"decision": payload.decision,
"comment": result.get("comment"),
"decided_by": result.get("decided_by"),
"decided_by_name": result.get("decided_by_name"),
"decided_at": result.get("decided_at"),
"status": result.get("status"),
"audit_key": result.get("audit_key"),
},
ip_address=request.client.host if request.client else None,
user_agent=request.headers.get("user-agent"),
)
return success_response(result)