Files
Aislo/resources/tester/test_b08_formwork.py
T
eomsangdonandClaude Opus 5 a314ac12fd feat(b05·b06·b08): BOX암거 수량식 — 등록부 두께·연장 칸 + m당 × 연장 전개식 · 세월교·날개벽은 근거 없음 사유로 닫음(12장 D · 브레인 판정 ①~⑥)
- 등록부 box_culvert: 연장(기본값 없음) · 측벽 0.3 · 상·저판 0.25 · 헌치 0.2 · 버림 0.1 — 제안값 = 산림과임업기술(임도) 5장 수량산출 예제 · KDS 44 90 00 300㎜ 병기(판 0.25 는 못 미침을 나란히)
- B06 BOX 세트(파이썬·TS 짝)가 두께 칸을 읽음 — 종전 「세월교 값 승계」(벽 0.2·판 0.3) 걷음 · 그림 따라감
- B08 전개식 `_UnitQuantity_Box`: 콘크리트 · 버림 · 유로폼(외벽·내벽·상판 밑·귀면) · 버림 옆 합판 · 동바리 · 비계(시종점 두 면은 개소당 한 번) · 철근은 울진 2×2 관측(D13 179·D16 157kg/m)만, 나머지 크기는 「크기별 식 없음」
- 울진 기번3 「암거수량집계표(2×2)」 m당과 맞음: 레미콘 2.84 · 버림 0.28 · 유로폼 11.131 · 합판 0.2 · 동바리 3.92 · 비계 벽체 5.2
- 치수 칸을 안 적은 BOX 는 제안값으로 서되 미확정(금액 밖) · 연장이 비면 안 섬
- 묶음 조각 12-01-01·12-38·12-04(6회)·12-03·12-20·12-19·12-25 · 동바리 대상 표시 · 세월교 「수량 근거 없음」

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
2026-09-15 02:36:25 +09:00

136 lines
5.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""거푸집 사용횟수 검사 — 품셈 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"]
# BOX암거는 2026-09-15 전개식이 서서 대상에서 빠짐 — 세월교만 남음(근거 없음 사유).
assert set(status["pending_types"]) == {"ford_bridge"}
def test_표에도_동바리_상태가_실림() -> None:
assert build_table([옹벽()])["shoring"]["applicable"] is False
box = {
"type_id": "box_culvert",
"options": {
"body_width_m": 2.0,
"body_height_m": 2.0,
"wall_thickness_m": 0.3,
"slab_thickness_m": 0.3,
"haunch_m": 0.2,
"blinding_thickness_m": 0.1,
"length_m": 5.0,
},
}
assert build_table([box])["shoring"]["applicable"] is True