Files
Aislo/M02_MasterTemplete/M02_Hopyo_Sangeun.py
T
eomsangdonandClaude Opus 5.5 cc588889f6 feat(718-1): 불러오기 결과 「단가산출」 켬 — 산근 블록마다 바탕 없는 단가산출(715-2 받음)
- 새 M02_Hopyo_Sangeun.py — 단산 블록을 부르는 첫 엑셀 줄 1 단위 단가를 고정 더한줄 하나로 · 본뜬 「HP-###### 단산N」 · 같은 본뜬은 그대로(겹침 없음)
- 길 POST /layers/{층}/hopyo/{키}/sangeun · [끝내기] 지문 기록에 단가산출도 셈
- 마법사: 결과 「단가산출」 체크 켬 → ② 걸음 [단가산출 만들기] · 알림 글 「일위대가 · 단가산출」
- 시험: test_718_1 단가산출 더함 · 낡은 대조 고침 — 716-3 왼쪽 판 차례(extras 없어짐) · SANGEUN_READY 대조
- 고정 더한줄 셈 값(엔진 값묶음)은 715-1b 뒤

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

104 lines
4.3 KiB
Python

"""M02 일위대가 불러오기 → 단가산출(PLAN 718-1 · 요구서 내역12 4장 22) —
산근(단산) 블록 = 바탕 없는 단가산출.
블록마다 SK 하나 — 그 블록을 부르는 첫 엑셀 줄(「단산N참조」)의 1 단위 단가
(노무비 · 재료비 · 경비)를 고정 더한줄 하나로(`M02_Hopyo_Fixed` 꼴 · 엑셀 숫자 그대로 ·
서버가 파일에서 읽음) · 이름 = 블록 이름(없으면 줄 품명) · 단위 = 줄 단위(없으면 블록 · 「식」) ·
구분 「실무자료」 · 상세구분 = 파일 · 본뜬 = {층 「실무자료」, 키 「HP-###### 단산N」, 파일, 원본,
확인} · 같은 본뜬이 이 층에 있으면 그대로(겹침 없음) · 만드는 층 = 부르는 층(마법사에서 고른 층).
"""
from __future__ import annotations
import json
from pathlib import Path
from typing import Any
from common_util.common_util_time import utc_now_text
from M02_MasterTemplete import M02_Hopyo_Fixed as hfix
from M02_MasterTemplete import M02_Hopyo_Store as hopyo_store
from M02_MasterTemplete import M02_Labor_Fixed as fixed
from M02_MasterTemplete import M02_Labor_Ref as refs
ORIGIN = "실무자료"
KIND = "sangeun"
def mark(key: str, no: int) -> str:
return f"{key} 단산{no}"
def made(folder: str | Path, key: str | None = None) -> dict[str, str]:
"""이 층 실무자료 단가산출 `{본뜬 키: SK 키}`(`key` = 그 HP 것만)."""
out = {}
for path in sorted((Path(folder) / KIND).glob("SK-*.json")):
try:
got = json.loads(path.read_bytes()).get("본뜬")
except (OSError, ValueError, AttributeError):
continue
if isinstance(got, dict) and got.get("층") == ORIGIN:
if key is None or str(got.get("키") or "").startswith(f"{key} "):
out[str(got.get("키"))] = path.stem
return out
def _doc(line: dict, block: dict, no: int, hp: dict, stamp: str, who: Any) -> dict[str, Any]:
name = str(block.get("이름") or line.get("이름") or "").strip() or f"단산{no}"
unit = str(line.get("단위") or block.get("단위") or "").strip() or "식"
spec = str(line.get("규격") or "").strip()
price = {k: hfix._plain(v) for k, v in hfix._parts(line.get("단가")).items()}
fx = {
"이름": name,
"규격": spec,
"단위": unit,
"단가": price,
"이음": dict.fromkeys(fixed.LINKS),
"출처": {"파일": hp.get("파일"), "호표": line.get("_호표"), "줄": int(line.get("차례", 0))},
}
return {
"종류": "단가산출",
"이름": name,
"단위": unit,
"구분": ORIGIN,
"상세구분": str(hp.get("파일") or ""),
"본뜬": {
"층": ORIGIN,
"키": mark(hp["키"], no),
"파일": hp.get("파일"),
"원본": list(refs.here()),
"확인": {"누가": who, "때": stamp},
},
"바탕": None,
"입력값": {},
"열린입력": [],
"고름": {},
"자재표시": {},
"덮개": {},
"더한줄": [{"고정": fx, "이름": name, "단위": unit, "수량": 1}],
"뺀줄": [],
}
def build(folder: Path, key: str, who: Any = None) -> dict[str, Any]:
"""[단가산출 만들기] — 산근 블록마다 바탕 없는 단가산출 →
`{블록, 만듦 [{번, 이름, 키}], 그대로}`."""
hp = hopyo_store.read(folder, key)
blocks = {int(b["번"]): b for b in hp.get("단산") or [] if b.get("번") is not None}
calls: dict[int, dict] = {}
for h in hp.get("호표") or []:
for line in h.get("줄") or []:
ref = line.get("참조") or {}
no = int(ref.get("번") or 0) if ref.get("종류") == "단산" else 0
if no in blocks and no not in calls:
calls[no] = {**line, "_호표": h.get("번")}
have, stamp = made(folder, key), utc_now_text()
out: dict[str, Any] = {"블록": len(calls), "만듦": [], "그대로": 0}
for no in sorted(calls):
if mark(key, no) in have:
out["그대로"] += 1
continue
doc = _doc(calls[no], blocks[no], no, hp, stamp, who)
got = refs.create(KIND, doc)
out["만듦"].append({"번": no, "이름": doc["이름"], "키": got["이름"]})
return out