From 5bbb0aa53bfe34836c3fc1879c0f6688af6b4188 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Mon, 14 Sep 2026 08:10:30 +0900 Subject: [PATCH] =?UTF-8?q?fix(b08,b09):=20=ED=95=9C=20=EC=A4=84=20?= =?UTF-8?q?=E3=80=8C=EC=95=94=E3=80=8D=20=EB=A7=89=ED=9E=98=20=EA=B9=8C?= =?UTF-8?q?=EB=8B=AD=20=EB=B0=94=EB=A1=9C=EC=9E=A1=EC=9D=8C=20=E2=80=94=20?= =?UTF-8?q?=E3=80=8C=EA=B3=B5=EC=A2=85=EC=BD=94=EB=93=9C=20=EC=97=86?= =?UTF-8?q?=EC=9D=8C=E3=80=8D=EC=9D=B4=20=EC=95=84=EB=8B=88=EB=9D=BC=20?= =?UTF-8?q?=EC=95=94=20=EA=B0=88=EB=9E=98=20=EA=B5=AC=EC=84=B1=EB=B9=84=20?= =?UTF-8?q?=EC=9E=85=EB=A0=A5=20=ED=95=84=EC=9A=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - B08: 갈래로 안 나뉜 암 총량은 시공법만 골라서는 안 풀림 → 사유 「암 갈래 구성비(%)가 아직 없어…」 · 시공법 안내 목록에서 뺌 - B09 내역: 공종을 못 고른 줄에 B08 막힘 까닭이 있으면 그 문구 그대로(입력 필요 ↔ 매핑 구멍 가름) - 배정 프로젝트 흙깎기 암 3,104.57㎥ · 측구터파기 암 160.48㎥ 가 이 자리 · 시험 1건 Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn --- B08_Quantity/B08_Quantity_Engine_Handoff.py | 2 +- .../B08_Quantity_Engine_Handoff_Mapping.py | 6 ++++++ B08_Quantity/B08_Quantity_Engine_Handoff_Rows.py | 3 +++ B09_Estimation/B09_Estimation_BillOfQuantities.py | 6 ++++++ resources/tester/test_b08_handoff.py | 14 ++++++++++++++ 5 files changed, 30 insertions(+), 1 deletion(-) diff --git a/B08_Quantity/B08_Quantity_Engine_Handoff.py b/B08_Quantity/B08_Quantity_Engine_Handoff.py index e3b7f446..8340e70b 100644 --- a/B08_Quantity/B08_Quantity_Engine_Handoff.py +++ b/B08_Quantity/B08_Quantity_Engine_Handoff.py @@ -185,7 +185,7 @@ def build_handoff( str(row.get("ground_class")) for row in work_items if row.get("ground_class") - and row.get("ground_class") != "토사" + and row.get("ground_class") not in ("토사", "암") # 「암」은 구성비가 빠진 것 and row.get("work_item_code") is None and row.get("origin") == ORIGIN_EARTHWORK } diff --git a/B08_Quantity/B08_Quantity_Engine_Handoff_Mapping.py b/B08_Quantity/B08_Quantity_Engine_Handoff_Mapping.py index 96598873..5e735b82 100644 --- a/B08_Quantity/B08_Quantity_Engine_Handoff_Mapping.py +++ b/B08_Quantity/B08_Quantity_Engine_Handoff_Mapping.py @@ -121,6 +121,12 @@ ORIGIN_PIPE = "pipe" #: 갈래 이름(연암·보통암…)만으로는 공종을 못 고른다(2026-09-07 일감 9 실서버에서 드러남). METHOD_TO_GROUND = {"ripping": "리핑암", "blasting": "발파암"} NOTE_METHOD_MISSING = "시공법 미지정으로 공종을 못 고름" +#: 암 총량이 갈래로 안 나뉘어 한 줄 「암」으로 선 경우 — 시공법은 **갈래마다** 고르므로 이 줄은 +#: 시공법만 골라서는 안 풀린다. 빠진 입력은 구성비다(2026-09-14 흙깎기·측구터파기 암). +NOTE_ROCK_RATIO_MISSING = ( + "암 갈래 구성비(%)가 아직 없어 암 총량이 한 줄 「암」으로 섬 — 산출 조건 「암 갈래 구성비」를 " + "넣고 갈래마다 시공법(리핑·발파)을 고르면 공종이 섬" +) #: 철근으로 보는 성분 이름 조각. **정확한 낱말이 아니라 앞머리**로 본다 — #: 「이형철근 D13」·「원형철근」처럼 규격이 뒤에 붙기 때문이다. `철근콘크리트`는 성분 이름이 diff --git a/B08_Quantity/B08_Quantity_Engine_Handoff_Rows.py b/B08_Quantity/B08_Quantity_Engine_Handoff_Rows.py index 68adef0a..602d9aa3 100644 --- a/B08_Quantity/B08_Quantity_Engine_Handoff_Rows.py +++ b/B08_Quantity/B08_Quantity_Engine_Handoff_Rows.py @@ -19,6 +19,7 @@ from B08_Quantity.B08_Quantity_Engine_Handoff_Mapping import ( METHOD_TO_GROUND, NOTE_HAUL_IN_SUMMARY, NOTE_METHOD_MISSING, + NOTE_ROCK_RATIO_MISSING, ORIGIN_EARTHWORK, ORIGIN_HAUL, ORIGIN_SLOPE, @@ -54,6 +55,8 @@ def _mapping_ground(ground: str | None, methods: dict[str, str | None]) -> tuple """ if ground is None or ground == "토사": return ground, "" + if ground == "암": + return None, NOTE_ROCK_RATIO_MISSING # 갈래로 안 나뉜 총량 — 시공법만으론 안 풀림 method = methods.get(ground) mapped = METHOD_TO_GROUND.get(method or "") if mapped: diff --git a/B09_Estimation/B09_Estimation_BillOfQuantities.py b/B09_Estimation/B09_Estimation_BillOfQuantities.py index 4712202a..aae78a79 100644 --- a/B09_Estimation/B09_Estimation_BillOfQuantities.py +++ b/B09_Estimation/B09_Estimation_BillOfQuantities.py @@ -546,12 +546,18 @@ def build_bill( if item.origin == "structure" else "공종을 못 골랐습니다 — B08 인계에 공종코드가 없습니다." ) + # ⚠ B08 이 막힘 까닭을 실어 보냈으면 **그 문구를 그대로** — 「코드가 없다」로 덮으면 + # 입력하면 풀리는 자리(암 갈래 구성비·시공법)가 매핑 구멍으로 읽힘(2026-09-14 흙깎기 암). + if item.blocked_reason: + kind = item.blocked_kind or _NOT_OUR_ROW + reason = f"{_BLOCKED_LABELS.get(kind, '막힘')} — {item.blocked_reason}" result.missing.append( { "name": item.display_name, "unit": item.unit, "quantity": str(item.quantity), "reason": reason, + **({"blocked_kind": item.blocked_kind} if item.blocked_kind else {}), } ) diff --git a/resources/tester/test_b08_handoff.py b/resources/tester/test_b08_handoff.py index 9e95f95f..c31fc7e2 100644 --- a/resources/tester/test_b08_handoff.py +++ b/resources/tester/test_b08_handoff.py @@ -367,6 +367,20 @@ def test_시공법을_안_정하면_찍지_않고_드러냄() -> None: assert any("시공법" in item for item in handoff["unmatched_work_items"]) +def test_갈래로_안_나뉜_암은_구성비가_빠졌다고_말함() -> None: + """2026-09-14 — 한 줄 「암」은 시공법만 골라서는 안 풀림. B09 내역도 이 까닭을 그대로 실음.""" + handoff = build_handoff(summary_table=집계표(집계줄("흙깎기", "암", 100.0))) + row = handoff["work_items"][0] + assert row["work_item_code"] is None and row["blocked_kind"] == "input_missing" + assert "암 갈래 구성비" in row["blocked_reason"] + assert handoff["missing_method_classes"] == [] # 시공법 안내에 「암」을 안 띄움 + + from B09_Estimation.B09_Estimation_BillOfQuantities import build_bill + + bill = build_bill(handoff) + assert any("입력이 필요합니다 — 암 갈래 구성비" in m["reason"] for m in bill.missing) + + def test_토사는_시공법이_필요없음() -> None: handoff = build_handoff(summary_table=집계표(집계줄("흙깎기", "토사", 100.0))) assert handoff["work_items"][0]["work_item_code"] == "FP-09-03-02"