TEST-BE-PR-001 fix calendar schema import recursion
This commit is contained in:
@@ -9,10 +9,10 @@ BE-CAL-API-004: TimeSlot cancel schemas.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import date, time, datetime
|
||||
from datetime import date as dt_date, time as dt_time, datetime as dt_datetime
|
||||
from enum import Enum
|
||||
from pydantic import BaseModel, Field, model_validator, field_validator
|
||||
from typing import Any, Optional
|
||||
from typing import Optional
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -102,17 +102,17 @@ class SlotStatusEnum(str, Enum):
|
||||
|
||||
class TimeSlotCreate(BaseModel):
|
||||
"""Request body for creating a single calendar slot."""
|
||||
date: Optional[date] = Field(None, description="Target date (defaults to today)")
|
||||
date: Optional[dt_date] = Field(None, description="Target date (defaults to today)")
|
||||
slot_type: SlotTypeEnum = Field(..., description="work | on_call | entertainment | system")
|
||||
scheduled_at: time = Field(..., description="Planned start time HH:MM (00:00-23:00)")
|
||||
scheduled_at: dt_time = Field(..., description="Planned start time HH:MM (00:00-23:00)")
|
||||
estimated_duration: int = Field(..., ge=1, le=50, description="Duration in minutes (1-50)")
|
||||
event_type: Optional[EventTypeEnum] = Field(None, description="job | entertainment | system_event")
|
||||
event_data: Optional[dict[str, Any]] = Field(None, description="Event details JSON")
|
||||
event_data: Optional[dict] = Field(None, description="Event details JSON")
|
||||
priority: int = Field(0, ge=0, le=99, description="Priority 0-99")
|
||||
|
||||
@field_validator("scheduled_at")
|
||||
@classmethod
|
||||
def _validate_scheduled_at(cls, v: time) -> time:
|
||||
def _validate_scheduled_at(cls, v: dt_time) -> dt_time:
|
||||
if v.hour > 23:
|
||||
raise ValueError("scheduled_at hour must be between 00 and 23")
|
||||
return v
|
||||
@@ -132,7 +132,7 @@ class TimeSlotResponse(BaseModel):
|
||||
"""Response for a single TimeSlot."""
|
||||
id: int
|
||||
user_id: int
|
||||
date: date
|
||||
date: dt_date
|
||||
slot_type: str
|
||||
estimated_duration: int
|
||||
scheduled_at: str # HH:MM:SS ISO format
|
||||
@@ -140,12 +140,12 @@ class TimeSlotResponse(BaseModel):
|
||||
attended: bool
|
||||
actual_duration: Optional[int] = None
|
||||
event_type: Optional[str] = None
|
||||
event_data: Optional[dict[str, Any]] = None
|
||||
event_data: Optional[dict] = None
|
||||
priority: int
|
||||
status: str
|
||||
plan_id: Optional[int] = None
|
||||
created_at: Optional[datetime] = None
|
||||
updated_at: Optional[datetime] = None
|
||||
created_at: Optional[dt_datetime] = None
|
||||
updated_at: Optional[dt_datetime] = None
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
@@ -169,15 +169,15 @@ class TimeSlotEdit(BaseModel):
|
||||
``virtual_id`` (for plan-generated virtual slots) in the URL path.
|
||||
"""
|
||||
slot_type: Optional[SlotTypeEnum] = Field(None, description="New slot type")
|
||||
scheduled_at: Optional[time] = Field(None, description="New start time HH:MM")
|
||||
scheduled_at: Optional[dt_time] = Field(None, description="New start time HH:MM")
|
||||
estimated_duration: Optional[int] = Field(None, ge=1, le=50, description="New duration in minutes (1-50)")
|
||||
event_type: Optional[EventTypeEnum] = Field(None, description="New event type")
|
||||
event_data: Optional[dict[str, Any]] = Field(None, description="New event details JSON")
|
||||
event_data: Optional[dict] = Field(None, description="New event details JSON")
|
||||
priority: Optional[int] = Field(None, ge=0, le=99, description="New priority 0-99")
|
||||
|
||||
@field_validator("scheduled_at")
|
||||
@classmethod
|
||||
def _validate_scheduled_at(cls, v: Optional[time]) -> Optional[time]:
|
||||
def _validate_scheduled_at(cls, v: Optional[dt_time]) -> Optional[dt_time]:
|
||||
if v is not None and v.hour > 23:
|
||||
raise ValueError("scheduled_at hour must be between 00 and 23")
|
||||
return v
|
||||
@@ -214,7 +214,7 @@ class CalendarSlotItem(BaseModel):
|
||||
id: Optional[int] = Field(None, description="Real slot DB id (None for virtual)")
|
||||
virtual_id: Optional[str] = Field(None, description="Virtual slot id (None for real)")
|
||||
user_id: int
|
||||
date: date
|
||||
date: dt_date
|
||||
slot_type: str
|
||||
estimated_duration: int
|
||||
scheduled_at: str # HH:MM:SS ISO format
|
||||
@@ -222,12 +222,12 @@ class CalendarSlotItem(BaseModel):
|
||||
attended: bool
|
||||
actual_duration: Optional[int] = None
|
||||
event_type: Optional[str] = None
|
||||
event_data: Optional[dict[str, Any]] = None
|
||||
event_data: Optional[dict] = None
|
||||
priority: int
|
||||
status: str
|
||||
plan_id: Optional[int] = None
|
||||
created_at: Optional[datetime] = None
|
||||
updated_at: Optional[datetime] = None
|
||||
created_at: Optional[dt_datetime] = None
|
||||
updated_at: Optional[dt_datetime] = None
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
@@ -235,7 +235,7 @@ class CalendarSlotItem(BaseModel):
|
||||
|
||||
class CalendarDayResponse(BaseModel):
|
||||
"""Response for a single-day calendar query."""
|
||||
date: date
|
||||
date: dt_date
|
||||
user_id: int
|
||||
slots: list[CalendarSlotItem] = Field(
|
||||
default_factory=list,
|
||||
@@ -290,16 +290,16 @@ class SchedulePlanCreate(BaseModel):
|
||||
"""Request body for creating a recurring schedule plan."""
|
||||
slot_type: SlotTypeEnum = Field(..., description="work | on_call | entertainment | system")
|
||||
estimated_duration: int = Field(..., ge=1, le=50, description="Duration in minutes (1-50)")
|
||||
at_time: time = Field(..., description="Daily scheduled time (HH:MM)")
|
||||
at_time: dt_time = Field(..., description="Daily scheduled time (HH:MM)")
|
||||
on_day: Optional[DayOfWeekEnum] = Field(None, description="Day of week (sun-sat)")
|
||||
on_week: Optional[int] = Field(None, ge=1, le=4, description="Week of month (1-4)")
|
||||
on_month: Optional[MonthOfYearEnum] = Field(None, description="Month (jan-dec)")
|
||||
event_type: Optional[EventTypeEnum] = Field(None, description="job | entertainment | system_event")
|
||||
event_data: Optional[dict[str, Any]] = Field(None, description="Event details JSON")
|
||||
event_data: Optional[dict] = Field(None, description="Event details JSON")
|
||||
|
||||
@field_validator("at_time")
|
||||
@classmethod
|
||||
def _validate_at_time(cls, v: time) -> time:
|
||||
def _validate_at_time(cls, v: dt_time) -> dt_time:
|
||||
if v.hour > 23:
|
||||
raise ValueError("at_time hour must be between 00 and 23")
|
||||
return v
|
||||
@@ -325,10 +325,10 @@ class SchedulePlanResponse(BaseModel):
|
||||
on_week: Optional[int] = None
|
||||
on_month: Optional[str] = None
|
||||
event_type: Optional[str] = None
|
||||
event_data: Optional[dict[str, Any]] = None
|
||||
event_data: Optional[dict] = None
|
||||
is_active: bool
|
||||
created_at: Optional[datetime] = None
|
||||
updated_at: Optional[datetime] = None
|
||||
created_at: Optional[dt_datetime] = None
|
||||
updated_at: Optional[dt_datetime] = None
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
@@ -352,19 +352,19 @@ class SchedulePlanEdit(BaseModel):
|
||||
"""
|
||||
slot_type: Optional[SlotTypeEnum] = Field(None, description="New slot type")
|
||||
estimated_duration: Optional[int] = Field(None, ge=1, le=50, description="New duration in minutes (1-50)")
|
||||
at_time: Optional[time] = Field(None, description="New daily time (HH:MM)")
|
||||
at_time: Optional[dt_time] = Field(None, description="New daily time (HH:MM)")
|
||||
on_day: Optional[DayOfWeekEnum] = Field(None, description="New day of week (sun-sat), use 'clear' param to remove")
|
||||
on_week: Optional[int] = Field(None, ge=1, le=4, description="New week of month (1-4), use 'clear' param to remove")
|
||||
on_month: Optional[MonthOfYearEnum] = Field(None, description="New month (jan-dec), use 'clear' param to remove")
|
||||
event_type: Optional[EventTypeEnum] = Field(None, description="New event type")
|
||||
event_data: Optional[dict[str, Any]] = Field(None, description="New event details JSON")
|
||||
event_data: Optional[dict] = Field(None, description="New event details JSON")
|
||||
clear_on_day: bool = Field(False, description="Clear on_day (set to NULL)")
|
||||
clear_on_week: bool = Field(False, description="Clear on_week (set to NULL)")
|
||||
clear_on_month: bool = Field(False, description="Clear on_month (set to NULL)")
|
||||
|
||||
@field_validator("at_time")
|
||||
@classmethod
|
||||
def _validate_at_time(cls, v: Optional[time]) -> Optional[time]:
|
||||
def _validate_at_time(cls, v: Optional[dt_time]) -> Optional[dt_time]:
|
||||
if v is not None and v.hour > 23:
|
||||
raise ValueError("at_time hour must be between 00 and 23")
|
||||
return v
|
||||
@@ -403,7 +403,7 @@ class DateListResponse(BaseModel):
|
||||
Returns only dates that have at least one materialized (real) future
|
||||
slot. Pure plan-generated (virtual) dates are excluded.
|
||||
"""
|
||||
dates: list[date] = Field(
|
||||
dates: list[dt_date] = Field(
|
||||
default_factory=list,
|
||||
description="Sorted list of future dates with materialized slots",
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user