"""728-2 지킴 — SK 단위 환산: 바탕 기준단위 → SK 단위 배 · 화면 줄 · 계 = SK 1 단위 몫 · 계수 없으면 셈 막음 · 「식」 = 옛 셈 · 둘째 기초 수량 처음값 · 돈 아닌 기초 고르기 창에서 뺌 · 고침 꼴 화면배 되돌림.""" from __future__ import annotations import json import subprocess import sys from decimal import Decimal from pathlib import Path import pytest ROOT = Path(__file__).resolve().parents[2] HERE = Path(__file__).resolve().parent sys.path.insert(0, str(ROOT)) sys.path.insert(0, str(ROOT / "resources/master_data/scripts")) import master_unit as mu # noqa: E402 from M01_MasterData import M01_MasterData_Store as m01 # noqa: E402 from M02_MasterTemplete import M02_Sangeun_Calc as sc # noqa: E402 from M02_MasterTemplete import M02_Sangeun_Doc as sd # noqa: E402 @pytest.fixture(scope="module") def whole(): return m01.loaded()[1] def _doc(base, unit, **more): return {"키": "SK-999999", "이름": "sub3임시", "단위": unit, "바탕": {"로직": base}, **more} def _shown(whole, doc): clean = sd.clean(doc, None, whole) return sc.per_unit(sc.run(clean, whole), clean) def test_단목베기_100본_제안_본으로_바꾸면_1본_계(whole): full = _shown(whole, _doc("GF000287", "100본")) assert full["배"] == 1 and round(full["기준"]["계"], 2) == Decimal("153889.40") assert sc.head_of({"단위": "100본"}) == "100본 당" one = _shown(whole, _doc("GF000287", "본")) assert one["배"] == 100 and round(one["기준"]["계"], 2) == Decimal("1538.89") assert sc.head_of({"단위": "본"}) == "1 본 당" pairs = [(x["수량"], y["수량"]) for x, y in zip(full["줄"], one["줄"], strict=True)] assert all(b == a / 100 for a, b in pairs) and one["화면배"] == 100 # 세부 품 ÷100 def test_사석_수상고르기_10제곱미터_에서_1제곱미터(whole): one = _shown(whole, _doc("GC000421", "㎡")) assert round(one["기준"]["계"], 2) == Decimal("44791.32") def test_성격_다르면_계수_칸_없으면_셈_막음(whole): with pytest.raises(sd.DocError, match="환산 계수"): _shown(whole, _doc("GF000099", "m")) base = _shown(whole, _doc("GF000099", "㎥"))["기준"]["계"] two = _shown(whole, _doc("GF000099", "m", 환산={"계수": 2})) assert two["배"] == 2 and two["기준"]["계"] == base / 2 with pytest.raises(sd.DocError, match="단위중량"): _shown(whole, _doc("GF000099", "톤")) rock = _shown( whole, _doc("GF000099", "톤", 환산={"단위중량": {"종별": "암석", "형상": "화강암"}}) ) assert rock["배"] == Decimal("2.7") # 1 ㎥ = 2.7 톤(2,700 ㎏/㎥) with pytest.raises(sd.DocError, match="0 보다"): sd.clean(_doc("GF000099", "m", 환산={"계수": 0}), None, whole) def test_식_빈_단위는_옛_셈(whole): old = _shown(whole, _doc("GF000287", "식")) assert old["배"] == 100 and round(old["1단위"]["계"], 2) == Decimal("1538.89") assert "화면배" not in old and old["기준"]["계"] == Decimal("153889.4") # 화면 = 바탕 몫 그대로 def test_둘째_기초_수량_처음값_배(whole): """바탕 10㎡(GC000421) + 둘째 기초 100㎡(GF000041) — 처음값 0.1 = 바탕 기준단위 몫.""" qty = mu.swap("10㎡", "100㎡")["배"] assert qty == Decimal("0.1") alone = sc.run(sd.clean(_doc("GF000041", "100㎡"), None, whole), whole)["1단위"]["계"] one = {"종류": "로직", "로직": "GF000041", "입력값": {}, "수량": float(qty)} got = sc.run(sd.clean(_doc("GC000421", "㎡", 더한줄=[one]), None, whole), whole) bare = sc.run(sd.clean(_doc("GC000421", "㎡"), None, whole), whole) added = got["1단위"]["계"] - bare["1단위"]["계"] assert abs(added - alone * qty / 10) < Decimal("0.01") # ㎡ 몫 = 100㎡ 값 ÷100 src = (ROOT / "M02_MasterTemplete/M02_MasterTemplete_Sangeun_Detail.ts").read_text( encoding="utf-8" ) assert "swapUnit(" in src and "addBase(" in src and "baseUnitOf(" in src def test_돈_아닌_기초_고르기_창에서_뺌(whole): money = [ r for tid, d in whole.index.items() if tid in ("GC", "GF", "QC", "QF") for r in d.values() if isinstance(r, dict) and "결과단위" in r and not str(r["결과단위"]).strip().startswith("원") ] assert len(money) == 21 src = (ROOT / "M02_MasterTemplete/M02_MasterTemplete_Find_Pick.ts").read_text(encoding="utf-8") assert '!logic.결과단위.trim().startsWith("원")' in src def test_고침_꼴_화면배_되돌림(): proc = subprocess.run( # noqa: S603 — 고정 실행 파일 ["node", str(HERE / "helper_728_2_cover_unit.cjs")], capture_output=True, text=True, encoding="utf-8", timeout=60, ) assert proc.returncode == 0, proc.stderr out = json.loads(proc.stdout) assert out["was"]["qty"] == pytest.approx(0.2) # 바탕 값 = 문서 몫(100본) assert out["cover"]["labor:LB000101#0"]["qty"] == pytest.approx(0.3) assert out["added"] == pytest.approx(60) assert out["shown"]["0"]["qty"] == pytest.approx(0.003) # 다시 그리면 화면 몫 assert out["shown"]["1"]["qty"] == pytest.approx(0.6)