o2o-negosium-original/negodata/backend/router/v1/quotation/protocol.py
Mina Choi eb6612af1c [refactor] negodata: 도메인 코드값 enum 정비 — 백엔드 정본 + 프론트 생성타입 사용
- 백엔드: 도메인 enum CodeEnum 상속(x-enum-varnames) → orval이 이름 있는 enum 생성. 응답 필드 enum 타입 지정(요청은 int 유지). ENUM_LABELS/DOMAIN_ENUMS·/v1/enums 제거
- 프론트: 생성 enum + 라벨맵으로 교체(매직넘버·발명 어휘 제거), 견적·세션 상태 코드화, role/delivery 라벨 프론트 소유
- 동반 정리: unwrap 캐스트·목업(buildSessions·데모)·死코드 제거, mapItem toMinPrice dedupe

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 17:06:26 +09:00

168 lines
5.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import uuid
from datetime import datetime
from typing import Any, Optional
from pydantic import ConfigDict
from common.enums import CardType, ChatSender, DeliveryType, QuotationStatus, QuotationType, SessionStatus
from common.models.gmodel import Res_PageProtocol, Res_WebPacketProtocol, WebPacketProtocol
class QuotationProtocol(WebPacketProtocol):
pass
class Req_CreateQuotation(QuotationProtocol):
qt_setting_id: uuid.UUID
version_id: Optional[uuid.UUID] = None # 미지정 시 기본 전략 버전(card.versions 시드)으로 채움
name: str = ""
number: str = ""
type: int = 0
status: int = 0
start_time: Optional[datetime] = None # 미지정 시 생성 시각(UTC)
end_time: datetime
round: int = 1
manager_name: Optional[str] = None
manager_email: Optional[str] = None
manager_contact_number: Optional[str] = None
memo: Optional[str] = None
item_ids: list[uuid.UUID] = [] # 협상 대상 상품. item×supplier 조합마다 세션 1개 생성
supplier_ids: list[uuid.UUID] = [] # 협상 초청 공급사
card_ids: list[uuid.UUID] = [] # 선택 협상카드. 버전을 만들어 묶고 quotation.version_id 로 연결
class QuotationData(WebPacketProtocol):
model_config = ConfigDict(from_attributes=True)
qt_id: uuid.UUID
user_id: uuid.UUID
qt_setting_id: uuid.UUID
version_id: uuid.UUID
name: str
number: str
type: QuotationType
round: int = 1
status: QuotationStatus
start_time: datetime
end_time: datetime
manager_name: Optional[str] = None
manager_email: Optional[str] = None
manager_contact_number: Optional[str] = None
memo: Optional[str] = None
iteration: int = 0
preferred_sp_yn: Optional[bool] = None
preferred_sp_id: Optional[uuid.UUID] = None
preferred_sp_name: Optional[str] = None
equal_bid_yn: Optional[bool] = None
equal_bid_data: Optional[Any] = None
participation_count: int = 0 # 견적별 참여 협력사 수(세션 distinct supplier). 목록 집계로 채움.
item_id: Optional[uuid.UUID] = None # 대표 상품 id(세션의 첫 item). 목록 조인으로 채움.
item_name: Optional[str] = None # 대표 상품명. 목록 조인으로 채움.
created_at: Optional[datetime] = None
updated_at: Optional[datetime] = None
class Res_Quotation(Res_WebPacketProtocol):
quotation: Optional[QuotationData] = None
class Res_QuotationList(Res_PageProtocol):
quotations: list[QuotationData] = []
class Res_DeleteQuotation(Res_WebPacketProtocol):
pass
class SessionData(WebPacketProtocol):
model_config = ConfigDict(from_attributes=True)
session_id: uuid.UUID
qt_id: uuid.UUID
supplier_id: uuid.UUID
item_id: uuid.UUID
qt_number: str
qt_round: int
qt_type: QuotationType
target_price: int
status: SessionStatus
bid_price: Optional[int] = None
bid_at: Optional[datetime] = None
end_time: datetime
reject_reason: Optional[str] = None
reject_price: Optional[int] = None
reject_delivery_type: Optional[DeliveryType] = None
url: str = "" # 세션 chat 실행 URL(공급사 협상 프론트). DB 미저장 — session_id 로 구성
class AsyncJob(WebPacketProtocol):
status: str = ""
message: str = ""
class Res_CreateQuotation(Res_WebPacketProtocol):
quotation: Optional[QuotationData] = None
sessions: list[SessionData] = [] # 견적 생성과 함께 만들어진 협상 세션(각 url 포함)
async_job: Optional[AsyncJob] = None
class Res_QuotationStatus(Res_WebPacketProtocol):
qt_id: Optional[uuid.UUID] = None
job_status: int = 0
message: str = ""
class Res_QuotationSessions(Res_WebPacketProtocol):
qt_id: Optional[uuid.UUID] = None
sessions: list[SessionData] = []
total: int = 0
class ChatMessageData(WebPacketProtocol):
model_config = ConfigDict(from_attributes=True)
chat_id: uuid.UUID
session_id: uuid.UUID
card_id: Optional[uuid.UUID] = None
index: int
sender: ChatSender
target_price: int
card_used_yn: Optional[bool] = None
indicator_value: Optional[float] = None
card_type: Optional[CardType] = None
script: Optional[str] = None
step: Optional[str] = None
class Res_SessionChat(Res_WebPacketProtocol):
session_id: Optional[uuid.UUID] = None
messages: list[ChatMessageData] = []
class Res_QuotationResult(Res_WebPacketProtocol):
qt_id: Optional[uuid.UUID] = None
winner_supplier_id: Optional[uuid.UUID] = None
winner_supplier_name: Optional[str] = None
is_equal_bid: Optional[bool] = None
equal_bid_data: Optional[Any] = None
result_count: int = 0
class QuotationCardData(WebPacketProtocol):
session_card_id: uuid.UUID
qt_id: Optional[uuid.UUID] = None
nego_card_id: Optional[uuid.UUID] = None
wild_card_id: Optional[uuid.UUID] = None
type: Optional[CardType] = None
number: Optional[str] = None
name: Optional[str] = None
script: Optional[str] = None # 협상 멘트(평문)
edit_script: Optional[Any] = None # 협상 멘트(Slate 서식본)
condition: Optional[str] = None # 와일드카드 전용: 사용 조건(트리거)
memo: Optional[str] = None # 와일드카드 전용: 메모
class Res_QuotationCards(Res_WebPacketProtocol):
qt_id: Optional[uuid.UUID] = None
cards: list[QuotationCardData] = []