Files
Aislo/M02_MasterTemplete/M02_Item_Sangeun.py
T
eomsangdonandClaude Opus 5.5 ccabbad6fb feat(719-2): 공사 쪽 M02 단가산출(SK) — B09 대가 블록 · 산근 · [업데이트] · 내 자료집 SK
- Labor_Source: 굳힌 SK = 품셈 꼴 대가 블록(사본 단가.json 굳힌 키 줄 · M01 안 읽음) · 단가산출 속 일위대가 · SK 줄 = 그 대가 블록 부르는 줄 · 고정 줄 = fixed · 단가 고친 줄 = fixed(M02 셈 단가) · cover = P:+SK 이름표(SK 고쳐도 B09 덮개 그대로) · 줄 sk · poom(품셈 값) · 부르는 줄 수량 ÷ 굳힌 줄 배 · 사전조합 알약 = 굳힌 알약 · 서고 sangeun 사본
- Sangeun: SK 하위 로직 = 산근 · 단가산출 속 참조 걸음 · 결과단위 배 = 사본 줄에서(_unit(row) · unit_of(whole, code))
- Linked: 굳힌 SK 자원 키(굳힌 키 로직 줄 · 고정 이음)
- Refresh: 미리 보기 단가산출(바뀌는 SK 줄) · 서고 사본 원본판 다르면 다시 굳힘
- Bill_Library: 종류 sangeun(내 자료집 SK 불러오기) · changed · refresh_copy(같은 폴더 · 값 그대로 · 원본판 없는 옛 사본 그대로)
- Daega_Personal: 품셈 블록(굳힌 SK 포함) → 개인 층 SK(B09 품 · 단가 덮개 = SK 덮개 · 더한줄 수량 · 단가)
- M02_Item_Sangeun: 굳힌 SK 정체(굳힌 줄 차례 → 원본 cid)
- 화면: 일위대가 펼침 SK 줄 되돌림 [단가산출 값으로] · 곁 글 품셈 값 · 내 자료집 단가산출 글 · 업데이트 미리 보기 SK 줄 · 단가연결 내 것 단가산출(Labor_Api fetchLibrary 종류 넓힘)
- 시험 test_719_2_sk_project 5 통과 + 1 건너뜀(715-1b 엔진 단가 · 값묶음 뒤 자동 실행)
- test_155_5: _unit 인자 = 로직 줄로 바뀜(사본 줄에서 배 읽음) — 부르는 줄 고침

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

105 lines
4.7 KiB
Python

"""프로젝트 사본 — M02 단가산출(SK) 풀어 굳힘(PLAN 719-1 · 요구서 내역12 원칙 3 · 4장 14).
사본을 만들 때(구조물 사본 `M02_Item_Source.build_source` · B09 서고 사본 `Bill_Library`) 굳힌
참조사본 안 SK 문서마다 고친 줄(`M02_Sangeun_Calc.resolve` = 바탕 사슬 + 덮개 · 더한줄 · 뺀줄)을
풀어 사본 `단가.json` 로직 줄 하나로 굳힘 — 사본 SK 문서는 그 줄만 바탕으로 가리킴(덮개 0 ·
연결 끊김). 셈은 그대로 `M02_Sangeun_Calc` 한 벌(사본 색인 = 사본 `단가.json`).
굳힌 키 = SK 참조 이름표(`ref_id` = 층 · 주인 · 키)에서 정해지는 `GX9#####`(해시 · 겹치면
이름표 차례로 다음 번호) — 같은 SK = 같은 굳힌 키([업데이트] 때 B09 덮개 cover · cid · 입력값 ·
고른자재가 짝을 안 잃음). 원본 층 문서는 읽기만.
사본 SK 문서 = {종류 · 키 · 이름 · 단위 · 구분 · 상세구분, 바탕 {로직: 굳힌 키}, 입력값(사슬 합),
열린입력, 켜쌓기율, 고름 · 자재표시(굳힌 줄 cid), 덮개 {}, 더한줄 [], 뺀줄 [],
굳힌줄(= 단가.json 줄), 원본(원래 SK 문서 · 「M02 에서 고침」 근거), 정체(굳힌 줄 차례 → 원본
cid · 더한줄 = `add:#k`), 바탕판, 짝잃음}.
단가산출 속 일위대가(SC) · SK 더한줄 = 참조 줄 그대로 → 사본 셈이 굳힌 참조사본으로 펼침.
"""
from __future__ import annotations
import hashlib
from typing import Any
from M02_MasterTemplete import M02_Labor_Ref as refs
from M02_MasterTemplete import M02_Sangeun_Doc as sd
#: 사본 `단가.json` 안 굳힌 SK 줄 파일(`master_formula.Master` 가 그룹 「로직」 으로 읽음)
FILE = "로직_단가산출.json"
ROW = "굳힌줄"
_HEAD, _LOW, _SPAN = "GX", 900000, 99999 # GX900000 ~ GX999998(999999 = M01 저장 전 초안)
def frozen_key(rid: str, taken: set[str]) -> str:
"""SK 이름표 → 굳힌 로직 키 — 해시 자리 · 이미 쓴 키면 다음 번호(제자리 `taken` 에 더함)."""
at = int(hashlib.sha256(rid.encode("utf-8")).hexdigest(), 16) % _SPAN
while (key := f"{_HEAD}{_LOW + at:06d}") in taken:
at = (at + 1) % _SPAN
taken.add(key)
return key
def is_sangeun(doc: Any) -> bool:
return isinstance(doc, dict) and doc.get("종류") == sd.TITLE
def freeze(copies: dict[str, dict[str, Any]]) -> dict[str, dict[str, Any]]:
"""참조사본 `{ref_id: 문서}` → SK 를 풀어 굳힌 참조사본(새 묶음 · 받은 것 안 고침) ·
못 푼 SK(없는 바탕 · 순환) = 그대로(사본 셈이 까닭을 냄)."""
from M01_MasterData import M01_MasterData_Store as m01
from M02_MasterTemplete import M02_Item_Prices as prices
from M02_MasterTemplete import M02_Sangeun_Calc as calc
sks = sorted(rid for rid, doc in copies.items() if is_sangeun(doc))
if not sks:
return copies
whole = m01.loaded()[1]
def read(ref: dict) -> dict | None:
return copies.get(refs.ref_id(ref))
out, taken = dict(copies), set()
for rid in sks:
doc = copies[rid]
try:
got = calc.resolve(doc, whole, read, (rid,))
except sd.DocError:
continue
key = frozen_key(rid, taken)
row = prices.to_json({**got["줄"], "키": key})
ids = sd.line_ids(row)
frozen = {k: doc.get(k) for k in ("종류", "키", "이름", "단위", "구분", "상세구분")}
frozen |= {
"바탕": {"로직": key},
"입력값": prices.to_json(got["입력값"]),
"열린입력": list(doc.get("열린입력") or []),
"고름": {ids[int(n)]: mt for n, mt in got["고름"].items()},
"자재표시": {ids[int(n)]: one for n, one in got["자재표시"].items()},
"덮개": {},
"더한줄": [],
"뺀줄": [],
ROW: row,
"원본": doc,
"정체": list(got["정체"]), # 굳힌 줄 차례 → 원본 cid(B09 덮개 · 내 자료집 · 719-2)
"바탕판": got["바탕판"],
"짝잃음": got["짝잃음"],
}
if got["켜쌓기율"] is not None:
frozen["켜쌓기율"] = prices.to_json(got["켜쌓기율"])
out[rid] = frozen
return out
def rows(copies: dict[str, Any]) -> list[dict[str, Any]]:
"""굳힌 SK 줄 — 사본 `단가.json` `FILE` 에 넣음(이름표 차례)."""
return [doc[ROW] for _, doc in sorted(copies.items()) if is_sangeun(doc) and ROW in doc]
def materials(copies: dict[str, Any]) -> list[str]:
"""굳힌 SK 고른 자재 키 — 단가 묶음에 담음."""
return [
str(mt)
for doc in copies.values()
if is_sangeun(doc)
for mt in (doc.get("고름") or {}).values()
]