Merge remote-tracking branch 'origin/sub_laptop_7' into main_laptop_1

This commit is contained in:
2026-11-02 21:18:53 +09:00
4 changed files with 73 additions and 5 deletions
+2 -1
View File
@@ -114,7 +114,8 @@ def _freeze_lines(rid: str, doc: dict, whole: Any, read: Any, taken: set[str]) -
for n in _patched(doc):
one = lines[n]
try:
got = calc.resolve(sd.clean(patch.as_doc(one, whole), None, whole), whole, read, (rid,))
doc_ = sd.clean(patch.as_doc(one, whole), None, whole)
got = calc.resolve(doc_, whole, read, (rid,), line=True) # 일위대가 기본 별도계상
row = {**got["줄"], "호표": [dict(x) for x in got["줄"]["호표"]]}
calc._bundles(row, whole, Expand(whole, read), (rid,)) # 고정 더한줄 = 값묶음
except sd.DocError:
+1 -1
View File
@@ -100,7 +100,7 @@ def run(whole: Any, one: dict, read: Any = None) -> dict[str, Any]:
try:
doc = sd.clean(as_doc(one, whole), None, whole)
return calc.run(doc, whole, None, read or refs.read_ref)
return calc.run(doc, whole, None, read or refs.read_ref, line=True)
except sd.DocError as e:
return {"기준": None, "까닭": str(e)}
+20 -3
View File
@@ -15,6 +15,8 @@ SK 단위 환산(728-2) = 배 = 바탕 기준단위(「100본」) → SK 단위(
「식」 · 빈 단위 = 앞 수 뗀 바탕 단위 = 옛 셈) ·
다른 성격 = 문서 `환산` {계수 | 단위중량 {종별, 형상}} · 없으면 셈 막음(까닭) ·
화면 셈 길 줄 · 계 = SK 1 단위 몫(`per_unit`).
바탕 재료(747-1) = 별도계상 빈 칸 = 직접계산(M01 기초처럼 재료비에 듦 · 「별도계상」 고른 줄만 밖) ·
일위대가 덮개 줄(`line` · `M02_Labor_Patch.run`)은 일위대가 기본(222-1 · 162-1) 그대로.
"""
from __future__ import annotations
@@ -126,7 +128,12 @@ def _base_of(doc: dict, whole: Any, read: Any, trail: tuple[str, ...]) -> dict[s
def resolve(
doc: dict, whole: Any, read: Any = refs.read_ref, trail: tuple = (), given: dict | None = None
doc: dict,
whole: Any,
read: Any = refs.read_ref,
trail: tuple = (),
given: dict | None = None,
line: bool = False,
) -> dict[str, Any]:
"""SK 문서 → 고친 줄 `{줄, 고름, 자재표시, 정체, 짝잃음, 입력값, 켜쌓기율, 배, 바탕판}` ·
`trail` = 지나온 참조 이름표(순환 · 깊이 422) · `given` = 공통 옵션(더한줄 로직 입력)."""
@@ -135,6 +142,8 @@ def resolve(
doc, lack = _fill(doc, whole, common)
got = sd.patched(base["줄"], doc, base["고름"], base["자재표시"])
items = got["줄"]["호표"]
if not line:
_direct(got["자재표시"], items)
for at, cid in enumerate(got["정체"][: len(items)]):
hit = re.match(r"^add:#(\d+)$", cid)
if hit and int(hit[1]) in lack:
@@ -155,6 +164,13 @@ def resolve(
}
def _direct(marks: dict, items: list) -> None:
"""SK 재료 줄 별도계상 빈 칸 = 직접계산(747-1 · 제자리) — 다른 두 칸은 그대로."""
for n, item in enumerate(items):
if item.get("종류") == "재료":
marks[str(n)] = {"별도계상": "직접계산", **labor.marks(marks.get(str(n)))}
# ── 못 셈 줄 = 그 줄만 빠짐(725-1 · 725-2) ─────────────────────────────────
NO_QTY = "수량 없음" # `M02_Labor_Expand.NO_QTY` 와 같은 글(가져오기 둘레 피함)
NO_QTY_WHY = "수량 없음 — 쓰는 자리에서 연결"
@@ -311,13 +327,14 @@ def run(
expand: Any = None,
trail: tuple = (),
detail: bool = False,
line: bool = False,
) -> dict[str, Any]:
"""SK 셈(저장 안 함) — `run_line` 답 + `{1단위, 배, 정체, 짝잃음, 바탕판}` · 줄마다 `cid` ·
고친 칸 `덮개`(칸 이름) · `원값`. 틀린 문서 · 순환 = `sd.DocError` ·
`detail` = 둘째 기초 세부 펼침(`_detail` · 화면 셈 길만)."""
`detail` = 둘째 기초 세부 펼침(`_detail` · 화면 셈 길만) · `line` = 일위대가 덮개 줄."""
from M02_MasterTemplete.M02_Labor_Expand import Expand
got = resolve(doc, whole, read, trail, given)
got = resolve(doc, whole, read, trail, given, line)
row = {**got["줄"], "호표": [dict(x) for x in got["줄"]["호표"]]}
_bundles(row, whole, expand or Expand(whole, read), trail)
head = {k: got[k] for k in ("정체", "짝잃음", "바탕판")} | {"배": got["배"]}
@@ -0,0 +1,50 @@
"""SK 바탕 재료 = M01 기초 그대로 셈(PLAN 747-1) — 별도계상 빈 칸 = 직접계산 · 고른 줄만 밖 ·
일위대가 덮개 줄(`M02_Labor_Patch.run`)은 일위대가 기본(별도계상) 그대로."""
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_Labor_Patch as patch
from M02_MasterTemplete import M02_Sangeun_Calc as calc
from M02_MasterTemplete import M02_Sangeun_Doc as sd
FORM = "GC000211" # 6-3-1 합판거푸집 — 합판 1.03 · 각재 0.038 · 폼타이 0 · 소모자재 = 재료비 %
PLY = "material:합판(내수 12㎜)#0"
def _whole():
return m01.loaded()[1]
def _run(**doc):
whole = _whole()
clean = sd.clean({"키": "SK-000001", "이름": "시험", "단위": "㎡", **doc}, None, whole)
return labor._json(calc.run(clean, whole))
def test_base_materials_count_like_m01():
m01_ = labor._json(labor.run_line(_whole(), FORM, None))
got = _run(바탕={"로직": FORM})
assert got["기준"]["재료비"] == pytest.approx(m01_["기준"]["재료비"])
assert got["기준"]["계"] == pytest.approx(m01_["기준"]["계"])
qty = {x["cid"]: x["수량"] for x in got["줄"]}
assert qty[PLY] == pytest.approx(1.03)
assert qty["material:폼타이 12.7㎜#0"] == 0 # M01 수량 0 = 0 그대로
def test_cover_and_explicit_apart():
base = _run(바탕={"로직": FORM})
more = _run(바탕={"로직": FORM}, 덮개={PLY: {"qty": 2}})
ply = next(x for x in base["줄"] if x["cid"] == PLY)
assert more["기준"]["재료비"] > base["기준"]["재료비"] + ply["단가"] * 0.9
out = _run(바탕={"로직": FORM}, 자재표시={PLY: {"별도계상": "별도계상"}})
assert all(x["cid"] != PLY for x in out["줄"])
assert out["기준"]["재료비"] < base["기준"]["재료비"] - ply["금액"] + 1
def test_hopyo_line_keeps_line_default():
whole = _whole()
line = {"로직": FORM, "입력값": {}, "패치": {"덮개": {PLY: {"qty": 2}}}}
got = labor._json(patch.run(whole, line))
assert all(x["cid"] != PLY for x in got["줄"]) # 일위대가 기본 = 별도계상(222-1)