- M01 단가산출 기초 · M02 단가산출 상세 보기 = 수식(줄 쌓기 · 기본) · 단가산출 상세 둘 - 줄 쌓기에 M02 사본 [단가 갱신] · [재생성](미리 셈 → 알림 → 저장 · 고침 있으면 막음) · 판 바뀜(409) 문서 그대로면 새 판으로 다시 저장 옮김 - 옛 수식 문서 화면 걷음(formula_doc_screen · defs · edit · lines · math · math_model · rows · sub · formula_doc.css) · 이미 안 부르던 796-2 수식 나무 화면(LogicLab_Equation · Defs · Var · css · M01_Logic_Equation_Model · sheet_formula_cell · ui_template_equation_defs · edit) 걷음 — 18 파일 4,860 줄 - formula_doc_render = 줄 쌓기가 쓰는 reach 만 · 옵션 가로 CSS 는 line_stack.css 로 - 남김 = 계산기 common_util_formula_doc* · 서버 길 · 옵션 · 사본 표지 · 합계 상자 · KaTeX · 시험 페이지 tools/line-stack-test - 시험: test_796_2 지움(걷은 화면 원본 검사뿐) · 799_1 · 800_2 걷은 화면 줄만 뺌 · 799_2 · 802_4b2 · 804_2 보기 · 화면 파일 대상 바꿈 · test_804_6 새로(걷은 파일 · 부르는 곳 없음 · 첫 탭 · 사본 할일) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
101 lines
3.2 KiB
Python
101 lines
3.2 KiB
Python
"""799-1 단가산출 소계 · 끝수 · 합계 지킴(보이기만 — 금액 셈은 그대로).
|
|
|
|
① 예시 셋 — 굴착기(블록 한 줄) · 거푸집(자원 + 덧줄) · 지게(자원) : 줄 합 + 끝수 = 합계(비목마다).
|
|
② 표본 — 호표 로직 여럿 : 합계 = 엔진 끝수 입힌 비목 합(전후 같음) · 줄 합 + 끝수 = 합계 · 결과 로직은 소계 없음.
|
|
③ 부품 짝 — `ui_template_equation_sum.ts` 가 서버 칸 이름을 그대로 읽음.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import importlib
|
|
from decimal import Decimal as D
|
|
from pathlib import Path
|
|
|
|
from M01_MasterData import M01_MasterData_Store as store
|
|
|
|
mf = importlib.import_module("master_formula")
|
|
mcut = importlib.import_module("master_cut")
|
|
meq = importlib.import_module("master_equation")
|
|
|
|
COSTS = ("노무비", "재료비", "경비", "계")
|
|
|
|
|
|
def _whole():
|
|
return store.loaded()[1]
|
|
|
|
|
|
def _logics() -> list[dict]:
|
|
"""M01 로직 줄 전부(키 순)."""
|
|
w = _whole()
|
|
return [
|
|
r
|
|
for tid, rows in sorted(w.index.items())
|
|
if mf.mk.GROUP_OF.get(tid) == "로직"
|
|
for r in rows.values()
|
|
]
|
|
|
|
|
|
def _export(key: str) -> dict:
|
|
w = _whole()
|
|
return meq.export(w, key, meq.given_of(w, w.logic(key), None))
|
|
|
|
|
|
def _closes(eq: dict) -> None:
|
|
sub = eq["소계"]
|
|
for k in COSTS:
|
|
got = sum((r[k] for r in sub["줄"]), D(0)) + sub["끝수"][k]
|
|
assert got == eq["합계"][k], (eq["열쇠"], k, got, eq["합계"][k])
|
|
|
|
|
|
def test_굴착기_블록_한_줄_끝수():
|
|
eq = _export("GC001148")
|
|
rows = eq["소계"]["줄"]
|
|
assert [r["갈래"] for r in rows] == ["블록"] and rows[0]["이름"] == "굴착기(무한궤도)"
|
|
assert (rows[0]["노무비"], rows[0]["재료비"], rows[0]["경비"]) == (
|
|
D("437.1"),
|
|
D("88.2"),
|
|
D("116.0"),
|
|
)
|
|
assert eq["합계"]["계"] == D("641.0") and eq["소계"]["끝수"]["계"] == D("-0.3")
|
|
_closes(eq)
|
|
|
|
|
|
def test_거푸집_자원_덧줄_지게_자원():
|
|
eq = _export("GC000211")
|
|
assert [r["갈래"] for r in eq["소계"]["줄"]] == ["직접"] # 801-3 직접 줄 한 묶음
|
|
_closes(eq)
|
|
eq = _export("GC001140")
|
|
assert [r["갈래"] for r in eq["소계"]["줄"]] == ["직접"]
|
|
_closes(eq)
|
|
|
|
|
|
def test_표본_합계는_엔진_끝수_그대로():
|
|
w = _whole()
|
|
keys = [x["키"] for x in _logics() if x.get("호표")][::25]
|
|
assert keys, "표본 없음"
|
|
seen = 0
|
|
for key in keys:
|
|
try:
|
|
eq = _export(key)
|
|
except mf.FormulaError:
|
|
continue
|
|
if "소계" not in eq:
|
|
continue
|
|
seen += 1
|
|
_closes(eq)
|
|
raw = mf.run(w, key, meq.given_of(w, w.logic(key), None))
|
|
cut = mcut.engine(w, key, raw)
|
|
assert {k: eq["합계"][k] for k in COSTS} == {k: cut[k] for k in COSTS}, key
|
|
assert seen >= 10
|
|
|
|
|
|
def test_결과_로직은_소계_없음():
|
|
key = next(x["키"] for x in _logics() if "결과" in x)
|
|
assert "소계" not in _export(key)
|
|
|
|
|
|
def test_화면_부품이_서버_칸을_읽음():
|
|
ts = Path("ui_template/ui_template_equation_sum.ts").read_text(encoding="utf-8")
|
|
for name in ("노무비", "재료비", "경비", "끝수", "합계"):
|
|
assert name in ts
|