103 lines
3.5 KiB
Python
103 lines
3.5 KiB
Python
"""
|
|
routes/admin_reports.py — Shift detail, unchecked, and summary reports.
|
|
"""
|
|
|
|
import logging
|
|
import io
|
|
import csv
|
|
from datetime import date, timedelta
|
|
from flask import Blueprint, render_template, request, send_file, Response
|
|
from models import (
|
|
get_shift_report, get_unchecked_report, get_summary_report,
|
|
get_report_filter_options,
|
|
)
|
|
from utils.decorators import admin_required
|
|
|
|
logger = logging.getLogger("routes.admin_reports")
|
|
admin_reports_bp = Blueprint("admin_reports", __name__, url_prefix="/admin/reports")
|
|
|
|
|
|
def _today():
|
|
return date.today()
|
|
|
|
|
|
@admin_reports_bp.route("/")
|
|
@admin_required
|
|
def reports():
|
|
tab = request.args.get("tab", "detail")
|
|
date_from = request.args.get("date_from") or str(_today() - timedelta(days=30))
|
|
date_to = request.args.get("date_to") or str(_today())
|
|
user_id = request.args.get("user_id")
|
|
website_id = request.args.get("website_id")
|
|
target_date = request.args.get("target_date") or str(_today())
|
|
|
|
users, websites = get_report_filter_options()
|
|
|
|
rows = []
|
|
try:
|
|
if tab == "detail":
|
|
rows = get_shift_report(
|
|
date_from=date_from, date_to=date_to,
|
|
user_id=int(user_id) if user_id else None,
|
|
website_id=int(website_id) if website_id else None,
|
|
)
|
|
elif tab == "unchecked":
|
|
rows = get_unchecked_report(
|
|
target_date=target_date,
|
|
user_id=int(user_id) if user_id else None,
|
|
)
|
|
elif tab == "summary":
|
|
rows = get_summary_report(date_from=date_from, date_to=date_to)
|
|
except Exception as e:
|
|
logger.error(f"Report query error: {e}")
|
|
|
|
return render_template("admin/reports.html",
|
|
tab=tab, rows=rows,
|
|
users=users, websites=websites,
|
|
date_from=date_from, date_to=date_to,
|
|
target_date=target_date,
|
|
user_id=user_id, website_id=website_id)
|
|
|
|
|
|
@admin_reports_bp.route("/export/csv")
|
|
@admin_required
|
|
def export_csv():
|
|
tab = request.args.get("tab", "detail")
|
|
date_from = request.args.get("date_from") or str(_today() - timedelta(days=30))
|
|
date_to = request.args.get("date_to") or str(_today())
|
|
user_id = request.args.get("user_id")
|
|
website_id = request.args.get("website_id")
|
|
target_date = request.args.get("target_date") or str(_today())
|
|
|
|
try:
|
|
if tab == "detail":
|
|
rows = get_shift_report(
|
|
date_from=date_from, date_to=date_to,
|
|
user_id=int(user_id) if user_id else None,
|
|
website_id=int(website_id) if website_id else None,
|
|
)
|
|
elif tab == "unchecked":
|
|
rows = get_unchecked_report(
|
|
target_date=target_date,
|
|
user_id=int(user_id) if user_id else None,
|
|
)
|
|
else:
|
|
rows = get_summary_report(date_from=date_from, date_to=date_to)
|
|
except Exception as e:
|
|
logger.error(f"CSV export error: {e}")
|
|
rows = []
|
|
|
|
output = io.StringIO()
|
|
writer = csv.DictWriter(output, fieldnames=rows[0].keys() if rows else [],
|
|
extrasaction="ignore")
|
|
writer.writeheader()
|
|
for row in rows:
|
|
writer.writerow({k: str(v) if v is not None else "" for k, v in row.items()})
|
|
|
|
output.seek(0)
|
|
return Response(
|
|
output.getvalue(),
|
|
mimetype="text/csv",
|
|
headers={"Content-Disposition": f"attachment; filename=report_{tab}_{date_to}.csv"},
|
|
)
|