diff --git a/resources/master_data/_갱신절차.md b/resources/master_data/_갱신절차.md index cda71a51..a399abdc 100644 --- a/resources/master_data/_갱신절차.md +++ b/resources/master_data/_갱신절차.md @@ -103,8 +103,8 @@ | 출처 | 한국은행환율 · `원가계산/환율_한국은행ECOS/환율_일별_*.csv` (ECOS 731Y001 · 5통화) | | 받는 법 | `collect_cost_sources.py values` (ECOS API) | | 주기 | 일별 · 견적 기준일마다 | -| 빌더 | 빌더 없음 (`scripts/_migrate_base.py` 는 옛 파일 한 번 옮기기) | -| 검사 | `check_master.py 틀 환율_한국은행환율.json` | +| 빌더 | `scripts/build_환율.py` (최신 일자 5통화 · `--check` 는 지금 JSON 과 비교만) | +| 검사 | `build_환율.py --check` · `check_master.py 틀 환율_한국은행환율.json` | ## 요율 (`요율_조달청제비율.json`) @@ -129,7 +129,7 @@ ## 구멍 목록 -- 환율 · 요율 · 품셈재료 · 로직 — 빌더 없음. +- 요율 · 품셈재료 · 로직 — 빌더 없음. - 기계 산림품셈 · 소요량 건설 건축·유지관리 · 소요량 산림 전 장 · 계수 건설 전 장 · 계수 산림 1장 밖 — 빌더 없음. - 자재품목 — 나라장터 스냅샷 → 마스터 줄 빌더 없음 · 유료 물가지 받는 길 미정. - 유가전력 — 휘발유·경유 새 판 반영 없음. diff --git a/resources/master_data/scripts/build_환율.py b/resources/master_data/scripts/build_환율.py new file mode 100644 index 00000000..a00f158f --- /dev/null +++ b/resources/master_data/scripts/build_환율.py @@ -0,0 +1,90 @@ +# -*- coding: utf-8 -*- +"""한국은행 ECOS 환율 일별 CSV → 환율_한국은행환율.json (테이블ID FX · 최신 일자 5통화). + +쓰기: ./venv/Scripts/python.exe resources/master_data/scripts/build_환율.py +비교: ./venv/Scripts/python.exe resources/master_data/scripts/build_환율.py --check (파일·대장 안 씀) +""" + +from __future__ import annotations + +import csv +import hashlib +import json +import sys +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).parent)) +import master_keys as mk # noqa: E402 +from _migrate_base import dump_master # noqa: E402 + +ROOT = Path(__file__).resolve().parents[3] +OUT = Path(__file__).resolve().parents[1] / "환율_한국은행환율.json" +CSV_DIR = ROOT / "resources/knowledge/original/원가계산/환율_한국은행ECOS" +NAMES = { # 항목코드 → (이름, 단위) + "0000001": ("USD", "원/USD"), + "0000002": ("JPY100", "원/JPY100"), + "0000003": ("EUR", "원/EUR"), + "0000012": ("GBP", "원/GBP"), + "0000053": ("CNY", "원/CNY"), +} + + +def build() -> tuple[Path, dict, list[dict], dict]: + path = sorted(CSV_DIR.glob("환율_일별_*.csv"))[-1] + last: dict[str, tuple[str, float]] = {} + with path.open(encoding="utf-8-sig", newline="") as f: + for r in csv.DictReader(f): + code, day, val = r["항목코드"], r["일자"], r["환율"] + if code in NAMES and val and (code not in last or day > last[code][0]): + last[code] = (day, float(val)) + day = max(d for d, _ in last.values()) + date = f"{day[:4]}-{day[4:6]}-{day[6:]}" + book = mk.load_book() + rows = [] + for code in sorted(NAMES): + name, unit = NAMES[code] + key = mk.issue(book, "FX", code, OUT.name) + rows.append( + { + "키": key, + "원문번호": code, + "구분": None, + "상세구분": None, + "이름": name, + "규격": date, + "단위": unit, + "값": last[code][1], + "출처": f"한국은행환율 {code}", + "비고": None, + } + ) + head = { + "그룹": "환율", + "원문": "한국은행환율", + "판": date, + "원천": [ + { + "경로": path.relative_to(ROOT).as_posix(), + "해시": hashlib.sha256(path.read_bytes()).hexdigest(), + "역할": "primary", + } + ], + "비고": ["규격 = 기준일 · 구분 · 상세구분은 두되 비움"], + } + return path, head, rows, book + + +def main() -> None: + _, head, rows, book = build() + if "--check" in sys.argv: + now = json.loads(OUT.read_text(encoding="utf-8")) + same = now["줄"] == rows and {k: now[k] for k in head} == head + print("같음" if same else "다름") + sys.exit(0 if same else 1) + mk.finish(book) + mk.save_book(book) + dump_master(OUT, head, rows) + + +if __name__ == "__main__": + main()