""" Exchange Rate API - 환율 정보 조회 (한국수출입은행 API 연동) """ from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.orm import Session from pydantic import BaseModel from typing import Optional, List from datetime import datetime from ..database import get_db from ..models.exchange_rate import ExchangeRate, ExchangeRateHistory from ..models.user import User from .auth import get_current_admin_user from ..services.exchange_rate_service import ( update_exchange_rates, get_all_exchange_rates, convert_krw_to_currency, SUPPORTED_CURRENCIES ) router = APIRouter(prefix="/api/exchange-rate", tags=["Exchange Rate"]) class ExchangeRateData(BaseModel): currency_code: str currency_name: str symbol: str deal_base_rate: float # 매매기준율 (1 USD = X KRW) ttb_rate: float # 전신환 받을때 tts_rate: float # 전신환 보낼때 weight_percent: float # 가중치 (%) adjusted_rate: float # 가중치 적용 환율 source_date: str updated_at: str class ExchangeRatesResponse(BaseModel): base_currency: str rates: List[ExchangeRateData] source: str last_updated: str class ExchangeRateWeightUpdate(BaseModel): currency_code: str weight_percent: float class ConvertRequest(BaseModel): amount: float from_currency: str = "KRW" to_currency: str class ConvertResponse(BaseModel): original_amount: float from_currency: str converted_amount: float to_currency: str rate_used: float @router.get("", response_model=ExchangeRatesResponse) async def get_exchange_rates(db: Session = Depends(get_db)): """환율 정보 조회""" rates = get_all_exchange_rates(db) # DB에 데이터가 없으면 업데이트 시도 if not rates: await update_exchange_rates(db) rates = get_all_exchange_rates(db) rate_list = [] for rate in rates: symbol = SUPPORTED_CURRENCIES.get(rate.currency_code, {}).get("symbol", "") rate_list.append(ExchangeRateData( currency_code=rate.currency_code, currency_name=rate.currency_name, symbol=symbol, deal_base_rate=rate.deal_base_rate, ttb_rate=rate.ttb_rate or rate.deal_base_rate, tts_rate=rate.tts_rate or rate.deal_base_rate, weight_percent=rate.weight_percent or 0.0, adjusted_rate=rate.adjusted_rate or rate.deal_base_rate, source_date=rate.source_date or "", updated_at=rate.updated_at.isoformat() if rate.updated_at else "" )) last_updated = "" if rates: latest = max(rates, key=lambda r: r.updated_at if r.updated_at else datetime.min) last_updated = latest.updated_at.isoformat() if latest.updated_at else "" return ExchangeRatesResponse( base_currency="KRW", rates=rate_list, source="koreaexim", last_updated=last_updated ) @router.get("/currency/{currency_code}") async def get_single_rate(currency_code: str, db: Session = Depends(get_db)): """특정 통화 환율 조회""" rate = db.query(ExchangeRate).filter( ExchangeRate.currency_code == currency_code.upper(), ExchangeRate.is_active == True ).first() if not rate: raise HTTPException(status_code=404, detail=f"Currency {currency_code} not found") symbol = SUPPORTED_CURRENCIES.get(rate.currency_code, {}).get("symbol", "") return { "currency_code": rate.currency_code, "currency_name": rate.currency_name, "symbol": symbol, "deal_base_rate": rate.deal_base_rate, "adjusted_rate": rate.adjusted_rate, "weight_percent": rate.weight_percent, "source_date": rate.source_date, "updated_at": rate.updated_at.isoformat() if rate.updated_at else None } @router.post("/convert", response_model=ConvertResponse) async def convert_currency( request: ConvertRequest, db: Session = Depends(get_db) ): """통화 변환""" if request.from_currency.upper() != "KRW": raise HTTPException(status_code=400, detail="Currently only KRW conversion is supported") converted = convert_krw_to_currency(db, request.amount, request.to_currency.upper()) if converted is None: raise HTTPException(status_code=404, detail=f"Currency {request.to_currency} not found") rate = db.query(ExchangeRate).filter( ExchangeRate.currency_code == request.to_currency.upper() ).first() return ConvertResponse( original_amount=request.amount, from_currency=request.from_currency.upper(), converted_amount=round(converted, 2), to_currency=request.to_currency.upper(), rate_used=rate.adjusted_rate if rate else 0 ) @router.get("/weights") async def get_exchange_rate_weights(db: Session = Depends(get_db)): """환율 가중치 설정 조회""" rates = get_all_exchange_rates(db) return { rate.currency_code.lower(): rate.weight_percent or 0.0 for rate in rates } @router.put("/weights/{currency_code}") async def update_exchange_rate_weight( currency_code: str, weight_percent: float, db: Session = Depends(get_db), current_user: User = Depends(get_current_admin_user) ): """환율 가중치 수정 (관리자 전용)""" rate = db.query(ExchangeRate).filter( ExchangeRate.currency_code == currency_code.upper() ).first() if not rate: raise HTTPException(status_code=404, detail=f"Currency {currency_code} not found") rate.weight_percent = weight_percent rate.adjusted_rate = rate.deal_base_rate * (1 + weight_percent / 100) db.commit() return { "message": "Weight updated successfully", "currency_code": rate.currency_code, "weight_percent": rate.weight_percent, "adjusted_rate": rate.adjusted_rate } @router.post("/refresh") async def refresh_exchange_rates( db: Session = Depends(get_db), current_user: User = Depends(get_current_admin_user) ): """환율 강제 갱신 (관리자 전용)""" result = await update_exchange_rates(db, force=True) return result @router.get("/history/{currency_code}") async def get_exchange_rate_history( currency_code: str, limit: int = 30, db: Session = Depends(get_db) ): """환율 변동 이력 조회""" history = db.query(ExchangeRateHistory).filter( ExchangeRateHistory.currency_code == currency_code.upper() ).order_by(ExchangeRateHistory.created_at.desc()).limit(limit).all() return [ { "currency_code": h.currency_code, "deal_base_rate": h.deal_base_rate, "source_date": h.source_date, "created_at": h.created_at.isoformat() if h.created_at else None } for h in history ] # 프론트엔드용 간단 API @router.get("/simple") async def get_simple_rates(db: Session = Depends(get_db)): """프론트엔드용 간단 환율 정보""" rates = get_all_exchange_rates(db) # DB에 데이터가 없으면 업데이트 시도 if not rates: await update_exchange_rates(db) rates = get_all_exchange_rates(db) result = {} for rate in rates: result[rate.currency_code] = { "rate": rate.adjusted_rate, # KRW per 1 unit (e.g., 1 USD = 1450 KRW) "symbol": SUPPORTED_CURRENCIES.get(rate.currency_code, {}).get("symbol", ""), "name": rate.currency_name } return result