160 lines
5.9 KiB
Python
160 lines
5.9 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""PRJLST.SMT [n_KANJUB]·[KANJUB_ADD] 키 → 원가계산서(제잡비) 계산 설정 (kanjub_cfg.py).
|
|
|
|
설정 = 원본 저장키 그대로(keys · 차수 접두 뗌) + 다른 화면이 쓰는 옛 칸(rates·fixed·scheme·anjunAuto 등).
|
|
되돌려 쓰기 = smt_updates(cfg, slot) — 키 왕복(F2-58).
|
|
근거: 지식DB STmate/old/20_분석 12 §10(선택축) · 20 §2(KAN_ORD) · 25 §1(저장키 241종)
|
|
· REA 18(D_ 고정 · 추가금액 키 꼴 ADD_AMT_g_ii_n) · REA 20(JAB_TYPE 계산 분류 · CAL_ACTL 실적).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
# 원본 저장키 몸통 → 옛 항목코드(화면·다른 계산 모듈이 쓰는 이름)
|
|
CODE_OF = {"T_KITA": "KITA", "EQIPSU": "EQIP"}
|
|
KEY_OF = {v: k for k, v in CODE_OF.items()}
|
|
REV_KEYS = (
|
|
"KANNO",
|
|
"SANBO",
|
|
"KOBO",
|
|
"KUNBO",
|
|
"SLVBO",
|
|
"YUNBO",
|
|
"TBUGUM",
|
|
"ANJUN",
|
|
"KITA",
|
|
"HWAN",
|
|
"EQIP",
|
|
)
|
|
# 차수와 무관한 공통 키(JAB_TYPE 계산 분류 · CAL_ACTL 실적 · VIS_TOTL 총괄표시)
|
|
GLOBAL_KEYS = ("JAB_TYPE", "CAL_ACTL", "VIS_TOTL")
|
|
# 간접비 순서 코드표 기본값(Start8x.Ini · 20번 §2.1)
|
|
KAN_ORD = {
|
|
1: ";301;302;303;310;304;305;306;312;313;321;307;308;309;311;361;362;363;364;365;366;367;368;369;370;",
|
|
2: ";351;301;302;303;310;304;305;306;312;313;331;332;333;334;335;336;337;338;307;308;309;311;361;362;363;364;365;366;367;368;369;370;",
|
|
}
|
|
|
|
|
|
def _num(kv: dict, key: str, default: float = 0.0) -> float:
|
|
try:
|
|
s = str(kv.get(key, "")).strip().replace(",", "")
|
|
return float(s) if s else default
|
|
except ValueError:
|
|
return default
|
|
|
|
|
|
def _val(v):
|
|
"""숫자로 읽히면 숫자, 아니면 글자 그대로."""
|
|
s = str(v).strip()
|
|
try:
|
|
f = float(s.replace(",", ""))
|
|
return int(f) if f.is_integer() and "." not in s else f
|
|
except ValueError:
|
|
return s
|
|
|
|
|
|
def add_rows(kv: dict) -> list[dict]:
|
|
"""추가금액 행 — ADD_CNT_g(묶음 1~4) · ADD_NAME/UNIT/BIGO_g_ii · ADD_AMT_g_ii_1~5(차수 칸) · ADD_BUGA(묶음2) · ADD_ADDT(묶음1)."""
|
|
out = []
|
|
for g in range(1, 5):
|
|
for i in range(1, int(_num(kv, f"ADD_CNT_{g}")) + 1):
|
|
row = f"{g}_{i:02d}"
|
|
out.append(
|
|
{
|
|
"group": g,
|
|
"name": kv.get(f"ADD_NAME_{row}", ""),
|
|
"unit": kv.get(f"ADD_UNIT_{row}", ""),
|
|
"bigo": kv.get(f"ADD_BIGO_{row}", ""),
|
|
"amts": [_num(kv, f"ADD_AMT_{row}_{s}") for s in range(1, 6)],
|
|
"vat": _num(kv, f"ADD_BUGA_{row}") == 1,
|
|
"addt": int(_num(kv, f"ADD_ADDT_{row}")),
|
|
}
|
|
)
|
|
return out
|
|
|
|
|
|
def add_amounts(kv: dict, slot: int = 1) -> list[dict]:
|
|
"""옛 칸 — 차수 slot 금액만 뽑은 추가금액 목록(stage = 묶음 1~4)."""
|
|
return [
|
|
{"stage": r["group"], "name": r["name"], "amount": r["amts"][slot - 1], "vat": r["vat"]}
|
|
for r in add_rows(kv)
|
|
]
|
|
|
|
|
|
def stage_slots(kv: dict) -> list[int]:
|
|
"""원가계산서가 저장된 차수 — [n_KANJUB] 묶음이 있는 차수."""
|
|
return [n for n in range(1, 5) if any(k.startswith(f"{n}_C_") for k in kv)] or [1]
|
|
|
|
|
|
def scheme_of(keys: dict) -> str:
|
|
"""4형식 — JAB_TYPE 3(수자원)·4(지역난방) = 수공, CAL_ACTL=1 = 실적(REA 18·20 · 12번 §2)."""
|
|
su = int(_num(keys, "JAB_TYPE")) in (3, 4)
|
|
actl = int(_num(keys, "CAL_ACTL")) == 1
|
|
return ("SA" if su else "TA") if actl else ("S" if su else "T")
|
|
|
|
|
|
def build_kanjub_config(kv: dict, slot: int = 1) -> dict:
|
|
p = f"{slot}_"
|
|
keys = {k[len(p) :]: _val(v) for k, v in kv.items() if k.startswith(p)}
|
|
keys.update({k: _val(kv[k]) for k in GLOBAL_KEYS if k in kv})
|
|
rates = {
|
|
CODE_OF.get(k[2:], k[2:]): float(_val(v) or 0)
|
|
for k, v in keys.items()
|
|
if k.startswith("R_") and isinstance(_val(v), (int, float))
|
|
}
|
|
fixed = {
|
|
CODE_OF.get(k[2:], k[2:]): _num(keys, "C_" + k[2:])
|
|
for k in keys
|
|
if k.startswith("D_") and _num(keys, k) == 1
|
|
}
|
|
return {
|
|
"slot": slot,
|
|
"scheme": scheme_of(keys),
|
|
"keys": keys,
|
|
"rates": rates,
|
|
"fixed": fixed,
|
|
"revModes": {k: "recalculated" for k in REV_KEYS},
|
|
"anjunAuto": int(_num(keys, "I_ANJUNAUTO")),
|
|
"anjunBaseAdd": _num(keys, "C_ANJUN_G"),
|
|
"addRows": add_rows(kv),
|
|
"addAmounts": add_amounts(kv, slot),
|
|
"kanOrd": dict(KAN_ORD),
|
|
}
|
|
|
|
|
|
def smt_updates(cfg: dict, slot: int | None = None, keys_out: dict | None = None) -> dict:
|
|
"""설정(+계산 결과 키) → PRJLST.SMT 갱신 사전(n_KEY · 공통 키 · ADD_*) — 저장 때 server.save 의 smt_updates 로 넘김."""
|
|
n = slot or int(cfg.get("slot", 1))
|
|
keys = dict(cfg.get("keys") or {})
|
|
for code, r in (cfg.get("rates") or {}).items():
|
|
keys["R_" + KEY_OF.get(code, code)] = r
|
|
if cfg.get("anjunAuto") is not None:
|
|
keys["I_ANJUNAUTO"] = cfg["anjunAuto"]
|
|
keys.update(keys_out or {})
|
|
out = {}
|
|
for k, v in keys.items():
|
|
out[k if k in GLOBAL_KEYS else f"{n}_{k}"] = _fmt(v)
|
|
rows = cfg.get("addRows") or []
|
|
for g in range(1, 5):
|
|
mine = [r for r in rows if int(r.get("group", 0)) == g]
|
|
out[f"ADD_CNT_{g}"] = str(len(mine))
|
|
for i, r in enumerate(mine, 1):
|
|
row = f"{g}_{i:02d}"
|
|
out[f"ADD_NAME_{row}"] = r.get("name", "")
|
|
out[f"ADD_UNIT_{row}"] = r.get("unit", "")
|
|
out[f"ADD_BIGO_{row}"] = r.get("bigo", "")
|
|
for s, a in enumerate((list(r.get("amts") or []) + [0] * 5)[:5], 1):
|
|
out[f"ADD_AMT_{row}_{s}"] = _fmt(a)
|
|
if g == 2:
|
|
out[f"ADD_BUGA_{row}"] = "1" if r.get("vat") else "0"
|
|
if g == 1:
|
|
out[f"ADD_ADDT_{row}"] = str(int(r.get("addt") or 0))
|
|
return out
|
|
|
|
|
|
def _fmt(v) -> str:
|
|
if isinstance(v, bool):
|
|
return "1" if v else "0"
|
|
if isinstance(v, float) and v.is_integer():
|
|
return str(int(v))
|
|
return str(v)
|