"""Pydantic request models for close tasks (PR2).""" from __future__ import annotations from pydantic import BaseModel, Field, field_validator from app.domains.finance.close_models import ( AI_WORK_VALUES, FREQUENCIES, TASK_STATUSES, ) class TaskCreateBody(BaseModel): process: str = Field(..., max_length=64) description: str = Field(..., min_length=1) sub_process: str = Field("", max_length=128) owner_person_id: str | None = Field(None, max_length=36) owner_label: str | None = Field(None, max_length=64) frequency: str = Field("monthly") calendar_day: str = Field("On going", max_length=16) estimated_hours: float | None = Field(None, ge=0) submit_to_fpa: bool = False ai_work: str = Field("none") link: str | None = Field(None, max_length=512) entity_codes: list[str] | None = None @field_validator("frequency") @classmethod def _vf(cls, v: str) -> str: if v not in FREQUENCIES: raise ValueError(f"frequency must be one of {FREQUENCIES}") return v @field_validator("ai_work") @classmethod def _va(cls, v: str) -> str: if v not in AI_WORK_VALUES: raise ValueError(f"ai_work must be one of {AI_WORK_VALUES}") return v class TaskUpdateBody(BaseModel): process: str | None = Field(None, max_length=64) description: str | None = Field(None, min_length=1) sub_process: str | None = Field(None, max_length=128) owner_person_id: str | None = Field(None, max_length=36) owner_label: str | None = Field(None, max_length=64) frequency: str | None = None calendar_day: str | None = Field(None, max_length=16) estimated_hours: float | None = Field(None, ge=0) submit_to_fpa: bool | None = None ai_work: str | None = None link: str | None = Field(None, max_length=512) entity_codes: list[str] | None = None class TaskStatusBody(BaseModel): status: str @field_validator("status") @classmethod def _v(cls, v: str) -> str: if v not in TASK_STATUSES: raise ValueError(f"status must be one of {TASK_STATUSES}") return v class TaskCommentBody(BaseModel): comment: str | None = Field(None, max_length=4000) commenter_person_id: str | None = Field(None, max_length=36) commenter_label: str | None = Field(None, max_length=64) class RollForwardBody(BaseModel): from_period: str = Field(..., description="Source period 'YYYY-MM'.") to_period: str = Field(..., description="New period 'YYYY-MM'.") class BulkStatusBody(BaseModel): task_ids: list[int] = Field(..., min_length=1, max_length=500) status: str @field_validator("status") @classmethod def _v(cls, v: str) -> str: if v not in TASK_STATUSES: raise ValueError(f"status must be one of {TASK_STATUSES}") return v class BulkReassignBody(BaseModel): task_ids: list[int] = Field(..., min_length=1, max_length=500) owner_person_id: str | None = Field(None, max_length=36) owner_label: str | None = Field(None, max_length=64) class EntityMapBody(BaseModel): legal_entity_id: str | None = Field(None, max_length=36) legal_entity_name: str | None = Field(None, max_length=255) class TemplateOwnerBody(BaseModel): owner_person_id: str | None = Field(None, max_length=36) owner_label: str | None = Field(None, max_length=64)