Files
Aislo/resources/tester/test_157_1_sangeun_steps.py
T
eomsangdonandClaude Opus 5.5 b55a3ee026 feat(b09): 산근 글 = 흐름도 함수 빠짐없이 · 약어 뜻 · 기계 번호 = 이름 규격(157-1 · 157-3)
- 중간 · 결과 · 호표 수량 = 「이름 = 이름식 = 값 넣은 식 = 값」 · 반올림 따위 부르기는 인자째
- 찾기 = 「표 이름(조건 = 값).칸」 · 만약 = 걸린 갈래만 · 돈 하위 로직 = 이름(산근 n호표)
- 돈 아닌 하위 로직(시간당 작업량 따위) = 「└ 」 줄로 입력 · 중간 · 결과 풀이
- 입력 = 「이름 : 설명 = 값 단위」 · 기계 · 직종 원문번호 = 「이름 규격」(M02_Labor_Inputs._labels)
- 함수 줄은 머리에만 — 호표 줄 · 계 · 금액 그대로 · 시험 test_157_1 새로 · 155_5 Q 줄 글 갱신

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QND7Co43B24zK2P937rdxt
2026-10-09 21:23:45 +09:00

122 lines
5.7 KiB
Python

"""157-1 산근 글 = M01 흐름도 함수 상자 빠짐없이 · 157-3 기계 번호 = 「이름 규격」(`Sangeun_Text`).
- 중간 여럿 · 중간이 중간을 부름 = 「이름 = 이름식 = 값 넣은 식 = 값」(GF000064 일수)
- 찾기 = 「이름 = 표 이름(조건 = 값).칸 = 값 단위」 · 돈 아닌 하위 로직 = 이름 + 「└ 」 풀이
- 돈 하위 로직 = 「로직 이름(산근 n호표)」 · 만약 = 걸린 갈래만 · 입력 = 「이름 : 설명 = 값 단위」
- 함수 줄은 머리에만 — 호표 줄 · 계 = 산근 풀이(`Sangeun.Solver`) 줄 글 · 금액 그대로
"""
import copy
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
from B09_Estimation import B09_Estimation_Sangeun as sg # noqa: E402
from B09_Estimation import B09_Estimation_Sangeun_Text as st # noqa: E402
from M02_MasterTemplete import M02_Item_Prices as item_prices # noqa: E402
EQ = {"labor": 55700, "material": 7695, "expense": 13041}
def _whole(codes, edit=None):
files = copy.deepcopy(item_prices.to_json(item_prices.collect(codes)))
if edit:
for data in files.values():
for row in data.get("줄") or []:
if isinstance(row, dict) and row.get("키") == codes[0]:
edit(row)
return item_prices.load_prices(files)
def _price_of(key):
if key.startswith("SG:"):
return {"no": 3, "labor": 1000.0, "material": 0.0, "expense": 0.0, "sum": 1000.0}
return EQ if key.startswith("EQ") else 1000.0
def test_중간이_중간을_부름_값_넣은_식까지():
got = st.render_sangeun_text(_whole(["GF000064"]), "GF000064", {}, _price_of)
assert "일수 = 1 / Q * (1 + 할증 %) = 1 / 11.19 * (1 + 10 %) = 0.0983" in got
assert "할증 = 소형가선 집재 숲가꾸기 주 속 수(구분 = 총 소요인력 할증).적용 = 10" in got
assert "보통인부 수량 = 2 * 일수 = 2 * 0.0983 = 0.1966 인" in got # 호표 수량 함수
def test_돈_아닌_하위_로직_풀이_찾기_결과식():
got = st.render_sangeun_text(_whole(["GF000089"]), "GF000089", {}, _price_of)
at = got.index("작업량 = 토사깍기(기계 · 굴착기 0.7㎥) 시간당 작업량 = 39.293")
assert got[at + 1 : at + 8] == [
"└ E입력 : 0.45",
"└ q = 토사깍기 장비(구분 = 무한궤도 굴착기).적용 = 0.7 ㎥",
"└ K = 토사깍기 기계(구분 = K).적용 = 0.9",
"└ f = 토사깍기 체적환산계수(구분 = f).적용 = 0.77",
"└ E = E입력 = 0.45",
"└ Cm = 토사깍기 기계(구분 = ㎝(sec)).적용 = 20",
"└ 결과 = 반올림(3,600 * q * K * f * E / Cm, 3) = "
"반올림(3,600 * 0.7 * 0.9 * 0.77 * 0.45 / 20, 3) = 39.293",
]
assert "굴착기(무한궤도) 0.7㎥ 노무비 : 55,700 * 1 / 39.293 = 1,417.5" in got
def test_결과_로직_맨_위():
got = st.render_sangeun_text(_whole(["GF000088"]), "GF000088", {}, _price_of)
assert (
"결과 = 반올림(3,600 * q * K * f * E / Cm, 3) = "
"반올림(3,600 * 0.7 * 0.9 * 0.77 * 0.45 / 20, 3) = 39.293"
) in got
def test_돈_하위_로직_산근_호표_번호():
def edit(row):
row["중간"].append(
{"이름": "참고", "식": "로직(GF000123, 지역=지역, 보정작업=보정작업).노무비"}
)
got = st.render_sangeun_text(_whole(["GF000089", "GF000123"], edit), "GF000089", {}, _price_of)
line = next(t for t in got if t.startswith("참고 = "))
assert line.startswith("참고 = 층따기(굴착기 0.7㎥)(산근 3호표).노무비 = ")
def test_만약_걸린_갈래_입력_설명_기계_이름():
got = st.render_sangeun_text(_whole(["GF000297"]), "GF000297", {"흉고직경": 20}, _price_of)
assert "흉고직경 : 가슴높이(1.2m) 지름(표 구간 안 값) = 20 ㎝" in got
assert "굴착기 = 굴착기(무한궤도) 0.6㎥" in got # 157-3 원문번호 '0201-0060' 대신
assert "기계 = 1" in got and not [t for t in got if "0201-" in t]
assert (
"특별인부 수량 = 식재작업 교목식재(흉고직경)(흉고직경(㎝) = 20).특별인부 * (1 - 감 %)"
" = 0.56 * (1 - 0 %) = 0.56 인"
) in got
def _solver(whole, code, given):
sheets = {"labor": [], "machine": [], "compare": []}
asked = []
def price_of(key):
asked.append(key)
return EQ if key.startswith("EQ") else None if key.startswith("SG:") else 1000.0
st.render_sangeun_text(whole, code, given, price_of)
for key in dict.fromkeys(k for k in asked if not k.startswith("SG:")):
if key.startswith("EQ"):
sheets["machine"].append({"key": key, **EQ})
elif key.startswith("LB"):
sheets["labor"].append({"key": key, "price": 1000.0})
else:
sheets["compare"].append({"key": key, "applied": 1000.0})
return sg.Solver(sheets).add(whole, {"code": code, "given": given}, "s1")
def test_호표_줄_계는_산근_풀이와_같음():
"""함수 줄이 늘어도 꼬리(호표 줄 · 계)는 산근 풀이 줄에 그대로 얹힘 — 금액 그대로."""
for code, given in (("GF000089", {}), ("GF000064", {}), ("GF000297", {"흉고직경": 20})):
whole = _whole([code])
block = _solver(whole, code, given)
parts = " + ".join(f"{st.PART_NAME[p]} {block[p]:,.0f}" for p in sg.PARTS)
assert block["foot"] == f"계 : {parts} = {block['sum']:,.0f}", code
assert all(ln.get("text") for ln in block["lines"]), code
assert any(" 수량 = " in t or " = " in t for t in block["head"]), code
assert not [t for ln in block["lines"] for t in ln["text"] if " 수량 = " in t], code