126 lines
5.8 KiB
Python
126 lines
5.8 KiB
Python
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))
|
|
|
|
|
|
@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)
|
|
)
|