- 까닭: 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>
127 lines
5.6 KiB
Python
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
|