fix(b08,b09): 한 줄 「암」 막힘 까닭 바로잡음 — 「공종코드 없음」이 아니라 암 갈래 구성비 입력 필요

- B08: 갈래로 안 나뉜 암 총량은 시공법만 골라서는 안 풀림 → 사유 「암 갈래 구성비(%)가 아직 없어…」 · 시공법 안내 목록에서 뺌
- B09 내역: 공종을 못 고른 줄에 B08 막힘 까닭이 있으면 그 문구 그대로(입력 필요 ↔ 매핑 구멍 가름)
- 배정 프로젝트 흙깎기 암 3,104.57㎥ · 측구터파기 암 160.48㎥ 가 이 자리 · 시험 1건

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
This commit is contained in:
2026-09-14 08:10:30 +09:00
co-authored by Claude Opus 5
parent 7b2affe119
commit 5bbb0aa53b
5 changed files with 30 additions and 1 deletions
+1 -1
View File
@@ -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
}
@@ -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」·「원형철근」처럼 규격이 뒤에 붙기 때문이다. `철근콘크리트`는 성분 이름이
@@ -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:
@@ -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 {}),
}
)
+14
View File
@@ -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"