- 새 M02_San_MatFind: 줄 판정 자원「재료찾기」{판정 · 방법 · 키 · 후보 · 단서} — 이어짐 · 규격 없음 — 고르기 · 후보 여럿 · 우리 표에 없음
- 단서: 산근 줄 설명 글 · 산근 머리 · STC 내역서 자재 줄 · STmate 엑셀 일위대가표(규격 빈 줄 · 별도계상 줄만 좁힘 · 관급/사급은 안 가름)
- 자동 규칙 A · B · C · E · F · F2(G 안 씀) — 원천 넷 이미 이은 464 종에 얹어 다른 키 0 · E 는 이름 같은 우리 줄 있으면 안 씀
- 별도계상 줄: 품목은 판정 키에만 · 줄 이음 · 단가 0 그대로
- 의심 고침: 블레이드 d=320~400 t=3.2 → 4" (규격 수 하나를 두 번 맞춤 — spec_fit 한 번씩) · 유압식드릴롯드 → 드릴롯드 AX 1.5(후보 하나 + 규격 수 부딪힘 = 이음 안 함) · 참싸리(박피)는 사용자 과녁대로 둠
- 전수: 금액 같음 3241/3241 · 기계 그대로 · 재료 이음 EST 원파일 99.7 그대로 · EST 엑셀 82.9→84.6 · STmate 원파일 59.8→68.5 · STmate 엑셀 66.7→76.5 · 새 이음 32 줄 틀림 0 · 키 바뀜 0
- 시험: test_817_1 표 일곱 줄 후보→이음(사용자 과녁 1 순위 키 그대로 · 보조강재만 새 키 MT030619) · 낡은 기대 고침
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
81 lines
3.9 KiB
Python
81 lines
3.9 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 엑셀 시트 → {꼴, 산근, 일위, 자원, 내역, 단가, 옵션, 표지}."""
|
|
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
|
|
|
|
out["단서"] = mf.from_book(sheets.get("일위대가표")) # 827-2 재료 단서
|
|
out["표지"] = [
|
|
f"{sx.NOTE}일위대가 구성 · 내역은 호표 길(산근만 읽음)",
|
|
f"{sx.NOTE}끝전 = 파일 투표 {rule}(비목버림 {got['비목버림']} · 합버림 {got['합버림_큰나머지']} 블록)",
|
|
]
|
|
return out
|