from typing import Optional from fastapi import APIRouter, Depends, Path, Query from fastapi.security import HTTPAuthorizationCredentials from common.models.gmodel import UserInfo from router.v1.validator.dependencies import IsValidAccessToken, RemoveNoneResponse, security from services.negotiation_service import NegotiationService from .protocol import ( Req_ExtraInfo, Req_Reject, Req_Renegotiation, Res_ExtraInfo, Res_Participate, Res_Reject, Res_Renegotiation, Res_SessionList, ) router = APIRouter(prefix="/v1/negotiation", tags=["Negotiation"], responses={404: {"description": "Not found"}}) @router.get( path="/sessions", response_model=Res_SessionList, summary="협상 세션 목록", description="로그인한 공급사의 협상 세션 목록. 필터(status/qt_type, 정수 코드)·페이지네이션 지원. 기본 정렬(order 미지정)은 '할 일(협상생성·협상중) 우선 + 마감 임박순', 종료(완료·미참여·거부)는 하단·최근순. order 를 주면 그룹 없이 전체 마감순으로 정렬.", ) async def list_sessions( user_info: UserInfo = Depends(IsValidAccessToken), credentials: HTTPAuthorizationCredentials = Depends(security), service: NegotiationService = Depends(), status: Optional[int] = Query(None, description="세션 상태 코드 (SessionStatus)"), qt_type: Optional[int] = Query(None, description="견적 유형 코드 (QtType: 1=재협상, 2=재견적, 3=신규협상, 4=신규견적)"), order: Optional[str] = Query(None, description="마감일 전체 정렬: asc(임박순)/desc(여유순). 미지정 시 기본 그룹 정렬('할 일' 우선 → 종료는 하단·최근순). 지정하면 그룹 없이 전체를 마감 기준으로 정렬."), page: int = Query(1, ge=1, description="페이지 (1부터)"), page_size: int = Query(20, ge=1, le=100, description="페이지당 건수 (1~100)"), keyword: Optional[str] = Query(None, description="검색어 — 견적번호·상품명·상품코드 부분일치(대소문자 무시)"), result: Optional[int] = Query(None, description="결과 필터(SessionResult): 1=낙찰 2=미낙찰 3=결렬(개찰). 미지정 시 전체"), ): return RemoveNoneResponse( await service.list_sessions(user_info, credentials.credentials, status, qt_type, order, page, page_size, keyword, result) ) @router.post( path="/sessions/{session_id}/participate", response_model=Res_Participate, summary="협상 참여", description="세션에 참여한다. 소유(공급사)·세션상태·견적마감·마감시간 검증 후 협상생성→협상중, 견적→견적진행중으로 전이.", ) async def participate( session_id: str = Path(description="대상 협상 세션 uuid"), user_info: UserInfo = Depends(IsValidAccessToken), credentials: HTTPAuthorizationCredentials = Depends(security), service: NegotiationService = Depends(), ): return RemoveNoneResponse(await service.participate(user_info, credentials.credentials, session_id)) @router.post( path="/sessions/{session_id}/reject", response_model=Res_Reject, summary="협상 거부", description="세션 참여를 거부하거나 진행 중인 협상을 거부한다. 소유(공급사)·세션상태(완료/미참여/거부 불가)·견적마감·마감시간 검증 후 협상거부로 전이하고 사유·공급 희망 가격·의견을 저장.", ) async def reject( session_id: str = Path(description="대상 협상 세션 uuid"), req: Req_Reject = ..., user_info: UserInfo = Depends(IsValidAccessToken), credentials: HTTPAuthorizationCredentials = Depends(security), service: NegotiationService = Depends(), ): return RemoveNoneResponse( await service.reject( user_info, credentials.credentials, session_id, req.reject_reason, req.reject_price, req.opinion, ) ) @router.post( path="/sessions/{session_id}/extra-info", response_model=Res_ExtraInfo, summary="협상완료 부가정보 저장", description="협상 타결(완료) 세션에 부가정보(표준납기/MOQ/발주배수/배송유형 등, 회사 정의 session_fields)를 저장한다. 본인 공급사의 완료 세션만 허용.", ) async def save_extra_info( session_id: str = Path(description="대상 협상 세션 uuid"), req: Req_ExtraInfo = ..., user_info: UserInfo = Depends(IsValidAccessToken), credentials: HTTPAuthorizationCredentials = Depends(security), service: NegotiationService = Depends(), ): return RemoveNoneResponse(await service.save_extra_info(user_info, credentials.credentials, session_id, req)) @router.post( path="/session/{session_id}/renegotiation", response_model=Res_Renegotiation, summary="재협상 요청", description="낙찰 없이 마감된(개찰) 건에 대해 공급사가 재협상을 요청한다. 담당자 승인 시 다음 라운드가 생성된다. 본인 공급사의 마지막 라운드 세션만 허용.", ) async def request_renegotiation( req: Req_Renegotiation, session_id: str = Path(..., description="협상 세션 uuid"), user_info: UserInfo = Depends(IsValidAccessToken), credentials: HTTPAuthorizationCredentials = Depends(security), service: NegotiationService = Depends(), ): return RemoveNoneResponse( await service.request_renegotiation(user_info, credentials.credentials, session_id, req) ) @router.delete( path="/session/{session_id}/renegotiation", response_model=Res_Renegotiation, summary="재협상 요청 철회", description="심사 대기(PENDING) 중인 본인 요청을 철회한다.", ) async def cancel_renegotiation( session_id: str = Path(..., description="협상 세션 uuid"), user_info: UserInfo = Depends(IsValidAccessToken), credentials: HTTPAuthorizationCredentials = Depends(security), service: NegotiationService = Depends(), ): return RemoveNoneResponse( await service.cancel_renegotiation(user_info, credentials.credentials, session_id) )