Display bank analyzer timestamps in firm timezone

This commit is contained in:
A R R R Associates
2026-08-03 15:19:17 +05:30
parent b1ccb8d0d2
commit 4a5416d1ea
+54 -6
View File
@@ -1,9 +1,12 @@
from __future__ import annotations from __future__ import annotations
from datetime import datetime, timezone
from pathlib import Path from pathlib import Path
from zoneinfo import ZoneInfo, ZoneInfoNotFoundError
from fastapi import APIRouter, File, Form, Request, UploadFile from fastapi import APIRouter, File, Form, Request, UploadFile
from fastapi.responses import FileResponse, JSONResponse, RedirectResponse from fastapi.responses import FileResponse, JSONResponse, RedirectResponse
from sqlalchemy import select
from app.core.db.common import CommonSessionLocal from app.core.db.common import CommonSessionLocal
from app.core.http_responses import ui_access_denied, not_found_response from app.core.http_responses import ui_access_denied, not_found_response
@@ -18,6 +21,47 @@ from .service import can_use, create_job_folder, delete_owned_job, enqueue_job,
router = APIRouter(prefix="/tools/bank-statement-analyzer", tags=["bank-statement-analyzer-ui"]) router = APIRouter(prefix="/tools/bank-statement-analyzer", tags=["bank-statement-analyzer-ui"])
def _display_timezone_name(request: Request, db, user) -> str:
"""Resolve the active branch timezone, falling back to tenant and India defaults."""
from app.modules.core.tenancy.models import Branch, Tenant
branch_id = request.session.get("active_branch_id") or getattr(user, "branch_id", None)
tenant_id = request.session.get("active_tenant_id") or getattr(user, "tenant_id", None)
if branch_id not in (None, "", 0, "0"):
branch = db.scalar(select(Branch).where(Branch.id == int(branch_id)))
branch_timezone = (getattr(branch, "timezone", None) or "").strip() if branch else ""
if branch_timezone:
return branch_timezone
if tenant_id not in (None, "", 0, "0"):
tenant = db.scalar(select(Tenant).where(Tenant.id == int(tenant_id)))
tenant_timezone = (getattr(tenant, "default_timezone", None) or "").strip() if tenant else ""
if tenant_timezone:
return tenant_timezone
return "Asia/Kolkata"
def _format_local_datetime(value: datetime | None, timezone_name: str) -> str | None:
if value is None:
return None
try:
target_timezone = ZoneInfo(timezone_name)
except ZoneInfoNotFoundError:
target_timezone = ZoneInfo("Asia/Kolkata")
aware_value = value if value.tzinfo is not None else value.replace(tzinfo=timezone.utc)
return aware_value.astimezone(target_timezone).strftime("%d-%b-%Y %I:%M %p %Z")
def _localised_job_view(job, timezone_name: str) -> dict:
view = job_view(job)
view["submitted_at"] = _format_local_datetime(view.get("submitted_at"), timezone_name)
view["completed_at"] = _format_local_datetime(view.get("completed_at"), timezone_name)
view["expires_at"] = _format_local_datetime(view.get("expires_at"), timezone_name)
return view
def _ctx(request, db, user, **extra): def _ctx(request, db, user, **extra):
data = { data = {
"request": request, "request": request,
@@ -53,9 +97,11 @@ def index(request: Request, job: str | None = None):
user, roles, denied = _auth(request, db) user, roles, denied = _auth(request, db)
if denied: if denied:
return denied return denied
timezone_name = _display_timezone_name(request, db, user)
selected_job = get_owned_job(user.id, job) if job else None selected_job = get_owned_job(user.id, job) if job else None
recent = [job_view(item) for item in list_user_jobs(user.id, limit=8)] recent = [_localised_job_view(item, timezone_name) for item in list_user_jobs(user.id, limit=8)]
return templates.TemplateResponse("modules/bank_statement_analyzer/templates/bank_statement_analyzer/index.html", _ctx(request, db, user, error="", active_job=job_view(selected_job) if selected_job else None, recent_jobs=recent)) active_job = _localised_job_view(selected_job, timezone_name) if selected_job else None
return templates.TemplateResponse("modules/bank_statement_analyzer/templates/bank_statement_analyzer/index.html", _ctx(request, db, user, error="", active_job=active_job, recent_jobs=recent, display_timezone=timezone_name))
finally: finally:
db.close() db.close()
@@ -83,8 +129,9 @@ async def analyze(request: Request, csrf_token: str = Form(...), bank_selection:
user = get_current_user(request, db=db) user = get_current_user(request, db=db)
if not user: if not user:
return RedirectResponse("/login", status_code=303) return RedirectResponse("/login", status_code=303)
recent = [job_view(item) for item in list_user_jobs(user.id, limit=8)] timezone_name = _display_timezone_name(request, db, user)
return templates.TemplateResponse("modules/bank_statement_analyzer/templates/bank_statement_analyzer/index.html", _ctx(request, db, user, error=str(exc), active_job=None, recent_jobs=recent, selected_bank=selected_bank, financial_year=financial_year, classification_enabled=classification_enabled), status_code=400) recent = [_localised_job_view(item, timezone_name) for item in list_user_jobs(user.id, limit=8)]
return templates.TemplateResponse("modules/bank_statement_analyzer/templates/bank_statement_analyzer/index.html", _ctx(request, db, user, error=str(exc), active_job=None, recent_jobs=recent, selected_bank=selected_bank, financial_year=financial_year, classification_enabled=classification_enabled, display_timezone=timezone_name), status_code=400)
finally: finally:
db.close() db.close()
@@ -97,8 +144,9 @@ def jobs(request: Request):
user, roles, denied = _auth(request, db) user, roles, denied = _auth(request, db)
if denied: if denied:
return denied return denied
items = [job_view(item) for item in list_user_jobs(user.id, limit=100)] timezone_name = _display_timezone_name(request, db, user)
return templates.TemplateResponse("modules/bank_statement_analyzer/templates/bank_statement_analyzer/jobs.html", _ctx(request, db, user, jobs=items)) items = [_localised_job_view(item, timezone_name) for item in list_user_jobs(user.id, limit=100)]
return templates.TemplateResponse("modules/bank_statement_analyzer/templates/bank_statement_analyzer/jobs.html", _ctx(request, db, user, jobs=items, display_timezone=timezone_name))
finally: finally:
db.close() db.close()