o2o-negosium-original/backend/common/enums.py

186 lines
7.1 KiB
Python
Raw Permalink 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.

from enum import Enum, auto
from fastapi import HTTPException
class ErrorType(Enum):
"""서버 전역 결과 코드. Res_WebPacketProtocol.result 에 담겨 클라이언트로 전달된다.
HTTP status 와 겹치지 않도록 구간을 분리해서 관리한다.
"""
SUCCESS = 0
FAIL = 1
# DB / Redis 에러
DB_RUN_FAILED = 10
DB_ALREADY_SAME_KEY = auto()
DB_INVALID_KEY = auto()
DB_EMPTY_DATA = auto()
DB_INVALID_TYPE = auto()
# 요청/직렬화 에러
JSON_PARSE_ERROR = 100
INVALID_REQUEST_DATA = auto()
INTERNAL_EXCEPTION = auto()
# http 에러 코드와 겹치지 않게 설정 - router 전용 예외 발생 옵션
HTTP_INVALID_CLIENT_REQUEST = 419
HTTP_TO_MANY_REQUEST = 429
HTTP_INVALID_CLIENT_ACCESS = 433
HTTP_ACCESS_TOKEN_EXPIRED = 434
HTTP_REFRESH_TOKEN_EXPIRED = 435
HTTP_INVALID_TOKEN_ACCESS = 436
# 계정 관련 에러
ACCOUNT_INVALID_INFO = 1200
ACCOUNT_ALREADY_EXIST = auto()
ACCOUNT_BLOCKED_USER = auto()
TOKEN_REVOKED = auto() # 제시된 토큰이 저장된 토큰과 불일치(로그아웃/타기기 로그인으로 교체됨)
# 협상(negotiation) 관련 에러 — 프론트 toast 용 코드
NEGO_FORBIDDEN = 1300 # 공급사 불일치(권한 없음)
NEGO_NOT_PARTICIPABLE = auto() # 1301 세션 상태가 미참여/협상거부라 참여 불가
NEGO_QUOTATION_CLOSED = auto() # 1302 견적 마감 상태
NEGO_DEADLINE_PASSED = auto() # 1303 견적 마감 시간 초과
NEGO_NOT_FOUND = auto() # 1304 세션/견적 없음
# 채팅(chat) 관련 에러
CHAT_NOT_IN_PROGRESS = 1400 # 협상중 상태가 아니라 대화 불가(미참여/완료/거부)
CHAT_PRICE_OUT_OF_RANGE = auto() # 1401 제시가가 허용 범위를 벗어남
CHAT_AGENT_UNAVAILABLE = auto() # 1402 협상 에이전트(agent) 호출 실패
CHAT_IN_PROGRESS = auto() # 1403 직전 턴 처리 중(동시 전송 가드)
CHAT_INPUT_MODE_MISMATCH = auto() # 1404 직전 봇이 요구한 입력 모드와 보낸 입력이 불일치(잘못된 버튼/타입) → 화면 리싱크 필요
CHAT_AGENT_TIMEOUT = auto() # 1405 agent 응답 타임아웃(처리됐을 수 있음 — 롤백/재시도 시 desync 위험)
# ErrorType 의 HTTP_* 값과 status_code 를 맞춰 router 단에서 raise 한다.
EXCEPTION_INVALID_CLIENT_REQUEST = HTTPException(status_code=ErrorType.HTTP_INVALID_CLIENT_REQUEST.value, detail=ErrorType.HTTP_INVALID_CLIENT_REQUEST.name)
EXCEPTION_TO_MANY_REQUEST = HTTPException(status_code=ErrorType.HTTP_TO_MANY_REQUEST.value, detail=ErrorType.HTTP_TO_MANY_REQUEST.name)
EXCEPTION_INVALID_CLIENT_ACCESS = HTTPException(status_code=ErrorType.HTTP_INVALID_CLIENT_ACCESS.value, detail=ErrorType.HTTP_INVALID_CLIENT_ACCESS.name)
EXCEPTION_ACCESS_TOKEN_EXPIRED = HTTPException(status_code=ErrorType.HTTP_ACCESS_TOKEN_EXPIRED.value, detail=ErrorType.HTTP_ACCESS_TOKEN_EXPIRED.name)
EXCEPTION_REFRESH_TOKEN_EXPIRED = HTTPException(status_code=ErrorType.HTTP_REFRESH_TOKEN_EXPIRED.value, detail=ErrorType.HTTP_REFRESH_TOKEN_EXPIRED.name)
EXCEPTION_HTTP_INVALID_TOKEN_ACCESS = HTTPException(status_code=ErrorType.HTTP_INVALID_TOKEN_ACCESS.value, detail=ErrorType.HTTP_INVALID_TOKEN_ACCESS.name)
class DBType(Enum):
"""논리 DB 구분. 모델마다 DBType() 으로 자신이 속한 DB 를 반환한다.
DB 가 늘어나면 여기에 추가하고 db_session_manager 의 맵에 등록만 하면 된다.
물리적으로 같은 negosium_db 라도 도메인별 논리 구분으로 나눠 둘 수 있다(커넥션 config 는 재사용).
"""
USER = 1 # 기본 유저 (supplier_users 테이블)
PARTNER = 2 # partner 도메인 (partner.suppliers, partner.items 등)
NEGOTIATION = 3 # negotiation 도메인 (negotiation.sessions 등)
QUOTATION = 4 # quotation 도메인 (quotation.quotations 등)
class DBWRType(Enum):
"""Read / Write 접속 구분. 조회는 DB_READ, 변경은 DB_WRITE 엔진을 사용한다."""
DB_READ = 1
DB_WRITE = 2
class AccountStatus(Enum):
"""계정 상태 코드. company.users / supplier.supplier_users 의 status 컬럼."""
ACTIVE = 1 # 활성
INACTIVE = 2 # 비활성
class UserRole(Enum):
"""유저 권한 코드. company.users / supplier.supplier_users 의 role 컬럼."""
USER = 1 # 일반 유저
MANAGER = 2 # 매니저
class TokenType(Enum):
"""토큰 종류 코드. supplier.supplier_user_tokens 의 type 컬럼."""
ACCESS = 1
REFRESH = 2
class QtType(Enum):
"""견적/세션 유형 코드. quotation.quotations.type / negotiation.sessions.qt_type.
신규/재 × 협상(1:1)/견적(1:N). 1·2(재)는 기존 데이터 보존 위해 고정, 신규는 3·4."""
RENEGO = 1 # 재협상(1:1)
REQUOTE = 2 # 재견적(1:N)
NEW_NEGO = 3 # 신규협상(1:1)
NEW_QUOTE = 4 # 신규견적(1:N)
class SessionStatus(Enum):
"""협상 세션 진행 상태 코드. negotiation.sessions.status"""
CREATED = 1 # 협상생성
IN_PROGRESS = 2 # 협상중
DONE = 3 # 협상완료
NOT_PARTICIPATED = 4 # 미참여
REJECTED = 5 # 협상거부
class QuotationStatus(Enum):
"""견적 진행 상태 코드. quotation.quotations.status """
CREATED = 1 # 견적생성
IN_PROGRESS = 2 # 견적진행중
CLOSED = 3 # 견적마감
class CloseReason(Enum):
"""견적 마감 사유. quotation.quotations.close_reason
낙찰(AWARDED) 외 OPEN_* 는 낙찰자 미정으로 마감된 '결렬' 건 — 공급사 재협상 요청 대상."""
AWARDED = 1 # 낙찰
OPEN_PRICE = 5 # 개찰: 낙찰 기준 미달
OPEN_EQUAL = 6 # 개찰: 동가
OPEN_NOSHOW = 7 # 개찰: 전원 미응찰
OPEN_REJECT = 8 # 개찰: 협상거부 존재
# 재협상 요청 가능한 마감 사유(낙찰 건은 제외).
RENEGOTIABLE_CLOSE_REASONS = (
CloseReason.OPEN_PRICE.value,
CloseReason.OPEN_EQUAL.value,
CloseReason.OPEN_NOSHOW.value,
CloseReason.OPEN_REJECT.value,
)
class RenegotiationStatus(Enum):
"""sessions.custom.renegotiation.status — 공급사 재협상 요청 상태(IMK #15)."""
PENDING = 1 # 접수, 담당자 심사 대기
APPROVED = 2 # 승인 — 다음 라운드 생성됨
REJECTED = 3 # 반려
CANCELED = 4 # 공급사 철회
class NotificationType(Enum):
"""company.notifications.type — negodata 담당자 인박스. 포털에서 만드는 건 재협상 요청뿐."""
RENEGO_REQUESTED = 5
class ChatSender(Enum):
"""채팅 발신자 코드. negotiation.chats.sender """
BOT = 1 # 공급사(갑) — bot 메시지
USER = 2 # 협력사(을) — user 입력
class DeliveryType(Enum):
"""배송 유형 코드. partner.items.delivery_type / negotiation.sessions.reject_delivery_type """
SUPPLIER = 1 # 협력사배송
COURIER = 2 # 지정택배배송
PICKUP = 3 # 픽업배송
@classmethod
def label_of(cls, code) -> str:
"""코드(1~3) → 한글 라벨. 알 수 없으면 빈 문자열."""
return {1: "협력사배송", 2: "지정택배배송", 3: "픽업배송"}.get(code, "")