B08_Quantity 86 · B09_Estimation 111 파일을 old_code/ 로 옮김(지우지 않음). 화면은 메뉴·주소·단계 막대만 남은 빈 틀 둘 — main.py 라우터 13 개는 끊음. B07 이 빌려 쓰던 비탈 길이·면적은 필요한 함수만 B07_DesignDetail_Engine_SlopeGeometry 로 옮겨 적음(면적 적분·노면 면적·측점 묶음은 안 옮김) · 시험 하나를 새로 둠. B07 구조물도 조립(Cad_StandardSheet)은 2026-09-13 에 이미 도면 목록에서 빠져 부르는 곳이 없어 old_code 로 같이 보냄 — 구조물 그림은 되살리지 않음. B06 구조물 몫 조회는 빈 값으로 두어 화면이 그대로 서게 함. B08·B09 를 부르던 시험 25 개도 old_code/resources/tester 로 옮김. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PAdA5ThqmtVSsbzjusk1cJ
161 lines
7.3 KiB
Python
161 lines
7.3 KiB
Python
"""건설 표 모양 판정·밑수 읽기 — 2026-09-18 브레인 일감(랩탑 메인).
|
|
|
|
못박는 것
|
|
- ⚠ **산림은 건설 층에 닿지 않음** — 건설 규칙은 산림 잣대가 못 가른 표에서만 돌고, 산림 미판정은 0.
|
|
- 건설 꼴 여섯(기계 손료표 · 율·계수 · 값 없는 설명표 · 건설 직종 · 단위 칸 · 공식 기호)을 가름.
|
|
- **못 가리면 미판정** — 지어내지 않음.
|
|
- 밑수 읽기: 건설 꼴 `(용접개소당)`·`(세면기 개당)`·`(m당 : 관길이기준)`·`(일당)` 를 읽되
|
|
⚠ `(1ha당, 100본당)` 처럼 **둘이면 안 고름** · `공㎥당` 은 `㎥` 로 안 깎임 · 「회」는 밑수가 아님.
|
|
- ⚠ **작업조 표에는 「일」 밑수를 안 붙임**(c3da333e — 붙이면 유로폼 호표가 사라짐).
|
|
금액 불변은 `test_work_item_key_gate.py` 원가계산서 시험(직접공사비 5,983,724)이 잼.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
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_Build_WorkItemMaster_FormsConst import ( # noqa: E402
|
|
judged_const_form,
|
|
)
|
|
from B08_Quantity.B08_Quantity_Build_WorkItemMaster_Table import ( # noqa: E402
|
|
basis_from_source,
|
|
crew_table,
|
|
detect_form,
|
|
new_report,
|
|
table_entry,
|
|
)
|
|
|
|
FOREST = ROOT / "resources/data_cost_input_value/pum_forest_2026.json"
|
|
MASTER = ROOT / "resources/data_work_item_master"
|
|
|
|
|
|
def table(headers: list[str], rows: list[list[str]]) -> dict:
|
|
return {"table_id": "T0001", "section": "시험", "line": 3, "headers": headers, "rows": rows}
|
|
|
|
|
|
# ── 산림을 흔들지 않음 ────────────────────────────────────────────────────
|
|
def test_산림_표는_건설_층에_닿지_않음() -> None:
|
|
"""산림 표는 산림 잣대에서 이미 갈림 — 건설 규칙이 산림 값을 바꿀 수 없음(마스터 산출로 잼)."""
|
|
master = json.loads((MASTER / "work_item_master_2026-01-01.json").read_text(encoding="utf-8"))
|
|
reached = [
|
|
t["pum_table_id"]
|
|
for w in master["work_items"]
|
|
for t in w.get("tables", [])
|
|
if str(t.get("form_basis", "")).startswith("건설 꼴")
|
|
]
|
|
assert reached == [], f"산림 표가 건설 층까지 내려감: {reached[:5]}"
|
|
|
|
|
|
def test_산림_마스터는_형태_미판정이_없음() -> None:
|
|
master = json.loads((MASTER / "work_item_master_2026-01-01.json").read_text(encoding="utf-8"))
|
|
assert master["stats"]["form_undetermined"] == 0
|
|
|
|
|
|
# ── 건설 꼴 가름 ─────────────────────────────────────────────────────────
|
|
def test_기계_손료표는_계수() -> None:
|
|
got = judged_const_form(
|
|
table(
|
|
["분류 번호", "규격 (ton)", "내용 시간", "상각 비율", "시 간 당(10-7)"],
|
|
[["0101-0007", "7", "12,000", "0.9", "1,811"]],
|
|
)
|
|
)
|
|
assert got and got[0] == "coefficient"
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"headers, rows",
|
|
[
|
|
(
|
|
["사용기간별 구 분", "3개월 (%)", "2개년초과 평균손율 (%)"],
|
|
[["철 물", "30", "85"]],
|
|
), # 손율
|
|
(["지형종류", "시가지"], [["계수", "0.58"]]), # 보정계수
|
|
(["설치간격", "0.6m이하"], [["요 율", "17%"]]), # 요율
|
|
],
|
|
)
|
|
def test_율_계수표는_계수(headers: list[str], rows: list[list[str]]) -> None:
|
|
got = judged_const_form(table(headers, rows))
|
|
assert got and got[0] == "coefficient"
|
|
|
|
|
|
def test_값이_없는_설명표는_참조() -> None:
|
|
got = judged_const_form(
|
|
table(["노 임 구 분", "산 정 식"], [["노임합계", "P+PO"], ["기본노임", "P"]])
|
|
)
|
|
assert got == ("reference", "값(숫자) 칸이 없음 — 설명·서식 표")
|
|
|
|
|
|
def test_건설_직종이_있으면_소요량() -> None:
|
|
got = judged_const_form(
|
|
table(["구 분", "특급 기술자", "고급 기술자"], [["작업계획", "0.5", "1.1"]])
|
|
)
|
|
assert got and got[0] == "requirement"
|
|
|
|
|
|
def test_비고의_산출식은_계수로_안_뒤집음() -> None:
|
|
"""인력품 표의 비고에 산출식이 있어도 **품 표**다(9-5-4 수치지도)."""
|
|
got = judged_const_form(
|
|
table(
|
|
["구 분", "고급 기술자", "비 고"],
|
|
[["자동독취", "0.016인", "4매×20분/60분/8시간=0.166일"]],
|
|
)
|
|
)
|
|
assert got and got[0] == "requirement"
|
|
|
|
|
|
def test_단위_칸과_값이_한_줄이면_소요량() -> None:
|
|
got = judged_const_form(table(["구 분", "단 위", "브라켓형"], [["비 계 공", "인", "1.40"]]))
|
|
assert got and got[0] == "requirement"
|
|
|
|
|
|
def test_줄_이름이_공식_기호뿐이면_계수() -> None:
|
|
got = judged_const_form(table(["구 분", "R.C.D", "올케이싱"], [["β", "1.14", "1.08"]]))
|
|
assert got and got[0] == "coefficient"
|
|
|
|
|
|
def test_못_가리면_미판정으로_남김() -> None:
|
|
"""지역·월별 숫자만 있는 표 — 무엇의 값인지 원문으로 못 가름."""
|
|
assert judged_const_form(table(["지역별", "1월", "2월"], [["춘천", "7", "5"]])) is None
|
|
assert detect_form(table(["지역별", "1월"], [["춘천", "7"]]), None)[0] == "undetermined"
|
|
|
|
|
|
# ── 밑수 읽기 ────────────────────────────────────────────────────────────
|
|
@pytest.mark.parametrize(
|
|
"line, want",
|
|
[
|
|
("1-2-1 용접접합('93년 보완)(용접개소당)", (1.0, "개소")),
|
|
("7-1-5 카운터형 세면기 설치(분리형)('26년 보완)(세면기 개당)", (1.0, "개")),
|
|
("- 1. 이중보온관 부설(m당 : 관길이기준)", (1.0, "m")),
|
|
("1-3-10 플륨관 해체('22년 보완)(일당)", (1.0, "일")),
|
|
("6-8-1 주철제 게이트 제수밸브 부설 및 접합('23년 보완)(기당)", (1.0, "기")),
|
|
("1-3-1 데크플레이트 가스절단('18년 보완)(절단길이 10m당)", (10.0, "m")),
|
|
("### 12-19. 강관비계 (단위: 공㎥당)", (1.0, "공㎥")),
|
|
("### 6-2-1. 둘레베기 (1ha당, 100본당)", (None, None)), # 밑수가 둘 — 안 고름
|
|
("### 10-4. 중기운반 (단위: 회당)", (None, None)), # 「회」는 밑수 단위가 아님
|
|
],
|
|
)
|
|
def test_건설_꼴_밑수_읽기(line: str, want: tuple) -> None:
|
|
assert basis_from_source([line, "", "| 머리 |"], 3) == want
|
|
|
|
|
|
def test_작업조_표에는_일_밑수를_안_붙임() -> None:
|
|
"""원문이 `(일당)` 이라도 작업조 표면 밑수를 비움 — 밑수는 시공량 열."""
|
|
crew = table(
|
|
["구 분", "단 위", "수 량", "시 공 량 (㎡)"],
|
|
[["형틀목공 보통인부", "인 인", "4 1", "25"]],
|
|
)
|
|
assert crew_table(crew)
|
|
lines = ["### 12-38-3 설치 및 해체 (일당)", "", "| 머리 |"]
|
|
entry = table_entry(crew, "12-38-3", "12-38-3", "12", lines, None, new_report())
|
|
assert (entry["basis_quantity"], entry["basis_unit"]) == (None, None)
|
|
plain = table(["구 분", "단 위", "수 량"], [["보통인부", "인", "1.4"]])
|
|
entry = table_entry(plain, "2-1", "2-1", "2", lines, None, new_report())
|
|
assert (entry["basis_quantity"], entry["basis_unit"]) == (1.0, "일")
|