Files
Aislo/M02_MasterTemplete/M02_Labor_Patch.py
T
eomsangdonandClaude Opus 5.5 b62a1d9356 feat(715-3): 일위대가 줄 덮개(패치) · SK 참조 줄 · [단가산출로 저장] 길 · 일위대가 단위 빈칸 막기 · 「1 단위 당」 머리
- 새 M02_Labor_Patch.py — 줄 칸 패치 = SK 꼴 {덮개, 뺀줄, 더한줄}(한 벌) · 로직 줄 · SK 참조 줄만 · 줄 고름 · 자재표시(차례)를 cid 로 바꿔 뺀줄 뒤 제자리 · 셈 = 이름 없는 SK 로 M02_Sangeun_Calc
- M02_Labor_Doc — clean 이 패치 정리 · calc 로직 줄 · 참조 줄 패치 갈래(몇 줄 · 690 줄)
- M02_Labor_Expand — 사전조합 안 줄 패치 갈래 · 머리 「1 ㎡ 당」
- M02_Labor_Ref — 사전조합 줄에 패치 남김 · 줄 있는 일위대가 단위 빈칸 400(빈 새 문서는 받음 — 화면 새로 단추가 단위 null) · 409 글 종류 이름 사전조합 → 일위대가 · labor → 구조물 조합
- POST /api/m02/layers/{층}/sangeun/from-line(층 쓰기 권한) — 새 SK + 바꿀 참조 줄 · 셈 답에 머리
- Labor_Calc.ts 짝은 그대로(settle 은 서버 기준을 받음 · 거울 시험 통과)
- 낡은 시험 고침: test_m02_labor_ref · test_175_precombo_mats · test_204_2_b09_bill_library 의 줄 있는 사전조합에 단위(빈칸 막기) · 참조 줄 분모 = 그 사전조합 단위
- 새 시험 test_715_3_labor_patch.py(임시 storage)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 16:04:31 +09:00

124 lines
5.3 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 = "패치"
KEEP = ("덮개", "뺀줄", "더한줄")
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[k]}
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 KEEP}
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)
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