- 새 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>
104 lines
4.3 KiB
Python
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
|