o2o-negosium-original/negodata/backend/router/v1/card/protocol.py
Mina Choi 1b9ca062f3 [feat] negodata: 협상카드 회사 스코프·공용 읽기전용 + 견적 목표가 산정내역 수정
협상카드
- 목록/조회를 등록자 개인 → 회사(company.users 조인) 단위로 확장: 같은 회사 유저 카드 + 공용(user_id NULL)
- 공용 카드는 기본 제공 자산 → 수정·삭제 불가(OWNER 포함), is_shared=True API 등록 거부
- 개인 카드 변경은 본인∪최고관리자만, 프론트 버튼 disable+툴팁
- 공개범위 셀렉터·엑셀 공개범위 컬럼·CardTable 전체 배지 제거(항상 개인 등록)
- test_card.py 5케이스 재작성

견적 목표가 산정내역
- get_setting_rates: 단일 컬럼 select 결과를 이중 인덱싱해 항상 예외 → 마진율이 늘 0으로 적용되던 버그 수정
- get_target_breakdown: 채택 후보 판정을 '현재 최소값' → '저장 목표가와 값 일치'로 변경(산정 후 상품가 변동에도 초록 체크 유지)
- 견적상세 협상카드 탭 세션ID 컬럼 제거

견적생성 모달
- 목표가 미리보기·마감기한 기본값(+1h)·미래 검증, combobox 팝오버 scrollIntoView, maskPrices 비율(%) 마스킹

Little-Helped: Stupid Claude
2026-07-09 17:04:40 +09:00

72 lines
2.7 KiB
Python

import uuid
from datetime import datetime
from typing import Any, Optional
from pydantic import ConfigDict
from common.enums import CardStatus, CardUsageType
from common.models.gmodel import Res_PageProtocol, Res_WebPacketProtocol, WebPacketProtocol
class CardProtocol(WebPacketProtocol):
pass
class Req_CreateCard(CardProtocol):
is_wildcard: bool = False
is_shared: bool = False # True(전체 공용 등록)는 거부된다 — 공용 카드는 DB 시드로만 관리. 항상 False 로 보낼 것
name: Optional[str] = None
number: Optional[str] = None
script: Optional[str] = None
edit_script: Optional[Any] = None
usage_type: int = CardUsageType.COMMON.value # 카드 적용 견적 구분(CardUsageType): 1=공통 2=신규견적전용 3=재견적전용
status: int = CardStatus.ACTIVE.value # 와일드카드 적용 여부(available 매핑). 일반카드는 무시.
condition: Optional[str] = None # 와일드카드 전용
memo: Optional[str] = None # 와일드카드 전용
class Req_UpdateCard(CardProtocol):
name: Optional[str] = None
number: Optional[str] = None
script: Optional[str] = None
edit_script: Optional[Any] = None
usage_type: Optional[int] = None # 카드 적용 견적 구분(CardUsageType): 1=공통 2=신규견적전용 3=재견적전용
status: Optional[int] = None
condition: Optional[str] = None
memo: Optional[str] = None
# 통합 카드 표현(nego_cards + wild_cards 공통).
class CardData(WebPacketProtocol):
model_config = ConfigDict(from_attributes=True)
nego_card_id: uuid.UUID # 통합 식별자(일반=nego_card_id / 와일드=wild_card_id)
user_id: Optional[uuid.UUID] = None
is_wildcard: bool = False
is_shared: bool = False # 전체(공용) 카드 여부 = user_id NULL. 목록 배지/폼 스코프 표시용
creator_name: Optional[str] = None # 작성자(등록자) 이름. user_id→company.users.name 조인. 공용 카드는 None
name: Optional[str] = None
number: Optional[str] = None
script: Optional[str] = None
edit_script: Optional[Any] = None
usage_type: CardUsageType = CardUsageType.COMMON # 카드 적용 견적 구분: 1=공통 2=신규견적전용 3=재견적전용
status: CardStatus = CardStatus.ACTIVE
condition: Optional[str] = None
memo: Optional[str] = None
created_at: Optional[datetime] = None
updated_at: Optional[datetime] = None
class Res_Card(Res_WebPacketProtocol):
card: Optional[CardData] = None
class Res_CardList(Res_PageProtocol):
cards: list[CardData] = []
total_nego: int = 0 # 협상카드 탭 카운트(검색 필터 반영)
total_wild: int = 0 # 와일드카드 탭 카운트(검색 필터 반영)
class Res_DeleteCard(Res_WebPacketProtocol):
pass