Files
Aislo/resources/tester/test_b08_formwork.py
T
eomsangdonandClaude Opus 5 d466bf67cf fix(data): 4바퀴 기초값 — 각재 비율 지어낸 것 뺌 · 손료 칸 밀림 · 전문공사 300억 이상 · 제조 노임 상위업종
브레인 4바퀴. 원문을 열어 하나씩 확인한 뒤 고침. **값(숫자)은 원문 그대로, 자리·이름만 맞춤.**

**① 거푸집 「각재」 비율 여섯 — 지어낸 것이라 뺌**
  원문 12-4(F0336)는 **「합 판」 한 줄에 두 열**(재료별% · 노무비%)을 적고 「각 재」 줄엔 비율이 없음.
  각재 자리에 있던 값이 **합판 줄의 노무비 열과 한 자도 안 다름** — 다른 열을 갖다 쓴 것이었음.
  ⇒ `plywood` → `plywood_material_pct` · 노무비 열은 `plywood_labor_pct` 로 제자리 ·
    각재는 `timber_absent` 로 **비워 두고 사유**(옛 값도 함께 남김)

**② 기계 손료 5202·5203 칸 밀림** — 규격 열이 둘·셋인 표라 한 칸(5202)·두 칸(5203) 밀려
  상각비율 자리에 내용시간(800·4,000)이 들어가 있었음. 원문 건설 8장 L2617~2633 대로 여덟 줄 맞춤

**③ 전문공사 일반관리비 300억 이상** — 마지막 구간이 「100억-300억 미만」으로 닫혀 **300억 넘는
  전문공사가 어느 구간에도 안 걸렸음.** 원본 XLSX 대로 300~1000억 · 1000억 이상(둘 다 4.5%)을 더함.
  ⚠ 대조 시험의 구간 지도(`SPECIAL_PRICE`)에도 그 둘이 없어 원문 쪽에서도 안 잡히고 있었음 — 함께 채움

**④ 제조 노임 115~123 상위업종** — 「품질 관리 / 하위업종」인데 하위만 담아 반쪽이었음(아홉 줄).
  원문(중소기업중앙회 조사표)대로 채움. 노임 값은 안 건드림

**⑤ 덤프 토사 E0 는 0.60 이 맞음** — 원문 10-12-1 은 식에 `E0=0.75` 를 적지만 바로 아래 [주]⑤
  「굴착기의 작업능력 산정 비교」 표가 `E0 | 토사 | 0.60(불량)` 비고에 **「임 도」** 라고 못박음. 근거를 자료에 적음
**⑥ 이형철근** — 원문이 범위 「6~7」로 적은 것을 `alt_rate_range` 로 함께 실음(쓰는 값은 7 그대로)

⚠ 기계 이름 뭉개짐·손료표 md 변환 오류는 **코덱스가 md 를 고치는 중**이라 손대지 않음

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QsGw1Dz9HmhuAxGisxmDPF
2026-09-18 01:18:24 +09:00

136 lines
5.1 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_material_pct"]["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