From 1a859b198c12ccd623110b853a7be769f8d9bb0f Mon Sep 17 00:00:00 2001 From: Mina Choi Date: Wed, 12 Aug 2026 11:02:10 +0900 Subject: [PATCH] =?UTF-8?q?[fix]=20negodata:=20=EC=A7=81=EC=A0=91=20?= =?UTF-8?q?=EB=82=99=EC=B0=B0=20=EB=82=99=EC=B0=B0=EA=B0=80=EA=B0=80=20?= =?UTF-8?q?=EA=B3=84=EC=95=BD=EA=B0=80=20=EB=8C=80=EC=8B=A0=20=EA=B1=B0?= =?UTF-8?q?=EB=B6=80=EA=B0=80=EB=A1=9C=20=ED=91=9C=EC=8B=9C=EB=90=98?= =?UTF-8?q?=EB=8D=98=20=EB=AC=B8=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 세션 목록 API(queries.py)가 SessionData 를 필드별로 수동 조립하는데 contract_price 를 빠뜨려, 담당자가 입력한 계약가가 응답에 안 실렸다(항상 null). 그 결과 프론트가 계약가를 못 읽고 제출가(거부가/투찰가)로 폴백해, 14,000,000 으로 직접 낙찰해도 낙찰가에 거부가가 떴다. 프로토콜·ORM·컬럼은 이미 있었으나 이 직렬화 한 줄이 누락돼 있었다. - queries.py: SessionData 조립에 contract_price=r.contract_price 추가 - ResultSummaryBand: 스펙트럼 낙찰점도 제출가(awardPrice)가 아니라 계약가(contractPrice)로 찍어 레일 낙찰가와 일치시킴 검증: 세션 API 응답에 contract_price 실제 내려오는 것 확인(화면 아닌 응답 직접). negodata 테스트 통과. --- negodata/backend/services/quotation/queries.py | 1 + .../QuotationDetailSheet/ResultSummaryBand.tsx | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/negodata/backend/services/quotation/queries.py b/negodata/backend/services/quotation/queries.py index 1d5ea0f..5216303 100644 --- a/negodata/backend/services/quotation/queries.py +++ b/negodata/backend/services/quotation/queries.py @@ -188,6 +188,7 @@ class QueriesMixin: end_time=r.end_time, reject_reason=r.reject_reason, reject_price=r.reject_price, + contract_price=r.contract_price, reject_delivery_type=r.reject_delivery_type, email_sent_at=r.email_sent_at, custom=r.custom, diff --git a/negodata/front/src/features/quotations/components/QuotationDetailSheet/ResultSummaryBand.tsx b/negodata/front/src/features/quotations/components/QuotationDetailSheet/ResultSummaryBand.tsx index 804b497..b36e9bc 100644 --- a/negodata/front/src/features/quotations/components/QuotationDetailSheet/ResultSummaryBand.tsx +++ b/negodata/front/src/features/quotations/components/QuotationDetailSheet/ResultSummaryBand.tsx @@ -9,6 +9,7 @@ import { awardPrice, buildQuotationResult, ceilingPriceOf, + contractPrice, is1v1, sessionStatusLabel, CHAIN_ROUND_STATE_LABEL, @@ -47,11 +48,13 @@ export function ResultSummaryBand({ const showManualBadge = quotation.award_type === AwardType.MANUAL; const reason = awardMeta(quotation)?.reason ?? ''; - // 가격을 제출한 협력사만 점으로. 낙찰자는 강조. + // 가격을 제출한 협력사만 점으로. 낙찰자는 강조하고, 낙찰자 값은 확정 계약가(직접 낙찰이면 계약가)를 쓴다 + // — 제출가(거부가 등)로 찍으면 레일 낙찰가와 어긋난다. const bids: SpectrumBid[] = sessionViews.flatMap((s) => { - const value = awardPrice(s); + const isWinner = winnerId != null && s.supplier_id === winnerId; + const value = isWinner ? contractPrice(s) : awardPrice(s); if (value == null) return []; - return [{ name: s.supplier_name, value, isWinner: winnerId != null && s.supplier_id === winnerId }]; + return [{ name: s.supplier_name, value, isWinner }]; }); return (