- 로직 자재 별도계상(빈 칸 = 기본) = 기준에서 빼고 일위대가 상세 줄에서 지움 · 자재목록엔 남김 - 사용자 자재 별도계상 = 합에서 뺌(파이썬 · TS settle 짝 · 거울 시험) - 사전조합 안 줄 · 프로젝트 사본 셈도 같은 길 - 별도계상 바꾸면 다시 셈(로직 자재 = 서버 · 사용자 자재 = 짝 셈) - 원문 출처 = 로직 출처 + 호표 · 입력 출처 같은 책 절(산림품셈 12-1-2 · 12-1-3) - 기존 시험 셋 = 직접계산 표시 · 대조용 apart 끔 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F3mdb91125mPoC6tpsQx4P
149 lines
7.9 KiB
Python
149 lines
7.9 KiB
Python
"""M02 구조물조합 일위대가 기계비빔타설(PLAN 222-1) — 단위 까닭 · 별도계상 빼기 · 원문 여럿.
|
|
|
|
① 단위 — GF000156 모래 · 자갈 = 원문 kg(QF000353) ÷ 단위중량(㎏/㎥) · 칸에 t/㎥ 값(2 · 2.1)을 넣으면
|
|
838 ÷ 2 = 419 ㎥ 처럼 1000 배 · 0 = 표 위끝(1,700 · 1,800 ㎏/㎥) → 0.49 · 0.57 ㎥ · 칸을 비우면
|
|
자동값(master_auto 「나누는 자리 = 1」)이 1 이라 838 ㎥(자료 · 기본값 몫 — 223 보고).
|
|
② 별도계상 — 로직 자재(`자재표시` · 빈 칸 = 기본 별도계상) = 기준에서 빠지고 `줄` 에서 지움 · `재료` 는
|
|
남음 · 사용자 자재 = 합에서 뺌(짝 TS `settle`) · 사전조합 안 줄 · 사본 셈 같은 길.
|
|
③ 원문 — 로직 출처 + 호표 · 입력 출처 가운데 같은 책 절 번호(「산림품셈 12-1-2 · 12-1-3」).
|
|
"""
|
|
|
|
import os
|
|
from decimal import Decimal
|
|
|
|
import pytest
|
|
|
|
from M01_MasterData import M01_MasterData_Store as m01
|
|
from M01_MasterData import M01_MasterData_Store_Make as make
|
|
from M02_MasterTemplete import M02_Labor_Doc as labor
|
|
from M02_MasterTemplete import M02_Labor_Inputs as inputs
|
|
from M02_MasterTemplete import M02_Labor_Ref as refs
|
|
from resources.tester.test_m02_labor_calc_mirror import _same, _ts
|
|
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
SRC = os.path.join(HERE, "..", "..", "M02_MasterTemplete")
|
|
MIX = "GF000156" # 기계비빔타설 — 호표 3 시멘트 · 4 모래 · 5 자갈
|
|
GIVEN = {"재료배합": "(A)", "골재최대치수": 40}
|
|
MAT = "MT000008"
|
|
DIRECT = {"별도계상": "직접계산"}
|
|
|
|
|
|
def _whole():
|
|
return m01.loaded()[1]
|
|
|
|
|
|
def _rows(got):
|
|
return {x["이름"]: {**x, "수량": float(x["수량"])} for x in got["줄"]}
|
|
|
|
|
|
# ── ① 단위 ──────────────────────────────────────────────────────────
|
|
def test_단위중량_칸에_t_값이면_1000배_0이면_표_위끝():
|
|
wrong = labor.run_line(_whole(), MIX, {**GIVEN, "모래단위중량": 2, "자갈단위중량": 2.1})
|
|
rows = _rows(wrong)
|
|
assert rows["시멘트"]["단위"] == "kg" and rows["시멘트"]["수량"] == pytest.approx(335)
|
|
assert rows["모래(건조상태)"]["수량"] == pytest.approx(838 / 2) # 419 ㎥
|
|
assert rows["자갈 또는 부순돌"]["수량"] == pytest.approx(1032 / 2.1) # 491.4 ㎥
|
|
zero = {**GIVEN, "모래단위중량": 0, "자갈단위중량": 0}
|
|
right = _rows(labor.run_line(_whole(), MIX, zero))
|
|
assert right["모래(건조상태)"]["수량"] == pytest.approx(838 / 1700)
|
|
assert right["자갈 또는 부순돌"]["수량"] == pytest.approx(1032 / 1800)
|
|
|
|
|
|
# ── ② 별도계상 ───────────────────────────────────────────────────────
|
|
def _calc(shown=None, mats=()):
|
|
line = {"로직": MIX, "입력값": GIVEN, "수량": {"손": 1}}
|
|
if shown:
|
|
line["자재표시"] = shown
|
|
doc = labor.clean({"열": "rv", "담은로직": [line], "자재": list(mats)})
|
|
return labor.calc(doc, {})
|
|
|
|
|
|
def test_로직_자재_기본_별도계상은_기준_줄에서_빠지고_재료엔_남음():
|
|
raw = labor.run_line(_whole(), MIX, GIVEN)
|
|
cut = sum(Decimal(str(m["금액"])) for m in raw["재료"])
|
|
one = _calc()["줄"][0]
|
|
names = {x["이름"] for x in one["줄"]}
|
|
assert not names & {"시멘트", "모래(건조상태)", "자갈 또는 부순돌"}
|
|
assert {"콘크리트공", "보통인부"} <= names
|
|
assert len(one["재료"]) == 3 # 자재목록(세 칸 고침)엔 남음
|
|
want = Decimal(str(raw["기준"]["재료비"])) - cut
|
|
assert one["기준"]["재료비"] == pytest.approx(float(want))
|
|
assert one["기준"]["계"] == pytest.approx(float(Decimal(str(raw["기준"]["계"])) - cut))
|
|
assert one["기준"]["노무비"] == pytest.approx(float(raw["기준"]["노무비"]))
|
|
|
|
|
|
def test_직접계산은_그대로_섞이면_그_자재만_빠짐():
|
|
raw = labor.run_line(_whole(), MIX, GIVEN)
|
|
full = _calc({str(n): DIRECT for n in (3, 4, 5)})["줄"][0]
|
|
assert full["기준"]["계"] == pytest.approx(float(raw["기준"]["계"]))
|
|
assert len(full["줄"]) == len(raw["줄"])
|
|
part = _calc({"3": DIRECT})["줄"][0] # 시멘트만 셈
|
|
names = {x["이름"] for x in part["줄"]}
|
|
assert "시멘트" in names and "모래(건조상태)" not in names
|
|
cement = next(m for m in raw["재료"] if m["이름"] == "시멘트")
|
|
others = sum(Decimal(str(m["금액"])) for m in raw["재료"]) - Decimal(str(cement["금액"]))
|
|
assert part["기준"]["계"] == pytest.approx(float(Decimal(str(raw["기준"]["계"])) - others))
|
|
|
|
|
|
def test_사용자_자재_별도계상은_합에서_빠지고_반영은_보임():
|
|
aside = _calc(None, [{"코드": MAT, "수량": {"손": 2}}])
|
|
direct = _calc(None, [{"코드": MAT, "수량": {"손": 2}, **DIRECT}])
|
|
price = direct["자재"][0]["기준단가"]
|
|
assert aside["자재"][0]["반영"] == pytest.approx(price * 2) # 목록엔 금액 보임
|
|
assert direct["반영합"]["계"] - aside["반영합"]["계"] == pytest.approx(price * 2)
|
|
assert direct["기준합"]["재료비"] - aside["기준합"]["재료비"] == pytest.approx(price)
|
|
|
|
|
|
@pytest.mark.parametrize("mark", [None, "직접계산", "별도계상", "옛값"])
|
|
def test_사용자_자재_별도계상_파이썬과_TS_같은_답(mark):
|
|
one = {"코드": MAT, "수량": {"손": 3}, **({"별도계상": mark} if mark else {})}
|
|
doc = labor.clean({"열": "rv", "담은로직": [{"로직": MIX, "입력값": GIVEN}], "자재": [one]})
|
|
doc["자재"][0].update({"별도계상": mark} if mark else {}) # 옛 값도 그대로 넘겨 봄
|
|
answer = labor.calc(doc, {})
|
|
values = {"기계비빔타설|㎥": 2}
|
|
_same(labor.settle(answer, doc, values), _ts(answer, doc, values))
|
|
|
|
|
|
def test_사전조합_안_줄도_별도계상_뺌():
|
|
raw = labor.run_line(_whole(), MIX, GIVEN)
|
|
cut = sum(Decimal(str(m["금액"])) for m in raw["재료"])
|
|
doc = {
|
|
"이름": "비빔 조합",
|
|
"단위": "㎥",
|
|
"담은로직": [{"로직": MIX, "입력값": GIVEN, "수량": {"손": 1}}],
|
|
"자재": [
|
|
{"코드": MAT, "수량": {"손": 2}}, # 기본 별도계상 = 안 셈 · 안 줄에도 없음
|
|
],
|
|
}
|
|
ref = {"층": "system", "주인": None, "키": "SC999999"}
|
|
got = refs.Expand(_whole(), lambda r: doc)(ref)
|
|
assert [x.get("자재") for x in got["안"]] == [None]
|
|
pill = got["안"][0]
|
|
times = Decimal(1) # 기계비빔타설 알약 배 1
|
|
assert pill["기준"]["계"] * times == pytest.approx(Decimal(str(raw["기준"]["계"])) - cut)
|
|
assert got["기준"]["계"] == pytest.approx(Decimal(str(raw["기준"]["계"])) - cut)
|
|
|
|
|
|
def test_화면_별도계상_바꾸면_다시_셈():
|
|
detail = open(os.path.join(SRC, "M02_MasterTemplete_Labor_Detail.ts"), encoding="utf-8").read()
|
|
assert 'if (key === "별도계상") changed(true);' in detail # 사용자 자재 = 짝 셈
|
|
assert 'if (key === "별도계상") changed();' in detail # 로직 자재 = 서버 기준
|
|
|
|
|
|
# ── ③ 원문 여럿 ──────────────────────────────────────────────────────
|
|
def test_원문_출처는_같은_책_절_모두():
|
|
src = inputs.sources(_whole().logic(MIX))
|
|
assert src == "산림품셈 12-1-2 · 12-1-3"
|
|
assert inputs.logic_inputs([MIX])["로직"][0]["출처"] == src
|
|
assert [f["number"] for f in make.source(src)["found"]] == ["12-1-2", "12-1-3"]
|
|
|
|
|
|
def test_원문_출처_번호_없거나_더할_것_없으면_그대로():
|
|
assert inputs.sources({"출처": "자체"}) == "자체"
|
|
assert inputs.sources({"출처": None}) is None
|
|
one = {
|
|
"출처": "산림품셈 3-1",
|
|
"호표": [{"출처": "건설품셈 공통 1-2-4 3"}, {"출처": "산림품셈 3-1"}],
|
|
}
|
|
assert inputs.sources(one) == "산림품셈 3-1" # 다른 책 · 같은 절은 안 붙임
|