Merge remote-tracking branch 'origin/dev' into main_laptop_1

This commit is contained in:
2026-09-15 00:46:45 +09:00
10 changed files with 246 additions and 95 deletions
@@ -0,0 +1,105 @@
"""준비공 상태 칸 — 「입력이 필요함」과 「값을 낼 근거가 없음」을 가른다 (2026-09-14 브레인 ㉴).
훑기에서 잡은 거짓 사유: 상태 칸이 **입력만 넣으면 서는 줄**(표토 두께·거리 · 임목폐기물 조사값 ·
부대시설 개소 · 임목파쇄 부피)까지 「값을 낼 근거가 없음」으로 덮었다. 반대로 인계는
**우리가 만들어야 하는 줄**(사방 원단위 · 뿌리 부피)까지 「입력이 필요합니다」로 보냈다.
① 입력이면 풀리는 줄 → 상태 「입력이 필요함」 · 인계 `input_missing`
② 자료·산식이 없는 줄 → 상태 「값을 낼 근거가 없음」 · 인계 `unit_data_missing`
③ 앞 단계(횡단·사면표)가 안 선 줄도 사람이 할 일이라 ①
④ 규준틀이 필요 없는 노선(비탈길이 10m 이상 구간 없음)은 「해당 없음」
"""
from __future__ import annotations
from B08_Quantity.B08_Quantity_Engine_Handoff import build_handoff
from B08_Quantity.B08_Quantity_Engine_Preparation import build_table
from B08_Quantity.B08_Quantity_Engine_Preparation_Status import (
STATUS_NEEDS_INPUT,
STATUS_NOT_APPLICABLE,
STATUS_PENDING,
)
SLOPE = {"tree_removal_fill": 600.0, "tree_removal_cut": 400.0, "face_dressing_cut": 300.0}
SHORT_SLOPES = [{"lengths": {"fill": 4.0}, "distance_m": 20.0, "fill_height_m": 2.0}]
def _table(**overrides: object) -> dict:
args: dict = {
"slope_totals": SLOPE,
"structures": [{"type_id": "erosion_check"}],
"slope_rows": SHORT_SLOPES,
"road_surface_area_m2": 1000.0,
"chipping_enabled": True,
"tree_waste": {},
"ancillary_counts": {},
}
args.update(overrides)
return build_table(**args)
def _by_item(table: dict) -> dict[str, dict]:
return {row["item"]: row for row in table["rows"]}
def test_입력이면_서는_줄은_입력이_필요함() -> None:
rows = _by_item(_table())
for item in (
"표토 운반·적치",
"임목파쇄",
"임목폐기물 처리",
"국가지점번호판",
"가설창고(컨테이너)",
):
assert rows[item]["status"] == STATUS_NEEDS_INPUT, item
# 두께를 넣으면 거리 칸이 남는다 — 여전히 입력이 필요함.
with_thickness = _by_item(_table(topsoil_thickness_m=0.2))
assert with_thickness["표토 운반·적치"]["status"] == STATUS_NEEDS_INPUT
def test_자료나_산식이_없는_줄은_근거가_없음() -> None:
rows = _by_item(_table())
assert rows["뿌리 운반"]["status"] == STATUS_PENDING
assert (
rows[next(k for k, r in rows.items() if r["group"] == "사방공")]["status"] == STATUS_PENDING
)
def test_앞_단계가_안_섰으면_입력이_필요함() -> None:
rows = _by_item(_table(slope_totals={}, slope_rows=[], road_surface_area_m2=None))
assert rows["표토제거"]["status"] == STATUS_NEEDS_INPUT
assert rows["뿌리 적재"]["status"] == STATUS_NEEDS_INPUT
assert rows["비탈 규준틀"]["status"] == STATUS_NEEDS_INPUT
assert rows["수평 규준틀"]["status"] == STATUS_NEEDS_INPUT
def test_규준틀이_필요_없는_노선은_해당_없음() -> None:
assert _by_item(_table())["비탈 규준틀"]["status"] == STATUS_NOT_APPLICABLE
def test_인계_막힘_갈래가_상태를_따른다() -> None:
table = _table()
handed = {row["name"]: row for row in build_handoff(preparation_table=table)["work_items"]}
assert handed["표토 운반·적치"]["blocked_kind"] == "input_missing"
assert handed["임목파쇄"]["blocked_kind"] == "input_missing"
# 우리가 만들어야 하는 줄 — 「입력이 필요합니다」로 보내면 사용자가 헛걸음한다.
assert handed["뿌리 운반"]["blocked_kind"] == "unit_data_missing"
assert handed["골막이"]["blocked_kind"] == "unit_data_missing"
# 해당 없음은 막힘이 아니다.
assert handed["비탈 규준틀"]["blocked_kind"] is None
# 공종이 품셈에 없는 부대시설은 개소를 넣어도 종전대로 「입력」(별도 단가) 갈래.
entered = _table(ancillary_counts={"national_point_sign": 3})
sign = next(
row
for row in build_handoff(preparation_table=entered)["work_items"]
if row["name"] == "국가지점번호판"
)
assert sign["blocked_kind"] == "input_missing"
def test_표_머리가_두_갈래를_따로_센다() -> None:
table = _table()
rows = table["rows"]
assert table["input_count"] == sum(1 for r in rows if r["status"] == STATUS_NEEDS_INPUT)
assert table["pending_count"] == sum(1 for r in rows if r["status"] == STATUS_PENDING)
assert table["input_count"] > 0 and table["pending_count"] > 0
+3 -2
View File
@@ -23,7 +23,7 @@ sys.path.insert(0, str(ROOT))
from B08_Quantity.B08_Quantity_Engine_Preparation import ( # noqa: E402
STATUS_COUNTED_ELSEWHERE,
STATUS_PENDING,
STATUS_NEEDS_INPUT,
STATUS_READY,
build_table,
preparation_rows,
@@ -61,7 +61,8 @@ def test_20m_이내면_제거_품에_들어_따로_안_셈() -> None:
def test_거리를_안_넣으면_막고_사유() -> None:
"""⚠ 「최고 홍수위보다 높은 장소」는 현장이 정한다 — 품셈이 거리를 주지 않는다."""
row = (0.2, None)["표토 운반·적치"]
assert row["amount"] is None and row["status"] == STATUS_PENDING
# 거리만 넣으면 서는 줄 — 「근거 없음」이 아니라 「입력이 필요함」(2026-09-14 ㉴).
assert row["amount"] is None and row["status"] == STATUS_NEEDS_INPUT
assert "운반거리가 아직 입력되지 않았습니다" in row["reason"]
assert row["reference_amount"] == 200.0 # 값을 버리지 않는다
+3 -2
View File
@@ -21,7 +21,7 @@ ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(ROOT))
from B08_Quantity.B08_Quantity_Engine_Preparation import ( # noqa: E402
STATUS_PENDING,
STATUS_NEEDS_INPUT,
STATUS_READY,
build_table,
)
@@ -43,7 +43,8 @@ def test_켜면_줄이_선다() -> None:
def test_켜도_부피는_지어내지_않는다() -> None:
row = (True)["임목파쇄"]
assert row["amount"] is None and row["status"] == STATUS_PENDING
# 부피를 넣으면 서는 줄 — 「입력이 필요함」(2026-09-14 ㉴).
assert row["amount"] is None and row["status"] == STATUS_NEEDS_INPUT
assert "부피" in row["reason"]