Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PAdA5ThqmtVSsbzjusk1cJ
91 lines
2.9 KiB
Python
91 lines
2.9 KiB
Python
# -*- 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()
|