Files
site/WESP_REL/app/routes/analytics.py
T
2026-07-17 12:57:18 +03:00

146 lines
4.9 KiB
Python

from flask import Blueprint, Response, jsonify, request
from app.routes.auth_decorators import require_auth
from app.services.analytics.export_sections import export_filename_base, parse_export_sections
from app.services.analytics.finance_summary import build_finance_summary
from app.services.analytics.pdf_export import build_analytics_pdf
from app.services.analytics.plan_fact_layers import build_plan_fact_rows
from app.services.analytics.stock_forecast import build_stock_forecast
from app.services.analytics.xlsx_summary import build_finance_summary_xlsx
bp = Blueprint("analytics", __name__, url_prefix="/api/analytics")
def _error(message: str, status_code: int = 400):
return jsonify({"error": True, "message": message}), status_code
def _export_params():
date_from = (request.args.get("date_from") or "").strip()
date_to = (request.args.get("date_to") or "").strip()
if not date_from or not date_to:
return None, None, None, None, _error("Укажите date_from и date_to (YYYY-MM-DD)", 400)
recipe_id = (request.args.get("recipe_id") or "").strip() or None
recipe_ids = (request.args.get("recipe_ids") or "").strip() or None
return date_from, date_to, recipe_id, recipe_ids, None
@bp.get("/finance")
@require_auth
def finance_summary():
return jsonify(
build_finance_summary(
date_from=request.args.get("date_from"),
date_to=request.args.get("date_to"),
recipe_id=(request.args.get("recipe_id") or "").strip() or None,
recipe_ids=(request.args.get("recipe_ids") or "").strip() or None,
)
)
@bp.get("/plan-fact")
@require_auth
def plan_fact():
return jsonify(
build_plan_fact_rows(
date_from=request.args.get("date_from"),
date_to=request.args.get("date_to"),
recipe_id=(request.args.get("recipe_id") or "").strip() or None,
recipe_ids=(request.args.get("recipe_ids") or "").strip() or None,
client_id=(request.args.get("client_id") or "").strip() or None,
)
)
@bp.get("/stock-forecast")
@require_auth
def stock_forecast():
from app.models import Component
return jsonify(
build_stock_forecast(
plan_date=request.args.get("plan_date"),
Component=Component,
)
)
def _filter_context_kwargs():
return {
"filter_farms": (request.args.get("filter_farms") or "").strip() or None,
"filter_dispensers": (request.args.get("filter_dispensers") or "").strip() or None,
"filter_recipes": (request.args.get("filter_recipes") or "").strip() or None,
}
@bp.get("/export")
@require_auth
def analytics_export():
date_from, date_to, recipe_id, recipe_ids, err = _export_params()
if err:
return err
fmt = (request.args.get("format") or "xlsx").strip().lower()
section = (request.args.get("section") or "all").strip().lower()
sections = parse_export_sections(section)
base_name = export_filename_base(
date_from=date_from, date_to=date_to, sections=sections
)
ctx = _filter_context_kwargs()
if fmt == "pdf":
data = build_analytics_pdf(
date_from=date_from,
date_to=date_to,
recipe_id=recipe_id,
recipe_ids=recipe_ids,
section=section,
**ctx,
)
return Response(
data,
mimetype="application/pdf",
headers={
"Content-Disposition": f'attachment; filename="{base_name}.pdf"'
},
)
if fmt in ("xlsx", "excel"):
data = build_finance_summary_xlsx(
date_from=date_from,
date_to=date_to,
recipe_id=recipe_id,
recipe_ids=recipe_ids,
section=section,
**ctx,
)
return Response(
data,
mimetype="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
headers={
"Content-Disposition": f'attachment; filename="{base_name}.xlsx"'
},
)
return _error("format должен быть xlsx или pdf", 400)
@bp.get("/finance/export")
@require_auth
def finance_export():
date_from, date_to, recipe_id, recipe_ids, err = _export_params()
if err:
return err
section = (request.args.get("section") or "all").strip().lower()
sections = parse_export_sections(section)
data = build_finance_summary_xlsx(
date_from=date_from,
date_to=date_to,
recipe_id=recipe_id,
recipe_ids=recipe_ids,
section=section,
**_filter_context_kwargs(),
)
filename = f"{export_filename_base(date_from=date_from, date_to=date_to, sections=sections)}.xlsx"
return Response(
data,
mimetype="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
headers={"Content-Disposition": f'attachment; filename="{filename}"'},
)