diff --git a/agent/docs/q-table 상세 설명.pdf b/agent/docs/q-table 상세 설명.pdf new file mode 100644 index 0000000..be0fb08 Binary files /dev/null and b/agent/docs/q-table 상세 설명.pdf differ diff --git a/agent/docs/동적_협상_알고리즘_설계서.pdf b/agent/docs/동적_협상_알고리즘_설계서.pdf new file mode 100644 index 0000000..b50da48 Binary files /dev/null and b/agent/docs/동적_협상_알고리즘_설계서.pdf differ diff --git a/agent/docs/조견표(Test-Set).csv b/agent/docs/조견표(Test-Set).csv new file mode 100644 index 0000000..a7e4b85 --- /dev/null +++ b/agent/docs/조견표(Test-Set).csv @@ -0,0 +1,30 @@ +ID,??MD,?????,?????,??? ???,????,???,???,????,????,???,???,1???,1? ?? ???,1? ????,????,2???,2? ?? ???,2? ????,????,3???,3? ?? ???,3? ????,????,4???,,,,, +1,,???,,,AT2025042400050,?????,"163,600",??,None (??),"8,180","8,099",,,,,,,,,,,,,,,,,, +2,,???,,,AT2025042200057,????,"350,000",??,Single (??),"35,000","33,600",35000,0,?? ?? ?? ??,o,34900,0.00286533,??? ?? ?? ??,o,33700,0.038575668,??? ?? ?? ??,x,33600,,,,, +3,,???,,,AT2025042300003,TV???,"6,790,000",??,Multiple (??),"48,500","46,560",50000,0,?? ?? ?? ??,x,46560,,?? ??,,,,,,,,,,, +4,,???,,,AT2025042200041,?????,"18,700,000",??,Multiple (??),"1,804,550","1,678,232",2200000,0,?? ?? ?? ??,x,2000000,0.1,?? ?? ?? ??,,1700000,0.294117647,??? ?? ?? ??,,1700000,,,,, +5,,???,,,AT2025041600034,???,"760,320",??,Multiple (??),"73,304","70,372",70000,,?? ??,,,,,,,,,,,,,,, +6,,???,,,AT2025042400010,????? ??,"780,000",??,Multiple (??),"75,642"," 72,617 ",,,,,,,,,,,,,,,,,, +7,,???,,,AT2025042400030,???,"313,000",??,Multiple (??),"31,300","29,735",50000,0,?? ?? ?? ??,,40000,0.25,?? ?? ?? ??,,30500,0.639344262,??? ?? ?? ??,,30500,,,,, +8,,???,,,AT2025042300096,?????,"706,800",??,None (??),"68,162","65,436",115800,0,?? ?? ?? ??,,70000,0.654285714,?? ?? ?? ??,,69000,0.67826087,??? ?? ?? ??,,65400,,,,, +9,,???,,,AT2025042300082,??????,"12,000",??,Multiple (??),"1,200","1,188",,,,,,,,,,,,,,,,,, +2.1,,???,ID 2 ???? ??(??>??),,AT2025042200057,????,"350,000",??,Single (??),"35,000"," 33,250 ",,,,,,,,,,,,,,,,,, +6.1,,???,ID 6 ???? ??(??>??),,AT2025042400010,????? ??,780000,??,Multiple (??),"75,642"," 71,860 ",,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,1,AT2025042400050,SOOT777,?????,,,,,,,,,,,,,,,,,,,,,, +,,,,2,AT2025042200057,JAJE89,????,,,,,,,,,,,,,,,,,,,,,, +,,,,3,AT2025042300003,VOV2,TV???,,,,,,,,,,,,,,,,,,,,,, +,,,,4,AT2025042200041,HEMEELY,?????,,,,,,,,,,,,,,,,,,,,,, +,,,,5,AT2025041600034,KMS5939,???,,,,,,,,,,,,,,,,,,,,,, +,,,,6,AT2025042400010,YTS111,????? ??,,,,,,,,,,,,,,,,,,,,,, +,,,,7,AT2025042400030,SJUN98,???,,,,,,,,,,,,,,,,,,,,,, +,,,,8,AT2025042300096,DREAMBIZ,?????,,,,,,,,,,,,,,,,,,,,,, +,,,,9,AT2025042300082,BWTCO40,??????,,,,,,,,,,,,,,,,,,,,,, +,,,,2.1,AT2025042200057,JAJE89,????,,,,,,,,,,,,,,,,,,,,,, +,,,,6.1,AT2025042400010,YTS111,????? ??,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,, diff --git a/agent/negotiation/chat/infra/repository/nego_context_crud.py b/agent/negotiation/chat/infra/repository/nego_context_crud.py index 24e5d81..fa8928a 100644 --- a/agent/negotiation/chat/infra/repository/nego_context_crud.py +++ b/agent/negotiation/chat/infra/repository/nego_context_crud.py @@ -28,7 +28,31 @@ _SESSIONS = table( ) _ITEMS = table("items", column("item_id"), column("price"), column("deleted"), schema="partner") _SUPPLIERS = table("suppliers", column("supplier_id"), column("total_revenue"), column("deleted"), schema="partner") -_QUOTATIONS = table("quotations", column("qt_id"), column("supplier_type"), column("deleted"), schema="quotation") +_QUOTATIONS = table( + "quotations", + column("qt_id"), column("version_id"), column("supplier_type"), column("deleted"), + schema="quotation", +) +_VERSION_NEGO_CARDS = table( + "version_nego_cards", + column("version_id"), column("nego_card_id"), column("created_at"), column("deleted"), + schema="card", +) +_VERSION_WILD_CARDS = table( + "version_wild_cards", + column("version_id"), column("wild_card_id"), column("created_at"), column("deleted"), + schema="card", +) +_NEGO_CARDS = table( + "nego_cards", + column("nego_card_id"), column("number"), column("deleted"), + schema="card", +) +_WILD_CARDS = table( + "wild_cards", + column("wild_card_id"), column("number"), column("deleted"), + schema="card", +) # 상품↔협력사 매핑 (2026-07-07 신설): supply_type = 이 협력사가 이 상품을 공급하는 방식(SupplierType). _SUPPLIER_ITEMS = table( "supplier_items", @@ -74,6 +98,11 @@ class INegoContextCRUD(ABC): """상품에 연결된 협력사 수 — 협상 세션 이력 기준(supplier_items 매핑 부재 시 폴백).""" pass + @abstractmethod + async def get_quotation_card_numbers(self, cdb: AsyncSession, quotation_id) -> Tuple[ErrorType, tuple[list[str], list[str]]]: + """견적 version_id 에 연결된 (일반카드 번호 목록, 와일드카드 번호 목록). 없으면 빈 목록.""" + pass + class NegoContextCRUD(INegoContextCRUD): async def get_session_row(self, cdb: AsyncSession, session_id) -> Tuple[ErrorType, Optional[tuple]]: @@ -181,3 +210,63 @@ class NegoContextCRUD(INegoContextCRUD): except Exception as ex: LOG.e_no_callstack(ex) return ErrorType.DB_RUN_FAILED, 0 + + async def get_quotation_card_numbers(self, cdb: AsyncSession, quotation_id) -> Tuple[ErrorType, tuple[list[str], list[str]]]: + try: + version_q = ( + select(_QUOTATIONS.c.version_id) + .where(_QUOTATIONS.c.qt_id == quotation_id, _QUOTATIONS.c.deleted == False) # noqa: E712 + .limit(1) + ) + err_type, rows = await DB_SESSION_MNG.execute(cdb, version_q, "get_quotation_version failed.", raise_error=False) + if err_type != ErrorType.SUCCESS: + return err_type, ([], []) + if not rows or rows[0] is None: + return ErrorType.SUCCESS, ([], []) + version_id = rows[0] + + nego_q = ( + select(_NEGO_CARDS.c.number) + .select_from( + _VERSION_NEGO_CARDS.join( + _NEGO_CARDS, + _VERSION_NEGO_CARDS.c.nego_card_id == _NEGO_CARDS.c.nego_card_id, + ) + ) + .where( + _VERSION_NEGO_CARDS.c.version_id == version_id, + _VERSION_NEGO_CARDS.c.deleted == False, # noqa: E712 + _NEGO_CARDS.c.deleted == False, # noqa: E712 + ) + .order_by(_VERSION_NEGO_CARDS.c.created_at) + ) + n_err, n_rows = await DB_SESSION_MNG.execute(cdb, nego_q, "get_quotation_nego_cards failed.", raise_error=False) + if n_err != ErrorType.SUCCESS: + return n_err, ([], []) + + wild_q = ( + select(_WILD_CARDS.c.number) + .select_from( + _VERSION_WILD_CARDS.join( + _WILD_CARDS, + _VERSION_WILD_CARDS.c.wild_card_id == _WILD_CARDS.c.wild_card_id, + ) + ) + .where( + _VERSION_WILD_CARDS.c.version_id == version_id, + _VERSION_WILD_CARDS.c.deleted == False, # noqa: E712 + _WILD_CARDS.c.deleted == False, # noqa: E712 + ) + .order_by(_VERSION_WILD_CARDS.c.created_at) + ) + w_err, w_rows = await DB_SESSION_MNG.execute(cdb, wild_q, "get_quotation_wild_cards failed.", raise_error=False) + if w_err != ErrorType.SUCCESS: + return w_err, ([], []) + + return ErrorType.SUCCESS, ( + [str(r) for r in n_rows if r is not None], + [str(r) for r in w_rows if r is not None], + ) + except Exception as ex: + LOG.e_no_callstack(ex) + return ErrorType.DB_RUN_FAILED, ([], []) diff --git a/agent/negotiation/chat/service/chat_engine.py b/agent/negotiation/chat/service/chat_engine.py index af362d3..77e1790 100644 --- a/agent/negotiation/chat/service/chat_engine.py +++ b/agent/negotiation/chat/service/chat_engine.py @@ -146,7 +146,15 @@ class ChatEngine: cond = c.get("condition") ok = False if cond == "check_wildcard_entry": - ok = (not ctx.get("wildcard_used")) and anchor < price <= anchor * 1.05 + ok = ( + (not ctx.get("wildcard_used")) + and anchor > 0 + and anchor < price + and ( + price <= anchor * 1.02 + or (bool(ctx.get("allow_selected_wildcards", True)) and price <= anchor * 1.05) + ) + ) elif cond == "check_is_supplier_type_c": ok = False # 공급사 유형 미보유 (PoC 단순화) elif cond == "check_price_match": # = 우선협상: 제시가가 앵커가 이하 @@ -176,6 +184,8 @@ class ChatEngine: if anchor > 0 and price <= anchor * 1.02: ctx["offer_1pct"] = int(round(price * 0.99)) # 1% 인하가 return "wild_card_1pct" + if not ctx.get("allow_selected_wildcards", True): + return "가격협상" return "wild_card_budget" # ---- render -------------------------------------------------------- diff --git a/agent/negotiation/chat/service/negotiation_context_loader.py b/agent/negotiation/chat/service/negotiation_context_loader.py index 0bc7bb4..b0dfb3e 100644 --- a/agent/negotiation/chat/service/negotiation_context_loader.py +++ b/agent/negotiation/chat/service/negotiation_context_loader.py @@ -43,6 +43,8 @@ class NegotiationDbContext: partner_type: PartnerType # 상품에 연결된 협력사 수(supplier_items 매핑, 없으면 세션 이력) → NONE/SINGLE/MULTIPLE revenue_amount: float # 매출액(원) — suppliers.total_revenue(KTC 미러). 없으면 0 distribution_code: Optional[str] # 유통 코드(A/B/C) — supplier_items.supply_type → quotations.supplier_type. 미지정 시 None + selected_nego_card_numbers: list[str] # 견적 생성 시 선택된 일반 협상카드 번호(card.nego_cards.number) + selected_wild_card_numbers: list[str] # 견적 생성 시 선택된 와일드카드 번호(card.wild_cards.number) class NegotiationContextLoader: @@ -93,6 +95,11 @@ class NegotiationContextLoader: if err != ErrorType.SUCCESS: supplier_count = 1 + # 견적 생성 모달에서 고른 카드셋. 값이 없으면 운영 DB 기준으로 "선택 카드 없음"이다. + # 데모/직접호출 경로(DB context 없음)만 ChatService 에서 기존 기본 카드셋으로 폴백한다. + _, selected_cards = await self.crud.get_quotation_card_numbers(s, quotation_id) + selected_nego_cards, selected_wild_cards = selected_cards + return NegotiationDbContext( rq_type="재협상" if int(qt_type) in _ONE_TO_ONE_QT_TYPES else "재견적", target_price=target, @@ -101,6 +108,8 @@ class NegotiationContextLoader: partner_type=PartnerType.from_count(supplier_count), revenue_amount=revenue_amount, distribution_code=_SUPPLIER_TYPE_TO_CODE.get(supplier_type) if supplier_type else None, + selected_nego_card_numbers=selected_nego_cards, + selected_wild_card_numbers=selected_wild_cards, ) try: diff --git a/agent/negotiation/chat/service/script_repository.py b/agent/negotiation/chat/service/script_repository.py index 61a1d5d..c5c78f0 100644 --- a/agent/negotiation/chat/service/script_repository.py +++ b/agent/negotiation/chat/service/script_repository.py @@ -90,14 +90,15 @@ class ScriptRepository: return self.format_script(text, variables) async def resolve_card_script(self, action_id: int, card_id: Optional[str], - variables: Optional[Dict[str, Any]] = None) -> Optional[str]: + variables: Optional[Dict[str, Any]] = None, + prefer_db: bool = False) -> Optional[str]: """카드 멘트 해석. cards.source_type == 'backoffice_db' 면 card.nego_cards.script(DB)를 우선 조회하고, 없거나 file 모드면 scripts_cards.json(파일) 폴백. 변수 치환 후 반환. DB 멘트는 백오피스(negodata)가 편집한 정본이라 파일보다 우선한다. 마커(**굵게** 등)가 섞여 있어도 agent 는 불투명 텍스트로 취급 — 표현 렌더는 프론트 소유. """ - if self._config.cards.source_type == _CARD_SOURCE_DB and card_id: + if (prefer_db or self._config.cards.source_type == _CARD_SOURCE_DB) and card_id: db_text = await self._fetch_card_script_db(card_id) if db_text: return self.format_script(db_text, variables) diff --git a/agent/services/chat_service.py b/agent/services/chat_service.py index 88df879..a64c3be 100644 --- a/agent/services/chat_service.py +++ b/agent/services/chat_service.py @@ -63,11 +63,20 @@ class ChatService: ) if session is None: + selected_nego_cards = db_ctx.selected_nego_card_numbers if db_ctx else [] + selected_wild_cards = db_ctx.selected_wild_card_numbers if db_ctx else [] + # 운영 DB 세션은 견적 version_id 에 묶인 카드만 사용한다. 직접 호출/데모(DB context 없음)는 + # 기존 테넌트 기본 action mapping 으로 폴백해 로컬 테스트와 콘솔 데모를 유지한다. + action_space_size = ( + min(len(selected_nego_cards), engine.action_space_size) + if db_ctx is not None + else engine.action_space_size + ) # session_id honoring: backend 가 보낸 session_id(= negotiation.sessions.session_id)를 # 새 uuid 발급 없이 그대로 세션 키로 쓴다. 없으면(직접 호출/데모) 생성. session = ChatSession( session_id=req.session_id or str(uuid.uuid4()), tenant_id=engine.tenant_id, company_id=engine.company_id, - rq_type=rq_type, action_space_size=engine.action_space_size, + rq_type=rq_type, action_space_size=action_space_size, context={ # 매출액 = suppliers.total_revenue, 유통코드 = quotations.supplier_type 매핑 (loader). # 미기재/미지정이면 기본값 폴백. @@ -83,6 +92,13 @@ class ChatService: "round": 0, # 기존 공급가(품목 기준가) — 가격협상_확인 인하율 산출용. "item_price": db_ctx.item_price if db_ctx else 0, + # 견적 생성 시 선택한 카드. 일반카드는 action_id 0..N-1 에 그대로 매핑한다. + # 1% 인하는 기본 와일드카드로 항상 열고, 재원부족 등 선택형 와일드카드는 + # 선택된 와일드카드가 있을 때만 허용한다. + "db_context_loaded": db_ctx is not None, + "selected_nego_card_numbers": selected_nego_cards, + "selected_wild_card_numbers": selected_wild_cards, + "allow_selected_wildcards": True if db_ctx is None else bool(selected_wild_cards), }, ) view = chat_engine.start(session) @@ -105,7 +121,7 @@ class ChatService: res.settled_price = int(session.context["input_price"]) # 3) 학습 결합 (가격협상 카드선택 → 카드 스크립트·협상지표 / 종료 보상) - if view.error is None and engine.action_space_size > 0: + if view.error is None and session.action_space_size > 0: if view.needs_card_selection: await self._select_and_learn(engine, chat_engine, repo, session, res) elif view.outcome is not None: @@ -172,11 +188,11 @@ class ChatService: LOG.e_no_callstack(f"[ChatService] state error: {ex}") return policy, version_id, repo = await QTablePolicyStore.load(engine) - ctx = PolicyContext(state_index=idx, snapshot=snap, action_space_size=engine.action_space_size, + ctx = PolicyContext(state_index=idx, snapshot=snap, action_space_size=session.action_space_size, episode=EpisodeState(used_action_ids=set(session.used_action_ids))) decision = policy.select(ctx) session.used_action_ids.add(decision.action_id) - card_id = engine.mapper.get_card_id(decision.action_id) + card_id = self._card_id_for_action(engine, session, decision.action_id) reward = RewardCalculator(engine.config.reward, engine.config.state).calculate(snap) policy.update(Transition(state_index=idx, action_id=decision.action_id, reward=reward.total, done=False)) await QTablePolicyStore.persist_cell(repo, version_id, policy, idx, decision.action_id) @@ -195,7 +211,12 @@ class ChatService: # ① 선택된 카드의 스크립트를 봇 메시지(script)로 출력 ② 협상지표 게이지(indicator_value) 동봉. # backend/front 가 indicator/bot_chat_type 패스스루·게이지 렌더 준비 완료 → 값만 채우면 표시된다. # 카드 멘트: backoffice_db 모드면 card.nego_cards.script(negodata 편집 정본), 아니면 파일 폴백. - card_script = await scripts.resolve_card_script(decision.action_id, card_id, chat_engine.vars_for(session)) + card_script = await scripts.resolve_card_script( + decision.action_id, + card_id, + chat_engine.vars_for(session), + prefer_db=bool(session.context.get("selected_nego_card_numbers")), + ) if card_script: res.script = card_script c = session.context @@ -218,9 +239,16 @@ class ChatService: policy.update(Transition(state_index=last_state, action_id=last_action, reward=reward.total, done=True)) await QTablePolicyStore.persist_cell(repo, version_id, policy, last_state, last_action) await self._log(repo, session, last_state, last_action, - engine.mapper.get_card_id(last_action), snap, reward, None, done=True) + self._card_id_for_action(engine, session, last_action), snap, reward, None, done=True) res.updated_q = float(policy.qtable.q[last_state, last_action]) + @staticmethod + def _card_id_for_action(engine: TenantEngine, session: ChatSession, action_id: int) -> Optional[str]: + selected = session.context.get("selected_nego_card_numbers") or [] + if 0 <= action_id < len(selected): + return str(selected[action_id]) + return engine.mapper.get_card_id(action_id) + async def _log(self, repo: LearningRepository, session, state_index, action_id, card_id, snap, reward, propensity, done): data = { "session_id": session.session_id, "state_index": state_index, "action_id": action_id, diff --git a/agent/tests/test_p7_chat.py b/agent/tests/test_p7_chat.py index 7c15fd3..42fce19 100644 --- a/agent/tests/test_p7_chat.py +++ b/agent/tests/test_p7_chat.py @@ -15,6 +15,8 @@ import pytest from router.v1.chat.protocol import Req_Chat from services.chat_service import ChatService, reset_sessions +from negotiation.chat.service.chat_engine import ChatEngine, ChatSession +from negotiation.chat.service.script_repository import ScriptRepository from negotiation.qtable.infra.repository.learning_repository import LearningRepository from tenancy.config_loader import TenantConfigLoader from tenancy.registry import TenantEngineRegistry @@ -122,6 +124,75 @@ def test_acceptance_ratio_dynamic_calc(): assert calc({"input_price": 9800}) == 0.0 # 기준가 전무(과거 세션 호환) +def test_selected_card_mapping_overrides_tenant_default(): + """운영 세션은 견적 version_id 에 묶인 카드 번호를 action_id 순서로 사용한다.""" + session = ChatSession( + session_id="00000000-0000-0000-0000-000000000001", + tenant_id="ktcommerce", + company_id="ktcommerce", + context={"selected_nego_card_numbers": ["2", "7"]}, + action_space_size=2, + ) + class _Mapper: + def get_card_id(self, action_id): + return f"DEFAULT-{action_id}" + class _Engine: + mapper = _Mapper() + + assert ChatService._card_id_for_action(_Engine(), session, 0) == "2" + assert ChatService._card_id_for_action(_Engine(), session, 1) == "7" + assert ChatService._card_id_for_action(_Engine(), session, 8) == "DEFAULT-8" + + +def test_default_1pct_wildcard_still_runs_without_selected_wildcard(): + """1% 인하는 기본 제공 카드라 DB 견적에서 와일드카드를 선택하지 않아도 발동한다.""" + cfg = TenantConfigLoader(tenants_dir=_TENANTS_DIR, cache_ttl_seconds=0).load("ktcommerce") + repo = ScriptRepository(cfg, _TENANTS_DIR) + engine = ChatEngine(repo, rq_type="재협상") + session = ChatSession( + session_id="00000000-0000-0000-0000-000000000002", + tenant_id="ktcommerce", + company_id="ktcommerce", + step="가격협상_확인", + action_space_size=0, + context={ + "input_price": 10000, + "anchor_price": 9900, + "target_price": 10000, + "round": 1, + "allow_selected_wildcards": False, + }, + ) + + view = engine.advance(session, "예") + assert view.step == "wild_card_1pct" + + +def test_budget_wildcard_requires_selected_wildcard_for_db_context(): + """재원부족 구간은 DB 견적에서 와일드카드를 선택했을 때만 발동한다.""" + cfg = TenantConfigLoader(tenants_dir=_TENANTS_DIR, cache_ttl_seconds=0).load("ktcommerce") + repo = ScriptRepository(cfg, _TENANTS_DIR) + engine = ChatEngine(repo, rq_type="재협상") + session = ChatSession( + session_id="00000000-0000-0000-0000-000000000003", + tenant_id="ktcommerce", + company_id="ktcommerce", + step="가격협상_확인", + action_space_size=0, + context={ + "input_price": 10200, + "anchor_price": 9900, + "target_price": 10000, + "round": 1, + "allow_selected_wildcards": False, + }, + ) + + view = engine.advance(session, "예") + assert view.step == "가격협상" + assert not view.step.startswith("wild_card_") + + @pytest.mark.asyncio async def test_priority_completes_without_wildcard(db_engine): reset_sessions() diff --git a/agent/tests/test_scripts_resources.py b/agent/tests/test_scripts_resources.py index d977b32..418e011 100644 --- a/agent/tests/test_scripts_resources.py +++ b/agent/tests/test_scripts_resources.py @@ -151,3 +151,20 @@ async def test_resolve_card_script_db_mode_falls_back_to_file(monkeypatch): out = await repo.resolve_card_script(0, "NGC-A001", {"input_price": 9800}) assert out and "9800" in out # 파일 폴백 멘트 + + +@pytest.mark.asyncio +async def test_resolve_card_script_prefer_db_for_selected_cards(monkeypatch): + """견적에서 선택된 백오피스 카드 번호는 file 모드여도 DB 멘트를 우선한다.""" + cfg = TenantConfigLoader(tenants_dir=_TENANTS_DIR, cache_ttl_seconds=0).load("ktcommerce") + assert cfg.cards.source_type == "file" + fake = _FakeCardRepo({"2": "선택 카드 DB 멘트 **{input_price}원**"}) + repo = ScriptRepository(cfg, _TENANTS_DIR, card_repo=fake) + + async def _fake_lambda(_db, _wr, func): + return await func(None) + from negotiation.chat.service import script_repository as _sr + monkeypatch.setattr(_sr.DB_SESSION_MNG, "execute_lambda", _fake_lambda) + + out = await repo.resolve_card_script(1, "2", {"input_price": 10200}, prefer_db=True) + assert out == "선택 카드 DB 멘트 **10200원**" diff --git a/negodata/front/tsconfig.tsbuildinfo b/negodata/front/tsconfig.tsbuildinfo new file mode 100644 index 0000000..5810964 --- /dev/null +++ b/negodata/front/tsconfig.tsbuildinfo @@ -0,0 +1 @@ +{"root":["./orval.config.ts","./vite.config.ts","./src/types.ts","./src/vite-env.d.ts","./src/api/generated/auth/auth.ts","./src/api/generated/card/card.ts","./src/api/generated/company-user/company-user.ts","./src/api/generated/dashboard/dashboard.ts","./src/api/generated/default/default.ts","./src/api/generated/item/item.ts","./src/api/generated/model/bodyuploaditemimagev1itemimagepost.ts","./src/api/generated/model/carddata.ts","./src/api/generated/model/carddatacondition.ts","./src/api/generated/model/carddatacreatedat.ts","./src/api/generated/model/carddataeditscript.ts","./src/api/generated/model/carddatamemo.ts","./src/api/generated/model/carddataname.ts","./src/api/generated/model/carddatanumber.ts","./src/api/generated/model/carddatascript.ts","./src/api/generated/model/carddataupdatedat.ts","./src/api/generated/model/carddatauserid.ts","./src/api/generated/model/cardstatus.ts","./src/api/generated/model/cardtype.ts","./src/api/generated/model/cardusagetype.ts","./src/api/generated/model/chatmessagedata.ts","./src/api/generated/model/chatmessagedatacardid.ts","./src/api/generated/model/chatmessagedatacardtype.ts","./src/api/generated/model/chatmessagedatacardusedyn.ts","./src/api/generated/model/chatmessagedataindicatorvalue.ts","./src/api/generated/model/chatmessagedatascript.ts","./src/api/generated/model/chatmessagedatastep.ts","./src/api/generated/model/chatsender.ts","./src/api/generated/model/closereason.ts","./src/api/generated/model/companydata.ts","./src/api/generated/model/companyuserdata.ts","./src/api/generated/model/companyuserdatacontactnumber.ts","./src/api/generated/model/companyuserdatacreatedat.ts","./src/api/generated/model/companyuserdataemail.ts","./src/api/generated/model/companyuserdatalastaccessedat.ts","./src/api/generated/model/companyuserdataname.ts","./src/api/generated/model/companyuserdataupdatedat.ts","./src/api/generated/model/dashboardactionlist.ts","./src/api/generated/model/dashboardemailunsent.ts","./src/api/generated/model/dashboardemailunsentitem.ts","./src/api/generated/model/dashboardquotationref.ts","./src/api/generated/model/dashboardquotationrefendtime.ts","./src/api/generated/model/dashboardscope.ts","./src/api/generated/model/deliverytype.ts","./src/api/generated/model/errorinfo.ts","./src/api/generated/model/errorinfocode.ts","./src/api/generated/model/errorinfodesc.ts","./src/api/generated/model/errorinfosuccess.ts","./src/api/generated/model/httpvalidationerror.ts","./src/api/generated/model/index.ts","./src/api/generated/model/itemcategory.ts","./src/api/generated/model/itemdata.ts","./src/api/generated/model/itemdatacategory.ts","./src/api/generated/model/itemdatacode.ts","./src/api/generated/model/itemdatacreatedat.ts","./src/api/generated/model/itemdatadeliveryfeeyn.ts","./src/api/generated/model/itemdatadeliverytype.ts","./src/api/generated/model/itemdataimageurl.ts","./src/api/generated/model/itemdatainternetlowestprice.ts","./src/api/generated/model/itemdataleadtime.ts","./src/api/generated/model/itemdatamadein.ts","./src/api/generated/model/itemdatamanufacturer.ts","./src/api/generated/model/itemdatamodelname.ts","./src/api/generated/model/itemdatamoq.ts","./src/api/generated/model/itemdataprice.ts","./src/api/generated/model/itemdatapurchaseprice.ts","./src/api/generated/model/itemdataquantityunit.ts","./src/api/generated/model/itemdatasellingprice.ts","./src/api/generated/model/itemdataspec.ts","./src/api/generated/model/itemdataupdatedat.ts","./src/api/generated/model/itemdatavatyn.ts","./src/api/generated/model/itemsupplytype.ts","./src/api/generated/model/listcardsparams.ts","./src/api/generated/model/listitemsparams.ts","./src/api/generated/model/listnotificationsparams.ts","./src/api/generated/model/listquotationsparams.ts","./src/api/generated/model/listsuppliersparams.ts","./src/api/generated/model/listusersparams.ts","./src/api/generated/model/notificationdata.ts","./src/api/generated/model/notificationdatacreatedat.ts","./src/api/generated/model/notificationdatadata.ts","./src/api/generated/model/notificationdatareadat.ts","./src/api/generated/model/notificationdatarefqtid.ts","./src/api/generated/model/notificationdatarefsessionid.ts","./src/api/generated/model/notificationtype.ts","./src/api/generated/model/quotationcarddata.ts","./src/api/generated/model/quotationcarddatacondition.ts","./src/api/generated/model/quotationcarddataeditscript.ts","./src/api/generated/model/quotationcarddatamemo.ts","./src/api/generated/model/quotationcarddataname.ts","./src/api/generated/model/quotationcarddatanegocardid.ts","./src/api/generated/model/quotationcarddatanumber.ts","./src/api/generated/model/quotationcarddataqtid.ts","./src/api/generated/model/quotationcarddatascript.ts","./src/api/generated/model/quotationcarddatatype.ts","./src/api/generated/model/quotationcarddatawildcardid.ts","./src/api/generated/model/quotationdata.ts","./src/api/generated/model/quotationdataclosereason.ts","./src/api/generated/model/quotationdatacreatedat.ts","./src/api/generated/model/quotationdatacreatorname.ts","./src/api/generated/model/quotationdataequalbiddata.ts","./src/api/generated/model/quotationdataequalbidyn.ts","./src/api/generated/model/quotationdataitemid.ts","./src/api/generated/model/quotationdataitemname.ts","./src/api/generated/model/quotationdatamanagercontactnumber.ts","./src/api/generated/model/quotationdatamanageremail.ts","./src/api/generated/model/quotationdatamanagername.ts","./src/api/generated/model/quotationdatamdprice.ts","./src/api/generated/model/quotationdatamemo.ts","./src/api/generated/model/quotationdatamidaction.ts","./src/api/generated/model/quotationdataoveraction.ts","./src/api/generated/model/quotationdatapreferredspid.ts","./src/api/generated/model/quotationdatapreferredspname.ts","./src/api/generated/model/quotationdatapreferredspyn.ts","./src/api/generated/model/quotationdatasuppliertype.ts","./src/api/generated/model/quotationdataupdatedat.ts","./src/api/generated/model/quotationsettingdata.ts","./src/api/generated/model/quotationsettingdatacreatedat.ts","./src/api/generated/model/quotationsettingdataupdatedat.ts","./src/api/generated/model/quotationsettingdatauserid.ts","./src/api/generated/model/quotationstatus.ts","./src/api/generated/model/quotationtype.ts","./src/api/generated/model/reqbulkmapbynames.ts","./src/api/generated/model/reqcheckcodes.ts","./src/api/generated/model/reqcreatecard.ts","./src/api/generated/model/reqcreatecardcondition.ts","./src/api/generated/model/reqcreatecardeditscript.ts","./src/api/generated/model/reqcreatecardmemo.ts","./src/api/generated/model/reqcreatecardname.ts","./src/api/generated/model/reqcreatecardnumber.ts","./src/api/generated/model/reqcreatecardscript.ts","./src/api/generated/model/reqcreatecompanyuser.ts","./src/api/generated/model/reqcreateitem.ts","./src/api/generated/model/reqcreateitemcategory.ts","./src/api/generated/model/reqcreateitemcode.ts","./src/api/generated/model/reqcreateitemdeliveryfeeyn.ts","./src/api/generated/model/reqcreateitemdeliverytype.ts","./src/api/generated/model/reqcreateitemimageurl.ts","./src/api/generated/model/reqcreateiteminternetlowestprice.ts","./src/api/generated/model/reqcreateitemleadtime.ts","./src/api/generated/model/reqcreateitemmadein.ts","./src/api/generated/model/reqcreateitemmanufacturer.ts","./src/api/generated/model/reqcreateitemmodelname.ts","./src/api/generated/model/reqcreateitemmoq.ts","./src/api/generated/model/reqcreateitemprice.ts","./src/api/generated/model/reqcreateitempurchaseprice.ts","./src/api/generated/model/reqcreateitemquantityunit.ts","./src/api/generated/model/reqcreateitemsellingprice.ts","./src/api/generated/model/reqcreateitemspec.ts","./src/api/generated/model/reqcreateitemvatyn.ts","./src/api/generated/model/reqcreatequotation.ts","./src/api/generated/model/reqcreatequotationmanagercontactnumber.ts","./src/api/generated/model/reqcreatequotationmanageremail.ts","./src/api/generated/model/reqcreatequotationmanagername.ts","./src/api/generated/model/reqcreatequotationmdprice.ts","./src/api/generated/model/reqcreatequotationmemo.ts","./src/api/generated/model/reqcreatequotationmidaction.ts","./src/api/generated/model/reqcreatequotationoveraction.ts","./src/api/generated/model/reqcreatequotationsetting.ts","./src/api/generated/model/reqcreatequotationstarttime.ts","./src/api/generated/model/reqcreatequotationsuppliertype.ts","./src/api/generated/model/reqcreatequotationversionid.ts","./src/api/generated/model/reqcreatesupplier.ts","./src/api/generated/model/reqcreatesuppliercode.ts","./src/api/generated/model/reqcreatesupplieritem.ts","./src/api/generated/model/reqcreatesuppliermanagercontactnumber.ts","./src/api/generated/model/reqcreatesuppliermanageremail.ts","./src/api/generated/model/reqcreatesuppliermanagername.ts","./src/api/generated/model/reqcreatesuppliertotalrevenue.ts","./src/api/generated/model/reqlogin.ts","./src/api/generated/model/reqregeneratequotation.ts","./src/api/generated/model/requpdatecard.ts","./src/api/generated/model/requpdatecardcondition.ts","./src/api/generated/model/requpdatecardeditscript.ts","./src/api/generated/model/requpdatecardmemo.ts","./src/api/generated/model/requpdatecardname.ts","./src/api/generated/model/requpdatecardnumber.ts","./src/api/generated/model/requpdatecardscript.ts","./src/api/generated/model/requpdatecardstatus.ts","./src/api/generated/model/requpdatecardusagetype.ts","./src/api/generated/model/requpdatecompanyuser.ts","./src/api/generated/model/requpdatecompanyusercontactnumber.ts","./src/api/generated/model/requpdatecompanyuseremail.ts","./src/api/generated/model/requpdatecompanyusername.ts","./src/api/generated/model/requpdatecompanyuserpassword.ts","./src/api/generated/model/requpdatecompanyuserstatus.ts","./src/api/generated/model/requpdateitem.ts","./src/api/generated/model/requpdateitemcategory.ts","./src/api/generated/model/requpdateitemcategorytype.ts","./src/api/generated/model/requpdateitemcode.ts","./src/api/generated/model/requpdateitemdeliveryfeeyn.ts","./src/api/generated/model/requpdateitemdeliverytype.ts","./src/api/generated/model/requpdateitemimageurl.ts","./src/api/generated/model/requpdateiteminternetlowestprice.ts","./src/api/generated/model/requpdateiteminternetlowestpriceyn.ts","./src/api/generated/model/requpdateitemleadtime.ts","./src/api/generated/model/requpdateitemmadein.ts","./src/api/generated/model/requpdateitemmanufacturer.ts","./src/api/generated/model/requpdateitemmodelname.ts","./src/api/generated/model/requpdateitemmoq.ts","./src/api/generated/model/requpdateitemname.ts","./src/api/generated/model/requpdateitemprice.ts","./src/api/generated/model/requpdateitempurchaseprice.ts","./src/api/generated/model/requpdateitemquantityunit.ts","./src/api/generated/model/requpdateitemsellingprice.ts","./src/api/generated/model/requpdateitemspec.ts","./src/api/generated/model/requpdateitemvatyn.ts","./src/api/generated/model/requpdateme.ts","./src/api/generated/model/requpdatemecontactnumber.ts","./src/api/generated/model/requpdatemeemail.ts","./src/api/generated/model/requpdatemename.ts","./src/api/generated/model/requpdatemepassword.ts","./src/api/generated/model/requpdatequotationsetting.ts","./src/api/generated/model/requpdatequotationsettingcardcount.ts","./src/api/generated/model/requpdatequotationsettingtargetmarginrate.ts","./src/api/generated/model/requpdatesupplier.ts","./src/api/generated/model/requpdatesuppliercode.ts","./src/api/generated/model/requpdatesuppliermanagercontactnumber.ts","./src/api/generated/model/requpdatesuppliermanageremail.ts","./src/api/generated/model/requpdatesuppliermanagername.ts","./src/api/generated/model/requpdatesuppliername.ts","./src/api/generated/model/requpdatesuppliertotalrevenue.ts","./src/api/generated/model/requpdatesupplytype.ts","./src/api/generated/model/resbulkmapbynames.ts","./src/api/generated/model/resbulkmapbynamesmsg.ts","./src/api/generated/model/rescard.ts","./src/api/generated/model/rescardcard.ts","./src/api/generated/model/rescardlist.ts","./src/api/generated/model/rescardlistmsg.ts","./src/api/generated/model/rescardmsg.ts","./src/api/generated/model/rescheckcodes.ts","./src/api/generated/model/rescheckcodesmsg.ts","./src/api/generated/model/rescompanyuser.ts","./src/api/generated/model/rescompanyuserlist.ts","./src/api/generated/model/rescompanyuserlistmsg.ts","./src/api/generated/model/rescompanyusermsg.ts","./src/api/generated/model/rescompanyuseruser.ts","./src/api/generated/model/rescreatequotation.ts","./src/api/generated/model/rescreatequotationmsg.ts","./src/api/generated/model/rescreatequotationqtid.ts","./src/api/generated/model/resdashboardsummary.ts","./src/api/generated/model/resdashboardsummarymsg.ts","./src/api/generated/model/resdeletecard.ts","./src/api/generated/model/resdeletecardmsg.ts","./src/api/generated/model/resdeletecompanyuser.ts","./src/api/generated/model/resdeletecompanyusermsg.ts","./src/api/generated/model/resdeleteitem.ts","./src/api/generated/model/resdeleteitemmsg.ts","./src/api/generated/model/resdeletequotation.ts","./src/api/generated/model/resdeletequotationmsg.ts","./src/api/generated/model/resdeletequotationsetting.ts","./src/api/generated/model/resdeletequotationsettingmsg.ts","./src/api/generated/model/resdeletesupplier.ts","./src/api/generated/model/resdeletesuppliermsg.ts","./src/api/generated/model/resitem.ts","./src/api/generated/model/resitemcategories.ts","./src/api/generated/model/resitemcategoriesmsg.ts","./src/api/generated/model/resitemimage.ts","./src/api/generated/model/resitemimagefilename.ts","./src/api/generated/model/resitemimageimageurl.ts","./src/api/generated/model/resitemimagemsg.ts","./src/api/generated/model/resitemimagesize.ts","./src/api/generated/model/resitemitem.ts","./src/api/generated/model/resitemlist.ts","./src/api/generated/model/resitemlistmsg.ts","./src/api/generated/model/resitemmsg.ts","./src/api/generated/model/resitemsupplytypelist.ts","./src/api/generated/model/resitemsupplytypelistmsg.ts","./src/api/generated/model/reslastsuppliertype.ts","./src/api/generated/model/reslastsuppliertypemsg.ts","./src/api/generated/model/reslastsuppliertypeqtnumber.ts","./src/api/generated/model/reslastsuppliertypesuppliertype.ts","./src/api/generated/model/reslogin.ts","./src/api/generated/model/resloginmsg.ts","./src/api/generated/model/reslowestpriceresult.ts","./src/api/generated/model/reslowestpriceresultmsg.ts","./src/api/generated/model/reslowestpricetrigger.ts","./src/api/generated/model/reslowestpricetriggermsg.ts","./src/api/generated/model/resme.ts","./src/api/generated/model/resmecompany.ts","./src/api/generated/model/resmecontactnumber.ts","./src/api/generated/model/resmeemail.ts","./src/api/generated/model/resmemsg.ts","./src/api/generated/model/resmename.ts","./src/api/generated/model/resnotificationlist.ts","./src/api/generated/model/resnotificationlistmsg.ts","./src/api/generated/model/resnotificationread.ts","./src/api/generated/model/resnotificationreadmsg.ts","./src/api/generated/model/resnotifysessions.ts","./src/api/generated/model/resnotifysessionsmsg.ts","./src/api/generated/model/resquotation.ts","./src/api/generated/model/resquotationcards.ts","./src/api/generated/model/resquotationcardsmsg.ts","./src/api/generated/model/resquotationcardsqtid.ts","./src/api/generated/model/resquotationlist.ts","./src/api/generated/model/resquotationlistmsg.ts","./src/api/generated/model/resquotationmsg.ts","./src/api/generated/model/resquotationquotation.ts","./src/api/generated/model/resquotationresult.ts","./src/api/generated/model/resquotationresultequalbiddata.ts","./src/api/generated/model/resquotationresultisequalbid.ts","./src/api/generated/model/resquotationresultmsg.ts","./src/api/generated/model/resquotationresultqtid.ts","./src/api/generated/model/resquotationresultwinnersupplierid.ts","./src/api/generated/model/resquotationresultwinnersuppliername.ts","./src/api/generated/model/resquotationsessions.ts","./src/api/generated/model/resquotationsessionsmsg.ts","./src/api/generated/model/resquotationsessionsqtid.ts","./src/api/generated/model/resquotationsetting.ts","./src/api/generated/model/resquotationsettinglist.ts","./src/api/generated/model/resquotationsettinglistmsg.ts","./src/api/generated/model/resquotationsettingmsg.ts","./src/api/generated/model/resquotationsettingsetting.ts","./src/api/generated/model/resquotationstatus.ts","./src/api/generated/model/resquotationstatusmsg.ts","./src/api/generated/model/resquotationstatusqtid.ts","./src/api/generated/model/resrefreshtoken.ts","./src/api/generated/model/resrefreshtokenmsg.ts","./src/api/generated/model/ressessionchat.ts","./src/api/generated/model/ressessionchatmsg.ts","./src/api/generated/model/ressessionchatsessionid.ts","./src/api/generated/model/ressupplier.ts","./src/api/generated/model/ressupplieritem.ts","./src/api/generated/model/ressupplieritemlist.ts","./src/api/generated/model/ressupplieritemlistmsg.ts","./src/api/generated/model/ressupplieritemmsg.ts","./src/api/generated/model/ressupplieritemsupplieritem.ts","./src/api/generated/model/ressupplierlist.ts","./src/api/generated/model/ressupplierlistmsg.ts","./src/api/generated/model/ressuppliermsg.ts","./src/api/generated/model/ressuppliersupplier.ts","./src/api/generated/model/restargetbreakdown.ts","./src/api/generated/model/restargetbreakdownanchoringprice.ts","./src/api/generated/model/restargetbreakdownchosenbasis.ts","./src/api/generated/model/restargetbreakdowninternetlowest.ts","./src/api/generated/model/restargetbreakdownmdprice.ts","./src/api/generated/model/restargetbreakdownmsg.ts","./src/api/generated/model/restargetbreakdownpurchase.ts","./src/api/generated/model/restargetbreakdownselling.ts","./src/api/generated/model/reswebpacketprotocol.ts","./src/api/generated/model/reswebpacketprotocolmsg.ts","./src/api/generated/model/sessiondata.ts","./src/api/generated/model/sessiondataanchoringprice.ts","./src/api/generated/model/sessiondatabidat.ts","./src/api/generated/model/sessiondatabidprice.ts","./src/api/generated/model/sessiondataemailsentat.ts","./src/api/generated/model/sessiondatarejectdeliverytype.ts","./src/api/generated/model/sessiondatarejectprice.ts","./src/api/generated/model/sessiondatarejectreason.ts","./src/api/generated/model/sessionstatus.ts","./src/api/generated/model/supplierdata.ts","./src/api/generated/model/supplierdatacode.ts","./src/api/generated/model/supplierdatacreatedat.ts","./src/api/generated/model/supplierdatamanagercontactnumber.ts","./src/api/generated/model/supplierdatamanageremail.ts","./src/api/generated/model/supplierdatamanagername.ts","./src/api/generated/model/supplierdatatotalrevenue.ts","./src/api/generated/model/supplierdataupdatedat.ts","./src/api/generated/model/supplieritemdata.ts","./src/api/generated/model/supplieritemdatacreatedat.ts","./src/api/generated/model/supplieritemdataitemcode.ts","./src/api/generated/model/supplieritemdataupdatedat.ts","./src/api/generated/model/suppliertype.ts","./src/api/generated/model/targetcandidate.ts","./src/api/generated/model/userrole.ts","./src/api/generated/model/userstatus.ts","./src/api/generated/model/validationerror.ts","./src/api/generated/model/validationerrorctx.ts","./src/api/generated/model/validationerrorlocitem.ts","./src/api/generated/notification/notification.ts","./src/api/generated/quotation/quotation.ts","./src/api/generated/quotation-setting/quotation-setting.ts","./src/api/generated/supplier/supplier.ts","./src/api/generated/supplier-item/supplier-item.ts","./src/api/mutator/custom-fetch.ts","./src/app/main.tsx","./src/app/provider.tsx","./src/app/router.tsx","./src/components/imagedropzone.tsx","./src/components/slaterenderer.tsx","./src/components/layout/authenticatedlayout.tsx","./src/components/layout/layout.tsx","./src/components/layout/notificationbell.tsx","./src/components/layout/pagecontainer.tsx","./src/components/layout/pagetoolbar.tsx","./src/components/ui/badge.tsx","./src/components/ui/button.tsx","./src/components/ui/card.tsx","./src/components/ui/combobox.tsx","./src/components/ui/data-table.tsx","./src/components/ui/dialog.tsx","./src/components/ui/drawer.tsx","./src/components/ui/dropdown-menu.tsx","./src/components/ui/input.tsx","./src/components/ui/select.tsx","./src/components/ui/sheet.tsx","./src/components/ui/switch.tsx","./src/components/ui/table-pagination.tsx","./src/components/ui/table.tsx","./src/components/ui/tabs.tsx","./src/components/ui/typography.tsx","./src/features/auth/service.ts","./src/features/auth/useauth.ts","./src/features/auth/components/profilesheet.tsx","./src/features/cards/types.ts","./src/features/cards/components/cardformsheet.tsx","./src/features/cards/components/cardtable.tsx","./src/features/cards/editor/cardscripteditor.tsx","./src/features/cards/editor/cardscripttoolbar.tsx","./src/features/cards/editor/index.ts","./src/features/cards/editor/slate.ts","./src/features/cards/editor/usecardscripteditor.ts","./src/features/cards/editor/variables.ts","./src/features/cards/hooks/usecards.ts","./src/features/dashboard/fmt.ts","./src/features/dashboard/index.ts","./src/features/dashboard/tones.ts","./src/features/dashboard/components/actionwidget.tsx","./src/features/dashboard/components/dashboardhero.tsx","./src/features/dashboard/components/deadlinewidget.tsx","./src/features/dashboard/components/emailunsentwidget.tsx","./src/features/dashboard/components/kpitile.tsx","./src/features/dashboard/components/lifecyclestepper.tsx","./src/features/dashboard/components/refwidget.tsx","./src/features/dashboard/components/resultexamples.tsx","./src/features/dashboard/components/scopesection.tsx","./src/features/dashboard/components/startchecklist.tsx","./src/features/members/api.ts","./src/features/members/types.ts","./src/features/members/components/memberformsheet.tsx","./src/features/members/components/membertable.tsx","./src/features/members/hooks/usemembers.ts","./src/features/onboarding/onboardingguidemodal.tsx","./src/features/onboarding/steps.ts","./src/features/partners/types.ts","./src/features/partners/components/exceluploadmodal.tsx","./src/features/partners/components/partnerformsheet.tsx","./src/features/partners/components/partnertable.tsx","./src/features/partners/components/supplieritemsmanager.tsx","./src/features/partners/hooks/usepartners.ts","./src/features/partners/hooks/usesupplieritems.ts","./src/features/products/types.ts","./src/features/products/components/exceluploadmodal.tsx","./src/features/products/components/priceupdatemodal.tsx","./src/features/products/components/productformsheet.tsx","./src/features/products/components/producttable.tsx","./src/features/products/hooks/useproducts.ts","./src/features/quotations/types.ts","./src/features/quotations/components/quotationcreatemodal.tsx","./src/features/quotations/components/quotationsettingsmodal.tsx","./src/features/quotations/components/quotationtable.tsx","./src/features/quotations/components/quotationdetailsheet/chattab.tsx","./src/features/quotations/components/quotationdetailsheet/drawerheadercards.tsx","./src/features/quotations/components/quotationdetailsheet/infofield.tsx","./src/features/quotations/components/quotationdetailsheet/pricingspectrum.tsx","./src/features/quotations/components/quotationdetailsheet/quotationcardstab.tsx","./src/features/quotations/components/quotationdetailsheet/regeneratemodal.tsx","./src/features/quotations/components/quotationdetailsheet/resultsummaryband.tsx","./src/features/quotations/components/quotationdetailsheet/roundtimeline.tsx","./src/features/quotations/components/quotationdetailsheet/sessionsstatustab.tsx","./src/features/quotations/components/quotationdetailsheet/statuspill.tsx","./src/features/quotations/components/quotationdetailsheet/targetpricemodal.tsx","./src/features/quotations/components/quotationdetailsheet/index.tsx","./src/features/quotations/hooks/usequotationchain.ts","./src/features/quotations/hooks/usequotations.ts","./src/lib/apierror.ts","./src/lib/confirm.tsx","./src/lib/emphasis.tsx","./src/lib/enumlabels.ts","./src/lib/excel.ts","./src/lib/notify.ts","./src/lib/useclientpagination.ts","./src/lib/useoverlayrouter.ts","./src/lib/usescrolllock.ts","./src/lib/useserverlist.ts","./src/lib/utils.ts","./src/pages/cards.tsx","./src/pages/dashboard.tsx","./src/pages/forbidden.tsx","./src/pages/login.tsx","./src/pages/members.tsx","./src/pages/not-found.tsx","./src/pages/notifications.tsx","./src/pages/partners.tsx","./src/pages/products.tsx","./src/pages/quotation.tsx","./src/pages/dev/dev-design.tsx","./src/stores/auth.ts"],"version":"5.8.3"} \ No newline at end of file