Files
Aislo/M02_MasterTemplete/M02_Labor_Patch.py
T
eomsangdonandClaude Opus 5.5 26b25626bd fix(747-1): M02 단가산출 바탕 재료 = M01 기초 그대로 셈 — 별도계상 빈 칸 = 직접계산
- 까닭: SK 셈이 바탕 로직 재료 줄에 일위대가 기본(별도계상 · 162-1)을 써 drop_apart 가 줄 · 재료비에서 뺌
- M02_Sangeun_Calc.resolve · run 에 line 인자 — SK = 바탕 재료 별도계상 빈 칸을 직접계산으로(고른 「별도계상」 만 밖)
- 일위대가 덮개 줄(Labor_Patch.run · Item_Sangeun._freeze_lines)은 line=True — 일위대가 기본 그대로
- 테스트1(GC000211) 재료비 1,404.81 → 36,525.06 · 계 = M01 124,419.85 · 기존 SK 17 중 GC000211 바탕 3 만 바뀜
- 새 지킴 시험 test_747_1_sk_material

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 21:15:03 +09:00

127 lines
5.6 KiB
Python

"""일위대가 · 사전조합 줄 덮개(PLAN 715-3 · 요구서 내역12 4장 16 · 4-1 확정 5).
줄 칸 `패치` = 단가산출(SK) 문서 꼴 `{덮개, 뺀줄, 더한줄}`(한 벌 · `M02_Sangeun_Doc`) — 그 줄에만 ·
로직 줄(`{로직, 입력값, 고름, 자재표시, 패치}`) · 단가산출 참조 줄(`{참조: SK, 패치}`)만 받음 ·
줄 `고름` · `자재표시`(호표 차례 열쇠)는 바탕 줄 차례 그대로 — 셈 때 cid 로 바꿔 뺀줄 뒤에도 제자리.
더한줄은 인력 · 재료 · 기계 · 로직 · 고정만(참조는 일위대가에 참조 줄로).
셈 = 줄을 이름 없는 SK 문서로(`as_doc`) → `M02_Sangeun_Calc` 한 벌 · 로직 줄 기준 = 결과단위 값(배는
알약 · `settle` 그대로) · 참조 줄 = 1 단위 값. [단가산출로 저장] = `as_doc` + 이름 · 단위 → 층 SK.
"""
from __future__ import annotations
from typing import Any
from M02_MasterTemplete import M02_Sangeun_Doc as sd
FIELD = "패치"
CALC = ("덮개", "뺀줄", "더한줄") # 셈에 드는 칸(`as_doc` · 화면 짝 꼴)
KEEP = (*CALC, "뺀더한줄") # 뺀더한줄 = [되살림] 기억(744-1)
TEMP = "SK-000000" # 이름 없는 줄 단가산출 — 저장 안 함
def _bad(text: str):
from M02_MasterTemplete import M02_MasterTemplete_Store as store
return store.StoreError(400, text)
def clean(one: dict, where: str, whole: Any, row: dict | None, opened: list | None = None) -> dict:
"""줄 칸 `패치` 정리 — 없거나 비면 `{}`(칸 안 둠) · 틀리면 400."""
raw = one.get(FIELD)
if not raw:
return {}
if not isinstance(raw, dict):
raise _bad(f"{where} · 패치는 묶음")
if any("참조" in x for x in raw.get("더한줄") or [] if isinstance(x, dict)):
raise _bad(f"{where} · 줄 더한줄엔 참조 못 넣음 — 일위대가에 참조 줄로")
body = {k: raw.get(k) for k in KEEP}
try:
got = sd.clean(
{"키": TEMP, "이름": "줄", "단위": "식", **body, "열린입력": opened or []}, row, whole
)
except sd.DocError as e:
raise _bad(f"{where} · {e}") from e
out = {k: got[k] for k in KEEP if got.get(k)}
for add in out.get("더한줄") or []: # 처음수량(744-1) = 넣을 때 수량 · 없으면 지금 수량
add.setdefault("처음수량", add["수량"])
return {FIELD: out} if out else {}
def ref_clean(one: dict, ref: dict, where: str) -> dict:
"""단가산출 참조 줄 패치 — 그 SK 의 열린입력이면 품 배율만."""
from M02_MasterTemplete import M02_Labor_Ref as refs
if not one.get(FIELD):
return {}
if refs.kind_of(ref["키"]) != sd.KIND:
raise _bad(f"{where} · 줄 덮개는 로직 줄 · 단가산출 참조 줄만")
from M01_MasterData import M01_MasterData_Store as m01
doc = refs.read_ref(ref) or {}
return clean(one, where, m01.loaded()[1], None, doc.get("열린입력"))
def _keyed(value: Any, ids: list[str]) -> dict:
"""차례 열쇠 → cid 열쇠(바탕 줄 차례)."""
out = {}
for n, v in (value or {}).items() if isinstance(value, dict) else ():
at = int(n) if str(n).isdigit() else -1
if 0 <= at < len(ids):
out[ids[at]] = v
return out
def as_doc(one: dict, whole: Any, name: str = "줄", unit: str = "식") -> dict[str, Any]:
"""일위대가 줄 → SK 문서(바탕 = 그 로직 · 그 SK) — 고름 · 자재표시는 cid 로."""
body = {k: (one.get(FIELD) or {}).get(k) or ([] if k != "덮개" else {}) for k in CALC}
head = {"키": TEMP, "이름": name, "단위": unit, **body}
if "참조" in one:
return {**head, "바탕": {"참조": one["참조"]}}
try:
ids = sd.line_ids(whole.logic(one["로직"]))
except Exception: # noqa: BLE001 — 없는 로직 = 셈이 까닭
ids = []
extra = {"켜쌓기율": one["켜쌓기율"]} if one.get("켜쌓기율") is not None else {}
return {
**head,
**extra,
"바탕": {"로직": one["로직"]},
"입력값": dict(one.get("입력값") or {}),
"고름": _keyed(one.get("고름"), ids),
"자재표시": _keyed(one.get("자재표시"), ids),
}
def run(whole: Any, one: dict, read: Any = None) -> dict[str, Any]:
"""패치 있는 로직 줄 기준(`run_line` 꼴 · 별도계상 뺀 뒤 · 기준 = 결과단위 값)."""
from M02_MasterTemplete import M02_Labor_Ref as refs
from M02_MasterTemplete import M02_Sangeun_Calc as calc
try:
doc = sd.clean(as_doc(one, whole), None, whole)
return calc.run(doc, whole, None, read or refs.read_ref, line=True)
except sd.DocError as e:
return {"기준": None, "까닭": str(e)}
def ref(one: dict, expand: Any) -> dict[str, Any]:
"""참조 줄 펼침 — 패치 있는 SK 참조는 그 줄만 다시 셈(캐시 안 씀) · 그 밖 `expand` 그대로."""
from M02_MasterTemplete import M02_Sangeun_Calc as calc
if not one.get(FIELD):
return expand(one["참조"])
doc = as_doc(one, expand.whole)
base = expand.read(one["참조"]) or {}
doc = {**doc, "이름": base.get("이름") or doc["이름"], "단위": base.get("단위") or doc["단위"]}
return calc.unit(doc, expand.whole, expand, ())
def to_sangeun(one: dict, name: str, unit: str, whole: Any) -> dict[str, Any]:
"""[단가산출로 저장] 문서 — 줄의 바탕 · 입력값 · 고름 · 덮개 → 이름 붙인 SK(키는 서버)."""
if "로직" not in one and "참조" not in one:
raise _bad("로직 줄 · 단가산출 참조 줄만 단가산출로 저장")
doc = as_doc(one, whole, name, unit)
doc.pop("키")
return doc