96 lines
3.9 KiB
Python
96 lines
3.9 KiB
Python
# ruff: noqa: F811 — 임시 층 fixture(world)를 test_m02_labor_ref 에서 받아 씀
|
|
"""796-2d 단가산출 상세 탭 소계 · 합계 = 엔진 합계 — 합밖 · 제외 단계 줄은 보이되 소계에 안 더함.
|
|
|
|
- 서버: 엔진 줄 표지 `합밖`(`master_cut.engine` — `master_formula_sum.skipped` 한 판정) ·
|
|
표지 줄 빼고 더하면 SK 셈 답 `기준` · 표지 없는 견본은 줄 표지 없음(금액 전후 같음)
|
|
- 화면: `boxesOf` 소계가 `out` 줄을 안 더함 · 맨 아래 합계 · 줄 `합밖` → `out` 이음(원문 확인)
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import shutil
|
|
import subprocess
|
|
from decimal import Decimal as D
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from M02_MasterTemplete import M02_MasterTemplete_Store as store
|
|
from M02_MasterTemplete import M02_Sangeun_Imported as imp
|
|
from resources.tester.test_795_1_sk_copy import _calc, _doc, _imported_row
|
|
from resources.tester.test_m02_labor_ref import world # noqa: F401 — 같은 임시 층
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
HO = ROOT / "M01_MasterData" / "M01_MasterData_UI_LogicLab_Ho.ts"
|
|
COSTS = ("노무비", "재료비", "경비")
|
|
|
|
|
|
def _answer(world, name, outside: bool):
|
|
me = world["personal"]
|
|
row = _imported_row()
|
|
if outside:
|
|
row["호표"][1] = {**row["호표"][1], "합밖": True}
|
|
with store.at(me):
|
|
key = imp.create(row, None, name)["이름"]
|
|
return _calc(me, _doc(me, key))
|
|
|
|
|
|
def _sum(lines, skip_out: bool) -> dict:
|
|
return {
|
|
k: sum(
|
|
(
|
|
D(str((x.get("비목") or {}).get(k) or 0))
|
|
for x in lines
|
|
if not (skip_out and x.get("합밖"))
|
|
),
|
|
D(0),
|
|
)
|
|
for k in COSTS
|
|
}
|
|
|
|
|
|
def test_outside_line_tagged_and_sum_equals_engine(world):
|
|
ans = _answer(world, "sub2임시 합밖상세", True)
|
|
out = [x for x in ans["줄"] if x.get("합밖")]
|
|
assert len(out) == 1 and sum(D(str(v or 0)) for v in out[0]["비목"].values()) > 0
|
|
kept = _sum(ans["줄"], True)
|
|
for k in COSTS: # 표지 줄 빼고 더해 1 원 버림 = 엔진 합계
|
|
assert int(kept[k]) == int(D(str(ans["기준"][k]))), k
|
|
assert sum(_sum(ans["줄"], False).values()) > sum(kept.values()) # 옛 소계(전부 더함)는 큼
|
|
|
|
|
|
def test_plain_sample_has_no_tag(world):
|
|
ans = _answer(world, "sub2임시 합밖없음", False)
|
|
assert not any("합밖" in x for x in ans["줄"])
|
|
kept = _sum(ans["줄"], True)
|
|
assert all(int(kept[k]) == int(D(str(ans["기준"][k]))) for k in COSTS)
|
|
|
|
|
|
@pytest.mark.skipif(shutil.which("node") is None, reason="node 가 없음")
|
|
def test_box_subtotal_skips_outside():
|
|
src = HO.read_text(encoding="utf-8")
|
|
pure = src[src.index("/* ── 순수 셈 ── */") : src.index("/* ── 순수 셈 끝 ── */")]
|
|
body = """
|
|
const e = (idx, bundle, amount, out) => ({ idx, bundle, merge: false, amount, out });
|
|
const got = boxesOf([e(0, "인력", 10, false), e(1, "인력", 7, true), e(2, "재료", 5)], ["경비"]);
|
|
console.log(JSON.stringify(got.map((b) => [b.묶음, b.소계, b.줄.length])));
|
|
"""
|
|
run = subprocess.run(
|
|
["node", "--experimental-strip-types", "--no-warnings",
|
|
"--input-type=module-typescript", "-e", pure + body],
|
|
capture_output=True, text=True, encoding="utf-8", timeout=60,
|
|
) # fmt: skip
|
|
assert run.returncode == 0, run.stderr
|
|
assert json.loads(run.stdout) == [["인력", 10, 2], ["재료", 5, 1], ["경비", 0, 0]] # 줄은 보임
|
|
|
|
|
|
def test_screen_wiring():
|
|
src = HO.read_text(encoding="utf-8")
|
|
assert src.count("out: !!line?.합밖,") == 2 # 호표 줄 · 덧줄
|
|
assert "e.group === g && !e.out" in src # 맨 아래 합계
|
|
assert 'createBadge(th("Out")' in src and len(src.splitlines()) <= 700
|
|
assert "합밖?: boolean" in (
|
|
ROOT / "M01_MasterData" / "M01_MasterData_UI_Logic_Api.ts"
|
|
).read_text(encoding="utf-8")
|