feat(750-1): SK 셈 답 하나에 보기 넷 — 텍스트 수식 글 · 시험 계산 중간 · 일위대가 줄 모달 줄모드
- 새 `M02_Sangeun_Views` — SK 고친 줄(`_Over`) · 같은 입력 · 같은 고름 위에서 `master_text.lines` + `annotate` = `글` · 줄마다 cid · 금액 · 소계 · 계 = SK 줄 · 기준(별도계상 뺌 · 단위 환산 ÷배 · 못 셈 까닭) · `중간` = 시험 계산 중간값 - `calc_doc` — 문서 `줄모드` true = 일위대가 그 줄 셈(`line` · 별도계상 기본) · 몸 `보기` false = 덧칸 안 지음(바탕 원값 셈) - `master_text.lines` · `master_sheet_line.annotate` — `files` 자리에 Master 도 받음(파일 묶음 길 그대로 · M01 `/text` 답 같음) - `lineDoc` — `줄모드: true`(일위대가 줄 모달 89,299.60 = 그 줄 금액) - 시험 `test_717_3` — lineDoc = as_doc 대조에서 `줄모드` 칸 따로 확인(서버 as_doc 은 `line` 인자로 줄 셈 · 문서 칸 없음) - 새 지킴 `test_750_1_sk_views` — 변형 일곱 · 참조 바탕 · 줄 모달 · 보기 false Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
- `환산근거` = 표 기준배 ↔ 결과단위 배(「10㎡당 → 1㎡당 ÷10」) · 재료 품목 단위 ↔ 줄 단위
|
||||
(712-2 `master_unit.note`) · 없으면 「」.
|
||||
줄 차례 맞춤 = `master_text.lines` 와 같은 차례(호표 줄마다 `_shares` 비목 · 뒤 덧줄).
|
||||
`files` 자리 = 파일 묶음 또는 Master(M02 SK 고친 줄 `_Over` · 750-1 · `_spread` 도 그대로 넘김).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -151,7 +152,7 @@ def annotate(files: dict, key: str, given: dict, answer: dict) -> dict:
|
||||
"""`master_text.lines` 답에 줄마다 `KEYS` 덧칸 · 머리 `기준단위` — 못 셈이면 답 그대로."""
|
||||
if not answer.get("ok") or "groups" not in answer:
|
||||
return answer
|
||||
master = mf.Master(files)
|
||||
master = files if hasattr(files, "logic") else mf.Master(files)
|
||||
row = master.logic(key)
|
||||
per = mbs.result_per(row.get("결과단위"))
|
||||
answer["기준단위"] = _per_text(per) or None
|
||||
|
||||
@@ -494,7 +494,7 @@ def lines(files: dict, key: str, given: dict) -> dict:
|
||||
"""로직 한 줄의 읽는 식 — 비목 묶음마다 줄과 소계 · 돈 아닌 로직은 「결과」 묶음 하나.
|
||||
호표 줄 계산이 막히면(재료 단가 없음 따위) `row` 구조만으로 이름 식·조각을 짓고
|
||||
`글`·`금액`은 비움(입력 자체가 없는 경우는 지금처럼 그대로 막힘 — `_env_of` 에서 걸림)."""
|
||||
master = mf.Master(files)
|
||||
master = files if hasattr(files, "logic") else mf.Master(files) # Master 째(750-1)
|
||||
row = master.logic(key)
|
||||
env = _env_of(master, row, given)
|
||||
marks = mc.aliases(row, master)
|
||||
|
||||
@@ -93,6 +93,7 @@ def test_화면_문서_서버_as_doc_꼴():
|
||||
"needsRef": ["needsIds", ref],
|
||||
}
|
||||
)
|
||||
assert got["logic"].pop("줄모드") is True and got["ref"].pop("줄모드") is True # 750-1
|
||||
assert got["logic"] == patch.as_doc({**one, "패치": drop}, whole)
|
||||
assert got["ref"] == patch.as_doc({**ref, "패치": COVER}, whole)
|
||||
assert got["bare"]["고름"] == {} and got["bare"]["덮개"] == {}
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
"""SK 보기 넷 = 셈 답 하나(PLAN 750-1 · 요구 588-1) — 화면 셈 답 `글`(텍스트 수식) ·
|
||||
시험 계산(`줄` · `기준` · `중간`) = SK 줄 · 계 · 변형 일곱(기본 · 줄 빼기 · 더하기 · 덧줄 ·
|
||||
별도계상 · 단위 환산 · 재료 고름) + 참조 바탕 · 일위대가 줄 모달(`줄모드`) = 일위대가 그 줄 셈 ·
|
||||
`보기` false = 덧칸 없음 · M01 엔진 · storage 안 씀."""
|
||||
|
||||
import pytest
|
||||
|
||||
from M01_MasterData import M01_MasterData_Store as m01
|
||||
from M02_MasterTemplete import M02_Labor_Doc as labor
|
||||
from M02_MasterTemplete import M02_Sangeun_Calc as calc
|
||||
from M02_MasterTemplete import M02_Sangeun_Doc as sd
|
||||
from M02_MasterTemplete import M02_Sangeun_Views as views
|
||||
|
||||
FORM = "GC000211" # 6-3-1 합판거푸집 — 재료 일곱 · 소모자재 = 재료비 % 덧줄
|
||||
PLY = "material:합판(내수 12㎜)#0"
|
||||
DOC = {"키": "SK-000002", "이름": "테스트1", "단위": "㎡", "바탕": {"로직": FORM}}
|
||||
ADD = {"종류": "인력", "요소": "LB000002", "이름": "보통인부(더함)", "단위": "인", "수량": 0.05}
|
||||
CASES = {
|
||||
"기본": {},
|
||||
"줄 빼기": {"뺀줄": ["material:각재#0"]},
|
||||
"더하기": {"더한줄": [ADD]},
|
||||
"덧줄": {"덮개": {"pct:소모자재#0": {"qty": 5}}},
|
||||
"별도계상": {"자재표시": {PLY: {"별도계상": "별도계상"}}},
|
||||
"단위 환산": {"단위": "10㎡"},
|
||||
"재료 고름": {"고름": {PLY: "MT000020"}},
|
||||
}
|
||||
|
||||
|
||||
def _whole():
|
||||
return m01.loaded()[1]
|
||||
|
||||
|
||||
def _answer(doc: dict, read=None, line: bool = False) -> dict:
|
||||
"""`calc_doc` 와 같은 길(층 검사만 뺌)."""
|
||||
whole = _whole()
|
||||
clean = sd.clean(doc, None, whole)
|
||||
got = calc.run(clean, whole, None, read or calc.refs.read_ref, detail=True, line=line)
|
||||
return labor._json(views.finish(calc.per_unit(got, clean)))
|
||||
|
||||
|
||||
def _same(a: dict) -> None:
|
||||
text, base = a["글"], a["기준"]
|
||||
assert text["ok"] is True
|
||||
money: dict[str, float] = {}
|
||||
for g in text["groups"]:
|
||||
assert g["소계"] == pytest.approx(base[g["비목"]])
|
||||
for one in g["줄"]:
|
||||
money[one["cid"]] = money.get(one["cid"], 0) + (one["금액"] or 0)
|
||||
assert set(money) == {x["cid"] for x in a["줄"]} # 글 줄 = SK 줄(cid)
|
||||
for x in a["줄"]:
|
||||
assert money[x["cid"]] == pytest.approx(x["금액"] or 0)
|
||||
assert text["계"] == pytest.approx(base["계"])
|
||||
assert sum(x["금액"] or 0 for x in a["줄"]) == pytest.approx(base["계"]) # 시험 계산 표 합
|
||||
assert a["중간"] and all(not isinstance(v, (dict, list)) for v in a["중간"].values())
|
||||
|
||||
|
||||
@pytest.mark.parametrize("name", list(CASES))
|
||||
def test_four_views_one_answer(name):
|
||||
a = _answer({**DOC, **CASES[name]})
|
||||
_same(a)
|
||||
if name == "별도계상":
|
||||
assert all(one.get("cid") != PLY for g in a["글"]["groups"] for one in g["줄"])
|
||||
if name == "단위 환산":
|
||||
assert a["글"]["나눔"] == pytest.approx(0.1)
|
||||
plain = _answer(DOC)
|
||||
assert a["기준"]["계"] == pytest.approx(plain["기준"]["계"] * 10)
|
||||
if name == "재료 고름":
|
||||
assert a["기준"]["재료비"] != pytest.approx(_answer(DOC)["기준"]["재료비"])
|
||||
|
||||
|
||||
def test_ref_base_same():
|
||||
"""참조 바탕(SK 위 SK) — 글도 바탕 SK 고친 줄 위에서."""
|
||||
parent = {**DOC, **CASES["덧줄"], "뺀줄": ["material:각재#0"]}
|
||||
ref = {"층": "personal", "주인": None, "키": "SK-000002"}
|
||||
_same(_answer({**DOC, "키": "SK-000003", "바탕": {"참조": ref}}, read=lambda r: parent))
|
||||
|
||||
|
||||
def test_row_modal_is_hopyo_line():
|
||||
"""일위대가 줄 모달(`줄모드`) = 일위대가 그 줄 셈(별도계상 기본 · 747 한쪽 흠)."""
|
||||
whole = _whole()
|
||||
line = labor._json(labor.drop_apart(labor.run_line(whole, FORM, None), {}))
|
||||
got = _answer({**DOC, "단위": "식", "줄모드": True}, line=True)
|
||||
assert got["기준"]["계"] == pytest.approx(line["기준"]["계"])
|
||||
assert [x["이름"] for x in got["줄"]] == [x["이름"] for x in line["줄"]]
|
||||
_same(got)
|
||||
|
||||
|
||||
def test_no_views_flag():
|
||||
"""`보기` false(바탕 원값 셈) = 금액만 · 덧칸 없음 · 금액 같음."""
|
||||
whole = _whole()
|
||||
clean = sd.clean(DOC, None, whole)
|
||||
got = labor._json(calc.run(clean, whole, None, detail=True, seen=False))
|
||||
assert "글" not in got and "중간" not in got
|
||||
assert got["기준"]["계"] == pytest.approx(_answer(DOC)["기준"]["계"])
|
||||
Reference in New Issue
Block a user