Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
117 lines
5.1 KiB
Python
117 lines
5.1 KiB
Python
"""철근 이름·규격 가르기(2026-09-14 · 목록 3+4) — **가르기 전후 물량이 그대로**인지 잼.
|
|
|
|
「이형철근 D13」 한 칸을 이름 「이형철근」 + 규격 「D13」 으로 가르면 셋이 같은 글자에 묶여 있어
|
|
하나만 고치면 조용히 어긋남(브레인 경고): ① 묶음 조각 `from_components` · `amounts[name]`
|
|
(D13·D16 이 서로 덮어씀) ② 이중계상 경계 검사 `_pickers`·`destinations`(못 집으면 검사가 놂)
|
|
③ 자재총괄 줄·할증. 이 시험은 **가르기 전 코드에서 먼저 초록**으로 만들고 가른 뒤에도 초록이어야 함.
|
|
|
|
옹벽 반중력식 10m D13 13.45 · D16 30.42 ㎏/m → 조각 0.4387 ton · 자재 134.5 · 304.2 ㎏
|
|
집수정 □형 Ø800 1개소 D13 4.776 ㎏
|
|
L형수로 H=0.2 10m D13 0.398 ㎏/m → 3.98 ㎏
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import copy
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
sys.path.insert(0, str(ROOT))
|
|
|
|
from B08_Quantity.B08_Quantity_Engine_Handoff import build_handoff, load_mapping # noqa: E402
|
|
from B08_Quantity.B08_Quantity_Engine_Handoff_Boundaries import ( # noqa: E402
|
|
verify_double_count_boundaries,
|
|
)
|
|
from B08_Quantity.B08_Quantity_Engine_MaterialSummary import build_table # noqa: E402
|
|
from B08_Quantity.B08_Quantity_Engine_UnitQuantity import build_table as build_unit # noqa: E402
|
|
|
|
|
|
def _구조물들() -> dict:
|
|
return build_unit(
|
|
[
|
|
{
|
|
"structure_id": "w1",
|
|
"type_id": "retaining_wall",
|
|
"start_m": 100.0,
|
|
"end_m": 110.0,
|
|
"options": {"form": "반중력식", "height_m": 2.0, "length_m": 10.0},
|
|
},
|
|
{
|
|
"structure_id": "b1",
|
|
"type_id": "pipe_inlet_basin",
|
|
"start_m": 200.0,
|
|
"end_m": 200.0,
|
|
"options": {
|
|
"inlet_basin_form": "□형(기본형)",
|
|
"inlet_basin_material": "콘크리트",
|
|
"pipe_diameter_mm": "800",
|
|
},
|
|
},
|
|
{
|
|
"structure_id": "d1",
|
|
"type_id": "open_ditch",
|
|
"start_m": 300.0,
|
|
"end_m": 310.0,
|
|
"options": {"ditch_spec": "L형수로 H=0.2", "length_m": 10.0},
|
|
},
|
|
],
|
|
{"retaining_wall": "옹벽", "pipe_inlet_basin": "집수정", "open_ditch": "개거"},
|
|
)
|
|
|
|
|
|
def test_옹벽_철근_조각은_D13_D16_을_다_모아_ton() -> None:
|
|
row = next(
|
|
r
|
|
for r in build_handoff(unit_quantity_table=_구조물들())["work_items"]
|
|
if r.get("composite_parts")
|
|
)
|
|
rebar = next(p for p in row["composite_parts"] if "12-03" in str(p.get("code")))
|
|
assert rebar["quantity"] == pytest.approx(0.4387) and not rebar.get("not_ready")
|
|
from B08_Quantity.B08_Quantity_Engine_Handoff import structure_kind
|
|
|
|
wall = next(s for s in _구조물들()["structures"] if s["type_id"] == "retaining_wall")
|
|
assert structure_kind(wall) == "철근구조물"
|
|
|
|
|
|
def test_자재총괄_철근_줄_물량과_할증이_그대로() -> None:
|
|
table = build_table(_구조물들())
|
|
rebar = {
|
|
row["supply_key"]: (row["net_amount"], row["surcharge_pct"], row["total_amount"])
|
|
for row in table["rows"]
|
|
if row["supply_key"].startswith("이형철근")
|
|
}
|
|
assert set(rebar) == {"이형철근 D13", "이형철근 D16"} # 관급구분·단가 키는 전후 같은 글자
|
|
assert rebar["이형철근 D13"][0] == pytest.approx(134.5 + 4.776 + 3.98)
|
|
assert rebar["이형철근 D16"][0] == pytest.approx(304.2)
|
|
assert rebar["이형철근 D13"][1] == 3 and rebar["이형철근 D16"][1] == 3 # 1-3-1 이형철근
|
|
assert "이형철근" not in " ".join(table["missing_rate_materials"])
|
|
|
|
|
|
def test_경계_검사가_철근을_여전히_집는다() -> None:
|
|
"""철근이 토공 축으로 잘못 가면 묶음 조각이 또 센다고 걸려야 함 — 못 집으면 검사가 놂."""
|
|
unit = copy.deepcopy(_구조물들())
|
|
wall = next(s for s in unit["structures"] if s["type_id"] == "retaining_wall")
|
|
for component in wall["components"]:
|
|
if str(component["name"]).startswith("이형철근"):
|
|
component["destination"] = "earthwork"
|
|
found = verify_double_count_boundaries(unit, None, load_mapping())
|
|
assert any("이형철근" in text and "묶음 조각" in text for text in found), found
|
|
assert not verify_double_count_boundaries(_구조물들(), None, load_mapping())
|
|
|
|
|
|
def test_가른_뒤_이름과_규격이_따로_서고_할증은_별칭_없이_이어짐() -> None:
|
|
table = build_table(_구조물들())
|
|
rows = [(r["name"], r["spec"]) for r in table["rows"] if r["name"].startswith("이형철근")]
|
|
assert sorted(rows) == [("이형철근", "D13"), ("이형철근", "D16")]
|
|
unit = _구조물들()
|
|
specs = {
|
|
(c["name"], c.get("spec"))
|
|
for s in unit["structures"]
|
|
for c in s["components"]
|
|
if str(c["name"]).startswith("이형철근")
|
|
}
|
|
assert specs == {("이형철근", "D13"), ("이형철근", "D16")}
|