Watch
1
0
Fork
You've already forked Seyyed_arc
0
forked from hesabix/arc
Seyyed_arc/hesabixAPI/adapters/api/v1/admin/fx_providers.py

164 lines
5 KiB
Python

from __future__ import annotations
from typing import Any, Dict, Optional
from fastapi import APIRouter, Body, Depends, Path, Query, Request
from sqlalchemy.orm import Session
from adapters.db.session import get_db
from app.core.auth_dependency import AuthContext, get_current_user
from app.core.responses import ApiError, format_datetime_fields, success_response
from app.services.fx_rate_provider_service import (
fetch_and_store_provider,
get_provider_by_code,
list_global_rates,
list_providers,
test_provider_connection,
upsert_provider,
)
router = APIRouter(prefix="/admin/fx-providers", tags=["admin-fx-providers", "مدیریت"])
def _require_admin(ctx: AuthContext) -> None:
if not ctx.has_app_permission("system_settings"):
raise ApiError("FORBIDDEN", "فقط مدیر سیستم می‌تواند ارائه‌دهندگان نرخ را مدیریت کند", http_status=403)
@router.get("", summary="لیست ارائه‌دهندگان نرخ ارز")
def admin_list_fx_providers(
request: Request,
db: Session = Depends(get_db),
ctx: AuthContext = Depends(get_current_user),
) -> dict:
_require_admin(ctx)
items = list_providers(db)
return success_response(
data=format_datetime_fields({"items": items}, request),
request=request,
message="FX_PROVIDERS_LIST",
)
@router.get("/global-rates", summary="اسنپ‌شات مرکزی نرخ‌ها")
def admin_list_fx_global_rates(
request: Request,
provider_code: Optional[str] = Query(None),
currency_code: Optional[str] = Query(None),
db: Session = Depends(get_db),
ctx: AuthContext = Depends(get_current_user),
) -> dict:
_require_admin(ctx)
items = list_global_rates(db, provider_code=provider_code, currency_code=currency_code)
return success_response(
data=format_datetime_fields({"items": items, "total": len(items)}, request),
request=request,
message="FX_GLOBAL_RATES_LIST",
)
@router.put("/{code}", summary="ایجاد/ویرایش ارائه‌دهنده نرخ")
def admin_upsert_fx_provider(
request: Request,
code: str = Path(..., description="کد ارائه‌دهنده مثل brsapi"),
body: Dict[str, Any] = Body(...),
db: Session = Depends(get_db),
ctx: AuthContext = Depends(get_current_user),
) -> dict:
_require_admin(ctx)
row = upsert_provider(db, code, body)
db.commit()
return success_response(
data=format_datetime_fields(row, request),
request=request,
message="FX_PROVIDER_SAVED",
)
@router.post("/{code}/test", summary="تست اتصال و ذخیره اسنپ‌شات")
def admin_test_fx_provider(
request: Request,
code: str = Path(...),
db: Session = Depends(get_db),
ctx: AuthContext = Depends(get_current_user),
) -> dict:
_require_admin(ctx)
provider = get_provider_by_code(db, code)
try:
result = test_provider_connection(db, provider)
db.commit()
except ApiError:
# وضعیت last_fetch_* قبل از raise flush شده؛ commit تا در UI دیده شود
db.commit()
raise
return success_response(
data=format_datetime_fields(result, request),
request=request,
message="FX_PROVIDER_TEST_OK",
)
@router.post("/{code}/fetch-now", summary="واکشی فوری نرخ‌ها")
def admin_fetch_fx_provider_now(
request: Request,
code: str = Path(...),
db: Session = Depends(get_db),
ctx: AuthContext = Depends(get_current_user),
) -> dict:
_require_admin(ctx)
provider = get_provider_by_code(db, code)
try:
result = fetch_and_store_provider(db, provider)
db.commit()
except ApiError:
db.commit()
raise
return success_response(
data=format_datetime_fields(result, request),
request=request,
message="FX_PROVIDER_FETCHED",
)
@router.get("/data-health/{business_id}", summary="سلامت داده چندارزی یک کسب‌وکار")
def admin_fx_data_health(
request: Request,
business_id: int = Path(...),
db: Session = Depends(get_db),
ctx: AuthContext = Depends(get_current_user),
) -> dict:
_require_admin(ctx)
from app.services.fx_data_health_service import get_fx_data_health
data = get_fx_data_health(db, business_id)
return success_response(data=data, request=request, message="FX_DATA_HEALTH")
@router.post("/data-health/{business_id}/backfill-base", summary="Backfill خطوط *_base (dry-run پیش‌فرض)")
def admin_fx_backfill_base(
request: Request,
business_id: int = Path(...),
body: Dict[str, Any] = Body(default={}),
db: Session = Depends(get_db),
ctx: AuthContext = Depends(get_current_user),
) -> dict:
_require_admin(ctx)
from app.services.fx_data_health_service import run_fx_base_backfill
dry_run = bool((body or {}).get("dry_run", True))
allow_infer = bool((body or {}).get("allow_infer", False))
only_with_fx = bool((body or {}).get("only_with_fx_snapshot", True))
max_docs = (body or {}).get("max_documents", 200)
try:
max_docs_i = int(max_docs) if max_docs is not None else None
except Exception:
max_docs_i = 200
data = run_fx_base_backfill(
db,
business_id,
dry_run=dry_run,
only_with_fx_snapshot=only_with_fx,
allow_infer=allow_infer,
max_documents=max_docs_i,
)
return success_response(data=data, request=request, message="FX_BACKFILL_BASE")