feat(master_data): 재료_시중물가 — 다산소프트 EST 2026-07 자재 23,980줄(개발용 · 배포 전 판권 구매)
- 값 묶음 채택·가격정보·물가자료·유통물가·물가정보·거래가격·견적가 · 면수 묶음 · 0 은 null - 원문 이름 「시중물가」 — _틀.md 2장 · check_master BOOKS - 옮기는 스크립트 build_재료_시중물가.py — 원본 대조(줄 수 · 출처별 합 · 표본 50줄) 포함 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JgUhN55Z3BCYhUJTjwTNfj
This commit is contained in:
@@ -12,7 +12,7 @@
|
||||
|
||||
- 이름 = `그룹_원문[_장].json` — 날짜 없음 · 마스터는 항상 최신. 예: `인력_건설노임.json` · `소요량_산림품셈_13장.json` · `로직_산림품셈_13장.json`
|
||||
- 그룹 = 인력 · 재료 · 기계 · 소요량 · 계수 · 환율 · 요율 · 로직
|
||||
- 원문 이름 = 산림품셈 · 건설품셈 · 건설노임 · 제조노임 · 나라장터자재 · 오피넷유가 · 한국은행환율 · 조달청제비율 · 자체
|
||||
- 원문 이름 = 산림품셈 · 건설품셈 · 건설노임 · 제조노임 · 나라장터자재 · 오피넷유가 · 시중물가 · 한국은행환율 · 조달청제비율 · 자체
|
||||
- UTF-8 · LF · 들여쓰기 2칸 · 칸 이름은 한글.
|
||||
|
||||
## 3. 출처
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
"""상용 적산 자료(ESTX 2026-07) 자재 → 재료_시중물가.json — 개발용 · 배포 전 판권 구매 뒤 갱신.
|
||||
|
||||
ESTX 자재 표 = StuffcDat(칸 뜻: 다산소프트/ESTX_값사전_자재노무기계.md).
|
||||
TC = 채택 · Cost1..6 = 출처 여섯 · Page1..6 = 면수.
|
||||
0 · 미저장 = 값 없음(null). 이름·규격은 원문 그대로(띄어쓰기·오자 포함). 코드 없는 빈 줄은 뺌.
|
||||
ESTX 에 대·중분류 칸이 없어 분류는 두지 않음.
|
||||
|
||||
쓰기: ./venv/Scripts/python.exe resources/master_data/scripts/build_재료_시중물가.py
|
||||
쓴 뒤 원본과 대조.
|
||||
"""
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import math
|
||||
import random
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).parent))
|
||||
from _migrate_base import dump_master # noqa: E402
|
||||
from compare_estx import ESTX, ROOT, SLOTS, Estx # noqa: E402
|
||||
|
||||
OUT = ROOT / "resources/master_data/재료_시중물가.json"
|
||||
|
||||
|
||||
def num(v):
|
||||
if not v:
|
||||
return None
|
||||
return int(v) if float(v).is_integer() else v
|
||||
|
||||
|
||||
def build(rows: list[dict]) -> list[dict]:
|
||||
out = []
|
||||
for r in sorted(rows, key=lambda r: r["Index"]):
|
||||
code = r.get("Code")
|
||||
if not code:
|
||||
continue
|
||||
price = {"채택": num(r.get("TC"))}
|
||||
pages = {}
|
||||
for i, slot in enumerate(SLOTS, 1):
|
||||
price[slot] = num(r.get(f"Cost{i}"))
|
||||
pages[slot] = r.get(f"Page{i}") or None
|
||||
out.append(
|
||||
{
|
||||
"열쇠": code,
|
||||
"이름": r.get("Name", ""),
|
||||
"규격": r.get("Size", ""),
|
||||
"단위": r.get("Unite", ""),
|
||||
"값": price,
|
||||
"면수": pages,
|
||||
"출처": f"시중물가 {code}",
|
||||
}
|
||||
)
|
||||
return out
|
||||
|
||||
|
||||
def check(rows: list[dict]) -> None:
|
||||
"""원본 대조 — 줄 수 · 출처별 값 합 · 표본 쉰 줄."""
|
||||
data = json.loads(OUT.read_text(encoding="utf-8"))
|
||||
got = {r["열쇠"]: r for r in data["줄"]}
|
||||
raw = {r["Code"]: r for r in rows if r.get("Code")}
|
||||
assert len(got) == len(data["줄"]) == len(raw), (len(got), len(raw))
|
||||
print(
|
||||
f"줄 {len(got)} = 원본 코드 있는 줄 {len(raw)} (코드 없는 빈 줄 {len(rows) - len(raw)} 뺌)"
|
||||
)
|
||||
for i, slot in enumerate(["채택", *SLOTS]):
|
||||
col = "TC" if i == 0 else f"Cost{i}"
|
||||
a = math.fsum(r.get(col) or 0 for r in raw.values())
|
||||
b = math.fsum(r["값"][slot] or 0 for r in got.values())
|
||||
n = sum(1 for r in got.values() if r["값"][slot] is not None)
|
||||
assert abs(a - b) < 1e-3, (slot, a, b)
|
||||
print(f" {slot}: 값 {n}줄 · 합 {b:,.1f} = 원본 {a:,.1f}")
|
||||
random.seed(20260719)
|
||||
for code in random.sample(sorted(raw), 50):
|
||||
r, g = raw[code], got[code]
|
||||
assert (g["이름"], g["규격"], g["단위"]) == (
|
||||
r.get("Name", ""),
|
||||
r.get("Size", ""),
|
||||
r.get("Unite", ""),
|
||||
)
|
||||
assert (g["값"]["채택"] or 0) == r.get("TC", 0)
|
||||
for i, slot in enumerate(SLOTS, 1):
|
||||
assert (g["값"][slot] or 0) == (r.get(f"Cost{i}") or 0), (code, slot)
|
||||
assert g["면수"][slot] == (r.get(f"Page{i}") or None), (code, slot)
|
||||
print(" 표본 50줄 이름·규격·단위·값 7·면수 6 같음")
|
||||
|
||||
|
||||
def main():
|
||||
rows = Estx().table("StuffcDat")
|
||||
head = {
|
||||
"그룹": "재료",
|
||||
"원문": "시중물가",
|
||||
"판": "2026-07",
|
||||
"원천": [
|
||||
{
|
||||
"경로": ESTX.relative_to(ROOT).as_posix(),
|
||||
"해시": hashlib.sha256(ESTX.read_bytes()).hexdigest(),
|
||||
"역할": "primary",
|
||||
}
|
||||
],
|
||||
"비고": ["다산소프트 EST 2026-07 자재 · 개발용 · 배포 전 판권 구매"],
|
||||
}
|
||||
dump_master(OUT, head, build(rows))
|
||||
check(rows)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -36,6 +36,7 @@ BOOKS = (
|
||||
"제조노임",
|
||||
"나라장터자재",
|
||||
"오피넷유가",
|
||||
"시중물가",
|
||||
"한국은행환율",
|
||||
"조달청제비율",
|
||||
"자체",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user