From 4b0455c23784cbaa10e0beafa3243d922e9b46d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=AF=BC=ED=97=8C?= Date: Mon, 6 Jul 2026 17:28:26 +0900 Subject: [PATCH] =?UTF-8?q?fix(negotiation):=20=ED=98=91=EC=83=81=EC=99=84?= =?UTF-8?q?=EB=A3=8C=20=EC=84=B8=EC=85=98=20=EC=9E=AC=EC=A7=84=EC=9E=85=20?= =?UTF-8?q?=EC=8B=9C=20=EA=B2=AC=EC=A0=81=EB=A7=88=EA=B0=90=C2=B7=EB=A7=88?= =?UTF-8?q?=EA=B0=90=EC=8B=9C=EA=B0=84=20=EA=B2=80=EC=A6=9D=20=EC=83=9D?= =?UTF-8?q?=EB=9E=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - DONE 세션의 participate 는 결과 열람용 재진입(무변경)이므로 견적마감(NEGO_QUOTATION_CLOSED)·마감시간 검증을 건너뛴다 - reject 는 blocked_statuses 로 DONE 을 이미 차단하므로 이 분기는 participate 에만 적용 - 테스트: 견적마감+마감시간 경과 상태에서도 완료 세션 참여 성공, 세션·견적 상태 무변경 검증 Co-Authored-By: Claude Fable 5 --- backend/services/negotiation_service.py | 6 ++++++ backend/tests/test_negotiation.py | 16 ++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/backend/services/negotiation_service.py b/backend/services/negotiation_service.py index 10a11f6..f551bf2 100644 --- a/backend/services/negotiation_service.py +++ b/backend/services/negotiation_service.py @@ -112,6 +112,12 @@ class NegotiationService: ) if err_type != ErrorType.SUCCESS or quote is None: return ErrorType.NEGO_NOT_FOUND, None, None + + # 협상완료 세션은 결과 열람용 재진입(무변경)이므로 견적마감·마감시간 검증을 건너뛴다. + # reject 는 blocked_statuses 로 DONE 을 이미 막으므로 이 분기는 participate 에만 닿는다. + if sess.status == SessionStatus.DONE.value: + return ErrorType.SUCCESS, sess, quote + if quote.status == QuotationStatus.CLOSED.value: return ErrorType.NEGO_QUOTATION_CLOSED, None, None diff --git a/backend/tests/test_negotiation.py b/backend/tests/test_negotiation.py index 8c68603..4c5663c 100644 --- a/backend/tests/test_negotiation.py +++ b/backend/tests/test_negotiation.py @@ -221,6 +221,22 @@ async def test_participate_in_progress_no_state_change(client, nego_seed, db_eng assert await _quotation_status(db_engine, qid) == 2 # 무변경 +async def test_participate_done_bypasses_quotation_closed(client, nego_seed, db_engine): + """협상완료 세션은 결과 열람용 재진입이므로 견적마감·마감시간이 지나도 참여(진입) 가능.""" + token = await _login_token(client) + sid, qid = nego_seed["sids"]["C"], nego_seed["qids"]["C"] # 협상완료 + async with db_engine.begin() as conn: + await conn.execute( + text("UPDATE quotation.quotations SET status = 3, end_time = now() - make_interval(hours => 1) WHERE qt_id = :qid"), + {"qid": qid}, + ) # 견적마감 + 마감시간 경과 + r = await _participate(client, token, sid) + assert r.json()["result"]["success"] is True + assert r.json()["session_id"] == str(sid) + assert await _session_status(db_engine, sid) == 3 # 무변경 (협상완료 유지) + assert await _quotation_status(db_engine, qid) == 3 # 무변경 (견적마감 유지) + + async def test_participate_session_not_found(client, nego_seed): token = await _login_token(client) r = await _participate(client, token, str(uuid.uuid4()))