92 lines
3.9 KiB
Python
92 lines
3.9 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""분리형 변경 STC 만들기 · 차수 인계 — 앞 파일의 현재안이 새 파일 BOQ11 차수1, 차수2 = 이번 변경 출발점.
|
|
|
|
근거: 16_골든셋_회귀_결과.md §4.5(한 파일에 BOQ11·BOQ12 → BOQ12 가 현재안) · §4.6(분리형: 새 파일 BOQ11 차수1 =
|
|
앞 파일 BOQ12 · 차수2 = 이번 변경분) · 08번 §2(통합형 / 분리형) · stc_project(해당분만 압축 · 차수 칸 복사)
|
|
규칙:
|
|
- 현재안 = 내역 표가 있는 PRJLST 행 중 PCODE 가 가장 큰 행(지정 가능) · 그 행 K_ORD k → 현재 차수 s = k+1
|
|
- 새 파일 = 그 공사만 담은 STC(BOQ11 · PRJLST 한 행 · 그 메모) · 내역 s 차 칸 → 1차 칸(s ≠ 1 일 때) → 2차 칸 복사
|
|
- PRJLST ?COSTs·COSTWs → 1차 칸 · 1차 → 2차 칸 · K_ORD = 1 · 메모 [s_KANJUB] → [1_KANJUB] · [1_KANJUB] → [2_KANJUB]
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import re
|
|
|
|
from dbf_memo import BLANK_PTR, SixMemo, ini_items, memo_text_bytes
|
|
from dbf_rw import DbfTable
|
|
from stc_project import SLOT_COL, _copy_slot, _rename_section, pack_selected
|
|
|
|
PRJ_SLOT = ("MCOST", "LCOST", "SCOST", "TCOST", "ACOST", "COSTW")
|
|
|
|
|
|
def current_pcode(files: dict) -> str:
|
|
"""현재안 공사 — BOQ 표가 있는 PRJLST 행 중 PCODE 최대(통합형 BOQ12 > BOQ11)."""
|
|
prj = DbfTable(files["PRJLST.DBF"])
|
|
codes = [
|
|
prj.get(i, "PCODE") for i in range(len(prj)) if f"BOQ{prj.get(i, 'PCODE')}.DBF" in files
|
|
]
|
|
if not codes:
|
|
raise ValueError("내역 표가 있는 공사 없음")
|
|
return max(codes, key=lambda c: int(c) if c.isdigit() else 0)
|
|
|
|
|
|
def _move_section(text: str, src: int, dst: int) -> str:
|
|
"""[src_KANJUB] 섹션을 [dst_KANJUB] 로 이름·키 접두를 바꿔 옮김(dst 가 이미 있으면 그대로)."""
|
|
if src == dst:
|
|
return text
|
|
secs = {s for s, _k, _v in ini_items(text)}
|
|
if f"{src}_KANJUB" not in secs or f"{dst}_KANJUB" in secs:
|
|
return text
|
|
out, cur = [], ""
|
|
for ln in text.split("\r\n"):
|
|
s = ln.strip()
|
|
if s.startswith("[") and s.endswith("]"):
|
|
cur = s[1:-1]
|
|
if cur == f"{src}_KANJUB":
|
|
ln = f"[{dst}_KANJUB]"
|
|
elif cur == f"{src}_KANJUB":
|
|
ln = re.sub(rf"^{src}_", f"{dst}_", ln)
|
|
out.append(ln)
|
|
return "\r\n".join(out)
|
|
|
|
|
|
def split_change(files: dict, pcode: str = "") -> tuple[dict, dict]:
|
|
"""앞 파일 files → 다음 변경 차수 파일 files · 보고."""
|
|
pc = pcode or current_pcode(files)
|
|
prj0 = DbfTable(files["PRJLST.DBF"])
|
|
si = next(i for i in range(len(prj0)) if prj0.get(i, "PCODE") == pc)
|
|
k = int(float(prj0.get(si, "K_ORD") or 0)) if "K_ORD" in prj0.fields else 0
|
|
s = k + 1
|
|
out = pack_selected(files, pc)
|
|
bt = DbfTable(out["BOQ11.DBF"])
|
|
if s != 1:
|
|
_copy_slot(bt, str(s), "1")
|
|
_copy_slot(bt, "1", "2")
|
|
bt.dirty = True
|
|
out["BOQ11.DBF"] = bt.to_bytes()
|
|
prj = DbfTable(out["PRJLST.DBF"])
|
|
for c in PRJ_SLOT:
|
|
a, one, two = f"{c}{s}", f"{c}1", f"{c}2"
|
|
if a in prj.fields and one in prj.fields:
|
|
prj.set_raw(0, one, prj0.raw(si, a))
|
|
if one in prj.fields and two in prj.fields:
|
|
prj.set_raw(0, two, prj.raw(0, one))
|
|
if "K_ORD" in prj.fields:
|
|
prj.set(0, "K_ORD", 1)
|
|
memo = SixMemo(out.get("PRJLST.SMT"))
|
|
text = memo.read(prj.raw(0, "PRJ_MEMO")).decode("cp949", "replace")
|
|
text = _rename_section(_move_section(text, s, 1), 1, 2)
|
|
fresh = SixMemo(None, memo.bs)
|
|
prj.set_raw(0, "PRJ_MEMO", fresh.write(BLANK_PTR, memo_text_bytes(text)) if text else BLANK_PTR)
|
|
out["PRJLST.DBF"] = prj.to_bytes()
|
|
out["PRJLST.SMT"] = fresh.to_bytes()
|
|
slot_cols = sorted({SLOT_COL.match(c).group(1) for c in bt.order if SLOT_COL.match(c)})
|
|
return out, {
|
|
"from_pcode": pc,
|
|
"from_slot": s,
|
|
"k_ord": 1,
|
|
"rows": len(bt),
|
|
"slot_cols": slot_cols,
|
|
}
|