- 계수_건설품셈_01장_적용기준.json 덧(CC000495~527): 규칙 · 계수만 절(1-2-2 · 1-2-3 · 1-2-4 · 1-2-5 · 1-2-6 · 1-2-8 · 1-3-2 · 1-4-1 · 1-4-2 · 1-5-1~10)마다 「규칙 글」 표(원문 글 그대로) + 수 표(단위 · 소수 표준 · 금액 단위 · 체적 변화율 L · C · 체적환산계수 f · 파쇄된 돌 10∼40% · 잡재료 2∼5% · 작업반장 · 공구손료 3% · 시공단위 품 소수자리 · 품 산정 식 · 예시 · 건설폐기물 발생량 · 공사용수) · 1-2-9 소규모 적용시공량 · 다수 규격 예시 = 계수로만 - 표 칸 「성격」 — 기존 1-3 · 1-4 표 33 + 1-2-9 둘(같은 성격 묶음 · 1-2-9 ↔ 1-4-6 작업시간 제한 한 성격) · 기존 표의 다른 글자 그대로 - 로직_건설품셈_01장_적용기준.json 덧: GC001192 건설폐기물 발생량(1-5-4 · 면적 × TON/㎡ × 폐콘크리트 증가율) · GC001193 공사용수(1-5-6 · 작업량 × 단위용수 × 잡용수율) · 원문 「-」 칸 = 줄 없음(멈춤) - 1-2-9 소규모 · 1-4 품의 할증 로직 = 만들지 않음(PLAN 783-1) - 빌더 덧 build_로직_건설품셈_01장_적용기준.py 나머지(+ _적용기준_나머지_표 · _적용기준_나머지_로직) · 키 = master_keys.issue(adopt 는 로직을 받지 않음) - check_master 「목차」(check_master_toc.py) — 공통 1장 원문 절 목록 ↔ 마스터 전수 · 통째 빠진 절 · 로직 없는 품·표·식 절 · 1-2-9 · 1-4-2 = 783-1 로 미룸 표지 - 지킴 시험 test_782_2_common_ch1.py · test_782_1_carry_127.py 로직 줄 목록 = 앞 셋만 봄(같은 파일에 1-5 로직이 붙어 낡음) - check_master 전후 같음(+ 목차 0) · 기존 로직 1513 셈 값 전후 같음 · 계산전부 1515 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
144 lines
4.9 KiB
Python
144 lines
4.9 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""782-2 건설 공통 1장 나머지 — 규칙 · 계수만 절 계수 표 · 1-5-4 · 1-5-6 로직 · 성격 칸 · 절 목록 대조(check_master 목차)."""
|
||
|
||
import copy
|
||
import sys
|
||
from decimal import Decimal
|
||
from pathlib import Path
|
||
|
||
import pytest
|
||
|
||
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "master_data/scripts"))
|
||
|
||
import check_master as cm # noqa: E402
|
||
import check_master_toc as toc # noqa: E402
|
||
import master_formula as mf # noqa: E402
|
||
|
||
COEF = "계수_건설품셈_01장_적용기준.json"
|
||
LOGIC = "로직_건설품셈_01장_적용기준.json"
|
||
WASTE, WATER = "GC001192", "GC001193"
|
||
|
||
|
||
@pytest.fixture(scope="module")
|
||
def whole():
|
||
return cm.master()
|
||
|
||
|
||
@pytest.fixture(scope="module")
|
||
def files():
|
||
return cm.load([COEF, LOGIC])
|
||
|
||
|
||
def result(whole, key, **given) -> Decimal:
|
||
return mf.run(whole, key, given)["결과"]
|
||
|
||
|
||
@pytest.mark.parametrize(
|
||
"given, want",
|
||
[
|
||
# 신축 철근콘크리트조 폐콘크리트류 0.04888 TON/㎡ × 1,000㎡
|
||
(
|
||
{
|
||
"공사": "신축",
|
||
"구조": "철근콘크리트조",
|
||
"폐기물": "폐콘크리트류",
|
||
"면적": 1000,
|
||
"증가율": 0,
|
||
},
|
||
"48.88",
|
||
),
|
||
# 주③ 파일 시공 15% 증가
|
||
(
|
||
{
|
||
"공사": "신축",
|
||
"구조": "철근콘크리트조",
|
||
"폐기물": "폐콘크리트류",
|
||
"면적": 1000,
|
||
"증가율": 15,
|
||
},
|
||
"56.212",
|
||
),
|
||
# 해체 아파트 혼합폐기물 0.1637 — 증가율은 폐콘크리트류만
|
||
(
|
||
{"공사": "해체", "구조": "아파트", "폐기물": "혼합폐기물", "면적": 1000, "증가율": 15},
|
||
"163.7",
|
||
),
|
||
],
|
||
)
|
||
def test_환경관리비(whole, given, want):
|
||
assert result(whole, WASTE, **given) == Decimal(want)
|
||
|
||
|
||
def test_환경관리비_빈칸(whole):
|
||
# 원문 「-」(신축 폐금속류) = 줄 없음 — 짐작 값 없이 멈춤
|
||
with pytest.raises(mf.FormulaError):
|
||
result(whole, WASTE, 공사="신축", 구조="아파트", 폐기물="폐금속류", 면적=1, 증가율=0)
|
||
|
||
|
||
@pytest.mark.parametrize(
|
||
"given, want",
|
||
[
|
||
({"구분": "콘크리트혼합 및 양생", "작업량": 100, "잡용수율": 0}, "27"),
|
||
({"구분": "콘크리트혼합 및 양생", "작업량": 100, "잡용수율": 45}, "39.15"),
|
||
({"구분": "보통벽돌쌓기", "작업량": 2, "잡용수율": 0}, "0.36"),
|
||
],
|
||
)
|
||
def test_공사용수(whole, given, want):
|
||
assert result(whole, WATER, **given) == Decimal(want)
|
||
|
||
|
||
def test_표_목록(files):
|
||
tables = files[COEF]["표"]
|
||
new = [t for t in tables if "CC000495" <= t["키"] <= "CC000527"]
|
||
assert len(new) == 33 and len(tables) == 45 + 33
|
||
by_no = {}
|
||
for t in new:
|
||
by_no.setdefault(t["원문번호"], []).append(t["키"])
|
||
assert set(by_no) == {
|
||
*("1-2-2", "1-2-3", "1-2-4", "1-2-5", "1-2-6", "1-2-8", "1-2-9", "1-3-2", "1-4-1", "1-4-2"),
|
||
*(f"1-5-{n}" for n in range(1, 11)),
|
||
}
|
||
uses = {t["키"]: t["용도"]["로직키"] for t in new if t["용도"]["로직키"]}
|
||
assert uses == {"CC000519": [WASTE], "CC000522": [WATER]}
|
||
assert [r["키"] for r in files[LOGIC]["줄"]] == [
|
||
"GC001140",
|
||
"GC001141",
|
||
"GC001142",
|
||
WASTE,
|
||
WATER,
|
||
]
|
||
|
||
|
||
def test_성격(files):
|
||
nature = {t["키"]: t.get("성격") for t in files[COEF]["표"]}
|
||
old = [f"CC{n:06d}" for n in range(1, 34)]
|
||
assert all(nature[k] for k in old) # 1-3 · 1-4 표 모두
|
||
small = {k for k, v in nature.items() if v == "작업시간 제한 · 소규모"}
|
||
assert small == {"CC000028", "CC000511", "CC000512"} # 1-4-6 작업시간 제한 ↔ 1-2-9 같은 성격
|
||
assert nature["CC000032"] == nature["CC000033"] # 1-4-7 기타 묶음
|
||
|
||
|
||
def test_check_master(files, whole):
|
||
found = [x for name, data in files.items() for x in cm.check_form(name, data)]
|
||
found += cm.check_body(files) + cm.check_logics(files, whole) + toc.check_toc(files)
|
||
assert found == []
|
||
|
||
|
||
def test_목차_대조(files):
|
||
rows = {r["절"]: r for r in toc.table(files)}
|
||
calc = [r for r in rows.values() if r["쓰임"] == "계산 대상"]
|
||
assert len(rows) == 31 and len(calc) == 27
|
||
assert all(r["계수"] or r["로직"] for r in calc)
|
||
assert {k: r["표지"] for k, r in rows.items() if r["표지"]} == {
|
||
"1-2-9": "783-1 로 미룸",
|
||
"1-4-2": "783-1 로 미룸",
|
||
}
|
||
# 통째 빠진 절 · 로직 없는 품·표·식 절을 잡음
|
||
cut = copy.deepcopy(files)
|
||
cut[COEF]["표"] = [t for t in cut[COEF]["표"] if t["원문번호"] != "1-5-8"]
|
||
cut[LOGIC]["줄"] = [r for r in cut[LOGIC]["줄"] if r["키"] != WATER]
|
||
found = toc.check_toc(cut)
|
||
assert any("1-5-8" in x and "통째 빠짐" in x for x in found)
|
||
assert any("1-5-6" in x and "로직 없음" in x for x in found)
|
||
assert len(found) == 2
|