""" Audit Session Pydantic schemas — extracted from compliance/api/schemas.py. Phase 1 Step 3: the monolithic ``compliance.api.schemas`` module is being split per domain under ``compliance.schemas``. This module is re-exported from ``compliance.api.schemas`` for backwards compatibility. """ from datetime import datetime, date from typing import Optional, List, Any, Dict from pydantic import BaseModel, ConfigDict, Field from compliance.schemas.common import ( PaginationMeta, RegulationType, ControlType, ControlDomain, ControlStatus, RiskLevel, EvidenceStatus, ) # ============================================================================ # Audit Session & Sign-off Schemas (Phase 3 - Sprint 3) # ============================================================================ class AuditResult(str): """Audit result values for sign-off.""" COMPLIANT = "compliant" COMPLIANT_WITH_NOTES = "compliant_notes" NON_COMPLIANT = "non_compliant" NOT_APPLICABLE = "not_applicable" PENDING = "pending" class AuditSessionStatus(str): """Audit session status values.""" DRAFT = "draft" IN_PROGRESS = "in_progress" COMPLETED = "completed" ARCHIVED = "archived" class CreateAuditSessionRequest(BaseModel): """Request to create a new audit session.""" name: str = Field(..., min_length=1, max_length=200) description: Optional[str] = None auditor_name: str = Field(..., min_length=1, max_length=100) auditor_email: Optional[str] = None auditor_organization: Optional[str] = None regulation_codes: Optional[List[str]] = None # Filter by regulations class UpdateAuditSessionRequest(BaseModel): """Request to update an audit session.""" name: Optional[str] = Field(None, min_length=1, max_length=200) description: Optional[str] = None status: Optional[str] = None class AuditSessionSummary(BaseModel): """Summary of an audit session for list views.""" id: str name: str auditor_name: str status: str total_items: int completed_items: int completion_percentage: float created_at: datetime started_at: Optional[datetime] = None completed_at: Optional[datetime] = None model_config = ConfigDict(from_attributes=True) class AuditSessionResponse(AuditSessionSummary): """Full response for an audit session.""" description: Optional[str] = None auditor_email: Optional[str] = None auditor_organization: Optional[str] = None regulation_ids: Optional[List[str]] = None compliant_count: int = 0 non_compliant_count: int = 0 updated_at: datetime model_config = ConfigDict(from_attributes=True) class AuditSessionListResponse(BaseModel): """List response for audit sessions.""" sessions: List[AuditSessionSummary] total: int class AuditSessionDetailResponse(AuditSessionResponse): """Detailed response including statistics breakdown.""" statistics: Optional["AuditStatistics"] = None class SignOffRequest(BaseModel): """Request to sign off a single requirement.""" result: str = Field(..., description="Audit result: compliant, compliant_notes, non_compliant, not_applicable, pending") notes: Optional[str] = None sign: bool = Field(False, description="Whether to create digital signature") class SignOffResponse(BaseModel): """Response for a sign-off operation.""" id: str session_id: str requirement_id: str result: str notes: Optional[str] = None is_signed: bool signature_hash: Optional[str] = None signed_at: Optional[datetime] = None signed_by: Optional[str] = None created_at: datetime updated_at: Optional[datetime] = None model_config = ConfigDict(from_attributes=True) class AuditChecklistItem(BaseModel): """A single item in the audit checklist.""" requirement_id: str regulation_code: str article: str paragraph: Optional[str] = None title: str description: Optional[str] = None # Current audit state current_result: str = "pending" # AuditResult notes: Optional[str] = None is_signed: bool = False signed_at: Optional[datetime] = None signed_by: Optional[str] = None # Context info evidence_count: int = 0 controls_mapped: int = 0 implementation_status: Optional[str] = None # Priority priority: int = 2 class AuditStatistics(BaseModel): """Statistics for an audit session.""" total: int compliant: int compliant_with_notes: int non_compliant: int not_applicable: int pending: int completion_percentage: float class AuditChecklistResponse(BaseModel): """Response for audit checklist endpoint.""" session: AuditSessionSummary items: List[AuditChecklistItem] pagination: PaginationMeta statistics: AuditStatistics class AuditChecklistFilterRequest(BaseModel): """Filter options for audit checklist.""" regulation_code: Optional[str] = None result_filter: Optional[str] = None # "pending", "compliant", "non_compliant", etc. search: Optional[str] = None signed_only: bool = False