feat: add report_date to monitoring sessions and update related functionality

fix: chart properly renders centered
This commit is contained in:
2026-03-27 22:18:50 +00:00
parent 95fedca8c9
commit 49bc625c1a
5 changed files with 192 additions and 62 deletions

View File

@@ -1159,7 +1159,7 @@ async def get_project_sessions(
if session.period_start_hour is not None and session.period_end_hour is not None and session.started_at:
from datetime import date as _date
local_start = utc_to_local(session.started_at)
start_day = local_start.date()
start_day = session.report_date if session.report_date else local_start.date()
sh = session.period_start_hour
eh = session.period_end_hour
@@ -1259,10 +1259,11 @@ async def get_sessions_calendar(
# Build calendar grid (MonSun weeks)
first_day = _date(year, month, 1)
last_day = _date(year, month, monthrange(year, month)[1])
# Start on Monday before first_day
grid_start = first_day - _td(days=first_day.weekday())
# End on Sunday after last_day
days_after = 6 - last_day.weekday()
# Start on Sunday before first_day (isoweekday: Mon=1 … Sun=7; weekday: Mon=0 … Sun=6)
days_before = (first_day.isoweekday() % 7) # Sun=0, Mon=1, …, Sat=6
grid_start = first_day - _td(days=days_before)
# End on Saturday after last_day
days_after = 6 - (last_day.isoweekday() % 7)
grid_end = last_day + _td(days=days_after)
weeks = []
@@ -2061,6 +2062,17 @@ async def patch_session(
except (ValueError, TypeError):
raise HTTPException(status_code=400, detail=f"{field} must be an integer 023 or null")
if "report_date" in data:
val = data["report_date"]
if val is None or val == "":
session.report_date = None
else:
try:
from datetime import date as _date
session.report_date = _date.fromisoformat(str(val))
except ValueError:
raise HTTPException(status_code=400, detail="Invalid report_date format. Use YYYY-MM-DD.")
db.commit()
return JSONResponse({
"status": "success",
@@ -2068,6 +2080,7 @@ async def patch_session(
"period_type": session.period_type,
"period_start_hour": session.period_start_hour,
"period_end_hour": session.period_end_hour,
"report_date": session.report_date.isoformat() if session.report_date else None,
})
@@ -2103,7 +2116,7 @@ async def view_session_detail(
effective_range = None
if session.period_start_hour is not None and session.period_end_hour is not None and session.started_at:
local_start = utc_to_local(session.started_at)
start_day = local_start.date()
start_day = session.report_date if session.report_date else local_start.date()
sh = session.period_start_hour
eh = session.period_end_hour
def _fmt_h(h):
@@ -2137,6 +2150,7 @@ async def view_session_detail(
"files": files,
"effective_range": effective_range,
"session_meta": session_meta,
"report_date": session.report_date.isoformat() if session.report_date else "",
})
@@ -2672,7 +2686,7 @@ async def generate_excel_report(
_plot_border.ln.solidFill = "000000"
_plot_border.ln.w = 12700
chart.plot_area.spPr = _plot_border
ws.add_chart(chart, "H4")
ws.add_chart(chart, "I4")
# --- Stats table: note at I28-I29, headers at I31, data rows 32-34 ---
note1 = ws.cell(row=28, column=9, value="Note: Averages are calculated by determining the arithmetic average ")
@@ -3160,7 +3174,7 @@ async def generate_report_from_preview(
_plot_border.ln.solidFill = "000000"
_plot_border.ln.w = 12700
chart.plot_area.spPr = _plot_border
ws.add_chart(chart, "H4")
ws.add_chart(chart, "I4")
# --- Stats block starting at I28 ---
# Stats table: note at I28-I29, headers at I31, data rows 32-34, border row 35
@@ -3508,7 +3522,7 @@ async def generate_combined_excel_report(
_plot_border.ln.solidFill = "000000"
_plot_border.ln.w = 12700
chart.plot_area.spPr = _plot_border
ws.add_chart(chart, "H4")
ws.add_chart(chart, "I4")
# Stats table: note at I28-I29, headers at I31, data rows 32-34, border row 35
note1 = ws.cell(row=28, column=9, value="Note: Averages are calculated by determining the arithmetic average ")
@@ -3751,6 +3765,7 @@ def _build_location_data_from_sessions(project_id: str, db, selected_session_ids
"period_start_hour": session.period_start_hour,
"period_end_hour": session.period_end_hour,
"started_at": session.started_at,
"report_date": session.report_date,
"rows": [],
}
@@ -3807,10 +3822,13 @@ def _build_location_data_from_sessions(project_id: str, db, selected_session_ids
if is_day_session:
# Day-style: start_h <= hour < end_h, restricted to the LAST calendar date
in_window = lambda h: sh <= h < eh
daytime_dates = sorted({
dt.date() for dt, row in parsed if dt and in_window(dt.hour)
})
target_date = daytime_dates[-1] if daytime_dates else None
if entry.get("report_date"):
target_date = entry["report_date"]
else:
daytime_dates = sorted({
dt.date() for dt, row in parsed if dt and in_window(dt.hour)
})
target_date = daytime_dates[-1] if daytime_dates else None
filtered = [
(dt, row) for dt, row in parsed
if dt and dt.date() == target_date and in_window(dt.hour)
@@ -4101,7 +4119,7 @@ async def generate_combined_from_preview(
_plot_border.ln.solidFill = "000000"
_plot_border.ln.w = 12700
chart.plot_area.spPr = _plot_border
ws.add_chart(chart, "H4")
ws.add_chart(chart, "I4")
hdr_fill_tbl = PatternFill(start_color="F2F2F2", end_color="F2F2F2", fill_type="solid")