Files
Aislo/tools/stmate-test/conv_jb.py
T

112 lines
3.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""기준 제비율표 JB_* 43종 읽기(읽기 전용) — 설치 폴더 System\\ST_BSC\\*.JB_1·JB_M·JB_R·JB_RA.
근거: 10_System_186개_파일분석장부.md §4(배포파일 ↔ DBF 구조 ↔ 프로젝트 표) · 12번 §9(5행 묶음 · 열 1~5 간접노무 ·
6~10 기타경비 · 2020-05-27 확장 = 뒤에 15열 덧붙임) · 파일 이름 '2026(상_0413)_제비율.JB_R' = 기준일
판(edition): JB_1 41×10 · JB_M 25×10 · JB_R 구형 50×20 · JB_R 2020 확장 50×35 · JB_RA 50×20
프로젝트 짝: JB_1 → RATE.DBF · JB_M → RATE_M.DBF · JB_R → RATE_R.DBF · JB_RA → RATE_RA.DBF
"""
from __future__ import annotations
import pathlib
import re
from dbf_rw import DbfTable
JB_DIR = pathlib.Path(r"C:\경영정보(주)\System\ST_BSC")
TABLE_OF = {"JB_1": "RATE.DBF", "JB_M": "RATE_M.DBF", "JB_R": "RATE_R.DBF", "JB_RA": "RATE_RA.DBF"}
SHAPES = {"JB_1": {(41, 10)}, "JB_M": {(25, 10)}, "JB_R": {(50, 20), (50, 35)}, "JB_RA": {(50, 20)}}
def _num(s: str) -> float:
try:
return float(s.strip() or 0)
except ValueError:
return 0.0
def matrix_of(b: bytes) -> tuple[list[str], list[list[float]]]:
t = DbfTable(b)
return t.order, [[_num(t.get(i, f)) for f in t.order] for i in range(len(t))]
def base_date(name: str) -> str:
"""'2026(상_0413,표준시장)' → '2026-04-13' · 월일 없으면 연도만."""
m = re.match(r"^(\d{4})\([^_]*_?(\d{4})?", name)
if not m:
return ""
y, md = m.group(1), m.group(2)
return f"{y}-{md[:2]}-{md[2:]}" if md else y
def edition(kind: str, rows: int, cols: int) -> str:
if kind == "JB_R":
return "2020 확장(35열 · 국가유산 열)" if cols >= 35 else "구형(20열)"
return "단일판"
def read_jb(path) -> dict:
p = pathlib.Path(path)
kind = p.suffix.upper().lstrip(".")
fields, m = matrix_of(p.read_bytes())
shape = (len(m), len(fields))
return {
"name": p.name,
"path": str(p),
"kind": kind,
"table": TABLE_OF.get(kind, ""),
"date": base_date(p.stem),
"actual": "실적" in p.stem or "표준시장" in p.stem,
"rows": shape[0],
"cols": shape[1],
"edition": edition(kind, *shape),
"shape_ok": shape in SHAPES.get(kind, set()),
"fields": fields,
"matrix": m,
}
def list_jb(root: pathlib.Path | None = None) -> list[dict]:
"""설치 폴더 JB_* 전부(행렬 제외 요약) — 종류·기준일 차례."""
d = pathlib.Path(root or JB_DIR)
if not d.exists():
return []
out = []
for p in sorted(d.glob("*.JB_*")):
r = read_jb(p)
r.pop("matrix")
out.append(r)
return sorted(out, key=lambda r: (r["kind"], r["date"], r["name"]))
def match_project(files: dict, root: pathlib.Path | None = None) -> dict:
"""프로젝트 RATE*.DBF 마다 셀이 모두 같은 기준 JB 파일(없으면 가장 적게 다른 것과 다른 셀 수)."""
d = pathlib.Path(root or JB_DIR)
cands = [read_jb(p) for p in sorted(d.glob("*.JB_*"))] if d.exists() else []
out = {}
for kind, table in TABLE_OF.items():
if table not in files:
continue
_f, pm = matrix_of(files[table])
best = None
for c in (x for x in cands if x["kind"] == kind):
if len(c["matrix"]) != len(pm):
continue
diff = sum(
1
for a, b in zip(c["matrix"], pm)
for j in range(max(len(a), len(b)))
if abs((a[j] if j < len(a) else 0.0) - (b[j] if j < len(b) else 0.0)) > 1e-9
)
if best is None or diff < best[0]:
best = (diff, c["name"], c["date"])
if best:
out[table] = {
"jb": best[1],
"date": best[2],
"diff_cells": best[0],
"exact": best[0] == 0,
}
return out