refactor(776-2): EST 단가산출 읽기 어댑터 떼어 냄 · 두 형식 블록 항목 · STmate 블록 단가 · 금액
- 새 M02_Hopyo_ReadEst.py — Basis.read(엑셀 「단가산출」 블록) · trade_names · sources 옮김 + 글 → 항목 풀이(L 직종 · X 장비 · M 자재 · 줄 율에 기대지 않는 것만) - Basis — 근거 후보만 남김 · 옛 이름(read · SHEET · GLINES · GCHARS · sources · trade_names)은 그대로 다시 냄 - Stmate — 블록 금액(머리 줄 C~F) · 항목(자원 + 단가 I~L · 금액 C~F · 기계 셋 줄 더함 · 행) · 항목 단가 639 중 635 - 항목만으로 지문 인력 · 장비 · 자재 다시 세움 = 지금 지문과 544 쌍 모두 같음(tmp 대조 · 776-3 길) - S1 · S2 해시 그대로 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -13,8 +13,11 @@ PR · 단위 % = % · 그 밖 기타.
|
||||
단가산출근거 = 「BDCOD|D…」 머리 → 다음 머리 · 「총계」 앞까지 한 블록 · 글 = B 열(머리 이름 줄 ·
|
||||
소계 · 계 뺌) · 자원 = M 열 「X00000_n」 줄(품 = H 열 · 이름 · 규격 = X 열 「이름 / 규격」 ·
|
||||
비면 목록표 · 기계 셋 줄(노무비 · 재료비 · 경비)은 하나로 · 절 = 그 앞 번호 절 제목) ·
|
||||
머리 이름 · 규격 · 단위 = 단가산출근거목록표 · 출처 = 블록 글 `Basis.sources` ·
|
||||
직종 = 자원 L 이름(우리 인력 · 옛이름 = 지금 이름).
|
||||
머리 이름 · 규격 · 단위 = 단가산출근거목록표 · 출처 = 블록 글 `ReadEst.sources` ·
|
||||
직종 = 자원 L 이름(우리 인력 · 옛이름 = 지금 이름) ·
|
||||
금액 = 머리 줄 C~F(1 단위) · 항목(776-2 · Book 블록 항목 · EST 어댑터 `M02_Hopyo_ReadEst` 와
|
||||
같은 꼴) = 자원 + `{직종(L), 밑품 = 품, 율 [], 인자 [], 단가 I~L, 금액 C~F, 어떻게 「QTY」, 행}`
|
||||
(기계 셋 줄 = 더함).
|
||||
검산 안 함 — `검산 {어긋남: [], 총괄표: 0}`.
|
||||
"""
|
||||
|
||||
@@ -23,8 +26,8 @@ from __future__ import annotations
|
||||
import re
|
||||
from typing import Any
|
||||
|
||||
from M02_MasterTemplete import M02_Hopyo_Basis as hopyo_basis
|
||||
from M02_MasterTemplete import M02_Hopyo_Excel as hopyo_excel # 서로 부름 — 부를 때만 씀
|
||||
from M02_MasterTemplete import M02_Hopyo_ReadEst as hopyo_est
|
||||
|
||||
SHEET = "일위대가표"
|
||||
CALC = "단가산출근거"
|
||||
@@ -39,6 +42,8 @@ _RES_A = re.compile(r"^([LMXS]\d{5})[LMS]$") # A 열 「L00002L」
|
||||
_RES_G = re.compile(r"&([LMXS]\d{5})[LMS]&") # G 열 식 「&L00002L&」
|
||||
_SECTION = re.compile(r"^\s*(?:\d+\s*[.)]|[①-⑩])\s*(.*\S)")
|
||||
_COLS = {"합계": 4, "노무비": 6, "재료비": 8, "경비": 10}
|
||||
_CALC_AMOUNT = {"합계": 2, "노무비": 3, "재료비": 4, "경비": 5} # 단가산출근거 C~F 금액
|
||||
_CALC_PRICE = {"합계": 8, "노무비": 9, "재료비": 10, "경비": 11} # I~L 단가(T · L · M · S)
|
||||
NOTE, CODE_COLS, RES_COL, QTY_COL, NAME_COL = 12, range(12, 26), 12, 7, 23
|
||||
_KIND = {"D": "단가산출", "B": "호표", "L": "노임", "X": "기계", "S": "별도계상", "W": "별도계상"}
|
||||
|
||||
@@ -67,6 +72,17 @@ def _code(row: list[Any], cols: Any = CODE_COLS) -> str | None:
|
||||
return None
|
||||
|
||||
|
||||
def _calc_money(row: list[Any], cols: dict[str, int]) -> dict[str, int | float | None]:
|
||||
return {k: hopyo_excel._out(v) for k, v in hopyo_excel._money(row, cols, 0).items()}
|
||||
|
||||
|
||||
def _add(into: dict[str, Any], more: dict[str, Any]) -> None:
|
||||
"""기계 셋 줄(노무비 · 재료비 · 경비) 단가 · 금액을 한 항목에 더함."""
|
||||
for k, v in more.items():
|
||||
if v is not None:
|
||||
into[k] = hopyo_excel._out(hopyo_excel._num(into.get(k) or 0) + hopyo_excel._num(v))
|
||||
|
||||
|
||||
def _lists(sheets: dict[str, list[list[Any]]]) -> dict[str, dict[str, str]]:
|
||||
"""목록표 → {코드: {이름, 규격, 단위}} — B 이름 · C 규격 · D 단위 · 코드 = 숨은 칸
|
||||
「COD|…」 · 없으면 코드 꼴 첫 칸(판마다 A 열 · 뒤 열)."""
|
||||
@@ -86,8 +102,8 @@ def _lists(sheets: dict[str, list[list[Any]]]) -> dict[str, dict[str, str]]:
|
||||
|
||||
# ── 단가산출근거 블록 ──────────────────────────────────────────────────
|
||||
def _blocks(rows: list[list[Any]], table: dict[str, dict[str, str]]) -> dict[str, dict[str, Any]]:
|
||||
"""{D 코드: {번, 코드, 이름, 규격, 단위, 행, 출처, 직종, 글, 자원}}."""
|
||||
names = hopyo_basis.trade_names()
|
||||
"""{D 코드: {번, 코드, 이름, 규격, 단위, 행, 출처, 직종, 글, 자원, 금액, 항목}}."""
|
||||
names = hopyo_est.trade_names()
|
||||
out: dict[str, dict[str, Any]] = {}
|
||||
block: dict[str, Any] | None = None
|
||||
title = ""
|
||||
@@ -109,6 +125,8 @@ def _blocks(rows: list[list[Any]], table: dict[str, dict[str, str]]) -> dict[str
|
||||
"행": [at, at],
|
||||
"글": [],
|
||||
"자원": [],
|
||||
"금액": _calc_money(row, _CALC_AMOUNT),
|
||||
"항목": [],
|
||||
},
|
||||
)
|
||||
title = ""
|
||||
@@ -135,30 +153,46 @@ def _blocks(rows: list[list[Any]], table: dict[str, dict[str, str]]) -> dict[str
|
||||
block["이름"], block["단위"] = name.strip() or text, unit.strip()
|
||||
continue
|
||||
if text and _flat(text) not in ("소계", "계"):
|
||||
if len(block["글"]) < hopyo_basis.GLINES:
|
||||
block["글"].append(text[: hopyo_basis.GCHARS])
|
||||
if len(block["글"]) < hopyo_est.GLINES:
|
||||
block["글"].append(text[: hopyo_est.GCHARS])
|
||||
if (sec := _SECTION.match(text)) and not re.match(r"^\s*\d+\.\d", text):
|
||||
title = sec.group(1).strip()
|
||||
if not code:
|
||||
continue
|
||||
price, amount = _calc_money(row, _CALC_PRICE), _calc_money(row, _CALC_AMOUNT)
|
||||
last = block["자원"][-1] if block["자원"] else None
|
||||
if code[0] == "X" and last and last["코드"] == code and last["절"] == title:
|
||||
continue # 기계 노무비 · 재료비 · 경비 셋 줄 = 하나
|
||||
_add(block["항목"][-1]["단가"], price) # 기계 노무비 · 재료비 · 경비 셋 줄 = 하나
|
||||
_add(block["항목"][-1]["금액"], amount)
|
||||
continue
|
||||
name, _, spec = _s(_cell(row, NAME_COL)).partition("/")
|
||||
info = table.get(code) or {}
|
||||
qty = hopyo_excel._num(_cell(row, QTY_COL))
|
||||
block["자원"].append(
|
||||
res = {
|
||||
"갈래": code[0],
|
||||
"코드": code,
|
||||
"이름": name.strip() or info.get("이름", ""),
|
||||
"규격": spec.strip() if name.strip() else info.get("규격", ""),
|
||||
"품": float(qty) if qty is not None else None,
|
||||
"절": title,
|
||||
}
|
||||
block["자원"].append(res)
|
||||
who = hopyo_est.trade(res["이름"]) if code[0] == "L" else None
|
||||
block["항목"].append(
|
||||
{
|
||||
"갈래": code[0],
|
||||
"코드": code,
|
||||
"이름": name.strip() or info.get("이름", ""),
|
||||
"규격": spec.strip() if name.strip() else info.get("규격", ""),
|
||||
"품": float(qty) if qty is not None else None,
|
||||
"절": title,
|
||||
**res,
|
||||
**({"직종": who} if code[0] == "L" else {}),
|
||||
"밑품": res["품"],
|
||||
"율": [],
|
||||
"인자": [],
|
||||
"단가": price,
|
||||
"금액": amount,
|
||||
"어떻게": "QTY",
|
||||
"행": at,
|
||||
}
|
||||
)
|
||||
for block in out.values():
|
||||
block["출처"] = hopyo_basis.sources(" ".join(block["글"]))
|
||||
block["출처"] = hopyo_est.sources(" ".join(block["글"]))
|
||||
trades = [names.get(_flat(r["이름"])) for r in block["자원"] if r["갈래"] == "L"]
|
||||
block["직종"] = list(dict.fromkeys(t for t in trades if t))
|
||||
return out
|
||||
@@ -257,7 +291,20 @@ def read(sheets: dict[str, list[list[Any]]]) -> dict[str, Any]:
|
||||
if not hopyo["근거글"]:
|
||||
del hopyo["근거글"]
|
||||
out.append({**hopyo_excel._json(hopyo), "줄": [hopyo_excel._json(x) for x in lines]})
|
||||
keep = ("번", "코드", "이름", "규격", "단위", "행", "출처", "직종", "글", "자원")
|
||||
keep = (
|
||||
"번",
|
||||
"코드",
|
||||
"이름",
|
||||
"규격",
|
||||
"단위",
|
||||
"행",
|
||||
"출처",
|
||||
"직종",
|
||||
"글",
|
||||
"자원",
|
||||
"금액",
|
||||
"항목",
|
||||
)
|
||||
return {
|
||||
"꼴": "STmate",
|
||||
"시트": SHEET,
|
||||
|
||||
Reference in New Issue
Block a user