Files
Aislo/M02_MasterTemplete/M02_San_Xlsx_Stmate.py
T
eomsangdonandClaude Opus 5.5 109789a746 feat(828-2): STmate 엑셀 일위대가표 숨은 칸 → 구성 줄 — 읽는 곳 하나 · 율 줄 · 닫기 · 일식 · 별도계상 · 판에 일위 재료
- M02_San_Xlsx_Ilwi(새) = 일위대가표 읽기 한 곳 — N 열 메타(COD · IPR · PRI · PRO · EQC · KWN · DVD) · O 열 차수 꼬리 기준 · 줄 꼴 = 828-1 M02_San_Ilwi 꼴 + 엑셀 칸(행 · 차수 · 비고 · 전체 · 율.코드 · 메타) · 숨은 칸 없음 = 옛 코드 찾기 · 단산 길 일위 빈 목록 + 표지
- 5 건 호표 136 · 줄 706 · STC 구성 줄과 코드 · 갈래 · 수량 · 율 · 밑줄 같음(다른 5 줄 = STC 별도계상 규칙이 비고 별산 표시를 놓침)
- 호표 길(M02_Hopyo_Stmate._hopyos) · 단산 길(M02_San_Xlsx_Stmate.read 일위) · 단서(M02_San_MatFind.from_book) 모두 공용 읽기 · 단서 · 산근 · 단가 전후 같음
- M02_Hopyo_Fixed._ratio = 숨은 칸 율 밑 · 대상 비목 먼저(글 짐작 대신) — 호표 길 전후 바뀜 = 영덕 제11호표 산악할증 0% 한 줄(금액만 → 비율 노무비 · 금액 0 그대로) · 단산 항목 1564 판정 그대로
- 재료 판(census) = 일위 구성 줄 자재도 셈(M02_San_MatFind.ilwi_found · 종 칸 일위 = 호표 코드 · 화면 「일위대가 N 호표」)
- 시험: 새 test_828_2_xlsx_ilwi_meta · test_827_2 단서 시트 보기에 「제N호표」 줄 넣음(실제 시트는 늘 있음 · 공용 읽기가 호표 머리부터 셈)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-13 20:39:15 +09:00

87 lines
4.4 KiB
Python

"""STmate 산근 엑셀 → 810-1 구조 줄(PLAN 812-1 · `M02_San_Stc.read` 와 같은 꼴 · 읽기만 · 서버 단독).
엑셀 「단가산출근거」 숨은 G 열 = 원파일 COSTN.SMT 원문 그대로 → 줄 = `M02_San_Stc.stc_line`(풀이 =
`M02_San_Stmate.parse_line` · 다시 짜지 않음) · 블록 머리 금액(C~F) = 원파일 저장(TAMT1 …) ·
단가 = 목록표(노무비 · 재료비 · 경비 · 중기 · 단가산출근거 · 숨은 메타 = COSTN 칸) ·
끝전 = 파일 투표(`_원파일파서_틀.md` 4 장 SAN_TYP 두 갈래 중 블록 계가 맞는 수가 많은 쪽 · 파일에 하나 ·
같으면 비목버림).
"""
from __future__ import annotations
from typing import Any
from M02_MasterTemplete import M02_San_Book as book
from M02_MasterTemplete import M02_San_Eval as ev
from M02_MasterTemplete import M02_San_Stc as stc
from M02_MasterTemplete import M02_San_Xlsx as sx
RULE = {"비목버림": "1", "합버림_큰나머지": "0"} # 끝전 갈래 → SAN_TYP
def _amt(head: dict) -> dict[str, float]:
return {c: float(head.get(k) or 0) for c, k in zip("TLMS", "CDEF")}
def vote(blocks: list[dict], prices: dict) -> tuple[str, dict[str, int]]:
"""파일 끝전 — 블록마다 두 갈래로 셈해(낙찰 · 조정 뒤) 엑셀 머리 계(C)와 맞는 수 · 많은 쪽(같으면
비목버림)."""
got = dict.fromkeys(RULE, 0)
for blk in blocks:
nodes = [ln["풀이"] for ln in blk["줄"]]
want = (blk.get("저장") or {}).get("T")
for rule in RULE:
try:
total = ev.stmate_block({"코드": blk["코드"]}, nodes, prices, rule)["금액"]["T"]
except Exception: # noqa: BLE001 — 못 셈 = 표 없음
continue
got[rule] += want is not None and abs(float(total) - float(want)) < 0.5
best = max(RULE, key=lambda r: (got[r], r == "비목버림"))
return best, got
def read(sheets: dict[str, list]) -> dict[str, Any]:
"""STmate 엑셀 시트 → {꼴, 산근, 일위, 자원, 내역, 단가, 옵션, 표지} · 일위 = 일위대가표 숨은 칸
구성 줄(828-2 `M02_San_Xlsx_Ilwi` · 숨은 칸 없으면 빈 목록 + 표지)."""
found = book.stmate_prices(sheets)
prices = {c: {k: p.get(k) for k in ("T", "L", "M", "S", "meta")} for c, p in found.items()}
res = {
c: {"종류": stc.KIND.get(c[:1]), **{k: p.get(k) for k in ("이름", "규격", "단위")}}
| {"저장": {k: p.get(k) for k in "TLMS"}}
for c, p in found.items()
}
out: dict[str, Any] = {"꼴": "STmate", "산근": [], "일위": [], "자원": res, "단가": prices}
for blk in book.stmate_blocks(sheets):
tags: list[str] = []
lines = [stc.stc_line(i, ln["G"], res, tags) for i, ln in enumerate(blk["몸"], 1)]
for one, src in zip(lines, blk["몸"]):
one["엑셀행"] = src["행"]
me = found.get(blk["코드"]) or {}
head = {"코드": blk["코드"], "이름": blk.get("이름") or me.get("이름")}
head |= {"규격": me.get("규격"), "단위": me.get("단위"), "저장": _amt(blk["머리"])}
_, tot = ev.run_stmate([ln["풀이"] for ln in lines], prices)
body = [{k: ln.get(k) for k in ("행", "B", "C", "D", "E", "F")} for ln in blk["몸"]]
out["산근"].append(
{**head, "줄": lines, "줄합": tot, "표지": tags, "엑셀행": blk["행"]}
| {
"몸": body,
"꼬리": blk["꼬리"],
} # 엑셀 줄 금액 · 계 꼬리(검산 · `M02_San_Emit.stmate`)
)
rule, got = vote(out["산근"], prices)
out["옵션"] = {"SAN_TYP": RULE[rule]}
out["내역"] = None
from M02_MasterTemplete import M02_San_MatFind as mf
from M02_MasterTemplete import M02_San_Xlsx_Ilwi as ilwi
sheet = ilwi.read(sheets.get(ilwi.SHEET)) # 828-2 일위대가표 숨은 칸 → 구성 줄(읽는 곳 하나)
out["일위"] = ilwi.blocks(sheet)
out["단서"] = mf.from_book(sheet) # 827-2 재료 단서
out["표지"] = [
f"{sx.NOTE}일위대가 구성 = 일위대가표 숨은 칸 · 내역은 안 읽음"
if sheet["숨은칸"]
else f"{sx.NOTE}일위대가표 숨은 칸 없음(값만 복사) — 구성 줄 안 읽음 · 일위대가는 호표 길",
f"{sx.NOTE}끝전 = 파일 투표 {rule}(비목버림 {got['비목버림']} · 합버림 {got['합버림_큰나머지']} 블록)",
]
return out