import uuid from datetime import datetime from typing import Optional from pydantic import Field from common.models.gmodel import Res_WebPacketProtocol, WebPacketProtocol class DashboardProtocol(WebPacketProtocol): pass class DashboardQuotationRef(WebPacketProtocol): qt_id: uuid.UUID name: str = "" end_time: Optional[datetime] = None # 마감 임박 위젯에서만 채움(나머지는 None) class DashboardActionList(WebPacketProtocol): total: int = 0 # 전수 COUNT(최신 N개 아님) items: list[DashboardQuotationRef] = [] # 정렬해서 상위 N개만(클릭 → /quotation?detail=qt_id) class DashboardEmailUnsentItem(WebPacketProtocol): qt_id: uuid.UUID name: str = "" unsent_count: int = 0 # 해당 견적의 미발송 세션(협력사) 수 class DashboardEmailUnsent(WebPacketProtocol): total: int = 0 # 미발송 견적 수(distinct qt_id) — 리스트와 일치하는 헤드라인 숫자 quotations: list[DashboardEmailUnsentItem] = [] # 견적 단위로 묶은 상위 N개 class DashboardScope(WebPacketProtocol): in_progress: int = 0 # 진행중(마감 전) 견적 수 = status != 마감 this_month: int = 0 # 이번 달 생성 견적 수(created_at 기준) awarded_this_month: int = 0 # 이번 달 낙찰 견적 수(CLOSED·preferred_sp_yn=True, 마감 시각 기준) deadline_soon: DashboardActionList = Field(default_factory=DashboardActionList) email_unsent: DashboardEmailUnsent = Field(default_factory=DashboardEmailUnsent) awarded: DashboardActionList = Field(default_factory=DashboardActionList) # 낙찰(단독 최저가 선정, preferred_sp_yn=True) equal_bid: DashboardActionList = Field(default_factory=DashboardActionList) # 동가 마감(자동 다음 차수 생성, equal_bid_yn=True) ruptured: DashboardActionList = Field(default_factory=DashboardActionList) # 결렬(낙찰자 없이 마감) class Res_DashboardSummary(Res_WebPacketProtocol): company: DashboardScope = Field(default_factory=DashboardScope) # 회사 전체(company_id 스코프) mine: DashboardScope = Field(default_factory=DashboardScope) # 내가 만든 견적(user_id 추가 스코프)