① 터파기·되메우기·잔토 — 소광리 「옹벽2.0」에 줄이 없어 브레인 판정대로 기초 폭 + 양쪽 여유 0.3(같은 파일 식생옹벽블럭 기초 터파기)로 수직 · 깊이 기초 0.4 + 버림 0.1 + 기초잡석 · 비탈분 제외(지반선이 제원에 없음) · earthwork 로만 m당 터파기 1.54 · 되메우기 0.36(터파기 − 기초·전단키·버림·잡석) · 잔토 1.18 · 인계 심도 구분은 판 깊이(0.7 m → 0~1m) ② 관측 값을 원문으로 — 콘크리트 1.35→1.345 · 버림 0.15→0.145 · 유로폼 3.2→3.205 ⇒ 기초잡석 0.30→0.29 ③ 물구멍관 — 실무 관측 식(「옹벽2.0」 T31 벽 높이 ÷ 개소당 면적 × 관 0.4)에 제원 칸이 닿음 · 규격 Ø50 이 붙어 자재총괄에서 돌쌓기 물구멍관과 한 줄(33.924 + 3.2 → 37.124 m) · 관 길이는 관측값으로 표시 - 검증 프로젝트 내역 본체 122,848,989 → 124,202,681원(+1,353,692 = 구조물터파기 심도 0~1m 15.4㎥ 1,341,216 + 되메우기 21.0→24.6㎥ +12,476) - 그림: 터파기 점선·「터파기 폭 2.20 × 깊이 0.70」 · 표 사유와 같은 말 · 옛 값을 박은 시험 8건을 원문 값으로(전 값은 주석) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
122 lines
4.6 KiB
Python
122 lines
4.6 KiB
Python
"""거푸집 사용횟수 검사 — 품셈 1-7-1 · 2026-09-07 ⑩.
|
||
|
||
⚠ 사용횟수는 **관측값이 아니라 법**이다 — 품셈 1-7-1 이 구조물 종류별로 정해 둔다.
|
||
⚠⚠ **횟수별 재료 환산은 여기서 하지 않는다.** 품셈 12-4 의 비율(%)은 일위대가 재료비에
|
||
걸리는 값이라, B08 이 곱해 넘기면 B09 가 또 곱해 두 번 준다.
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
ROOT = Path(__file__).resolve().parents[2]
|
||
sys.path.insert(0, str(ROOT))
|
||
|
||
from B08_Quantity.B08_Quantity_Engine_Formwork import ( # noqa: E402
|
||
FORMWORK_NAMES,
|
||
NOTE_REUSE_MISSING,
|
||
FormworkTable,
|
||
annotate,
|
||
load_formwork_table,
|
||
shoring_status,
|
||
)
|
||
from B08_Quantity.B08_Quantity_Engine_UnitQuantity import build_table # noqa: E402
|
||
|
||
|
||
def 옹벽() -> dict:
|
||
return {
|
||
"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},
|
||
}
|
||
|
||
|
||
def test_원문에_이름이_있는_구조물은_횟수가_붙음() -> None:
|
||
"""품셈 1-7-1 의 3회 줄에 「옹벽」이 그대로 있다."""
|
||
table = build_table([옹벽()], {"retaining_wall": "옹벽"})
|
||
forms = [c for s in table["structures"] for c in s["components"] if c["name"] in FORMWORK_NAMES]
|
||
assert forms
|
||
assert all(c["reuse_count"] == 3 for c in forms)
|
||
assert all("1-7-1" in c["reuse_note"] for c in forms)
|
||
assert table["formwork_reuse_missing"] == []
|
||
|
||
|
||
def test_횟수별_비율을_여기서_곱하지_않을것() -> None:
|
||
"""⚠ 이 시험이 이 파일의 핵심 — 합판 3회 46.1 % 를 여기서 곱하면 B09 와 겹쳐 두 번 준다.
|
||
B08 이 내는 것은 **접촉 면적 그대로**이고 횟수는 옆에 적기만 한다."""
|
||
table = build_table([옹벽()], {"retaining_wall": "옹벽"})
|
||
euroform = next(
|
||
c for s in table["structures"] for c in s["components"] if c["name"] == "유로폼"
|
||
)
|
||
# 3.205 ㎡/m × 10m — 46.1 % 를 곱하지 않았다(2026-09-14 원문 값 3.205 · 전 라이브러리 3.20 → 32.0)
|
||
assert abs(euroform["amount"] - 32.05) < 1e-9
|
||
# 비율표는 데이터에 있되 값에 안 걸린다.
|
||
assert load_formwork_table().reuse_ratio_pct["plywood"]["3"] == 46.1
|
||
|
||
|
||
def test_모르는_종류는_지어내지_않고_미확보() -> None:
|
||
structures = [
|
||
{
|
||
"type_id": "듣도보도못한구조물",
|
||
"name": "무엇",
|
||
"components": [{"name": "합판거푸집", "unit": "㎡", "amount": 5.0}],
|
||
}
|
||
]
|
||
notes, missing = annotate(structures)
|
||
assert missing == ["듣도보도못한구조물"]
|
||
assert structures[0]["components"][0]["reuse_count"] is None
|
||
assert structures[0]["components"][0]["reuse_note"] == NOTE_REUSE_MISSING
|
||
|
||
|
||
def test_거푸집이_없는_구조물은_건드리지_않음() -> None:
|
||
structures = [
|
||
{
|
||
"type_id": "retaining_wall",
|
||
"components": [{"name": "콘크리트", "unit": "㎥", "amount": 1.0}],
|
||
}
|
||
]
|
||
notes, missing = annotate(structures)
|
||
assert notes == [] and missing == []
|
||
assert "reuse_count" not in structures[0]["components"][0]
|
||
|
||
|
||
def test_이름은_정확히_일치로만_본다() -> None:
|
||
"""부분일치면 「거푸집씻기」(공사용수 항목)가 거푸집으로 잡힌다."""
|
||
structures = [
|
||
{
|
||
"type_id": "retaining_wall",
|
||
"components": [{"name": "거푸집씻기", "unit": "㎥", "amount": 1.0}],
|
||
}
|
||
]
|
||
annotate(structures)
|
||
assert "reuse_count" not in structures[0]["components"][0]
|
||
|
||
|
||
def test_파일이_없으면_전부_미확보() -> None:
|
||
structures = [
|
||
{
|
||
"type_id": "retaining_wall",
|
||
"components": [{"name": "유로폼", "unit": "㎡", "amount": 1.0}],
|
||
}
|
||
]
|
||
notes, missing = annotate(structures, FormworkTable())
|
||
assert missing == ["retaining_wall"]
|
||
|
||
|
||
# ── 동바리 ──────────────────────────────────────────────────────────
|
||
|
||
|
||
def test_동바리는_대상이_없으면_없다고_말할것() -> None:
|
||
"""0 으로 적으면 「대상이 없음」과 「값이 0」이 구별되지 않는다."""
|
||
status = shoring_status()
|
||
assert status["applicable"] is False
|
||
assert status["reason"]
|
||
assert set(status["pending_types"]) == {"box_culvert", "ford_bridge"}
|
||
|
||
|
||
def test_표에도_동바리_상태가_실림() -> None:
|
||
assert build_table([옹벽()])["shoring"]["applicable"] is False
|