"""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