@@ -8,6 +8,7 @@ from datetime import UTC, datetime, timedelta
|
||||
from typing import Any
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||
from pydantic import BaseModel, Field
|
||||
from sqlalchemy import select
|
||||
|
||||
from app.core.database import session_scope
|
||||
@@ -15,6 +16,7 @@ from app.modules.sync.tenant import TenantContext, require_enterprise_zootech
|
||||
from app.modules.zootech.models import ZootechComponent
|
||||
from app.modules.zootech.report_models import ZootechFeedAlert, ZootechLoadingReport
|
||||
from app.modules.zootech.wesp_compat_reports import _parse_payload, _parse_report_time
|
||||
from app.modules.zootech import wesp_feed_quality_settings_service as fq_settings_service
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@@ -171,16 +173,6 @@ def analytics_finance_wesp(
|
||||
"topComponents": top_out,
|
||||
"reportCount": len(reports),
|
||||
}
|
||||
# #region agent log
|
||||
try:
|
||||
import pathlib
|
||||
_log_path = pathlib.Path("/Users/vlad/Documents/wesp new (1)/.cursor/debug-785e22.log")
|
||||
_log_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
with _log_path.open("a", encoding="utf-8") as _lf:
|
||||
_lf.write(json.dumps({"sessionId":"785e22","hypothesisId":"E","location":"wesp_compat_analytics.py:finance","message":"finance summary","data":{"date_from":date_from,"date_to":date_to,"report_count":len(reports),"underloadRub":result["underloadRub"],"top_count":len(top_out)},"timestamp":int(datetime.now(UTC).timestamp()*1000)}, ensure_ascii=False) + "\n")
|
||||
except Exception:
|
||||
pass
|
||||
# #endregion
|
||||
return result
|
||||
|
||||
|
||||
@@ -189,10 +181,73 @@ def analytics_plan_fact_wesp(
|
||||
enterprise_id: str = Query(...),
|
||||
date_from: str | None = Query(None),
|
||||
date_to: str | None = Query(None),
|
||||
recipe_id: str | None = Query(None),
|
||||
recipe_ids: str | None = Query(None),
|
||||
client_id: str | None = Query(None),
|
||||
tenant: TenantContext = Depends(require_enterprise_zootech),
|
||||
):
|
||||
_require_ent(enterprise_id, tenant)
|
||||
return {"items": []}
|
||||
from app.modules.zootech import wesp_analytics_service as analytics_service
|
||||
|
||||
return analytics_service.build_plan_fact_rows(
|
||||
enterprise_id,
|
||||
date_from=date_from,
|
||||
date_to=date_to,
|
||||
recipe_id=recipe_id,
|
||||
recipe_ids=recipe_ids,
|
||||
client_id=client_id,
|
||||
)
|
||||
|
||||
|
||||
@router.get("/analytics/stock-forecast")
|
||||
def analytics_stock_forecast_wesp(
|
||||
enterprise_id: str = Query(...),
|
||||
plan_date: str | None = Query(None),
|
||||
tenant: TenantContext = Depends(require_enterprise_zootech),
|
||||
):
|
||||
_require_ent(enterprise_id, tenant)
|
||||
from app.modules.zootech import wesp_analytics_service as analytics_service
|
||||
|
||||
return analytics_service.build_stock_forecast(enterprise_id, plan_date=plan_date)
|
||||
|
||||
|
||||
@router.get("/analytics/export")
|
||||
def analytics_export_wesp(
|
||||
enterprise_id: str = Query(...),
|
||||
date_from: str | None = Query(None),
|
||||
date_to: str | None = Query(None),
|
||||
fmt: str = Query("xlsx"),
|
||||
section: str = Query("all"),
|
||||
tenant: TenantContext = Depends(require_enterprise_zootech),
|
||||
):
|
||||
_require_ent(enterprise_id, tenant)
|
||||
if not date_from or not date_to:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail={"error": True, "message": "Укажите date_from и date_to (YYYY-MM-DD)"},
|
||||
)
|
||||
normalized_fmt = (fmt or "xlsx").strip().lower()
|
||||
if normalized_fmt not in ("xlsx", "excel", "pdf"):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail={"error": True, "message": "format должен быть xlsx или pdf"},
|
||||
)
|
||||
from app.modules.zootech import wesp_analytics_service as analytics_service
|
||||
|
||||
data, mime, filename = analytics_service.build_analytics_export(
|
||||
enterprise_id,
|
||||
date_from=date_from,
|
||||
date_to=date_to,
|
||||
fmt="pdf" if normalized_fmt == "pdf" else "xlsx",
|
||||
section=section,
|
||||
)
|
||||
from fastapi.responses import Response
|
||||
|
||||
return Response(
|
||||
content=data,
|
||||
media_type=mime,
|
||||
headers={"Content-Disposition": f'attachment; filename="{filename}"'},
|
||||
)
|
||||
|
||||
|
||||
def _parse_alert_payload_json(raw: str | None) -> dict[str, Any]:
|
||||
@@ -281,6 +336,37 @@ def _feed_alerts_for_range(
|
||||
return items[: max(1, min(limit, 500))]
|
||||
|
||||
|
||||
class FeedQualitySettingsBody(BaseModel):
|
||||
settings: dict[str, Any] = Field(default_factory=dict)
|
||||
|
||||
|
||||
@router.get("/feed-quality/settings")
|
||||
def feed_quality_settings_get_wesp(
|
||||
enterprise_id: str = Query(...),
|
||||
tenant: TenantContext = Depends(require_enterprise_zootech),
|
||||
):
|
||||
_require_ent(enterprise_id, tenant)
|
||||
return fq_settings_service.settings_for_api(enterprise_id)
|
||||
|
||||
|
||||
@router.put("/feed-quality/settings")
|
||||
def feed_quality_settings_put_wesp(
|
||||
body: FeedQualitySettingsBody,
|
||||
enterprise_id: str = Query(...),
|
||||
tenant: TenantContext = Depends(require_enterprise_zootech),
|
||||
):
|
||||
_require_ent(enterprise_id, tenant)
|
||||
partial = body.settings if isinstance(body.settings, dict) else {}
|
||||
try:
|
||||
saved = fq_settings_service.save_feed_quality_settings(enterprise_id, partial)
|
||||
except (TypeError, ValueError) as exc:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail={"error": True, "message": str(exc)},
|
||||
) from exc
|
||||
return {"saved": True, "settings": saved, "reevaluatedReports": 0}
|
||||
|
||||
|
||||
@router.get("/feed-quality/alerts/summary")
|
||||
def feed_quality_alerts_summary_wesp(
|
||||
enterprise_id: str = Query(...),
|
||||
|
||||
Reference in New Issue
Block a user